@basmilius/apple-common 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.d.ts CHANGED
@@ -2,19 +2,3 @@ import { type Interface } from "node:readline";
2
2
  export declare const cli: Interface;
3
3
  export declare function prompt(message: string): Promise<string>;
4
4
  export declare function waitFor(ms: number): Promise<void>;
5
- declare class Reporter {
6
- #private;
7
- all(): void;
8
- disable(group: DebugGroup): void;
9
- enable(group: DebugGroup): void;
10
- isEnabled(group: DebugGroup): boolean;
11
- debug(...data: any[]): void;
12
- error(...data: any[]): void;
13
- info(...data: any[]): void;
14
- net(...data: any[]): void;
15
- raw(...data: any[]): void;
16
- warn(...data: any[]): void;
17
- }
18
- export declare const reporter: Reporter;
19
- type DebugGroup = "debug" | "error" | "info" | "net" | "raw" | "warn";
20
- export {};
@@ -1,4 +1,5 @@
1
1
  import { EventEmitter } from "node:events";
2
+ import type { Context } from "./context";
2
3
  import type { ConnectionState, EventMap } from "./types";
3
4
  type ConnectionEventMap = {
4
5
  close: [hadError: boolean];
@@ -11,10 +12,11 @@ type ConnectionEventMap = {
11
12
  export declare class Connection<TEventMap extends EventMap> extends EventEmitter<ConnectionEventMap | TEventMap> {
12
13
  #private;
13
14
  get address(): string;
15
+ get context(): Context;
14
16
  get port(): number;
15
17
  get isConnected(): boolean;
16
18
  get state(): ConnectionState;
17
- constructor(address: string, port: number);
19
+ constructor(context: Context, address: string, port: number);
18
20
  connect(): Promise<void>;
19
21
  destroy(): Promise<void>;
20
22
  disconnect(): Promise<void>;
@@ -24,7 +26,7 @@ export declare class Connection<TEventMap extends EventMap> extends EventEmitter
24
26
  }
25
27
  export declare class EncryptionAwareConnection<TEventMap extends EventMap> extends Connection<TEventMap> {
26
28
  get isEncrypted(): boolean;
27
- enableEncryption(readKey: Buffer, writeKey: Buffer): Promise<void>;
29
+ enableEncryption(readKey: Buffer, writeKey: Buffer): void;
28
30
  }
29
31
  export declare class EncryptionState {
30
32
  readKey: Buffer;
@@ -0,0 +1,7 @@
1
+ import { Logger } from "./reporter";
2
+ export declare class Context {
3
+ #private;
4
+ get deviceId(): string;
5
+ get logger(): Logger;
6
+ constructor(deviceId: string);
7
+ }
package/dist/index.d.ts CHANGED
@@ -1,10 +1,14 @@
1
1
  export { v4 as uuid } from "uuid";
2
2
  export { Chacha20, Curve25519, hkdf } from "./crypto";
3
3
  export { type DiscoveryResult, Discovery } from "./discovery";
4
- export { getLocalIP, getMacAddress, TimingServer } from "./net";
5
- export { prompt, waitFor, cli, reporter } from "./cli";
4
+ export { getLocalIP, getMacAddress } from "./net";
5
+ export { prompt, waitFor, cli } from "./cli";
6
6
  export { Connection, EncryptionAwareConnection, EncryptionState } from "./connection";
7
+ export { Context } from "./context";
7
8
  export { AIRPLAY_SERVICE, AIRPLAY_TRANSIENT_PIN, COMPANION_LINK_SERVICE, HTTP_TIMEOUT, RAOP_SERVICE } from "./const";
8
9
  export { type AccessoryCredentials, type AccessoryKeys, AccessoryPair, AccessoryVerify } from "./pairing";
10
+ export { type Logger, type Reporter, reporter } from "./reporter";
9
11
  export { ENCRYPTION } from "./symbols";
10
- export { uint16ToBE, uint53ToLE } from "./utils";
12
+ export { TimingServer } from "./timing";
13
+ export { randomInt32, randomInt64, uint16ToBE, uint53ToLE } from "./utils";
14
+ export type { ConnectionState, EventMap } from "./types";
package/dist/index.js CHANGED
@@ -821,45 +821,6 @@ async function waitFor(ms) {
821
821
  return new Promise((resolve) => setTimeout(resolve, ms));
822
822
  }
823
823
 
824
- class Reporter {
825
- #enabled = [];
826
- all() {
827
- this.#enabled = ["debug", "error", "info", "net", "raw", "warn"];
828
- }
829
- disable(group) {
830
- if (this.#enabled.includes(group)) {
831
- this.#enabled.splice(this.#enabled.indexOf(group), 1);
832
- }
833
- }
834
- enable(group) {
835
- if (!this.#enabled.includes(group)) {
836
- this.#enabled.push(group);
837
- }
838
- }
839
- isEnabled(group) {
840
- return this.#enabled.includes(group);
841
- }
842
- debug(...data) {
843
- this.isEnabled("debug") && console.debug(`\x1B[36m[debug]\x1B[39m`, ...data);
844
- }
845
- error(...data) {
846
- this.isEnabled("error") && console.error(`\x1B[31m[error]\x1B[39m`, ...data);
847
- }
848
- info(...data) {
849
- this.isEnabled("info") && console.info(`\x1B[32m[info]\x1B[39m`, ...data);
850
- }
851
- net(...data) {
852
- this.isEnabled("net") && console.info(`\x1B[33m[net]\x1B[39m`, ...data);
853
- }
854
- raw(...data) {
855
- this.isEnabled("raw") && console.log(`\x1B[34m[raw]\x1B[39m`, ...data);
856
- }
857
- warn(...data) {
858
- this.isEnabled("warn") && console.warn(`\x1B[33m[warn]\x1B[39m`, ...data);
859
- }
860
- }
861
- var reporter = new Reporter;
862
-
863
824
  // src/const.ts
864
825
  var AIRPLAY_TRANSIENT_PIN = "3939";
865
826
  var HTTP_TIMEOUT = 6000;
@@ -947,64 +908,9 @@ function getMacAddress_default() {
947
908
  }
948
909
  return "00:00:00:00:00:00";
949
910
  }
950
- // src/net/timing.ts
951
- import { createSocket } from "node:dgram";
952
- import { NTP } from "@basmilius/apple-encoding";
953
- class timing_default {
954
- get port() {
955
- return this.#port;
956
- }
957
- #socket;
958
- #port = 0;
959
- constructor() {
960
- this.#socket = createSocket("udp4");
961
- this.#socket.on("error", (err) => this.#onError(err));
962
- this.#socket.on("message", (data, info) => this.#onMessage(data, info));
963
- }
964
- async close() {
965
- this.#socket.close();
966
- this.#port = 0;
967
- }
968
- async listen() {
969
- return new Promise((resolve) => {
970
- this.#socket.once("listening", () => this.#onListening());
971
- this.#socket.bind(0, resolve);
972
- });
973
- }
974
- async#onError(err) {
975
- reporter.error("Timing server error", err);
976
- }
977
- async#onListening() {
978
- const { port } = this.#socket.address();
979
- this.#port = port;
980
- }
981
- async#onMessage(data, info) {
982
- try {
983
- const request = NTP.decode(data);
984
- const ntp = NTP.now();
985
- const [receivedSeconds, receivedFraction] = NTP.parts(ntp);
986
- reporter.info(`Timing server ntp=${ntp} receivedSeconds=${receivedSeconds} receivedFraction=${receivedFraction}`);
987
- const response = NTP.encode({
988
- proto: request.proto,
989
- type: 83 | 128,
990
- seqno: request.seqno,
991
- padding: 0,
992
- reftime_sec: request.sendtime_sec,
993
- reftime_frac: request.sendtime_frac,
994
- recvtime_sec: receivedSeconds,
995
- recvtime_frac: receivedFraction,
996
- sendtime_sec: receivedSeconds,
997
- sendtime_frac: receivedFraction
998
- });
999
- this.#socket.send(response, info.port, info.address);
1000
- } catch (err) {
1001
- reporter.warn(`Timing server received malformed packet (${data.length} bytes) from ${info.address}:${info.port}`, err);
1002
- }
1003
- }
1004
- }
1005
911
  // src/connection.ts
