appium-ios-remotexpc 0.21.1 → 0.22.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.
Files changed (92) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/build/src/lib/apple-tv/constants.d.ts +4 -3
  3. package/build/src/lib/apple-tv/constants.d.ts.map +1 -1
  4. package/build/src/lib/apple-tv/constants.js +10 -3
  5. package/build/src/lib/apple-tv/discovery/device-discovery.d.ts.map +1 -1
  6. package/build/src/lib/apple-tv/discovery/device-discovery.js +2 -2
  7. package/build/src/lib/apple-tv/encryption/index.d.ts +1 -0
  8. package/build/src/lib/apple-tv/encryption/index.d.ts.map +1 -1
  9. package/build/src/lib/apple-tv/encryption/index.js +1 -0
  10. package/build/src/lib/apple-tv/encryption/x25519.d.ts +8 -0
  11. package/build/src/lib/apple-tv/encryption/x25519.d.ts.map +1 -0
  12. package/build/src/lib/apple-tv/encryption/x25519.js +52 -0
  13. package/build/src/lib/apple-tv/index.d.ts +1 -0
  14. package/build/src/lib/apple-tv/index.d.ts.map +1 -1
  15. package/build/src/lib/apple-tv/index.js +1 -0
  16. package/build/src/lib/apple-tv/network/network-client.js +2 -2
  17. package/build/src/lib/apple-tv/pairing/user-input-service.d.ts.map +1 -1
  18. package/build/src/lib/apple-tv/pairing/user-input-service.js +2 -2
  19. package/build/src/lib/apple-tv/pairing-protocol/constants.d.ts +17 -0
  20. package/build/src/lib/apple-tv/pairing-protocol/constants.d.ts.map +1 -1
  21. package/build/src/lib/apple-tv/pairing-protocol/constants.js +25 -0
  22. package/build/src/lib/apple-tv/pairing-protocol/index.d.ts +2 -1
  23. package/build/src/lib/apple-tv/pairing-protocol/index.d.ts.map +1 -1
  24. package/build/src/lib/apple-tv/pairing-protocol/index.js +2 -1
  25. package/build/src/lib/apple-tv/pairing-protocol/pair-verification-protocol.d.ts +66 -0
  26. package/build/src/lib/apple-tv/pairing-protocol/pair-verification-protocol.d.ts.map +1 -0
  27. package/build/src/lib/apple-tv/pairing-protocol/pair-verification-protocol.js +178 -0
  28. package/build/src/lib/apple-tv/pairing-protocol/pairing-protocol.d.ts +35 -2
  29. package/build/src/lib/apple-tv/pairing-protocol/pairing-protocol.d.ts.map +1 -1
  30. package/build/src/lib/apple-tv/pairing-protocol/pairing-protocol.js +48 -14
  31. package/build/src/lib/apple-tv/storage/index.d.ts +1 -1
  32. package/build/src/lib/apple-tv/storage/index.d.ts.map +1 -1
  33. package/build/src/lib/apple-tv/storage/pairing-storage.d.ts +4 -1
  34. package/build/src/lib/apple-tv/storage/pairing-storage.d.ts.map +1 -1
  35. package/build/src/lib/apple-tv/storage/pairing-storage.js +59 -4
  36. package/build/src/lib/apple-tv/storage/types.d.ts +7 -1
  37. package/build/src/lib/apple-tv/storage/types.d.ts.map +1 -1
  38. package/build/src/lib/apple-tv/tunnel/index.d.ts +3 -0
  39. package/build/src/lib/apple-tv/tunnel/index.d.ts.map +1 -0
  40. package/build/src/lib/apple-tv/tunnel/index.js +1 -0
  41. package/build/src/lib/apple-tv/tunnel/tunnel-service.d.ts +57 -0
  42. package/build/src/lib/apple-tv/tunnel/tunnel-service.d.ts.map +1 -0
  43. package/build/src/lib/apple-tv/tunnel/tunnel-service.js +357 -0
  44. package/build/src/lib/apple-tv/tunnel/types.d.ts +22 -0
  45. package/build/src/lib/apple-tv/tunnel/types.d.ts.map +1 -0
  46. package/build/src/lib/apple-tv/tunnel/types.js +1 -0
  47. package/build/src/lib/bonjour/bonjour-discovery.d.ts.map +1 -1
  48. package/build/src/lib/bonjour/bonjour-discovery.js +3 -3
  49. package/build/src/lib/lockdown/index.d.ts.map +1 -1
  50. package/build/src/lib/plist/length-based-splitter.d.ts.map +1 -1
  51. package/build/src/lib/plist/length-based-splitter.js +0 -7
  52. package/build/src/lib/tunnel/index.d.ts +1 -0
  53. package/build/src/lib/tunnel/index.d.ts.map +1 -1
  54. package/build/src/lib/tunnel/packet-stream-server.d.ts.map +1 -1
  55. package/build/src/lib/tunnel/tunnel-registry-server.d.ts +1 -0
  56. package/build/src/lib/tunnel/tunnel-registry-server.d.ts.map +1 -1
  57. package/build/src/lib/tunnel/tunnel-registry-server.js +1 -1
  58. package/build/src/services/ios/afc/index.d.ts.map +1 -1
  59. package/build/src/services/ios/afc/index.js +14 -2
  60. package/build/src/services/ios/afc/stream-utils.d.ts.map +1 -1
  61. package/build/src/services/ios/afc/stream-utils.js +0 -2
  62. package/build/src/services/ios/mobile-config/index.js +2 -2
  63. package/package.json +2 -1
  64. package/scripts/pair-appletv.ts +2 -2
  65. package/scripts/start-appletv-tunnel.ts +178 -0
  66. package/scripts/test-tunnel-creation.ts +32 -23
  67. package/src/lib/apple-tv/constants.ts +11 -3
  68. package/src/lib/apple-tv/discovery/device-discovery.ts +2 -3
  69. package/src/lib/apple-tv/encryption/index.ts +6 -0
  70. package/src/lib/apple-tv/encryption/x25519.ts +79 -0
  71. package/src/lib/apple-tv/index.ts +1 -0
  72. package/src/lib/apple-tv/network/network-client.ts +2 -2
  73. package/src/lib/apple-tv/pairing/user-input-service.ts +2 -2
  74. package/src/lib/apple-tv/pairing-protocol/constants.ts +29 -0
  75. package/src/lib/apple-tv/pairing-protocol/index.ts +12 -1
  76. package/src/lib/apple-tv/pairing-protocol/pair-verification-protocol.ts +329 -0
  77. package/src/lib/apple-tv/pairing-protocol/pairing-protocol.ts +49 -19
  78. package/src/lib/apple-tv/storage/index.ts +1 -1
  79. package/src/lib/apple-tv/storage/pairing-storage.ts +73 -5
  80. package/src/lib/apple-tv/storage/types.ts +8 -1
  81. package/src/lib/apple-tv/tunnel/index.ts +2 -0
  82. package/src/lib/apple-tv/tunnel/tunnel-service.ts +543 -0
  83. package/src/lib/apple-tv/tunnel/types.ts +23 -0
  84. package/src/lib/bonjour/bonjour-discovery.ts +3 -5
  85. package/src/lib/lockdown/index.ts +0 -7
  86. package/src/lib/plist/length-based-splitter.ts +0 -22
  87. package/src/lib/tunnel/index.ts +2 -8
  88. package/src/lib/tunnel/packet-stream-server.ts +0 -8
  89. package/src/lib/tunnel/tunnel-registry-server.ts +1 -1
  90. package/src/services/ios/afc/index.ts +14 -3
  91. package/src/services/ios/afc/stream-utils.ts +0 -2
  92. package/src/services/ios/mobile-config/index.ts +2 -2
