Add bulk wipe

This commit is contained in:
Aleks Rutins 2025-06-09 13:32:53 -04:00
parent 4721569c5d
commit b24a5bb612
No known key found for this signature in database
6 changed files with 119 additions and 2 deletions

21
gum.js Normal file
View file

@ -0,0 +1,21 @@
import { spawn } from "child_process";
export function gum(...args) {
return new Promise((res, rej) => {
const gum = spawn("gum", args, {
env: { ...process.env, TERM: "xterm-256color" },
});
gum.stderr.pipe(process.stderr);
gum.stdout.on("data", (data) => {
res(data.toString());
});
gum.on("exit", res);
});
}
export function info(msg) {
return gum("log", "-l", "info", msg);
}

View file

@ -1,8 +1,9 @@
#!/usr/bin/env bash #!/usr/bin/env bash
while true; do while true; do
cmd=$(gum choose wipe exit) cmd=$(gum choose wipe wipebulk exit)
case $cmd in case $cmd in
exit) exit;; exit) exit;;
*) source ./$cmd.sh;; "") exit;;
*) source ./$cmd;;
esac esac
done done

25
mosyle.js Normal file
View file

@ -0,0 +1,25 @@
export function call(endpoint, data, auth) {
const headers = {
"Content-Type": "application/json",
};
if (auth) headers.Authorization = `Bearer ${auth}`;
return fetch("https://managerapi.mosyle.com/v2" + endpoint, {
method: "POST",
headers,
body: JSON.stringify(data),
});
}
export async function authenticate(email, password, token) {
const response = await call("/login", {
email,
password,
accessToken: token,
});
if (!response.ok) throw new Error("Authentication failed");
return response.headers.get("Authorization").replace(/^Bearer\s/, "");
}
export function bulk(data, auth) {
return call("/bulkops", data, auth);
}

View file

3
wipebulk Normal file
View file

@ -0,0 +1,3 @@
#!/usr/bin/env bash
gum log "Enter your serial numbers below, one per line."
gum write --placeholder "FXN234342G" | node wipebulk.js

67
wipebulk.js Normal file
View file

@ -0,0 +1,67 @@
#!/usr/bin/env node
import fs from "fs";
import { info } from "./gum.js";
import { authenticate, bulk, call } from "./mosyle.js";
let serialsTxt = "";
for await (const chunk of process.stdin) {
serialsTxt += chunk;
}
const serials = serialsTxt.split("\n").filter(Boolean);
const accessToken = process.env.MOSYLE_TOKEN;
info("Authenticating...");
const token = await authenticate(
process.env.MOSYLE_USER,
process.env.MOSYLE_PASSWORD,
accessToken,
);
info("Getting devices...");
const devices = await call(
"/listdevices",
{ accessToken, serial_number: serials, options: { os: "ios" } },
token,
)
.then((res) => res.json())
.then((j) =>
j.status == "OK"
? j.response.devices.map((d) => d.deviceudid)
: console.error(j),
);
info("Changing to limbo and wiping...");
console.log(
await (
await bulk(
{
accessToken,
elements: [
{
operation: "change_to_limbo",
devices,
},
{
operation: "wipe_devices",
devices,
options: {
PreserveDataPlan: "true",
DisallowProximitySetup: "true",
RevokeVPPLicenses: "true",
EnableReturnToService: "true",
},
},
],
},
token,
)
).text(),
);
await info(
"To do more, paste this comma-separated list of serial numbers into the Mosyle search box:",
);
console.log(serials.join(","));