1006
912
  import { EventEmitter } from "node:events";
1007
- import { Socket as Socket2 } from "node:net";
913
+ import { Socket } from "node:net";
1008
914
 
1009
915
  // src/symbols.ts
1010
916
  var ENCRYPTION = Symbol();
@@ -1019,6 +925,9 @@ class Connection extends EventEmitter {
1019
925
  get address() {
1020
926
  return this.#address;
1021
927
  }
928
+ get context() {
929
+ return this.#context;
930
+ }
1022
931
  get port() {
1023
932
  return this.#port;
1024
933
  }
@@ -1044,6 +953,7 @@ class Connection extends EventEmitter {
1044
953
  #address;
1045
954
  #port;
1046
955
  #bindings;
956
+ #context;
1047
957
  #debug = false;
1048
958
  #retryAttempt = 0;
1049
959
  #retryAttempts = 3;
@@ -1053,10 +963,11 @@ class Connection extends EventEmitter {
1053
963
  #socket;
1054
964
  #state;
1055
965
  #connectPromise;
1056
- constructor(address, port) {
966
+ constructor(context, address, port) {
1057
967
  super();
1058
968
  this.#address = address;
1059
969
  this.#port = port;
970
+ this.#context = context;
1060
971
  this.#bindings = {
1061
972
  onClose: this.#onClose.bind(this),
1062
973
  onConnect: this.#onConnect.bind(this),
@@ -1121,7 +1032,7 @@ class Connection extends EventEmitter {
1121
1032
  return new Promise((resolve, reject) => {
1122
1033
  this.#state = "connecting";
1123
1034
  this.#connectPromise = { resolve, reject };
1124
- this.#socket = new Socket2;
1035
+ this.#socket = new Socket;
1125
1036
  this.#socket.setTimeout(SOCKET_TIMEOUT);
1126
1037
  this.#socket.on("close", this.#bindings.onClose);
1127
1038
  this.#socket.on("connect", this.#bindings.onConnect);
@@ -1129,7 +1040,7 @@ class Connection extends EventEmitter {
1129
1040
  this.#socket.on("end", this.#bindings.onEnd);
1130
1041
  this.#socket.on("error", this.#bindings.onError);
1131
1042
  this.#socket.on("timeout", this.#bindings.onTimeout);
1132
- reporter.net(`Connecting to ${this.#address}:${this.#port}...`);
1043
+ this.#context.logger.net(`Connecting to ${this.#address}:${this.#port}...`);
1133
1044
  this.#socket.connect({
1134
1045
  host: this.#address,
1135
1046
  port: this.#port,
@@ -1158,7 +1069,7 @@ class Connection extends EventEmitter {
1158
1069
  return;
1159
1070
  }
1160
1071
  this.#retryAttempt++;
1161
- reporter.net(`Retry attempt ${this.#retryAttempt} / ${this.#retryAttempts} in ${this.#retryInterval}ms...`);
1072
+ this.#context.logger.net(`Retry attempt ${this.#retryAttempt} / ${this.#retryAttempts} in ${this.#retryInterval}ms...`);
1162
1073
  const { resolve, reject } = this.#connectPromise ?? NOOP_PROMISE_HANDLER;
1163
1074
  this.#cleanup();
1164
1075
  this.#retryTimeout = setTimeout(async () => {
@@ -1174,7 +1085,7 @@ class Connection extends EventEmitter {
1174
1085
  const wasConnected = this.#state === "connected";
1175
1086
  if (this.#state !== "closing") {
1176
1087
  this.#state = "disconnected";
1177
- reporter.net(`Connection closed (${hadError ? "with error" : "normally"}).`);
1088
+ this.#context.logger.net(`Connection closed (${hadError ? "with error" : "normally"}).`);
1178
1089
  }
1179
1090
  this.emit("close", hadError);
1180
1091
  if (wasConnected && this.#retryEnabled && hadError) {
@@ -1193,9 +1104,9 @@ class Connection extends EventEmitter {
1193
1104
  #onData(data) {
1194
1105
  if (this.#debug) {
1195
1106
  const cutoff = Math.min(data.byteLength, 64);
1196
- reporter.debug(`Received ${data.byteLength} bytes of data.`);
1197
- reporter.debug(`hex=${data.subarray(0, cutoff).toString("hex")}`);
1198
- reporter.debug(`ascii=${data.toString("ascii").replace(/[^\x20-\x7E]/g, ".").substring(0, cutoff)}`);
1107
+ this.#context.logger.debug(`Received ${data.byteLength} bytes of data.`);
1108
+ this.#context.logger.debug(`hex=${data.subarray(0, cutoff).toString("hex")}`);
1109
+ this.#context.logger.debug(`ascii=${data.toString("ascii").replace(/[^\x20-\x7E]/g, ".").substring(0, cutoff)}`);
1199
1110
  }
1200
1111
  this.emit("data", data);
1201
1112
  }
@@ -1203,11 +1114,11 @@ class Connection extends EventEmitter {
1203
1114
  this.emit("end");
1204
1115
  }
1205
1116
  #onError(err) {
1206
- reporter.error(`Connection error: ${err.message}`);
1117
+ this.#context.logger.error(`Connection error: ${err.message}`);
1207
1118
  if (this.listenerCount("error") > 0) {
1208
1119
  this.emit("error", err);
1209
1120
  } else {
1210
- reporter.warn("No error handler registered. This is likely a bug.", this.constructor.name, "#onError");
1121
+ this.#context.logger.warn("No error handler registered. This is likely a bug.", this.constructor.name, "#onError");
1211
1122
  }
1212
1123
  if (this.#state === "connecting") {
1213
1124
  this.#scheduleRetry(err);
@@ -1216,7 +1127,7 @@ class Connection extends EventEmitter {
1216
1127
  }
1217
1128
  }
1218
1129
  #onTimeout() {
1219
- reporter.error("Connection timed out.");
1130
+ this.#context.logger.error("Connection timed out.");
1220
1131
  const err = new Error("Connection timed out.");
1221
1132
  this.emit("timeout");
1222
1133
  if (this.#state === "connecting") {
@@ -1233,7 +1144,7 @@ class EncryptionAwareConnection extends Connection {
1233
1144
  return !!this[ENCRYPTION];
1234
1145
  }
1235
1146
  [ENCRYPTION];
1236
- async enableEncryption(readKey, writeKey) {
1147
+ enableEncryption(readKey, writeKey) {
1237
1148
  this[ENCRYPTION] = new EncryptionState(readKey, writeKey);
1238
1149
  }
1239
1150
  }
@@ -1250,20 +1161,119 @@ class EncryptionState {
1250
1161
  this.writeKey = writeKey;
1251
1162
  }
1252
1163
  }
1164
+ // src/reporter.ts
1165
+ class Logger {
1166
+ #id;
1167
+ constructor(id) {
1168
+ this.#id = id;
1169
+ }
1170
+ debug(...data) {
1171
+ debug(`\x1B[36m[${this.#id}]\x1B[39m`, ...data);
1172
+ }
1173
+ error(...data) {
1174
+ error(`\x1B[36m[${this.#id}]\x1B[39m`, ...data);
1175
+ }
1176
+ info(...data) {
1177
+ info(`\x1B[36m[${this.#id}]\x1B[39m`, ...data);
1178
+ }
1179
+ net(...data) {
1180
+ net(`\x1B[36m[${this.#id}]\x1B[39m`, ...data);
1181
+ }
1182
+ raw(...data) {
1183
+ raw(`\x1B[36m[${this.#id}]\x1B[39m`, ...data);
1184
+ }
1185
+ warn(...data) {
1186
+ warn(`\x1B[36m[${this.#id}]\x1B[39m`, ...data);
1187
+ }
1188
+ }
1189
+
1190
+ class Reporter {
1191
+ #enabled = [];
1192
+ all() {
1193
+ this.#enabled = ["debug", "error", "info", "net", "raw", "warn"];
1194
+ }
1195
+ disable(group) {
1196
+ if (this.#enabled.includes(group)) {
1197
+ this.#enabled.splice(this.#enabled.indexOf(group), 1);
1198
+ }
1199
+ }
1200
+ enable(group) {
1201
+ if (!this.#enabled.includes(group)) {
1202
+ this.#enabled.push(group);
1203
+ }
1204
+ }
1205
+ isEnabled(group) {
1206
+ return this.#enabled.includes(group);
1207
+ }
1208
+ }
1209
+ function debug(...data) {
1210
+ reporter.isEnabled("debug") && console.debug(`\x1B[36m[debug]\x1B[39m`, ...data);
1211
+ }
1212
+ function error(...data) {
1213
+ reporter.isEnabled("error") && console.error(`\x1B[31m[error]\x1B[39m`, ...data);
1214
+ }
1215
+ function info(...data) {
1216
+ reporter.isEnabled("info") && console.info(`\x1B[32m[info]\x1B[39m`, ...data);
1217
+ }
1218
+ function net(...data) {
1219
+ reporter.isEnabled("net") && console.info(`\x1B[33m[net]\x1B[39m`, ...data);
1220
+ }
1221
+ function raw(...data) {
1222
+ reporter.isEnabled("raw") && console.log(`\x1B[34m[raw]\x1B[39m`, ...data);
1223
+ }
1224
+ function warn(...data) {
1225
+ reporter.isEnabled("warn") && console.warn(`\x1B[33m[warn]\x1B[39m`, ...data);
1226
+ }
1227
+ var reporter = new Reporter;
1228
+
1229
+ // src/context.ts
1230
+ class Context {
1231
+ get deviceId() {
1232
+ return this.#deviceId;
1233
+ }
1234
+ get logger() {
1235
+ return this.#logger;
1236
+ }
1237
+ #deviceId;
1238
+ #logger;
1239
+ constructor(deviceId) {
1240
+ this.#deviceId = deviceId;
1241
+ this.#logger = new Logger(deviceId);
1242
+ }
1243
+ }
1253
1244
  // src/pairing.ts
1254
1245
  import { OPack, TLV8 } from "@basmilius/apple-encoding";
1255
1246
  import { SRP, SrpClient } from "fast-srp-hap";
1256
1247
  import { v4 as uuid } from "uuid";
1257
1248
  import tweetnacl2 from "tweetnacl";
1258
1249
 
1259
- class AccessoryPair {
1250
+ class BasePairing {
1251
+ get context() {
1252
+ return this.#context;
1253
+ }
1254
+ #context;
1255
+ constructor(context) {
1256
+ this.#context = context;
1257
+ }
1258
+ tlv(buffer) {
1259
+ const data = TLV8.decode(buffer);
1260
+ if (data.has(TLV8.Value.Error)) {
1261
+ TLV8.bail(data);
1262
+ }
1263
+ this.#context.logger.raw("Decoded TLV", data);
1264
+ return data;
1265
+ }
1266
+ }
1267
+
1268
+ class AccessoryPair extends BasePairing {
1260
1269
  #name;
1261
1270
  #pairingId;
1262
1271
  #requestHandler;
1263
1272
  #publicKey;
1264
1273
  #secretKey;
1265
1274
  #srp;
1266
- constructor(requestHandler) {
1275
+ constructor(context, requestHandler) {
1276
+ super(context);
1267
1277
  this.#name = "basmilius/apple-protocols";
1268
1278
  this.#pairingId = Buffer.from(uuid().toUpperCase());
1269
1279
  this.#requestHandler = requestHandler;
@@ -1317,7 +1327,7 @@ class AccessoryPair {
1317
1327
  [TLV8.Value.State, TLV8.State.M1],
1318
1328
  ...additionalTlv
1319
1329
  ]));
1320
- const data = tlv(response);
1330
+ const data = this.tlv(response);
1321
1331
  const publicKey = data.get(TLV8.Value.PublicKey);
1322
1332
  const salt = data.get(TLV8.Value.Salt);
1323
1333
  return { publicKey, salt };
@@ -1336,7 +1346,7 @@ class AccessoryPair {
1336
1346
  [TLV8.Value.PublicKey, m2.publicKey],
1337
1347
  [TLV8.Value.Proof, m2.proof]
1338
1348
  ]));
1339
- const data = tlv(response);
1349
+ const data = this.tlv(response);
1340
1350
  const serverProof = data.get(TLV8.Value.Proof);
1341
1351
  return { serverProof };
1342
1352
  }
@@ -1380,7 +1390,7 @@ class AccessoryPair {
1380
1390
  [TLV8.Value.State, TLV8.State.M5],
1381
1391
  [TLV8.Value.EncryptedData, encrypted]
1382
1392
  ]));
1383
- const data = tlv(response);
1393
+ const data = this.tlv(response);
1384
1394
  const encryptedDataRaw = data.get(TLV8.Value.EncryptedData);
1385
1395
  const encryptedData = encryptedDataRaw.subarray(0, -16);
1386
1396
  const encryptedTag = encryptedDataRaw.subarray(-16);
@@ -1421,10 +1431,11 @@ class AccessoryPair {
1421
1431
  }
1422
1432
  }
1423
1433
 
1424
- class AccessoryVerify {
1434
+ class AccessoryVerify extends BasePairing {
1425
1435
  #ephemeralKeyPair;
1426
1436
  #requestHandler;
1427
- constructor(requestHandler) {
1437
+ constructor(context, requestHandler) {
1438
+ super(context);
1428
1439
  this.#ephemeralKeyPair = exports_curve25519.generateKeyPair();
1429
1440
  this.#requestHandler = requestHandler;
1430
1441
  }
@@ -1439,7 +1450,7 @@ class AccessoryVerify {
1439
1450
  [TLV8.Value.State, TLV8.State.M1],
1440
1451
  [TLV8.Value.PublicKey, Buffer.from(this.#ephemeralKeyPair.publicKey)]
1441
1452
  ]));
1442
- const data = tlv(response);
1453
+ const data = this.tlv(response);
1443
1454
  const serverPublicKey = data.get(TLV8.Value.PublicKey);
1444
1455
  const encryptedData = data.get(TLV8.Value.EncryptedData);
1445
1456
  return {
@@ -1507,15 +1518,71 @@ class AccessoryVerify {
1507
1518
  };
1508
1519
  }
1509
1520
  }
1510
- function tlv(buffer) {
1511
- const data = TLV8.decode(buffer);
1512
- if (data.has(TLV8.Value.Error)) {
1513
- TLV8.bail(data);
1521
+ // src/timing.ts
1522
+ import { createSocket } from "node:dgram";
1523
+ import { NTP } from "@basmilius/apple-encoding";
1524
+ class TimingServer {
1525
+ get port() {
1526
+ return this.#port;
1527
+ }
1528
+ #logger;
1529
+ #socket;
1530
+ #port = 0;
1531
+ constructor() {
1532
+ this.#logger = new Logger("timing-server");
1533
+ this.#socket = createSocket("udp4");
1534
+ this.#socket.on("error", (err) => this.#onError(err));
1535
+ this.#socket.on("message", (data, info2) => this.#onMessage(data, info2));
1536
+ }
1537
+ async close() {
1538
+ this.#socket.close();
1539
+ this.#port = 0;
1540
+ }
1541
+ async listen() {
1542
+ return new Promise((resolve) => {
1543
+ this.#socket.once("listening", () => this.#onListening());
1544
+ this.#socket.bind(0, resolve);
1545
+ });
1546
+ }
1547
+ async#onError(err) {
1548
+ this.#logger.error("Timing server error", err);
1549
+ }
1550
+ async#onListening() {
1551
+ const { port } = this.#socket.address();
1552
+ this.#port = port;
1553
+ }
1554
+ async#onMessage(data, info2) {
1555
+ try {
1556
+ const request = NTP.decode(data);
1557
+ const ntp = NTP.now();
1558
+ const [receivedSeconds, receivedFraction] = NTP.parts(ntp);
1559
+ this.#logger.info(`Timing server ntp=${ntp} receivedSeconds=${receivedSeconds} receivedFraction=${receivedFraction}`);
1560
+ const response = NTP.encode({
1561
+ proto: request.proto,
1562
+ type: 83 | 128,
1563
+ seqno: request.seqno,
1564
+ padding: 0,
1565
+ reftime_sec: request.sendtime_sec,
1566
+ reftime_frac: request.sendtime_frac,
1567
+ recvtime_sec: receivedSeconds,
1568
+ recvtime_frac: receivedFraction,
1569
+ sendtime_sec: receivedSeconds,
1570
+ sendtime_frac: receivedFraction
1571
+ });
1572
+ this.#socket.send(response, info2.port, info2.address);
1573
+ } catch (err) {
1574
+ this.#logger.warn(`Timing server received malformed packet (${data.length} bytes) from ${info2.address}:${info2.port}`, err);
1575
+ }
1514
1576
  }
1515
- reporter.raw("Decoded TLV", data);
1516
- return data;
1517
1577
  }
1518
1578
  // src/utils.ts
1579
+ import { randomBytes } from "node:crypto";
1580
+ function randomInt32() {
1581
+ return randomBytes(4).readUInt32BE(0);
1582
+ }
1583
+ function randomInt64() {
1584
+ return randomBytes(8).readBigUint64LE(0);
1585
+ }
1519
1586
  function uint16ToBE(value) {
1520
1587
  const buffer = Buffer.alloc(2);
1521
1588
  buffer.writeUInt16BE(value, 0);
@@ -1551,12 +1618,14 @@ export {
1551
1618
  uint53ToLE,
1552
1619
  uint16ToBE,
1553
1620
  reporter,
1621
+ randomInt64,
1622
+ randomInt32,
1554
1623
  prompt,
1555
1624
  hkdf_default as hkdf,
1556
1625
  getMacAddress_default as getMacAddress,
1557
1626
  getLocalIP_default as getLocalIP,
1558
1627
  cli,
1559
- timing_default as TimingServer,
1628
+ TimingServer,
1560
1629
  RAOP_SERVICE,
1561
1630
  HTTP_TIMEOUT,
1562
1631
  EncryptionState,
@@ -1564,6 +1633,7 @@ export {
1564
1633
  ENCRYPTION,
1565
1634
  Discovery,
1566
1635
  exports_curve25519 as Curve25519,
1636
+ Context,
1567
1637
  Connection,
1568
1638
  exports_chacha20 as Chacha20,
1569
1639
  COMPANION_LINK_SERVICE,
@@ -1,3 +1,2 @@
1
1
  export { default as getLocalIP } from "./getLocalIP";
2
2
  export { default as getMacAddress } from "./getMacAddress";
3
- export { default as TimingServer } from "./timing";
package/dist/pairing.d.ts CHANGED
@@ -1,6 +1,13 @@
1
- export declare class AccessoryPair {
1
+ import type { Context } from "./context";
2
+ declare abstract class BasePairing {
2
3
  #private;
3
- constructor(requestHandler: RequestHandler);
4
+ get context(): Context;
5
+ constructor(context: Context);
6
+ tlv(buffer: Buffer): Map<number, Buffer>;
7
+ }
8
+ export declare class AccessoryPair extends BasePairing {
9
+ #private;
10
+ constructor(context: Context, requestHandler: RequestHandler);
4
11
  start(): Promise<void>;
5
12
  pin(askPin: () => Promise<string>): Promise<AccessoryCredentials>;
6
13
  transient(): Promise<AccessoryKeys>;
@@ -11,9 +18,9 @@ export declare class AccessoryPair {
11
18
  m5(m4: PairM4): Promise<PairM5>;
12
19
  m6(m4: PairM4, m5: PairM5): Promise<AccessoryCredentials>;
13
20
  }
14
- export declare class AccessoryVerify {
21
+ export declare class AccessoryVerify extends BasePairing {
15
22
  #private;
16
- constructor(requestHandler: RequestHandler);
23
+ constructor(context: Context, requestHandler: RequestHandler);
17
24
  start(credentials: AccessoryCredentials): Promise<AccessoryKeys>;
18
25
  }
19
26
  type RequestHandler = (step: "m1" | "m3" | "m5", data: Buffer) => Promise<Buffer>;
@@ -0,0 +1,20 @@
1
+ type DebugGroup = "debug" | "error" | "info" | "net" | "raw" | "warn";
2
+ export declare class Logger {
3
+ #private;
4
+ constructor(id: string);
5
+ debug(...data: any[]): void;
6
+ error(...data: any[]): void;
7
+ info(...data: any[]): void;
8
+ net(...data: any[]): void;
9
+ raw(...data: any[]): void;
10
+ warn(...data: any[]): void;
11
+ }
12
+ export declare class Reporter {
13
+ #private;
14
+ all(): void;
15
+ disable(group: DebugGroup): void;
16
+ enable(group: DebugGroup): void;
17
+ isEnabled(group: DebugGroup): boolean;
18
+ }
19
+ export declare const reporter: Reporter;
20
+ export {};
@@ -1,4 +1,4 @@
1
- export default class {
1
+ export declare class TimingServer {
2
2
  #private;
3
3
  get port(): number;
4
4
  constructor();
package/dist/utils.d.ts CHANGED
@@ -1,2 +1,4 @@
1
+ export declare function randomInt32(): number;
2
+ export declare function randomInt64(): bigint;
1
3
  export declare function uint16ToBE(value: number): Buffer;
2
4
  export declare function uint53ToLE(value: number): Buffer;
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.1.3",
4
+ "version": "0.2.0",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": {
@@ -38,7 +38,7 @@
38
38
  }
39
39
  },
40
40
  "dependencies": {
41
- "@basmilius/apple-encoding": "0.1.3",
41
+ "@basmilius/apple-encoding": "0.2.0",
42
42
  "@stablelib/chacha20poly1305": "^2.0.1",
43
43
  "fast-srp-hap": "^2.0.4",
44
44
  "node-dns-sd": "^1.0.1",