@basmilius/apple-common 0.7.2 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +283 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +3 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +11 -10
- package/dist/cli.d.ts +0 -2
- package/dist/connection.d.ts +0 -38
- package/dist/const.d.ts +0 -6
- package/dist/context.d.ts +0 -7
- package/dist/discovery.d.ts +0 -10
- package/dist/index.d.ts +0 -13
- package/dist/index.js +0 -942
- package/dist/pairing.d.ts +0 -59
- package/dist/reporter.d.ts +0 -22
- package/dist/symbols.d.ts +0 -1
- package/dist/timing.d.ts +0 -7
- package/dist/types.d.ts +0 -120
- package/dist/utils.d.ts +0 -6
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { DiscoveryResult as DiscoveryResult$1 } from "node-dns-sd";
|
|
3
|
+
import { EventEmitter } from "node:events";
|
|
4
|
+
|
|
5
|
+
//#region ../../node_modules/.bun/uuid@13.0.0/node_modules/uuid/dist/types.d.ts
|
|
6
|
+
type Version4Options = {
|
|
7
|
+
random?: Uint8Array;
|
|
8
|
+
rng?: () => Uint8Array;
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region ../../node_modules/.bun/uuid@13.0.0/node_modules/uuid/dist/v4.d.ts
|
|
12
|
+
declare function v4(options?: Version4Options, buf?: undefined, offset?: number): string;
|
|
13
|
+
declare function v4<TBuf extends Uint8Array = Uint8Array>(options: Version4Options | undefined, buf: TBuf, offset?: number): TBuf;
|
|
14
|
+
//#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>;
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/reporter.d.ts
|
|
31
|
+
type DebugGroup = 'debug' | 'error' | 'info' | 'net' | 'raw' | 'warn';
|
|
32
|
+
declare class Logger {
|
|
33
|
+
#private;
|
|
34
|
+
get id(): string;
|
|
35
|
+
get label(): string;
|
|
36
|
+
constructor(id: string);
|
|
37
|
+
debug(...data: any[]): void;
|
|
38
|
+
error(...data: any[]): void;
|
|
39
|
+
info(...data: any[]): void;
|
|
40
|
+
net(...data: any[]): void;
|
|
41
|
+
raw(...data: any[]): void;
|
|
42
|
+
warn(...data: any[]): void;
|
|
43
|
+
}
|
|
44
|
+
declare class Reporter {
|
|
45
|
+
#private;
|
|
46
|
+
all(): void;
|
|
47
|
+
disable(group: DebugGroup): void;
|
|
48
|
+
enable(group: DebugGroup): void;
|
|
49
|
+
isEnabled(group: DebugGroup): boolean;
|
|
50
|
+
}
|
|
51
|
+
declare const reporter: Reporter;
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/context.d.ts
|
|
54
|
+
declare class Context {
|
|
55
|
+
#private;
|
|
56
|
+
get deviceId(): string;
|
|
57
|
+
get logger(): Logger;
|
|
58
|
+
constructor(deviceId: string);
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/symbols.d.ts
|
|
62
|
+
declare const ENCRYPTION: unique symbol;
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/types.d.ts
|
|
65
|
+
type ConnectionState = 'closing' | 'connected' | 'connecting' | 'disconnected' | 'failed';
|
|
66
|
+
type EventMap = Record<string, any>;
|
|
67
|
+
type DnsRecordClass = 'IN' | 'CS' | 'CH' | 'HS' | 'ANY';
|
|
68
|
+
type DnsRecordType = 'A' | 'AAAA' | 'CNAME' | 'MX' | 'NS' | 'NSEC' | 'PTR' | 'SOA' | 'SRV' | 'TXT';
|
|
69
|
+
type DnsRecordBase = {
|
|
70
|
+
readonly name: string;
|
|
71
|
+
readonly type: DnsRecordType;
|
|
72
|
+
readonly class: DnsRecordClass;
|
|
73
|
+
readonly flash: boolean;
|
|
74
|
+
readonly ttl: number;
|
|
75
|
+
};
|
|
76
|
+
type DnsRecordA = DnsRecordBase & {
|
|
77
|
+
readonly type: 'A';
|
|
78
|
+
readonly rdata: string;
|
|
79
|
+
};
|
|
80
|
+
type DnsRecordAAAA = DnsRecordBase & {
|
|
81
|
+
readonly type: 'AAAA';
|
|
82
|
+
readonly rdata: string;
|
|
83
|
+
};
|
|
84
|
+
type DnsRecordPTR = DnsRecordBase & {
|
|
85
|
+
readonly type: 'PTR';
|
|
86
|
+
readonly rdata: string;
|
|
87
|
+
};
|
|
88
|
+
type DnsRecordTXT = DnsRecordBase & {
|
|
89
|
+
readonly type: 'TXT';
|
|
90
|
+
readonly rdata: Record<string, string>;
|
|
91
|
+
readonly rdata_buffer: Record<string, Buffer>;
|
|
92
|
+
};
|
|
93
|
+
type DnsRecordSRV = DnsRecordBase & {
|
|
94
|
+
readonly type: 'SRV';
|
|
95
|
+
readonly rdata: {
|
|
96
|
+
readonly priority: number;
|
|
97
|
+
readonly weight: number;
|
|
98
|
+
readonly port: number;
|
|
99
|
+
readonly target: string;
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
type DnsRecordNSEC = DnsRecordBase & {
|
|
103
|
+
readonly type: 'NSEC';
|
|
104
|
+
readonly rdata: string;
|
|
105
|
+
};
|
|
106
|
+
type DnsRecord = DnsRecordA | DnsRecordAAAA | DnsRecordPTR | DnsRecordTXT | DnsRecordSRV | DnsRecordNSEC;
|
|
107
|
+
type DnsPacketHeader = {
|
|
108
|
+
readonly id: number;
|
|
109
|
+
readonly qr: number;
|
|
110
|
+
readonly op: number;
|
|
111
|
+
readonly aa: number;
|
|
112
|
+
readonly tc: number;
|
|
113
|
+
readonly rd: number;
|
|
114
|
+
readonly ra: number;
|
|
115
|
+
readonly z: number;
|
|
116
|
+
readonly ad: number;
|
|
117
|
+
readonly cd: number;
|
|
118
|
+
readonly rc: number;
|
|
119
|
+
readonly questions: number;
|
|
120
|
+
readonly answers: number;
|
|
121
|
+
readonly authorities: number;
|
|
122
|
+
readonly additionals: number;
|
|
123
|
+
};
|
|
124
|
+
type DnsPacket = {
|
|
125
|
+
readonly address: string;
|
|
126
|
+
readonly header: DnsPacketHeader;
|
|
127
|
+
readonly questions: DnsRecord[];
|
|
128
|
+
readonly answers: DnsRecord[];
|
|
129
|
+
readonly authorities: DnsRecord[];
|
|
130
|
+
readonly additionals: DnsRecord[];
|
|
131
|
+
};
|
|
132
|
+
type Result = {
|
|
133
|
+
readonly fqdn: string;
|
|
134
|
+
readonly address: string;
|
|
135
|
+
readonly modelName: string;
|
|
136
|
+
readonly familyName: string | null;
|
|
137
|
+
readonly service: {
|
|
138
|
+
readonly port: number;
|
|
139
|
+
readonly protocol: 'tcp' | 'udp';
|
|
140
|
+
readonly type: string;
|
|
141
|
+
};
|
|
142
|
+
readonly packet: DnsPacket;
|
|
143
|
+
readonly [key: string]: unknown;
|
|
144
|
+
};
|
|
145
|
+
type DiscoveryResult = {
|
|
146
|
+
readonly id: string;
|
|
147
|
+
readonly txt: Record<string, string>;
|
|
148
|
+
} & Result;
|
|
149
|
+
//#endregion
|
|
150
|
+
//#region src/connection.d.ts
|
|
151
|
+
type ConnectionEventMap = {
|
|
152
|
+
close: [hadError: boolean];
|
|
153
|
+
connect: [];
|
|
154
|
+
data: [data: Buffer];
|
|
155
|
+
end: [];
|
|
156
|
+
error: [err: Error];
|
|
157
|
+
timeout: [];
|
|
158
|
+
};
|
|
159
|
+
declare class Connection<TEventMap extends EventMap> extends EventEmitter<ConnectionEventMap | TEventMap> {
|
|
160
|
+
#private;
|
|
161
|
+
get address(): string;
|
|
162
|
+
get context(): Context;
|
|
163
|
+
get port(): number;
|
|
164
|
+
get isConnected(): boolean;
|
|
165
|
+
get state(): ConnectionState;
|
|
166
|
+
constructor(context: Context, address: string, port: number);
|
|
167
|
+
connect(): Promise<void>;
|
|
168
|
+
destroy(): void;
|
|
169
|
+
disconnect(): Promise<void>;
|
|
170
|
+
debug(enabled: boolean): this;
|
|
171
|
+
retry(attempts: number, interval?: number): this;
|
|
172
|
+
write(data: Buffer | Uint8Array): void;
|
|
173
|
+
}
|
|
174
|
+
declare class EncryptionAwareConnection<TEventMap extends EventMap> extends Connection<TEventMap> {
|
|
175
|
+
get isEncrypted(): boolean;
|
|
176
|
+
[ENCRYPTION]?: EncryptionState;
|
|
177
|
+
enableEncryption(readKey: Buffer, writeKey: Buffer): void;
|
|
178
|
+
}
|
|
179
|
+
declare class EncryptionState {
|
|
180
|
+
readKey: Buffer;
|
|
181
|
+
readCount: number;
|
|
182
|
+
writeKey: Buffer;
|
|
183
|
+
writeCount: number;
|
|
184
|
+
constructor(readKey: Buffer, writeKey: Buffer);
|
|
185
|
+
}
|
|
186
|
+
//#endregion
|
|
187
|
+
//#region src/const.d.ts
|
|
188
|
+
declare const AIRPLAY_TRANSIENT_PIN = "3939";
|
|
189
|
+
declare const HTTP_TIMEOUT = 6000;
|
|
190
|
+
declare const AIRPLAY_SERVICE = "_airplay._tcp.local";
|
|
191
|
+
declare const COMPANION_LINK_SERVICE = "_companion-link._tcp.local";
|
|
192
|
+
declare const RAOP_SERVICE = "_raop._tcp.local";
|
|
193
|
+
//#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
|
+
//#region src/timing.d.ts
|
|
254
|
+
declare class TimingServer {
|
|
255
|
+
#private;
|
|
256
|
+
get port(): number;
|
|
257
|
+
constructor();
|
|
258
|
+
close(): void;
|
|
259
|
+
listen(): Promise<void>;
|
|
260
|
+
}
|
|
261
|
+
//#endregion
|
|
262
|
+
//#region src/utils.d.ts
|
|
263
|
+
declare function generateActiveRemoteId(): string;
|
|
264
|
+
declare function generateDacpId(): string;
|
|
265
|
+
declare function generateSessionId(): string;
|
|
266
|
+
declare function getLocalIP(): string | null;
|
|
267
|
+
declare function getMacAddress(): string;
|
|
268
|
+
declare function randomInt32(): number;
|
|
269
|
+
declare function randomInt64(): bigint;
|
|
270
|
+
declare function uint16ToBE(value: number): Buffer;
|
|
271
|
+
declare function uint53ToLE(value: number): Buffer;
|
|
272
|
+
//#endregion
|
|
273
|
+
//#region src/audioSource.d.ts
|
|
274
|
+
interface AudioSource {
|
|
275
|
+
get duration(): number;
|
|
276
|
+
readFrames(count: number): Promise<Buffer | null>;
|
|
277
|
+
reset(): Promise<void>;
|
|
278
|
+
start(): Promise<void>;
|
|
279
|
+
stop(): Promise<void>;
|
|
280
|
+
}
|
|
281
|
+
//#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
|
|
@@ -0,0 +1 @@
|
|
|
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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"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{randomBytes as e,randomFillSync as t,randomUUID as n}from"node:crypto";import r from"node-dns-sd";import{createInterface as i}from"node:readline";import{EventEmitter as a}from"node:events";import{Socket as o}from"node:net";import{NTP as s,OPack as c,TLV8 as l}from"@basmilius/apple-encoding";import{Chacha20 as u,Curve25519 as d,Ed25519 as f,hkdf as p}from"@basmilius/apple-encryption";import{SRP as m,SrpClient as h}from"fast-srp-hap";import{createSocket as g}from"node:dgram";import{networkInterfaces as _}from"node:os";const v=[];for(let e=0;e<256;++e)v.push((e+256).toString(16).slice(1));function y(e,t=0){return(v[e[t+0]]+v[e[t+1]]+v[e[t+2]]+v[e[t+3]]+`-`+v[e[t+4]]+v[e[t+5]]+`-`+v[e[t+6]]+v[e[t+7]]+`-`+v[e[t+8]]+v[e[t+9]]+`-`+v[e[t+10]]+v[e[t+11]]+v[e[t+12]]+v[e[t+13]]+v[e[t+14]]+v[e[t+15]]).toLowerCase()}const b=new Uint8Array(256);let x=b.length;function S(){return x>b.length-16&&(t(b),x=0),b.slice(x,x+=16)}var C={randomUUID:n};function w(e,t,n){e||={};let r=e.random??e.rng?.()??S();if(r.length<16)throw Error(`Random bytes length must be >= 16`);if(r[6]=r[6]&15|64,r[8]=r[8]&63|128,t){if(n||=0,n<0||n+16>t.length)throw RangeError(`UUID byte range ${n}:${n+15} is out of buffer bounds`);for(let e=0;e<16;++e)t[n+e]=r[e];return t}return y(r)}function T(e,t,n){return C.randomUUID&&!t&&!e?C.randomUUID():w(e,t,n)}async function E(e){let t=i({input:process.stdin,output:process.stdout}),n=await new Promise(n=>t.question(`${e}: `,n));return t.close(),n}async function D(e){return new Promise(t=>setTimeout(t,e))}const O=`3939`,k=6e3,A=`_airplay._tcp.local`,j=`_companion-link._tcp.local`,M=`_raop._tcp.local`;var N=class e{#e;constructor(e){this.#e=e}async find(){return(await r.discover({name:this.#e})).map(e=>({id:P(e)??e.fqdn,txt:ee(e),...e}))}async findUntil(e,t=10,n=1e3){for(;t>0;){let r=await this.find(),i=r.find(t=>t.id===e);if(i)return i;console.log(),console.log(`Device not found, retrying in ${n}ms...`),console.log(r.map(e=>` ● ${e.id} (${e.fqdn})`).join(`
|
|
2
|
+
`)),t--,await D(n)}throw Error(`Device not found after serveral tries, aborting.`)}static airplay(){return new e(A)}static companionLink(){return new e(j)}static raop(){return new e(M)}};function P(e){if(!e?.packet)return null;let{answers:t=[],additionals:n=[]}=e.packet,r=[...t,...n],i=r.find(e=>e.type===`SRV`);if(i?.rdata?.target)return i.rdata.target;if(e.address){let t=r.find(t=>(t.type===`A`||t.type===`AAAA`)&&t.rdata===e.address);if(t?.name)return t.name}let a=r.find(e=>e.type===`A`);return a?.name?a.name:e.modelName?`${e.modelName.replace(/\s+/g,`-`).replace(/[^a-zA-Z0-9-]/g,``)}.local`:null}function ee(e){if(!e.packet)return{};let{answers:t=[],additionals:n=[]}=e.packet,r=[...t,...n],i={};for(let e of r)e.type===`TXT`&&e.rdata&&Object.assign(i,e.rdata);return i}const F=Symbol(),I={resolve:()=>{},reject:e=>{}};var L=class extends a{get address(){return this.#e}get context(){return this.#n}get port(){return this.#t}get isConnected(){return this.#u===`connected`}get state(){if(this.#u===`closing`||this.#u===`failed`)return this.#u;if(!this.#l)return`disconnected`;switch(this.#l.readyState){case`opening`:return`connecting`;case`open`:return`connected`;default:return this.#u}}#e;#t;#n;#r=!1;#i=0;#a=3;#o=!0;#s=3e3;#c;#l;#u;#d;constructor(e,t,n){super(),this.#e=t,this.#t=n,this.#n=e,this.#u=`disconnected`}async connect(){if(this.#u!==`connected`){if(this.#u===`connecting`)throw Error(`A connection is already being established.`);return this.#o=!0,this.#i=0,this.#f()}}destroy(){this.#l?.destroy()}async disconnect(){if(this.#c&&=(clearTimeout(this.#c),void 0),this.#o=!1,!(!this.#l||this.#u===`disconnected`))return new Promise(e=>{this.#u=`closing`,this.#l.once(`close`,()=>{this.#p(),e()}),this.#l.end()})}debug(e){return this.#r=e,this}retry(e,t=3e3){return this.#a=e,this.#s=t,this}write(e){if(!this.#l||this.state!==`connected`||!this.#l.writable){this.emit(`error`,Error(`Cannot write to a disconnected connection.`));return}this.#l.write(e,e=>{e&&(this.#n.logger.error(`Failed to write data to socket.`),this.emit(`error`,e))})}async#f(){return new Promise((e,t)=>{this.#u=`connecting`,this.#d={resolve:e,reject:t},this.#l?.removeAllListeners(),this.#l=void 0,this.#l=new o,this.#l.setNoDelay(!0),this.#l.setTimeout(1e4),this.#l.on(`close`,this.#h.bind(this)),this.#l.on(`connect`,this.#g.bind(this)),this.#l.on(`data`,this.#_.bind(this)),this.#l.on(`end`,this.#v.bind(this)),this.#l.on(`error`,this.#y.bind(this)),this.#l.on(`timeout`,this.#b.bind(this)),this.#n.logger.net(`Connecting to ${this.#e}:${this.#t}...`),this.#l.connect({host:this.#e,port:this.#t,keepAlive:!0})})}#p(){this.#c&&=(clearTimeout(this.#c),void 0),this.#l&&=(this.#l.removeAllListeners(),this.#l.destroy(),void 0),this.#u=`disconnected`,this.#d=void 0}#m(e){if(!this.#o||this.#i>=this.#a){this.#u=`failed`,this.#d?.reject(e),this.#d=void 0;return}this.#c&&=(clearTimeout(this.#c),void 0),this.#i++,this.#n.logger.net(`Retry attempt ${this.#i} / ${this.#a} in ${this.#s}ms...`);let{resolve:t,reject:n}=this.#d??I;this.#p(),this.#c=setTimeout(async()=>{this.#c=void 0;try{this.#d={resolve:t,reject:n},await this.#f(),t()}catch{}},this.#s)}#h(e){let t=this.#u===`connected`;this.#u!==`closing`&&(this.#u=`disconnected`,this.#n.logger.net(`Connection closed (${e?`with error`:`normally`}).`)),this.emit(`close`,e),t&&this.#o&&e&&this.#m(Error(`Connection closed unexpectedly.`))}#g(){this.#u=`connected`,this.#i=0,this.#l.setKeepAlive(!0,1e4),this.#l.setTimeout(0),this.emit(`connect`),this.#d?.resolve(),this.#d=void 0}#_(e){if(this.#r){let t=Math.min(e.byteLength,64);this.#n.logger.debug(`Received ${e.byteLength} bytes of data.`),this.#n.logger.debug(`hex=${e.subarray(0,t).toString(`hex`)}`),this.#n.logger.debug(`ascii=${e.toString(`ascii`).replace(/[^\x20-\x7E]/g,`.`).substring(0,t)}`)}this.emit(`data`,e)}#v(){this.emit(`end`)}#y(e){this.#n.logger.error(`Connection error: ${e.message}`),this.listenerCount(`error`)>0?this.emit(`error`,e):this.#n.logger.warn(`No error handler registered. This is likely a bug.`,this.constructor.name,`#onError`),this.#u===`connecting`?this.#m(e):this.#u=`failed`}#b(){this.#n.logger.error(`Connection timed out.`);let e=Error(`Connection timed out.`);this.emit(`timeout`),this.#u===`connecting`?this.#m(e):(this.#u=`failed`,this.#l?.destroy())}},R=class extends L{get isEncrypted(){return!!this[F]}[F];enableEncryption(e,t){this[F]=new z(e,t)}},z=class{readKey;readCount;writeKey;writeCount;constructor(e,t){this.readCount=0,this.readKey=e,this.writeCount=0,this.writeKey=t}},B=class{get id(){return this.#e}get label(){return this.#t}#e;#t;constructor(e){this.#e=e,this.#t=`\u001b[36m[${e}]\u001b[39m`}debug(...e){H(this.#t,...e)}error(...e){U(this.#t,...e)}info(...e){W(this.#t,...e)}net(...e){G(this.#t,...e)}raw(...e){K(this.#t,...e)}warn(...e){q(this.#t,...e)}},V=class{#e=[];all(){this.#e=[`debug`,`error`,`info`,`net`,`raw`,`warn`]}disable(e){this.#e.includes(e)&&this.#e.splice(this.#e.indexOf(e),1)}enable(e){this.#e.includes(e)||this.#e.push(e)}isEnabled(e){return this.#e.includes(e)}};function H(...e){J.isEnabled(`debug`)&&console.debug(`\x1B[36m[debug]\x1B[39m`,...e)}function U(...e){J.isEnabled(`error`)&&console.error(`\x1B[31m[error]\x1B[39m`,...e)}function W(...e){J.isEnabled(`info`)&&console.info(`\x1B[32m[info]\x1B[39m`,...e)}function G(...e){J.isEnabled(`net`)&&console.info(`\x1B[33m[net]\x1B[39m`,...e)}function K(...e){J.isEnabled(`raw`)&&console.log(`\x1B[34m[raw]\x1B[39m`,...e)}function q(...e){J.isEnabled(`warn`)&&console.warn(`\x1B[33m[warn]\x1B[39m`,...e)}const J=new V;var Y=class{get deviceId(){return this.#e}get logger(){return this.#t}#e;#t;constructor(e){this.#e=e,this.#t=new B(e)}},X=class{get context(){return this.#e}#e;constructor(e){this.#e=e}tlv(e){let t=l.decode(e);return t.has(l.Value.Error)&&l.bail(t),this.#e.logger.raw(`Decoded TLV`,t),t}},Z=class extends X{#e;#t;#n;#r;#i;#a;constructor(e,t){super(e),this.#e=`basmilius/apple-protocols`,this.#t=Buffer.from(T().toUpperCase()),this.#n=t}async start(){let e=f.generateKeyPair();this.#r=Buffer.from(e.publicKey),this.#i=Buffer.from(e.secretKey)}async pin(e){let t=await this.m1(),n=await this.m2(t,await e()),r=await this.m3(n),i=await this.m4(r),a=await this.m5(i),o=await this.m6(i,a);if(!o)throw Error(`Pairing failed, could not get accessory keys.`);return o}async transient(){let e=await this.m1([[l.Value.Flags,l.Flags.TransientPairing]]),t=await this.m2(e),n=await this.m3(t),r=await this.m4(n),i=p({hash:`sha512`,key:r.sharedSecret,length:32,salt:Buffer.from(`Control-Salt`),info:Buffer.from(`Control-Read-Encryption-Key`)}),a=p({hash:`sha512`,key:r.sharedSecret,length:32,salt:Buffer.from(`Control-Salt`),info:Buffer.from(`Control-Write-Encryption-Key`)});return{pairingId:this.#t,sharedSecret:r.sharedSecret,accessoryToControllerKey:i,controllerToAccessoryKey:a}}async m1(e=[]){let t=await this.#n(`m1`,l.encode([[l.Value.Method,l.Method.PairSetup],[l.Value.State,l.State.M1],...e])),n=this.tlv(t);return{publicKey:n.get(l.Value.PublicKey),salt:n.get(l.Value.Salt)}}async m2(e,t=O){let n=await m.genKey(32);return this.#a=new h(m.params.hap,e.salt,Buffer.from(`Pair-Setup`),Buffer.from(t),n,!0),this.#a.setB(e.publicKey),{publicKey:this.#a.computeA(),proof:this.#a.computeM1()}}async m3(e){let t=await this.#n(`m3`,l.encode([[l.Value.State,l.State.M3],[l.Value.PublicKey,e.publicKey],[l.Value.Proof,e.proof]]));return{serverProof:this.tlv(t).get(l.Value.Proof)}}async m4(e){return this.#a.checkM2(e.serverProof),{sharedSecret:this.#a.computeK()}}async m5(e){let t=p({hash:`sha512`,key:e.sharedSecret,length:32,salt:Buffer.from(`Pair-Setup-Controller-Sign-Salt`,`utf8`),info:Buffer.from(`Pair-Setup-Controller-Sign-Info`,`utf8`)}),n=p({hash:`sha512`,key:e.sharedSecret,length:32,salt:Buffer.from(`Pair-Setup-Encrypt-Salt`,`utf8`),info:Buffer.from(`Pair-Setup-Encrypt-Info`,`utf8`)}),r=Buffer.concat([t,this.#t,this.#r]),i=f.sign(r,this.#i),a=l.encode([[l.Value.Identifier,this.#t],[l.Value.PublicKey,this.#r],[l.Value.Signature,Buffer.from(i)],[l.Value.Name,c.encode({name:this.#e})]]),{authTag:o,ciphertext:s}=u.encrypt(n,Buffer.from(`PS-Msg05`),null,a),d=Buffer.concat([s,o]),m=await this.#n(`m5`,l.encode([[l.Value.State,l.State.M5],[l.Value.EncryptedData,d]])),h=this.tlv(m).get(l.Value.EncryptedData),g=h.subarray(0,-16);return{authTag:h.subarray(-16),data:g,sessionKey:n}}async m6(e,t){let n=u.decrypt(t.sessionKey,Buffer.from(`PS-Msg06`),null,t.data,t.authTag),r=l.decode(n),i=r.get(l.Value.Identifier),a=r.get(l.Value.PublicKey),o=r.get(l.Value.Signature),s=p({hash:`sha512`,key:e.sharedSecret,length:32,salt:Buffer.from(`Pair-Setup-Accessory-Sign-Salt`),info:Buffer.from(`Pair-Setup-Accessory-Sign-Info`)}),c=Buffer.concat([s,i,a]);if(!f.verify(c,o,a))throw Error(`Invalid accessory signature.`);return{accessoryIdentifier:i.toString(),accessoryLongTermPublicKey:a,pairingId:this.#t,publicKey:this.#r,secretKey:this.#i}}},Q=class extends X{#e;#t;constructor(e,t){super(e),this.#e=d.generateKeyPair(),this.#t=t}async start(e){let t=await this.#n(),n=await this.#r(e.accessoryIdentifier,e.accessoryLongTermPublicKey,t);return await this.#i(e.pairingId,e.secretKey,n),await this.#a(n,e.pairingId)}async#n(){let e=await this.#t(`m1`,l.encode([[l.Value.State,l.State.M1],[l.Value.PublicKey,Buffer.from(this.#e.publicKey)]])),t=this.tlv(e),n=t.get(l.Value.PublicKey);return{encryptedData:t.get(l.Value.EncryptedData),serverPublicKey:n}}async#r(e,t,n){let r=Buffer.from(d.generateSharedSecKey(this.#e.secretKey,n.serverPublicKey)),i=p({hash:`sha512`,key:r,length:32,salt:Buffer.from(`Pair-Verify-Encrypt-Salt`),info:Buffer.from(`Pair-Verify-Encrypt-Info`)}),a=n.encryptedData.subarray(0,-16),o=n.encryptedData.subarray(-16),s=u.decrypt(i,Buffer.from(`PV-Msg02`),null,a,o),c=l.decode(s),m=c.get(l.Value.Identifier),h=c.get(l.Value.Signature);if(m.toString()!==e)throw Error(`Invalid accessory identifier. Expected ${m.toString()} to be ${e}.`);let g=Buffer.concat([n.serverPublicKey,m,this.#e.publicKey]);if(!f.verify(g,h,t))throw Error(`Invalid accessory signature.`);return{serverEphemeralPublicKey:n.serverPublicKey,sessionKey:i,sharedSecret:r}}async#i(e,t,n){let r=Buffer.concat([this.#e.publicKey,e,n.serverEphemeralPublicKey]),i=Buffer.from(f.sign(r,t)),a=l.encode([[l.Value.Identifier,e],[l.Value.Signature,i]]),{authTag:o,ciphertext:s}=u.encrypt(n.sessionKey,Buffer.from(`PV-Msg03`),null,a),c=Buffer.concat([s,o]);return await this.#t(`m3`,l.encode([[l.Value.State,l.State.M3],[l.Value.EncryptedData,c]])),{}}async#a(e,t){return{accessoryToControllerKey:Buffer.alloc(0),controllerToAccessoryKey:Buffer.alloc(0),pairingId:t,sharedSecret:e.sharedSecret}}},te=class{get port(){return this.#n}#e;#t;#n=0;constructor(){this.#e=new B(`timing-server`),this.#t=g(`udp4`),this.#t.on(`connect`,this.#r.bind(this)),this.#t.on(`error`,this.#i.bind(this)),this.#t.on(`message`,this.#o.bind(this))}close(){this.#t.close(),this.#n=0}listen(){return new Promise((e,t)=>{this.#t.once(`error`,t),this.#t.once(`listening`,()=>{this.#t.removeListener(`error`,t),this.#a(),e()}),this.#t.bind(0,e)})}#r(){this.#t.setRecvBufferSize(16384),this.#t.setSendBufferSize(16384)}#i(e){this.#e.error(`Timing server error`,e)}#a(){let{port:e}=this.#t.address();this.#n=e}#o(e,t){try{let n=s.decode(e),r=s.now(),[i,a]=s.parts(r);this.#e.info(`Timing server ntp=${r} receivedSeconds=${i} receivedFraction=${a}`);let o=s.encode({proto:n.proto,type:211,seqno:n.seqno,padding:0,reftime_sec:n.sendtime_sec,reftime_frac:n.sendtime_frac,recvtime_sec:i,recvtime_frac:a,sendtime_sec:i,sendtime_frac:a});this.#t.send(o,t.port,t.address,e=>{e&&this.#e.warn(`Timing server failed to send response to ${t.address}:${t.port}`,e)})}catch(n){this.#e.warn(`Timing server received malformed packet (${e.length} bytes) from ${t.address}:${t.port}`,n)}}};function ne(){return Math.floor(Math.random()*2**32).toString(10)}function re(){return Math.floor(Math.random()*2**64).toString(16).toUpperCase()}function ie(){return Math.floor(Math.random()*2**32).toString(10)}function $(){let e=_();for(let t of Object.values(e))if(t){for(let e of t)if(!(e.internal||e.family!==`IPv4`)&&e.address&&e.address!==`127.0.0.1`)return e.address}return null}function ae(){let e=_();for(let t of Object.values(e))if(t){for(let e of t)if(!(e.internal||e.family!==`IPv4`)&&e.mac&&e.mac!==`00:00:00:00:00:00`)return e.mac.toUpperCase()}return`00:00:00:00:00:00`}function oe(){return e(4).readUInt32BE(0)}function se(){return e(8).readBigUint64LE(0)}function ce(e){let t=Buffer.allocUnsafe(2);return t.writeUInt16BE(e,0),t}function le(e){let[t,n]=ue(e),r=Buffer.allocUnsafe(8);return r.writeUInt32LE(n,0),r.writeUInt32LE(t,4),r}function ue(e){let t=4294967295;if(e<=-1||e>9007199254740991)throw Error(`Number out of range.`);if(Math.floor(e)!==e)throw Error(`Number is not an integer.`);let n=0,r=e&4294967295,i=r<0?(e&2147483647)+2147483648:r;return e>t&&(n=(e-i)/(t+1)),[n,i]}export{A as AIRPLAY_SERVICE,O as AIRPLAY_TRANSIENT_PIN,Z as AccessoryPair,Q as AccessoryVerify,j as COMPANION_LINK_SERVICE,L as Connection,Y as Context,N as Discovery,F as ENCRYPTION,R as EncryptionAwareConnection,z as EncryptionState,k as HTTP_TIMEOUT,M as RAOP_SERVICE,te as TimingServer,ne as generateActiveRemoteId,re as generateDacpId,ie as generateSessionId,$ as getLocalIP,ae as getMacAddress,E as prompt,oe as randomInt32,se as randomInt64,J as reporter,ce as uint16ToBE,le as uint53ToLE,T as uuid,D as waitFor};
|
|
3
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
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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"}
|
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.
|
|
4
|
+
"version": "0.8.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": {
|
|
@@ -25,28 +25,29 @@
|
|
|
25
25
|
"provenance": false
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
|
-
"build": "tsgo &&
|
|
28
|
+
"build": "tsgo --noEmit && tsdown",
|
|
29
|
+
"dev": "tsdown --watch",
|
|
29
30
|
"test:discovery": "bun --watch test-discovery.ts"
|
|
30
31
|
},
|
|
31
|
-
"main": "./dist/index.
|
|
32
|
-
"types": "./dist/index.d.
|
|
33
|
-
"typings": "./dist/index.d.
|
|
32
|
+
"main": "./dist/index.mjs",
|
|
33
|
+
"types": "./dist/index.d.mts",
|
|
34
|
+
"typings": "./dist/index.d.mts",
|
|
34
35
|
"sideEffects": false,
|
|
35
36
|
"exports": {
|
|
36
37
|
".": {
|
|
37
|
-
"types": "./dist/index.d.
|
|
38
|
-
"default": "./dist/index.
|
|
38
|
+
"types": "./dist/index.d.mts",
|
|
39
|
+
"default": "./dist/index.mjs"
|
|
39
40
|
}
|
|
40
41
|
},
|
|
41
42
|
"dependencies": {
|
|
42
|
-
"@basmilius/apple-encoding": "0.
|
|
43
|
-
"@basmilius/apple-encryption": "0.
|
|
43
|
+
"@basmilius/apple-encoding": "0.8.1",
|
|
44
|
+
"@basmilius/apple-encryption": "0.8.1",
|
|
44
45
|
"fast-srp-hap": "^2.0.4",
|
|
45
46
|
"node-dns-sd": "^1.0.1"
|
|
46
47
|
},
|
|
47
48
|
"devDependencies": {
|
|
48
|
-
"@basmilius/tools": "^2.25.0",
|
|
49
49
|
"@types/bun": "^1.3.9",
|
|
50
|
+
"tsdown": "^0.21.0-beta.2",
|
|
50
51
|
"uuid": "^13.0.0"
|
|
51
52
|
}
|
|
52
53
|
}
|
package/dist/cli.d.ts
DELETED
package/dist/connection.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from "node:events";
|
|
2
|
-
import type { Context } from "./context";
|
|
3
|
-
import type { ConnectionState, EventMap } from "./types";
|
|
4
|
-
type ConnectionEventMap = {
|
|
5
|
-
close: [hadError: boolean];
|
|
6
|
-
connect: [];
|
|
7
|
-
data: [data: Buffer];
|
|
8
|
-
end: [];
|
|
9
|
-
error: [err: Error];
|
|
10
|
-
timeout: [];
|
|
11
|
-
};
|
|
12
|
-
export declare class Connection<TEventMap extends EventMap> extends EventEmitter<ConnectionEventMap | TEventMap> {
|
|
13
|
-
#private;
|
|
14
|
-
get address(): string;
|
|
15
|
-
get context(): Context;
|
|
16
|
-
get port(): number;
|
|
17
|
-
get isConnected(): boolean;
|
|
18
|
-
get state(): ConnectionState;
|
|
19
|
-
constructor(context: Context, address: string, port: number);
|
|
20
|
-
connect(): Promise<void>;
|
|
21
|
-
destroy(): Promise<void>;
|
|
22
|
-
disconnect(): Promise<void>;
|
|
23
|
-
debug(enabled: boolean): this;
|
|
24
|
-
retry(attempts: number, interval?: number): this;
|
|
25
|
-
write(data: Buffer | Uint8Array): void;
|
|
26
|
-
}
|
|
27
|
-
export declare class EncryptionAwareConnection<TEventMap extends EventMap> extends Connection<TEventMap> {
|
|
28
|
-
get isEncrypted(): boolean;
|
|
29
|
-
enableEncryption(readKey: Buffer, writeKey: Buffer): void;
|
|
30
|
-
}
|
|
31
|
-
export declare class EncryptionState {
|
|
32
|
-
readKey: Buffer;
|
|
33
|
-
readCount: number;
|
|
34
|
-
writeKey: Buffer;
|
|
35
|
-
writeCount: number;
|
|
36
|
-
constructor(readKey: Buffer, writeKey: Buffer);
|
|
37
|
-
}
|
|
38
|
-
export {};
|
package/dist/const.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export declare const AIRPLAY_TRANSIENT_PIN = "3939";
|
|
2
|
-
export declare const HTTP_TIMEOUT = 6e3;
|
|
3
|
-
export declare const SOCKET_TIMEOUT = 1e4;
|
|
4
|
-
export declare const AIRPLAY_SERVICE = "_airplay._tcp.local";
|
|
5
|
-
export declare const COMPANION_LINK_SERVICE = "_companion-link._tcp.local";
|
|
6
|
-
export declare const RAOP_SERVICE = "_raop._tcp.local";
|
package/dist/context.d.ts
DELETED
package/dist/discovery.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { DiscoveryResult } from "node-dns-sd";
|
|
2
|
-
export declare class Discovery {
|
|
3
|
-
#private;
|
|
4
|
-
constructor(service: string);
|
|
5
|
-
find(): Promise<DiscoveryResult[]>;
|
|
6
|
-
findUntil(id: string, tries?: number, timeout?: number): Promise<DiscoveryResult>;
|
|
7
|
-
static airplay(): Discovery;
|
|
8
|
-
static companionLink(): Discovery;
|
|
9
|
-
static raop(): Discovery;
|
|
10
|
-
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export { v4 as uuid } from "uuid";
|
|
2
|
-
export { Discovery } from "./discovery";
|
|
3
|
-
export { prompt, waitFor } from "./cli";
|
|
4
|
-
export { Connection, EncryptionAwareConnection, EncryptionState } from "./connection";
|
|
5
|
-
export { Context } from "./context";
|
|
6
|
-
export { AIRPLAY_SERVICE, AIRPLAY_TRANSIENT_PIN, COMPANION_LINK_SERVICE, HTTP_TIMEOUT, RAOP_SERVICE } from "./const";
|
|
7
|
-
export { type AccessoryCredentials, type AccessoryKeys, AccessoryPair, AccessoryVerify } from "./pairing";
|
|
8
|
-
export { type Logger, type Reporter, reporter } from "./reporter";
|
|
9
|
-
export { ENCRYPTION } from "./symbols";
|
|
10
|
-
export { TimingServer } from "./timing";
|
|
11
|
-
export { getLocalIP, getMacAddress, randomInt32, randomInt64, uint16ToBE, uint53ToLE } from "./utils";
|
|
12
|
-
export type { AudioSource } from "./audioSource";
|
|
13
|
-
export type { ConnectionState, DiscoveryResult, EventMap } from "./types";
|