appium-ios-remotexpc 0.0.6 → 0.1.1

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.
Files changed (31) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/src/lib/apple-tv/srp/crypto-utils.d.ts +53 -0
  3. package/build/src/lib/apple-tv/srp/crypto-utils.d.ts.map +1 -0
  4. package/build/src/lib/apple-tv/srp/crypto-utils.js +128 -0
  5. package/build/src/lib/apple-tv/srp/index.d.ts +3 -0
  6. package/build/src/lib/apple-tv/srp/index.d.ts.map +1 -0
  7. package/build/src/lib/apple-tv/srp/index.js +2 -0
  8. package/build/src/lib/apple-tv/srp/srp-client.d.ts +130 -0
  9. package/build/src/lib/apple-tv/srp/srp-client.d.ts.map +1 -0
  10. package/build/src/lib/apple-tv/srp/srp-client.js +288 -0
  11. package/build/src/lib/tunnel/index.d.ts +1 -1
  12. package/build/src/lib/tunnel/index.d.ts.map +1 -1
  13. package/build/src/lib/tunnel/index.js +1 -1
  14. package/build/src/lib/tunnel/packet-stream-client.d.ts +1 -1
  15. package/build/src/lib/tunnel/packet-stream-client.d.ts.map +1 -1
  16. package/build/src/lib/tunnel/packet-stream-server.d.ts +1 -1
  17. package/build/src/lib/tunnel/packet-stream-server.d.ts.map +1 -1
  18. package/build/src/lib/types.d.ts +1 -1
  19. package/build/src/lib/types.d.ts.map +1 -1
  20. package/build/src/lib/types.js +0 -3
  21. package/build/src/services/ios/syslog-service/index.d.ts +1 -1
  22. package/build/src/services/ios/syslog-service/index.d.ts.map +1 -1
  23. package/package.json +2 -2
  24. package/src/lib/apple-tv/srp/crypto-utils.ts +166 -0
  25. package/src/lib/apple-tv/srp/index.ts +8 -0
  26. package/src/lib/apple-tv/srp/srp-client.ts +387 -0
  27. package/src/lib/tunnel/index.ts +4 -1
  28. package/src/lib/tunnel/packet-stream-client.ts +1 -1
  29. package/src/lib/tunnel/packet-stream-server.ts +1 -1
  30. package/src/lib/types.ts +1 -1
  31. package/src/services/ios/syslog-service/index.ts +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [0.1.1](https://github.com/appium/appium-ios-remotexpc/compare/v0.1.0...v0.1.1) (2025-07-23)
2
+
3
+ ### Bug Fixes
4
+
5
+ * change tuntap dependency to appium-ios-tuntap ([#55](https://github.com/appium/appium-ios-remotexpc/issues/55)) ([dad93be](https://github.com/appium/appium-ios-remotexpc/commit/dad93be92c73ab67a028878777d42d31c799288c))
6
+
7
+ ## [0.1.0](https://github.com/appium/appium-ios-remotexpc/compare/v0.0.6...v0.1.0) (2025-07-05)
8
+
9
+ ### Features
10
+
11
+ * add SRP implementation for Apple TV authentication ([#51](https://github.com/appium/appium-ios-remotexpc/issues/51)) ([4cc8c4e](https://github.com/appium/appium-ios-remotexpc/commit/4cc8c4ef92a689306a903bcc8dd5cfad5b024d7b))
12
+
1
13
  ## [0.0.6](https://github.com/appium/appium-ios-remotexpc/compare/v0.0.5...v0.0.6) (2025-07-05)
2
14
 
3
15
  ### Bug Fixes
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Computes a cryptographic hash of the provided input buffers.
3
+ *
4
+ * @param inputs - Variable number of Buffer objects to hash
5
+ * @returns The computed hash as a Buffer
6
+ * @throws {Error} If no inputs provided
7
+ */
8
+ export declare function hash(...inputs: Buffer[]): Buffer;
9
+ /**
10
+ * Calculates the SRP multiplier parameter k = H(N, g).
11
+ *
12
+ * @param N - The large safe prime modulus
13
+ * @param g - The generator
14
+ * @param keyLength - The key length in bytes
15
+ * @returns The calculated k value as a bigint
16
+ * @throws {Error} If parameters are invalid
17
+ */
18
+ export declare function calculateK(N: bigint, g: bigint, keyLength: number): bigint;
19
+ /**
20
+ * Calculates the private key x = H(salt, H(username:password)).
21
+ *
22
+ * @param salt - The salt buffer
23
+ * @param username - The username string
24
+ * @param password - The password string
25
+ * @returns The calculated x value as a bigint
26
+ * @throws {Error} If parameters are invalid
27
+ */
28
+ export declare function calculateX(salt: Buffer, username: string, password: string): bigint;
29
+ /**
30
+ * Calculates the random scrambling parameter u = H(A, B).
31
+ *
32
+ * @param A - The client's public key
33
+ * @param B - The server's public key
34
+ * @param keyLength - The key length in bytes
35
+ * @returns The calculated u value as a bigint
36
+ * @throws {Error} If parameters are invalid
37
+ */
38
+ export declare function calculateU(A: bigint, B: bigint, keyLength: number): bigint;
39
+ /**
40
+ * Calculates the client evidence M1 = H(H(N) xor H(g), H(username), salt, A, B, K).
41
+ *
42
+ * @param N - The large safe prime modulus
43
+ * @param g - The generator
44
+ * @param username - The username string
45
+ * @param salt - The salt buffer
46
+ * @param A - The client's public key
47
+ * @param B - The server's public key
48
+ * @param K - The session key
49
+ * @returns The calculated M1 evidence as a Buffer
50
+ * @throws {Error} If parameters are invalid
51
+ */
52
+ export declare function calculateM1(N: bigint, g: bigint, username: string, salt: Buffer, A: bigint, B: bigint, K: Buffer): Buffer;
53
+ //# sourceMappingURL=crypto-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto-utils.d.ts","sourceRoot":"","sources":["../../../../../src/lib/apple-tv/srp/crypto-utils.ts"],"names":[],"mappings":"AASA;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAehD;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAa1E;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,MAAM,CAcR;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAkB1E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CACzB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR,MAAM,CA6BR"}
@@ -0,0 +1,128 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { SRP_HASH_ALGORITHM } from '../constants.js';
3
+ import { bigIntToBuffer, bigIntToMinimalBuffer, bufferToBigInt, } from '../utils/buffer-utils.js';
4
+ /**
5
+ * Computes a cryptographic hash of the provided input buffers.
6
+ *
7
+ * @param inputs - Variable number of Buffer objects to hash
8
+ * @returns The computed hash as a Buffer
9
+ * @throws {Error} If no inputs provided
10
+ */
11
+ export function hash(...inputs) {
12
+ if (inputs.length === 0) {
13
+ throw new Error('At least one input buffer is required for hashing');
14
+ }
15
+ const hasher = createHash(SRP_HASH_ALGORITHM);
16
+ for (const input of inputs) {
17
+ if (!Buffer.isBuffer(input)) {
18
+ throw new Error('All inputs must be Buffer objects');
19
+ }
20
+ hasher.update(input);
21
+ }
22
+ return hasher.digest();
23
+ }
24
+ /**
25
+ * Calculates the SRP multiplier parameter k = H(N, g).
26
+ *
27
+ * @param N - The large safe prime modulus
28
+ * @param g - The generator
29
+ * @param keyLength - The key length in bytes
30
+ * @returns The calculated k value as a bigint
31
+ * @throws {Error} If parameters are invalid
32
+ */
33
+ export function calculateK(N, g, keyLength) {
34
+ if (N <= BigInt(0) || g <= BigInt(0)) {
35
+ throw new Error('N and g must be positive');
36
+ }
37
+ if (keyLength <= 0) {
38
+ throw new Error('Key length must be positive');
39
+ }
40
+ const NBuffer = bigIntToBuffer(N, keyLength);
41
+ const gBuffer = bigIntToBuffer(g, keyLength);
42
+ const kHash = hash(NBuffer, gBuffer);
43
+ return bufferToBigInt(kHash);
44
+ }
45
+ /**
46
+ * Calculates the private key x = H(salt, H(username:password)).
47
+ *
48
+ * @param salt - The salt buffer
49
+ * @param username - The username string
50
+ * @param password - The password string
51
+ * @returns The calculated x value as a bigint
52
+ * @throws {Error} If parameters are invalid
53
+ */
54
+ export function calculateX(salt, username, password) {
55
+ if (!Buffer.isBuffer(salt) || salt.length === 0) {
56
+ throw new Error('Salt must be a non-empty Buffer');
57
+ }
58
+ if (!username || !password) {
59
+ throw new Error('Username and password must be non-empty strings');
60
+ }
61
+ const usernamePasswordHash = hash(Buffer.from(`${username}:${password}`, 'utf8'));
62
+ const xHash = hash(salt, usernamePasswordHash);
63
+ return bufferToBigInt(xHash);
64
+ }
65
+ /**
66
+ * Calculates the random scrambling parameter u = H(A, B).
67
+ *
68
+ * @param A - The client's public key
69
+ * @param B - The server's public key
70
+ * @param keyLength - The key length in bytes
71
+ * @returns The calculated u value as a bigint
72
+ * @throws {Error} If parameters are invalid
73
+ */
74
+ export function calculateU(A, B, keyLength) {
75
+ if (A <= BigInt(0) || B <= BigInt(0)) {
76
+ throw new Error('Public keys A and B must be positive');
77
+ }
78
+ if (keyLength <= 0) {
79
+ throw new Error('Key length must be positive');
80
+ }
81
+ const ABuffer = bigIntToBuffer(A, keyLength);
82
+ const BBuffer = bigIntToBuffer(B, keyLength);
83
+ const uHash = hash(ABuffer, BBuffer);
84
+ const u = bufferToBigInt(uHash);
85
+ if (u === BigInt(0)) {
86
+ throw new Error('Calculated u value cannot be zero (hash collision)');
87
+ }
88
+ return u;
89
+ }
90
+ /**
91
+ * Calculates the client evidence M1 = H(H(N) xor H(g), H(username), salt, A, B, K).
92
+ *
93
+ * @param N - The large safe prime modulus
94
+ * @param g - The generator
95
+ * @param username - The username string
96
+ * @param salt - The salt buffer
97
+ * @param A - The client's public key
98
+ * @param B - The server's public key
99
+ * @param K - The session key
100
+ * @returns The calculated M1 evidence as a Buffer
101
+ * @throws {Error} If parameters are invalid
102
+ */
103
+ export function calculateM1(N, g, username, salt, A, B, K) {
104
+ if (N <= BigInt(0) || g <= BigInt(0) || A <= BigInt(0) || B <= BigInt(0)) {
105
+ throw new Error('All bigint parameters must be positive');
106
+ }
107
+ if (!username) {
108
+ throw new Error('Username must be non-empty');
109
+ }
110
+ if (!Buffer.isBuffer(salt) || salt.length === 0) {
111
+ throw new Error('Salt must be a non-empty Buffer');
112
+ }
113
+ if (!Buffer.isBuffer(K) || K.length === 0) {
114
+ throw new Error('Session key K must be a non-empty Buffer');
115
+ }
116
+ const NBytes = bigIntToMinimalBuffer(N);
117
+ const gBytes = bigIntToMinimalBuffer(g);
118
+ const NHash = hash(NBytes);
119
+ const gHash = hash(gBytes);
120
+ const NgXorBytes = Buffer.alloc(NHash.length);
121
+ for (let i = 0; i < NHash.length; i++) {
122
+ NgXorBytes[i] = NHash[i] ^ gHash[i];
123
+ }
124
+ const usernameHash = hash(Buffer.from(username, 'utf8'));
125
+ const ABytes = bigIntToMinimalBuffer(A);
126
+ const BBytes = bigIntToMinimalBuffer(B);
127
+ return hash(NgXorBytes, usernameHash, salt, ABytes, BBytes, K);
128
+ }
@@ -0,0 +1,3 @@
1
+ export { SRPClient } from './srp-client.js';
2
+ export { hash, calculateK, calculateX, calculateU, calculateM1, } from './crypto-utils.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/lib/apple-tv/srp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EACL,IAAI,EACJ,UAAU,EACV,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { SRPClient } from './srp-client.js';
2
+ export { hash, calculateK, calculateX, calculateU, calculateM1, } from './crypto-utils.js';
@@ -0,0 +1,130 @@
1
+ /**
2
+ * SRP (Secure Remote Password) client implementation following RFC 5054.
3
+ *
4
+ * This class handles the client-side operations of the SRP protocol,
5
+ * including key generation, authentication proof computation, and
6
+ * session key derivation.
7
+ */
8
+ export declare class SRPClient {
9
+ private static readonly ZERO;
10
+ private static readonly ONE;
11
+ private static readonly MAX_KEY_GENERATION_ATTEMPTS;
12
+ private readonly N;
13
+ private readonly g;
14
+ private readonly k;
15
+ private readonly N_MINUS_ONE;
16
+ private username;
17
+ private password;
18
+ private _salt;
19
+ private _a;
20
+ private _A;
21
+ private _B;
22
+ private _S;
23
+ private _K;
24
+ private keysGenerated;
25
+ private disposed;
26
+ constructor();
27
+ /**
28
+ * Sets the user identity credentials.
29
+ * Note: Username is set to SRP_USERNAME constant, but can be overridden.
30
+ *
31
+ * @param username - The username for authentication
32
+ * @param password - The password for authentication
33
+ * @throws {SRPError} If username or password is empty
34
+ */
35
+ setIdentity(username: string, password: string): void;
36
+ /**
37
+ * Gets the salt value received from the server.
38
+ *
39
+ * @returns The salt buffer or null if not set
40
+ */
41
+ get salt(): Buffer | null;
42
+ /**
43
+ * Sets the salt value received from the server.
44
+ *
45
+ * @param value - The salt buffer from the server
46
+ * @throws {SRPError} If salt is empty or client is disposed
47
+ */
48
+ set salt(value: Buffer);
49
+ /**
50
+ * Gets the server's public key B.
51
+ *
52
+ * @returns The server's public key as a Buffer or null if not set
53
+ */
54
+ get serverPublicKey(): Buffer | null;
55
+ /**
56
+ * Sets the server's public key B.
57
+ *
58
+ * @param value - The server's public key as a Buffer
59
+ * @throws {SRPError} If the server public key is invalid or client is disposed
60
+ */
61
+ set serverPublicKey(value: Buffer);
62
+ /**
63
+ * Gets the client's public key A.
64
+ *
65
+ * @returns The client's public key as a Buffer
66
+ * @throws {SRPError} If keys are not generated yet or client is disposed
67
+ */
68
+ get publicKey(): Buffer;
69
+ /**
70
+ * Computes the authentication proof M1.
71
+ *
72
+ * @returns The authentication proof as a Buffer
73
+ * @throws {SRPError} If required parameters are not set or client is disposed
74
+ */
75
+ computeProof(): Buffer;
76
+ /**
77
+ * Gets the computed session key K.
78
+ *
79
+ * @returns The session key as a Buffer
80
+ * @throws {SRPError} If session key is not computed or client is disposed
81
+ */
82
+ get sessionKey(): Buffer;
83
+ /**
84
+ * Checks if the client is ready to perform operations.
85
+ *
86
+ * @returns True if salt and server public key are set
87
+ */
88
+ isReady(): boolean;
89
+ /**
90
+ * Checks if session key has been computed.
91
+ *
92
+ * @returns True if a session key is available
93
+ */
94
+ hasSessionKey(): boolean;
95
+ /**
96
+ * Clears sensitive data and disposes the client.
97
+ * After calling this method, the client instance should not be used.
98
+ */
99
+ dispose(): void;
100
+ /**
101
+ * Generates client keys if both salt and server public key are available.
102
+ * This method ensures keys are generated only once.
103
+ */
104
+ private generateClientKeysIfReady;
105
+ /**
106
+ * Generates the client's private and public keys using cryptographically secure methods.
107
+ *
108
+ * @throws {SRPError} If generated public key is invalid or key generation fails
109
+ */
110
+ private generateClientKeys;
111
+ /**
112
+ * Computes the shared secret S and derives the session key K.
113
+ *
114
+ * @throws {SRPError} If required parameters are not set
115
+ */
116
+ private computeSharedSecret;
117
+ /**
118
+ * Validates that identity has been set.
119
+ *
120
+ * @throws {SRPError} If password is not set (username is set by default)
121
+ */
122
+ private validateIdentitySet;
123
+ /**
124
+ * Throws an error if the client has been disposed.
125
+ *
126
+ * @throws {SRPError} If client is disposed
127
+ */
128
+ private throwIfDisposed;
129
+ }
130
+ //# sourceMappingURL=srp-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"srp-client.d.ts","sourceRoot":"","sources":["../../../../../src/lib/apple-tv/srp/srp-client.ts"],"names":[],"mappings":"AA0BA;;;;;;GAMG;AACH,qBAAa,SAAS;IAEpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAa;IACzC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAa;IACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,2BAA2B,CAAO;IAE1D,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAkB;IACpC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAiB;IACnC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,EAAE,CAAuB;IACjC,OAAO,CAAC,EAAE,CAAuB;IACjC,OAAO,CAAC,EAAE,CAAuB;IAGjC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAS;;IAWzB;;;;;;;OAOG;IACI,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAgB5D;;;;OAIG;IACH,IAAI,IAAI,IAAI,MAAM,GAAG,IAAI,CAExB;IAED;;;;;OAKG;IACH,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,EAWrB;IAED;;;;OAIG;IACH,IAAI,eAAe,IAAI,MAAM,GAAG,IAAI,CAEnC;IAED;;;;;OAKG;IACH,IAAI,eAAe,CAAC,KAAK,EAAE,MAAM,EAwBhC;IAED;;;;;OAKG;IACH,IAAI,SAAS,IAAI,MAAM,CAUtB;IAED;;;;;OAKG;IACI,YAAY,IAAI,MAAM;IAyB7B;;;;;OAKG;IACH,IAAI,UAAU,IAAI,MAAM,CAavB;IAED;;;;OAIG;IACI,OAAO,IAAI,OAAO;IAIzB;;;;OAIG;IACI,aAAa,IAAI,OAAO;IAI/B;;;OAGG;IACI,OAAO,IAAI,IAAI;IAqBtB;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAOjC;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAqC1B;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAiC3B;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAQ3B;;;;OAIG;IACH,OAAO,CAAC,eAAe;CAKxB"}
@@ -0,0 +1,288 @@
1
+ import { logger } from '@appium/support';
2
+ import { randomBytes } from 'node:crypto';
3
+ import { SRP_GENERATOR, SRP_KEY_LENGTH_BYTES, SRP_PRIME_3072, SRP_PRIVATE_KEY_BITS, SRP_USERNAME, } from '../constants.js';
4
+ import { SRPError } from '../errors.js';
5
+ import { bigIntToBuffer, bufferToBigInt, modPow, } from '../utils/buffer-utils.js';
6
+ import { calculateK, calculateM1, calculateU, calculateX, hash, } from './crypto-utils.js';
7
+ const log = logger.getLogger('SRPClient');
8
+ /**
9
+ * SRP (Secure Remote Password) client implementation following RFC 5054.
10
+ *
11
+ * This class handles the client-side operations of the SRP protocol,
12
+ * including key generation, authentication proof computation, and
13
+ * session key derivation.
14
+ */
15
+ export class SRPClient {
16
+ // Constants
17
+ static ZERO = BigInt(0);
18
+ static ONE = BigInt(1);
19
+ static MAX_KEY_GENERATION_ATTEMPTS = 100;
20
+ N = SRP_PRIME_3072;
21
+ g = SRP_GENERATOR;
22
+ k;
23
+ N_MINUS_ONE;
24
+ username;
25
+ password;
26
+ _salt = null;
27
+ _a = SRPClient.ZERO;
28
+ _A = SRPClient.ZERO;
29
+ _B = null;
30
+ _S = null;
31
+ _K = null;
32
+ // State tracking
33
+ keysGenerated = false;
34
+ disposed = false;
35
+ constructor() {
36
+ this.k = calculateK(this.N, this.g, SRP_KEY_LENGTH_BYTES);
37
+ this.N_MINUS_ONE = this.N - SRPClient.ONE;
38
+ this.username = SRP_USERNAME;
39
+ this.password = '';
40
+ log.debug('Initialized SRP client with k value');
41
+ }
42
+ /**
43
+ * Sets the user identity credentials.
44
+ * Note: Username is set to SRP_USERNAME constant, but can be overridden.
45
+ *
46
+ * @param username - The username for authentication
47
+ * @param password - The password for authentication
48
+ * @throws {SRPError} If username or password is empty
49
+ */
50
+ setIdentity(username, password) {
51
+ this.throwIfDisposed();
52
+ if (!username?.trim()) {
53
+ throw new SRPError('Username cannot be empty');
54
+ }
55
+ if (!password) {
56
+ throw new SRPError('Password cannot be empty');
57
+ }
58
+ this.username = username.trim();
59
+ this.password = password;
60
+ log.debug('Identity set successfully');
61
+ }
62
+ /**
63
+ * Gets the salt value received from the server.
64
+ *
65
+ * @returns The salt buffer or null if not set
66
+ */
67
+ get salt() {
68
+ return this._salt;
69
+ }
70
+ /**
71
+ * Sets the salt value received from the server.
72
+ *
73
+ * @param value - The salt buffer from the server
74
+ * @throws {SRPError} If salt is empty or client is disposed
75
+ */
76
+ set salt(value) {
77
+ this.throwIfDisposed();
78
+ if (!value || value.length === 0) {
79
+ throw new SRPError('Salt cannot be empty');
80
+ }
81
+ this._salt = value;
82
+ this.generateClientKeysIfReady();
83
+ log.debug('Salt set successfully');
84
+ }
85
+ /**
86
+ * Gets the server's public key B.
87
+ *
88
+ * @returns The server's public key as a Buffer or null if not set
89
+ */
90
+ get serverPublicKey() {
91
+ return this._B ? bigIntToBuffer(this._B, SRP_KEY_LENGTH_BYTES) : null;
92
+ }
93
+ /**
94
+ * Sets the server's public key B.
95
+ *
96
+ * @param value - The server's public key as a Buffer
97
+ * @throws {SRPError} If the server public key is invalid or client is disposed
98
+ */
99
+ set serverPublicKey(value) {
100
+ this.throwIfDisposed();
101
+ if (!value || value.length !== SRP_KEY_LENGTH_BYTES) {
102
+ throw new SRPError(`Server public key must be ${SRP_KEY_LENGTH_BYTES} bytes, got ${value?.length || 0}`);
103
+ }
104
+ this._B = bufferToBigInt(value);
105
+ if (this._B <= SRPClient.ONE || this._B >= this.N_MINUS_ONE) {
106
+ throw new SRPError('Invalid server public key B: must be in range (1, N-1)');
107
+ }
108
+ // Additional security check
109
+ if (this._B % this.N === SRPClient.ZERO) {
110
+ throw new SRPError('Invalid server public key B: divisible by N');
111
+ }
112
+ this.generateClientKeysIfReady();
113
+ log.debug('Server public key set successfully');
114
+ }
115
+ /**
116
+ * Gets the client's public key A.
117
+ *
118
+ * @returns The client's public key as a Buffer
119
+ * @throws {SRPError} If keys are not generated yet or client is disposed
120
+ */
121
+ get publicKey() {
122
+ this.throwIfDisposed();
123
+ if (this._A === SRPClient.ZERO) {
124
+ throw new SRPError('Client keys not generated yet. Set salt and serverPublicKey properties first.');
125
+ }
126
+ return bigIntToBuffer(this._A, SRP_KEY_LENGTH_BYTES);
127
+ }
128
+ /**
129
+ * Computes the authentication proof M1.
130
+ *
131
+ * @returns The authentication proof as a Buffer
132
+ * @throws {SRPError} If required parameters are not set or client is disposed
133
+ */
134
+ computeProof() {
135
+ this.throwIfDisposed();
136
+ this.validateIdentitySet();
137
+ if (!this._K) {
138
+ this.computeSharedSecret();
139
+ }
140
+ if (!this._salt || !this._K || !this._B) {
141
+ throw new SRPError('Cannot compute proof: salt, session key, and server public key must be set');
142
+ }
143
+ return calculateM1(this.N, this.g, this.username, this._salt, this._A, this._B, this._K);
144
+ }
145
+ /**
146
+ * Gets the computed session key K.
147
+ *
148
+ * @returns The session key as a Buffer
149
+ * @throws {SRPError} If session key is not computed or client is disposed
150
+ */
151
+ get sessionKey() {
152
+ this.throwIfDisposed();
153
+ this.validateIdentitySet();
154
+ if (!this._K) {
155
+ this.computeSharedSecret();
156
+ }
157
+ if (!this._K) {
158
+ throw new SRPError('Session key not computed');
159
+ }
160
+ return this._K;
161
+ }
162
+ /**
163
+ * Checks if the client is ready to perform operations.
164
+ *
165
+ * @returns True if salt and server public key are set
166
+ */
167
+ isReady() {
168
+ return !this.disposed && !!(this._salt && this._B && this.keysGenerated);
169
+ }
170
+ /**
171
+ * Checks if session key has been computed.
172
+ *
173
+ * @returns True if a session key is available
174
+ */
175
+ hasSessionKey() {
176
+ return !this.disposed && !!this._K;
177
+ }
178
+ /**
179
+ * Clears sensitive data and disposes the client.
180
+ * After calling this method, the client instance should not be used.
181
+ */
182
+ dispose() {
183
+ if (this.disposed) {
184
+ return;
185
+ }
186
+ // Clear sensitive data
187
+ this.password = '';
188
+ this._a = SRPClient.ZERO;
189
+ if (this._K) {
190
+ this._K.fill(0);
191
+ }
192
+ this._salt = null;
193
+ this._S = null;
194
+ this._B = null;
195
+ this.disposed = true;
196
+ log.debug('SRP client disposed and sensitive data cleared');
197
+ }
198
+ /**
199
+ * Generates client keys if both salt and server public key are available.
200
+ * This method ensures keys are generated only once.
201
+ */
202
+ generateClientKeysIfReady() {
203
+ if (this._salt && this._B && !this.keysGenerated) {
204
+ this.generateClientKeys();
205
+ this.keysGenerated = true;
206
+ }
207
+ }
208
+ /**
209
+ * Generates the client's private and public keys using cryptographically secure methods.
210
+ *
211
+ * @throws {SRPError} If generated public key is invalid or key generation fails
212
+ */
213
+ generateClientKeys() {
214
+ this.validateIdentitySet();
215
+ let attempts = 0;
216
+ while (attempts < SRPClient.MAX_KEY_GENERATION_ATTEMPTS) {
217
+ const randomBits = randomBytes(SRP_PRIVATE_KEY_BITS / 8);
218
+ this._a = bufferToBigInt(randomBits);
219
+ // Ensure key is in valid range without introducing bias
220
+ if (this._a >= this.N) {
221
+ attempts++;
222
+ continue;
223
+ }
224
+ if (this._a === SRPClient.ZERO) {
225
+ attempts++;
226
+ continue;
227
+ }
228
+ this._A = modPow(this.g, this._a, this.N);
229
+ if (this._A <= SRPClient.ONE || this._A >= this.N_MINUS_ONE) {
230
+ attempts++;
231
+ continue;
232
+ }
233
+ // Successfully generated valid keys
234
+ log.debug('Generated client keys successfully');
235
+ return;
236
+ }
237
+ throw new SRPError(`Failed to generate secure client keys after ${SRPClient.MAX_KEY_GENERATION_ATTEMPTS} attempts`);
238
+ }
239
+ /**
240
+ * Computes the shared secret S and derives the session key K.
241
+ *
242
+ * @throws {SRPError} If required parameters are not set
243
+ */
244
+ computeSharedSecret() {
245
+ this.validateIdentitySet();
246
+ if (!this._salt || !this._B) {
247
+ throw new SRPError('Salt and server public key must be set first');
248
+ }
249
+ if (this._A === SRPClient.ZERO) {
250
+ throw new SRPError('Client keys not generated');
251
+ }
252
+ const u = calculateU(this._A, this._B, SRP_KEY_LENGTH_BYTES);
253
+ log.debug('Calculated u value');
254
+ const x = calculateX(this._salt, this.username, this.password);
255
+ log.debug('Calculated x value');
256
+ const gx = modPow(this.g, x, this.N);
257
+ const kgx = (this.k * gx) % this.N;
258
+ // Fix negative modulo operation
259
+ let base = this._B - kgx;
260
+ base = ((base % this.N) + this.N) % this.N;
261
+ const exponent = this._a + u * x;
262
+ this._S = modPow(base, exponent, this.N);
263
+ log.debug('Calculated shared secret S');
264
+ const SBuffer = bigIntToBuffer(this._S, SRP_KEY_LENGTH_BYTES);
265
+ this._K = hash(SBuffer);
266
+ log.debug('Calculated session key K');
267
+ }
268
+ /**
269
+ * Validates that identity has been set.
270
+ *
271
+ * @throws {SRPError} If password is not set (username is set by default)
272
+ */
273
+ validateIdentitySet() {
274
+ if (!this.password) {
275
+ throw new SRPError('Password must be set before performing operations. Call setIdentity() first.');
276
+ }
277
+ }
278
+ /**
279
+ * Throws an error if the client has been disposed.
280
+ *
281
+ * @throws {SRPError} If client is disposed
282
+ */
283
+ throwIfDisposed() {
284
+ if (this.disposed) {
285
+ throw new SRPError('SRP client has been disposed');
286
+ }
287
+ }
288
+ }
@@ -1,5 +1,5 @@
1
+ import { type TunnelConnection } from 'appium-ios-tuntap';
1
2
  import type { TLSSocket } from 'tls';
2
- import { type TunnelConnection } from 'tuntap-bridge';
3
3
  import { RemoteXpcConnection } from '../remote-xpc/remote-xpc-connection.js';
4
4
  /**
5
5
  * A wrapper around the tunnel connection that
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/tunnel/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AACrC,OAAO,EAAE,KAAK,gBAAgB,EAA2B,MAAM,eAAe,CAAC;AAE/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAsB7E;;;GAGG;AACH,cAAM,oBAAoB;IAExB,OAAO,CAAC,cAAc,CAA+C;IAErE;;;;;OAKG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAKtC;;;;OAIG;IACH,gBAAgB,IAAI,MAAM,EAAE;IAM5B;;;;;;OAMG;IACG,yBAAyB,CAC7B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,CAAC;IA2C/B;;;;;;OAMG;IACG,SAAS,CAAC,mBAAmB,EAAE,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAmD1E;;;;;OAKG;IACH,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAU5D;;;;;OAKG;IACG,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgC1D;;;;OAIG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAatC;;;;;OAKG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;CAGnC;AAGD,eAAO,MAAM,aAAa,sBAA6B,CAAC;AAExD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/tunnel/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAErC,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAsB7E;;;GAGG;AACH,cAAM,oBAAoB;IAExB,OAAO,CAAC,cAAc,CAA+C;IAErE;;;;;OAKG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAKtC;;;;OAIG;IACH,gBAAgB,IAAI,MAAM,EAAE;IAM5B;;;;;;OAMG;IACG,yBAAyB,CAC7B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,CAAC;IA2C/B;;;;;;OAMG;IACG,SAAS,CAAC,mBAAmB,EAAE,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAmD1E;;;;;OAKG;IACH,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAU5D;;;;;OAKG;IACG,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgC1D;;;;OAIG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAatC;;;;;OAKG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;CAGnC;AAGD,eAAO,MAAM,aAAa,sBAA6B,CAAC;AAExD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { logger } from '@appium/support';
2
- import { connectToTunnelLockdown } from 'tuntap-bridge';
2
+ import { connectToTunnelLockdown, } from 'appium-ios-tuntap';
3
3
  import { RemoteXpcConnection } from '../remote-xpc/remote-xpc-connection.js';
4
4
  const log = logger.getLogger('TunnelManager');
5
5
  /**
@@ -1,5 +1,5 @@
1
+ import type { PacketConsumer } from 'appium-ios-tuntap';
1
2
  import { EventEmitter } from 'events';
2
- import type { PacketConsumer } from 'tuntap-bridge';
3
3
  /**
4
4
  * Client that connects to a PacketStreamServer to receive packet data
5
5
  * Implements the PacketSource interface required by SyslogService
@@ -1 +1 @@
1
- {"version":3,"file":"packet-stream-client.d.ts","sourceRoot":"","sources":["../../../../src/lib/tunnel/packet-stream-client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,eAAe,CAAC;AAShE;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,YAAY;IAOhD,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAPvB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkC;IAClE,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,SAAS,CAAS;gBAGP,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM;IAKzB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC9B,WAAW,IAAI,OAAO;IAIhB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IASjC,iBAAiB,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI;IAIjD,oBAAoB,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI;IAIpD;;OAEG;IACH,OAAO,CAAC,UAAU;IAKlB;;OAEG;IACH,OAAO,CAAC,aAAa;IA2BrB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAc5B;;OAEG;IACH,OAAO,CAAC,cAAc;IAStB;;OAEG;IACH,OAAO,CAAC,WAAW;IAWnB;;OAEG;IACH,OAAO,CAAC,eAAe;CASxB"}
1
+ {"version":3,"file":"packet-stream-client.d.ts","sourceRoot":"","sources":["../../../../src/lib/tunnel/packet-stream-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAUtC;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,YAAY;IAOhD,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAPvB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkC;IAClE,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,SAAS,CAAS;gBAGP,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM;IAKzB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC9B,WAAW,IAAI,OAAO;IAIhB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IASjC,iBAAiB,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI;IAIjD,oBAAoB,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI;IAIpD;;OAEG;IACH,OAAO,CAAC,UAAU;IAKlB;;OAEG;IACH,OAAO,CAAC,aAAa;IA2BrB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAc5B;;OAEG;IACH,OAAO,CAAC,cAAc;IAStB;;OAEG;IACH,OAAO,CAAC,WAAW;IAWnB;;OAEG;IACH,OAAO,CAAC,eAAe;CASxB"}