@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.js
CHANGED
|
@@ -32425,6 +32425,131 @@ async function getActivationState(udid) {
|
|
|
32425
32425
|
}
|
|
32426
32426
|
}
|
|
32427
32427
|
|
|
32428
|
+
// src/logic/actions/pair.ts
|
|
32429
|
+
async function isPaired(udid) {
|
|
32430
|
+
logTask(`Checking pairing status for ${udid}`);
|
|
32431
|
+
try {
|
|
32432
|
+
const result = await runIDeviceTool("idevicepair", ["-u", udid, "validate"]);
|
|
32433
|
+
if (!result) {
|
|
32434
|
+
return false;
|
|
32435
|
+
}
|
|
32436
|
+
return result.stdout.toLowerCase().includes("success");
|
|
32437
|
+
} catch {
|
|
32438
|
+
return false;
|
|
32439
|
+
}
|
|
32440
|
+
}
|
|
32441
|
+
async function trustDevice(udid, timeout2 = 6e4, onWaitingForTrust) {
|
|
32442
|
+
logTask(`Trusting device ${udid}`);
|
|
32443
|
+
if (await isPaired(udid)) {
|
|
32444
|
+
logInfo(`Device ${udid} is already trusted`);
|
|
32445
|
+
return true;
|
|
32446
|
+
}
|
|
32447
|
+
logInfo(`Initiating pairing for device ${udid}`);
|
|
32448
|
+
try {
|
|
32449
|
+
const pairResult = await pair(udid);
|
|
32450
|
+
if (pairResult) {
|
|
32451
|
+
logInfo(`Device ${udid} paired successfully`);
|
|
32452
|
+
return true;
|
|
32453
|
+
}
|
|
32454
|
+
} catch (error) {
|
|
32455
|
+
logError(`Pairing failed with ${udid}: ${error}`);
|
|
32456
|
+
}
|
|
32457
|
+
logInfo("Please accept the trust dialog on the device...");
|
|
32458
|
+
onWaitingForTrust?.();
|
|
32459
|
+
try {
|
|
32460
|
+
await waitForPairing(udid, timeout2, 1e3);
|
|
32461
|
+
logInfo(`Device ${udid} is now trusted`);
|
|
32462
|
+
return true;
|
|
32463
|
+
} catch {
|
|
32464
|
+
logInfo(`Timeout waiting for trust acceptance on device ${udid}`);
|
|
32465
|
+
return false;
|
|
32466
|
+
}
|
|
32467
|
+
}
|
|
32468
|
+
async function waitForPairing(udid, timeout2 = 12e4, pollInterval = 1e3) {
|
|
32469
|
+
logTask(`Waiting for pairing on device ${udid}`);
|
|
32470
|
+
const startTime = Date.now();
|
|
32471
|
+
while (Date.now() - startTime < timeout2) {
|
|
32472
|
+
if (await isPaired(udid)) {
|
|
32473
|
+
logInfo(`Device ${udid} is now paired`);
|
|
32474
|
+
return true;
|
|
32475
|
+
}
|
|
32476
|
+
await new Promise((resolve5) => setTimeout(resolve5, pollInterval));
|
|
32477
|
+
}
|
|
32478
|
+
throw new Error(`Timeout waiting for device pairing after ${timeout2}ms`);
|
|
32479
|
+
}
|
|
32480
|
+
async function pair(udid) {
|
|
32481
|
+
logTask(`Initiating pairing for device ${udid}`);
|
|
32482
|
+
try {
|
|
32483
|
+
const result = await runIDeviceTool("idevicepair", ["-u", udid, "pair"]);
|
|
32484
|
+
if (!result) {
|
|
32485
|
+
return false;
|
|
32486
|
+
}
|
|
32487
|
+
return result.stdout.toLowerCase().includes("success");
|
|
32488
|
+
} catch (error) {
|
|
32489
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
32490
|
+
if (errorMsg.includes("Please accept the trust dialog")) {
|
|
32491
|
+
return false;
|
|
32492
|
+
}
|
|
32493
|
+
throw error;
|
|
32494
|
+
}
|
|
32495
|
+
}
|
|
32496
|
+
async function unpair(udid) {
|
|
32497
|
+
logTask(`Un-pairing device ${udid}`);
|
|
32498
|
+
try {
|
|
32499
|
+
const result = await runIDeviceTool("idevicepair", ["-u", udid, "unpair"]);
|
|
32500
|
+
if (!result) {
|
|
32501
|
+
return false;
|
|
32502
|
+
}
|
|
32503
|
+
return result.stdout.toLowerCase().includes("success");
|
|
32504
|
+
} catch {
|
|
32505
|
+
return false;
|
|
32506
|
+
}
|
|
32507
|
+
}
|
|
32508
|
+
|
|
32509
|
+
// src/logic/actions/appState.ts
|
|
32510
|
+
var FRONTMOST_KEYS = [
|
|
32511
|
+
"FrontmostApplicationBundleID",
|
|
32512
|
+
"FrontmostApplicationBundleId",
|
|
32513
|
+
"FrontmostAppBundleIdentifier",
|
|
32514
|
+
"ForegroundApplicationBundleID",
|
|
32515
|
+
"ForegroundApplicationBundleId",
|
|
32516
|
+
"ForegroundAppBundleId",
|
|
32517
|
+
"ApplicationBundleIdentifier",
|
|
32518
|
+
"BundleIdentifier",
|
|
32519
|
+
"bundleIdentifier",
|
|
32520
|
+
"bundleId"
|
|
32521
|
+
];
|
|
32522
|
+
async function isAppOpened(bundleId, udid) {
|
|
32523
|
+
logTask(`Checking if app ${bundleId} is opened on device ${udid}`);
|
|
32524
|
+
if (!await isPaired(udid)) {
|
|
32525
|
+
await waitForPairing(udid, 1e4);
|
|
32526
|
+
}
|
|
32527
|
+
try {
|
|
32528
|
+
for (const key of FRONTMOST_KEYS) {
|
|
32529
|
+
const result = await runIDeviceTool("ideviceinfo", ["-u", udid, "-k", key]);
|
|
32530
|
+
const output = result?.stdout?.trim() ?? "";
|
|
32531
|
+
if (!output) {
|
|
32532
|
+
continue;
|
|
32533
|
+
}
|
|
32534
|
+
if (isBundleIdMatch(output, bundleId)) {
|
|
32535
|
+
return true;
|
|
32536
|
+
}
|
|
32537
|
+
}
|
|
32538
|
+
} catch (error) {
|
|
32539
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
32540
|
+
logInfo(`isAppOpened failed: ${errorMsg}`);
|
|
32541
|
+
}
|
|
32542
|
+
return false;
|
|
32543
|
+
}
|
|
32544
|
+
function isBundleIdMatch(value, bundleId) {
|
|
32545
|
+
if (value === bundleId) {
|
|
32546
|
+
return true;
|
|
32547
|
+
}
|
|
32548
|
+
const escaped = bundleId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
32549
|
+
const matcher = new RegExp(`(^|[^A-Za-z0-9_.-])${escaped}($|[^A-Za-z0-9_.-])`);
|
|
32550
|
+
return matcher.test(value);
|
|
32551
|
+
}
|
|
32552
|
+
|
|
32428
32553
|
// src/logic/actions/device.ts
|
|
32429
32554
|
var import_node_fs2 = require("node:fs");
|
|
32430
32555
|
var import_node_path3 = require("node:path");
|
|
@@ -33287,100 +33412,46 @@ function resolveCredentialsPath(options) {
|
|
|
33287
33412
|
return process.env.MDM_CRED_PATH ?? process.env.APP_CRED_PATH;
|
|
33288
33413
|
}
|
|
33289
33414
|
|
|
33290
|
-
// src/logic/actions/
|
|
33291
|
-
async function
|
|
33292
|
-
logTask(`
|
|
33293
|
-
|
|
33294
|
-
const result = await runIDeviceTool("idevicepair", ["-u", udid, "validate"]);
|
|
33295
|
-
if (!result) {
|
|
33296
|
-
return false;
|
|
33297
|
-
}
|
|
33298
|
-
return result.stdout.toLowerCase().includes("success");
|
|
33299
|
-
} catch {
|
|
33300
|
-
return false;
|
|
33301
|
-
}
|
|
33415
|
+
// src/logic/actions/install.ts
|
|
33416
|
+
async function installLocalApp(ipaPath, udid) {
|
|
33417
|
+
logTask(`Installing app ${ipaPath} on device ${udid}`);
|
|
33418
|
+
await runIDeviceTool("ideviceinstaller", ["-u", udid, "install", ipaPath]);
|
|
33302
33419
|
}
|
|
33303
|
-
|
|
33304
|
-
|
|
33305
|
-
|
|
33306
|
-
|
|
33307
|
-
|
|
33308
|
-
|
|
33309
|
-
logInfo(`Initiating pairing for device ${udid}`);
|
|
33310
|
-
try {
|
|
33311
|
-
const pairResult = await pair(udid);
|
|
33312
|
-
if (pairResult) {
|
|
33313
|
-
logInfo(`Device ${udid} paired successfully`);
|
|
33314
|
-
return true;
|
|
33315
|
-
}
|
|
33316
|
-
} catch (error) {
|
|
33317
|
-
logError(`Pairing failed with ${udid}: ${error}`);
|
|
33318
|
-
}
|
|
33319
|
-
logInfo("Please accept the trust dialog on the device...");
|
|
33320
|
-
onWaitingForTrust?.();
|
|
33321
|
-
try {
|
|
33322
|
-
await waitForPairing(udid, timeout2, 1e3);
|
|
33323
|
-
logInfo(`Device ${udid} is now trusted`);
|
|
33324
|
-
return true;
|
|
33325
|
-
} catch {
|
|
33326
|
-
logInfo(`Timeout waiting for trust acceptance on device ${udid}`);
|
|
33327
|
-
return false;
|
|
33420
|
+
function getMdmInstallOptionsFromEnv() {
|
|
33421
|
+
const appId = process.env.MDM_APP_ID;
|
|
33422
|
+
const url = process.env.MDM_APP_URL;
|
|
33423
|
+
const waitForInstalled = parseBooleanEnv(process.env.MDM_APP_WAIT_FOR_INSTALLED);
|
|
33424
|
+
if (!appId && !url) {
|
|
33425
|
+
throw new Error("MDM install requires MDM_APP_ID or MDM_APP_URL.");
|
|
33328
33426
|
}
|
|
33427
|
+
return {
|
|
33428
|
+
appId,
|
|
33429
|
+
url,
|
|
33430
|
+
waitForInstalled
|
|
33431
|
+
};
|
|
33329
33432
|
}
|
|
33330
|
-
|
|
33331
|
-
|
|
33332
|
-
|
|
33333
|
-
while (Date.now() - startTime < timeout2) {
|
|
33334
|
-
if (await isPaired(udid)) {
|
|
33335
|
-
logInfo(`Device ${udid} is now paired`);
|
|
33336
|
-
return true;
|
|
33337
|
-
}
|
|
33338
|
-
await new Promise((resolve5) => setTimeout(resolve5, pollInterval));
|
|
33433
|
+
function parseBooleanEnv(value) {
|
|
33434
|
+
if (!value) {
|
|
33435
|
+
return void 0;
|
|
33339
33436
|
}
|
|
33340
|
-
|
|
33341
|
-
|
|
33342
|
-
|
|
33343
|
-
logTask(`Initiating pairing for device ${udid}`);
|
|
33344
|
-
try {
|
|
33345
|
-
const result = await runIDeviceTool("idevicepair", ["-u", udid, "pair"]);
|
|
33346
|
-
if (!result) {
|
|
33347
|
-
return false;
|
|
33348
|
-
}
|
|
33349
|
-
return result.stdout.toLowerCase().includes("success");
|
|
33350
|
-
} catch (error) {
|
|
33351
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
33352
|
-
if (errorMsg.includes("Please accept the trust dialog")) {
|
|
33353
|
-
return false;
|
|
33354
|
-
}
|
|
33355
|
-
throw error;
|
|
33437
|
+
const normalized = value.trim().toLowerCase();
|
|
33438
|
+
if (normalized === "true" || normalized === "1" || normalized === "yes") {
|
|
33439
|
+
return true;
|
|
33356
33440
|
}
|
|
33357
|
-
|
|
33358
|
-
async function unpair(udid) {
|
|
33359
|
-
logTask(`Un-pairing device ${udid}`);
|
|
33360
|
-
try {
|
|
33361
|
-
const result = await runIDeviceTool("idevicepair", ["-u", udid, "unpair"]);
|
|
33362
|
-
if (!result) {
|
|
33363
|
-
return false;
|
|
33364
|
-
}
|
|
33365
|
-
return result.stdout.toLowerCase().includes("success");
|
|
33366
|
-
} catch {
|
|
33441
|
+
if (normalized === "false" || normalized === "0" || normalized === "no") {
|
|
33367
33442
|
return false;
|
|
33368
33443
|
}
|
|
33444
|
+
return void 0;
|
|
33369
33445
|
}
|
|
33370
|
-
|
|
33371
|
-
// src/logic/actions/install.ts
|
|
33372
|
-
async function installApp(ipaPath, udid, options) {
|
|
33373
|
-
if (options?.installViaMdm) {
|
|
33374
|
-
logTask(`Installing app on device ${udid} via MDM`);
|
|
33375
|
-
const mdmClient = await resolveMdmClient(options.mdm);
|
|
33376
|
-
const mdmInstallOptions = getMdmInstallOptions(options.mdm);
|
|
33377
|
-
await mdmClient.installApp(udid, mdmInstallOptions);
|
|
33378
|
-
}
|
|
33446
|
+
async function installManagedApp(ipaPath, udid, timeBetweenInstalls) {
|
|
33379
33447
|
await installLocalApp(ipaPath, udid);
|
|
33380
|
-
|
|
33381
|
-
|
|
33382
|
-
logTask(
|
|
33383
|
-
await
|
|
33448
|
+
const mdmInstallOptions = getMdmInstallOptionsFromEnv();
|
|
33449
|
+
const client = await createMdmClientFromEnv();
|
|
33450
|
+
logTask("Installing app via MDM for management takeover");
|
|
33451
|
+
await new Promise((resolve5) => setTimeout(resolve5, timeBetweenInstalls));
|
|
33452
|
+
if (client) {
|
|
33453
|
+
client.installApp(udid, mdmInstallOptions);
|
|
33454
|
+
}
|
|
33384
33455
|
}
|
|
33385
33456
|
async function uninstallApp(bundleId, udid) {
|
|
33386
33457
|
logTask(`Uninstalling app ${bundleId} from device ${udid}`);
|
|
@@ -33466,33 +33537,6 @@ async function launchApp(bundleId, args, udid) {
|
|
|
33466
33537
|
throw error;
|
|
33467
33538
|
}
|
|
33468
33539
|
}
|
|
33469
|
-
async function resolveMdmClient(options) {
|
|
33470
|
-
if (options?.client) {
|
|
33471
|
-
return options.client;
|
|
33472
|
-
}
|
|
33473
|
-
if (options?.clientConfig) {
|
|
33474
|
-
return createMdmClient(options.clientConfig);
|
|
33475
|
-
}
|
|
33476
|
-
const envClient = await createMdmClientFromEnv();
|
|
33477
|
-
if (!envClient) {
|
|
33478
|
-
throw new Error(
|
|
33479
|
-
"MDM client not configured. Set MDM_ENDPOINT and MDM_CRED_PATH or pass mdm.client."
|
|
33480
|
-
);
|
|
33481
|
-
}
|
|
33482
|
-
return envClient;
|
|
33483
|
-
}
|
|
33484
|
-
function getMdmInstallOptions(options) {
|
|
33485
|
-
const appId = options?.appId;
|
|
33486
|
-
const url = options?.url;
|
|
33487
|
-
if (!appId && !url) {
|
|
33488
|
-
throw new Error("MDM install requires an appId or url.");
|
|
33489
|
-
}
|
|
33490
|
-
return {
|
|
33491
|
-
appId,
|
|
33492
|
-
url,
|
|
33493
|
-
waitForInstalled: options?.waitForInstalled
|
|
33494
|
-
};
|
|
33495
|
-
}
|
|
33496
33540
|
async function launchAppWithPymobiledevice3(bundleId, args, udid) {
|
|
33497
33541
|
logTask(`Launching app ${bundleId} using pymobiledevice3`);
|
|
33498
33542
|
const { exec } = await import("node:child_process");
|
|
@@ -33669,7 +33713,6 @@ function killPortForwardProcess(process2) {
|
|
|
33669
33713
|
}
|
|
33670
33714
|
|
|
33671
33715
|
// src/logic/activationFlow.ts
|
|
33672
|
-
var import_node_fs4 = require("node:fs");
|
|
33673
33716
|
var import_promises2 = require("node:fs/promises");
|
|
33674
33717
|
var import_node_os2 = require("node:os");
|
|
33675
33718
|
var import_node_path7 = require("node:path");
|
|
@@ -33937,6 +33980,99 @@ function safeParseJson(line) {
|
|
|
33937
33980
|
return void 0;
|
|
33938
33981
|
}
|
|
33939
33982
|
}
|
|
33983
|
+
function isRecord(value) {
|
|
33984
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
33985
|
+
}
|
|
33986
|
+
function getStringField(record, key) {
|
|
33987
|
+
const value = record[key];
|
|
33988
|
+
return typeof value === "string" ? value : void 0;
|
|
33989
|
+
}
|
|
33990
|
+
function getBooleanField(record, key) {
|
|
33991
|
+
const value = record[key];
|
|
33992
|
+
return typeof value === "boolean" ? value : void 0;
|
|
33993
|
+
}
|
|
33994
|
+
function getNumberField(record, key) {
|
|
33995
|
+
const value = record[key];
|
|
33996
|
+
return typeof value === "number" ? value : void 0;
|
|
33997
|
+
}
|
|
33998
|
+
function getRecordField(record, key) {
|
|
33999
|
+
const value = record[key];
|
|
34000
|
+
return isRecord(value) ? value : void 0;
|
|
34001
|
+
}
|
|
34002
|
+
function toProfileManifest(record) {
|
|
34003
|
+
if (!record) {
|
|
34004
|
+
return void 0;
|
|
34005
|
+
}
|
|
34006
|
+
const description = getStringField(record, "Description");
|
|
34007
|
+
const isActive = getBooleanField(record, "IsActive");
|
|
34008
|
+
if (description === void 0 && isActive === void 0) {
|
|
34009
|
+
return void 0;
|
|
34010
|
+
}
|
|
34011
|
+
return {
|
|
34012
|
+
Description: description,
|
|
34013
|
+
IsActive: isActive
|
|
34014
|
+
};
|
|
34015
|
+
}
|
|
34016
|
+
function toProfileMetadata(record) {
|
|
34017
|
+
if (!record) {
|
|
34018
|
+
return void 0;
|
|
34019
|
+
}
|
|
34020
|
+
const payloadDescription = getStringField(record, "PayloadDescription");
|
|
34021
|
+
const payloadDisplayName = getStringField(record, "PayloadDisplayName");
|
|
34022
|
+
const payloadRemovalDisallowed = getBooleanField(record, "PayloadRemovalDisallowed");
|
|
34023
|
+
const payloadUuid = getStringField(record, "PayloadUUID");
|
|
34024
|
+
const payloadVersion = getNumberField(record, "PayloadVersion");
|
|
34025
|
+
if (payloadDescription === void 0 && payloadDisplayName === void 0 && payloadRemovalDisallowed === void 0 && payloadUuid === void 0 && payloadVersion === void 0) {
|
|
34026
|
+
return void 0;
|
|
34027
|
+
}
|
|
34028
|
+
return {
|
|
34029
|
+
PayloadDescription: payloadDescription,
|
|
34030
|
+
PayloadDisplayName: payloadDisplayName,
|
|
34031
|
+
PayloadRemovalDisallowed: payloadRemovalDisallowed,
|
|
34032
|
+
PayloadUUID: payloadUuid,
|
|
34033
|
+
PayloadVersion: payloadVersion
|
|
34034
|
+
};
|
|
34035
|
+
}
|
|
34036
|
+
function toProfileListEntry(item) {
|
|
34037
|
+
const identifier = getStringField(item, "Identifier");
|
|
34038
|
+
const manifest = toProfileManifest(getRecordField(item, "Manifest"));
|
|
34039
|
+
const metadata = toProfileMetadata(getRecordField(item, "Metadata"));
|
|
34040
|
+
const status = getStringField(item, "Status");
|
|
34041
|
+
if (!identifier && !manifest && !metadata && !status) {
|
|
34042
|
+
return void 0;
|
|
34043
|
+
}
|
|
34044
|
+
return {
|
|
34045
|
+
Identifier: identifier,
|
|
34046
|
+
Manifest: manifest,
|
|
34047
|
+
Metadata: metadata,
|
|
34048
|
+
Status: status
|
|
34049
|
+
};
|
|
34050
|
+
}
|
|
34051
|
+
function parseProfileListOutput(output) {
|
|
34052
|
+
const profiles = [];
|
|
34053
|
+
for (const item of output) {
|
|
34054
|
+
if (Array.isArray(item)) {
|
|
34055
|
+
for (const entry2 of item) {
|
|
34056
|
+
if (!isRecord(entry2)) {
|
|
34057
|
+
continue;
|
|
34058
|
+
}
|
|
34059
|
+
const profileEntry = toProfileListEntry(entry2);
|
|
34060
|
+
if (profileEntry) {
|
|
34061
|
+
profiles.push(profileEntry);
|
|
34062
|
+
}
|
|
34063
|
+
}
|
|
34064
|
+
continue;
|
|
34065
|
+
}
|
|
34066
|
+
if (!isRecord(item)) {
|
|
34067
|
+
continue;
|
|
34068
|
+
}
|
|
34069
|
+
const entry = toProfileListEntry(item);
|
|
34070
|
+
if (entry) {
|
|
34071
|
+
profiles.push(entry);
|
|
34072
|
+
}
|
|
34073
|
+
}
|
|
34074
|
+
return profiles;
|
|
34075
|
+
}
|
|
33940
34076
|
function createIosCli(iosBinaryPath) {
|
|
33941
34077
|
return {
|
|
33942
34078
|
async listDevices() {
|
|
@@ -33975,6 +34111,13 @@ function createIosCli(iosBinaryPath) {
|
|
|
33975
34111
|
},
|
|
33976
34112
|
async info(deviceId) {
|
|
33977
34113
|
return runIosCommand(iosBinaryPath, ["info", "--udid", deviceId]);
|
|
34114
|
+
},
|
|
34115
|
+
async listProfiles(deviceId) {
|
|
34116
|
+
const raw = await runIosCommand(iosBinaryPath, ["profile", "list", "--udid", deviceId]);
|
|
34117
|
+
return {
|
|
34118
|
+
profiles: parseProfileListOutput(raw.output),
|
|
34119
|
+
raw
|
|
34120
|
+
};
|
|
33978
34121
|
}
|
|
33979
34122
|
};
|
|
33980
34123
|
}
|
|
@@ -33983,16 +34126,10 @@ function createIosCli(iosBinaryPath) {
|
|
|
33983
34126
|
var import_meta3 = {};
|
|
33984
34127
|
var DEFAULT_RETRIES = 150;
|
|
33985
34128
|
var DEFAULT_RETRY_DELAY_MS = 1e3;
|
|
33986
|
-
var
|
|
33987
|
-
var TIME_TO_WAIT_FOR_MANAGED_APP_INSTALL = 1e4;
|
|
33988
|
-
function sleep(ms) {
|
|
33989
|
-
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
33990
|
-
}
|
|
34129
|
+
var MCE_MDM_PROFILE_PREFIX = "com.mce.mdm";
|
|
33991
34130
|
var ActivationFlow = class {
|
|
33992
34131
|
iosCli;
|
|
33993
34132
|
mdmClientPromise;
|
|
33994
|
-
// private readonly organizationName?: string;
|
|
33995
|
-
resourcesDir;
|
|
33996
34133
|
constructor(config) {
|
|
33997
34134
|
const iosBinaryPath = resolveIosBinaryPath(config);
|
|
33998
34135
|
if (!iosBinaryPath) {
|
|
@@ -34000,25 +34137,40 @@ var ActivationFlow = class {
|
|
|
34000
34137
|
}
|
|
34001
34138
|
this.iosCli = createIosCli(iosBinaryPath);
|
|
34002
34139
|
this.mdmClientPromise = createMdmClientFromEnv({ resourcesDir: config.resourcesDir });
|
|
34003
|
-
this.resourcesDir = config.resourcesDir;
|
|
34004
34140
|
}
|
|
34005
34141
|
async run(udid) {
|
|
34006
34142
|
logTask(`Starting activation flow for device ${udid}`);
|
|
34007
34143
|
const activationState = await this.getActivationState(udid);
|
|
34008
|
-
if (activationState
|
|
34144
|
+
if (activationState === "Activated") {
|
|
34145
|
+
const isEnrolled = await this.isEnrolledToMceMdm(udid);
|
|
34146
|
+
if (isEnrolled) {
|
|
34147
|
+
logInfo("Device already activated and enrolled to MCE MDM. Skipping activation flow.");
|
|
34148
|
+
return async () => {
|
|
34149
|
+
};
|
|
34150
|
+
}
|
|
34151
|
+
} else if (activationState) {
|
|
34009
34152
|
logInfo(`Activation state is ${activationState}, activating device`);
|
|
34010
34153
|
await this.retryActivateCommand("activate device", () => this.iosCli.activate(udid));
|
|
34011
34154
|
} else {
|
|
34012
34155
|
await this.retryIosCommand("wipe", () => this.iosCli.wipe(udid));
|
|
34013
|
-
return
|
|
34156
|
+
return void 0;
|
|
34014
34157
|
}
|
|
34015
34158
|
const wifiProfileIdentifier = await this.installWifiProfile(udid);
|
|
34016
34159
|
await this.installMdmProfile(udid);
|
|
34017
34160
|
await this.retryIosCommand("skip steps", () => this.iosCli.skipSteps(udid));
|
|
34018
|
-
|
|
34019
|
-
|
|
34020
|
-
|
|
34021
|
-
|
|
34161
|
+
return () => this.removeWifiProfile(udid, wifiProfileIdentifier);
|
|
34162
|
+
}
|
|
34163
|
+
async isEnrolledToMceMdm(udid) {
|
|
34164
|
+
const profiles = await this.listProfiles(udid);
|
|
34165
|
+
return profiles.some((profile) => isMceMdmProfile(profile));
|
|
34166
|
+
}
|
|
34167
|
+
async listProfiles(udid) {
|
|
34168
|
+
const result = await this.retry(
|
|
34169
|
+
"list profiles",
|
|
34170
|
+
() => this.iosCli.listProfiles(udid),
|
|
34171
|
+
(response) => response.raw.exitCode === 0
|
|
34172
|
+
);
|
|
34173
|
+
return result.profiles;
|
|
34022
34174
|
}
|
|
34023
34175
|
async installWifiProfile(udid) {
|
|
34024
34176
|
const wifiProfile = await generateWifiProfileFromEnv();
|
|
@@ -34060,39 +34212,6 @@ var ActivationFlow = class {
|
|
|
34060
34212
|
);
|
|
34061
34213
|
await removeTempFile(profilePath, "mdm profile");
|
|
34062
34214
|
}
|
|
34063
|
-
// private async installTrustProfile(udid: string): Promise<void> {
|
|
34064
|
-
// const resourcesProfilePath = getResourcesTrustProfilePath(this.resourcesDir);
|
|
34065
|
-
// if (existsSync(resourcesProfilePath)) {
|
|
34066
|
-
// logTask("Installing trust profile from resources");
|
|
34067
|
-
// await this.retryIosCommand("install trust profile", () =>
|
|
34068
|
-
// this.iosCli.installProfile(udid, resourcesProfilePath)
|
|
34069
|
-
// );
|
|
34070
|
-
// return;
|
|
34071
|
-
// }
|
|
34072
|
-
// if (!this.organizationName) {
|
|
34073
|
-
// logError("ORGANIZATION_NAME is required to generate trust profile");
|
|
34074
|
-
// throw new Error("ORGANIZATION_NAME is required for trust profile generation");
|
|
34075
|
-
// }
|
|
34076
|
-
// const trustProfile = await generateTrustProfileFromEnv(this.organizationName);
|
|
34077
|
-
// if (!trustProfile) {
|
|
34078
|
-
// return;
|
|
34079
|
-
// }
|
|
34080
|
-
// logTask("Generating trust profile and saving to resources");
|
|
34081
|
-
// await ensureResourcesDirExists(this.resourcesDir);
|
|
34082
|
-
// await writeFile(resourcesProfilePath, trustProfile, "utf-8");
|
|
34083
|
-
// await this.retryIosCommand("install trust profile", () =>
|
|
34084
|
-
// this.iosCli.installProfile(udid, resourcesProfilePath)
|
|
34085
|
-
// );
|
|
34086
|
-
// }
|
|
34087
|
-
async installManagedApp(udid) {
|
|
34088
|
-
const ipaPath = resolveManagedAppPath(this.resourcesDir);
|
|
34089
|
-
await installLocalApp(ipaPath, udid);
|
|
34090
|
-
const mdmInstallOptions = getMdmInstallOptionsFromEnv();
|
|
34091
|
-
const client = await this.requireMdmClient();
|
|
34092
|
-
logTask("Installing app via MDM for management takeover");
|
|
34093
|
-
await sleep(TIME_BETWEEN_INSTALLS);
|
|
34094
|
-
client.installApp(udid, mdmInstallOptions);
|
|
34095
|
-
}
|
|
34096
34215
|
async removeWifiProfile(udid, profileIdentifier) {
|
|
34097
34216
|
if (!profileIdentifier) {
|
|
34098
34217
|
return;
|
|
@@ -34148,40 +34267,6 @@ async function removeTempFile(filePath, label) {
|
|
|
34148
34267
|
logError(`Failed to remove ${label} temp file: ${errorMsg}`);
|
|
34149
34268
|
}
|
|
34150
34269
|
}
|
|
34151
|
-
function resolveManagedAppPath(resourcesDir) {
|
|
34152
|
-
const resolvedResourcesDir = resolveResourcesDir(resourcesDir);
|
|
34153
|
-
const ipaPath = (0, import_node_path7.join)(resolvedResourcesDir, "deviceagent.ipa");
|
|
34154
|
-
if (!(0, import_node_fs4.existsSync)(ipaPath)) {
|
|
34155
|
-
throw new Error(`Managed app IPA not found at ${ipaPath}`);
|
|
34156
|
-
}
|
|
34157
|
-
return ipaPath;
|
|
34158
|
-
}
|
|
34159
|
-
function getMdmInstallOptionsFromEnv() {
|
|
34160
|
-
const appId = process.env.MDM_APP_ID;
|
|
34161
|
-
const url = process.env.MDM_APP_URL;
|
|
34162
|
-
const waitForInstalled = parseBooleanEnv(process.env.MDM_APP_WAIT_FOR_INSTALLED);
|
|
34163
|
-
if (!appId && !url) {
|
|
34164
|
-
throw new Error("MDM install requires MDM_APP_ID or MDM_APP_URL.");
|
|
34165
|
-
}
|
|
34166
|
-
return {
|
|
34167
|
-
appId,
|
|
34168
|
-
url,
|
|
34169
|
-
waitForInstalled
|
|
34170
|
-
};
|
|
34171
|
-
}
|
|
34172
|
-
function parseBooleanEnv(value) {
|
|
34173
|
-
if (!value) {
|
|
34174
|
-
return void 0;
|
|
34175
|
-
}
|
|
34176
|
-
const normalized = value.trim().toLowerCase();
|
|
34177
|
-
if (normalized === "true" || normalized === "1" || normalized === "yes") {
|
|
34178
|
-
return true;
|
|
34179
|
-
}
|
|
34180
|
-
if (normalized === "false" || normalized === "0" || normalized === "no") {
|
|
34181
|
-
return false;
|
|
34182
|
-
}
|
|
34183
|
-
return void 0;
|
|
34184
|
-
}
|
|
34185
34270
|
function getProfileIdentifierFromProfile(profile) {
|
|
34186
34271
|
const pattern = /<key>PayloadIdentifier<\/key>\s*<string>([^<]+)<\/string>/g;
|
|
34187
34272
|
const matches = [];
|
|
@@ -34244,6 +34329,19 @@ function isActivationSuccess(result) {
|
|
|
34244
34329
|
const hasFatal = result.logMessages.some((log) => log.level === "error");
|
|
34245
34330
|
return !hasFatal;
|
|
34246
34331
|
}
|
|
34332
|
+
function isMceMdmProfile(profile) {
|
|
34333
|
+
const identifier = profile.Identifier;
|
|
34334
|
+
if (!identifier) {
|
|
34335
|
+
return false;
|
|
34336
|
+
}
|
|
34337
|
+
if (!identifier.startsWith(MCE_MDM_PROFILE_PREFIX)) {
|
|
34338
|
+
return false;
|
|
34339
|
+
}
|
|
34340
|
+
if (profile.Manifest?.IsActive === false) {
|
|
34341
|
+
return false;
|
|
34342
|
+
}
|
|
34343
|
+
return true;
|
|
34344
|
+
}
|
|
34247
34345
|
|
|
34248
34346
|
// src/logic/appleDeviceKit.ts
|
|
34249
34347
|
var AppleDeviceKit = class {
|
|
@@ -34328,9 +34426,9 @@ var AppleDeviceKit = class {
|
|
|
34328
34426
|
*
|
|
34329
34427
|
* @param ipaPath Path to the IPA file
|
|
34330
34428
|
*/
|
|
34331
|
-
async installApp(ipaPath,
|
|
34429
|
+
async installApp(ipaPath, timeBetweenInstalls = 1e4) {
|
|
34332
34430
|
this.ensureNotDisposed();
|
|
34333
|
-
|
|
34431
|
+
return installManagedApp(ipaPath, this.deviceId, timeBetweenInstalls);
|
|
34334
34432
|
}
|
|
34335
34433
|
/**
|
|
34336
34434
|
* Uninstall an app by bundle ID (uninstall agent)
|
|
@@ -34350,6 +34448,15 @@ var AppleDeviceKit = class {
|
|
|
34350
34448
|
this.ensureNotDisposed();
|
|
34351
34449
|
return isAppInstalled(bundleId, this.deviceId);
|
|
34352
34450
|
}
|
|
34451
|
+
/**
|
|
34452
|
+
* Check if an app is currently opened on the device
|
|
34453
|
+
*
|
|
34454
|
+
* @param bundleId Application bundle identifier
|
|
34455
|
+
*/
|
|
34456
|
+
async isAppOpened(bundleId) {
|
|
34457
|
+
this.ensureNotDisposed();
|
|
34458
|
+
return isAppOpened(bundleId, this.deviceId);
|
|
34459
|
+
}
|
|
34353
34460
|
/**
|
|
34354
34461
|
* List all installed user applications
|
|
34355
34462
|
*/
|