@mcesystems/apple-kit 1.0.54 → 1.0.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +303 -196
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +303 -196
- package/dist/index.mjs.map +4 -4
- package/dist/types/logic/actions/appState.d.ts +2 -0
- package/dist/types/logic/actions/appState.d.ts.map +1 -0
- package/dist/types/logic/actions/install.d.ts +1 -0
- package/dist/types/logic/actions/install.d.ts.map +1 -1
- package/dist/types/logic/activationFlow.d.ts +3 -3
- package/dist/types/logic/activationFlow.d.ts.map +1 -1
- package/dist/types/logic/appleDeviceKit.d.ts +9 -3
- package/dist/types/logic/appleDeviceKit.d.ts.map +1 -1
- package/dist/types/logic/iosCli.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -32411,6 +32411,131 @@ async function getActivationState(udid) {
|
|
|
32411
32411
|
}
|
|
32412
32412
|
}
|
|
32413
32413
|
|
|
32414
|
+
// src/logic/actions/pair.ts
|
|
32415
|
+
async function isPaired(udid) {
|
|
32416
|
+
logTask(`Checking pairing status for ${udid}`);
|
|
32417
|
+
try {
|
|
32418
|
+
const result = await runIDeviceTool("idevicepair", ["-u", udid, "validate"]);
|
|
32419
|
+
if (!result) {
|
|
32420
|
+
return false;
|
|
32421
|
+
}
|
|
32422
|
+
return result.stdout.toLowerCase().includes("success");
|
|
32423
|
+
} catch {
|
|
32424
|
+
return false;
|
|
32425
|
+
}
|
|
32426
|
+
}
|
|
32427
|
+
async function trustDevice(udid, timeout2 = 6e4, onWaitingForTrust) {
|
|
32428
|
+
logTask(`Trusting device ${udid}`);
|
|
32429
|
+
if (await isPaired(udid)) {
|
|
32430
|
+
logInfo(`Device ${udid} is already trusted`);
|
|
32431
|
+
return true;
|
|
32432
|
+
}
|
|
32433
|
+
logInfo(`Initiating pairing for device ${udid}`);
|
|
32434
|
+
try {
|
|
32435
|
+
const pairResult = await pair(udid);
|
|
32436
|
+
if (pairResult) {
|
|
32437
|
+
logInfo(`Device ${udid} paired successfully`);
|
|
32438
|
+
return true;
|
|
32439
|
+
}
|
|
32440
|
+
} catch (error) {
|
|
32441
|
+
logError(`Pairing failed with ${udid}: ${error}`);
|
|
32442
|
+
}
|
|
32443
|
+
logInfo("Please accept the trust dialog on the device...");
|
|
32444
|
+
onWaitingForTrust?.();
|
|
32445
|
+
try {
|
|
32446
|
+
await waitForPairing(udid, timeout2, 1e3);
|
|
32447
|
+
logInfo(`Device ${udid} is now trusted`);
|
|
32448
|
+
return true;
|
|
32449
|
+
} catch {
|
|
32450
|
+
logInfo(`Timeout waiting for trust acceptance on device ${udid}`);
|
|
32451
|
+
return false;
|
|
32452
|
+
}
|
|
32453
|
+
}
|
|
32454
|
+
async function waitForPairing(udid, timeout2 = 12e4, pollInterval = 1e3) {
|
|
32455
|
+
logTask(`Waiting for pairing on device ${udid}`);
|
|
32456
|
+
const startTime = Date.now();
|
|
32457
|
+
while (Date.now() - startTime < timeout2) {
|
|
32458
|
+
if (await isPaired(udid)) {
|
|
32459
|
+
logInfo(`Device ${udid} is now paired`);
|
|
32460
|
+
return true;
|
|
32461
|
+
}
|
|
32462
|
+
await new Promise((resolve5) => setTimeout(resolve5, pollInterval));
|
|
32463
|
+
}
|
|
32464
|
+
throw new Error(`Timeout waiting for device pairing after ${timeout2}ms`);
|
|
32465
|
+
}
|
|
32466
|
+
async function pair(udid) {
|
|
32467
|
+
logTask(`Initiating pairing for device ${udid}`);
|
|
32468
|
+
try {
|
|
32469
|
+
const result = await runIDeviceTool("idevicepair", ["-u", udid, "pair"]);
|
|
32470
|
+
if (!result) {
|
|
32471
|
+
return false;
|
|
32472
|
+
}
|
|
32473
|
+
return result.stdout.toLowerCase().includes("success");
|
|
32474
|
+
} catch (error) {
|
|
32475
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
32476
|
+
if (errorMsg.includes("Please accept the trust dialog")) {
|
|
32477
|
+
return false;
|
|
32478
|
+
}
|
|
32479
|
+
throw error;
|
|
32480
|
+
}
|
|
32481
|
+
}
|
|
32482
|
+
async function unpair(udid) {
|
|
32483
|
+
logTask(`Un-pairing device ${udid}`);
|
|
32484
|
+
try {
|
|
32485
|
+
const result = await runIDeviceTool("idevicepair", ["-u", udid, "unpair"]);
|
|
32486
|
+
if (!result) {
|
|
32487
|
+
return false;
|
|
32488
|
+
}
|
|
32489
|
+
return result.stdout.toLowerCase().includes("success");
|
|
32490
|
+
} catch {
|
|
32491
|
+
return false;
|
|
32492
|
+
}
|
|
32493
|
+
}
|
|
32494
|
+
|
|
32495
|
+
// src/logic/actions/appState.ts
|
|
32496
|
+
var FRONTMOST_KEYS = [
|
|
32497
|
+
"FrontmostApplicationBundleID",
|
|
32498
|
+
"FrontmostApplicationBundleId",
|
|
32499
|
+
"FrontmostAppBundleIdentifier",
|
|
32500
|
+
"ForegroundApplicationBundleID",
|
|
32501
|
+
"ForegroundApplicationBundleId",
|
|
32502
|
+
"ForegroundAppBundleId",
|
|
32503
|
+
"ApplicationBundleIdentifier",
|
|
32504
|
+
"BundleIdentifier",
|
|
32505
|
+
"bundleIdentifier",
|
|
32506
|
+
"bundleId"
|
|
32507
|
+
];
|
|
32508
|
+
async function isAppOpened(bundleId, udid) {
|
|
32509
|
+
logTask(`Checking if app ${bundleId} is opened on device ${udid}`);
|
|
32510
|
+
if (!await isPaired(udid)) {
|
|
32511
|
+
await waitForPairing(udid, 1e4);
|
|
32512
|
+
}
|
|
32513
|
+
try {
|
|
32514
|
+
for (const key of FRONTMOST_KEYS) {
|
|
32515
|
+
const result = await runIDeviceTool("ideviceinfo", ["-u", udid, "-k", key]);
|
|
32516
|
+
const output = result?.stdout?.trim() ?? "";
|
|
32517
|
+
if (!output) {
|
|
32518
|
+
continue;
|
|
32519
|
+
}
|
|
32520
|
+
if (isBundleIdMatch(output, bundleId)) {
|
|
32521
|
+
return true;
|
|
32522
|
+
}
|
|
32523
|
+
}
|
|
32524
|
+
} catch (error) {
|
|
32525
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
32526
|
+
logInfo(`isAppOpened failed: ${errorMsg}`);
|
|
32527
|
+
}
|
|
32528
|
+
return false;
|
|
32529
|
+
}
|
|
32530
|
+
function isBundleIdMatch(value, bundleId) {
|
|
32531
|
+
if (value === bundleId) {
|
|
32532
|
+
return true;
|
|
32533
|
+
}
|
|
32534
|
+
const escaped = bundleId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
32535
|
+
const matcher = new RegExp(`(^|[^A-Za-z0-9_.-])${escaped}($|[^A-Za-z0-9_.-])`);
|
|
32536
|
+
return matcher.test(value);
|
|
32537
|
+
}
|
|
32538
|
+
|
|
32414
32539
|
// src/logic/actions/device.ts
|
|
32415
32540
|
import { existsSync as existsSync2 } from "node:fs";
|
|
32416
32541
|
import { join as join3 } from "node:path";
|
|
@@ -33273,100 +33398,46 @@ function resolveCredentialsPath(options) {
|
|
|
33273
33398
|
return process.env.MDM_CRED_PATH ?? process.env.APP_CRED_PATH;
|
|
33274
33399
|
}
|
|
33275
33400
|
|
|
33276
|
-
// src/logic/actions/
|
|
33277
|
-
async function
|
|
33278
|
-
logTask(`
|
|
33279
|
-
|
|
33280
|
-
const result = await runIDeviceTool("idevicepair", ["-u", udid, "validate"]);
|
|
33281
|
-
if (!result) {
|
|
33282
|
-
return false;
|
|
33283
|
-
}
|
|
33284
|
-
return result.stdout.toLowerCase().includes("success");
|
|
33285
|
-
} catch {
|
|
33286
|
-
return false;
|
|
33287
|
-
}
|
|
33401
|
+
// src/logic/actions/install.ts
|
|
33402
|
+
async function installLocalApp(ipaPath, udid) {
|
|
33403
|
+
logTask(`Installing app ${ipaPath} on device ${udid}`);
|
|
33404
|
+
await runIDeviceTool("ideviceinstaller", ["-u", udid, "install", ipaPath]);
|
|
33288
33405
|
}
|
|
33289
|
-
|
|
33290
|
-
|
|
33291
|
-
|
|
33292
|
-
|
|
33293
|
-
|
|
33294
|
-
|
|
33295
|
-
logInfo(`Initiating pairing for device ${udid}`);
|
|
33296
|
-
try {
|
|
33297
|
-
const pairResult = await pair(udid);
|
|
33298
|
-
if (pairResult) {
|
|
33299
|
-
logInfo(`Device ${udid} paired successfully`);
|
|
33300
|
-
return true;
|
|
33301
|
-
}
|
|
33302
|
-
} catch (error) {
|
|
33303
|
-
logError(`Pairing failed with ${udid}: ${error}`);
|
|
33304
|
-
}
|
|
33305
|
-
logInfo("Please accept the trust dialog on the device...");
|
|
33306
|
-
onWaitingForTrust?.();
|
|
33307
|
-
try {
|
|
33308
|
-
await waitForPairing(udid, timeout2, 1e3);
|
|
33309
|
-
logInfo(`Device ${udid} is now trusted`);
|
|
33310
|
-
return true;
|
|
33311
|
-
} catch {
|
|
33312
|
-
logInfo(`Timeout waiting for trust acceptance on device ${udid}`);
|
|
33313
|
-
return false;
|
|
33406
|
+
function getMdmInstallOptionsFromEnv() {
|
|
33407
|
+
const appId = process.env.MDM_APP_ID;
|
|
33408
|
+
const url = process.env.MDM_APP_URL;
|
|
33409
|
+
const waitForInstalled = parseBooleanEnv(process.env.MDM_APP_WAIT_FOR_INSTALLED);
|
|
33410
|
+
if (!appId && !url) {
|
|
33411
|
+
throw new Error("MDM install requires MDM_APP_ID or MDM_APP_URL.");
|
|
33314
33412
|
}
|
|
33413
|
+
return {
|
|
33414
|
+
appId,
|
|
33415
|
+
url,
|
|
33416
|
+
waitForInstalled
|
|
33417
|
+
};
|
|
33315
33418
|
}
|
|
33316
|
-
|
|
33317
|
-
|
|
33318
|
-
|
|
33319
|
-
while (Date.now() - startTime < timeout2) {
|
|
33320
|
-
if (await isPaired(udid)) {
|
|
33321
|
-
logInfo(`Device ${udid} is now paired`);
|
|
33322
|
-
return true;
|
|
33323
|
-
}
|
|
33324
|
-
await new Promise((resolve5) => setTimeout(resolve5, pollInterval));
|
|
33419
|
+
function parseBooleanEnv(value) {
|
|
33420
|
+
if (!value) {
|
|
33421
|
+
return void 0;
|
|
33325
33422
|
}
|
|
33326
|
-
|
|
33327
|
-
|
|
33328
|
-
|
|
33329
|
-
logTask(`Initiating pairing for device ${udid}`);
|
|
33330
|
-
try {
|
|
33331
|
-
const result = await runIDeviceTool("idevicepair", ["-u", udid, "pair"]);
|
|
33332
|
-
if (!result) {
|
|
33333
|
-
return false;
|
|
33334
|
-
}
|
|
33335
|
-
return result.stdout.toLowerCase().includes("success");
|
|
33336
|
-
} catch (error) {
|
|
33337
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
33338
|
-
if (errorMsg.includes("Please accept the trust dialog")) {
|
|
33339
|
-
return false;
|
|
33340
|
-
}
|
|
33341
|
-
throw error;
|
|
33423
|
+
const normalized = value.trim().toLowerCase();
|
|
33424
|
+
if (normalized === "true" || normalized === "1" || normalized === "yes") {
|
|
33425
|
+
return true;
|
|
33342
33426
|
}
|
|
33343
|
-
|
|
33344
|
-
async function unpair(udid) {
|
|
33345
|
-
logTask(`Un-pairing device ${udid}`);
|
|
33346
|
-
try {
|
|
33347
|
-
const result = await runIDeviceTool("idevicepair", ["-u", udid, "unpair"]);
|
|
33348
|
-
if (!result) {
|
|
33349
|
-
return false;
|
|
33350
|
-
}
|
|
33351
|
-
return result.stdout.toLowerCase().includes("success");
|
|
33352
|
-
} catch {
|
|
33427
|
+
if (normalized === "false" || normalized === "0" || normalized === "no") {
|
|
33353
33428
|
return false;
|
|
33354
33429
|
}
|
|
33430
|
+
return void 0;
|
|
33355
33431
|
}
|
|
33356
|
-
|
|
33357
|
-
// src/logic/actions/install.ts
|
|
33358
|
-
async function installApp(ipaPath, udid, options) {
|
|
33359
|
-
if (options?.installViaMdm) {
|
|
33360
|
-
logTask(`Installing app on device ${udid} via MDM`);
|
|
33361
|
-
const mdmClient = await resolveMdmClient(options.mdm);
|
|
33362
|
-
const mdmInstallOptions = getMdmInstallOptions(options.mdm);
|
|
33363
|
-
await mdmClient.installApp(udid, mdmInstallOptions);
|
|
33364
|
-
}
|
|
33432
|
+
async function installManagedApp(ipaPath, udid, timeBetweenInstalls) {
|
|
33365
33433
|
await installLocalApp(ipaPath, udid);
|
|
33366
|
-
|
|
33367
|
-
|
|
33368
|
-
logTask(
|
|
33369
|
-
await
|
|
33434
|
+
const mdmInstallOptions = getMdmInstallOptionsFromEnv();
|
|
33435
|
+
const client = await createMdmClientFromEnv();
|
|
33436
|
+
logTask("Installing app via MDM for management takeover");
|
|
33437
|
+
await new Promise((resolve5) => setTimeout(resolve5, timeBetweenInstalls));
|
|
33438
|
+
if (client) {
|
|
33439
|
+
client.installApp(udid, mdmInstallOptions);
|
|
33440
|
+
}
|
|
33370
33441
|
}
|
|
33371
33442
|
async function uninstallApp(bundleId, udid) {
|
|
33372
33443
|
logTask(`Uninstalling app ${bundleId} from device ${udid}`);
|
|
@@ -33452,33 +33523,6 @@ async function launchApp(bundleId, args, udid) {
|
|
|
33452
33523
|
throw error;
|
|
33453
33524
|
}
|
|
33454
33525
|
}
|
|
33455
|
-
async function resolveMdmClient(options) {
|
|
33456
|
-
if (options?.client) {
|
|
33457
|
-
return options.client;
|
|
33458
|
-
}
|
|
33459
|
-
if (options?.clientConfig) {
|
|
33460
|
-
return createMdmClient(options.clientConfig);
|
|
33461
|
-
}
|
|
33462
|
-
const envClient = await createMdmClientFromEnv();
|
|
33463
|
-
if (!envClient) {
|
|
33464
|
-
throw new Error(
|
|
33465
|
-
"MDM client not configured. Set MDM_ENDPOINT and MDM_CRED_PATH or pass mdm.client."
|
|
33466
|
-
);
|
|
33467
|
-
}
|
|
33468
|
-
return envClient;
|
|
33469
|
-
}
|
|
33470
|
-
function getMdmInstallOptions(options) {
|
|
33471
|
-
const appId = options?.appId;
|
|
33472
|
-
const url = options?.url;
|
|
33473
|
-
if (!appId && !url) {
|
|
33474
|
-
throw new Error("MDM install requires an appId or url.");
|
|
33475
|
-
}
|
|
33476
|
-
return {
|
|
33477
|
-
appId,
|
|
33478
|
-
url,
|
|
33479
|
-
waitForInstalled: options?.waitForInstalled
|
|
33480
|
-
};
|
|
33481
|
-
}
|
|
33482
33526
|
async function launchAppWithPymobiledevice3(bundleId, args, udid) {
|
|
33483
33527
|
logTask(`Launching app ${bundleId} using pymobiledevice3`);
|
|
33484
33528
|
const { exec } = await import("node:child_process");
|
|
@@ -33655,7 +33699,6 @@ function killPortForwardProcess(process2) {
|
|
|
33655
33699
|
}
|
|
33656
33700
|
|
|
33657
33701
|
// src/logic/activationFlow.ts
|
|
33658
|
-
import { existsSync as existsSync4 } from "node:fs";
|
|
33659
33702
|
import { unlink, writeFile } from "node:fs/promises";
|
|
33660
33703
|
import { tmpdir } from "node:os";
|
|
33661
33704
|
import { dirname as dirname3, join as join7, resolve as resolve4 } from "node:path";
|
|
@@ -33922,6 +33965,99 @@ function safeParseJson(line) {
|
|
|
33922
33965
|
return void 0;
|
|
33923
33966
|
}
|
|
33924
33967
|
}
|
|
33968
|
+
function isRecord(value) {
|
|
33969
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
33970
|
+
}
|
|
33971
|
+
function getStringField(record, key) {
|
|
33972
|
+
const value = record[key];
|
|
33973
|
+
return typeof value === "string" ? value : void 0;
|
|
33974
|
+
}
|
|
33975
|
+
function getBooleanField(record, key) {
|
|
33976
|
+
const value = record[key];
|
|
33977
|
+
return typeof value === "boolean" ? value : void 0;
|
|
33978
|
+
}
|
|
33979
|
+
function getNumberField(record, key) {
|
|
33980
|
+
const value = record[key];
|
|
33981
|
+
return typeof value === "number" ? value : void 0;
|
|
33982
|
+
}
|
|
33983
|
+
function getRecordField(record, key) {
|
|
33984
|
+
const value = record[key];
|
|
33985
|
+
return isRecord(value) ? value : void 0;
|
|
33986
|
+
}
|
|
33987
|
+
function toProfileManifest(record) {
|
|
33988
|
+
if (!record) {
|
|
33989
|
+
return void 0;
|
|
33990
|
+
}
|
|
33991
|
+
const description = getStringField(record, "Description");
|
|
33992
|
+
const isActive = getBooleanField(record, "IsActive");
|
|
33993
|
+
if (description === void 0 && isActive === void 0) {
|
|
33994
|
+
return void 0;
|
|
33995
|
+
}
|
|
33996
|
+
return {
|
|
33997
|
+
Description: description,
|
|
33998
|
+
IsActive: isActive
|
|
33999
|
+
};
|
|
34000
|
+
}
|
|
34001
|
+
function toProfileMetadata(record) {
|
|
34002
|
+
if (!record) {
|
|
34003
|
+
return void 0;
|
|
34004
|
+
}
|
|
34005
|
+
const payloadDescription = getStringField(record, "PayloadDescription");
|
|
34006
|
+
const payloadDisplayName = getStringField(record, "PayloadDisplayName");
|
|
34007
|
+
const payloadRemovalDisallowed = getBooleanField(record, "PayloadRemovalDisallowed");
|
|
34008
|
+
const payloadUuid = getStringField(record, "PayloadUUID");
|
|
34009
|
+
const payloadVersion = getNumberField(record, "PayloadVersion");
|
|
34010
|
+
if (payloadDescription === void 0 && payloadDisplayName === void 0 && payloadRemovalDisallowed === void 0 && payloadUuid === void 0 && payloadVersion === void 0) {
|
|
34011
|
+
return void 0;
|
|
34012
|
+
}
|
|
34013
|
+
return {
|
|
34014
|
+
PayloadDescription: payloadDescription,
|
|
34015
|
+
PayloadDisplayName: payloadDisplayName,
|
|
34016
|
+
PayloadRemovalDisallowed: payloadRemovalDisallowed,
|
|
34017
|
+
PayloadUUID: payloadUuid,
|
|
34018
|
+
PayloadVersion: payloadVersion
|
|
34019
|
+
};
|
|
34020
|
+
}
|
|
34021
|
+
function toProfileListEntry(item) {
|
|
34022
|
+
const identifier = getStringField(item, "Identifier");
|
|
34023
|
+
const manifest = toProfileManifest(getRecordField(item, "Manifest"));
|
|
34024
|
+
const metadata = toProfileMetadata(getRecordField(item, "Metadata"));
|
|
34025
|
+
const status = getStringField(item, "Status");
|
|
34026
|
+
if (!identifier && !manifest && !metadata && !status) {
|
|
34027
|
+
return void 0;
|
|
34028
|
+
}
|
|
34029
|
+
return {
|
|
34030
|
+
Identifier: identifier,
|
|
34031
|
+
Manifest: manifest,
|
|
34032
|
+
Metadata: metadata,
|
|
34033
|
+
Status: status
|
|
34034
|
+
};
|
|
34035
|
+
}
|
|
34036
|
+
function parseProfileListOutput(output) {
|
|
34037
|
+
const profiles = [];
|
|
34038
|
+
for (const item of output) {
|
|
34039
|
+
if (Array.isArray(item)) {
|
|
34040
|
+
for (const entry2 of item) {
|
|
34041
|
+
if (!isRecord(entry2)) {
|
|
34042
|
+
continue;
|
|
34043
|
+
}
|
|
34044
|
+
const profileEntry = toProfileListEntry(entry2);
|
|
34045
|
+
if (profileEntry) {
|
|
34046
|
+
profiles.push(profileEntry);
|
|
34047
|
+
}
|
|
34048
|
+
}
|
|
34049
|
+
continue;
|
|
34050
|
+
}
|
|
34051
|
+
if (!isRecord(item)) {
|
|
34052
|
+
continue;
|
|
34053
|
+
}
|
|
34054
|
+
const entry = toProfileListEntry(item);
|
|
34055
|
+
if (entry) {
|
|
34056
|
+
profiles.push(entry);
|
|
34057
|
+
}
|
|
34058
|
+
}
|
|
34059
|
+
return profiles;
|
|
34060
|
+
}
|
|
33925
34061
|
function createIosCli(iosBinaryPath) {
|
|
33926
34062
|
return {
|
|
33927
34063
|
async listDevices() {
|
|
@@ -33960,6 +34096,13 @@ function createIosCli(iosBinaryPath) {
|
|
|
33960
34096
|
},
|
|
33961
34097
|
async info(deviceId) {
|
|
33962
34098
|
return runIosCommand(iosBinaryPath, ["info", "--udid", deviceId]);
|
|
34099
|
+
},
|
|
34100
|
+
async listProfiles(deviceId) {
|
|
34101
|
+
const raw = await runIosCommand(iosBinaryPath, ["profile", "list", "--udid", deviceId]);
|
|
34102
|
+
return {
|
|
34103
|
+
profiles: parseProfileListOutput(raw.output),
|
|
34104
|
+
raw
|
|
34105
|
+
};
|
|
33963
34106
|
}
|
|
33964
34107
|
};
|
|
33965
34108
|
}
|
|
@@ -33967,16 +34110,10 @@ function createIosCli(iosBinaryPath) {
|
|
|
33967
34110
|
// src/logic/activationFlow.ts
|
|
33968
34111
|
var DEFAULT_RETRIES = 150;
|
|
33969
34112
|
var DEFAULT_RETRY_DELAY_MS = 1e3;
|
|
33970
|
-
var
|
|
33971
|
-
var TIME_TO_WAIT_FOR_MANAGED_APP_INSTALL = 1e4;
|
|
33972
|
-
function sleep(ms) {
|
|
33973
|
-
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
33974
|
-
}
|
|
34113
|
+
var MCE_MDM_PROFILE_PREFIX = "com.mce.mdm";
|
|
33975
34114
|
var ActivationFlow = class {
|
|
33976
34115
|
iosCli;
|
|
33977
34116
|
mdmClientPromise;
|
|
33978
|
-
// private readonly organizationName?: string;
|
|
33979
|
-
resourcesDir;
|
|
33980
34117
|
constructor(config) {
|
|
33981
34118
|
const iosBinaryPath = resolveIosBinaryPath(config);
|
|
33982
34119
|
if (!iosBinaryPath) {
|
|
@@ -33984,25 +34121,40 @@ var ActivationFlow = class {
|
|
|
33984
34121
|
}
|
|
33985
34122
|
this.iosCli = createIosCli(iosBinaryPath);
|
|
33986
34123
|
this.mdmClientPromise = createMdmClientFromEnv({ resourcesDir: config.resourcesDir });
|
|
33987
|
-
this.resourcesDir = config.resourcesDir;
|
|
33988
34124
|
}
|
|
33989
34125
|
async run(udid) {
|
|
33990
34126
|
logTask(`Starting activation flow for device ${udid}`);
|
|
33991
34127
|
const activationState = await this.getActivationState(udid);
|
|
33992
|
-
if (activationState
|
|
34128
|
+
if (activationState === "Activated") {
|
|
34129
|
+
const isEnrolled = await this.isEnrolledToMceMdm(udid);
|
|
34130
|
+
if (isEnrolled) {
|
|
34131
|
+
logInfo("Device already activated and enrolled to MCE MDM. Skipping activation flow.");
|
|
34132
|
+
return async () => {
|
|
34133
|
+
};
|
|
34134
|
+
}
|
|
34135
|
+
} else if (activationState) {
|
|
33993
34136
|
logInfo(`Activation state is ${activationState}, activating device`);
|
|
33994
34137
|
await this.retryActivateCommand("activate device", () => this.iosCli.activate(udid));
|
|
33995
34138
|
} else {
|
|
33996
34139
|
await this.retryIosCommand("wipe", () => this.iosCli.wipe(udid));
|
|
33997
|
-
return
|
|
34140
|
+
return void 0;
|
|
33998
34141
|
}
|
|
33999
34142
|
const wifiProfileIdentifier = await this.installWifiProfile(udid);
|
|
34000
34143
|
await this.installMdmProfile(udid);
|
|
34001
34144
|
await this.retryIosCommand("skip steps", () => this.iosCli.skipSteps(udid));
|
|
34002
|
-
|
|
34003
|
-
|
|
34004
|
-
|
|
34005
|
-
|
|
34145
|
+
return () => this.removeWifiProfile(udid, wifiProfileIdentifier);
|
|
34146
|
+
}
|
|
34147
|
+
async isEnrolledToMceMdm(udid) {
|
|
34148
|
+
const profiles = await this.listProfiles(udid);
|
|
34149
|
+
return profiles.some((profile) => isMceMdmProfile(profile));
|
|
34150
|
+
}
|
|
34151
|
+
async listProfiles(udid) {
|
|
34152
|
+
const result = await this.retry(
|
|
34153
|
+
"list profiles",
|
|
34154
|
+
() => this.iosCli.listProfiles(udid),
|
|
34155
|
+
(response) => response.raw.exitCode === 0
|
|
34156
|
+
);
|
|
34157
|
+
return result.profiles;
|
|
34006
34158
|
}
|
|
34007
34159
|
async installWifiProfile(udid) {
|
|
34008
34160
|
const wifiProfile = await generateWifiProfileFromEnv();
|
|
@@ -34044,39 +34196,6 @@ var ActivationFlow = class {
|
|
|
34044
34196
|
);
|
|
34045
34197
|
await removeTempFile(profilePath, "mdm profile");
|
|
34046
34198
|
}
|
|
34047
|
-
// private async installTrustProfile(udid: string): Promise<void> {
|
|
34048
|
-
// const resourcesProfilePath = getResourcesTrustProfilePath(this.resourcesDir);
|
|
34049
|
-
// if (existsSync(resourcesProfilePath)) {
|
|
34050
|
-
// logTask("Installing trust profile from resources");
|
|
34051
|
-
// await this.retryIosCommand("install trust profile", () =>
|
|
34052
|
-
// this.iosCli.installProfile(udid, resourcesProfilePath)
|
|
34053
|
-
// );
|
|
34054
|
-
// return;
|
|
34055
|
-
// }
|
|
34056
|
-
// if (!this.organizationName) {
|
|
34057
|
-
// logError("ORGANIZATION_NAME is required to generate trust profile");
|
|
34058
|
-
// throw new Error("ORGANIZATION_NAME is required for trust profile generation");
|
|
34059
|
-
// }
|
|
34060
|
-
// const trustProfile = await generateTrustProfileFromEnv(this.organizationName);
|
|
34061
|
-
// if (!trustProfile) {
|
|
34062
|
-
// return;
|
|
34063
|
-
// }
|
|
34064
|
-
// logTask("Generating trust profile and saving to resources");
|
|
34065
|
-
// await ensureResourcesDirExists(this.resourcesDir);
|
|
34066
|
-
// await writeFile(resourcesProfilePath, trustProfile, "utf-8");
|
|
34067
|
-
// await this.retryIosCommand("install trust profile", () =>
|
|
34068
|
-
// this.iosCli.installProfile(udid, resourcesProfilePath)
|
|
34069
|
-
// );
|
|
34070
|
-
// }
|
|
34071
|
-
async installManagedApp(udid) {
|
|
34072
|
-
const ipaPath = resolveManagedAppPath(this.resourcesDir);
|
|
34073
|
-
await installLocalApp(ipaPath, udid);
|
|
34074
|
-
const mdmInstallOptions = getMdmInstallOptionsFromEnv();
|
|
34075
|
-
const client = await this.requireMdmClient();
|
|
34076
|
-
logTask("Installing app via MDM for management takeover");
|
|
34077
|
-
await sleep(TIME_BETWEEN_INSTALLS);
|
|
34078
|
-
client.installApp(udid, mdmInstallOptions);
|
|
34079
|
-
}
|
|
34080
34199
|
async removeWifiProfile(udid, profileIdentifier) {
|
|
34081
34200
|
if (!profileIdentifier) {
|
|
34082
34201
|
return;
|
|
@@ -34132,40 +34251,6 @@ async function removeTempFile(filePath, label) {
|
|
|
34132
34251
|
logError(`Failed to remove ${label} temp file: ${errorMsg}`);
|
|
34133
34252
|
}
|
|
34134
34253
|
}
|
|
34135
|
-
function resolveManagedAppPath(resourcesDir) {
|
|
34136
|
-
const resolvedResourcesDir = resolveResourcesDir(resourcesDir);
|
|
34137
|
-
const ipaPath = join7(resolvedResourcesDir, "deviceagent.ipa");
|
|
34138
|
-
if (!existsSync4(ipaPath)) {
|
|
34139
|
-
throw new Error(`Managed app IPA not found at ${ipaPath}`);
|
|
34140
|
-
}
|
|
34141
|
-
return ipaPath;
|
|
34142
|
-
}
|
|
34143
|
-
function getMdmInstallOptionsFromEnv() {
|
|
34144
|
-
const appId = process.env.MDM_APP_ID;
|
|
34145
|
-
const url = process.env.MDM_APP_URL;
|
|
34146
|
-
const waitForInstalled = parseBooleanEnv(process.env.MDM_APP_WAIT_FOR_INSTALLED);
|
|
34147
|
-
if (!appId && !url) {
|
|
34148
|
-
throw new Error("MDM install requires MDM_APP_ID or MDM_APP_URL.");
|
|
34149
|
-
}
|
|
34150
|
-
return {
|
|
34151
|
-
appId,
|
|
34152
|
-
url,
|
|
34153
|
-
waitForInstalled
|
|
34154
|
-
};
|
|
34155
|
-
}
|
|
34156
|
-
function parseBooleanEnv(value) {
|
|
34157
|
-
if (!value) {
|
|
34158
|
-
return void 0;
|
|
34159
|
-
}
|
|
34160
|
-
const normalized = value.trim().toLowerCase();
|
|
34161
|
-
if (normalized === "true" || normalized === "1" || normalized === "yes") {
|
|
34162
|
-
return true;
|
|
34163
|
-
}
|
|
34164
|
-
if (normalized === "false" || normalized === "0" || normalized === "no") {
|
|
34165
|
-
return false;
|
|
34166
|
-
}
|
|
34167
|
-
return void 0;
|
|
34168
|
-
}
|
|
34169
34254
|
function getProfileIdentifierFromProfile(profile) {
|
|
34170
34255
|
const pattern = /<key>PayloadIdentifier<\/key>\s*<string>([^<]+)<\/string>/g;
|
|
34171
34256
|
const matches = [];
|
|
@@ -34228,6 +34313,19 @@ function isActivationSuccess(result) {
|
|
|
34228
34313
|
const hasFatal = result.logMessages.some((log) => log.level === "error");
|
|
34229
34314
|
return !hasFatal;
|
|
34230
34315
|
}
|
|
34316
|
+
function isMceMdmProfile(profile) {
|
|
34317
|
+
const identifier = profile.Identifier;
|
|
34318
|
+
if (!identifier) {
|
|
34319
|
+
return false;
|
|
34320
|
+
}
|
|
34321
|
+
if (!identifier.startsWith(MCE_MDM_PROFILE_PREFIX)) {
|
|
34322
|
+
return false;
|
|
34323
|
+
}
|
|
34324
|
+
if (profile.Manifest?.IsActive === false) {
|
|
34325
|
+
return false;
|
|
34326
|
+
}
|
|
34327
|
+
return true;
|
|
34328
|
+
}
|
|
34231
34329
|
|
|
34232
34330
|
// src/logic/appleDeviceKit.ts
|
|
34233
34331
|
var AppleDeviceKit = class {
|
|
@@ -34312,9 +34410,9 @@ var AppleDeviceKit = class {
|
|
|
34312
34410
|
*
|
|
34313
34411
|
* @param ipaPath Path to the IPA file
|
|
34314
34412
|
*/
|
|
34315
|
-
async installApp(ipaPath,
|
|
34413
|
+
async installApp(ipaPath, timeBetweenInstalls = 1e4) {
|
|
34316
34414
|
this.ensureNotDisposed();
|
|
34317
|
-
|
|
34415
|
+
return installManagedApp(ipaPath, this.deviceId, timeBetweenInstalls);
|
|
34318
34416
|
}
|
|
34319
34417
|
/**
|
|
34320
34418
|
* Uninstall an app by bundle ID (uninstall agent)
|
|
@@ -34334,6 +34432,15 @@ var AppleDeviceKit = class {
|
|
|
34334
34432
|
this.ensureNotDisposed();
|
|
34335
34433
|
return isAppInstalled(bundleId, this.deviceId);
|
|
34336
34434
|
}
|
|
34435
|
+
/**
|
|
34436
|
+
* Check if an app is currently opened on the device
|
|
34437
|
+
*
|
|
34438
|
+
* @param bundleId Application bundle identifier
|
|
34439
|
+
*/
|
|
34440
|
+
async isAppOpened(bundleId) {
|
|
34441
|
+
this.ensureNotDisposed();
|
|
34442
|
+
return isAppOpened(bundleId, this.deviceId);
|
|
34443
|
+
}
|
|
34337
34444
|
/**
|
|
34338
34445
|
* List all installed user applications
|
|
34339
34446
|
*/
|