appium-ios-remotexpc 0.0.3 → 0.0.5
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/CHANGELOG.md +12 -0
- package/build/src/base-plist-service.d.ts +51 -0
- package/build/src/base-plist-service.d.ts.map +1 -0
- package/build/src/base-plist-service.js +61 -0
- package/build/src/base-socket-service.d.ts +15 -0
- package/build/src/base-socket-service.d.ts.map +1 -0
- package/build/src/base-socket-service.js +46 -0
- package/build/src/index.d.ts +9 -0
- package/build/src/index.d.ts.map +1 -0
- package/build/src/index.js +7 -0
- package/build/src/lib/apple-tv/constants.d.ts +77 -0
- package/build/src/lib/apple-tv/constants.d.ts.map +1 -0
- package/build/src/lib/apple-tv/constants.js +106 -0
- package/build/src/lib/apple-tv/encryption/chacha20-poly1305.d.ts +22 -0
- package/build/src/lib/apple-tv/encryption/chacha20-poly1305.d.ts.map +1 -0
- package/build/src/lib/apple-tv/encryption/chacha20-poly1305.js +97 -0
- package/build/src/lib/apple-tv/encryption/ed25519.d.ts +16 -0
- package/build/src/lib/apple-tv/encryption/ed25519.d.ts.map +1 -0
- package/build/src/lib/apple-tv/encryption/ed25519.js +93 -0
- package/build/src/lib/apple-tv/encryption/hkdf.d.ts +18 -0
- package/build/src/lib/apple-tv/encryption/hkdf.d.ts.map +1 -0
- package/build/src/lib/apple-tv/encryption/hkdf.js +73 -0
- package/build/src/lib/apple-tv/encryption/index.d.ts +5 -0
- package/build/src/lib/apple-tv/encryption/index.d.ts.map +1 -0
- package/build/src/lib/apple-tv/encryption/index.js +4 -0
- package/build/src/lib/apple-tv/encryption/opack2.d.ts +57 -0
- package/build/src/lib/apple-tv/encryption/opack2.d.ts.map +1 -0
- package/build/src/lib/apple-tv/encryption/opack2.js +203 -0
- package/build/src/lib/apple-tv/errors.d.ts +17 -0
- package/build/src/lib/apple-tv/errors.d.ts.map +1 -0
- package/build/src/lib/apple-tv/errors.js +30 -0
- package/build/src/lib/apple-tv/tlv/decoder.d.ts +19 -0
- package/build/src/lib/apple-tv/tlv/decoder.d.ts.map +1 -0
- package/build/src/lib/apple-tv/tlv/decoder.js +49 -0
- package/build/src/lib/apple-tv/tlv/encoder.d.ts +10 -0
- package/build/src/lib/apple-tv/tlv/encoder.d.ts.map +1 -0
- package/build/src/lib/apple-tv/tlv/encoder.js +20 -0
- package/build/src/lib/apple-tv/tlv/index.d.ts +4 -0
- package/build/src/lib/apple-tv/tlv/index.d.ts.map +1 -0
- package/build/src/lib/apple-tv/tlv/index.js +3 -0
- package/build/src/lib/apple-tv/tlv/pairing-tlv.d.ts +14 -0
- package/build/src/lib/apple-tv/tlv/pairing-tlv.d.ts.map +1 -0
- package/build/src/lib/apple-tv/tlv/pairing-tlv.js +27 -0
- package/build/src/lib/apple-tv/types.d.ts +36 -0
- package/build/src/lib/apple-tv/types.d.ts.map +1 -0
- package/build/src/lib/apple-tv/types.js +1 -0
- package/build/src/lib/apple-tv/utils/buffer-utils.d.ts +40 -0
- package/build/src/lib/apple-tv/utils/buffer-utils.d.ts.map +1 -0
- package/build/src/lib/apple-tv/utils/buffer-utils.js +76 -0
- package/build/src/lib/apple-tv/utils/index.d.ts +3 -0
- package/build/src/lib/apple-tv/utils/index.d.ts.map +1 -0
- package/build/src/lib/apple-tv/utils/index.js +2 -0
- package/build/src/lib/apple-tv/utils/uuid-generator.d.ts +9 -0
- package/build/src/lib/apple-tv/utils/uuid-generator.d.ts.map +1 -0
- package/build/src/lib/apple-tv/utils/uuid-generator.js +36 -0
- package/build/src/lib/lockdown/index.d.ts +87 -0
- package/build/src/lib/lockdown/index.d.ts.map +1 -0
- package/build/src/lib/lockdown/index.js +324 -0
- package/build/src/lib/pair-record/index.d.ts +3 -0
- package/build/src/lib/pair-record/index.d.ts.map +1 -0
- package/build/src/lib/pair-record/index.js +2 -0
- package/build/src/lib/pair-record/pair-record.d.ts +48 -0
- package/build/src/lib/pair-record/pair-record.d.ts.map +1 -0
- package/build/src/lib/pair-record/pair-record.js +85 -0
- package/build/src/lib/plist/binary-plist-creator.d.ts +14 -0
- package/build/src/lib/plist/binary-plist-creator.d.ts.map +1 -0
- package/build/src/lib/plist/binary-plist-creator.js +475 -0
- package/build/src/lib/plist/binary-plist-parser.d.ts +14 -0
- package/build/src/lib/plist/binary-plist-parser.d.ts.map +1 -0
- package/build/src/lib/plist/binary-plist-parser.js +449 -0
- package/build/src/lib/plist/constants.d.ts +36 -0
- package/build/src/lib/plist/constants.d.ts.map +1 -0
- package/build/src/lib/plist/constants.js +43 -0
- package/build/src/lib/plist/index.d.ts +14 -0
- package/build/src/lib/plist/index.d.ts.map +1 -0
- package/build/src/lib/plist/index.js +16 -0
- package/build/src/lib/plist/length-based-splitter.d.ts +43 -0
- package/build/src/lib/plist/length-based-splitter.d.ts.map +1 -0
- package/build/src/lib/plist/length-based-splitter.js +228 -0
- package/build/src/lib/plist/plist-creator.d.ts +8 -0
- package/build/src/lib/plist/plist-creator.d.ts.map +1 -0
- package/build/src/lib/plist/plist-creator.js +33 -0
- package/build/src/lib/plist/plist-decoder.d.ts +25 -0
- package/build/src/lib/plist/plist-decoder.d.ts.map +1 -0
- package/build/src/lib/plist/plist-decoder.js +103 -0
- package/build/src/lib/plist/plist-encoder.d.ts +10 -0
- package/build/src/lib/plist/plist-encoder.d.ts.map +1 -0
- package/build/src/lib/plist/plist-encoder.js +27 -0
- package/build/src/lib/plist/plist-parser.d.ts +9 -0
- package/build/src/lib/plist/plist-parser.d.ts.map +1 -0
- package/build/src/lib/plist/plist-parser.js +109 -0
- package/build/src/lib/plist/plist-service.d.ts +86 -0
- package/build/src/lib/plist/plist-service.d.ts.map +1 -0
- package/build/src/lib/plist/plist-service.js +180 -0
- package/build/src/lib/plist/unified-plist-creator.d.ts +9 -0
- package/build/src/lib/plist/unified-plist-creator.d.ts.map +1 -0
- package/build/src/lib/plist/unified-plist-creator.js +14 -0
- package/build/src/lib/plist/unified-plist-parser.d.ts +8 -0
- package/build/src/lib/plist/unified-plist-parser.d.ts.map +1 -0
- package/build/src/lib/plist/unified-plist-parser.js +23 -0
- package/build/src/lib/plist/utils.d.ts +97 -0
- package/build/src/lib/plist/utils.d.ts.map +1 -0
- package/build/src/lib/plist/utils.js +287 -0
- package/build/src/lib/remote-xpc/constants.d.ts +20 -0
- package/build/src/lib/remote-xpc/constants.d.ts.map +1 -0
- package/build/src/lib/remote-xpc/constants.js +21 -0
- package/build/src/lib/remote-xpc/handshake-frames.d.ts +74 -0
- package/build/src/lib/remote-xpc/handshake-frames.d.ts.map +1 -0
- package/build/src/lib/remote-xpc/handshake-frames.js +285 -0
- package/build/src/lib/remote-xpc/handshake.d.ts +14 -0
- package/build/src/lib/remote-xpc/handshake.d.ts.map +1 -0
- package/build/src/lib/remote-xpc/handshake.js +95 -0
- package/build/src/lib/remote-xpc/remote-xpc-connection.d.ts +55 -0
- package/build/src/lib/remote-xpc/remote-xpc-connection.d.ts.map +1 -0
- package/build/src/lib/remote-xpc/remote-xpc-connection.js +365 -0
- package/build/src/lib/remote-xpc/xpc-protocol.d.ts +22 -0
- package/build/src/lib/remote-xpc/xpc-protocol.d.ts.map +1 -0
- package/build/src/lib/remote-xpc/xpc-protocol.js +368 -0
- package/build/src/lib/tunnel/index.d.ts +69 -0
- package/build/src/lib/tunnel/index.d.ts.map +1 -0
- package/build/src/lib/tunnel/index.js +205 -0
- package/build/src/lib/tunnel/packet-stream-client.d.ts +46 -0
- package/build/src/lib/tunnel/packet-stream-client.d.ts.map +1 -0
- package/build/src/lib/tunnel/packet-stream-client.js +152 -0
- package/build/src/lib/tunnel/packet-stream-server.d.ts +37 -0
- package/build/src/lib/tunnel/packet-stream-server.d.ts.map +1 -0
- package/build/src/lib/tunnel/packet-stream-server.js +109 -0
- package/build/src/lib/tunnel/tunnel-api-client.d.ts +85 -0
- package/build/src/lib/tunnel/tunnel-api-client.d.ts.map +1 -0
- package/build/src/lib/tunnel/tunnel-api-client.js +207 -0
- package/build/src/lib/tunnel/tunnel-registry-server.d.ts +68 -0
- package/build/src/lib/tunnel/tunnel-registry-server.d.ts.map +1 -0
- package/build/src/lib/tunnel/tunnel-registry-server.js +351 -0
- package/build/src/lib/types.d.ts +238 -0
- package/build/src/lib/types.d.ts.map +1 -0
- package/build/src/lib/types.js +4 -0
- package/build/src/lib/usbmux/index.d.ts +177 -0
- package/build/src/lib/usbmux/index.d.ts.map +1 -0
- package/build/src/lib/usbmux/index.js +490 -0
- package/build/src/lib/usbmux/usbmux-decoder.d.ts +19 -0
- package/build/src/lib/usbmux/usbmux-decoder.d.ts.map +1 -0
- package/build/src/lib/usbmux/usbmux-decoder.js +38 -0
- package/build/src/lib/usbmux/usbmux-encoder.d.ts +12 -0
- package/build/src/lib/usbmux/usbmux-encoder.d.ts.map +1 -0
- package/build/src/lib/usbmux/usbmux-encoder.js +32 -0
- package/build/src/service-connection.d.ts +34 -0
- package/build/src/service-connection.d.ts.map +1 -0
- package/build/src/service-connection.js +51 -0
- package/build/src/services/index.d.ts +6 -0
- package/build/src/services/index.d.ts.map +1 -0
- package/build/src/services/index.js +5 -0
- package/build/src/services/ios/base-service.d.ts +35 -0
- package/build/src/services/ios/base-service.d.ts.map +1 -0
- package/build/src/services/ios/base-service.js +55 -0
- package/build/src/services/ios/diagnostic-service/index.d.ts +46 -0
- package/build/src/services/ios/diagnostic-service/index.d.ts.map +1 -0
- package/build/src/services/ios/diagnostic-service/index.js +169 -0
- package/build/src/services/ios/diagnostic-service/keys.d.ts +5 -0
- package/build/src/services/ios/diagnostic-service/keys.d.ts.map +1 -0
- package/build/src/services/ios/diagnostic-service/keys.js +770 -0
- package/build/src/services/ios/syslog-service/index.d.ts +91 -0
- package/build/src/services/ios/syslog-service/index.d.ts.map +1 -0
- package/build/src/services/ios/syslog-service/index.js +323 -0
- package/build/src/services/ios/tunnel-service/index.d.ts +17 -0
- package/build/src/services/ios/tunnel-service/index.d.ts.map +1 -0
- package/build/src/services/ios/tunnel-service/index.js +57 -0
- package/build/src/services.d.ts +14 -0
- package/build/src/services.d.ts.map +1 -0
- package/build/src/services.js +48 -0
- package/package.json +12 -3
- package/src/lib/apple-tv/constants.ts +42 -0
- package/src/lib/apple-tv/encryption/chacha20-poly1305.ts +147 -0
- package/src/lib/apple-tv/encryption/ed25519.ts +126 -0
- package/src/lib/apple-tv/encryption/hkdf.ts +95 -0
- package/src/lib/apple-tv/encryption/index.ts +11 -0
- package/src/lib/apple-tv/encryption/opack2.ts +257 -0
- package/.github/dependabot.yml +0 -38
- package/.github/workflows/format-check.yml +0 -43
- package/.github/workflows/lint-and-build.yml +0 -40
- package/.github/workflows/pr-title.yml +0 -16
- package/.github/workflows/publish.js.yml +0 -43
- package/.github/workflows/test-validation.yml +0 -40
- package/.mocharc.json +0 -8
- package/.prettierignore +0 -3
- package/.prettierrc +0 -17
- package/.releaserc +0 -48
- package/assets/images/ios-arch.png +0 -0
- package/eslint.config.js +0 -45
- package/npm-shrinkwrap.json +0 -2711
- package/test/integration/diagnostics-test.ts +0 -44
- package/test/integration/read-pair-record-test.ts +0 -39
- package/test/integration/tunnel-test.ts +0 -104
- package/test/unit/apple-tv/tlv/decoder.spec.ts +0 -144
- package/test/unit/apple-tv/tlv/encoder.spec.ts +0 -91
- package/test/unit/apple-tv/tlv/pairing-tlv.spec.ts +0 -101
- package/test/unit/apple-tv/tlv/tlv-integration.spec.ts +0 -146
- package/test/unit/apple-tv/utils/buffer-utils.spec.ts +0 -74
- package/test/unit/apple-tv/utils/uuid-generator.spec.ts +0 -39
- package/test/unit/fixtures/index.ts +0 -88
- package/test/unit/fixtures/usbmuxconnectmessage.bin +0 -0
- package/test/unit/fixtures/usbmuxlistdevicemessage.bin +0 -0
- package/test/unit/plist/error-handling.spec.ts +0 -101
- package/test/unit/plist/fixtures/sample.binary.plist +0 -0
- package/test/unit/plist/fixtures/sample.xml.plist +0 -38
- package/test/unit/plist/plist-parser.spec.ts +0 -283
- package/test/unit/plist/plist.spec.ts +0 -205
- package/test/unit/plist/tag-position-handling.spec.ts +0 -90
- package/test/unit/plist/unified-plist-parser.spec.ts +0 -227
- package/test/unit/plist/utils.spec.ts +0 -249
- package/test/unit/plist/xml-cleaning.spec.ts +0 -60
- package/test/unit/tunnel/tunnel-registry-server.spec.ts +0 -194
- package/test/unit/usbmux/usbmux-specs.ts +0 -71
- package/tsconfig.json +0 -36
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { Socket } from 'node:net';
|
|
2
|
+
import { BaseSocketService } from '../../base-socket-service.js';
|
|
3
|
+
import { type PairRecord } from '../pair-record/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* Interface for device properties
|
|
6
|
+
*/
|
|
7
|
+
export interface DeviceProperties {
|
|
8
|
+
ConnectionSpeed: number;
|
|
9
|
+
ConnectionType: string;
|
|
10
|
+
DeviceID: number;
|
|
11
|
+
LocationID: number;
|
|
12
|
+
ProductID: number;
|
|
13
|
+
SerialNumber: string;
|
|
14
|
+
USBSerialNumber: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Interface for a device
|
|
18
|
+
*/
|
|
19
|
+
export interface Device {
|
|
20
|
+
DeviceID: number;
|
|
21
|
+
MessageType: string;
|
|
22
|
+
Properties: DeviceProperties;
|
|
23
|
+
}
|
|
24
|
+
export declare const USBMUXD_PORT = 27015;
|
|
25
|
+
export declare const DEFAULT_USBMUXD_SOCKET = "/var/run/usbmuxd";
|
|
26
|
+
export declare const DEFAULT_USBMUXD_HOST = "127.0.0.1";
|
|
27
|
+
export declare const MAX_FRAME_SIZE: number;
|
|
28
|
+
export declare const USBMUX_RESULT: {
|
|
29
|
+
OK: number;
|
|
30
|
+
BADCOMMAND: number;
|
|
31
|
+
BADDEV: number;
|
|
32
|
+
CONNREFUSED: number;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Function to swap bytes for a 16-bit value
|
|
36
|
+
* Used for usbmuxd port numbers
|
|
37
|
+
*/
|
|
38
|
+
export declare function byteSwap16(value: number): number;
|
|
39
|
+
/**
|
|
40
|
+
* Socket options for connecting to usbmuxd
|
|
41
|
+
*/
|
|
42
|
+
export interface SocketOptions {
|
|
43
|
+
socketPath?: string;
|
|
44
|
+
socketPort?: number;
|
|
45
|
+
socketHost?: string;
|
|
46
|
+
timeout?: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Connects a socket to usbmuxd service
|
|
50
|
+
* @param opts - Connection options
|
|
51
|
+
* @returns Promise that resolves with a socket connected to usbmuxd
|
|
52
|
+
*/
|
|
53
|
+
export declare function getDefaultSocket(opts?: Partial<SocketOptions>): Promise<Socket>;
|
|
54
|
+
/**
|
|
55
|
+
* usbmux class for communicating with usbmuxd
|
|
56
|
+
*/
|
|
57
|
+
export declare class Usbmux extends BaseSocketService {
|
|
58
|
+
private readonly _decoder;
|
|
59
|
+
private readonly _splitter;
|
|
60
|
+
private readonly _encoder;
|
|
61
|
+
private _tag;
|
|
62
|
+
private readonly _responseCallbacks;
|
|
63
|
+
/**
|
|
64
|
+
* Creates a new usbmux instance
|
|
65
|
+
* @param socketClient - Connected socket to usbmuxd
|
|
66
|
+
*/
|
|
67
|
+
constructor(socketClient: Socket);
|
|
68
|
+
/**
|
|
69
|
+
* Returns the BUID of the host computer from usbmuxd
|
|
70
|
+
* @param timeout - Timeout in milliseconds
|
|
71
|
+
* @returns Promise that resolves with the BUID
|
|
72
|
+
*/
|
|
73
|
+
readBUID(timeout?: number): Promise<string>;
|
|
74
|
+
/**
|
|
75
|
+
* Reads the pair record of a device, checking local cache first
|
|
76
|
+
* @param udid - Device UDID
|
|
77
|
+
* @param timeout - Timeout in milliseconds
|
|
78
|
+
* @returns Promise that resolves with the pair record or null if not found
|
|
79
|
+
*/
|
|
80
|
+
readPairRecord(udid: string, timeout?: number): Promise<PairRecord | null>;
|
|
81
|
+
/**
|
|
82
|
+
* Lists all devices connected to the host
|
|
83
|
+
* @param timeout - Timeout in milliseconds
|
|
84
|
+
* @returns Promise that resolves with the device list
|
|
85
|
+
*/
|
|
86
|
+
listDevices(timeout?: number): Promise<Device[]>;
|
|
87
|
+
/**
|
|
88
|
+
* Looks for a device with the passed udid
|
|
89
|
+
* @param udid - Device UDID
|
|
90
|
+
* @param timeout - Timeout in milliseconds
|
|
91
|
+
* @returns Promise that resolves with the device or undefined if not found
|
|
92
|
+
*/
|
|
93
|
+
findDevice(udid: string, timeout?: number): Promise<Device | undefined>;
|
|
94
|
+
/**
|
|
95
|
+
* Connects to a certain port on the device
|
|
96
|
+
* @param deviceID - Device ID
|
|
97
|
+
* @param port - Port to connect to
|
|
98
|
+
* @param timeout - Timeout in milliseconds
|
|
99
|
+
* @returns Promise that resolves with the connected socket
|
|
100
|
+
*/
|
|
101
|
+
connect(deviceID: string | number, port: number, timeout?: number): Promise<Socket>;
|
|
102
|
+
/**
|
|
103
|
+
* Closes the current USBMUX connection gracefully.
|
|
104
|
+
* For non-tunnel commands, call this after the operation is complete.
|
|
105
|
+
* For Connect commands (which consume the connection),
|
|
106
|
+
* the caller is responsible for closing the returned socket.
|
|
107
|
+
*
|
|
108
|
+
* @returns Promise that resolves when the socket is closed.
|
|
109
|
+
*/
|
|
110
|
+
close(): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Handles incoming data from the decoder
|
|
113
|
+
* @param data - Decoded data
|
|
114
|
+
* @private
|
|
115
|
+
*/
|
|
116
|
+
private _handleData;
|
|
117
|
+
/**
|
|
118
|
+
* Sends a plist to usbmuxd
|
|
119
|
+
* @param json - JSON object with tag and payload
|
|
120
|
+
* @private
|
|
121
|
+
*/
|
|
122
|
+
private _sendPlist;
|
|
123
|
+
/**
|
|
124
|
+
* Sets up a promise to receive and process a plist response
|
|
125
|
+
* @param timeout - Timeout in milliseconds
|
|
126
|
+
* @param responseCallback - Callback to process the response
|
|
127
|
+
* @returns Object with tag and promise
|
|
128
|
+
* @private
|
|
129
|
+
*/
|
|
130
|
+
private _receivePlistPromise;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Creates a new usbmux instance
|
|
134
|
+
* @param opts - Socket options
|
|
135
|
+
* @returns Promise that resolves with a usbmux instance
|
|
136
|
+
*/
|
|
137
|
+
export declare function createUsbmux(opts?: Partial<SocketOptions>): Promise<Usbmux>;
|
|
138
|
+
/**
|
|
139
|
+
* RelayService class for tunneling connections through a local TCP server
|
|
140
|
+
*/
|
|
141
|
+
export declare class RelayService {
|
|
142
|
+
private readonly deviceID;
|
|
143
|
+
private readonly devicePort;
|
|
144
|
+
private readonly relayPort;
|
|
145
|
+
private usbmuxClient;
|
|
146
|
+
private server;
|
|
147
|
+
/**
|
|
148
|
+
* Creates a new RelayService instance
|
|
149
|
+
* @param deviceID - The device ID to connect to
|
|
150
|
+
* @param devicePort - The port on the device to connect to
|
|
151
|
+
* @param relayPort - The local port to use for the relay server
|
|
152
|
+
*/
|
|
153
|
+
constructor(deviceID: string | number, devicePort: number, relayPort?: number);
|
|
154
|
+
/**
|
|
155
|
+
* Starts the relay service
|
|
156
|
+
* @returns Promise that resolves when the relay is set up
|
|
157
|
+
*/
|
|
158
|
+
start(): Promise<void>;
|
|
159
|
+
/**
|
|
160
|
+
* Connects to the relay service
|
|
161
|
+
* @returns Promise that resolves with a socket connected to the relay
|
|
162
|
+
*/
|
|
163
|
+
connect(): Promise<Socket>;
|
|
164
|
+
/**
|
|
165
|
+
* Stops the relay service
|
|
166
|
+
*/
|
|
167
|
+
stop(): Promise<void>;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Connects to a device and sets up a relay service in one operation
|
|
171
|
+
* @param deviceID - The device ID to connect to
|
|
172
|
+
* @param port - The port on the device to connect to
|
|
173
|
+
* @param relayPort - The local port to use for the relay server
|
|
174
|
+
* @returns Promise that resolves with a connected socket
|
|
175
|
+
*/
|
|
176
|
+
export declare function connectAndRelay(deviceID: string | number, port: number, relayPort?: number): Promise<Socket>;
|
|
177
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/usbmux/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
import { logger } from '@appium/support';
|
|
2
|
+
import { Server, Socket, createConnection, createServer } from 'node:net';
|
|
3
|
+
import { release } from 'node:os';
|
|
4
|
+
import { BaseSocketService } from '../../base-socket-service.js';
|
|
5
|
+
import { processPlistResponse } from '../pair-record/index.js';
|
|
6
|
+
import {} from '../pair-record/pair-record.js';
|
|
7
|
+
import { LengthBasedSplitter, parsePlist } from '../plist/index.js';
|
|
8
|
+
import { UsbmuxDecoder } from '../usbmux/usbmux-decoder.js';
|
|
9
|
+
import { UsbmuxEncoder } from '../usbmux/usbmux-encoder.js';
|
|
10
|
+
const log = logger.getLogger('Usbmux');
|
|
11
|
+
export const USBMUXD_PORT = 27015;
|
|
12
|
+
export const DEFAULT_USBMUXD_SOCKET = '/var/run/usbmuxd';
|
|
13
|
+
export const DEFAULT_USBMUXD_HOST = '127.0.0.1';
|
|
14
|
+
export const MAX_FRAME_SIZE = 100 * 1024 * 1024; // 1MB
|
|
15
|
+
// Result codes from usbmuxd
|
|
16
|
+
export const USBMUX_RESULT = {
|
|
17
|
+
OK: 0,
|
|
18
|
+
BADCOMMAND: 1,
|
|
19
|
+
BADDEV: 2,
|
|
20
|
+
CONNREFUSED: 3,
|
|
21
|
+
};
|
|
22
|
+
// Package info for client identification
|
|
23
|
+
const PROG_NAME = 'appium-internal';
|
|
24
|
+
const CLIENT_VERSION_STRING = 'appium-internal-1.0.0';
|
|
25
|
+
/**
|
|
26
|
+
* Function to swap bytes for a 16-bit value
|
|
27
|
+
* Used for usbmuxd port numbers
|
|
28
|
+
*/
|
|
29
|
+
export function byteSwap16(value) {
|
|
30
|
+
return ((value & 0xff) << 8) | ((value >> 8) & 0xff);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Helper function to check if a file exists
|
|
34
|
+
* @param path - Path to check
|
|
35
|
+
* @returns Boolean indicating if the file exists
|
|
36
|
+
*/
|
|
37
|
+
async function fileExists(path) {
|
|
38
|
+
try {
|
|
39
|
+
await import('fs').then((fs) => fs.promises.access(path));
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Connects a socket to usbmuxd service
|
|
48
|
+
* @param opts - Connection options
|
|
49
|
+
* @returns Promise that resolves with a socket connected to usbmuxd
|
|
50
|
+
*/
|
|
51
|
+
export async function getDefaultSocket(opts = {}) {
|
|
52
|
+
const defaults = {
|
|
53
|
+
socketPath: DEFAULT_USBMUXD_SOCKET,
|
|
54
|
+
socketPort: USBMUXD_PORT,
|
|
55
|
+
socketHost: DEFAULT_USBMUXD_HOST,
|
|
56
|
+
timeout: 5000,
|
|
57
|
+
};
|
|
58
|
+
if (process.env.USBMUXD_SOCKET_ADDRESS &&
|
|
59
|
+
!opts.socketPath &&
|
|
60
|
+
!opts.socketPort &&
|
|
61
|
+
!opts.socketHost) {
|
|
62
|
+
log.debug(`Using USBMUXD_SOCKET_ADDRESS environment variable as default socket: ${process.env.USBMUXD_SOCKET_ADDRESS}`);
|
|
63
|
+
// "unix:" or "UNIX:" prefix is optional for unix socket paths.
|
|
64
|
+
const usbmuxdSocketAddress = process.env.USBMUXD_SOCKET_ADDRESS.replace(/^(unix):/i, '');
|
|
65
|
+
const [ip, port] = usbmuxdSocketAddress.split(':');
|
|
66
|
+
if (ip && port) {
|
|
67
|
+
defaults.socketHost = ip;
|
|
68
|
+
defaults.socketPort = parseInt(port, 10);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
defaults.socketPath = usbmuxdSocketAddress;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const { socketPath, socketPort, socketHost, timeout } = {
|
|
75
|
+
...defaults,
|
|
76
|
+
...opts,
|
|
77
|
+
};
|
|
78
|
+
let socket;
|
|
79
|
+
if (await fileExists(socketPath ?? '')) {
|
|
80
|
+
socket = createConnection(socketPath ?? '');
|
|
81
|
+
}
|
|
82
|
+
else if (process.platform === 'win32' ||
|
|
83
|
+
(process.platform === 'linux' && /microsoft/i.test(release()))) {
|
|
84
|
+
// Connect to usbmuxd when running on WSL1
|
|
85
|
+
socket = createConnection({
|
|
86
|
+
port: socketPort,
|
|
87
|
+
host: socketHost,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
throw new Error(`The usbmuxd socket at '${socketPath}' does not exist or is not accessible`);
|
|
92
|
+
}
|
|
93
|
+
return await new Promise((resolve, reject) => {
|
|
94
|
+
const timeoutId = setTimeout(() => {
|
|
95
|
+
socket.removeAllListeners();
|
|
96
|
+
reject(new Error(`Connection timed out after ${timeout}ms`));
|
|
97
|
+
}, timeout ?? 5000);
|
|
98
|
+
socket.once('error', (err) => {
|
|
99
|
+
clearTimeout(timeoutId);
|
|
100
|
+
reject(err);
|
|
101
|
+
});
|
|
102
|
+
socket.once('connect', () => {
|
|
103
|
+
clearTimeout(timeoutId);
|
|
104
|
+
resolve(socket);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* usbmux class for communicating with usbmuxd
|
|
110
|
+
*/
|
|
111
|
+
export class Usbmux extends BaseSocketService {
|
|
112
|
+
_decoder;
|
|
113
|
+
_splitter;
|
|
114
|
+
_encoder;
|
|
115
|
+
_tag;
|
|
116
|
+
_responseCallbacks;
|
|
117
|
+
/**
|
|
118
|
+
* Creates a new usbmux instance
|
|
119
|
+
* @param socketClient - Connected socket to usbmuxd
|
|
120
|
+
*/
|
|
121
|
+
constructor(socketClient) {
|
|
122
|
+
super(socketClient);
|
|
123
|
+
this._decoder = new UsbmuxDecoder();
|
|
124
|
+
this._splitter = new LengthBasedSplitter({
|
|
125
|
+
readableStream: socketClient,
|
|
126
|
+
littleEndian: true,
|
|
127
|
+
maxFrameLength: MAX_FRAME_SIZE,
|
|
128
|
+
lengthFieldOffset: 0,
|
|
129
|
+
lengthFieldLength: 4,
|
|
130
|
+
lengthAdjustment: 0,
|
|
131
|
+
});
|
|
132
|
+
this._socketClient.pipe(this._decoder);
|
|
133
|
+
this._encoder = new UsbmuxEncoder();
|
|
134
|
+
this._encoder.pipe(this._socketClient);
|
|
135
|
+
this._assignClientFailureHandlers(this._encoder);
|
|
136
|
+
this._tag = 0;
|
|
137
|
+
this._responseCallbacks = {};
|
|
138
|
+
this._decoder.on('data', this._handleData.bind(this));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Returns the BUID of the host computer from usbmuxd
|
|
142
|
+
* @param timeout - Timeout in milliseconds
|
|
143
|
+
* @returns Promise that resolves with the BUID
|
|
144
|
+
*/
|
|
145
|
+
async readBUID(timeout = 5000) {
|
|
146
|
+
const { tag, receivePromise } = this._receivePlistPromise(timeout, (data) => {
|
|
147
|
+
if (data.payload.BUID) {
|
|
148
|
+
return data.payload.BUID;
|
|
149
|
+
}
|
|
150
|
+
throw new Error(`Unexpected data: ${JSON.stringify(data)}`);
|
|
151
|
+
});
|
|
152
|
+
this._sendPlist({
|
|
153
|
+
tag,
|
|
154
|
+
payload: {
|
|
155
|
+
MessageType: 'ReadBUID',
|
|
156
|
+
ProgName: PROG_NAME,
|
|
157
|
+
ClientVersionString: CLIENT_VERSION_STRING,
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
return await receivePromise;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Reads the pair record of a device, checking local cache first
|
|
164
|
+
* @param udid - Device UDID
|
|
165
|
+
* @param timeout - Timeout in milliseconds
|
|
166
|
+
* @returns Promise that resolves with the pair record or null if not found
|
|
167
|
+
*/
|
|
168
|
+
async readPairRecord(udid, timeout = 5000) {
|
|
169
|
+
// Request from usbmuxd if not found in cache
|
|
170
|
+
const { tag, receivePromise } = this._receivePlistPromise(timeout, (data) => {
|
|
171
|
+
if (!data.payload.PairRecordData) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
// Parse the pair record and assert the type
|
|
176
|
+
return processPlistResponse(parsePlist(data.payload.PairRecordData));
|
|
177
|
+
}
|
|
178
|
+
catch (e) {
|
|
179
|
+
throw new Error(`Failed to parse pair record data: ${e}`);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
this._sendPlist({
|
|
183
|
+
tag,
|
|
184
|
+
payload: {
|
|
185
|
+
MessageType: 'ReadPairRecord',
|
|
186
|
+
PairRecordID: udid,
|
|
187
|
+
ProgName: PROG_NAME,
|
|
188
|
+
ClientVersionString: CLIENT_VERSION_STRING,
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
return await receivePromise;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Lists all devices connected to the host
|
|
195
|
+
* @param timeout - Timeout in milliseconds
|
|
196
|
+
* @returns Promise that resolves with the device list
|
|
197
|
+
*/
|
|
198
|
+
async listDevices(timeout = 5000) {
|
|
199
|
+
const { tag, receivePromise } = this._receivePlistPromise(timeout, (data) => {
|
|
200
|
+
if (data.payload.DeviceList) {
|
|
201
|
+
return data.payload.DeviceList;
|
|
202
|
+
}
|
|
203
|
+
throw new Error(`Unexpected data: ${JSON.stringify(data)}`);
|
|
204
|
+
});
|
|
205
|
+
this._sendPlist({
|
|
206
|
+
tag,
|
|
207
|
+
payload: {
|
|
208
|
+
MessageType: 'ListDevices',
|
|
209
|
+
ProgName: PROG_NAME,
|
|
210
|
+
ClientVersionString: CLIENT_VERSION_STRING,
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
return await receivePromise;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Looks for a device with the passed udid
|
|
217
|
+
* @param udid - Device UDID
|
|
218
|
+
* @param timeout - Timeout in milliseconds
|
|
219
|
+
* @returns Promise that resolves with the device or undefined if not found
|
|
220
|
+
*/
|
|
221
|
+
async findDevice(udid, timeout = 5000) {
|
|
222
|
+
const devices = await this.listDevices(timeout);
|
|
223
|
+
return devices.find((device) => device.Properties.SerialNumber === udid);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Connects to a certain port on the device
|
|
227
|
+
* @param deviceID - Device ID
|
|
228
|
+
* @param port - Port to connect to
|
|
229
|
+
* @param timeout - Timeout in milliseconds
|
|
230
|
+
* @returns Promise that resolves with the connected socket
|
|
231
|
+
*/
|
|
232
|
+
async connect(deviceID, port, timeout = 5000) {
|
|
233
|
+
const { tag, receivePromise } = this._receivePlistPromise(timeout, (data) => {
|
|
234
|
+
if (data.payload.MessageType !== 'Result') {
|
|
235
|
+
throw new Error(`Unexpected data: ${JSON.stringify(data)}`);
|
|
236
|
+
}
|
|
237
|
+
if (data.payload.Number === USBMUX_RESULT.OK) {
|
|
238
|
+
this._splitter.shutdown();
|
|
239
|
+
this._socketClient.unpipe(this._splitter);
|
|
240
|
+
this._splitter.unpipe(this._decoder);
|
|
241
|
+
return this._socketClient;
|
|
242
|
+
}
|
|
243
|
+
else if (data.payload.Number === USBMUX_RESULT.CONNREFUSED) {
|
|
244
|
+
throw new Error(`Connection was refused to port ${port}`);
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
throw new Error(`Connection failed with code ${data.payload.Number}`);
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
this._sendPlist({
|
|
251
|
+
tag,
|
|
252
|
+
payload: {
|
|
253
|
+
MessageType: 'Connect',
|
|
254
|
+
ProgName: PROG_NAME,
|
|
255
|
+
ClientVersionString: CLIENT_VERSION_STRING,
|
|
256
|
+
DeviceID: deviceID,
|
|
257
|
+
PortNumber: byteSwap16(port),
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
return await receivePromise;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Closes the current USBMUX connection gracefully.
|
|
264
|
+
* For non-tunnel commands, call this after the operation is complete.
|
|
265
|
+
* For Connect commands (which consume the connection),
|
|
266
|
+
* the caller is responsible for closing the returned socket.
|
|
267
|
+
*
|
|
268
|
+
* @returns Promise that resolves when the socket is closed.
|
|
269
|
+
*/
|
|
270
|
+
close() {
|
|
271
|
+
return new Promise((resolve, reject) => {
|
|
272
|
+
// If the socket is still open, end it gracefully.
|
|
273
|
+
if (!this._socketClient.destroyed) {
|
|
274
|
+
// End the connection and then destroy it once closed.
|
|
275
|
+
this._socketClient.end((err) => {
|
|
276
|
+
if (err) {
|
|
277
|
+
log.error(`Error closing usbmux socket: ${err}`);
|
|
278
|
+
this._socketClient.destroy();
|
|
279
|
+
reject(err);
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
this._socketClient.destroy();
|
|
283
|
+
resolve();
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
resolve();
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Handles incoming data from the decoder
|
|
294
|
+
* @param data - Decoded data
|
|
295
|
+
* @private
|
|
296
|
+
*/
|
|
297
|
+
_handleData(data) {
|
|
298
|
+
const cb = this._responseCallbacks[data.header.tag];
|
|
299
|
+
if (cb) {
|
|
300
|
+
cb(data);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Sends a plist to usbmuxd
|
|
305
|
+
* @param json - JSON object with tag and payload
|
|
306
|
+
* @private
|
|
307
|
+
*/
|
|
308
|
+
_sendPlist(json) {
|
|
309
|
+
this._encoder.write(json);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Sets up a promise to receive and process a plist response
|
|
313
|
+
* @param timeout - Timeout in milliseconds
|
|
314
|
+
* @param responseCallback - Callback to process the response
|
|
315
|
+
* @returns Object with tag and promise
|
|
316
|
+
* @private
|
|
317
|
+
*/
|
|
318
|
+
_receivePlistPromise(timeout = 5000, responseCallback) {
|
|
319
|
+
const tag = this._tag++;
|
|
320
|
+
let timeoutId;
|
|
321
|
+
const receivePromise = new Promise((resolve, reject) => {
|
|
322
|
+
this._responseCallbacks[tag] = (data) => {
|
|
323
|
+
try {
|
|
324
|
+
// Clear the timeout to prevent it from triggering
|
|
325
|
+
if (timeoutId) {
|
|
326
|
+
clearTimeout(timeoutId);
|
|
327
|
+
}
|
|
328
|
+
// Process the response
|
|
329
|
+
resolve(responseCallback(data));
|
|
330
|
+
}
|
|
331
|
+
catch (e) {
|
|
332
|
+
reject(e);
|
|
333
|
+
}
|
|
334
|
+
finally {
|
|
335
|
+
delete this._responseCallbacks[tag];
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
// Set the timeout handler
|
|
339
|
+
timeoutId = setTimeout(() => {
|
|
340
|
+
if (this._responseCallbacks[tag]) {
|
|
341
|
+
delete this._responseCallbacks[tag];
|
|
342
|
+
log.warn(`Timeout waiting for response with tag ${tag} after ${timeout}ms`);
|
|
343
|
+
reject(new Error(`Failed to receive any data within the timeout: ${timeout}ms - The device might be busy or unresponsive`));
|
|
344
|
+
}
|
|
345
|
+
}, timeout);
|
|
346
|
+
});
|
|
347
|
+
// Add cleanup handler when promise is settled
|
|
348
|
+
receivePromise
|
|
349
|
+
.catch(() => { })
|
|
350
|
+
.finally(() => {
|
|
351
|
+
if (this._responseCallbacks[tag]) {
|
|
352
|
+
delete this._responseCallbacks[tag];
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
return { tag, receivePromise };
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Creates a new usbmux instance
|
|
360
|
+
* @param opts - Socket options
|
|
361
|
+
* @returns Promise that resolves with a usbmux instance
|
|
362
|
+
*/
|
|
363
|
+
export async function createUsbmux(opts = {}) {
|
|
364
|
+
const socket = await getDefaultSocket(opts);
|
|
365
|
+
return new Usbmux(socket);
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* RelayService class for tunneling connections through a local TCP server
|
|
369
|
+
*/
|
|
370
|
+
export class RelayService {
|
|
371
|
+
deviceID;
|
|
372
|
+
devicePort;
|
|
373
|
+
relayPort;
|
|
374
|
+
usbmuxClient;
|
|
375
|
+
server;
|
|
376
|
+
/**
|
|
377
|
+
* Creates a new RelayService instance
|
|
378
|
+
* @param deviceID - The device ID to connect to
|
|
379
|
+
* @param devicePort - The port on the device to connect to
|
|
380
|
+
* @param relayPort - The local port to use for the relay server
|
|
381
|
+
*/
|
|
382
|
+
constructor(deviceID, devicePort, relayPort = 2222) {
|
|
383
|
+
this.deviceID = deviceID;
|
|
384
|
+
this.devicePort = devicePort;
|
|
385
|
+
this.relayPort = relayPort;
|
|
386
|
+
this.usbmuxClient = null;
|
|
387
|
+
this.server = null;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Starts the relay service
|
|
391
|
+
* @returns Promise that resolves when the relay is set up
|
|
392
|
+
*/
|
|
393
|
+
async start() {
|
|
394
|
+
log.info(`Starting relay to device ${this.deviceID} on port ${this.devicePort}...`);
|
|
395
|
+
// Create a usbmux instance and connect to the device
|
|
396
|
+
const usbmux = await createUsbmux();
|
|
397
|
+
this.usbmuxClient = await usbmux.connect(this.deviceID, this.devicePort);
|
|
398
|
+
// Set up the relay server
|
|
399
|
+
this.server = createServer((localSocket) => {
|
|
400
|
+
log.debug('🔌 Local client connected to relay!');
|
|
401
|
+
// Set up the bidirectional pipe between local socket and usbmux connection
|
|
402
|
+
if (this.usbmuxClient) {
|
|
403
|
+
localSocket.pipe(this.usbmuxClient).pipe(localSocket);
|
|
404
|
+
}
|
|
405
|
+
// Handle socket events
|
|
406
|
+
localSocket.on('close', () => {
|
|
407
|
+
log.debug('Local connection closed (tunnel remains open).');
|
|
408
|
+
});
|
|
409
|
+
localSocket.on('error', (err) => {
|
|
410
|
+
log.error(`Local socket error: ${err}`);
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
// Start the server
|
|
414
|
+
await new Promise((resolve, reject) => {
|
|
415
|
+
if (!this.server) {
|
|
416
|
+
return reject(new Error('Server not initialized'));
|
|
417
|
+
}
|
|
418
|
+
this.server.listen(this.relayPort, () => {
|
|
419
|
+
log.info(`Relay server running on localhost:${this.relayPort}`);
|
|
420
|
+
resolve();
|
|
421
|
+
});
|
|
422
|
+
this.server.on('error', (err) => {
|
|
423
|
+
reject(err);
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Connects to the relay service
|
|
429
|
+
* @returns Promise that resolves with a socket connected to the relay
|
|
430
|
+
*/
|
|
431
|
+
async connect() {
|
|
432
|
+
return new Promise((resolve, reject) => {
|
|
433
|
+
const socket = createConnection({ host: '127.0.0.1', port: this.relayPort }, () => {
|
|
434
|
+
log.debug('Connected to service via local relay.');
|
|
435
|
+
resolve(socket);
|
|
436
|
+
});
|
|
437
|
+
socket.on('error', (err) => {
|
|
438
|
+
reject(err);
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Stops the relay service
|
|
444
|
+
*/
|
|
445
|
+
async stop() {
|
|
446
|
+
return new Promise((resolve, reject) => {
|
|
447
|
+
if (this.server) {
|
|
448
|
+
this.server.close((err) => {
|
|
449
|
+
if (err) {
|
|
450
|
+
log.error(`Error stopping relay server: ${err}`);
|
|
451
|
+
reject(err);
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
log.info('Relay server stopped');
|
|
455
|
+
resolve();
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
resolve();
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Connects to a device and sets up a relay service in one operation
|
|
467
|
+
* @param deviceID - The device ID to connect to
|
|
468
|
+
* @param port - The port on the device to connect to
|
|
469
|
+
* @param relayPort - The local port to use for the relay server
|
|
470
|
+
* @returns Promise that resolves with a connected socket
|
|
471
|
+
*/
|
|
472
|
+
export async function connectAndRelay(deviceID, port, relayPort = 2222) {
|
|
473
|
+
// Create and start the relay service
|
|
474
|
+
const relay = new RelayService(deviceID, port, relayPort);
|
|
475
|
+
let socket;
|
|
476
|
+
try {
|
|
477
|
+
// Start the relay
|
|
478
|
+
await relay.start();
|
|
479
|
+
// Connect to the relay
|
|
480
|
+
socket = await relay.connect();
|
|
481
|
+
return socket;
|
|
482
|
+
}
|
|
483
|
+
finally {
|
|
484
|
+
if (!socket) {
|
|
485
|
+
await relay
|
|
486
|
+
.stop()
|
|
487
|
+
.catch((err) => log.error(`Error stopping relay: ${err}`));
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Transform, type TransformCallback } from 'stream';
|
|
2
|
+
import type { PlistDictionary } from '../types.js';
|
|
3
|
+
export interface UsbmuxHeader {
|
|
4
|
+
length: number;
|
|
5
|
+
version: number;
|
|
6
|
+
type: number;
|
|
7
|
+
tag: number;
|
|
8
|
+
}
|
|
9
|
+
export interface DecodedUsbmux {
|
|
10
|
+
header: UsbmuxHeader;
|
|
11
|
+
payload: PlistDictionary;
|
|
12
|
+
}
|
|
13
|
+
export declare class UsbmuxDecoder extends Transform {
|
|
14
|
+
private _buffer;
|
|
15
|
+
constructor();
|
|
16
|
+
_transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void;
|
|
17
|
+
private _decode;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=usbmux-decoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usbmux-decoder.d.ts","sourceRoot":"","sources":["../../../../src/lib/usbmux/usbmux-decoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAG3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAInD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,eAAe,CAAC;CAC1B;AAED,qBAAa,aAAc,SAAQ,SAAS;IAC1C,OAAO,CAAC,OAAO,CAA2B;;IAM1C,UAAU,CACR,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,iBAAiB,GAC1B,IAAI;IAwBP,OAAO,CAAC,OAAO;CAWhB"}
|