@basmilius/apple-common 0.8.2 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,4 @@
1
1
  /// <reference types="node" />
2
- import { DiscoveryResult as DiscoveryResult$1 } from "node-dns-sd";
3
2
  import { EventEmitter } from "node:events";
4
3
 
5
4
  //#region ../../node_modules/.bun/uuid@13.0.0/node_modules/uuid/dist/types.d.ts
@@ -12,20 +11,62 @@ type Version4Options = {
12
11
  declare function v4(options?: Version4Options, buf?: undefined, offset?: number): string;
13
12
  declare function v4<TBuf extends Uint8Array = Uint8Array>(options: Version4Options | undefined, buf: TBuf, offset?: number): TBuf;
14
13
  //#endregion
15
- //#region src/discovery.d.ts
16
- declare class Discovery {
17
- #private;
18
- constructor(service: string);
19
- find(): Promise<DiscoveryResult$1[]>;
20
- findUntil(id: string, tries?: number, timeout?: number): Promise<DiscoveryResult$1>;
21
- static airplay(): Discovery;
22
- static companionLink(): Discovery;
23
- static raop(): Discovery;
24
- }
25
- //#endregion
26
- //#region src/cli.d.ts
27
- declare function prompt(message: string): Promise<string>;
28
- declare function waitFor(ms: number): Promise<void>;
14
+ //#region src/airplayFeatures.d.ts
15
+ declare const AirPlayFeatureFlags: {
16
+ readonly SupportsAirPlayVideoV1: bigint;
17
+ readonly SupportsAirPlayPhoto: bigint;
18
+ readonly SupportsAirPlayVideoFairPlay: bigint;
19
+ readonly SupportsAirPlayVideoVolumeControl: bigint;
20
+ readonly SupportsAirPlayVideoHTTPLiveStreams: bigint;
21
+ readonly SupportsAirPlaySlideShow: bigint;
22
+ readonly SupportsAirPlayScreen: bigint;
23
+ readonly SupportsAirPlayAudio: bigint;
24
+ readonly AudioRedundant: bigint;
25
+ readonly Authentication_4: bigint;
26
+ readonly MetadataFeatures_0: bigint;
27
+ readonly MetadataFeatures_1: bigint;
28
+ readonly MetadataFeatures_2: bigint;
29
+ readonly AudioFormats_0: bigint;
30
+ readonly AudioFormats_1: bigint;
31
+ readonly AudioFormats_2: bigint;
32
+ readonly AudioFormats_3: bigint;
33
+ readonly Authentication_1: bigint;
34
+ readonly Authentication_8: bigint;
35
+ readonly SupportsLegacyPairing: bigint;
36
+ readonly HasUnifiedAdvertiserInfo: bigint;
37
+ readonly IsCarPlay: bigint;
38
+ readonly SupportsAirPlayVideoPlayQueue: bigint;
39
+ readonly SupportsAirPlayFromCloud: bigint;
40
+ readonly SupportsTLS_PSK: bigint;
41
+ readonly SupportsUnifiedMediaControl: bigint;
42
+ readonly SupportsBufferedAudio: bigint;
43
+ readonly SupportsPTP: bigint;
44
+ readonly SupportsScreenMultiCodec: bigint;
45
+ readonly SupportsSystemPairing: bigint;
46
+ readonly IsAPValeriaScreenSender: bigint;
47
+ readonly SupportsHKPairingAndAccessControl: bigint;
48
+ readonly SupportsCoreUtilsPairingAndEncryption: bigint;
49
+ readonly SupportsAirPlayVideoV2: bigint;
50
+ readonly MetadataFeatures_3: bigint;
51
+ readonly SupportsUnifiedPairSetupAndMFi: bigint;
52
+ readonly SupportsSetPeersExtendedMessage: bigint;
53
+ readonly SupportsAPSync: bigint;
54
+ readonly SupportsWoL: bigint;
55
+ readonly SupportsWoL2: bigint;
56
+ readonly SupportsHangdogRemoteControl: bigint;
57
+ readonly SupportsAudioStreamConnectionSetup: bigint;
58
+ readonly SupportsAudioMetadataControl: bigint;
59
+ readonly SupportsRFC2198Redundancy: bigint;
60
+ };
61
+ type AirPlayFeatureFlagName = keyof typeof AirPlayFeatureFlags;
62
+ type PairingRequirement = 'none' | 'pin' | 'transient' | 'homekit';
63
+ declare const parseFeatures: (features: string) => bigint;
64
+ declare const hasFeatureFlag: (features: bigint, flag: bigint) => boolean;
65
+ declare const describeFlags: (features: bigint) => AirPlayFeatureFlagName[];
66
+ declare const getProtocolVersion: (txt: Record<string, string>) => 1 | 2;
67
+ declare const getPairingRequirement: (txt: Record<string, string>) => PairingRequirement;
68
+ declare const isPasswordRequired: (txt: Record<string, string>) => boolean;
69
+ declare const isRemoteControlSupported: (txt: Record<string, string>) => boolean;
29
70
  //#endregion
30
71
  //#region src/reporter.d.ts
31
72
  type DebugGroup = 'debug' | 'error' | 'info' | 'net' | 'raw' | 'warn';
@@ -58,8 +99,107 @@ declare class Context {
58
99
  constructor(deviceId: string);
59
100
  }
60
101
  //#endregion
61
- //#region src/symbols.d.ts
62
- declare const ENCRYPTION: unique symbol;
102
+ //#region src/pairing.d.ts
103
+ declare abstract class BasePairing {
104
+ #private;
105
+ get context(): Context;
106
+ constructor(context: Context);
107
+ tlv(buffer: Buffer): Map<number, Buffer>;
108
+ }
109
+ declare class AccessoryPair extends BasePairing {
110
+ #private;
111
+ constructor(context: Context, requestHandler: RequestHandler);
112
+ start(): Promise<void>;
113
+ pin(askPin: () => Promise<string>): Promise<AccessoryCredentials>;
114
+ transient(): Promise<AccessoryKeys>;
115
+ m1(additionalTlv?: [number, number | Buffer][]): Promise<PairM1>;
116
+ m2(m1: PairM1, pin?: string): Promise<PairM2>;
117
+ m3(m2: PairM2): Promise<PairM3>;
118
+ m4(m3: PairM3): Promise<PairM4>;
119
+ m5(m4: PairM4): Promise<PairM5>;
120
+ m6(m4: PairM4, m5: PairM5): Promise<AccessoryCredentials>;
121
+ }
122
+ declare class AccessoryVerify extends BasePairing {
123
+ #private;
124
+ constructor(context: Context, requestHandler: RequestHandler);
125
+ start(credentials: AccessoryCredentials): Promise<AccessoryKeys>;
126
+ }
127
+ type RequestHandler = (step: 'm1' | 'm3' | 'm5', data: Buffer) => Promise<Buffer>;
128
+ type PairM1 = {
129
+ readonly publicKey: Buffer;
130
+ readonly salt: Buffer;
131
+ };
132
+ type PairM2 = {
133
+ readonly publicKey: Buffer;
134
+ readonly proof: Buffer;
135
+ };
136
+ type PairM3 = {
137
+ readonly serverProof: Buffer;
138
+ };
139
+ type PairM4 = {
140
+ readonly sharedSecret: Buffer;
141
+ };
142
+ type PairM5 = {
143
+ readonly authTag: Buffer;
144
+ readonly data: Buffer;
145
+ readonly sessionKey: Buffer;
146
+ };
147
+ type AccessoryCredentials = {
148
+ readonly accessoryIdentifier: string;
149
+ readonly accessoryLongTermPublicKey: Buffer;
150
+ readonly pairingId: Buffer;
151
+ readonly publicKey: Buffer;
152
+ readonly secretKey: Buffer;
153
+ };
154
+ type AccessoryKeys = {
155
+ readonly pairingId: Buffer;
156
+ readonly sharedSecret: Buffer;
157
+ readonly accessoryToControllerKey: Buffer;
158
+ readonly controllerToAccessoryKey: Buffer;
159
+ };
160
+ //#endregion
161
+ //#region src/storage.d.ts
162
+ type ProtocolType = 'airplay' | 'companionLink' | 'raop';
163
+ type StoredDevice = {
164
+ readonly identifier: string;
165
+ readonly name: string;
166
+ };
167
+ type StorageData = {
168
+ version: 1;
169
+ devices: Record<string, StoredDevice>;
170
+ credentials: Record<string, SerializedCredentials>;
171
+ };
172
+ type SerializedCredentials = {
173
+ readonly accessoryIdentifier: string;
174
+ readonly accessoryLongTermPublicKey: string;
175
+ readonly pairingId: string;
176
+ readonly publicKey: string;
177
+ readonly secretKey: string;
178
+ };
179
+ declare abstract class Storage {
180
+ #private;
181
+ get data(): StorageData;
182
+ abstract load(): Promise<void>;
183
+ abstract save(): Promise<void>;
184
+ protected setData(data: StorageData): void;
185
+ getDevice(identifier: string): StoredDevice | undefined;
186
+ setDevice(identifier: string, device: StoredDevice): void;
187
+ removeDevice(identifier: string): void;
188
+ listDevices(): StoredDevice[];
189
+ getCredentials(deviceId: string, protocol: ProtocolType): AccessoryCredentials | undefined;
190
+ setCredentials(deviceId: string, protocol: ProtocolType, credentials: AccessoryCredentials): void;
191
+ removeCredentials(deviceId: string, protocol: ProtocolType): void;
192
+ }
193
+ declare class JsonStorage extends Storage {
194
+ #private;
195
+ constructor(path?: string);
196
+ load(): Promise<void>;
197
+ save(): Promise<void>;
198
+ }
199
+ declare class MemoryStorage extends Storage {
200
+ load(): Promise<void>;
201
+ save(): Promise<void>;
202
+ }
63
203
  //#endregion
64
204
  //#region src/types.d.ts
65
205
  type ConnectionState = 'closing' | 'connected' | 'connecting' | 'disconnected' | 'failed';
@@ -145,7 +285,48 @@ type Result = {
145
285
  type DiscoveryResult = {
146
286
  readonly id: string;
147
287
  readonly txt: Record<string, string>;
288
+ readonly features?: bigint;
148
289
  } & Result;
290
+ type CombinedDiscoveryResult = {
291
+ readonly id: string;
292
+ readonly name: string;
293
+ readonly address: string;
294
+ airplay?: DiscoveryResult;
295
+ companionLink?: DiscoveryResult;
296
+ raop?: DiscoveryResult;
297
+ };
298
+ //#endregion
299
+ //#region src/discovery.d.ts
300
+ declare class Discovery {
301
+ #private;
302
+ constructor(service: string);
303
+ find(useCache?: boolean): Promise<DiscoveryResult[]>;
304
+ findUntil(id: string, tries?: number, timeout?: number): Promise<DiscoveryResult>;
305
+ static clearCache(): void;
306
+ static wake(address: string): Promise<void>;
307
+ static discoverAll(): Promise<CombinedDiscoveryResult[]>;
308
+ static airplay(): Discovery;
309
+ static companionLink(): Discovery;
310
+ static raop(): Discovery;
311
+ }
312
+ //#endregion
313
+ //#region src/mdns.d.ts
314
+ type MdnsService = {
315
+ readonly name: string;
316
+ readonly type: string;
317
+ readonly address: string;
318
+ readonly port: number;
319
+ readonly properties: Record<string, string>;
320
+ };
321
+ declare const unicast: (hosts: string[], services: string[], timeout?: number) => Promise<MdnsService[]>;
322
+ declare const multicast: (services: string[], timeout?: number) => Promise<MdnsService[]>;
323
+ //#endregion
324
+ //#region src/cli.d.ts
325
+ declare function prompt(message: string): Promise<string>;
326
+ declare function waitFor(ms: number): Promise<void>;
327
+ //#endregion
328
+ //#region src/symbols.d.ts
329
+ declare const ENCRYPTION: unique symbol;
149
330
  //#endregion
150
331
  //#region src/connection.d.ts
151
332
  type ConnectionEventMap = {
@@ -191,65 +372,6 @@ declare const AIRPLAY_SERVICE = "_airplay._tcp.local";
191
372
  declare const COMPANION_LINK_SERVICE = "_companion-link._tcp.local";
192
373
  declare const RAOP_SERVICE = "_raop._tcp.local";
193
374
  //#endregion
194
- //#region src/pairing.d.ts
195
- declare abstract class BasePairing {
196
- #private;
197
- get context(): Context;
198
- constructor(context: Context);
199
- tlv(buffer: Buffer): Map<number, Buffer>;
200
- }
201
- declare class AccessoryPair extends BasePairing {
202
- #private;
203
- constructor(context: Context, requestHandler: RequestHandler);
204
- start(): Promise<void>;
205
- pin(askPin: () => Promise<string>): Promise<AccessoryCredentials>;
206
- transient(): Promise<AccessoryKeys>;
207
- m1(additionalTlv?: [number, number | Buffer][]): Promise<PairM1>;
208
- m2(m1: PairM1, pin?: string): Promise<PairM2>;
209
- m3(m2: PairM2): Promise<PairM3>;
210
- m4(m3: PairM3): Promise<PairM4>;
211
- m5(m4: PairM4): Promise<PairM5>;
212
- m6(m4: PairM4, m5: PairM5): Promise<AccessoryCredentials>;
213
- }
214
- declare class AccessoryVerify extends BasePairing {
215
- #private;
216
- constructor(context: Context, requestHandler: RequestHandler);
217
- start(credentials: AccessoryCredentials): Promise<AccessoryKeys>;
218
- }
219
- type RequestHandler = (step: 'm1' | 'm3' | 'm5', data: Buffer) => Promise<Buffer>;
220
- type PairM1 = {
221
- readonly publicKey: Buffer;
222
- readonly salt: Buffer;
223
- };
224
- type PairM2 = {
225
- readonly publicKey: Buffer;
226
- readonly proof: Buffer;
227
- };
228
- type PairM3 = {
229
- readonly serverProof: Buffer;
230
- };
231
- type PairM4 = {
232
- readonly sharedSecret: Buffer;
233
- };
234
- type PairM5 = {
235
- readonly authTag: Buffer;
236
- readonly data: Buffer;
237
- readonly sessionKey: Buffer;
238
- };
239
- type AccessoryCredentials = {
240
- readonly accessoryIdentifier: string;
241
- readonly accessoryLongTermPublicKey: Buffer;
242
- readonly pairingId: Buffer;
243
- readonly publicKey: Buffer;
244
- readonly secretKey: Buffer;
245
- };
246
- type AccessoryKeys = {
247
- readonly pairingId: Buffer;
248
- readonly sharedSecret: Buffer;
249
- readonly accessoryToControllerKey: Buffer;
250
- readonly controllerToAccessoryKey: Buffer;
251
- };
252
- //#endregion
253
375
  //#region src/timing.d.ts
254
376
  declare class TimingServer {
255
377
  #private;
@@ -279,5 +401,4 @@ interface AudioSource {
279
401
  stop(): Promise<void>;
280
402
  }
281
403
  //#endregion
282
- export { AIRPLAY_SERVICE, AIRPLAY_TRANSIENT_PIN, type AccessoryCredentials, type AccessoryKeys, AccessoryPair, AccessoryVerify, type AudioSource, COMPANION_LINK_SERVICE, Connection, type ConnectionState, Context, Discovery, type DiscoveryResult, ENCRYPTION, EncryptionAwareConnection, EncryptionState, type EventMap, HTTP_TIMEOUT, type Logger, RAOP_SERVICE, type Reporter, TimingServer, generateActiveRemoteId, generateDacpId, generateSessionId, getLocalIP, getMacAddress, prompt, randomInt32, randomInt64, reporter, uint16ToBE, uint53ToLE, v4 as uuid, waitFor };
283
- //# sourceMappingURL=index.d.mts.map
404
+ export { AIRPLAY_SERVICE, AIRPLAY_TRANSIENT_PIN, type AccessoryCredentials, type AccessoryKeys, AccessoryPair, AccessoryVerify, type AirPlayFeatureFlagName, AirPlayFeatureFlags, type AudioSource, COMPANION_LINK_SERVICE, type CombinedDiscoveryResult, Connection, type ConnectionState, Context, Discovery, type DiscoveryResult, ENCRYPTION, EncryptionAwareConnection, EncryptionState, type EventMap, HTTP_TIMEOUT, JsonStorage, type Logger, type MdnsService, MemoryStorage, type PairingRequirement, type ProtocolType, RAOP_SERVICE, type Reporter, Storage, type StorageData, type StoredDevice, TimingServer, describeFlags, generateActiveRemoteId, generateDacpId, generateSessionId, getLocalIP, getMacAddress, getPairingRequirement, getProtocolVersion, hasFeatureFlag, isPasswordRequired, isRemoteControlSupported, multicast as mdnsMulticast, unicast as mdnsUnicast, parseFeatures, prompt, randomInt32, randomInt64, reporter, uint16ToBE, uint53ToLE, v4 as uuid, waitFor };
package/dist/index.mjs CHANGED
@@ -1,14 +1,20 @@
1
+ import { createRequire } from "node:module";
1
2
  import { randomBytes, randomFillSync, randomUUID } from "node:crypto";
2
- import mdns from "node-dns-sd";
3
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
+ import { dirname, join } from "node:path";
5
+ import { Socket, createConnection } from "node:net";
3
6
  import { createInterface } from "node:readline";
7
+ import { createSocket } from "node:dgram";
8
+ import { networkInterfaces } from "node:os";
4
9
  import { EventEmitter } from "node:events";
5
- import { Socket } from "node:net";
6
10
  import { NTP, OPack, TLV8 } from "@basmilius/apple-encoding";
7
11
  import { Chacha20, Curve25519, Ed25519, hkdf } from "@basmilius/apple-encryption";
8
12
  import { SRP, SrpClient } from "fast-srp-hap";
9
- import { createSocket } from "node:dgram";
10
- import { networkInterfaces } from "node:os";
11
13
 
14
+ //#region \0rolldown/runtime.js
15
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
16
+
17
+ //#endregion
12
18
  //#region ../../node_modules/.bun/uuid@13.0.0/node_modules/uuid/dist-node/stringify.js
13
19
  const byteToHex = [];
14
20
  for (let i = 0; i < 256; ++i) byteToHex.push((i + 256).toString(16).slice(1));
@@ -53,6 +59,178 @@ function v4(options, buf, offset) {
53
59
  return _v4(options, buf, offset);
54
60
  }
55
61
 
62
+ //#endregion
63
+ //#region src/airplayFeatures.ts
64
+ const AirPlayFeatureFlags = {
65
+ SupportsAirPlayVideoV1: 1n << 0n,
66
+ SupportsAirPlayPhoto: 1n << 1n,
67
+ SupportsAirPlayVideoFairPlay: 1n << 2n,
68
+ SupportsAirPlayVideoVolumeControl: 1n << 3n,
69
+ SupportsAirPlayVideoHTTPLiveStreams: 1n << 4n,
70
+ SupportsAirPlaySlideShow: 1n << 5n,
71
+ SupportsAirPlayScreen: 1n << 7n,
72
+ SupportsAirPlayAudio: 1n << 9n,
73
+ AudioRedundant: 1n << 11n,
74
+ Authentication_4: 1n << 14n,
75
+ MetadataFeatures_0: 1n << 15n,
76
+ MetadataFeatures_1: 1n << 16n,
77
+ MetadataFeatures_2: 1n << 17n,
78
+ AudioFormats_0: 1n << 18n,
79
+ AudioFormats_1: 1n << 19n,
80
+ AudioFormats_2: 1n << 20n,
81
+ AudioFormats_3: 1n << 21n,
82
+ Authentication_1: 1n << 23n,
83
+ Authentication_8: 1n << 26n,
84
+ SupportsLegacyPairing: 1n << 27n,
85
+ HasUnifiedAdvertiserInfo: 1n << 30n,
86
+ IsCarPlay: 1n << 32n,
87
+ SupportsAirPlayVideoPlayQueue: 1n << 33n,
88
+ SupportsAirPlayFromCloud: 1n << 34n,
89
+ SupportsTLS_PSK: 1n << 35n,
90
+ SupportsUnifiedMediaControl: 1n << 38n,
91
+ SupportsBufferedAudio: 1n << 40n,
92
+ SupportsPTP: 1n << 41n,
93
+ SupportsScreenMultiCodec: 1n << 42n,
94
+ SupportsSystemPairing: 1n << 43n,
95
+ IsAPValeriaScreenSender: 1n << 44n,
96
+ SupportsHKPairingAndAccessControl: 1n << 46n,
97
+ SupportsCoreUtilsPairingAndEncryption: 1n << 48n,
98
+ SupportsAirPlayVideoV2: 1n << 49n,
99
+ MetadataFeatures_3: 1n << 50n,
100
+ SupportsUnifiedPairSetupAndMFi: 1n << 51n,
101
+ SupportsSetPeersExtendedMessage: 1n << 52n,
102
+ SupportsAPSync: 1n << 54n,
103
+ SupportsWoL: 1n << 55n,
104
+ SupportsWoL2: 1n << 56n,
105
+ SupportsHangdogRemoteControl: 1n << 58n,
106
+ SupportsAudioStreamConnectionSetup: 1n << 59n,
107
+ SupportsAudioMetadataControl: 1n << 60n,
108
+ SupportsRFC2198Redundancy: 1n << 61n
109
+ };
110
+ const PASSWORD_BIT = 128n;
111
+ const LEGACY_PAIRING_BIT = 512n;
112
+ const PIN_REQUIRED_BIT = 8n;
113
+ const parseFeatures = (features) => {
114
+ const parts = features.split(",").map((part) => part.trim());
115
+ if (parts.length === 1) return BigInt(parts[0]);
116
+ if (parts.length === 2) {
117
+ const low = BigInt(parts[0]);
118
+ return BigInt(parts[1]) << 32n | low;
119
+ }
120
+ throw new Error(`Invalid features format: ${features}`);
121
+ };
122
+ const hasFeatureFlag = (features, flag) => (features & flag) !== 0n;
123
+ const describeFlags = (features) => {
124
+ const result = [];
125
+ for (const [name, flag] of Object.entries(AirPlayFeatureFlags)) if (hasFeatureFlag(features, flag)) result.push(name);
126
+ return result;
127
+ };
128
+ const getProtocolVersion = (txt) => {
129
+ const featuresStr = txt.features ?? txt.ft;
130
+ if (!featuresStr) return 1;
131
+ const features = parseFeatures(featuresStr);
132
+ if (hasFeatureFlag(features, AirPlayFeatureFlags.SupportsUnifiedMediaControl)) return 2;
133
+ if (hasFeatureFlag(features, AirPlayFeatureFlags.SupportsCoreUtilsPairingAndEncryption)) return 2;
134
+ return 1;
135
+ };
136
+ const getPairingRequirement = (txt) => {
137
+ const featuresStr = txt.features ?? txt.ft;
138
+ if (!featuresStr) return "none";
139
+ const features = parseFeatures(featuresStr);
140
+ const sf = txt.sf ? BigInt(txt.sf) : 0n;
141
+ if (hasFeatureFlag(features, AirPlayFeatureFlags.SupportsHKPairingAndAccessControl)) return "homekit";
142
+ if ((sf & PIN_REQUIRED_BIT) !== 0n) return "pin";
143
+ if (hasFeatureFlag(features, AirPlayFeatureFlags.SupportsSystemPairing)) return "transient";
144
+ if ((sf & LEGACY_PAIRING_BIT) !== 0n) return "pin";
145
+ return "none";
146
+ };
147
+ const isPasswordRequired = (txt) => {
148
+ if (txt.pw === "true") return true;
149
+ return ((txt.sf ? BigInt(txt.sf) : 0n) & PASSWORD_BIT) !== 0n;
150
+ };
151
+ const isRemoteControlSupported = (txt) => {
152
+ const featuresStr = txt.features ?? txt.ft;
153
+ if (!featuresStr) return false;
154
+ return hasFeatureFlag(parseFeatures(featuresStr), AirPlayFeatureFlags.SupportsHangdogRemoteControl);
155
+ };
156
+
157
+ //#endregion
158
+ //#region src/storage.ts
159
+ const credentialKey = (deviceId, protocol) => `${deviceId}:${protocol}`;
160
+ const serializeCredentials = (credentials) => ({
161
+ accessoryIdentifier: credentials.accessoryIdentifier,
162
+ accessoryLongTermPublicKey: credentials.accessoryLongTermPublicKey.toString("base64"),
163
+ pairingId: credentials.pairingId.toString("base64"),
164
+ publicKey: credentials.publicKey.toString("base64"),
165
+ secretKey: credentials.secretKey.toString("base64")
166
+ });
167
+ const deserializeCredentials = (stored) => ({
168
+ accessoryIdentifier: stored.accessoryIdentifier,
169
+ accessoryLongTermPublicKey: Buffer.from(stored.accessoryLongTermPublicKey, "base64"),
170
+ pairingId: Buffer.from(stored.pairingId, "base64"),
171
+ publicKey: Buffer.from(stored.publicKey, "base64"),
172
+ secretKey: Buffer.from(stored.secretKey, "base64")
173
+ });
174
+ const createEmptyData = () => ({
175
+ version: 1,
176
+ devices: {},
177
+ credentials: {}
178
+ });
179
+ var Storage = class {
180
+ #data = createEmptyData();
181
+ get data() {
182
+ return this.#data;
183
+ }
184
+ setData(data) {
185
+ this.#data = data;
186
+ }
187
+ getDevice(identifier) {
188
+ return this.#data.devices[identifier];
189
+ }
190
+ setDevice(identifier, device) {
191
+ this.#data.devices[identifier] = device;
192
+ }
193
+ removeDevice(identifier) {
194
+ delete this.#data.devices[identifier];
195
+ for (const key of Object.keys(this.#data.credentials)) if (key.startsWith(`${identifier}:`)) delete this.#data.credentials[key];
196
+ }
197
+ listDevices() {
198
+ return Object.values(this.#data.devices);
199
+ }
200
+ getCredentials(deviceId, protocol) {
201
+ const stored = this.#data.credentials[credentialKey(deviceId, protocol)];
202
+ if (!stored) return;
203
+ return deserializeCredentials(stored);
204
+ }
205
+ setCredentials(deviceId, protocol, credentials) {
206
+ this.#data.credentials[credentialKey(deviceId, protocol)] = serializeCredentials(credentials);
207
+ }
208
+ removeCredentials(deviceId, protocol) {
209
+ delete this.#data.credentials[credentialKey(deviceId, protocol)];
210
+ }
211
+ };
212
+ var JsonStorage = class extends Storage {
213
+ #path;
214
+ constructor(path) {
215
+ super();
216
+ this.#path = path ?? join(process.env.HOME ?? process.env.USERPROFILE ?? ".", ".config", "apple-protocols", "storage.json");
217
+ }
218
+ async load() {
219
+ if (!existsSync(this.#path)) return;
220
+ const raw = readFileSync(this.#path, "utf-8");
221
+ const json = JSON.parse(raw);
222
+ if (json.version === 1) this.setData(json);
223
+ }
224
+ async save() {
225
+ mkdirSync(dirname(this.#path), { recursive: true });
226
+ writeFileSync(this.#path, JSON.stringify(this.data, null, 2), "utf-8");
227
+ }
228
+ };
229
+ var MemoryStorage = class extends Storage {
230
+ async load() {}
231
+ async save() {}
232
+ };
233
+
56
234
  //#endregion
57
235
  //#region src/cli.ts
58
236
  async function prompt(message) {
@@ -77,23 +255,452 @@ const AIRPLAY_SERVICE = "_airplay._tcp.local";
77
255
  const COMPANION_LINK_SERVICE = "_companion-link._tcp.local";
78
256
  const RAOP_SERVICE = "_raop._tcp.local";
79
257
 
258
+ //#endregion
259
+ //#region src/mdns.ts
260
+ const MDNS_ADDRESS = "224.0.0.251";
261
+ const MDNS_PORT = 5353;
262
+ const QUERY_ID = 13823;
263
+ const SERVICES_PER_MSG = 3;
264
+ const QueryType = {
265
+ A: 1,
266
+ PTR: 12,
267
+ TXT: 16,
268
+ AAAA: 28,
269
+ SRV: 33,
270
+ ANY: 255
271
+ };
272
+ const encodeQName = (name) => {
273
+ const parts = [];
274
+ const labels = splitServiceName(name);
275
+ for (const label of labels) {
276
+ const encoded = Buffer.from(label, "utf-8");
277
+ if (encoded.byteLength > 63) parts.push(Buffer.from([63]), encoded.subarray(0, 63));
278
+ else parts.push(Buffer.from([encoded.byteLength]), encoded);
279
+ }
280
+ parts.push(Buffer.from([0]));
281
+ return Buffer.concat(parts);
282
+ };
283
+ const splitServiceName = (name) => {
284
+ const match = name.match(/\._[a-z]+\._(?:tcp|udp)\.local$/);
285
+ if (match) return [name.substring(0, match.index), ...match[0].substring(1).split(".")];
286
+ return name.split(".");
287
+ };
288
+ const encodeDnsHeader = (header) => {
289
+ const buf = Buffer.allocUnsafe(12);
290
+ buf.writeUInt16BE(header.id, 0);
291
+ buf.writeUInt16BE(header.flags, 2);
292
+ buf.writeUInt16BE(header.qdcount, 4);
293
+ buf.writeUInt16BE(header.ancount, 6);
294
+ buf.writeUInt16BE(header.nscount, 8);
295
+ buf.writeUInt16BE(header.arcount, 10);
296
+ return buf;
297
+ };
298
+ const encodeDnsQuestion = (name, qtype, unicastResponse = false) => {
299
+ const qname = encodeQName(name);
300
+ const suffix = Buffer.allocUnsafe(4);
301
+ suffix.writeUInt16BE(qtype, 0);
302
+ suffix.writeUInt16BE(unicastResponse ? 32769 : 1, 2);
303
+ return Buffer.concat([qname, suffix]);
304
+ };
305
+ const createQueryPackets = (services, qtype = QueryType.PTR, unicastResponse = false) => {
306
+ const packets = [];
307
+ for (let i = 0; i < services.length; i += SERVICES_PER_MSG) {
308
+ const chunk = services.slice(i, i + SERVICES_PER_MSG);
309
+ const questions = chunk.map((s) => encodeDnsQuestion(s, qtype, unicastResponse));
310
+ const header = encodeDnsHeader({
311
+ id: QUERY_ID,
312
+ flags: 0,
313
+ qdcount: chunk.length,
314
+ ancount: 0,
315
+ nscount: 0,
316
+ arcount: 0
317
+ });
318
+ packets.push(Buffer.concat([header, ...questions]));
319
+ }
320
+ return packets;
321
+ };
322
+ const decodeQName = (buf, offset) => {
323
+ const labels = [];
324
+ let currentOffset = offset;
325
+ let jumped = false;
326
+ let returnOffset = offset;
327
+ while (currentOffset < buf.byteLength) {
328
+ const length = buf[currentOffset];
329
+ if (length === 0) {
330
+ if (!jumped) returnOffset = currentOffset + 1;
331
+ break;
332
+ }
333
+ if ((length & 192) === 192) {
334
+ const pointer = (length & 63) << 8 | buf[currentOffset + 1];
335
+ if (!jumped) returnOffset = currentOffset + 2;
336
+ currentOffset = pointer;
337
+ jumped = true;
338
+ continue;
339
+ }
340
+ currentOffset++;
341
+ labels.push(buf.toString("utf-8", currentOffset, currentOffset + length));
342
+ currentOffset += length;
343
+ if (!jumped) returnOffset = currentOffset;
344
+ }
345
+ return [labels.join("."), returnOffset];
346
+ };
347
+ const decodeDnsHeader = (buf) => ({
348
+ id: buf.readUInt16BE(0),
349
+ flags: buf.readUInt16BE(2),
350
+ qdcount: buf.readUInt16BE(4),
351
+ ancount: buf.readUInt16BE(6),
352
+ nscount: buf.readUInt16BE(8),
353
+ arcount: buf.readUInt16BE(10)
354
+ });
355
+ const decodeQuestion = (buf, offset) => {
356
+ const [qname, newOffset] = decodeQName(buf, offset);
357
+ return [{
358
+ qname,
359
+ qtype: buf.readUInt16BE(newOffset),
360
+ qclass: buf.readUInt16BE(newOffset + 2)
361
+ }, newOffset + 4];
362
+ };
363
+ const decodeTxtRecord = (buf, offset, length) => {
364
+ const properties = {};
365
+ let pos = offset;
366
+ const end = offset + length;
367
+ while (pos < end) {
368
+ const strLen = buf[pos];
369
+ pos++;
370
+ if (strLen === 0 || pos + strLen > end) break;
371
+ const str = buf.toString("utf-8", pos, pos + strLen);
372
+ pos += strLen;
373
+ const eqIndex = str.indexOf("=");
374
+ if (eqIndex >= 0) properties[str.substring(0, eqIndex)] = str.substring(eqIndex + 1);
375
+ else properties[str] = "";
376
+ }
377
+ return properties;
378
+ };
379
+ const decodeSrvRecord = (buf, offset) => {
380
+ const priority = buf.readUInt16BE(offset);
381
+ const weight = buf.readUInt16BE(offset + 2);
382
+ const port = buf.readUInt16BE(offset + 4);
383
+ const [target] = decodeQName(buf, offset + 6);
384
+ return {
385
+ priority,
386
+ weight,
387
+ port,
388
+ target
389
+ };
390
+ };
391
+ const decodeResource = (buf, offset) => {
392
+ const [qname, nameEnd] = decodeQName(buf, offset);
393
+ const qtype = buf.readUInt16BE(nameEnd);
394
+ const qclass = buf.readUInt16BE(nameEnd + 2);
395
+ const ttl = buf.readUInt32BE(nameEnd + 4);
396
+ const rdLength = buf.readUInt16BE(nameEnd + 8);
397
+ const rdOffset = nameEnd + 10;
398
+ let rdata;
399
+ switch (qtype) {
400
+ case QueryType.A:
401
+ rdata = `${buf[rdOffset]}.${buf[rdOffset + 1]}.${buf[rdOffset + 2]}.${buf[rdOffset + 3]}`;
402
+ break;
403
+ case QueryType.AAAA: {
404
+ const parts = [];
405
+ for (let i = 0; i < 8; i++) parts.push(buf.readUInt16BE(rdOffset + i * 2).toString(16));
406
+ rdata = parts.join(":");
407
+ break;
408
+ }
409
+ case QueryType.PTR: {
410
+ const [name] = decodeQName(buf, rdOffset);
411
+ rdata = name;
412
+ break;
413
+ }
414
+ case QueryType.SRV:
415
+ rdata = decodeSrvRecord(buf, rdOffset);
416
+ break;
417
+ case QueryType.TXT:
418
+ rdata = decodeTxtRecord(buf, rdOffset, rdLength);
419
+ break;
420
+ default: rdata = buf.subarray(rdOffset, rdOffset + rdLength);
421
+ }
422
+ return [{
423
+ qname,
424
+ qtype,
425
+ qclass,
426
+ ttl,
427
+ rdata
428
+ }, rdOffset + rdLength];
429
+ };
430
+ const decodeDnsResponse = (buf) => {
431
+ const header = decodeDnsHeader(buf);
432
+ let offset = 12;
433
+ for (let i = 0; i < header.qdcount; i++) {
434
+ const [, newOffset] = decodeQuestion(buf, offset);
435
+ offset = newOffset;
436
+ }
437
+ const answers = [];
438
+ for (let i = 0; i < header.ancount; i++) {
439
+ const [record, newOffset] = decodeResource(buf, offset);
440
+ answers.push(record);
441
+ offset = newOffset;
442
+ }
443
+ for (let i = 0; i < header.nscount; i++) {
444
+ const [, newOffset] = decodeResource(buf, offset);
445
+ offset = newOffset;
446
+ }
447
+ const resources = [];
448
+ for (let i = 0; i < header.arcount; i++) {
449
+ const [record, newOffset] = decodeResource(buf, offset);
450
+ resources.push(record);
451
+ offset = newOffset;
452
+ }
453
+ return {
454
+ header,
455
+ answers,
456
+ resources
457
+ };
458
+ };
459
+ var ServiceCollector = class {
460
+ #ptrMap = /* @__PURE__ */ new Map();
461
+ #srvMap = /* @__PURE__ */ new Map();
462
+ #txtMap = /* @__PURE__ */ new Map();
463
+ #addressMap = /* @__PURE__ */ new Map();
464
+ addRecords(answers, resources) {
465
+ for (const record of [...answers, ...resources]) switch (record.qtype) {
466
+ case QueryType.PTR: {
467
+ const existing = this.#ptrMap.get(record.qname);
468
+ if (existing) existing.add(record.rdata);
469
+ else this.#ptrMap.set(record.qname, new Set([record.rdata]));
470
+ break;
471
+ }
472
+ case QueryType.SRV:
473
+ this.#srvMap.set(record.qname, record.rdata);
474
+ break;
475
+ case QueryType.TXT:
476
+ this.#txtMap.set(record.qname, record.rdata);
477
+ break;
478
+ case QueryType.A:
479
+ this.#addressMap.set(record.qname, record.rdata);
480
+ break;
481
+ }
482
+ }
483
+ get services() {
484
+ const results = [];
485
+ for (const [serviceType, instanceNames] of this.#ptrMap) for (const instanceQName of instanceNames) {
486
+ const srv = this.#srvMap.get(instanceQName);
487
+ if (!srv || srv.port === 0) continue;
488
+ const address = this.#addressMap.get(srv.target);
489
+ if (!address) continue;
490
+ const txt = this.#txtMap.get(instanceQName) ?? {};
491
+ const typeIndex = instanceQName.indexOf("._");
492
+ const name = typeIndex >= 0 ? instanceQName.substring(0, typeIndex) : instanceQName;
493
+ if (!results.some((s) => s.name === name && s.type === serviceType)) results.push({
494
+ name,
495
+ type: serviceType,
496
+ address,
497
+ port: srv.port,
498
+ properties: txt
499
+ });
500
+ }
501
+ return results;
502
+ }
503
+ };
504
+ const WAKE_PORTS$1 = [
505
+ 7e3,
506
+ 3689,
507
+ 49152,
508
+ 32498
509
+ ];
510
+ const knock = (address) => {
511
+ const promises = WAKE_PORTS$1.map((port) => new Promise((resolve) => {
512
+ const socket = createConnection({
513
+ host: address,
514
+ port,
515
+ timeout: 500
516
+ });
517
+ socket.on("connect", () => {
518
+ socket.destroy();
519
+ resolve();
520
+ });
521
+ socket.on("error", () => {
522
+ socket.destroy();
523
+ resolve();
524
+ });
525
+ socket.on("timeout", () => {
526
+ socket.destroy();
527
+ resolve();
528
+ });
529
+ }));
530
+ return Promise.all(promises).then(() => {});
531
+ };
532
+ const unicast = (hosts, services, timeout = 4) => {
533
+ return new Promise((resolve) => {
534
+ const queries = createQueryPackets(services);
535
+ const collector = new ServiceCollector();
536
+ const sockets = [];
537
+ let resolved = false;
538
+ const finish = () => {
539
+ if (resolved) return;
540
+ resolved = true;
541
+ clearInterval(interval);
542
+ for (const socket of sockets) try {
543
+ socket.close();
544
+ } catch {}
545
+ resolve(collector.services);
546
+ };
547
+ for (const host of hosts) {
548
+ const socket = createSocket("udp4");
549
+ sockets.push(socket);
550
+ socket.on("message", (data) => {
551
+ try {
552
+ const response = decodeDnsResponse(data);
553
+ collector.addRecords(response.answers, response.resources);
554
+ } catch {}
555
+ });
556
+ socket.on("error", () => {});
557
+ }
558
+ let interval;
559
+ Promise.all(hosts.map((h) => knock(h))).then(() => {
560
+ const sendQueries = () => {
561
+ for (let i = 0; i < hosts.length; i++) for (const query of queries) sockets[i]?.send(query, MDNS_PORT, hosts[i]);
562
+ };
563
+ sendQueries();
564
+ interval = setInterval(sendQueries, 1e3);
565
+ setTimeout(finish, timeout * 1e3);
566
+ });
567
+ });
568
+ };
569
+ const multicast = (services, timeout = 4) => {
570
+ return new Promise((resolve) => {
571
+ const collector = new ServiceCollector();
572
+ const queries = createQueryPackets(services);
573
+ const sockets = [];
574
+ let resolved = false;
575
+ let interval;
576
+ const finish = () => {
577
+ if (resolved) return;
578
+ resolved = true;
579
+ clearInterval(interval);
580
+ for (const socket of sockets) try {
581
+ socket.close();
582
+ } catch {}
583
+ resolve(collector.services);
584
+ };
585
+ const onMessage = (data) => {
586
+ try {
587
+ const response = decodeDnsResponse(data);
588
+ collector.addRecords(response.answers, response.resources);
589
+ } catch {}
590
+ };
591
+ const addSocket = (address, port) => {
592
+ return new Promise((resolveSocket) => {
593
+ const socket = createSocket({
594
+ type: "udp4",
595
+ reuseAddr: true
596
+ });
597
+ socket.on("message", onMessage);
598
+ socket.on("error", () => {
599
+ resolveSocket(null);
600
+ });
601
+ socket.bind(port, address ?? "", () => {
602
+ if (address) try {
603
+ socket.setMulticastInterface(address);
604
+ socket.addMembership(MDNS_ADDRESS, address);
605
+ } catch {}
606
+ else try {
607
+ socket.addMembership(MDNS_ADDRESS);
608
+ } catch {}
609
+ sockets.push(socket);
610
+ resolveSocket(socket);
611
+ });
612
+ });
613
+ };
614
+ const getPrivateAddresses = () => {
615
+ try {
616
+ const { networkInterfaces } = __require("node:os");
617
+ const interfaces = networkInterfaces();
618
+ const addresses = [];
619
+ for (const nets of Object.values(interfaces)) for (const net of nets) if (net.family === "IPv4" && net.internal === false) addresses.push(net.address);
620
+ return addresses;
621
+ } catch {
622
+ return [];
623
+ }
624
+ };
625
+ const setup = async () => {
626
+ await addSocket(null, MDNS_PORT);
627
+ for (const address of getPrivateAddresses()) await addSocket(address, 0);
628
+ if (sockets.length === 0) {
629
+ resolve([]);
630
+ return;
631
+ }
632
+ const sendQueries = () => {
633
+ for (const socket of sockets) for (const query of queries) try {
634
+ socket.send(query, MDNS_PORT, MDNS_ADDRESS);
635
+ } catch {}
636
+ };
637
+ sendQueries();
638
+ interval = setInterval(sendQueries, 1e3);
639
+ setTimeout(finish, timeout * 1e3);
640
+ };
641
+ setup();
642
+ });
643
+ };
644
+
80
645
  //#endregion
81
646
  //#region src/discovery.ts
647
+ const CACHE_TTL = 3e4;
648
+ const WAKE_PORTS = [
649
+ 7e3,
650
+ 3689,
651
+ 49152,
652
+ 32498
653
+ ];
654
+ const toDiscoveryResult = (service) => {
655
+ const txt = service.properties;
656
+ const featuresStr = txt.features ?? txt.ft;
657
+ const model = txt.model ?? txt.am ?? "";
658
+ const protocol = service.type.includes("._tcp") ? "tcp" : "udp";
659
+ const hostname = service.name.replace(/\s+/g, "-");
660
+ return {
661
+ id: `${hostname}.local`,
662
+ fqdn: `${hostname}.local`,
663
+ address: service.address,
664
+ modelName: model,
665
+ familyName: null,
666
+ txt,
667
+ features: featuresStr ? tryParseFeatures(featuresStr) : void 0,
668
+ service: {
669
+ port: service.port,
670
+ protocol,
671
+ type: service.type
672
+ },
673
+ packet: null
674
+ };
675
+ };
676
+ const tryParseFeatures = (features) => {
677
+ try {
678
+ return parseFeatures(features);
679
+ } catch {
680
+ return;
681
+ }
682
+ };
82
683
  var Discovery = class Discovery {
684
+ static #cache = /* @__PURE__ */ new Map();
83
685
  #service;
84
686
  constructor(service) {
85
687
  this.#service = service;
86
688
  }
87
- async find() {
88
- return (await mdns.discover({ name: this.#service })).map((result) => ({
89
- id: generateId(result) ?? result.fqdn,
90
- txt: getTxt(result),
91
- ...result
92
- }));
689
+ async find(useCache = true) {
690
+ if (useCache) {
691
+ const cached = Discovery.#cache.get(this.#service);
692
+ if (cached && cached.expiresAt > Date.now()) return cached.results;
693
+ }
694
+ const mapped = (await multicast([this.#service], 4)).map(toDiscoveryResult);
695
+ Discovery.#cache.set(this.#service, {
696
+ results: mapped,
697
+ expiresAt: Date.now() + CACHE_TTL
698
+ });
699
+ return mapped;
93
700
  }
94
701
  async findUntil(id, tries = 10, timeout = 1e3) {
95
702
  while (tries > 0) {
96
- const devices = await this.find();
703
+ const devices = await this.find(false);
97
704
  const device = devices.find((device) => device.id === id);
98
705
  if (device) return device;
99
706
  console.log();
@@ -102,7 +709,57 @@ var Discovery = class Discovery {
102
709
  tries--;
103
710
  await waitFor(timeout);
104
711
  }
105
- throw new Error("Device not found after serveral tries, aborting.");
712
+ throw new Error("Device not found after several tries, aborting.");
713
+ }
714
+ static clearCache() {
715
+ Discovery.#cache.clear();
716
+ }
717
+ static async wake(address) {
718
+ const promises = WAKE_PORTS.map((port) => new Promise((resolve) => {
719
+ const socket = createConnection({
720
+ host: address,
721
+ port,
722
+ timeout: 500
723
+ });
724
+ socket.on("connect", () => {
725
+ socket.destroy();
726
+ resolve();
727
+ });
728
+ socket.on("error", () => {
729
+ socket.destroy();
730
+ resolve();
731
+ });
732
+ socket.on("timeout", () => {
733
+ socket.destroy();
734
+ resolve();
735
+ });
736
+ }));
737
+ await Promise.all(promises);
738
+ }
739
+ static async discoverAll() {
740
+ const allServices = await multicast([
741
+ AIRPLAY_SERVICE,
742
+ COMPANION_LINK_SERVICE,
743
+ RAOP_SERVICE
744
+ ], 4);
745
+ const devices = /* @__PURE__ */ new Map();
746
+ for (const service of allServices) {
747
+ const result = toDiscoveryResult(service);
748
+ const existing = devices.get(result.id);
749
+ if (existing) {
750
+ if (service.type === AIRPLAY_SERVICE) existing.airplay = result;
751
+ else if (service.type === COMPANION_LINK_SERVICE) existing.companionLink = result;
752
+ else if (service.type === RAOP_SERVICE) existing.raop = result;
753
+ } else devices.set(result.id, {
754
+ id: result.id,
755
+ name: result.fqdn,
756
+ address: result.address,
757
+ airplay: service.type === AIRPLAY_SERVICE ? result : void 0,
758
+ companionLink: service.type === COMPANION_LINK_SERVICE ? result : void 0,
759
+ raop: service.type === RAOP_SERVICE ? result : void 0
760
+ });
761
+ }
762
+ return [...devices.values()];
106
763
  }
107
764
  static airplay() {
108
765
  return new Discovery(AIRPLAY_SERVICE);
@@ -114,29 +771,6 @@ var Discovery = class Discovery {
114
771
  return new Discovery(RAOP_SERVICE);
115
772
  }
116
773
  };
117
- function generateId(result) {
118
- if (!result?.packet) return null;
119
- const { answers = [], additionals = [] } = result.packet;
120
- const allRecords = [...answers, ...additionals];
121
- const srvRecord = allRecords.find((record) => record.type === "SRV");
122
- if (srvRecord?.rdata?.target) return srvRecord.rdata.target;
123
- if (result.address) {
124
- const addressRecord = allRecords.find((record) => (record.type === "A" || record.type === "AAAA") && record.rdata === result.address);
125
- if (addressRecord?.name) return addressRecord.name;
126
- }
127
- const aRecord = allRecords.find((record) => record.type === "A");
128
- if (aRecord?.name) return aRecord.name;
129
- if (result.modelName) return `${result.modelName.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9-]/g, "")}.local`;
130
- return null;
131
- }
132
- function getTxt(result) {
133
- if (!result.packet) return {};
134
- const { answers = [], additionals = [] } = result.packet;
135
- const records = [...answers, ...additionals];
136
- const txt = {};
137
- for (const record of records) if (record.type === "TXT" && record.rdata) Object.assign(txt, record.rdata);
138
- return txt;
139
- }
140
774
 
141
775
  //#endregion
142
776
  //#region src/symbols.ts
@@ -841,5 +1475,4 @@ function splitUInt53(number) {
841
1475
  }
842
1476
 
843
1477
  //#endregion
844
- export { AIRPLAY_SERVICE, AIRPLAY_TRANSIENT_PIN, AccessoryPair, AccessoryVerify, COMPANION_LINK_SERVICE, Connection, Context, Discovery, ENCRYPTION, EncryptionAwareConnection, EncryptionState, HTTP_TIMEOUT, RAOP_SERVICE, TimingServer, generateActiveRemoteId, generateDacpId, generateSessionId, getLocalIP, getMacAddress, prompt, randomInt32, randomInt64, reporter, uint16ToBE, uint53ToLE, v4 as uuid, waitFor };
845
- //# sourceMappingURL=index.mjs.map
1478
+ export { AIRPLAY_SERVICE, AIRPLAY_TRANSIENT_PIN, AccessoryPair, AccessoryVerify, AirPlayFeatureFlags, COMPANION_LINK_SERVICE, Connection, Context, Discovery, ENCRYPTION, EncryptionAwareConnection, EncryptionState, HTTP_TIMEOUT, JsonStorage, MemoryStorage, RAOP_SERVICE, Storage, TimingServer, describeFlags, generateActiveRemoteId, generateDacpId, generateSessionId, getLocalIP, getMacAddress, getPairingRequirement, getProtocolVersion, hasFeatureFlag, isPasswordRequired, isRemoteControlSupported, multicast as mdnsMulticast, unicast as mdnsUnicast, parseFeatures, prompt, randomInt32, randomInt64, reporter, uint16ToBE, uint53ToLE, v4 as uuid, waitFor };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@basmilius/apple-common",
3
3
  "description": "Common features shared across various apple protocol packages.",
4
- "version": "0.8.2",
4
+ "version": "0.9.3",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": {
@@ -9,6 +9,11 @@
9
9
  "email": "bas@mili.us",
10
10
  "url": "https://bas.dev"
11
11
  },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/basmilius/apple-protocols",
15
+ "directory": "packages/common"
16
+ },
12
17
  "keywords": [
13
18
  "apple",
14
19
  "airplay",
@@ -40,10 +45,9 @@
40
45
  }
41
46
  },
42
47
  "dependencies": {
43
- "@basmilius/apple-encoding": "0.8.2",
44
- "@basmilius/apple-encryption": "0.8.2",
45
- "fast-srp-hap": "^2.0.4",
46
- "node-dns-sd": "^1.0.1"
48
+ "@basmilius/apple-encoding": "0.9.3",
49
+ "@basmilius/apple-encryption": "0.9.3",
50
+ "fast-srp-hap": "^2.0.4"
47
51
  },
48
52
  "devDependencies": {
49
53
  "@types/bun": "^1.3.9",
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.mts","names":["UUIDTypes","TBuf","Uint8Array","Version1Options","node","clockseq","random","rng","msecs","nsecs","_v6","Version4Options","Version6Options","Version7Options","seq","Version4Options","v4","options","buf","offset","TBuf","Uint8Array","default","DiscoveryResult","Discovery","Promise","private","constructor","service","find","findUntil","id","tries","timeout","airplay","companionLink","raop","prompt","Promise","message","waitFor","ms","DebugGroup","Logger","private","id","label","constructor","debug","data","error","info","net","raw","warn","Reporter","all","disable","group","enable","isEnabled","reporter","Logger","Context","private","deviceId","logger","constructor","ENCRYPTION","ConnectionState","EventMap","Record","DnsRecordClass","DnsRecordType","DnsRecordBase","name","type","class","flash","ttl","DnsRecordA","rdata","DnsRecordAAAA","DnsRecordPTR","DnsRecordTXT","Buffer","rdata_buffer","DnsRecordSRV","priority","weight","port","target","DnsRecordNSEC","DnsRecord","DnsPacketHeader","id","qr","op","aa","tc","rd","ra","z","ad","cd","rc","questions","answers","authorities","additionals","DnsPacket","address","header","Result","fqdn","modelName","familyName","service","protocol","packet","key","DiscoveryResult","txt","EventEmitter","Context","ENCRYPTION","ConnectionState","EventMap","ConnectionEventMap","Buffer","Error","close","hadError","connect","data","end","error","err","timeout","Connection","TEventMap","Promise","Uint8Array","private","address","context","port","isConnected","state","constructor","destroy","disconnect","debug","enabled","retry","attempts","interval","write","EncryptionAwareConnection","EncryptionState","isEncrypted","enableEncryption","readKey","writeKey","readCount","writeCount","AIRPLAY_TRANSIENT_PIN","HTTP_TIMEOUT","SOCKET_TIMEOUT","AIRPLAY_SERVICE","COMPANION_LINK_SERVICE","RAOP_SERVICE","Context","BasePairing","Buffer","Map","private","context","constructor","tlv","buffer","AccessoryPair","RequestHandler","Promise","AccessoryCredentials","AccessoryKeys","PairM1","PairM2","PairM3","PairM4","PairM5","requestHandler","start","pin","askPin","transient","m1","additionalTlv","m2","m3","m4","m5","m6","AccessoryVerify","credentials","step","data","publicKey","salt","proof","serverProof","sharedSecret","authTag","sessionKey","accessoryIdentifier","accessoryLongTermPublicKey","pairingId","secretKey","accessoryToControllerKey","controllerToAccessoryKey","TimingServer","Promise","private","port","constructor","close","listen","generateActiveRemoteId","generateDacpId","generateSessionId","getLocalIP","getMacAddress","randomInt32","randomInt64","uint16ToBE","Buffer","value","uint53ToLE","AudioSource","Buffer","Promise","duration","readFrames","count","reset","start","stop"],"sources":["../../../node_modules/.bun/uuid@13.0.0/node_modules/uuid/dist/types.d.ts","../../../node_modules/.bun/uuid@13.0.0/node_modules/uuid/dist/v4.d.ts","../src/discovery.d.ts","../src/cli.d.ts","../src/reporter.d.ts","../src/context.d.ts","../src/symbols.d.ts","../src/types.d.ts","../src/connection.d.ts","../src/const.d.ts","../src/pairing.d.ts","../src/timing.d.ts","../src/utils.d.ts","../src/audioSource.d.ts"],"x_google_ignoreList":[0,1],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","names":["native","#service","#address","#context","#port","#state","#socket","#retryEnabled","#retryAttempt","#attemptConnect","#retryTimeout","#cleanup","#debug","#retryAttempts","#retryInterval","#connectPromise","#onClose","#onConnect","#onData","#onEnd","#onError","#onTimeout","#scheduleRetry","#id","#label","#enabled","#deviceId","#logger","#context","#name","#pairingId","#requestHandler","uuid","#publicKey","#secretKey","#srp","#ephemeralKeyPair","#m1","#m2","#m3","#m4","#port","#logger","#socket","#onConnect","#onError","#onMessage","#onListening"],"sources":["../../../node_modules/.bun/uuid@13.0.0/node_modules/uuid/dist-node/stringify.js","../../../node_modules/.bun/uuid@13.0.0/node_modules/uuid/dist-node/rng.js","../../../node_modules/.bun/uuid@13.0.0/node_modules/uuid/dist-node/native.js","../../../node_modules/.bun/uuid@13.0.0/node_modules/uuid/dist-node/v4.js","../src/cli.ts","../src/const.ts","../src/discovery.ts","../src/symbols.ts","../src/connection.ts","../src/reporter.ts","../src/context.ts","../src/pairing.ts","../src/timing.ts","../src/utils.ts"],"sourcesContent":["import validate from './validate.js';\nconst byteToHex = [];\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).slice(1));\n}\nexport function unsafeStringify(arr, offset = 0) {\n return (byteToHex[arr[offset + 0]] +\n byteToHex[arr[offset + 1]] +\n byteToHex[arr[offset + 2]] +\n byteToHex[arr[offset + 3]] +\n '-' +\n byteToHex[arr[offset + 4]] +\n byteToHex[arr[offset + 5]] +\n '-' +\n byteToHex[arr[offset + 6]] +\n byteToHex[arr[offset + 7]] +\n '-' +\n byteToHex[arr[offset + 8]] +\n byteToHex[arr[offset + 9]] +\n '-' +\n byteToHex[arr[offset + 10]] +\n byteToHex[arr[offset + 11]] +\n byteToHex[arr[offset + 12]] +\n byteToHex[arr[offset + 13]] +\n byteToHex[arr[offset + 14]] +\n byteToHex[arr[offset + 15]]).toLowerCase();\n}\nfunction stringify(arr, offset = 0) {\n const uuid = unsafeStringify(arr, offset);\n if (!validate(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n return uuid;\n}\nexport default stringify;\n","import { randomFillSync } from 'node:crypto';\nconst rnds8Pool = new Uint8Array(256);\nlet poolPtr = rnds8Pool.length;\nexport default function rng() {\n if (poolPtr > rnds8Pool.length - 16) {\n randomFillSync(rnds8Pool);\n poolPtr = 0;\n }\n return rnds8Pool.slice(poolPtr, (poolPtr += 16));\n}\n","import { randomUUID } from 'node:crypto';\nexport default { randomUUID };\n","import native from './native.js';\nimport rng from './rng.js';\nimport { unsafeStringify } from './stringify.js';\nfunction _v4(options, buf, offset) {\n options = options || {};\n const rnds = options.random ?? options.rng?.() ?? rng();\n if (rnds.length < 16) {\n throw new Error('Random bytes length must be >= 16');\n }\n rnds[6] = (rnds[6] & 0x0f) | 0x40;\n rnds[8] = (rnds[8] & 0x3f) | 0x80;\n if (buf) {\n offset = offset || 0;\n if (offset < 0 || offset + 16 > buf.length) {\n throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);\n }\n for (let i = 0; i < 16; ++i) {\n buf[offset + i] = rnds[i];\n }\n return buf;\n }\n return unsafeStringify(rnds);\n}\nfunction v4(options, buf, offset) {\n if (native.randomUUID && !buf && !options) {\n return native.randomUUID();\n }\n return _v4(options, buf, offset);\n}\nexport default v4;\n","import { createInterface } from 'node:readline';\n\nexport async function prompt(message: string): Promise<string> {\n const cli = createInterface({\n input: process.stdin,\n output: process.stdout\n });\n\n const answer = await new Promise<string>(resolve => cli.question(`${message}: `, resolve));\n\n cli.close();\n\n return answer;\n}\n\nexport async function waitFor(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n","export const AIRPLAY_TRANSIENT_PIN = '3939';\n\nexport const HTTP_TIMEOUT = 6000;\nexport const SOCKET_TIMEOUT = 10000;\n\nexport const AIRPLAY_SERVICE = '_airplay._tcp.local';\nexport const COMPANION_LINK_SERVICE = '_companion-link._tcp.local';\nexport const RAOP_SERVICE = '_raop._tcp.local';\n","import mdns, { DiscoveryResult, DnsRecord, Result } from 'node-dns-sd';\nimport { waitFor } from './cli';\nimport { AIRPLAY_SERVICE, COMPANION_LINK_SERVICE, RAOP_SERVICE } from './const';\n\nexport class Discovery {\n readonly #service: string;\n\n constructor(service: string) {\n this.#service = service;\n }\n\n async find(): Promise<DiscoveryResult[]> {\n const results = await mdns.discover({\n name: this.#service\n });\n\n return results.map(result => ({\n id: generateId(result) ?? result.fqdn,\n txt: getTxt(result),\n ...result\n }));\n }\n\n async findUntil(id: string, tries: number = 10, timeout: number = 1000): Promise<DiscoveryResult> {\n while (tries > 0) {\n const devices = await this.find();\n const device = devices.find(device => device.id === id);\n\n if (device) {\n return device;\n }\n\n console.log();\n console.log(`Device not found, retrying in ${timeout}ms...`);\n console.log(devices.map(d => ` ● ${d.id} (${d.fqdn})`).join('\\n'));\n\n tries--;\n\n await waitFor(timeout);\n }\n\n throw new Error('Device not found after serveral tries, aborting.');\n }\n\n static airplay(): Discovery {\n return new Discovery(AIRPLAY_SERVICE);\n }\n\n static companionLink(): Discovery {\n return new Discovery(COMPANION_LINK_SERVICE);\n }\n\n static raop(): Discovery {\n return new Discovery(RAOP_SERVICE);\n }\n}\n\nfunction generateId(result: Result): string | null {\n if (!result?.packet) {\n return null;\n }\n\n const {answers = [], additionals = []} = result.packet;\n const allRecords = [...answers, ...additionals];\n\n // Strategy 1: Find SRV record and get the target (most reliable)\n const srvRecord = allRecords.find((record) => record.type === 'SRV');\n if (srvRecord?.rdata?.target) {\n return srvRecord.rdata.target;\n }\n\n // Strategy 2: Find A or AAAA record name that matches the IP address\n // (the record name is the hostname)\n if (result.address) {\n const addressRecord = allRecords.find(record => (record.type === 'A' || record.type === 'AAAA') && record.rdata === result.address);\n\n if (addressRecord?.name) {\n return addressRecord.name;\n }\n }\n\n // Strategy 3: Find any A record and use its name as hostname\n const aRecord = allRecords.find((record) => record.type === 'A');\n if (aRecord?.name) {\n return aRecord.name;\n }\n\n // Strategy 4: Fallback - derive from fqdn/modelName (less reliable)\n if (result.modelName) {\n const hostname = result.modelName\n .replace(/\\s+/g, '-')\n .replace(/[^a-zA-Z0-9-]/g, '');\n\n return `${hostname}.local`;\n }\n\n return null;\n}\n\nfunction getTxt(result: Result): Record<string, string> {\n if (!result.packet) {\n return {};\n }\n\n const {answers = [], additionals = []} = result.packet;\n const records: DnsRecord[] = [\n ...answers,\n ...additionals\n ];\n\n const txt: Record<string, string> = {};\n\n for (const record of records) {\n if (record.type === 'TXT' && record.rdata) {\n Object.assign(txt, record.rdata);\n }\n }\n\n return txt;\n}\n","export const ENCRYPTION: unique symbol = Symbol();\n","import { EventEmitter } from 'node:events';\nimport { Socket } from 'node:net';\nimport { SOCKET_TIMEOUT } from './const';\nimport type { Context } from './context';\nimport { ENCRYPTION } from './symbols';\nimport type { ConnectionState, EventMap } from './types';\n\nconst NOOP_PROMISE_HANDLER = {\n resolve: () => {\n },\n reject: (_: Error) => {\n }\n} as const;\n\ntype ConnectionEventMap = {\n close: [hadError: boolean];\n connect: [];\n data: [data: Buffer];\n end: [];\n error: [err: Error];\n timeout: [];\n};\n\nexport class Connection<TEventMap extends EventMap> extends EventEmitter<ConnectionEventMap | TEventMap> {\n get address(): string {\n return this.#address;\n }\n\n get context(): Context {\n return this.#context;\n }\n\n get port(): number {\n return this.#port;\n }\n\n get isConnected(): boolean {\n return this.#state === 'connected';\n }\n\n get state(): ConnectionState {\n if (this.#state === 'closing' || this.#state === 'failed') {\n return this.#state;\n }\n\n if (!this.#socket) {\n return 'disconnected';\n }\n\n switch (this.#socket.readyState) {\n case 'opening':\n return 'connecting';\n\n case 'open':\n return 'connected';\n\n default:\n return this.#state;\n }\n }\n\n readonly #address: string;\n readonly #port: number;\n readonly #context: Context;\n #debug: boolean = false;\n #retryAttempt: number = 0;\n #retryAttempts: number = 3;\n #retryEnabled: boolean = true;\n #retryInterval: number = 3000;\n #retryTimeout?: NodeJS.Timeout;\n #socket?: Socket;\n #state: ConnectionState;\n\n #connectPromise?: {\n resolve: () => void;\n reject: (err: Error) => void;\n };\n\n constructor(context: Context, address: string, port: number) {\n super();\n\n this.#address = address;\n this.#port = port;\n this.#context = context;\n\n this.#state = 'disconnected';\n }\n\n async connect(): Promise<void> {\n if (this.#state === 'connected') {\n return;\n }\n\n if (this.#state === 'connecting') {\n throw new Error('A connection is already being established.');\n }\n\n this.#retryEnabled = true;\n this.#retryAttempt = 0;\n\n return this.#attemptConnect();\n }\n\n destroy(): void {\n this.#socket?.destroy();\n }\n\n async disconnect(): Promise<void> {\n if (this.#retryTimeout) {\n clearTimeout(this.#retryTimeout);\n this.#retryTimeout = undefined;\n }\n\n this.#retryEnabled = false;\n\n if (!this.#socket || this.#state === 'disconnected') {\n return;\n }\n\n return new Promise(resolve => {\n this.#state = 'closing';\n this.#socket.once('close', () => {\n this.#cleanup();\n resolve();\n });\n this.#socket.end();\n });\n }\n\n debug(enabled: boolean): this {\n this.#debug = enabled;\n\n return this;\n }\n\n retry(attempts: number, interval: number = 3000): this {\n this.#retryAttempts = attempts;\n this.#retryInterval = interval;\n\n return this;\n }\n\n write(data: Buffer | Uint8Array): void {\n if (!this.#socket || this.state !== 'connected' || !this.#socket.writable) {\n this.emit('error', new Error('Cannot write to a disconnected connection.'));\n return;\n }\n\n this.#socket.write(data, err => {\n if (!err) {\n return;\n }\n\n this.#context.logger.error('Failed to write data to socket.');\n this.emit('error', err);\n });\n }\n\n async #attemptConnect(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.#state = 'connecting';\n this.#connectPromise = {resolve, reject};\n\n this.#socket?.removeAllListeners();\n this.#socket = undefined;\n\n this.#socket = new Socket();\n this.#socket.setNoDelay(true);\n this.#socket.setTimeout(SOCKET_TIMEOUT);\n\n this.#socket.on('close', this.#onClose.bind(this));\n this.#socket.on('connect', this.#onConnect.bind(this));\n this.#socket.on('data', this.#onData.bind(this));\n this.#socket.on('end', this.#onEnd.bind(this));\n this.#socket.on('error', this.#onError.bind(this));\n this.#socket.on('timeout', this.#onTimeout.bind(this));\n\n this.#context.logger.net(`Connecting to ${this.#address}:${this.#port}...`);\n\n this.#socket.connect({\n host: this.#address,\n port: this.#port,\n keepAlive: true\n });\n });\n }\n\n #cleanup(): void {\n if (this.#retryTimeout) {\n clearTimeout(this.#retryTimeout);\n this.#retryTimeout = undefined;\n }\n\n if (this.#socket) {\n this.#socket.removeAllListeners();\n this.#socket.destroy();\n this.#socket = undefined;\n }\n\n this.#state = 'disconnected';\n this.#connectPromise = undefined;\n }\n\n #scheduleRetry(err: Error): void {\n if (!this.#retryEnabled || this.#retryAttempt >= this.#retryAttempts) {\n this.#state = 'failed';\n this.#connectPromise?.reject(err);\n this.#connectPromise = undefined;\n return;\n }\n\n if (this.#retryTimeout) {\n clearTimeout(this.#retryTimeout);\n this.#retryTimeout = undefined;\n }\n\n this.#retryAttempt++;\n this.#context.logger.net(`Retry attempt ${this.#retryAttempt} / ${this.#retryAttempts} in ${this.#retryInterval}ms...`);\n\n const {resolve, reject} = this.#connectPromise ?? NOOP_PROMISE_HANDLER;\n this.#cleanup();\n\n this.#retryTimeout = setTimeout(async () => {\n this.#retryTimeout = undefined;\n\n try {\n // Re-assign the stored handlers\n this.#connectPromise = {resolve, reject};\n await this.#attemptConnect();\n resolve();\n } catch (retryErr) {\n // Error handling is done in #onError/#onTimeout\n }\n }, this.#retryInterval);\n }\n\n #onClose(hadError: boolean): void {\n const wasConnected = this.#state === 'connected';\n\n if (this.#state !== 'closing') {\n this.#state = 'disconnected';\n this.#context.logger.net(`Connection closed (${hadError ? 'with error' : 'normally'}).`);\n }\n\n this.emit('close', hadError);\n\n if (wasConnected && this.#retryEnabled && hadError) {\n this.#scheduleRetry(new Error('Connection closed unexpectedly.'));\n }\n }\n\n #onConnect(): void {\n this.#state = 'connected';\n this.#retryAttempt = 0;\n\n this.#socket.setKeepAlive(true, 10000);\n this.#socket.setTimeout(0);\n\n this.emit('connect');\n this.#connectPromise?.resolve();\n this.#connectPromise = undefined;\n }\n\n #onData(data: Buffer): void {\n if (this.#debug) {\n const cutoff = Math.min(data.byteLength, 64);\n this.#context.logger.debug(`Received ${data.byteLength} bytes of data.`);\n this.#context.logger.debug(`hex=${data.subarray(0, cutoff).toString('hex')}`);\n this.#context.logger.debug(`ascii=${data.toString('ascii').replace(/[^\\x20-\\x7E]/g, '.').substring(0, cutoff)}`);\n }\n\n this.emit('data', data);\n }\n\n #onEnd(): void {\n this.emit('end');\n }\n\n #onError(err: Error): void {\n this.#context.logger.error(`Connection error: ${err.message}`);\n\n if (this.listenerCount('error') > 0) {\n this.emit('error', err);\n } else {\n this.#context.logger.warn('No error handler registered. This is likely a bug.', this.constructor.name, '#onError');\n }\n\n if (this.#state === 'connecting') {\n this.#scheduleRetry(err);\n } else {\n this.#state = 'failed';\n }\n }\n\n #onTimeout(): void {\n this.#context.logger.error('Connection timed out.');\n\n const err = new Error('Connection timed out.');\n\n this.emit('timeout');\n\n if (this.#state === 'connecting') {\n this.#scheduleRetry(err);\n } else {\n this.#state = 'failed';\n this.#socket?.destroy();\n }\n }\n}\n\nexport class EncryptionAwareConnection<TEventMap extends EventMap> extends Connection<TEventMap> {\n get isEncrypted(): boolean {\n return !!this[ENCRYPTION];\n }\n\n [ENCRYPTION]?: EncryptionState;\n\n enableEncryption(readKey: Buffer, writeKey: Buffer): void {\n this[ENCRYPTION] = new EncryptionState(readKey, writeKey);\n }\n}\n\nexport class EncryptionState {\n readKey: Buffer;\n readCount: number;\n writeKey: Buffer;\n writeCount: number;\n\n constructor(readKey: Buffer, writeKey: Buffer) {\n this.readCount = 0;\n this.readKey = readKey;\n this.writeCount = 0;\n this.writeKey = writeKey;\n }\n}\n","type DebugGroup =\n | 'debug'\n | 'error'\n | 'info'\n | 'net'\n | 'raw'\n | 'warn';\n\nexport class Logger {\n get id(): string {\n return this.#id;\n }\n\n get label(): string {\n return this.#label;\n }\n\n readonly #id: string;\n readonly #label: string;\n\n constructor(id: string) {\n this.#id = id;\n this.#label = `\\u001b[36m[${id}]\\u001b[39m`;\n }\n\n debug(...data: any[]): void {\n debug(this.#label, ...data);\n }\n\n error(...data: any[]): void {\n error(this.#label, ...data);\n }\n\n info(...data: any[]): void {\n info(this.#label, ...data);\n }\n\n net(...data: any[]): void {\n net(this.#label, ...data);\n }\n\n raw(...data: any[]): void {\n raw(this.#label, ...data);\n }\n\n warn(...data: any[]): void {\n warn(this.#label, ...data);\n }\n}\n\nexport class Reporter {\n #enabled: DebugGroup[] = [];\n\n all(): void {\n this.#enabled = ['debug', 'error', 'info', 'net', 'raw', 'warn'] as DebugGroup[];\n }\n\n disable(group: DebugGroup): void {\n if (this.#enabled.includes(group)) {\n this.#enabled.splice(this.#enabled.indexOf(group), 1);\n }\n }\n\n enable(group: DebugGroup): void {\n if (!this.#enabled.includes(group)) {\n this.#enabled.push(group);\n }\n }\n\n isEnabled(group: DebugGroup): boolean {\n return this.#enabled.includes(group);\n }\n}\n\nfunction debug(...data: any[]): void {\n reporter.isEnabled('debug') && console.debug(`\\u001b[36m[debug]\\u001b[39m`, ...data);\n}\n\nfunction error(...data: any[]): void {\n reporter.isEnabled('error') && console.error(`\\u001b[31m[error]\\u001b[39m`, ...data);\n}\n\nfunction info(...data: any[]): void {\n reporter.isEnabled('info') && console.info(`\\u001b[32m[info]\\u001b[39m`, ...data);\n}\n\nfunction net(...data: any[]): void {\n reporter.isEnabled('net') && console.info(`\\u001b[33m[net]\\u001b[39m`, ...data);\n}\n\nfunction raw(...data: any[]): void {\n reporter.isEnabled('raw') && console.log(`\\u001b[34m[raw]\\u001b[39m`, ...data);\n}\n\nfunction warn(...data: any[]): void {\n reporter.isEnabled('warn') && console.warn(`\\u001b[33m[warn]\\u001b[39m`, ...data);\n}\n\nexport const reporter: Reporter = new Reporter();\n","import { Logger } from './reporter';\n\nexport class Context {\n get deviceId(): string {\n return this.#deviceId;\n }\n\n get logger(): Logger {\n return this.#logger;\n }\n\n readonly #deviceId: string;\n readonly #logger: Logger;\n\n constructor(deviceId: string) {\n this.#deviceId = deviceId;\n this.#logger = new Logger(deviceId);\n }\n}\n","import { OPack, TLV8 } from '@basmilius/apple-encoding';\nimport { Chacha20, Curve25519, Ed25519, hkdf, type KeyPair } from '@basmilius/apple-encryption';\nimport { SRP, SrpClient } from 'fast-srp-hap';\nimport { v4 as uuid } from 'uuid';\nimport { AIRPLAY_TRANSIENT_PIN } from './const';\nimport type { Context } from './context';\n\nabstract class BasePairing {\n get context(): Context {\n return this.#context;\n }\n\n readonly #context: Context;\n\n constructor(context: Context) {\n this.#context = context;\n }\n\n tlv(buffer: Buffer): Map<number, Buffer> {\n const data = TLV8.decode(buffer);\n\n if (data.has(TLV8.Value.Error)) {\n TLV8.bail(data);\n }\n\n this.#context.logger.raw('Decoded TLV', data);\n\n return data;\n }\n}\n\nexport class AccessoryPair extends BasePairing {\n readonly #name: string;\n readonly #pairingId: Buffer;\n readonly #requestHandler: RequestHandler;\n #publicKey: Buffer;\n #secretKey: Buffer;\n #srp: SrpClient;\n\n constructor(context: Context, requestHandler: RequestHandler) {\n super(context);\n\n this.#name = 'basmilius/apple-protocols';\n this.#pairingId = Buffer.from(uuid().toUpperCase());\n this.#requestHandler = requestHandler;\n }\n\n async start(): Promise<void> {\n const keyPair = Ed25519.generateKeyPair();\n this.#publicKey = Buffer.from(keyPair.publicKey);\n this.#secretKey = Buffer.from(keyPair.secretKey);\n }\n\n async pin(askPin: () => Promise<string>): Promise<AccessoryCredentials> {\n const m1 = await this.m1();\n const m2 = await this.m2(m1, await askPin());\n const m3 = await this.m3(m2);\n const m4 = await this.m4(m3);\n const m5 = await this.m5(m4);\n const m6 = await this.m6(m4, m5);\n\n if (!m6) {\n throw new Error('Pairing failed, could not get accessory keys.');\n }\n\n return m6;\n }\n\n async transient(): Promise<AccessoryKeys> {\n const m1 = await this.m1([[TLV8.Value.Flags, TLV8.Flags.TransientPairing]]);\n const m2 = await this.m2(m1);\n const m3 = await this.m3(m2);\n const m4 = await this.m4(m3);\n\n const accessoryToControllerKey = hkdf({\n hash: 'sha512',\n key: m4.sharedSecret,\n length: 32,\n salt: Buffer.from('Control-Salt'),\n info: Buffer.from('Control-Read-Encryption-Key')\n });\n\n const controllerToAccessoryKey = hkdf({\n hash: 'sha512',\n key: m4.sharedSecret,\n length: 32,\n salt: Buffer.from('Control-Salt'),\n info: Buffer.from('Control-Write-Encryption-Key')\n });\n\n return {\n pairingId: this.#pairingId,\n sharedSecret: m4.sharedSecret,\n accessoryToControllerKey,\n controllerToAccessoryKey\n };\n }\n\n async m1(additionalTlv: [number, number | Buffer][] = []): Promise<PairM1> {\n const response = await this.#requestHandler('m1', TLV8.encode([\n [TLV8.Value.Method, TLV8.Method.PairSetup],\n [TLV8.Value.State, TLV8.State.M1],\n ...additionalTlv\n ]));\n\n const data = this.tlv(response);\n const publicKey = data.get(TLV8.Value.PublicKey);\n const salt = data.get(TLV8.Value.Salt);\n\n return {publicKey, salt};\n }\n\n async m2(m1: PairM1, pin: string = AIRPLAY_TRANSIENT_PIN): Promise<PairM2> {\n const srpKey = await SRP.genKey(32);\n\n this.#srp = new SrpClient(SRP.params.hap, m1.salt, Buffer.from('Pair-Setup'), Buffer.from(pin), srpKey, true);\n this.#srp.setB(m1.publicKey);\n\n const publicKey = this.#srp.computeA();\n const proof = this.#srp.computeM1();\n\n return {publicKey, proof};\n }\n\n async m3(m2: PairM2): Promise<PairM3> {\n const response = await this.#requestHandler('m3', TLV8.encode([\n [TLV8.Value.State, TLV8.State.M3],\n [TLV8.Value.PublicKey, m2.publicKey],\n [TLV8.Value.Proof, m2.proof]\n ]));\n\n const data = this.tlv(response);\n const serverProof = data.get(TLV8.Value.Proof);\n\n return {serverProof};\n }\n\n async m4(m3: PairM3): Promise<PairM4> {\n this.#srp.checkM2(m3.serverProof);\n\n const sharedSecret = this.#srp.computeK();\n\n return {sharedSecret};\n }\n\n async m5(m4: PairM4): Promise<PairM5> {\n const iosDeviceX = hkdf({\n hash: 'sha512',\n key: m4.sharedSecret,\n length: 32,\n salt: Buffer.from('Pair-Setup-Controller-Sign-Salt', 'utf8'),\n info: Buffer.from('Pair-Setup-Controller-Sign-Info', 'utf8')\n });\n\n const sessionKey = hkdf({\n hash: 'sha512',\n key: m4.sharedSecret,\n length: 32,\n salt: Buffer.from('Pair-Setup-Encrypt-Salt', 'utf8'),\n info: Buffer.from('Pair-Setup-Encrypt-Info', 'utf8')\n });\n\n const deviceInfo = Buffer.concat([\n iosDeviceX,\n this.#pairingId,\n this.#publicKey\n ]);\n\n const signature = Ed25519.sign(deviceInfo, this.#secretKey);\n\n const innerTlv = TLV8.encode([\n [TLV8.Value.Identifier, this.#pairingId],\n [TLV8.Value.PublicKey, this.#publicKey],\n [TLV8.Value.Signature, Buffer.from(signature)],\n [TLV8.Value.Name, OPack.encode({\n name: this.#name\n })]\n ]);\n\n const {authTag, ciphertext} = Chacha20.encrypt(sessionKey, Buffer.from('PS-Msg05'), null, innerTlv);\n const encrypted = Buffer.concat([ciphertext, authTag]);\n\n const response = await this.#requestHandler('m5', TLV8.encode([\n [TLV8.Value.State, TLV8.State.M5],\n [TLV8.Value.EncryptedData, encrypted]\n ]));\n\n const data = this.tlv(response);\n const encryptedDataRaw = data.get(TLV8.Value.EncryptedData);\n const encryptedData = encryptedDataRaw.subarray(0, -16);\n const encryptedTag = encryptedDataRaw.subarray(-16);\n\n return {\n authTag: encryptedTag,\n data: encryptedData,\n sessionKey\n };\n }\n\n async m6(m4: PairM4, m5: PairM5): Promise<AccessoryCredentials> {\n const data = Chacha20.decrypt(m5.sessionKey, Buffer.from('PS-Msg06'), null, m5.data, m5.authTag);\n const tlv = TLV8.decode(data);\n\n const accessoryIdentifier = tlv.get(TLV8.Value.Identifier);\n const accessoryLongTermPublicKey = tlv.get(TLV8.Value.PublicKey);\n const accessorySignature = tlv.get(TLV8.Value.Signature);\n\n const accessoryX = hkdf({\n hash: 'sha512',\n key: m4.sharedSecret,\n length: 32,\n salt: Buffer.from('Pair-Setup-Accessory-Sign-Salt'),\n info: Buffer.from('Pair-Setup-Accessory-Sign-Info')\n });\n\n const accessoryInfo = Buffer.concat([\n accessoryX,\n accessoryIdentifier,\n accessoryLongTermPublicKey\n ]);\n\n if (!Ed25519.verify(accessoryInfo, accessorySignature, accessoryLongTermPublicKey)) {\n throw new Error('Invalid accessory signature.');\n }\n\n return {\n accessoryIdentifier: accessoryIdentifier.toString(),\n accessoryLongTermPublicKey: accessoryLongTermPublicKey,\n pairingId: this.#pairingId,\n publicKey: this.#publicKey,\n secretKey: this.#secretKey\n };\n }\n}\n\nexport class AccessoryVerify extends BasePairing {\n readonly #ephemeralKeyPair: KeyPair;\n readonly #requestHandler: RequestHandler;\n\n constructor(context: Context, requestHandler: RequestHandler) {\n super(context);\n\n this.#ephemeralKeyPair = Curve25519.generateKeyPair();\n this.#requestHandler = requestHandler;\n }\n\n async start(credentials: AccessoryCredentials): Promise<AccessoryKeys> {\n const m1 = await this.#m1();\n const m2 = await this.#m2(credentials.accessoryIdentifier, credentials.accessoryLongTermPublicKey, m1);\n\n await this.#m3(credentials.pairingId, credentials.secretKey, m2);\n\n return await this.#m4(m2, credentials.pairingId);\n }\n\n async #m1(): Promise<VerifyM1> {\n const response = await this.#requestHandler('m1', TLV8.encode([\n [TLV8.Value.State, TLV8.State.M1],\n [TLV8.Value.PublicKey, Buffer.from(this.#ephemeralKeyPair.publicKey)]\n ]));\n\n const data = this.tlv(response);\n const serverPublicKey = data.get(TLV8.Value.PublicKey);\n const encryptedData = data.get(TLV8.Value.EncryptedData);\n\n return {\n encryptedData,\n serverPublicKey\n };\n }\n\n async #m2(localAccessoryIdentifier: string, longTermPublicKey: Buffer, m1: VerifyM1): Promise<VerifyM2> {\n const sharedSecret = Buffer.from(Curve25519.generateSharedSecKey(\n this.#ephemeralKeyPair.secretKey,\n m1.serverPublicKey\n ));\n\n const sessionKey = hkdf({\n hash: 'sha512',\n key: sharedSecret,\n length: 32,\n salt: Buffer.from('Pair-Verify-Encrypt-Salt'),\n info: Buffer.from('Pair-Verify-Encrypt-Info')\n });\n\n const encryptedData = m1.encryptedData.subarray(0, -16);\n const encryptedTag = m1.encryptedData.subarray(-16);\n\n const data = Chacha20.decrypt(sessionKey, Buffer.from('PV-Msg02'), null, encryptedData, encryptedTag);\n const tlv = TLV8.decode(data);\n\n const accessoryIdentifier = tlv.get(TLV8.Value.Identifier);\n const accessorySignature = tlv.get(TLV8.Value.Signature);\n\n if (accessoryIdentifier.toString() !== localAccessoryIdentifier) {\n throw new Error(`Invalid accessory identifier. Expected ${accessoryIdentifier.toString()} to be ${localAccessoryIdentifier}.`);\n }\n\n const accessoryInfo = Buffer.concat([\n m1.serverPublicKey,\n accessoryIdentifier,\n this.#ephemeralKeyPair.publicKey\n ]);\n\n if (!Ed25519.verify(accessoryInfo, accessorySignature, longTermPublicKey)) {\n throw new Error('Invalid accessory signature.');\n }\n\n return {\n serverEphemeralPublicKey: m1.serverPublicKey,\n sessionKey,\n sharedSecret\n };\n }\n\n async #m3(pairingId: Buffer, secretKey: Buffer, m2: VerifyM2): Promise<VerifyM3> {\n const iosDeviceInfo = Buffer.concat([\n this.#ephemeralKeyPair.publicKey,\n pairingId,\n m2.serverEphemeralPublicKey\n ]);\n\n const iosDeviceSignature = Buffer.from(Ed25519.sign(iosDeviceInfo, secretKey));\n\n const innerTlv = TLV8.encode([\n [TLV8.Value.Identifier, pairingId],\n [TLV8.Value.Signature, iosDeviceSignature]\n ]);\n\n const {authTag, ciphertext} = Chacha20.encrypt(m2.sessionKey, Buffer.from('PV-Msg03'), null, innerTlv);\n const encrypted = Buffer.concat([ciphertext, authTag]);\n\n await this.#requestHandler('m3', TLV8.encode([\n [TLV8.Value.State, TLV8.State.M3],\n [TLV8.Value.EncryptedData, encrypted]\n ]));\n\n return {};\n }\n\n async #m4(m2: VerifyM2, pairingId: Buffer): Promise<AccessoryKeys> {\n return {\n accessoryToControllerKey: Buffer.alloc(0),\n controllerToAccessoryKey: Buffer.alloc(0),\n pairingId,\n sharedSecret: m2.sharedSecret\n };\n }\n}\n\ntype RequestHandler = (step: 'm1' | 'm3' | 'm5', data: Buffer) => Promise<Buffer>;\n\ntype PairM1 = {\n readonly publicKey: Buffer;\n readonly salt: Buffer;\n}\n\ntype PairM2 = {\n readonly publicKey: Buffer;\n readonly proof: Buffer;\n};\n\ntype PairM3 = {\n readonly serverProof: Buffer;\n};\n\ntype PairM4 = {\n readonly sharedSecret: Buffer;\n};\n\ntype PairM5 = {\n readonly authTag: Buffer;\n readonly data: Buffer;\n readonly sessionKey: Buffer;\n};\n\ntype VerifyM1 = {\n readonly encryptedData: Buffer;\n readonly serverPublicKey: Buffer;\n};\n\ntype VerifyM2 = {\n readonly serverEphemeralPublicKey: Buffer;\n readonly sessionKey: Buffer;\n readonly sharedSecret: Buffer;\n};\n\ntype VerifyM3 = {};\n\nexport type AccessoryCredentials = {\n readonly accessoryIdentifier: string;\n readonly accessoryLongTermPublicKey: Buffer;\n readonly pairingId: Buffer;\n readonly publicKey: Buffer;\n readonly secretKey: Buffer;\n};\n\nexport type AccessoryKeys = {\n readonly pairingId: Buffer;\n readonly sharedSecret: Buffer;\n readonly accessoryToControllerKey: Buffer;\n readonly controllerToAccessoryKey: Buffer;\n};\n","import { createSocket, RemoteInfo, Socket } from 'node:dgram';\nimport { NTP } from '@basmilius/apple-encoding';\nimport { Logger } from './reporter';\n\nexport class TimingServer {\n get port(): number {\n return this.#port;\n }\n\n readonly #logger: Logger;\n readonly #socket: Socket;\n #port: number = 0;\n\n constructor() {\n this.#logger = new Logger('timing-server');\n this.#socket = createSocket('udp4');\n\n this.#socket.on('connect', this.#onConnect.bind(this));\n this.#socket.on('error', this.#onError.bind(this));\n this.#socket.on('message', this.#onMessage.bind(this));\n }\n\n close(): void {\n this.#socket.close();\n this.#port = 0;\n }\n\n listen(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n this.#socket.once('error', reject);\n this.#socket.once('listening', () => {\n this.#socket.removeListener('error', reject);\n this.#onListening();\n resolve();\n });\n this.#socket.bind(0, resolve);\n });\n }\n\n #onConnect(): void {\n this.#socket.setRecvBufferSize(16384);\n this.#socket.setSendBufferSize(16384);\n }\n\n #onError(err: Error): void {\n this.#logger.error('Timing server error', err);\n }\n\n #onListening(): void {\n const {port} = this.#socket.address();\n this.#port = port;\n }\n\n #onMessage(data: Buffer, info: RemoteInfo): void {\n try {\n const request = NTP.decode(data);\n const ntp = NTP.now();\n const [receivedSeconds, receivedFraction] = NTP.parts(ntp);\n\n this.#logger.info(`Timing server ntp=${ntp} receivedSeconds=${receivedSeconds} receivedFraction=${receivedFraction}`);\n\n const response = NTP.encode({\n proto: request.proto,\n type: 0x53 | 0x80,\n seqno: request.seqno,\n padding: 0,\n reftime_sec: request.sendtime_sec,\n reftime_frac: request.sendtime_frac,\n recvtime_sec: receivedSeconds,\n recvtime_frac: receivedFraction,\n sendtime_sec: receivedSeconds,\n sendtime_frac: receivedFraction\n });\n\n this.#socket.send(response, info.port, info.address, err => {\n if (!err) {\n return;\n }\n\n this.#logger.warn(`Timing server failed to send response to ${info.address}:${info.port}`, err);\n });\n } catch (err) {\n this.#logger.warn(`Timing server received malformed packet (${data.length} bytes) from ${info.address}:${info.port}`, err);\n }\n }\n}\n","import { randomBytes } from 'node:crypto';\nimport { networkInterfaces } from 'node:os';\n\nexport function generateActiveRemoteId(): string {\n return Math.floor(Math.random() * 2 ** 32).toString(10);\n}\n\nexport function generateDacpId(): string {\n return Math.floor(Math.random() * 2 ** 64).toString(16).toUpperCase();\n}\n\nexport function generateSessionId(): string {\n return Math.floor(Math.random() * 2 ** 32).toString(10);\n}\n\nexport function getLocalIP(): string | null {\n const interfaces = networkInterfaces();\n\n for (const iface of Object.values(interfaces)) {\n if (!iface) {\n continue;\n }\n\n for (const net of iface) {\n if (net.internal || net.family !== 'IPv4') {\n continue;\n }\n\n if (net.address && net.address !== '127.0.0.1') {\n return net.address;\n }\n }\n }\n\n return null;\n}\n\nexport function getMacAddress(): string {\n const interfaces = networkInterfaces();\n\n for (const iface of Object.values(interfaces)) {\n if (!iface) {\n continue;\n }\n\n for (const net of iface) {\n if (net.internal || net.family !== 'IPv4') {\n continue;\n }\n\n if (net.mac && net.mac !== '00:00:00:00:00:00') {\n return net.mac.toUpperCase();\n }\n }\n }\n\n return '00:00:00:00:00:00';\n}\n\nexport function randomInt32(): number {\n return randomBytes(4).readUInt32BE(0);\n}\n\nexport function randomInt64(): bigint {\n return randomBytes(8).readBigUint64LE(0);\n}\n\nexport function uint16ToBE(value: number): Buffer {\n const buffer = Buffer.allocUnsafe(2);\n buffer.writeUInt16BE(value, 0);\n\n return buffer;\n}\n\nexport function uint53ToLE(value: number): Buffer {\n const [upper, lower] = splitUInt53(value);\n const buffer = Buffer.allocUnsafe(8);\n buffer.writeUInt32LE(lower, 0);\n buffer.writeUInt32LE(upper, 4);\n\n return buffer;\n}\n\nfunction splitUInt53(number: number): [number, number] {\n const MAX_UINT32 = 0x00000000FFFFFFFF;\n const MAX_INT53 = 0x001FFFFFFFFFFFFF;\n\n if (number <= -1 || number > MAX_INT53) {\n throw new Error('Number out of range.');\n }\n\n if (Math.floor(number) !== number) {\n throw new Error('Number is not an integer.');\n }\n\n let upper: number = 0;\n const signbit = number & 0xFFFFFFFF;\n const lower = signbit < 0 ? (number & 0x7FFFFFFF) + 0x80000000 : signbit;\n\n if (number > MAX_UINT32) {\n upper = (number - lower) / (MAX_UINT32 + 1);\n }\n\n return [upper, lower];\n}\n"],"x_google_ignoreList":[0,1,2,3],"mappings":"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"}