appium-ios-remotexpc 0.0.5 → 0.1.0
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/index.d.ts +1 -1
- package/build/src/index.d.ts.map +1 -1
- package/build/src/lib/apple-tv/srp/crypto-utils.d.ts +53 -0
- package/build/src/lib/apple-tv/srp/crypto-utils.d.ts.map +1 -0
- package/build/src/lib/apple-tv/srp/crypto-utils.js +128 -0
- package/build/src/lib/apple-tv/srp/index.d.ts +3 -0
- package/build/src/lib/apple-tv/srp/index.d.ts.map +1 -0
- package/build/src/lib/apple-tv/srp/index.js +2 -0
- package/build/src/lib/apple-tv/srp/srp-client.d.ts +130 -0
- package/build/src/lib/apple-tv/srp/srp-client.d.ts.map +1 -0
- package/build/src/lib/apple-tv/srp/srp-client.js +288 -0
- package/build/src/lib/remote-xpc/remote-xpc-connection.d.ts +1 -2
- package/build/src/lib/remote-xpc/remote-xpc-connection.d.ts.map +1 -1
- package/build/src/lib/remote-xpc/remote-xpc-connection.js +1 -2
- package/build/src/lib/tunnel/index.d.ts +3 -2
- package/build/src/lib/tunnel/index.d.ts.map +1 -1
- package/build/src/lib/tunnel/index.js +6 -3
- package/build/src/lib/types.d.ts +11 -0
- package/build/src/lib/types.d.ts.map +1 -1
- package/build/src/services/ios/diagnostic-service/index.d.ts.map +1 -1
- package/build/src/services/ios/diagnostic-service/index.js +0 -1
- package/build/src/services.d.ts +3 -3
- package/build/src/services.d.ts.map +1 -1
- package/build/src/services.js +8 -5
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/lib/apple-tv/srp/crypto-utils.ts +166 -0
- package/src/lib/apple-tv/srp/index.ts +8 -0
- package/src/lib/apple-tv/srp/srp-client.ts +387 -0
- package/src/lib/remote-xpc/remote-xpc-connection.ts +1 -2
- package/src/lib/tunnel/index.ts +7 -5
- package/src/lib/types.ts +12 -0
- package/src/services/ios/diagnostic-service/index.ts +0 -1
- package/src/services.ts +10 -7
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import { logger } from '@appium/support';
|
|
2
|
+
import { randomBytes } from 'node:crypto';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
SRP_GENERATOR,
|
|
6
|
+
SRP_KEY_LENGTH_BYTES,
|
|
7
|
+
SRP_PRIME_3072,
|
|
8
|
+
SRP_PRIVATE_KEY_BITS,
|
|
9
|
+
SRP_USERNAME,
|
|
10
|
+
} from '../constants.js';
|
|
11
|
+
import { SRPError } from '../errors.js';
|
|
12
|
+
import {
|
|
13
|
+
bigIntToBuffer,
|
|
14
|
+
bufferToBigInt,
|
|
15
|
+
modPow,
|
|
16
|
+
} from '../utils/buffer-utils.js';
|
|
17
|
+
import {
|
|
18
|
+
calculateK,
|
|
19
|
+
calculateM1,
|
|
20
|
+
calculateU,
|
|
21
|
+
calculateX,
|
|
22
|
+
hash,
|
|
23
|
+
} from './crypto-utils.js';
|
|
24
|
+
|
|
25
|
+
const log = logger.getLogger('SRPClient');
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* SRP (Secure Remote Password) client implementation following RFC 5054.
|
|
29
|
+
*
|
|
30
|
+
* This class handles the client-side operations of the SRP protocol,
|
|
31
|
+
* including key generation, authentication proof computation, and
|
|
32
|
+
* session key derivation.
|
|
33
|
+
*/
|
|
34
|
+
export class SRPClient {
|
|
35
|
+
// Constants
|
|
36
|
+
private static readonly ZERO = BigInt(0);
|
|
37
|
+
private static readonly ONE = BigInt(1);
|
|
38
|
+
private static readonly MAX_KEY_GENERATION_ATTEMPTS = 100;
|
|
39
|
+
|
|
40
|
+
private readonly N = SRP_PRIME_3072;
|
|
41
|
+
private readonly g = SRP_GENERATOR;
|
|
42
|
+
private readonly k: bigint;
|
|
43
|
+
private readonly N_MINUS_ONE: bigint;
|
|
44
|
+
|
|
45
|
+
private username: string;
|
|
46
|
+
private password: string;
|
|
47
|
+
private _salt: Buffer | null = null;
|
|
48
|
+
private _a: bigint = SRPClient.ZERO;
|
|
49
|
+
private _A: bigint = SRPClient.ZERO;
|
|
50
|
+
private _B: bigint | null = null;
|
|
51
|
+
private _S: bigint | null = null;
|
|
52
|
+
private _K: Buffer | null = null;
|
|
53
|
+
|
|
54
|
+
// State tracking
|
|
55
|
+
private keysGenerated = false;
|
|
56
|
+
private disposed = false;
|
|
57
|
+
|
|
58
|
+
constructor() {
|
|
59
|
+
this.k = calculateK(this.N, this.g, SRP_KEY_LENGTH_BYTES);
|
|
60
|
+
this.N_MINUS_ONE = this.N - SRPClient.ONE;
|
|
61
|
+
this.username = SRP_USERNAME;
|
|
62
|
+
this.password = '';
|
|
63
|
+
|
|
64
|
+
log.debug('Initialized SRP client with k value');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Sets the user identity credentials.
|
|
69
|
+
* Note: Username is set to SRP_USERNAME constant, but can be overridden.
|
|
70
|
+
*
|
|
71
|
+
* @param username - The username for authentication
|
|
72
|
+
* @param password - The password for authentication
|
|
73
|
+
* @throws {SRPError} If username or password is empty
|
|
74
|
+
*/
|
|
75
|
+
public setIdentity(username: string, password: string): void {
|
|
76
|
+
this.throwIfDisposed();
|
|
77
|
+
|
|
78
|
+
if (!username?.trim()) {
|
|
79
|
+
throw new SRPError('Username cannot be empty');
|
|
80
|
+
}
|
|
81
|
+
if (!password) {
|
|
82
|
+
throw new SRPError('Password cannot be empty');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
this.username = username.trim();
|
|
86
|
+
this.password = password;
|
|
87
|
+
|
|
88
|
+
log.debug('Identity set successfully');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Gets the salt value received from the server.
|
|
93
|
+
*
|
|
94
|
+
* @returns The salt buffer or null if not set
|
|
95
|
+
*/
|
|
96
|
+
get salt(): Buffer | null {
|
|
97
|
+
return this._salt;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Sets the salt value received from the server.
|
|
102
|
+
*
|
|
103
|
+
* @param value - The salt buffer from the server
|
|
104
|
+
* @throws {SRPError} If salt is empty or client is disposed
|
|
105
|
+
*/
|
|
106
|
+
set salt(value: Buffer) {
|
|
107
|
+
this.throwIfDisposed();
|
|
108
|
+
|
|
109
|
+
if (!value || value.length === 0) {
|
|
110
|
+
throw new SRPError('Salt cannot be empty');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
this._salt = value;
|
|
114
|
+
this.generateClientKeysIfReady();
|
|
115
|
+
|
|
116
|
+
log.debug('Salt set successfully');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Gets the server's public key B.
|
|
121
|
+
*
|
|
122
|
+
* @returns The server's public key as a Buffer or null if not set
|
|
123
|
+
*/
|
|
124
|
+
get serverPublicKey(): Buffer | null {
|
|
125
|
+
return this._B ? bigIntToBuffer(this._B, SRP_KEY_LENGTH_BYTES) : null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Sets the server's public key B.
|
|
130
|
+
*
|
|
131
|
+
* @param value - The server's public key as a Buffer
|
|
132
|
+
* @throws {SRPError} If the server public key is invalid or client is disposed
|
|
133
|
+
*/
|
|
134
|
+
set serverPublicKey(value: Buffer) {
|
|
135
|
+
this.throwIfDisposed();
|
|
136
|
+
|
|
137
|
+
if (!value || value.length !== SRP_KEY_LENGTH_BYTES) {
|
|
138
|
+
throw new SRPError(
|
|
139
|
+
`Server public key must be ${SRP_KEY_LENGTH_BYTES} bytes, got ${value?.length || 0}`,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
this._B = bufferToBigInt(value);
|
|
144
|
+
|
|
145
|
+
if (this._B <= SRPClient.ONE || this._B >= this.N_MINUS_ONE) {
|
|
146
|
+
throw new SRPError(
|
|
147
|
+
'Invalid server public key B: must be in range (1, N-1)',
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Additional security check
|
|
152
|
+
if (this._B % this.N === SRPClient.ZERO) {
|
|
153
|
+
throw new SRPError('Invalid server public key B: divisible by N');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
this.generateClientKeysIfReady();
|
|
157
|
+
log.debug('Server public key set successfully');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Gets the client's public key A.
|
|
162
|
+
*
|
|
163
|
+
* @returns The client's public key as a Buffer
|
|
164
|
+
* @throws {SRPError} If keys are not generated yet or client is disposed
|
|
165
|
+
*/
|
|
166
|
+
get publicKey(): Buffer {
|
|
167
|
+
this.throwIfDisposed();
|
|
168
|
+
|
|
169
|
+
if (this._A === SRPClient.ZERO) {
|
|
170
|
+
throw new SRPError(
|
|
171
|
+
'Client keys not generated yet. Set salt and serverPublicKey properties first.',
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return bigIntToBuffer(this._A, SRP_KEY_LENGTH_BYTES);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Computes the authentication proof M1.
|
|
180
|
+
*
|
|
181
|
+
* @returns The authentication proof as a Buffer
|
|
182
|
+
* @throws {SRPError} If required parameters are not set or client is disposed
|
|
183
|
+
*/
|
|
184
|
+
public computeProof(): Buffer {
|
|
185
|
+
this.throwIfDisposed();
|
|
186
|
+
this.validateIdentitySet();
|
|
187
|
+
|
|
188
|
+
if (!this._K) {
|
|
189
|
+
this.computeSharedSecret();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (!this._salt || !this._K || !this._B) {
|
|
193
|
+
throw new SRPError(
|
|
194
|
+
'Cannot compute proof: salt, session key, and server public key must be set',
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return calculateM1(
|
|
199
|
+
this.N,
|
|
200
|
+
this.g,
|
|
201
|
+
this.username,
|
|
202
|
+
this._salt,
|
|
203
|
+
this._A,
|
|
204
|
+
this._B,
|
|
205
|
+
this._K,
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Gets the computed session key K.
|
|
211
|
+
*
|
|
212
|
+
* @returns The session key as a Buffer
|
|
213
|
+
* @throws {SRPError} If session key is not computed or client is disposed
|
|
214
|
+
*/
|
|
215
|
+
get sessionKey(): Buffer {
|
|
216
|
+
this.throwIfDisposed();
|
|
217
|
+
this.validateIdentitySet();
|
|
218
|
+
|
|
219
|
+
if (!this._K) {
|
|
220
|
+
this.computeSharedSecret();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (!this._K) {
|
|
224
|
+
throw new SRPError('Session key not computed');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return this._K;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Checks if the client is ready to perform operations.
|
|
232
|
+
*
|
|
233
|
+
* @returns True if salt and server public key are set
|
|
234
|
+
*/
|
|
235
|
+
public isReady(): boolean {
|
|
236
|
+
return !this.disposed && !!(this._salt && this._B && this.keysGenerated);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Checks if session key has been computed.
|
|
241
|
+
*
|
|
242
|
+
* @returns True if a session key is available
|
|
243
|
+
*/
|
|
244
|
+
public hasSessionKey(): boolean {
|
|
245
|
+
return !this.disposed && !!this._K;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Clears sensitive data and disposes the client.
|
|
250
|
+
* After calling this method, the client instance should not be used.
|
|
251
|
+
*/
|
|
252
|
+
public dispose(): void {
|
|
253
|
+
if (this.disposed) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Clear sensitive data
|
|
258
|
+
this.password = '';
|
|
259
|
+
this._a = SRPClient.ZERO;
|
|
260
|
+
|
|
261
|
+
if (this._K) {
|
|
262
|
+
this._K.fill(0);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
this._salt = null;
|
|
266
|
+
this._S = null;
|
|
267
|
+
this._B = null;
|
|
268
|
+
this.disposed = true;
|
|
269
|
+
|
|
270
|
+
log.debug('SRP client disposed and sensitive data cleared');
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Generates client keys if both salt and server public key are available.
|
|
275
|
+
* This method ensures keys are generated only once.
|
|
276
|
+
*/
|
|
277
|
+
private generateClientKeysIfReady(): void {
|
|
278
|
+
if (this._salt && this._B && !this.keysGenerated) {
|
|
279
|
+
this.generateClientKeys();
|
|
280
|
+
this.keysGenerated = true;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Generates the client's private and public keys using cryptographically secure methods.
|
|
286
|
+
*
|
|
287
|
+
* @throws {SRPError} If generated public key is invalid or key generation fails
|
|
288
|
+
*/
|
|
289
|
+
private generateClientKeys(): void {
|
|
290
|
+
this.validateIdentitySet();
|
|
291
|
+
|
|
292
|
+
let attempts = 0;
|
|
293
|
+
|
|
294
|
+
while (attempts < SRPClient.MAX_KEY_GENERATION_ATTEMPTS) {
|
|
295
|
+
const randomBits = randomBytes(SRP_PRIVATE_KEY_BITS / 8);
|
|
296
|
+
this._a = bufferToBigInt(randomBits);
|
|
297
|
+
|
|
298
|
+
// Ensure key is in valid range without introducing bias
|
|
299
|
+
if (this._a >= this.N) {
|
|
300
|
+
attempts++;
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (this._a === SRPClient.ZERO) {
|
|
305
|
+
attempts++;
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
this._A = modPow(this.g, this._a, this.N);
|
|
310
|
+
|
|
311
|
+
if (this._A <= SRPClient.ONE || this._A >= this.N_MINUS_ONE) {
|
|
312
|
+
attempts++;
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Successfully generated valid keys
|
|
317
|
+
log.debug('Generated client keys successfully');
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
throw new SRPError(
|
|
322
|
+
`Failed to generate secure client keys after ${SRPClient.MAX_KEY_GENERATION_ATTEMPTS} attempts`,
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Computes the shared secret S and derives the session key K.
|
|
328
|
+
*
|
|
329
|
+
* @throws {SRPError} If required parameters are not set
|
|
330
|
+
*/
|
|
331
|
+
private computeSharedSecret(): void {
|
|
332
|
+
this.validateIdentitySet();
|
|
333
|
+
|
|
334
|
+
if (!this._salt || !this._B) {
|
|
335
|
+
throw new SRPError('Salt and server public key must be set first');
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (this._A === SRPClient.ZERO) {
|
|
339
|
+
throw new SRPError('Client keys not generated');
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const u = calculateU(this._A, this._B, SRP_KEY_LENGTH_BYTES);
|
|
343
|
+
log.debug('Calculated u value');
|
|
344
|
+
|
|
345
|
+
const x = calculateX(this._salt, this.username, this.password);
|
|
346
|
+
log.debug('Calculated x value');
|
|
347
|
+
|
|
348
|
+
const gx = modPow(this.g, x, this.N);
|
|
349
|
+
const kgx = (this.k * gx) % this.N;
|
|
350
|
+
|
|
351
|
+
// Fix negative modulo operation
|
|
352
|
+
let base = this._B - kgx;
|
|
353
|
+
base = ((base % this.N) + this.N) % this.N;
|
|
354
|
+
|
|
355
|
+
const exponent = this._a + u * x;
|
|
356
|
+
this._S = modPow(base, exponent, this.N);
|
|
357
|
+
log.debug('Calculated shared secret S');
|
|
358
|
+
|
|
359
|
+
const SBuffer = bigIntToBuffer(this._S, SRP_KEY_LENGTH_BYTES);
|
|
360
|
+
this._K = hash(SBuffer);
|
|
361
|
+
log.debug('Calculated session key K');
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Validates that identity has been set.
|
|
366
|
+
*
|
|
367
|
+
* @throws {SRPError} If password is not set (username is set by default)
|
|
368
|
+
*/
|
|
369
|
+
private validateIdentitySet(): void {
|
|
370
|
+
if (!this.password) {
|
|
371
|
+
throw new SRPError(
|
|
372
|
+
'Password must be set before performing operations. Call setIdentity() first.',
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Throws an error if the client has been disposed.
|
|
379
|
+
*
|
|
380
|
+
* @throws {SRPError} If client is disposed
|
|
381
|
+
*/
|
|
382
|
+
private throwIfDisposed(): void {
|
|
383
|
+
if (this.disposed) {
|
|
384
|
+
throw new SRPError('SRP client has been disposed');
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
@@ -457,5 +457,4 @@ function extractServices(response: string): ServicesResponse {
|
|
|
457
457
|
return { services };
|
|
458
458
|
}
|
|
459
459
|
|
|
460
|
-
export
|
|
461
|
-
export { type Service, type ServicesResponse };
|
|
460
|
+
export { RemoteXpcConnection, type Service, type ServicesResponse };
|
package/src/lib/tunnel/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { logger } from '@appium/support';
|
|
|
2
2
|
import type { TLSSocket } from 'tls';
|
|
3
3
|
import { type TunnelConnection, connectToTunnelLockdown } from 'tuntap-bridge';
|
|
4
4
|
|
|
5
|
-
import RemoteXpcConnection from '../remote-xpc/remote-xpc-connection.js';
|
|
5
|
+
import { RemoteXpcConnection } from '../remote-xpc/remote-xpc-connection.js';
|
|
6
6
|
|
|
7
7
|
const log = logger.getLogger('TunnelManager');
|
|
8
8
|
|
|
@@ -64,9 +64,12 @@ class TunnelManagerService {
|
|
|
64
64
|
async createRemoteXPCConnection(
|
|
65
65
|
address: string,
|
|
66
66
|
rsdPort: number,
|
|
67
|
-
): Promise<
|
|
67
|
+
): Promise<RemoteXpcConnection> {
|
|
68
68
|
try {
|
|
69
|
-
const remoteXPC = new RemoteXpcConnection([
|
|
69
|
+
const remoteXPC: RemoteXpcConnection = new RemoteXpcConnection([
|
|
70
|
+
address,
|
|
71
|
+
rsdPort,
|
|
72
|
+
]);
|
|
70
73
|
|
|
71
74
|
// Connect to RemoteXPC with delay between retries
|
|
72
75
|
let retries = 3;
|
|
@@ -75,7 +78,6 @@ class TunnelManagerService {
|
|
|
75
78
|
while (retries > 0) {
|
|
76
79
|
try {
|
|
77
80
|
await remoteXPC.connect();
|
|
78
|
-
|
|
79
81
|
// Update the registry entry with the RemoteXPC connection
|
|
80
82
|
const entry = this.tunnelRegistry.get(address);
|
|
81
83
|
if (entry) {
|
|
@@ -249,5 +251,5 @@ class TunnelManagerService {
|
|
|
249
251
|
// Create and export the singleton instance
|
|
250
252
|
export const TunnelManager = new TunnelManagerService();
|
|
251
253
|
// Export packet streaming IPC functionality
|
|
252
|
-
export { PacketStreamServer } from './packet-stream-server.js';
|
|
253
254
|
export { PacketStreamClient } from './packet-stream-client.js';
|
|
255
|
+
export { PacketStreamServer } from './packet-stream-server.js';
|
package/src/lib/types.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { EventEmitter } from 'events';
|
|
|
5
5
|
import type { PacketData } from 'tuntap-bridge';
|
|
6
6
|
|
|
7
7
|
import type { BaseService, Service } from '../services/ios/base-service.js';
|
|
8
|
+
import type { RemoteXpcConnection } from './remote-xpc/remote-xpc-connection.js';
|
|
8
9
|
import type { Device } from './usbmux/index.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -190,6 +191,17 @@ export interface DiagnosticsServiceConstructor {
|
|
|
190
191
|
new (address: [string, number]): DiagnosticsService;
|
|
191
192
|
}
|
|
192
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Represents a DiagnosticsService instance with its associated RemoteXPC connection
|
|
196
|
+
* This allows callers to properly manage the connection lifecycle
|
|
197
|
+
*/
|
|
198
|
+
export interface DiagnosticsServiceWithConnection {
|
|
199
|
+
/** The DiagnosticsService instance */
|
|
200
|
+
diagnosticsService: DiagnosticsService;
|
|
201
|
+
/** The RemoteXPC connection that can be used to close the connection */
|
|
202
|
+
remoteXPC: RemoteXpcConnection;
|
|
203
|
+
}
|
|
204
|
+
|
|
193
205
|
/**
|
|
194
206
|
* Options for configuring syslog capture
|
|
195
207
|
*/
|
package/src/services.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { strongbox } from '@appium/strongbox';
|
|
2
2
|
|
|
3
|
-
import RemoteXpcConnection from './lib/remote-xpc/remote-xpc-connection.js';
|
|
3
|
+
import { RemoteXpcConnection } from './lib/remote-xpc/remote-xpc-connection.js';
|
|
4
4
|
import { TunnelManager } from './lib/tunnel/index.js';
|
|
5
5
|
import { TunnelApiClient } from './lib/tunnel/tunnel-api-client.js';
|
|
6
6
|
import type {
|
|
7
|
-
|
|
7
|
+
DiagnosticsServiceWithConnection,
|
|
8
8
|
SyslogService as SyslogServiceType,
|
|
9
9
|
} from './lib/types.js';
|
|
10
10
|
import DiagnosticsService from './services/ios/diagnostic-service/index.js';
|
|
@@ -15,15 +15,18 @@ const TUNNEL_REGISTRY_PORT = 'tunnelRegistryPort';
|
|
|
15
15
|
|
|
16
16
|
export async function startDiagnosticsService(
|
|
17
17
|
udid: string,
|
|
18
|
-
): Promise<
|
|
18
|
+
): Promise<DiagnosticsServiceWithConnection> {
|
|
19
19
|
const { remoteXPC, tunnelConnection } = await createRemoteXPCConnection(udid);
|
|
20
20
|
const diagnosticsService = remoteXPC.findService(
|
|
21
21
|
DiagnosticsService.RSD_SERVICE_NAME,
|
|
22
22
|
);
|
|
23
|
-
return
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
return {
|
|
24
|
+
remoteXPC: remoteXPC as RemoteXpcConnection,
|
|
25
|
+
diagnosticsService: new DiagnosticsService([
|
|
26
|
+
tunnelConnection.host,
|
|
27
|
+
parseInt(diagnosticsService.port, 10),
|
|
28
|
+
]),
|
|
29
|
+
};
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
export async function startSyslogService(
|