@mcesystems/apple-kit 1.0.87 → 1.0.91
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 +862 -429
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +936 -481
- package/dist/index.mjs.map +4 -4
- package/dist/types/index.d.ts +135 -11
- package/package.json +8 -7
- package/scripts/prepare-ios.ts +8 -8
package/dist/types/index.d.ts
CHANGED
|
@@ -3,6 +3,84 @@
|
|
|
3
3
|
import { ChildProcess } from 'node:child_process';
|
|
4
4
|
import { EventEmitter } from 'node:events';
|
|
5
5
|
|
|
6
|
+
export interface MdmClientOptions {
|
|
7
|
+
endpoint?: string;
|
|
8
|
+
authApiUrl?: string;
|
|
9
|
+
credentialsPath?: string;
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface InstallAppMdmOptions {
|
|
13
|
+
appId?: string;
|
|
14
|
+
url?: string;
|
|
15
|
+
waitForInstalled?: boolean;
|
|
16
|
+
clientConfig?: MdmClientOptions$1;
|
|
17
|
+
}
|
|
18
|
+
export interface MdmClientOptions$1 {
|
|
19
|
+
endpoint?: string;
|
|
20
|
+
authApiUrl?: string;
|
|
21
|
+
credentialsPath?: string;
|
|
22
|
+
timeoutMs?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* WiFi Profile Types
|
|
26
|
+
*/
|
|
27
|
+
export type WifiEncryptionType = "WEP" | "WPA" | "WPA2" | "WPA3" | "Any" | "None";
|
|
28
|
+
export type WifiEapType = "TLS" | "TTLS" | "LEAP" | "PEAP" | "EAP-FAST" | "EAP-SIM" | "EAP-AKA";
|
|
29
|
+
export interface WifiProfileConfig {
|
|
30
|
+
ssid: string;
|
|
31
|
+
password?: string;
|
|
32
|
+
encryptionType?: WifiEncryptionType;
|
|
33
|
+
autoJoin?: boolean;
|
|
34
|
+
hiddenNetwork?: boolean;
|
|
35
|
+
organizationName?: string;
|
|
36
|
+
displayName?: string;
|
|
37
|
+
enterprise?: boolean;
|
|
38
|
+
username?: string;
|
|
39
|
+
eapType?: WifiEapType;
|
|
40
|
+
acceptAnyCertificate?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface ActivationFlowConfig {
|
|
43
|
+
/**
|
|
44
|
+
* Whether to install MDM profile.
|
|
45
|
+
* If not set, defaults to true.
|
|
46
|
+
*/
|
|
47
|
+
withMdm?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Path to the ios CLI binary (go-ios wrapper).
|
|
50
|
+
* If not set, defaults to resourcesDir/ios/bin/{platform}/ios(.exe).
|
|
51
|
+
*/
|
|
52
|
+
iosBinaryPath?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Path to the certificate file (optional).
|
|
55
|
+
* If not set, defaults to CERT_FILE from env.
|
|
56
|
+
*/
|
|
57
|
+
certFile?: string;
|
|
58
|
+
/**
|
|
59
|
+
* MDM client options.
|
|
60
|
+
* If not set, defaults to MDM_CLIENT_OPTIONS from env.
|
|
61
|
+
*/
|
|
62
|
+
mdmClientOptions?: MdmClientOptions;
|
|
63
|
+
/**
|
|
64
|
+
* Organization name used for trust profile display (optional).
|
|
65
|
+
* If not set, uses ORGANIZATION_NAME from env.
|
|
66
|
+
*/
|
|
67
|
+
organizationName?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Folder to read/write trust_profile.mobileconfig (optional).
|
|
70
|
+
* If not set, defaults to the package resources folder.
|
|
71
|
+
*/
|
|
72
|
+
resourcesDir?: string;
|
|
73
|
+
/**
|
|
74
|
+
* WiFi profile configuration.
|
|
75
|
+
* If not set, defaults to WIFI_PROFILE_CONFIG from env.
|
|
76
|
+
*/
|
|
77
|
+
wifiProfileConfig?: WifiProfileConfig;
|
|
78
|
+
/**
|
|
79
|
+
* Folder to read/write plist files (optional).
|
|
80
|
+
* If not set, defaults to the package resources folder.
|
|
81
|
+
*/
|
|
82
|
+
plistDir?: string;
|
|
83
|
+
}
|
|
6
84
|
export interface DeviceListOutput {
|
|
7
85
|
deviceList: string[];
|
|
8
86
|
}
|
|
@@ -182,11 +260,6 @@ export interface PortForwardResult {
|
|
|
182
260
|
/** The device port being forwarded to */
|
|
183
261
|
devicePort: number;
|
|
184
262
|
}
|
|
185
|
-
export interface InstallAppMdmOptions {
|
|
186
|
-
appId?: string;
|
|
187
|
-
url?: string;
|
|
188
|
-
waitForInstalled?: boolean;
|
|
189
|
-
}
|
|
190
263
|
/**
|
|
191
264
|
* AppleDeviceKit - iOS device operations wrapper
|
|
192
265
|
*
|
|
@@ -300,6 +373,14 @@ export declare class AppleDeviceKit {
|
|
|
300
373
|
*/
|
|
301
374
|
wipe(): Promise<void>;
|
|
302
375
|
removeProfile(profileIdentifier: string): Promise<void>;
|
|
376
|
+
/**
|
|
377
|
+
* Check if the device is connected to WiFi.
|
|
378
|
+
* Returns the connected SSID when connected, undefined when not.
|
|
379
|
+
* Uses ios syslog capture and parses for the CurrentBSS pattern.
|
|
380
|
+
*
|
|
381
|
+
* @param timeoutMs Duration to capture syslog before parsing (default 5000)
|
|
382
|
+
*/
|
|
383
|
+
isWifiConnected(timeoutMs?: number): Promise<string | undefined>;
|
|
303
384
|
listProfiles(): Promise<IosProfileListResult>;
|
|
304
385
|
/**
|
|
305
386
|
* Activate the device using the activation flow.
|
|
@@ -312,7 +393,7 @@ export declare class AppleDeviceKit {
|
|
|
312
393
|
*
|
|
313
394
|
* Precondition: the device must be paired and trusted.
|
|
314
395
|
*/
|
|
315
|
-
activate(signal?: AbortSignal): {
|
|
396
|
+
activate(signal?: AbortSignal, config?: ActivationFlowConfig): {
|
|
316
397
|
promise: Promise<(() => Promise<void>) | undefined>;
|
|
317
398
|
events: EventEmitter;
|
|
318
399
|
};
|
|
@@ -353,7 +434,7 @@ export declare class IosClient {
|
|
|
353
434
|
private iosPath;
|
|
354
435
|
private udid;
|
|
355
436
|
private readonly _usbmuxdAddress?;
|
|
356
|
-
constructor(iosPath: string, udid: string, _usbmuxdAddress?: string
|
|
437
|
+
constructor(iosPath: string, udid: string, _usbmuxdAddress?: string);
|
|
357
438
|
get usbmuxdAddress(): string | undefined;
|
|
358
439
|
private safeParseJson;
|
|
359
440
|
private parseFsyncTreeStdout;
|
|
@@ -365,7 +446,7 @@ export declare class IosClient {
|
|
|
365
446
|
installProfile(profilePath: string): Promise<IosCommandResult>;
|
|
366
447
|
removeProfile(profileName: string): Promise<IosCommandResult>;
|
|
367
448
|
listProfiles(): Promise<IosProfileListResult>;
|
|
368
|
-
skipSteps(steps?: string[]): Promise<IosCommandResult>;
|
|
449
|
+
skipSteps(steps?: string[], certFile?: string, organizationName?: string): Promise<IosCommandResult>;
|
|
369
450
|
listSteps(): Promise<IosCommandResult>;
|
|
370
451
|
activate(): Promise<IosCommandResult>;
|
|
371
452
|
pair(): Promise<IosCommandResult>;
|
|
@@ -393,27 +474,70 @@ export declare class IosClient {
|
|
|
393
474
|
srcPath: string;
|
|
394
475
|
dstPath: string;
|
|
395
476
|
}): Promise<IosCommandResult>;
|
|
477
|
+
/**
|
|
478
|
+
* Capture syslog output for a duration. The syslog command streams and does not exit;
|
|
479
|
+
* we run it for timeoutMs then kill the process.
|
|
480
|
+
* If stopWhen returns true, we stop early and return immediately.
|
|
481
|
+
*/
|
|
482
|
+
captureSyslog(timeoutMs?: number, stopWhen?: (output: {
|
|
483
|
+
stdout: string;
|
|
484
|
+
stderr: string;
|
|
485
|
+
}) => boolean): Promise<{
|
|
486
|
+
stdout: string;
|
|
487
|
+
stderr: string;
|
|
488
|
+
}>;
|
|
396
489
|
fsyncTree({ app, path, }: {
|
|
397
490
|
app: string;
|
|
398
491
|
path?: string;
|
|
399
492
|
}): Promise<IosFsyncTreeResult>;
|
|
400
493
|
}
|
|
494
|
+
declare class DeviceActions {
|
|
495
|
+
private readonly udid;
|
|
496
|
+
private readonly iosClient;
|
|
497
|
+
constructor(udid: string, iosClient: IosClient);
|
|
498
|
+
info(): Promise<LockdownInfo>;
|
|
499
|
+
listDevices(): Promise<IosListResult>;
|
|
500
|
+
wipe(): Promise<void>;
|
|
501
|
+
removeProfile(profileIdentifier: string): Promise<void>;
|
|
502
|
+
listProfiles(): Promise<IosProfileListResult>;
|
|
503
|
+
pair(): Promise<boolean>;
|
|
504
|
+
trustDevice({ timeout, pollInterval, onWaitingForTrust, signal, }: {
|
|
505
|
+
timeout?: number;
|
|
506
|
+
pollInterval?: number;
|
|
507
|
+
onWaitingForTrust?: () => void;
|
|
508
|
+
signal?: AbortSignal;
|
|
509
|
+
}): Promise<boolean>;
|
|
510
|
+
waitForPairing({ timeout, pollInterval, signal, }: {
|
|
511
|
+
timeout?: number;
|
|
512
|
+
pollInterval?: number;
|
|
513
|
+
signal?: AbortSignal;
|
|
514
|
+
}): Promise<boolean>;
|
|
515
|
+
/**
|
|
516
|
+
* Returns true if device is paired and trusted.
|
|
517
|
+
* Uses info() which only succeeds when full pairing is established (user has accepted Trust).
|
|
518
|
+
* Prefer this over lockdown file check since file location/timing can vary by platform.
|
|
519
|
+
*/
|
|
520
|
+
private isPairedViaInfo;
|
|
521
|
+
isWifiConnected(timeoutMs?: number): Promise<string | undefined>;
|
|
522
|
+
unpair(): Promise<boolean>;
|
|
523
|
+
}
|
|
401
524
|
export declare class ActivationFlow {
|
|
402
525
|
private readonly udid;
|
|
403
526
|
private readonly iosClient;
|
|
527
|
+
private readonly deviceActions;
|
|
404
528
|
private mdmClient;
|
|
405
|
-
constructor(udid: string, iosClient: IosClient);
|
|
406
|
-
run(steps?: string[], signal?: AbortSignal): {
|
|
529
|
+
constructor(udid: string, iosClient: IosClient, deviceActions: DeviceActions);
|
|
530
|
+
run(steps?: string[], signal?: AbortSignal, config?: ActivationFlowConfig): {
|
|
407
531
|
promise: Promise<(() => Promise<void>) | undefined>;
|
|
408
532
|
events: EventEmitter;
|
|
409
533
|
};
|
|
410
534
|
private runInternal;
|
|
411
535
|
private installWifiProfile;
|
|
412
536
|
private installMdmProfile;
|
|
537
|
+
private retryMdmEnrollmentProfile;
|
|
413
538
|
private removeWifiProfile;
|
|
414
539
|
private retryIosCommand;
|
|
415
540
|
private retryActivateCommand;
|
|
416
|
-
private retry;
|
|
417
541
|
}
|
|
418
542
|
/**
|
|
419
543
|
* Activation flow event names (use with EventEmitter.on/emit).
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcesystems/apple-kit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.91",
|
|
4
4
|
"description": "iOS device management toolkit using libimobiledevice command-line tools",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/types/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
+
"my-internal": "./src/index.ts",
|
|
10
11
|
"types": "./dist/types/index.d.ts",
|
|
11
12
|
"import": "./dist/index.mjs",
|
|
12
13
|
"require": "./dist/index.js"
|
|
@@ -37,8 +38,9 @@
|
|
|
37
38
|
"graphql-request": "^5.2.0",
|
|
38
39
|
"tsx": "^4.21.0",
|
|
39
40
|
"plist": "^3.1.0",
|
|
40
|
-
"
|
|
41
|
-
"@mcesystems/
|
|
41
|
+
"ts-retry-promise": "^0.8.1",
|
|
42
|
+
"@mcesystems/tool-debug-g4": "1.0.91",
|
|
43
|
+
"@mcesystems/mdm-client-g4": "1.0.91"
|
|
42
44
|
},
|
|
43
45
|
"devDependencies": {
|
|
44
46
|
"@types/node": "^22.10.2",
|
|
@@ -52,8 +54,7 @@
|
|
|
52
54
|
"rimraf": "^6.0.1",
|
|
53
55
|
"typescript": "^5.7.2",
|
|
54
56
|
"vitest": "^2.1.8",
|
|
55
|
-
"@types/plist": "^3.0.5"
|
|
56
|
-
"@mcesystems/usb-device-listener": "1.0.87"
|
|
57
|
+
"@types/plist": "^3.0.5"
|
|
57
58
|
},
|
|
58
59
|
"files": [
|
|
59
60
|
"dist",
|
|
@@ -71,10 +72,10 @@
|
|
|
71
72
|
"build": "tsx esbuild.config.mts",
|
|
72
73
|
"build:all": "pnpm --filter @mcesystems/apple-kit... build",
|
|
73
74
|
"clean": "rimraf dist",
|
|
74
|
-
"check:types": "tsc --noEmit",
|
|
75
|
+
"check:types": "tsc -p tsconfig.build.json --noEmit",
|
|
75
76
|
"activate:example": "tsx src/examples/activationExample.ts",
|
|
76
77
|
"ios:example": "tsx src/examples/iosExample.ts",
|
|
77
|
-
"
|
|
78
|
+
"pairing:example": "tsx src/examples/waitForPairingExample.ts",
|
|
78
79
|
"pack": "npm pack",
|
|
79
80
|
"test": "vitest run",
|
|
80
81
|
"test:watch": "vitest"
|
package/scripts/prepare-ios.ts
CHANGED
|
@@ -9,15 +9,15 @@ import { fileURLToPath } from "node:url";
|
|
|
9
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
10
|
const __dirname = path.dirname(__filename);
|
|
11
11
|
|
|
12
|
-
const PACKAGE_ROOT = path.resolve(__dirname, "..");
|
|
13
|
-
const
|
|
12
|
+
const PACKAGE_ROOT = process.env.PACKAGE_ROOT ?? path.resolve(__dirname, "..");
|
|
13
|
+
const DESTINATION_DIR = process.env.DESTINATION_DIR ?? path.join(PACKAGE_ROOT, "resources");
|
|
14
14
|
const GO_IOS_DIST_DIR = path.join(PACKAGE_ROOT, "node_modules", "go-ios", "dist");
|
|
15
15
|
|
|
16
16
|
const WINTUN_VERSION = "0.14.1";
|
|
17
17
|
const WINTUN_ZIP_NAME = `wintun-${WINTUN_VERSION}.zip`;
|
|
18
18
|
const WINTUN_URL = `https://www.wintun.net/builds/${WINTUN_ZIP_NAME}`;
|
|
19
|
-
const WINTUN_ZIP_PATH = path.join(
|
|
20
|
-
const WINTUN_EXTRACT_DIR = path.join(
|
|
19
|
+
const WINTUN_ZIP_PATH = path.join(DESTINATION_DIR, WINTUN_ZIP_NAME);
|
|
20
|
+
const WINTUN_EXTRACT_DIR = path.join(DESTINATION_DIR, ".wintun-extract");
|
|
21
21
|
|
|
22
22
|
async function pathExists(targetPath: string): Promise<boolean> {
|
|
23
23
|
try {
|
|
@@ -180,7 +180,7 @@ async function copyGoIosBinary(): Promise<void> {
|
|
|
180
180
|
if (!(await pathExists(sourcePath))) {
|
|
181
181
|
throw new Error(`go-ios binary not found: ${sourcePath}`);
|
|
182
182
|
}
|
|
183
|
-
await copyFile(sourcePath, path.join(
|
|
183
|
+
await copyFile(sourcePath, path.join(DESTINATION_DIR, destinationName));
|
|
184
184
|
console.log(`Copied go-ios binary to resources/${destinationName}`);
|
|
185
185
|
}
|
|
186
186
|
|
|
@@ -201,17 +201,17 @@ async function copyWintunDll(): Promise<void> {
|
|
|
201
201
|
throw new Error(`wintun.dll not found after extraction: ${dllPath}`);
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
await copyFile(dllPath, path.join(
|
|
204
|
+
await copyFile(dllPath, path.join(DESTINATION_DIR, "wintun.dll"));
|
|
205
205
|
console.log(`Copied wintun.dll (${archFolder}) to resources/`);
|
|
206
206
|
|
|
207
207
|
if (await pathExists(licensePath)) {
|
|
208
|
-
await copyFile(licensePath, path.join(
|
|
208
|
+
await copyFile(licensePath, path.join(DESTINATION_DIR, "wintun-LICENSE.txt"));
|
|
209
209
|
console.log("Copied Wintun license to resources/wintun-LICENSE.txt");
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
async function main(): Promise<void> {
|
|
214
|
-
await mkdir(
|
|
214
|
+
await mkdir(DESTINATION_DIR, { recursive: true });
|
|
215
215
|
await copyGoIosBinary();
|
|
216
216
|
await copyWintunDll();
|
|
217
217
|
}
|