@@ -1,6 +1,6 @@
1
- import { logger } from '@appium/support';
2
1
  import { randomBytes } from 'node:crypto';
3
2
  import { hostname } from 'node:os';
3
+ import { getLogger } from '../../logger.js';
4
4
  import { DEFAULT_PAIRING_CONFIG, PairingDataComponentType, } from '../constants.js';
5
5
  import { encodeAppleTVDeviceInfo } from '../deviceInfo/index.js';
6
6
  import { createEd25519Signature, decryptChaCha20Poly1305, encryptChaCha20Poly1305, generateEd25519KeyPair, hkdf, } from '../encryption/index.js';
@@ -11,11 +11,45 @@ import { PairingStorage } from '../storage/pairing-storage.js';
11
11
  import { createPairVerificationData, createSetupManualPairingData, decodeTLV8ToDict, encodeTLV8, } from '../tlv/index.js';
12
12
  import { generateHostId } from '../utils/uuid-generator.js';
13
13
  import { INFO_TYPE, PAIRING_MESSAGES, PAIRING_STATES } from './constants.js';
14
- /** Implements the Apple TV pairing protocol including SRP authentication and key exchange */
14
+ const log = getLogger('PairingProtocol');
15
+ /**
16
+ * Implements the HomeKit Accessory Protocol (HAP) Pair-Setup process for Apple TV.
17
+ *
18
+ * Protocol Overview:
19
+ * This class implements the HAP Pair-Setup protocol, which establishes a secure pairing
20
+ * between a controller (this client) and an Apple TV accessory. The protocol uses SRP
21
+ * (Secure Remote Password) authentication to verify a user-provided PIN without transmitting
22
+ * the PIN itself over the network.
23
+ *
24
+ * Message Exchange Flow (M1-M6):
25
+ * - M1/M2: Initial setup request and SRP challenge (salt + server public key)
26
+ * - M3/M4: Client sends SRP proof, server validates and responds
27
+ * - M5/M6: Exchange of long-term public keys and signatures (encrypted)
28
+ *
29
+ * After successful pairing, the generated Ed25519 key pair is stored and used for
30
+ * subsequent Pair-Verify operations to establish encrypted sessions.
31
+ *
32
+ * Technical Details:
33
+ * - Uses SRP-6a protocol for password-authenticated key exchange (RFC 5054)
34
+ * - Employs Ed25519 for long-term identity keys (RFC 8032)
35
+ * - Uses ChaCha20-Poly1305 for authenticated encryption (RFC 8439)
36
+ * - Derives session keys using HKDF (RFC 5869)
37
+ * - Encodes messages in TLV8 (Type-Length-Value) format
38
+ *
39
+ * References:
40
+ * - HAP Specification: https://developer.apple.com/homekit/ (Apple Developer)
41
+ * - HAP-NodeJS (community implementation): https://github.com/homebridge/HAP-NodeJS
42
+ * - SRP Protocol: https://datatracker.ietf.org/doc/html/rfc5054
43
+ * - Ed25519: https://datatracker.ietf.org/doc/html/rfc8032
44
+ * - ChaCha20-Poly1305: https://datatracker.ietf.org/doc/html/rfc8439
45
+ * - HKDF: https://datatracker.ietf.org/doc/html/rfc5869
46
+ *
47
+ * @see PairVerificationProtocol for the verification protocol used after pairing
48
+ * @see SRPClient for SRP authentication implementation
49
+ */
15
50
  export class PairingProtocol {
16
51
  networkClient;
17
52
  userInput;
18
- static log = logger.getLogger('PairingProtocol');
19
53
  _sequenceNumber = 0;
20
54
  constructor(networkClient, userInput) {
21
55
  this.networkClient = networkClient;
@@ -43,7 +77,7 @@ export class PairingProtocol {
43
77
  return this.createPairingResult(device, ltpk, ltsk);
44
78
  }
45
79
  catch (error) {
46
- PairingProtocol.log.error('Pairing flow failed:', error);
80
+ log.error('Pairing flow failed:', error);
47
81
  throw error;
48
82
  }
49
83
  }
@@ -90,7 +124,7 @@ export class PairingProtocol {
90
124
  const request = this.createHandshakeRequest();
91
125
  await this.networkClient.sendPacket(request);
92
126
  await this.networkClient.receiveResponse();
93
- PairingProtocol.log.debug('Handshake completed');
127
+ log.debug('Handshake completed');
94
128
  }
95
129
  /**
96
130
  * Attempts to verify existing pairing credentials with Apple TV
@@ -102,7 +136,7 @@ export class PairingProtocol {
102
136
  await this.networkClient.receiveResponse();
103
137
  const failedRequest = this.createPairVerifyFailedRequest();
104
138
  await this.networkClient.sendPacket(failedRequest);
105
- PairingProtocol.log.debug('Pair verification attempt completed');
139
+ log.debug('Pair verification attempt completed');
106
140
  }
107
141
  /**
108
142
  * Initiates manual pairing setup process with Apple TV
@@ -113,7 +147,7 @@ export class PairingProtocol {
113
147
  const request = this.createSetupManualPairingRequest();
114
148
  await this.networkClient.sendPacket(request);
115
149
  const response = await this.networkClient.receiveResponse();
116
- PairingProtocol.log.debug('Manual pairing setup completed');
150
+ log.debug('Manual pairing setup completed');
117
151
  return response;
118
152
  }
119
153
  /**
@@ -144,7 +178,7 @@ export class PairingProtocol {
144
178
  await this.sendSRPProof(srpClient);
145
179
  const response = await this.networkClient.receiveResponse();
146
180
  this.validateSRPProofResponse(response);
147
- PairingProtocol.log.debug('SRP authentication completed');
181
+ log.debug('SRP authentication completed');
148
182
  return srpClient;
149
183
  }
150
184
  /**
@@ -154,12 +188,12 @@ export class PairingProtocol {
154
188
  */
155
189
  async receiveM6Completion(decryptKey) {
156
190
  const m6Response = await this.networkClient.receiveResponse();
157
- PairingProtocol.log.info('M6 Response received');
191
+ log.info('M6 Response received');
158
192
  try {
159
193
  this.processM6Response(m6Response, decryptKey);
160
194
  }
161
195
  catch (error) {
162
- PairingProtocol.log.warn('M6 decryption failed - but pairing may still be successful:', error.message);
196
+ log.warn('M6 decryption failed - but pairing may still be successful:', error.message);
163
197
  }
164
198
  }
165
199
  /**
@@ -443,10 +477,10 @@ export class PairingProtocol {
443
477
  const m6DataBase64 = m6Response.message.plain._0.event._0.pairingData._0.data;
444
478
  const m6TLVBuffer = Buffer.from(m6DataBase64, 'base64');
445
479
  const m6Parsed = decodeTLV8ToDict(m6TLVBuffer);
446
- PairingProtocol.log.debug('M6 TLV types received:', Object.keys(m6Parsed).map((k) => `0x${Number(k).toString(16)}`));
480
+ log.debug('M6 TLV types received:', Object.keys(m6Parsed).map((k) => `0x${Number(k).toString(16)}`));
447
481
  const stateData = m6Parsed[PairingDataComponentType.STATE];
448
482
  if (stateData && stateData[0] === PAIRING_STATES.M6) {
449
- PairingProtocol.log.info('✅ Pairing completed successfully (STATE=0x06)');
483
+ log.info('✅ Pairing completed successfully (STATE=0x06)');
450
484
  }
451
485
  const encryptedData = m6Parsed[PairingDataComponentType.ENCRYPTED_DATA];
452
486
  if (encryptedData) {
@@ -457,7 +491,7 @@ export class PairingProtocol {
457
491
  nonce,
458
492
  });
459
493
  const decryptedTLV = decodeTLV8ToDict(decrypted);
460
- PairingProtocol.log.debug('M6 decrypted content types:', Object.keys(decryptedTLV));
494
+ log.debug('M6 decrypted content types:', Object.keys(decryptedTLV));
461
495
  }
462
496
  }
463
497
  /**
@@ -473,7 +507,7 @@ export class PairingProtocol {
473
507
  info: Buffer.from(PAIRING_MESSAGES.ENCRYPT_INFO, 'utf8'),
474
508
  length: 32,
475
509
  });
476
- PairingProtocol.log.debug('Derived encryption keys');
510
+ log.debug('Derived encryption keys');
477
511
  return {
478
512
  encryptKey: sharedKey,
479
513
  decryptKey: sharedKey,
@@ -1,3 +1,3 @@
1
1
  export { PairingStorage } from './pairing-storage.js';
2
- export type { PairingStorageInterface } from './types.js';
2
+ export type { PairingStorageInterface, PairRecord } from './types.js';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/lib/apple-tv/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/lib/apple-tv/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
@@ -1,12 +1,15 @@
1
1
  import type { PairingConfig } from '../types.js';
2
- import type { PairingStorageInterface } from './types.js';
2
+ import type { PairRecord, PairingStorageInterface } from './types.js';
3
3
  /** Manages persistent storage of pairing credentials as plist files */
4
4
  export declare class PairingStorage implements PairingStorageInterface {
5
5
  private readonly config;
6
6
  private readonly log;
7
7
  private readonly box;
8
+ private strongboxDir?;
8
9
  constructor(config: PairingConfig);
9
10
  save(deviceId: string, ltpk: Buffer, ltsk: Buffer, remoteUnlockHostKey?: string): Promise<string>;
11
+ load(deviceId: string): Promise<PairRecord | null>;
12
+ getAvailableDeviceIds(): Promise<string[]>;
10
13
  private createPlistContent;
11
14
  }
12
15
  //# sourceMappingURL=pairing-storage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pairing-storage.d.ts","sourceRoot":"","sources":["../../../../../src/lib/apple-tv/storage/pairing-storage.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D,uEAAuE;AACvE,qBAAa,cAAe,YAAW,uBAAuB;IAIhD,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAsC;IAC1D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAEQ,MAAM,EAAE,aAAa;IAI5C,IAAI,CACR,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,mBAAmB,SAAK,GACvB,OAAO,CAAC,MAAM,CAAC;IAyBlB,OAAO,CAAC,kBAAkB;CAW3B"}
1
+ {"version":3,"file":"pairing-storage.d.ts","sourceRoot":"","sources":["../../../../../src/lib/apple-tv/storage/pairing-storage.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAEtE,uEAAuE;AACvE,qBAAa,cAAe,YAAW,uBAAuB;IAKhD,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA+B;IACnD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;IACrB,OAAO,CAAC,YAAY,CAAC,CAAS;gBAED,MAAM,EAAE,aAAa;IAI5C,IAAI,CACR,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,mBAAmB,SAAK,GACvB,OAAO,CAAC,MAAM,CAAC;IAyBZ,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAwClD,qBAAqB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAwBhD,OAAO,CAAC,kBAAkB;CAW3B"}
@@ -1,20 +1,24 @@
1
1
  import { strongbox } from '@appium/strongbox';
2
- import { logger } from '@appium/support';
2
+ import { readdir } from 'node:fs/promises';
3
+ import { dirname } from 'node:path';
3
4
  import { STRONGBOX_CONTAINER_NAME } from '../../../constants.js';
4
- import { createXmlPlist } from '../../plist/index.js';
5
+ import { getLogger } from '../../logger.js';
6
+ import { createXmlPlist, parseXmlPlist } from '../../plist/index.js';
7
+ import { APPLETV_PAIRING_PREFIX } from '../constants.js';
5
8
  import { PairingError } from '../errors.js';
6
9
  /** Manages persistent storage of pairing credentials as plist files */
7
10
  export class PairingStorage {
8
11
  config;
9
- log = logger.getLogger('PairingStorage');
12
+ log = getLogger('PairingStorage');
10
13
  box;
14
+ strongboxDir;
11
15
  constructor(config) {
12
16
  this.config = config;
13
17
  this.box = strongbox(STRONGBOX_CONTAINER_NAME);
14
18
  }
15
19
  async save(deviceId, ltpk, ltsk, remoteUnlockHostKey = '') {
16
20
  try {
17
- const itemName = `appletv_pairing_${deviceId}`;
21
+ const itemName = `${APPLETV_PAIRING_PREFIX}${deviceId}`;
18
22
  const plistContent = this.createPlistContent(ltpk, ltsk, remoteUnlockHostKey);
19
23
  const item = await this.box.createItemWithValue(itemName, plistContent);
20
24
  const itemPath = item.id;
@@ -26,6 +30,57 @@ export class PairingStorage {
26
30
  throw new PairingError('Failed to save pairing record', 'SAVE_ERROR', error);
27
31
  }
28
32
  }
33
+ async load(deviceId) {
34
+ const itemName = `${APPLETV_PAIRING_PREFIX}${deviceId}`;
35
+ try {
36
+ const item = this.box.getItem(itemName) ?? (await this.box.createItem(itemName));
37
+ const pairingData = await item.read();
38
+ if (!pairingData) {
39
+ this.log.debug(`No pair record found for device ${deviceId}`);
40
+ return null;
41
+ }
42
+ const parsed = parseXmlPlist(pairingData);
43
+ if (!parsed.private_key || !parsed.public_key) {
44
+ throw new Error('Could not parse pairing record keys');
45
+ }
46
+ const privateKey = Buffer.isBuffer(parsed.private_key)
47
+ ? parsed.private_key
48
+ : Buffer.from(parsed.private_key, 'base64');
49
+ const publicKey = Buffer.isBuffer(parsed.public_key)
50
+ ? parsed.public_key
51
+ : Buffer.from(parsed.public_key, 'base64');
52
+ this.log.debug(`Loaded pair record for ${deviceId}`);
53
+ return {
54
+ privateKey,
55
+ publicKey,
56
+ remoteUnlockHostKey: parsed.remote_unlock_host_key || '',
57
+ };
58
+ }
59
+ catch (error) {
60
+ this.log.error(`Failed to load pair record for ${deviceId}:`, error);
61
+ return null;
62
+ }
63
+ }
64
+ async getAvailableDeviceIds() {
65
+ try {
66
+ if (!this.strongboxDir) {
67
+ const dummyItem = await this.box.createItem('_temp');
68
+ this.strongboxDir = dirname(dummyItem.id);
69
+ // Clean up the temporary item after extracting the directory path
70
+ await dummyItem.clear();
71
+ }
72
+ const files = await readdir(this.strongboxDir);
73
+ const deviceIds = files
74
+ .filter((file) => file.startsWith(APPLETV_PAIRING_PREFIX))
75
+ .map((file) => file.replace(APPLETV_PAIRING_PREFIX, ''));
76
+ this.log.debug(`Found ${deviceIds.length} pair record(s): ${deviceIds.join(', ')}`);
77
+ return deviceIds;
78
+ }
79
+ catch (error) {
80
+ this.log.debug('Error getting available device IDs:', error);
81
+ return [];
82
+ }
83
+ }
29
84
  createPlistContent(publicKey, privateKey, remoteUnlockHostKey) {
30
85
  return createXmlPlist({
31
86
  private_key: privateKey,
@@ -1,5 +1,11 @@
1
- /** Interface for storing pairing credentials to disk */
1
+ export interface PairRecord {
2
+ publicKey: Buffer;
3
+ privateKey: Buffer;
4
+ remoteUnlockHostKey: string;
5
+ }
2
6
  export interface PairingStorageInterface {
3
7
  save(deviceId: string, ltpk: Buffer, ltsk: Buffer, remoteUnlockHostKey?: string): Promise<string>;
8
+ load(deviceId: string): Promise<PairRecord | null>;
9
+ getAvailableDeviceIds(): Promise<string[]>;
4
10
  }
5
11
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/lib/apple-tv/storage/types.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,MAAM,WAAW,uBAAuB;IACtC,IAAI,CACF,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,mBAAmB,CAAC,EAAE,MAAM,GAC3B,OAAO,CAAC,MAAM,CAAC,CAAC;CACpB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/lib/apple-tv/storage/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,CACF,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,mBAAmB,CAAC,EAAE,MAAM,GAC3B,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACnD,qBAAqB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC5C"}
@@ -0,0 +1,3 @@
1
+ export { TunnelService, AppleTVTunnelService } from './tunnel-service.js';
2
+ export type { TcpListenerInfo } from './types.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/lib/apple-tv/tunnel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC1E,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1 @@
1
+ export { TunnelService, AppleTVTunnelService } from './tunnel-service.js';
@@ -0,0 +1,57 @@
1
+ import * as tls from 'node:tls';
2
+ import type { AppleTVDevice } from '../../bonjour/bonjour-discovery.js';
3
+ import type { NetworkClientInterface } from '../network/types.js';
4
+ import type { VerificationKeys } from '../pairing-protocol/pair-verification-protocol.js';
5
+ import type { TcpListenerInfo } from './types.js';
6
+ export declare class TunnelService {
7
+ private readonly networkClient;
8
+ private readonly keys;
9
+ private sequenceNumber;
10
+ private static readonly log;
11
+ private encryptedSequenceNumber;
12
+ constructor(networkClient: NetworkClientInterface, keys: VerificationKeys, sequenceNumber: number);
13
+ createTcpListener(): Promise<TcpListenerInfo>;
14
+ createTlsPskConnection(hostname: string, port: number): Promise<tls.TLSSocket>;
15
+ getSequenceNumber(): number;
16
+ }
17
+ /**
18
+ * High-level service for establishing Apple TV tunnels.
19
+ * Orchestrates device discovery, pairing verification, and tunnel creation.
20
+ */
21
+ export declare class AppleTVTunnelService {
22
+ private readonly networkClient;
23
+ private readonly storage;
24
+ private sequenceNumber;
25
+ constructor();
26
+ disconnect(): void;
27
+ startTunnel(deviceId?: string, specificDeviceIdentifier?: string): Promise<{
28
+ socket: tls.TLSSocket;
29
+ device: AppleTVDevice;
30
+ }>;
31
+ /**
32
+ * Logs information about discovered devices
33
+ */
34
+ private logDiscoveredDevices;
35
+ /**
36
+ * Selects devices to process based on the specific device identifier
37
+ */
38
+ private selectDevicesToProcess;
39
+ /**
40
+ * Validates pair records and returns the list of identifiers to try
41
+ */
42
+ private validateAndGetPairRecords;
43
+ /**
44
+ * Attempts to establish a connection with a device using a specific pair record
45
+ */
46
+ private attemptDeviceConnection;
47
+ /**
48
+ * Logs a summary of all failed connection attempts
49
+ */
50
+ private logFailureSummary;
51
+ private discoverDevices;
52
+ private performHandshake;
53
+ private performPairVerification;
54
+ private createTcpListener;
55
+ private createTlsPskConnection;
56
+ }
57
+ //# sourceMappingURL=tunnel-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tunnel-service.d.ts","sourceRoot":"","sources":["../../../../../src/lib/apple-tv/tunnel/tunnel-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAEhC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAUxE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mDAAmD,CAAC;AAG1F,OAAO,KAAK,EAAE,eAAe,EAA2B,MAAM,YAAY,CAAC;AAI3E,qBAAa,aAAa;IAKtB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,cAAc;IANxB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAA8B;IACzD,OAAO,CAAC,uBAAuB,CAAK;gBAGjB,aAAa,EAAE,sBAAsB,EACrC,IAAI,EAAE,gBAAgB,EAC/B,cAAc,EAAE,MAAM;IAG1B,iBAAiB,IAAI,OAAO,CAAC,eAAe,CAAC;IAoF7C,sBAAsB,CAC1B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;IAoEzB,iBAAiB,IAAI,MAAM;CAG5B;AAED;;;GAGG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,cAAc,CAAK;;IAO3B,UAAU,IAAI,IAAI;IAIZ,WAAW,CACf,QAAQ,CAAC,EAAE,MAAM,EACjB,wBAAwB,CAAC,EAAE,MAAM,GAChC,OAAO,CAAC;QAAE,MAAM,EAAE,GAAG,CAAC,SAAS,CAAC;QAAC,MAAM,EAAE,aAAa,CAAA;KAAE,CAAC;IAiD5D;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAgC9B;;OAEG;YACW,yBAAyB;IAgBvC;;OAEG;YACW,uBAAuB;IA2DrC;;OAEG;IACH,OAAO,CAAC,iBAAiB;YAWX,eAAe;YAoDf,gBAAgB;YA4BhB,uBAAuB;YAmBvB,iBAAiB;YAiBjB,sBAAsB;CAYrC"}