@layervai/qurl 0.3.1 → 0.4.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/README.md +187 -7
- package/dist/cjs/client.d.ts +17 -10
- package/dist/cjs/client.js +649 -96
- package/dist/cjs/errors.d.ts +11 -11
- package/dist/cjs/errors.js +25 -20
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/internal.d.ts +4 -0
- package/dist/cjs/internal.js +16 -0
- package/dist/cjs/node/deployment.d.ts +44 -0
- package/dist/cjs/node/deployment.js +167 -0
- package/dist/cjs/node/native-udp.d.ts +37 -0
- package/dist/cjs/node/native-udp.js +294 -0
- package/dist/cjs/node/nhp-wire.d.ts +35 -0
- package/dist/cjs/node/nhp-wire.js +261 -0
- package/dist/cjs/node/portal-opener.d.ts +83 -0
- package/dist/cjs/node/portal-opener.js +767 -0
- package/dist/cjs/node/qv2.d.ts +38 -0
- package/dist/cjs/node/qv2.js +292 -0
- package/dist/cjs/node/strict-json.d.ts +12 -0
- package/dist/cjs/node/strict-json.js +174 -0
- package/dist/cjs/node.d.ts +3 -0
- package/dist/cjs/node.js +11 -0
- package/dist/cjs/types.d.ts +7 -18
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/client.d.ts +17 -10
- package/dist/esm/client.d.ts.map +1 -1
- package/dist/esm/client.js +647 -94
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/errors.d.ts +11 -11
- package/dist/esm/errors.d.ts.map +1 -1
- package/dist/esm/errors.js +25 -20
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/internal.d.ts +5 -0
- package/dist/esm/internal.d.ts.map +1 -0
- package/dist/esm/internal.js +14 -0
- package/dist/esm/internal.js.map +1 -0
- package/dist/esm/node/deployment.d.ts +45 -0
- package/dist/esm/node/deployment.d.ts.map +1 -0
- package/dist/esm/node/deployment.js +163 -0
- package/dist/esm/node/deployment.js.map +1 -0
- package/dist/esm/node/native-udp.d.ts +38 -0
- package/dist/esm/node/native-udp.d.ts.map +1 -0
- package/dist/esm/node/native-udp.js +291 -0
- package/dist/esm/node/native-udp.js.map +1 -0
- package/dist/esm/node/nhp-wire.d.ts +36 -0
- package/dist/esm/node/nhp-wire.d.ts.map +1 -0
- package/dist/esm/node/nhp-wire.js +257 -0
- package/dist/esm/node/nhp-wire.js.map +1 -0
- package/dist/esm/node/portal-opener.d.ts +84 -0
- package/dist/esm/node/portal-opener.d.ts.map +1 -0
- package/dist/esm/node/portal-opener.js +757 -0
- package/dist/esm/node/portal-opener.js.map +1 -0
- package/dist/esm/node/qv2.d.ts +39 -0
- package/dist/esm/node/qv2.d.ts.map +1 -0
- package/dist/esm/node/qv2.js +286 -0
- package/dist/esm/node/qv2.js.map +1 -0
- package/dist/esm/node/strict-json.d.ts +13 -0
- package/dist/esm/node/strict-json.d.ts.map +1 -0
- package/dist/esm/node/strict-json.js +171 -0
- package/dist/esm/node/strict-json.js.map +1 -0
- package/dist/esm/node.d.ts +4 -0
- package/dist/esm/node.d.ts.map +1 -0
- package/dist/esm/node.js +2 -0
- package/dist/esm/node.js.map +1 -0
- package/dist/esm/types.d.ts +7 -18
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +25 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.js","sourceRoot":"","sources":["../../src/internal.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,gFAAgF;AAChF,mBAAmB;AAEnB;;sEAEsE;AACtE,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,IAAI,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC;IACrB,OAAO,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,CAAC;QAC3D,GAAG,EAAE,CAAC;IACR,CAAC;IACD,OAAO,GAAG,KAAK,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { KeyObject } from "node:crypto";
|
|
2
|
+
import { type StrictJsonValue } from "./strict-json.js";
|
|
3
|
+
export interface PortalDeployment {
|
|
4
|
+
readonly issuers: readonly PortalDeploymentIssuer[];
|
|
5
|
+
readonly cells: readonly PortalDeploymentCell[];
|
|
6
|
+
}
|
|
7
|
+
export interface PortalDeploymentIssuer {
|
|
8
|
+
readonly kid: string;
|
|
9
|
+
readonly spki_der_b64: string;
|
|
10
|
+
}
|
|
11
|
+
export interface PortalDeploymentCell {
|
|
12
|
+
readonly cell_id?: string;
|
|
13
|
+
readonly host: string;
|
|
14
|
+
readonly port: number;
|
|
15
|
+
readonly server_public_key_b64: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ValidatedDeployment {
|
|
18
|
+
readonly issuers: ReadonlyMap<string, KeyObject>;
|
|
19
|
+
readonly cells: ReadonlyMap<string, ValidatedCell>;
|
|
20
|
+
}
|
|
21
|
+
export interface ValidatedCell {
|
|
22
|
+
readonly host: string;
|
|
23
|
+
readonly port: 443;
|
|
24
|
+
readonly serverPublicKey: Uint8Array;
|
|
25
|
+
}
|
|
26
|
+
interface DeploymentFileRuntime {
|
|
27
|
+
readonly open: (path: string, flags: number) => number;
|
|
28
|
+
readonly stat: (descriptor: number) => {
|
|
29
|
+
readonly size: number;
|
|
30
|
+
isFile(): boolean;
|
|
31
|
+
};
|
|
32
|
+
readonly read: (descriptor: number, buffer: Buffer, offset: number, length: number, position: number) => number;
|
|
33
|
+
readonly close: (descriptor: number) => void;
|
|
34
|
+
}
|
|
35
|
+
/** Load and validate deployment trust once, before an opener can do network I/O. */
|
|
36
|
+
export declare function loadPortalDeployment(explicit?: PortalDeployment): ValidatedDeployment;
|
|
37
|
+
declare function readBoundedDeploymentFile(path: string, runtime?: DeploymentFileRuntime): Buffer;
|
|
38
|
+
export declare function fingerprintKey(key: Uint8Array): string;
|
|
39
|
+
declare function decodeFlexibleBase64(value: StrictJsonValue | undefined, name: string): Uint8Array;
|
|
40
|
+
export declare const deploymentTesting: {
|
|
41
|
+
readBoundedDeploymentFile: typeof readBoundedDeploymentFile;
|
|
42
|
+
decodeFlexibleBase64: typeof decodeFlexibleBase64;
|
|
43
|
+
};
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=deployment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment.d.ts","sourceRoot":"","sources":["../../../src/node/deployment.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAuC,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAG7F,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS,sBAAsB,EAAE,CAAC;IACpD,QAAQ,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACjD;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC;CACxC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACjD,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CACpD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC;IACnB,QAAQ,CAAC,eAAe,EAAE,UAAU,CAAC;CACtC;AAOD,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACvD,QAAQ,CAAC,IAAI,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,IAAI,OAAO,CAAA;KAAE,CAAC;IACpF,QAAQ,CAAC,IAAI,EAAE,CACb,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,KACb,MAAM,CAAC;IACZ,QAAQ,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C;AASD,oFAAoF;AACpF,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,gBAAgB,GAAG,mBAAmB,CAWrF;AAED,iBAAS,yBAAyB,CAChC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,qBAAoD,GAC5D,MAAM,CA2BR;AAsDD,wBAAgB,cAAc,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAEtD;AAED,iBAAS,oBAAoB,CAAC,KAAK,EAAE,eAAe,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,CAgB1F;AAqCD,eAAO,MAAM,iBAAiB;;;CAAsD,CAAC"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { closeSync, constants as fsConstants, fstatSync, openSync, readSync } from "node:fs";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { isStrictJsonObject, parseStrictJson } from "./strict-json.js";
|
|
4
|
+
import { issuerKeyFromSpki } from "./qv2.js";
|
|
5
|
+
const DEPLOYMENT_KEYS = new Set(["issuers", "cells", "relay_allowlist", "hub"]);
|
|
6
|
+
const ISSUER_KEYS = new Set(["kid", "spki_der_b64"]);
|
|
7
|
+
const CELL_KEYS = new Set(["cell_id", "host", "port", "server_public_key_b64"]);
|
|
8
|
+
const MAX_DEPLOYMENT_BYTES = 1_048_576;
|
|
9
|
+
const defaultDeploymentFileRuntime = {
|
|
10
|
+
open: openSync,
|
|
11
|
+
stat: fstatSync,
|
|
12
|
+
read: readSync,
|
|
13
|
+
close: closeSync,
|
|
14
|
+
};
|
|
15
|
+
/** Load and validate deployment trust once, before an opener can do network I/O. */
|
|
16
|
+
export function loadPortalDeployment(explicit) {
|
|
17
|
+
if (explicit !== undefined)
|
|
18
|
+
return validateDeployment(explicit);
|
|
19
|
+
const configured = process.env.QURL_DEPLOYMENT;
|
|
20
|
+
if (!configured || configured.trim() === "") {
|
|
21
|
+
throw new Error("native qURL opening requires deployment trust in QURL_DEPLOYMENT");
|
|
22
|
+
}
|
|
23
|
+
const trimmed = configured.trim();
|
|
24
|
+
const raw = trimmed.startsWith("{")
|
|
25
|
+
? Buffer.from(trimmed, "utf8")
|
|
26
|
+
: readBoundedDeploymentFile(trimmed);
|
|
27
|
+
return validateDeploymentValue(parseStrictJson(raw, MAX_DEPLOYMENT_BYTES));
|
|
28
|
+
}
|
|
29
|
+
function readBoundedDeploymentFile(path, runtime = defaultDeploymentFileRuntime) {
|
|
30
|
+
// O_NONBLOCK prevents a FIFO or device path from hanging construction before
|
|
31
|
+
// fstat can enforce the regular-file contract. It has no effect on files.
|
|
32
|
+
const descriptor = runtime.open(path, fsConstants.O_RDONLY | fsConstants.O_NONBLOCK);
|
|
33
|
+
try {
|
|
34
|
+
const metadata = runtime.stat(descriptor);
|
|
35
|
+
if (!metadata.isFile())
|
|
36
|
+
throw new Error("native qURL deployment path must be a regular file");
|
|
37
|
+
if (!Number.isSafeInteger(metadata.size) || metadata.size > MAX_DEPLOYMENT_BYTES) {
|
|
38
|
+
throw new Error("native qURL deployment file exceeds its 1 MiB limit");
|
|
39
|
+
}
|
|
40
|
+
const bytes = Buffer.alloc(metadata.size);
|
|
41
|
+
let offset = 0;
|
|
42
|
+
while (offset < bytes.byteLength) {
|
|
43
|
+
const count = runtime.read(descriptor, bytes, offset, bytes.byteLength - offset, offset);
|
|
44
|
+
if (count === 0) {
|
|
45
|
+
throw new Error("native qURL deployment file changed while it was read");
|
|
46
|
+
}
|
|
47
|
+
offset += count;
|
|
48
|
+
}
|
|
49
|
+
const extra = Buffer.alloc(1);
|
|
50
|
+
if (runtime.read(descriptor, extra, 0, 1, offset) !== 0) {
|
|
51
|
+
throw new Error("native qURL deployment file changed while it was read");
|
|
52
|
+
}
|
|
53
|
+
return bytes.subarray(0, offset);
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
runtime.close(descriptor);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function validateDeployment(explicit) {
|
|
60
|
+
// Convert through JSON only to give the programmatic form the same strict,
|
|
61
|
+
// immutable validation path as the environment/file form. Deployment data is
|
|
62
|
+
// public trust material, not a secret.
|
|
63
|
+
let encoded;
|
|
64
|
+
try {
|
|
65
|
+
encoded = JSON.stringify(explicit);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
throw new Error("native qURL deployment is not JSON serializable");
|
|
69
|
+
}
|
|
70
|
+
if (encoded === undefined)
|
|
71
|
+
throw new Error("native qURL deployment is missing");
|
|
72
|
+
return validateDeploymentValue(parseStrictJson(Buffer.from(encoded, "utf8"), MAX_DEPLOYMENT_BYTES));
|
|
73
|
+
}
|
|
74
|
+
function validateDeploymentValue(value) {
|
|
75
|
+
const root = requireObject(value, "deployment");
|
|
76
|
+
rejectUnknown(root, DEPLOYMENT_KEYS, "deployment");
|
|
77
|
+
const issuerRows = requireArray(root.issuers, "deployment issuers");
|
|
78
|
+
const cellRows = requireArray(root.cells, "deployment cells");
|
|
79
|
+
if (issuerRows.length === 0)
|
|
80
|
+
throw new Error("deployment must contain at least one issuer");
|
|
81
|
+
if (cellRows.length === 0)
|
|
82
|
+
throw new Error("native-only deployment must contain at least one cell");
|
|
83
|
+
const issuers = new Map();
|
|
84
|
+
for (const row of issuerRows) {
|
|
85
|
+
const item = requireObject(row, "deployment issuer");
|
|
86
|
+
rejectUnknown(item, ISSUER_KEYS, "deployment issuer");
|
|
87
|
+
const kid = requireTrimmed(item.kid, "deployment issuer kid");
|
|
88
|
+
if (issuers.has(kid))
|
|
89
|
+
throw new Error("deployment contains a duplicate issuer kid");
|
|
90
|
+
issuers.set(kid, issuerKeyFromSpki(decodeFlexibleBase64(item.spki_der_b64, "issuer key")));
|
|
91
|
+
}
|
|
92
|
+
const cells = new Map();
|
|
93
|
+
for (const row of cellRows) {
|
|
94
|
+
const item = requireObject(row, "deployment cell");
|
|
95
|
+
rejectUnknown(item, CELL_KEYS, "deployment cell");
|
|
96
|
+
const host = requireTrimmed(item.host, "deployment cell host");
|
|
97
|
+
if (item.port !== 443n)
|
|
98
|
+
throw new Error("deployment cell must use NHP UDP port 443");
|
|
99
|
+
const serverPublicKey = decodeFlexibleBase64(item.server_public_key_b64, "cell public key");
|
|
100
|
+
if (serverPublicKey.byteLength !== 32)
|
|
101
|
+
throw new Error("cell public key must be 32 bytes");
|
|
102
|
+
const fingerprint = fingerprintKey(serverPublicKey);
|
|
103
|
+
if (cells.has(fingerprint))
|
|
104
|
+
throw new Error("deployment contains a duplicate cell public key");
|
|
105
|
+
// Validate cell_id for schema parity, but do not use it as identity. The
|
|
106
|
+
// full X25519 public key is the cryptographic cell binding.
|
|
107
|
+
if (item.cell_id !== undefined)
|
|
108
|
+
requireString(item.cell_id, "cell id");
|
|
109
|
+
cells.set(fingerprint, { host, port: 443, serverPublicKey });
|
|
110
|
+
}
|
|
111
|
+
return { issuers, cells };
|
|
112
|
+
}
|
|
113
|
+
export function fingerprintKey(key) {
|
|
114
|
+
return createHash("sha256").update(key).digest().subarray(0, 8).toString("base64url");
|
|
115
|
+
}
|
|
116
|
+
function decodeFlexibleBase64(value, name) {
|
|
117
|
+
const encoded = requireTrimmed(value, name);
|
|
118
|
+
const hasStandard = /[+/]/.test(encoded);
|
|
119
|
+
const hasUrl = /[-_]/.test(encoded);
|
|
120
|
+
if (hasStandard && hasUrl)
|
|
121
|
+
throw new Error(`${name} mixes base64 alphabets`);
|
|
122
|
+
if (!/^(?:[A-Za-z0-9+/_-]{4})*(?:[A-Za-z0-9+/_-]{2}==|[A-Za-z0-9+/_-]{3}=)?$/.test(encoded)) {
|
|
123
|
+
// Also permit the unpadded two/three-character tail used by Raw encodings.
|
|
124
|
+
if (!/^[A-Za-z0-9+/_-]+$/.test(encoded) || encoded.length % 4 === 1) {
|
|
125
|
+
throw new Error(`${name} is not valid base64`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const normalized = encoded.replace(/-/g, "+").replace(/_/g, "/").replace(/=+$/, "");
|
|
129
|
+
const decoded = Buffer.from(normalized, "base64");
|
|
130
|
+
const canonical = decoded.toString("base64").replace(/=+$/, "");
|
|
131
|
+
if (canonical !== normalized)
|
|
132
|
+
throw new Error(`${name} is not canonical base64`);
|
|
133
|
+
return new Uint8Array(decoded);
|
|
134
|
+
}
|
|
135
|
+
function requireObject(value, name) {
|
|
136
|
+
if (!isStrictJsonObject(value))
|
|
137
|
+
throw new Error(`${name} must be one JSON object`);
|
|
138
|
+
return value;
|
|
139
|
+
}
|
|
140
|
+
function requireArray(value, name) {
|
|
141
|
+
if (!Array.isArray(value))
|
|
142
|
+
throw new Error(`${name} must be an array`);
|
|
143
|
+
return value;
|
|
144
|
+
}
|
|
145
|
+
function requireString(value, name) {
|
|
146
|
+
if (typeof value !== "string")
|
|
147
|
+
throw new Error(`${name} must be a string`);
|
|
148
|
+
return value;
|
|
149
|
+
}
|
|
150
|
+
function requireTrimmed(value, name) {
|
|
151
|
+
const string = requireString(value, name);
|
|
152
|
+
if (string === "" || string.trim() !== string)
|
|
153
|
+
throw new Error(`${name} must be non-empty and trimmed`);
|
|
154
|
+
return string;
|
|
155
|
+
}
|
|
156
|
+
function rejectUnknown(value, allowed, name) {
|
|
157
|
+
for (const key of Object.keys(value)) {
|
|
158
|
+
if (!allowed.has(key))
|
|
159
|
+
throw new Error(`${name} contains an unknown field`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
export const deploymentTesting = { readBoundedDeploymentFile, decodeFlexibleBase64 };
|
|
163
|
+
//# sourceMappingURL=deployment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment.js","sourceRoot":"","sources":["../../../src/node/deployment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { lookup } from "node:dns/promises";
|
|
2
|
+
import { type Socket } from "node:dgram";
|
|
3
|
+
import { buildNHPMessage, decryptNHPReply, type NHPMessage } from "./nhp-wire.js";
|
|
4
|
+
import type { ValidatedCell } from "./deployment.js";
|
|
5
|
+
export declare const NATIVE_DEFAULT_TIMEOUT_MS = 3000;
|
|
6
|
+
export declare const NATIVE_DEFAULT_MAX_ADDRESSES = 3;
|
|
7
|
+
export interface NativeExchangeOptions {
|
|
8
|
+
readonly signal?: AbortSignal;
|
|
9
|
+
/** Per-address timeout; serial fallback can use maxAddresses times this value. */
|
|
10
|
+
readonly timeoutMs?: number;
|
|
11
|
+
/** Maximum number of resolved addresses tried serially. */
|
|
12
|
+
readonly maxAddresses?: number;
|
|
13
|
+
}
|
|
14
|
+
interface NativeKnockRuntime {
|
|
15
|
+
readonly buildMessage: typeof buildNHPMessage;
|
|
16
|
+
readonly resolveAddresses: typeof resolvePublicAddresses;
|
|
17
|
+
readonly exchange: typeof exchangeDatagram;
|
|
18
|
+
readonly decryptReply: typeof decryptNHPReply;
|
|
19
|
+
}
|
|
20
|
+
export declare function nativeKnock(cell: ValidatedCell, devicePrivateKey: Uint8Array, body: Uint8Array, options?: NativeExchangeOptions): Promise<NHPMessage>;
|
|
21
|
+
declare function nativeKnockWithRuntime(cell: ValidatedCell, devicePrivateKey: Uint8Array, body: Uint8Array, options: NativeExchangeOptions, runtime: NativeKnockRuntime): Promise<NHPMessage>;
|
|
22
|
+
declare function resolvePublicAddresses(host: string, maximum: number, signal?: AbortSignal, lookupAddresses?: typeof lookup): Promise<Array<{
|
|
23
|
+
address: string;
|
|
24
|
+
family: 4 | 6;
|
|
25
|
+
}>>;
|
|
26
|
+
declare function isPublicAddress(address: string, family: number): boolean;
|
|
27
|
+
declare function exchangeDatagram(address: string, family: 4 | 6, port: number, packet: Uint8Array, timeoutMs: number, signal?: AbortSignal): Promise<Uint8Array>;
|
|
28
|
+
declare function sendOwnedDatagram(socket: Socket, packet: Uint8Array, finish: (error: unknown) => void): void;
|
|
29
|
+
export declare const nativeUdpTesting: {
|
|
30
|
+
isPublicAddress: typeof isPublicAddress;
|
|
31
|
+
resolvePublicAddresses: typeof resolvePublicAddresses;
|
|
32
|
+
nativeKnockWithRuntime: typeof nativeKnockWithRuntime;
|
|
33
|
+
exchangeDatagram: typeof exchangeDatagram;
|
|
34
|
+
sendOwnedDatagram: typeof sendOwnedDatagram;
|
|
35
|
+
socketExchangeError: (cause: unknown) => Error;
|
|
36
|
+
};
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=native-udp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-udp.d.ts","sourceRoot":"","sources":["../../../src/node/native-udp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAEvD,OAAO,EACL,eAAe,EACf,eAAe,EAIf,KAAK,UAAU,EAChB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAIrD,eAAO,MAAM,yBAAyB,OAAQ,CAAC;AAC/C,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAmF9C,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,kFAAkF;IAClF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,2DAA2D;IAC3D,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,YAAY,EAAE,OAAO,eAAe,CAAC;IAC9C,QAAQ,CAAC,gBAAgB,EAAE,OAAO,sBAAsB,CAAC;IACzD,QAAQ,CAAC,QAAQ,EAAE,OAAO,gBAAgB,CAAC;IAC3C,QAAQ,CAAC,YAAY,EAAE,OAAO,eAAe,CAAC;CAC/C;AASD,wBAAsB,WAAW,CAC/B,IAAI,EAAE,aAAa,EACnB,gBAAgB,EAAE,UAAU,EAC5B,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,UAAU,CAAC,CAErB;AAED,iBAAe,sBAAsB,CACnC,IAAI,EAAE,aAAa,EACnB,gBAAgB,EAAE,UAAU,EAC5B,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,qBAAqB,EAC9B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,UAAU,CAAC,CA+CrB;AAED,iBAAe,sBAAsB,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,WAAW,EACpB,eAAe,GAAE,OAAO,MAAe,GACtC,OAAO,CAAC,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAA;CAAE,CAAC,CAAC,CAsBpD;AAED,iBAAS,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAIjE;AAoBD,iBAAS,gBAAgB,CACvB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,CAAC,GAAG,CAAC,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CAyCrB;AAED,iBAAS,iBAAiB,CACxB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAC/B,IAAI,CAiBN;AA2BD,eAAO,MAAM,gBAAgB;;;;;;iCAME,OAAO,KAAG,KAAK;CAC7C,CAAC"}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { lookup } from "node:dns/promises";
|
|
2
|
+
import { createSocket } from "node:dgram";
|
|
3
|
+
import { BlockList, isIP } from "node:net";
|
|
4
|
+
import { buildNHPMessage, decryptNHPReply, NHP_PACKET_SIZE, NHP_TYPE_COOKIE, NHP_TYPE_KNOCK, } from "./nhp-wire.js";
|
|
5
|
+
// Keep these defaults exported inside the Node implementation so the portal
|
|
6
|
+
// lifecycle can derive one bounded whole-open deadline from the same values.
|
|
7
|
+
export const NATIVE_DEFAULT_TIMEOUT_MS = 3_000;
|
|
8
|
+
export const NATIVE_DEFAULT_MAX_ADDRESSES = 3;
|
|
9
|
+
const ipv4Denied = new BlockList();
|
|
10
|
+
// Keep this set in lockstep with qurl-go's nonRoutablePrefixes plus the
|
|
11
|
+
// IsPrivate/IsLoopback/IsLinkLocal/IsMulticast predicates it applies first.
|
|
12
|
+
for (const [network, prefix] of [
|
|
13
|
+
["0.0.0.0", 8],
|
|
14
|
+
["10.0.0.0", 8],
|
|
15
|
+
["100.64.0.0", 10],
|
|
16
|
+
["127.0.0.0", 8],
|
|
17
|
+
["169.254.0.0", 16],
|
|
18
|
+
["172.16.0.0", 12],
|
|
19
|
+
["192.0.0.0", 24],
|
|
20
|
+
["192.0.2.0", 24],
|
|
21
|
+
["192.168.0.0", 16],
|
|
22
|
+
["192.88.99.0", 24],
|
|
23
|
+
["198.18.0.0", 15],
|
|
24
|
+
["198.51.100.0", 24],
|
|
25
|
+
["203.0.113.0", 24],
|
|
26
|
+
["224.0.0.0", 4],
|
|
27
|
+
["240.0.0.0", 4],
|
|
28
|
+
]) {
|
|
29
|
+
ipv4Denied.addSubnet(network, prefix, "ipv4");
|
|
30
|
+
}
|
|
31
|
+
const ipv6Allowed = new BlockList();
|
|
32
|
+
for (const [network, prefix] of [
|
|
33
|
+
["2001:200::", 23],
|
|
34
|
+
["2001:400::", 23],
|
|
35
|
+
["2001:600::", 23],
|
|
36
|
+
["2001:800::", 22],
|
|
37
|
+
["2001:c00::", 23],
|
|
38
|
+
["2001:e00::", 23],
|
|
39
|
+
["2001:1200::", 23],
|
|
40
|
+
["2001:1400::", 22],
|
|
41
|
+
["2001:1800::", 23],
|
|
42
|
+
["2001:1a00::", 23],
|
|
43
|
+
["2001:1c00::", 22],
|
|
44
|
+
["2001:2000::", 19],
|
|
45
|
+
["2001:4000::", 23],
|
|
46
|
+
["2001:4200::", 23],
|
|
47
|
+
["2001:4400::", 23],
|
|
48
|
+
["2001:4600::", 23],
|
|
49
|
+
["2001:4800::", 23],
|
|
50
|
+
["2001:4a00::", 23],
|
|
51
|
+
["2001:4c00::", 23],
|
|
52
|
+
["2001:5000::", 20],
|
|
53
|
+
["2001:8000::", 19],
|
|
54
|
+
["2001:a000::", 20],
|
|
55
|
+
["2001:b000::", 20],
|
|
56
|
+
["2003::", 18],
|
|
57
|
+
["2400::", 12],
|
|
58
|
+
["2410::", 12],
|
|
59
|
+
["2600::", 12],
|
|
60
|
+
["2610::", 23],
|
|
61
|
+
["2620::", 23],
|
|
62
|
+
["2630::", 12],
|
|
63
|
+
["2800::", 12],
|
|
64
|
+
["2a00::", 12],
|
|
65
|
+
["2a10::", 12],
|
|
66
|
+
["2c00::", 12],
|
|
67
|
+
]) {
|
|
68
|
+
ipv6Allowed.addSubnet(network, prefix, "ipv6");
|
|
69
|
+
}
|
|
70
|
+
const ipv6Denied = new BlockList();
|
|
71
|
+
for (const [network, prefix] of [
|
|
72
|
+
["100::", 64],
|
|
73
|
+
["64:ff9b::", 96],
|
|
74
|
+
["64:ff9b:1::", 48],
|
|
75
|
+
["2001::", 23],
|
|
76
|
+
["2001:db8::", 32],
|
|
77
|
+
["2002::", 16],
|
|
78
|
+
["3fff::", 20],
|
|
79
|
+
["5f00::", 16],
|
|
80
|
+
["fc00::", 7],
|
|
81
|
+
["fe80::", 10],
|
|
82
|
+
["fec0::", 10],
|
|
83
|
+
["ff00::", 8],
|
|
84
|
+
]) {
|
|
85
|
+
ipv6Denied.addSubnet(network, prefix, "ipv6");
|
|
86
|
+
}
|
|
87
|
+
const defaultNativeKnockRuntime = {
|
|
88
|
+
buildMessage: buildNHPMessage,
|
|
89
|
+
resolveAddresses: resolvePublicAddresses,
|
|
90
|
+
exchange: exchangeDatagram,
|
|
91
|
+
decryptReply: decryptNHPReply,
|
|
92
|
+
};
|
|
93
|
+
export async function nativeKnock(cell, devicePrivateKey, body, options = {}) {
|
|
94
|
+
return nativeKnockWithRuntime(cell, devicePrivateKey, body, options, defaultNativeKnockRuntime);
|
|
95
|
+
}
|
|
96
|
+
async function nativeKnockWithRuntime(cell, devicePrivateKey, body, options, runtime) {
|
|
97
|
+
if (options.signal?.aborted)
|
|
98
|
+
throw options.signal.reason;
|
|
99
|
+
const built = runtime.buildMessage({
|
|
100
|
+
type: NHP_TYPE_KNOCK,
|
|
101
|
+
devicePrivateKey,
|
|
102
|
+
serverPublicKey: cell.serverPublicKey,
|
|
103
|
+
body,
|
|
104
|
+
});
|
|
105
|
+
try {
|
|
106
|
+
const addresses = await runtime.resolveAddresses(cell.host, options.maxAddresses ?? NATIVE_DEFAULT_MAX_ADDRESSES, options.signal);
|
|
107
|
+
let lastError;
|
|
108
|
+
for (const address of addresses) {
|
|
109
|
+
try {
|
|
110
|
+
const packet = await runtime.exchange(address.address, address.family, cell.port, built.packet, options.timeoutMs ?? NATIVE_DEFAULT_TIMEOUT_MS, options.signal);
|
|
111
|
+
const reply = runtime.decryptReply(devicePrivateKey, cell.serverPublicKey, packet);
|
|
112
|
+
// NHP 1.1 COOKIE is a stateless busy response. Go intentionally does
|
|
113
|
+
// not bind its counter to the request; only an ACK must match it.
|
|
114
|
+
if (reply.type === NHP_TYPE_COOKIE)
|
|
115
|
+
return reply;
|
|
116
|
+
if (reply.counter !== built.counter) {
|
|
117
|
+
reply.body.fill(0);
|
|
118
|
+
throw new Error("NHP reply counter does not match the request");
|
|
119
|
+
}
|
|
120
|
+
return reply;
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
if (options.signal?.aborted)
|
|
124
|
+
throw options.signal.reason;
|
|
125
|
+
// Authentication and reply-policy failures happen after a datagram was
|
|
126
|
+
// received. They are terminal and must not fall through to another DNS
|
|
127
|
+
// address. Only local socket failures carry this private marker.
|
|
128
|
+
if (!isSocketExchangeError(error))
|
|
129
|
+
throw error;
|
|
130
|
+
lastError = error.cause;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
throw new Error("native NHP exchange failed", { cause: lastError });
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
built.packet.fill(0);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function resolvePublicAddresses(host, maximum, signal, lookupAddresses = lookup) {
|
|
140
|
+
if (!Number.isInteger(maximum) || maximum < 1 || maximum > 16) {
|
|
141
|
+
throw new Error("native NHP maxAddresses must be an integer from 1 to 16");
|
|
142
|
+
}
|
|
143
|
+
if (signal?.aborted)
|
|
144
|
+
throw signal.reason;
|
|
145
|
+
let rows;
|
|
146
|
+
try {
|
|
147
|
+
rows = await waitForAbort(lookupAddresses(host, { all: true, verbatim: true }), signal);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
if (signal?.aborted)
|
|
151
|
+
throw signal.reason;
|
|
152
|
+
throw new Error("native NHP endpoint DNS resolution failed", { cause: error });
|
|
153
|
+
}
|
|
154
|
+
if (signal?.aborted)
|
|
155
|
+
throw signal.reason;
|
|
156
|
+
const accepted = [];
|
|
157
|
+
for (const row of rows) {
|
|
158
|
+
if (row.family !== 4 && row.family !== 6)
|
|
159
|
+
continue;
|
|
160
|
+
if (!isPublicAddress(row.address, row.family))
|
|
161
|
+
continue;
|
|
162
|
+
accepted.push({ address: row.address, family: row.family });
|
|
163
|
+
if (accepted.length === maximum)
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
if (accepted.length === 0)
|
|
167
|
+
throw new Error("native NHP endpoint resolved to no public address");
|
|
168
|
+
return accepted;
|
|
169
|
+
}
|
|
170
|
+
function isPublicAddress(address, family) {
|
|
171
|
+
if (isIP(address) !== family)
|
|
172
|
+
return false;
|
|
173
|
+
if (family === 4)
|
|
174
|
+
return !ipv4Denied.check(address, "ipv4");
|
|
175
|
+
return ipv6Allowed.check(address, "ipv6") && !ipv6Denied.check(address, "ipv6");
|
|
176
|
+
}
|
|
177
|
+
class SocketExchangeError extends Error {
|
|
178
|
+
constructor(cause) {
|
|
179
|
+
super("native NHP socket exchange failed", { cause });
|
|
180
|
+
this.name = "SocketExchangeError";
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// A received datagram is an authority-bearing response attempt. Its malformed
|
|
184
|
+
// shape must stop address fallback instead of being treated as a local socket
|
|
185
|
+
// miss that can send the same knock to another address.
|
|
186
|
+
class ReceivedDatagramError extends Error {
|
|
187
|
+
}
|
|
188
|
+
function isSocketExchangeError(error) {
|
|
189
|
+
return error instanceof SocketExchangeError;
|
|
190
|
+
}
|
|
191
|
+
function exchangeDatagram(address, family, port, packet, timeoutMs, signal) {
|
|
192
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 60_000) {
|
|
193
|
+
return Promise.reject(new Error("native NHP timeout must be from 1 to 60000 milliseconds"));
|
|
194
|
+
}
|
|
195
|
+
if (signal?.aborted) {
|
|
196
|
+
return Promise.reject(signal.reason ?? new DOMException("Aborted", "AbortError"));
|
|
197
|
+
}
|
|
198
|
+
return new Promise((resolve, reject) => {
|
|
199
|
+
const socket = createSocket(family === 6 ? "udp6" : "udp4");
|
|
200
|
+
let settled = false;
|
|
201
|
+
const finish = (error, reply) => {
|
|
202
|
+
if (settled)
|
|
203
|
+
return;
|
|
204
|
+
settled = true;
|
|
205
|
+
clearTimeout(timer);
|
|
206
|
+
signal?.removeEventListener("abort", abort);
|
|
207
|
+
// An error that arrives while close settles must not become an unhandled
|
|
208
|
+
// EventEmitter error after the one-shot operational listener ran.
|
|
209
|
+
socket.on("error", () => undefined);
|
|
210
|
+
try {
|
|
211
|
+
socket.close();
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
// The socket can already be closed by a synchronous setup failure.
|
|
215
|
+
}
|
|
216
|
+
if (error instanceof ReceivedDatagramError)
|
|
217
|
+
reject(error);
|
|
218
|
+
else if (error !== undefined)
|
|
219
|
+
reject(new SocketExchangeError(error));
|
|
220
|
+
else
|
|
221
|
+
resolve(new Uint8Array(reply));
|
|
222
|
+
};
|
|
223
|
+
const abort = () => finish(signal?.reason ?? new DOMException("Aborted", "AbortError"));
|
|
224
|
+
const timer = setTimeout(() => finish(new Error("native NHP reply timed out")), timeoutMs);
|
|
225
|
+
timer.unref();
|
|
226
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
227
|
+
socket.once("error", (error) => finish(error));
|
|
228
|
+
socket.once("message", (reply) => {
|
|
229
|
+
if (reply.byteLength > NHP_PACKET_SIZE) {
|
|
230
|
+
finish(new ReceivedDatagramError("native NHP reply is too large"));
|
|
231
|
+
}
|
|
232
|
+
else
|
|
233
|
+
finish(undefined, reply);
|
|
234
|
+
});
|
|
235
|
+
socket.connect(port, address, () => {
|
|
236
|
+
sendOwnedDatagram(socket, packet, finish);
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
function sendOwnedDatagram(socket, packet, finish) {
|
|
241
|
+
// dgram owns its input until this callback. Use an independent encrypted
|
|
242
|
+
// datagram so nativeKnock can wipe the builder's packet immediately when an
|
|
243
|
+
// abort settles the exchange. Wipe this copy only after libuv releases it.
|
|
244
|
+
const outbound = Buffer.from(packet);
|
|
245
|
+
try {
|
|
246
|
+
socket.send(outbound, (error) => {
|
|
247
|
+
try {
|
|
248
|
+
if (error)
|
|
249
|
+
finish(error);
|
|
250
|
+
}
|
|
251
|
+
finally {
|
|
252
|
+
outbound.fill(0);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
outbound.fill(0);
|
|
258
|
+
finish(error);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
function waitForAbort(promise, signal) {
|
|
262
|
+
if (!signal)
|
|
263
|
+
return promise;
|
|
264
|
+
if (signal.aborted) {
|
|
265
|
+
return Promise.reject(signal.reason ?? new DOMException("Aborted", "AbortError"));
|
|
266
|
+
}
|
|
267
|
+
return new Promise((resolve, reject) => {
|
|
268
|
+
const abort = () => {
|
|
269
|
+
cleanup();
|
|
270
|
+
reject(signal.reason ?? new DOMException("Aborted", "AbortError"));
|
|
271
|
+
};
|
|
272
|
+
const cleanup = () => signal.removeEventListener("abort", abort);
|
|
273
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
274
|
+
promise.then((value) => {
|
|
275
|
+
cleanup();
|
|
276
|
+
resolve(value);
|
|
277
|
+
}, (error) => {
|
|
278
|
+
cleanup();
|
|
279
|
+
reject(error);
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
export const nativeUdpTesting = {
|
|
284
|
+
isPublicAddress,
|
|
285
|
+
resolvePublicAddresses,
|
|
286
|
+
nativeKnockWithRuntime,
|
|
287
|
+
exchangeDatagram,
|
|
288
|
+
sendOwnedDatagram,
|
|
289
|
+
socketExchangeError: (cause) => new SocketExchangeError(cause),
|
|
290
|
+
};
|
|
291
|
+
//# sourceMappingURL=native-udp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-udp.js","sourceRoot":"","sources":["../../../src/node/native-udp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EAAE,YAAY,EAAe,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EACL,eAAe,EACf,eAAe,EACf,eAAe,EACf,eAAe,EACf,cAAc,GAEf,MAAM,eAAe,CAAC;AAGvB,4EAA4E;AAC5E,6EAA6E;AAC7E,MAAM,CAAC,MAAM,yBAAyB,GAAG,KAAK,CAAC;AAC/C,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC;AAE9C,MAAM,UAAU,GAAG,IAAI,SAAS,EAAE,CAAC;AACnC,wEAAwE;AACxE,4EAA4E;AAC5E,KAAK,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI;IAC9B,CAAC,SAAS,EAAE,CAAC,CAAC;IACd,CAAC,UAAU,EAAE,CAAC,CAAC;IACf,CAAC,YAAY,EAAE,EAAE,CAAC;IAClB,CAAC,WAAW,EAAE,CAAC,CAAC;IAChB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,YAAY,EAAE,EAAE,CAAC;IAClB,CAAC,WAAW,EAAE,EAAE,CAAC;IACjB,CAAC,WAAW,EAAE,EAAE,CAAC;IACjB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,YAAY,EAAE,EAAE,CAAC;IAClB,CAAC,cAAc,EAAE,EAAE,CAAC;IACpB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,WAAW,EAAE,CAAC,CAAC;IAChB,CAAC,WAAW,EAAE,CAAC,CAAC;CACR,EAAE,CAAC;IACX,UAAU,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,WAAW,GAAG,IAAI,SAAS,EAAE,CAAC;AACpC,KAAK,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI;IAC9B,CAAC,YAAY,EAAE,EAAE,CAAC;IAClB,CAAC,YAAY,EAAE,EAAE,CAAC;IAClB,CAAC,YAAY,EAAE,EAAE,CAAC;IAClB,CAAC,YAAY,EAAE,EAAE,CAAC;IAClB,CAAC,YAAY,EAAE,EAAE,CAAC;IAClB,CAAC,YAAY,EAAE,EAAE,CAAC;IAClB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,QAAQ,EAAE,EAAE,CAAC;CACN,EAAE,CAAC;IACX,WAAW,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,GAAG,IAAI,SAAS,EAAE,CAAC;AACnC,KAAK,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI;IAC9B,CAAC,OAAO,EAAE,EAAE,CAAC;IACb,CAAC,WAAW,EAAE,EAAE,CAAC;IACjB,CAAC,aAAa,EAAE,EAAE,CAAC;IACnB,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,YAAY,EAAE,EAAE,CAAC;IAClB,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,QAAQ,EAAE,CAAC,CAAC;IACb,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,QAAQ,EAAE,CAAC,CAAC;CACL,EAAE,CAAC;IACX,UAAU,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAChD,CAAC;AAiBD,MAAM,yBAAyB,GAAuB;IACpD,YAAY,EAAE,eAAe;IAC7B,gBAAgB,EAAE,sBAAsB;IACxC,QAAQ,EAAE,gBAAgB;IAC1B,YAAY,EAAE,eAAe;CAC9B,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAmB,EACnB,gBAA4B,EAC5B,IAAgB,EAChB,OAAO,GAA0B,EAAE;IAEnC,OAAO,sBAAsB,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,OAAO,EAAE,yBAAyB,CAAC,CAAC;AAClG,CAAC;AAED,KAAK,UAAU,sBAAsB,CACnC,IAAmB,EACnB,gBAA4B,EAC5B,IAAgB,EAChB,OAA8B,EAC9B,OAA2B;IAE3B,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO;QAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;IACzD,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC;QACjC,IAAI,EAAE,cAAc;QACpB,gBAAgB;QAChB,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,IAAI;KACL,CAAC,CAAC;IACH,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,gBAAgB,CAC9C,IAAI,CAAC,IAAI,EACT,OAAO,CAAC,YAAY,IAAI,4BAA4B,EACpD,OAAO,CAAC,MAAM,CACf,CAAC;QACF,IAAI,SAAkB,CAAC;QACvB,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE,CAAC;YAChC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CACnC,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,MAAM,EACd,IAAI,CAAC,IAAI,EACT,KAAK,CAAC,MAAM,EACZ,OAAO,CAAC,SAAS,IAAI,yBAAyB,EAC9C,OAAO,CAAC,MAAM,CACf,CAAC;gBACF,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC,gBAAgB,EAAE,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;gBACnF,qEAAqE;gBACrE,kEAAkE;gBAClE,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe;oBAAE,OAAO,KAAK,CAAC;gBACjD,IAAI,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;oBACpC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;oBACnB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;gBAClE,CAAC;gBACD,OAAO,KAAK,CAAC;YACf,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO;oBAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;gBACzD,uEAAuE;gBACvE,uEAAuE;gBACvE,iEAAiE;gBACjE,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC;oBAAE,MAAM,KAAK,CAAC;gBAC/C,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC;YAC1B,CAAC;QACH,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IACtE,CAAC;YAAS,CAAC;QACT,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,sBAAsB,CACnC,IAAY,EACZ,OAAe,EACf,MAAoB,EACpB,eAAe,GAAkB,MAAM;IAEvC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,EAAE,EAAE,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,MAAM,EAAE,OAAO;QAAE,MAAM,MAAM,CAAC,MAAM,CAAC;IACzC,IAAI,IAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,YAAY,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;IAC1F,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,MAAM,EAAE,OAAO;YAAE,MAAM,MAAM,CAAC,MAAM,CAAC;QACzC,MAAM,IAAI,KAAK,CAAC,2CAA2C,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACjF,CAAC;IACD,IAAI,MAAM,EAAE,OAAO;QAAE,MAAM,MAAM,CAAC,MAAM,CAAC;IACzC,MAAM,QAAQ,GAA8C,EAAE,CAAC;IAC/D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACnD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC;YAAE,SAAS;QACxD,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAC5D,IAAI,QAAQ,CAAC,MAAM,KAAK,OAAO;YAAE,MAAM;IACzC,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IAChG,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,eAAe,CAAC,OAAe,EAAE,MAAc;IACtD,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IAC3C,IAAI,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC5D,OAAO,WAAW,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAClF,CAAC;AAED,MAAM,mBAAoB,SAAQ,KAAK;IAGrC,YAAY,KAAc;QACxB,KAAK,CAAC,mCAAmC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,8EAA8E;AAC9E,8EAA8E;AAC9E,wDAAwD;AACxD,MAAM,qBAAsB,SAAQ,KAAK;CAAG;AAE5C,SAAS,qBAAqB,CAAC,KAAc;IAC3C,OAAO,KAAK,YAAY,mBAAmB,CAAC;AAC9C,CAAC;AAED,SAAS,gBAAgB,CACvB,OAAe,EACf,MAAa,EACb,IAAY,EACZ,MAAkB,EAClB,SAAiB,EACjB,MAAoB;IAEpB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC,IAAI,SAAS,GAAG,MAAM,EAAE,CAAC;QACxE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC,CAAC;IAC9F,CAAC;IACD,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;QACpB,OAAO,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,IAAI,YAAY,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC5D,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,MAAM,MAAM,GAAG,CAAC,KAAe,EAAE,KAAc,EAAQ,EAAE;YACvD,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC5C,yEAAyE;YACzE,kEAAkE;YAClE,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YACpC,IAAI,CAAC;gBACH,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,CAAC;YAAC,MAAM,CAAC;gBACP,mEAAmE;YACrE,CAAC;YACD,IAAI,KAAK,YAAY,qBAAqB;gBAAE,MAAM,CAAC,KAAK,CAAC,CAAC;iBACrD,IAAI,KAAK,KAAK,SAAS;gBAAE,MAAM,CAAC,IAAI,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC;;gBAChE,OAAO,CAAC,IAAI,UAAU,CAAC,KAAM,CAAC,CAAC,CAAC;QACvC,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,GAAS,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,IAAI,IAAI,YAAY,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;QAC9F,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QAC3F,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/C,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;YAC/B,IAAI,KAAK,CAAC,UAAU,GAAG,eAAe,EAAE,CAAC;gBACvC,MAAM,CAAC,IAAI,qBAAqB,CAAC,+BAA+B,CAAC,CAAC,CAAC;YACrE,CAAC;;gBAAM,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE;YACjC,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB,CACxB,MAAc,EACd,MAAkB,EAClB,MAAgC;IAEhC,yEAAyE;IACzE,4EAA4E;IAC5E,2EAA2E;IAC3E,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;YAC9B,IAAI,CAAC;gBACH,IAAI,KAAK;oBAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YAC3B,CAAC;oBAAS,CAAC;gBACT,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACnB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,MAAM,CAAC,KAAK,CAAC,CAAC;IAChB,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAI,OAAmB,EAAE,MAAoB;IAChE,IAAI,CAAC,MAAM;QAAE,OAAO,OAAO,CAAC;IAC5B,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,IAAI,YAAY,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,GAAG,EAAE;YACjB,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,IAAI,YAAY,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;QACrE,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACjE,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,OAAO,CAAC,IAAI,CACV,CAAC,KAAK,EAAE,EAAE;YACR,OAAO,EAAE,CAAC;YACV,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC,EACD,CAAC,KAAc,EAAE,EAAE;YACjB,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,eAAe;IACf,sBAAsB;IACtB,sBAAsB;IACtB,gBAAgB;IAChB,iBAAiB;IACjB,mBAAmB,EAAE,CAAC,KAAc,EAAS,EAAE,CAAC,IAAI,mBAAmB,CAAC,KAAK,CAAC;CAC/E,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export declare const NHP_TYPE_KNOCK = 1;
|
|
2
|
+
export declare const NHP_TYPE_ACK = 2;
|
|
3
|
+
export declare const NHP_TYPE_COOKIE = 7;
|
|
4
|
+
export declare const NHP_HEADER_SIZE = 240;
|
|
5
|
+
export declare const NHP_PACKET_SIZE = 4096;
|
|
6
|
+
export declare const NHP_MAX_BODY_SIZE: number;
|
|
7
|
+
export interface NHPMessage {
|
|
8
|
+
readonly type: number;
|
|
9
|
+
readonly flags: number;
|
|
10
|
+
readonly counter: bigint;
|
|
11
|
+
readonly timestampNanos: bigint;
|
|
12
|
+
readonly body: Uint8Array;
|
|
13
|
+
}
|
|
14
|
+
export interface BuildNHPMessageInput {
|
|
15
|
+
readonly type: number;
|
|
16
|
+
readonly devicePrivateKey: Uint8Array;
|
|
17
|
+
readonly serverPublicKey: Uint8Array;
|
|
18
|
+
readonly body: Uint8Array;
|
|
19
|
+
readonly ephemeralPrivateKey?: Uint8Array;
|
|
20
|
+
readonly timestampNanos?: bigint;
|
|
21
|
+
readonly counter?: bigint;
|
|
22
|
+
readonly preamble?: number;
|
|
23
|
+
}
|
|
24
|
+
export declare function buildNHPMessage(input: BuildNHPMessageInput): {
|
|
25
|
+
packet: Uint8Array;
|
|
26
|
+
counter: bigint;
|
|
27
|
+
};
|
|
28
|
+
export declare function decryptNHPReply(devicePrivateKey: Uint8Array, expectedServerPublicKey: Uint8Array, packetValue: Uint8Array): NHPMessage;
|
|
29
|
+
declare function validateReplyProfile(type: number, flags: number): void;
|
|
30
|
+
declare function inflateReplyBody(body: Buffer, flags: number): Buffer;
|
|
31
|
+
export declare const nhpWireTesting: {
|
|
32
|
+
validateReplyProfile: typeof validateReplyProfile;
|
|
33
|
+
inflateReplyBody: typeof inflateReplyBody;
|
|
34
|
+
};
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=nhp-wire.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nhp-wire.d.ts","sourceRoot":"","sources":["../../../src/node/nhp-wire.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,cAAc,IAAI,CAAC;AAChC,eAAO,MAAM,YAAY,IAAI,CAAC;AAC9B,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,eAAO,MAAM,eAAe,MAAM,CAAC;AACnC,eAAO,MAAM,eAAe,OAAQ,CAAC;AACrC,eAAO,MAAM,iBAAiB,QAAyC,CAAC;AAaxE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,gBAAgB,EAAE,UAAU,CAAC;IACtC,QAAQ,CAAC,eAAe,EAAE,UAAU,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,mBAAmB,CAAC,EAAE,UAAU,CAAC;IAC1C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG;IAC5D,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB,CAyEA;AAED,wBAAgB,eAAe,CAC7B,gBAAgB,EAAE,UAAU,EAC5B,uBAAuB,EAAE,UAAU,EACnC,WAAW,EAAE,UAAU,GACtB,UAAU,CA4EZ;AAED,iBAAS,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAI/D;AAED,iBAAS,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAO7D;AAmGD,eAAO,MAAM,cAAc;;;CAA6C,CAAC"}
|