@honeybbq/teamspeak-client 0.2.3 → 0.3.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 +1 -0
- package/dist/address-BR-5unVo.cjs +2 -0
- package/dist/address-BR-5unVo.cjs.map +1 -0
- package/dist/address-BfmovVpp.js +65 -0
- package/dist/address-BfmovVpp.js.map +1 -0
- package/dist/address.d.ts +9 -0
- package/dist/address.d.ts.map +1 -0
- package/dist/address.test.d.ts +2 -0
- package/dist/address.test.d.ts.map +1 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.test.d.ts +2 -0
- package/dist/api.test.d.ts.map +1 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/command/index.cjs +1 -1
- package/dist/command/index.mjs +2 -2
- package/dist/{command-CTDmBXd_.js → command-BLe-C2L2.js} +2 -4
- package/dist/{command-CTDmBXd_.js.map → command-BLe-C2L2.js.map} +1 -1
- package/dist/command-DAK4pUBP.cjs +4 -0
- package/dist/{command-CUPNiKRl.cjs.map → command-DAK4pUBP.cjs.map} +1 -1
- package/dist/{crypt-handshake-D2Rsi2e3.cjs → crypt-handshake-CQkQreLx.cjs} +2 -2
- package/dist/{crypt-handshake-D2Rsi2e3.cjs.map → crypt-handshake-CQkQreLx.cjs.map} +1 -1
- package/dist/{crypt-handshake-DIj51kno.js → crypt-handshake-DziOY4Lq.js} +2 -2
- package/dist/{crypt-handshake-DIj51kno.js.map → crypt-handshake-DziOY4Lq.js.map} +1 -1
- package/dist/{crypt-init2-C2X9oK4i.js → crypt-init2-D70ha4LB.js} +6 -6
- package/dist/{crypt-init2-C2X9oK4i.js.map → crypt-init2-D70ha4LB.js.map} +1 -1
- package/dist/{crypt-init2-CazdFwqF.cjs → crypt-init2-DparLekm.cjs} +2 -2
- package/dist/{crypt-init2-CazdFwqF.cjs.map → crypt-init2-DparLekm.cjs.map} +1 -1
- package/dist/crypto/identity.d.ts.map +1 -1
- package/dist/crypto/index.cjs +1 -1
- package/dist/crypto/index.mjs +2 -2
- package/dist/{crypto-CwIMggQG.js → crypto-Bg02m4ZE.js} +7 -7
- package/dist/crypto-Bg02m4ZE.js.map +1 -0
- package/dist/crypto-CDlweUL3.cjs +2 -0
- package/dist/crypto-CDlweUL3.cjs.map +1 -0
- package/dist/discovery/index.cjs +1 -1
- package/dist/discovery/index.mjs +1 -1
- package/dist/discovery/resolver.d.ts.map +1 -1
- package/dist/{handler-BP38rMNl.js → handler-DI_abe9c.js} +153 -125
- package/dist/handler-DI_abe9c.js.map +1 -0
- package/dist/handler-DuwoO5RC.cjs +2 -0
- package/dist/handler-DuwoO5RC.cjs.map +1 -0
- package/dist/handshake/index.cjs +1 -1
- package/dist/handshake/index.mjs +2 -2
- package/dist/helpers.d.ts.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +154 -140
- package/dist/index.mjs.map +1 -1
- package/dist/{parser-B6cGUByG.cjs → parser-CL33R9tr.cjs} +2 -2
- package/dist/{parser-B6cGUByG.cjs.map → parser-CL33R9tr.cjs.map} +1 -1
- package/dist/{parser-BPzO8py_.js → parser-DZMv3Jm-.js} +2 -2
- package/dist/{parser-BPzO8py_.js.map → parser-DZMv3Jm-.js.map} +1 -1
- package/dist/primitives-cNNAeFCo.cjs +2 -0
- package/dist/primitives-cNNAeFCo.cjs.map +1 -0
- package/dist/primitives-xIr6Tjk4.js +1457 -0
- package/dist/primitives-xIr6Tjk4.js.map +1 -0
- package/dist/resolver-6B8dI9gr.js +141 -0
- package/dist/resolver-6B8dI9gr.js.map +1 -0
- package/dist/resolver-DCcmyWSK.cjs +4 -0
- package/dist/resolver-DCcmyWSK.cjs.map +1 -0
- package/dist/transport/handler.d.ts +2 -0
- package/dist/transport/handler.d.ts.map +1 -1
- package/dist/transport/index.cjs +1 -1
- package/dist/transport/index.mjs +1 -1
- package/dist/transport/whisper.test.d.ts +2 -0
- package/dist/transport/whisper.test.d.ts.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/dist/command-CUPNiKRl.cjs +0 -4
- package/dist/crypto-CwIMggQG.js.map +0 -1
- package/dist/crypto-IbzNNTgO.cjs +0 -2
- package/dist/crypto-IbzNNTgO.cjs.map +0 -1
- package/dist/handler-BJdwhtkp.cjs +0 -2
- package/dist/handler-BJdwhtkp.cjs.map +0 -1
- package/dist/handler-BP38rMNl.js.map +0 -1
- package/dist/primitives-Bt-L4BZa.js +0 -1483
- package/dist/primitives-Bt-L4BZa.js.map +0 -1
- package/dist/primitives-ClIhDdNZ.cjs +0 -2
- package/dist/primitives-ClIhDdNZ.cjs.map +0 -1
- package/dist/resolver-B7jho9CP.cjs +0 -4
- package/dist/resolver-B7jho9CP.cjs.map +0 -1
- package/dist/resolver-BDCF2KbM.js +0 -162
- package/dist/resolver-BDCF2KbM.js.map +0 -1
- package/dist/types-ANvuLFWH.cjs +0 -2
- package/dist/types-ANvuLFWH.cjs.map +0 -1
- package/dist/types-Xm1vrW4s.js +0 -18
- package/dist/types-Xm1vrW4s.js.map +0 -1
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { n as e, o as t, r as n, t as r } from "./address-BfmovVpp.js";
|
|
2
|
+
import { resolveSrv as i } from "node:dns/promises";
|
|
3
|
+
import { createConnection as a } from "node:net";
|
|
4
|
+
//#region src/discovery/resolver.ts
|
|
5
|
+
var o = 41144, s = "https://named.myteamspeak.com/lookup", c = 6e5, l = class {
|
|
6
|
+
#e = /* @__PURE__ */ new Map();
|
|
7
|
+
constructor(e = t) {}
|
|
8
|
+
async resolve(t, i) {
|
|
9
|
+
if (!t) throw Error("empty address");
|
|
10
|
+
let a = this.#t(t);
|
|
11
|
+
if (a) return a;
|
|
12
|
+
let { host: o, port: s } = n(t);
|
|
13
|
+
if (r(o)) return [{
|
|
14
|
+
addr: e(o, s),
|
|
15
|
+
source: "Direct",
|
|
16
|
+
expiry: /* @__PURE__ */ new Date(0)
|
|
17
|
+
}];
|
|
18
|
+
if (!o.includes(".") && o !== "localhost") {
|
|
19
|
+
let e = await u(o, i);
|
|
20
|
+
if (e) return this.resolve(e, i);
|
|
21
|
+
}
|
|
22
|
+
let c = await this.#r(o, i);
|
|
23
|
+
if (c) return this.#n(t, c);
|
|
24
|
+
let l = p(o), d = await this.#i(l, o, i);
|
|
25
|
+
if (d) return this.#n(t, [{
|
|
26
|
+
addr: d,
|
|
27
|
+
source: "TSDNS-SRV",
|
|
28
|
+
expiry: /* @__PURE__ */ new Date(0)
|
|
29
|
+
}]);
|
|
30
|
+
let f = await this.#a(l, o, i);
|
|
31
|
+
if (f) return this.#n(t, [{
|
|
32
|
+
addr: f,
|
|
33
|
+
source: "TSDNS-Direct",
|
|
34
|
+
expiry: /* @__PURE__ */ new Date(0)
|
|
35
|
+
}]);
|
|
36
|
+
let m = [{
|
|
37
|
+
addr: e(o, s),
|
|
38
|
+
source: "Direct",
|
|
39
|
+
expiry: /* @__PURE__ */ new Date(0)
|
|
40
|
+
}];
|
|
41
|
+
return this.#n(t, m);
|
|
42
|
+
}
|
|
43
|
+
#t(e) {
|
|
44
|
+
let t = this.#e.get(e);
|
|
45
|
+
if (!t || t.length === 0) return null;
|
|
46
|
+
let n = t[0];
|
|
47
|
+
return n.expiry.getTime() > 0 && Date.now() > n.expiry.getTime() ? null : t;
|
|
48
|
+
}
|
|
49
|
+
#n(e, t) {
|
|
50
|
+
let n = new Date(Date.now() + c), r = t.map((e) => ({
|
|
51
|
+
...e,
|
|
52
|
+
expiry: n
|
|
53
|
+
}));
|
|
54
|
+
return this.#e.set(e, r), r;
|
|
55
|
+
}
|
|
56
|
+
async #r(t, n) {
|
|
57
|
+
try {
|
|
58
|
+
let r = await m(i(`_ts3._udp.${t}`), n);
|
|
59
|
+
return !r || r.length === 0 ? null : r.map((t) => ({
|
|
60
|
+
addr: e(t.name.replace(/\.$/, ""), String(t.port)),
|
|
61
|
+
source: "SRV",
|
|
62
|
+
expiry: /* @__PURE__ */ new Date(0)
|
|
63
|
+
}));
|
|
64
|
+
} catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async #i(t, n, r) {
|
|
69
|
+
for (let a of t) try {
|
|
70
|
+
let t = await m(i(`_tsdns._tcp.${a}`), r);
|
|
71
|
+
if (!t || t.length === 0) continue;
|
|
72
|
+
for (let i of t) {
|
|
73
|
+
let t = await d(e(i.name.replace(/\.$/, ""), String(i.port)), n, r);
|
|
74
|
+
if (t) return t;
|
|
75
|
+
}
|
|
76
|
+
} catch {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
async #a(t, n, r) {
|
|
82
|
+
for (let i of t) {
|
|
83
|
+
let t = await d(e(i, String(o)), n, r);
|
|
84
|
+
if (t) return t;
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
async function u(e, t) {
|
|
90
|
+
try {
|
|
91
|
+
let n = new URL(s);
|
|
92
|
+
n.searchParams.set("name", e);
|
|
93
|
+
let r = t ? { signal: t } : {}, i = await fetch(n.toString(), r);
|
|
94
|
+
return i.ok && (await i.text()).split("\n")[0]?.trim() || null;
|
|
95
|
+
} catch {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function d(e, t, n) {
|
|
100
|
+
let [r, i] = f(e), o = parseInt(i, 10);
|
|
101
|
+
return new Promise((e) => {
|
|
102
|
+
let i = setTimeout(() => {
|
|
103
|
+
s.destroy(), e(null);
|
|
104
|
+
}, 3e3), s = a({
|
|
105
|
+
host: r,
|
|
106
|
+
port: o,
|
|
107
|
+
timeout: 2e3
|
|
108
|
+
}, () => {
|
|
109
|
+
s.write(`${t}\n`);
|
|
110
|
+
}), c = "";
|
|
111
|
+
s.on("data", (t) => {
|
|
112
|
+
c += t.toString();
|
|
113
|
+
let n = c.indexOf("\n");
|
|
114
|
+
if (n >= 0) {
|
|
115
|
+
clearTimeout(i), s.destroy();
|
|
116
|
+
let t = c.slice(0, n).trim();
|
|
117
|
+
e(!t || t === "404" || t === "errors" ? null : t);
|
|
118
|
+
}
|
|
119
|
+
}), s.on("error", () => {
|
|
120
|
+
clearTimeout(i), e(null);
|
|
121
|
+
}), n && n.addEventListener("abort", () => {
|
|
122
|
+
clearTimeout(i), s.destroy(), e(null);
|
|
123
|
+
}, { once: !0 });
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function f(e) {
|
|
127
|
+
let { host: t, port: r } = n(e);
|
|
128
|
+
return [t, r];
|
|
129
|
+
}
|
|
130
|
+
function p(e) {
|
|
131
|
+
let t = e.split("."), n = [];
|
|
132
|
+
for (let e = 0; e < t.length - 1; e++) n.push(t.slice(e).join("."));
|
|
133
|
+
return n.slice(0, 3);
|
|
134
|
+
}
|
|
135
|
+
function m(e, t) {
|
|
136
|
+
return t ? Promise.race([e, new Promise((e, n) => t.addEventListener("abort", () => n(t.reason), { once: !0 }))]) : e;
|
|
137
|
+
}
|
|
138
|
+
//#endregion
|
|
139
|
+
export { l as t };
|
|
140
|
+
|
|
141
|
+
//# sourceMappingURL=resolver-6B8dI9gr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver-6B8dI9gr.js","names":[],"sources":["../src/discovery/resolver.ts"],"sourcesContent":["import { resolveSrv } from \"node:dns/promises\";\nimport { createConnection } from \"node:net\";\nimport type { Logger } from \"../types.js\";\nimport type { ResolvedAddr } from \"../types.js\";\nimport { noopLogger } from \"../types.js\";\nimport { isIpAddress, joinHostPort, splitHostPort } from \"../address.js\";\n\nconst TS_DNS_DEFAULT_PORT = 41144;\nconst NICKNAME_LOOKUP_URL = \"https://named.myteamspeak.com/lookup\";\nconst CACHE_TTL_MS = 10 * 60 * 1000;\n\nexport class Resolver {\n readonly #cache = new Map<string, ResolvedAddr[]>();\n\n constructor(_log: Logger = noopLogger) {}\n\n async resolve(inputAddr: string, signal?: AbortSignal): Promise<ResolvedAddr[]> {\n if (!inputAddr) throw new Error(\"empty address\");\n\n const cached = this.#getValidCache(inputAddr);\n if (cached) return cached;\n\n const { host, port } = splitHostPort(inputAddr);\n\n if (isIpAddress(host)) {\n return [{ addr: joinHostPort(host, port), source: \"Direct\", expiry: new Date(0) }];\n }\n\n // Nickname resolution (no dots → not a domain)\n if (!host.includes(\".\") && host !== \"localhost\") {\n const nickAddr = await resolveNickname(host, signal);\n if (nickAddr) {\n return this.resolve(nickAddr, signal);\n }\n }\n\n // SRV _ts3._udp.<host>\n const srvResults = await this.#resolveSRV(host, signal);\n if (srvResults) return this.#setCache(inputAddr, srvResults);\n\n const domainList = getDomainList(host);\n\n // TSDNS via SRV _tsdns._tcp.<domain>\n const tsdnsSrv = await this.#resolveTSDNSSRV(domainList, host, signal);\n if (tsdnsSrv) {\n return this.#setCache(inputAddr, [\n { addr: tsdnsSrv, source: \"TSDNS-SRV\", expiry: new Date(0) },\n ]);\n }\n\n // TSDNS direct :41144\n const tsdnsDirect = await this.#resolveTSDNSDirect(domainList, host, signal);\n if (tsdnsDirect) {\n return this.#setCache(inputAddr, [\n { addr: tsdnsDirect, source: \"TSDNS-Direct\", expiry: new Date(0) },\n ]);\n }\n\n // Plain DNS fallback\n const fallback: ResolvedAddr[] = [\n { addr: joinHostPort(host, port), source: \"Direct\", expiry: new Date(0) },\n ];\n return this.#setCache(inputAddr, fallback);\n }\n\n #getValidCache(inputAddr: string): ResolvedAddr[] | null {\n const cached = this.#cache.get(inputAddr);\n if (!cached || cached.length === 0) return null;\n const first = cached[0]!;\n if (first.expiry.getTime() > 0 && Date.now() > first.expiry.getTime()) return null;\n return cached;\n }\n\n #setCache(key: string, results: ResolvedAddr[]): ResolvedAddr[] {\n const expiry = new Date(Date.now() + CACHE_TTL_MS);\n const withExpiry = results.map((r) => ({ ...r, expiry }));\n this.#cache.set(key, withExpiry);\n return withExpiry;\n }\n\n async #resolveSRV(host: string, signal?: AbortSignal): Promise<ResolvedAddr[] | null> {\n try {\n const srvs = await withSignal(resolveSrv(`_ts3._udp.${host}`), signal);\n if (!srvs || srvs.length === 0) return null;\n return srvs.map((srv) => ({\n addr: joinHostPort(srv.name.replace(/\\.$/, \"\"), String(srv.port)),\n source: \"SRV\",\n expiry: new Date(0),\n }));\n } catch {\n return null;\n }\n }\n\n async #resolveTSDNSSRV(\n domains: string[],\n queryHost: string,\n signal?: AbortSignal,\n ): Promise<string | null> {\n for (const domain of domains) {\n try {\n const srvs = await withSignal(resolveSrv(`_tsdns._tcp.${domain}`), signal);\n if (!srvs || srvs.length === 0) continue;\n for (const srv of srvs) {\n const tsdnsAddr = joinHostPort(srv.name.replace(/\\.$/, \"\"), String(srv.port));\n const result = await queryTSDNS(tsdnsAddr, queryHost, signal);\n if (result) return result;\n }\n } catch {\n continue;\n }\n }\n return null;\n }\n\n async #resolveTSDNSDirect(\n domains: string[],\n queryHost: string,\n signal?: AbortSignal,\n ): Promise<string | null> {\n for (const domain of domains) {\n const tsdnsAddr = joinHostPort(domain, String(TS_DNS_DEFAULT_PORT));\n const result = await queryTSDNS(tsdnsAddr, queryHost, signal);\n if (result) return result;\n }\n return null;\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\nasync function resolveNickname(nickname: string, signal?: AbortSignal): Promise<string | null> {\n try {\n const url = new URL(NICKNAME_LOOKUP_URL);\n url.searchParams.set(\"name\", nickname);\n const init: RequestInit = signal ? { signal } : {};\n const resp = await fetch(url.toString(), init);\n if (!resp.ok) return null;\n const text = await resp.text();\n const line = text.split(\"\\n\")[0]?.trim();\n return line || null;\n } catch {\n return null;\n }\n}\n\nfunction queryTSDNS(\n tsdnsAddr: string,\n queryHost: string,\n signal?: AbortSignal,\n): Promise<string | null> {\n const [host, portStr] = splitHostPortParts(tsdnsAddr);\n const port = parseInt(portStr, 10);\n\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n socket.destroy();\n resolve(null);\n }, 3_000);\n\n const socket = createConnection({ host, port, timeout: 2_000 }, () => {\n socket.write(`${queryHost}\\n`);\n });\n\n let buf = \"\";\n socket.on(\"data\", (chunk: Buffer) => {\n buf += chunk.toString();\n const idx = buf.indexOf(\"\\n\");\n if (idx >= 0) {\n clearTimeout(timeout);\n socket.destroy();\n const line = buf.slice(0, idx).trim();\n if (!line || line === \"404\" || line === \"errors\") resolve(null);\n else resolve(line);\n }\n });\n\n socket.on(\"error\", () => {\n clearTimeout(timeout);\n resolve(null);\n });\n\n if (signal) {\n signal.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timeout);\n socket.destroy();\n resolve(null);\n },\n { once: true },\n );\n }\n });\n}\n\nfunction splitHostPortParts(addr: string): [string, string] {\n const { host, port } = splitHostPort(addr);\n return [host, port];\n}\n\nfunction getDomainList(host: string): string[] {\n const parts = host.split(\".\");\n const list: string[] = [];\n for (let i = 0; i < parts.length - 1; i++) {\n list.push(parts.slice(i).join(\".\"));\n }\n return list.slice(0, 3);\n}\n\nfunction withSignal<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) return promise;\n return Promise.race([\n promise,\n new Promise<T>((_, reject) =>\n signal.addEventListener(\"abort\", () => reject(signal.reason), { once: true }),\n ),\n ]);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
const e=require("./address-BR-5unVo.cjs");let t=require("node:dns/promises"),n=require("node:net");var r=41144,i=`https://named.myteamspeak.com/lookup`,a=6e5,o=class{#e=new Map;constructor(t=e.o){}async resolve(t,n){if(!t)throw Error(`empty address`);let r=this.#t(t);if(r)return r;let{host:i,port:a}=e.r(t);if(e.t(i))return[{addr:e.n(i,a),source:`Direct`,expiry:new Date(0)}];if(!i.includes(`.`)&&i!==`localhost`){let e=await s(i,n);if(e)return this.resolve(e,n)}let o=await this.#r(i,n);if(o)return this.#n(t,o);let c=u(i),l=await this.#i(c,i,n);if(l)return this.#n(t,[{addr:l,source:`TSDNS-SRV`,expiry:new Date(0)}]);let d=await this.#a(c,i,n);if(d)return this.#n(t,[{addr:d,source:`TSDNS-Direct`,expiry:new Date(0)}]);let f=[{addr:e.n(i,a),source:`Direct`,expiry:new Date(0)}];return this.#n(t,f)}#t(e){let t=this.#e.get(e);if(!t||t.length===0)return null;let n=t[0];return n.expiry.getTime()>0&&Date.now()>n.expiry.getTime()?null:t}#n(e,t){let n=new Date(Date.now()+a),r=t.map(e=>({...e,expiry:n}));return this.#e.set(e,r),r}async#r(n,r){try{let i=await d((0,t.resolveSrv)(`_ts3._udp.${n}`),r);return!i||i.length===0?null:i.map(t=>({addr:e.n(t.name.replace(/\.$/,``),String(t.port)),source:`SRV`,expiry:new Date(0)}))}catch{return null}}async#i(n,r,i){for(let a of n)try{let n=await d((0,t.resolveSrv)(`_tsdns._tcp.${a}`),i);if(!n||n.length===0)continue;for(let t of n){let n=await c(e.n(t.name.replace(/\.$/,``),String(t.port)),r,i);if(n)return n}}catch{continue}return null}async#a(t,n,i){for(let a of t){let t=await c(e.n(a,String(r)),n,i);if(t)return t}return null}};async function s(e,t){try{let n=new URL(i);n.searchParams.set(`name`,e);let r=t?{signal:t}:{},a=await fetch(n.toString(),r);return a.ok&&(await a.text()).split(`
|
|
2
|
+
`)[0]?.trim()||null}catch{return null}}function c(e,t,r){let[i,a]=l(e),o=parseInt(a,10);return new Promise(e=>{let a=setTimeout(()=>{s.destroy(),e(null)},3e3),s=(0,n.createConnection)({host:i,port:o,timeout:2e3},()=>{s.write(`${t}\n`)}),c=``;s.on(`data`,t=>{c+=t.toString();let n=c.indexOf(`
|
|
3
|
+
`);if(n>=0){clearTimeout(a),s.destroy();let t=c.slice(0,n).trim();e(!t||t===`404`||t===`errors`?null:t)}}),s.on(`error`,()=>{clearTimeout(a),e(null)}),r&&r.addEventListener(`abort`,()=>{clearTimeout(a),s.destroy(),e(null)},{once:!0})})}function l(t){let{host:n,port:r}=e.r(t);return[n,r]}function u(e){let t=e.split(`.`),n=[];for(let e=0;e<t.length-1;e++)n.push(t.slice(e).join(`.`));return n.slice(0,3)}function d(e,t){return t?Promise.race([e,new Promise((e,n)=>t.addEventListener(`abort`,()=>n(t.reason),{once:!0}))]):e}Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return o}});
|
|
4
|
+
//# sourceMappingURL=resolver-DCcmyWSK.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver-DCcmyWSK.cjs","names":[],"sources":["../src/discovery/resolver.ts"],"sourcesContent":["import { resolveSrv } from \"node:dns/promises\";\nimport { createConnection } from \"node:net\";\nimport type { Logger } from \"../types.js\";\nimport type { ResolvedAddr } from \"../types.js\";\nimport { noopLogger } from \"../types.js\";\nimport { isIpAddress, joinHostPort, splitHostPort } from \"../address.js\";\n\nconst TS_DNS_DEFAULT_PORT = 41144;\nconst NICKNAME_LOOKUP_URL = \"https://named.myteamspeak.com/lookup\";\nconst CACHE_TTL_MS = 10 * 60 * 1000;\n\nexport class Resolver {\n readonly #cache = new Map<string, ResolvedAddr[]>();\n\n constructor(_log: Logger = noopLogger) {}\n\n async resolve(inputAddr: string, signal?: AbortSignal): Promise<ResolvedAddr[]> {\n if (!inputAddr) throw new Error(\"empty address\");\n\n const cached = this.#getValidCache(inputAddr);\n if (cached) return cached;\n\n const { host, port } = splitHostPort(inputAddr);\n\n if (isIpAddress(host)) {\n return [{ addr: joinHostPort(host, port), source: \"Direct\", expiry: new Date(0) }];\n }\n\n // Nickname resolution (no dots → not a domain)\n if (!host.includes(\".\") && host !== \"localhost\") {\n const nickAddr = await resolveNickname(host, signal);\n if (nickAddr) {\n return this.resolve(nickAddr, signal);\n }\n }\n\n // SRV _ts3._udp.<host>\n const srvResults = await this.#resolveSRV(host, signal);\n if (srvResults) return this.#setCache(inputAddr, srvResults);\n\n const domainList = getDomainList(host);\n\n // TSDNS via SRV _tsdns._tcp.<domain>\n const tsdnsSrv = await this.#resolveTSDNSSRV(domainList, host, signal);\n if (tsdnsSrv) {\n return this.#setCache(inputAddr, [\n { addr: tsdnsSrv, source: \"TSDNS-SRV\", expiry: new Date(0) },\n ]);\n }\n\n // TSDNS direct :41144\n const tsdnsDirect = await this.#resolveTSDNSDirect(domainList, host, signal);\n if (tsdnsDirect) {\n return this.#setCache(inputAddr, [\n { addr: tsdnsDirect, source: \"TSDNS-Direct\", expiry: new Date(0) },\n ]);\n }\n\n // Plain DNS fallback\n const fallback: ResolvedAddr[] = [\n { addr: joinHostPort(host, port), source: \"Direct\", expiry: new Date(0) },\n ];\n return this.#setCache(inputAddr, fallback);\n }\n\n #getValidCache(inputAddr: string): ResolvedAddr[] | null {\n const cached = this.#cache.get(inputAddr);\n if (!cached || cached.length === 0) return null;\n const first = cached[0]!;\n if (first.expiry.getTime() > 0 && Date.now() > first.expiry.getTime()) return null;\n return cached;\n }\n\n #setCache(key: string, results: ResolvedAddr[]): ResolvedAddr[] {\n const expiry = new Date(Date.now() + CACHE_TTL_MS);\n const withExpiry = results.map((r) => ({ ...r, expiry }));\n this.#cache.set(key, withExpiry);\n return withExpiry;\n }\n\n async #resolveSRV(host: string, signal?: AbortSignal): Promise<ResolvedAddr[] | null> {\n try {\n const srvs = await withSignal(resolveSrv(`_ts3._udp.${host}`), signal);\n if (!srvs || srvs.length === 0) return null;\n return srvs.map((srv) => ({\n addr: joinHostPort(srv.name.replace(/\\.$/, \"\"), String(srv.port)),\n source: \"SRV\",\n expiry: new Date(0),\n }));\n } catch {\n return null;\n }\n }\n\n async #resolveTSDNSSRV(\n domains: string[],\n queryHost: string,\n signal?: AbortSignal,\n ): Promise<string | null> {\n for (const domain of domains) {\n try {\n const srvs = await withSignal(resolveSrv(`_tsdns._tcp.${domain}`), signal);\n if (!srvs || srvs.length === 0) continue;\n for (const srv of srvs) {\n const tsdnsAddr = joinHostPort(srv.name.replace(/\\.$/, \"\"), String(srv.port));\n const result = await queryTSDNS(tsdnsAddr, queryHost, signal);\n if (result) return result;\n }\n } catch {\n continue;\n }\n }\n return null;\n }\n\n async #resolveTSDNSDirect(\n domains: string[],\n queryHost: string,\n signal?: AbortSignal,\n ): Promise<string | null> {\n for (const domain of domains) {\n const tsdnsAddr = joinHostPort(domain, String(TS_DNS_DEFAULT_PORT));\n const result = await queryTSDNS(tsdnsAddr, queryHost, signal);\n if (result) return result;\n }\n return null;\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\nasync function resolveNickname(nickname: string, signal?: AbortSignal): Promise<string | null> {\n try {\n const url = new URL(NICKNAME_LOOKUP_URL);\n url.searchParams.set(\"name\", nickname);\n const init: RequestInit = signal ? { signal } : {};\n const resp = await fetch(url.toString(), init);\n if (!resp.ok) return null;\n const text = await resp.text();\n const line = text.split(\"\\n\")[0]?.trim();\n return line || null;\n } catch {\n return null;\n }\n}\n\nfunction queryTSDNS(\n tsdnsAddr: string,\n queryHost: string,\n signal?: AbortSignal,\n): Promise<string | null> {\n const [host, portStr] = splitHostPortParts(tsdnsAddr);\n const port = parseInt(portStr, 10);\n\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n socket.destroy();\n resolve(null);\n }, 3_000);\n\n const socket = createConnection({ host, port, timeout: 2_000 }, () => {\n socket.write(`${queryHost}\\n`);\n });\n\n let buf = \"\";\n socket.on(\"data\", (chunk: Buffer) => {\n buf += chunk.toString();\n const idx = buf.indexOf(\"\\n\");\n if (idx >= 0) {\n clearTimeout(timeout);\n socket.destroy();\n const line = buf.slice(0, idx).trim();\n if (!line || line === \"404\" || line === \"errors\") resolve(null);\n else resolve(line);\n }\n });\n\n socket.on(\"error\", () => {\n clearTimeout(timeout);\n resolve(null);\n });\n\n if (signal) {\n signal.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timeout);\n socket.destroy();\n resolve(null);\n },\n { once: true },\n );\n }\n });\n}\n\nfunction splitHostPortParts(addr: string): [string, string] {\n const { host, port } = splitHostPort(addr);\n return [host, port];\n}\n\nfunction getDomainList(host: string): string[] {\n const parts = host.split(\".\");\n const list: string[] = [];\n for (let i = 0; i < parts.length - 1; i++) {\n list.push(parts.slice(i).join(\".\"));\n }\n return list.slice(0, 3);\n}\n\nfunction withSignal<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) return promise;\n return Promise.race([\n promise,\n new Promise<T>((_, reject) =>\n signal.addEventListener(\"abort\", () => reject(signal.reason), { once: true }),\n ),\n ]);\n}\n"],"mappings":"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"}
|
|
@@ -13,6 +13,8 @@ export declare class PacketHandler {
|
|
|
13
13
|
receivedFinalInitAck(): void;
|
|
14
14
|
sendPacket(pType: PacketType, data: Uint8Array, flags: number): void;
|
|
15
15
|
sendVoicePacket(data: Uint8Array, codec: number): void;
|
|
16
|
+
/** Send an unencrypted TeamSpeak voice whisper packet to up to 32 clients. */
|
|
17
|
+
sendWhisperPacket(data: Uint8Array, targetClientIds: number[], codec: number): void;
|
|
16
18
|
close(): void;
|
|
17
19
|
}
|
|
18
20
|
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/transport/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,IAAI,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/transport/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,IAAI,SAAS,EAAE,MAAM,YAAY,CAAC;AAGpE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EACL,KAAK,MAAM,EACX,UAAU,EAMX,MAAM,aAAa,CAAC;AAyBrB,qBAAa,aAAa;;IACxB,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IAC9C,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;gBAyB1C,KAAK,EAAE,KAAK,EAAE,MAAM,GAAE,MAAmB;IAKrD,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI7B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBpC,KAAK,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IAkC5B,oBAAoB,IAAI,IAAI;IAI5B,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IASpE,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IA+BtD,8EAA8E;IAC9E,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IA0CnF,KAAK,IAAI,IAAI;CA8cd"}
|
package/dist/transport/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../handler-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../handler-DuwoO5RC.cjs");exports.GenerationWindow=e.r,exports.PacketFlags=e.i,exports.PacketHandler=e.t,exports.PacketType=e.a,exports.Qlz=e.n,exports.buildC2SHeader=e.o,exports.isUnencrypted=e.s,exports.packetFlags=e.c,exports.packetType=e.l,exports.parseC2SHeader=e.u,exports.parseS2CHeader=e.d;
|
package/dist/transport/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as e, c as t, d as n, i as r, l as i, n as a, o, r as s, s as c, t as l, u } from "../handler-
|
|
1
|
+
import { a as e, c as t, d as n, i as r, l as i, n as a, o, r as s, s as c, t as l, u } from "../handler-DI_abe9c.js";
|
|
2
2
|
export { s as GenerationWindow, r as PacketFlags, l as PacketHandler, e as PacketType, a as Qlz, o as buildC2SHeader, c as isUnencrypted, t as packetFlags, i as packetType, u as parseC2SHeader, n as parseS2CHeader };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whisper.test.d.ts","sourceRoot":"","sources":["../../src/transport/whisper.test.ts"],"names":[],"mappings":""}
|
package/dist/types.d.ts
CHANGED
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,wDAAwD;AACxD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,SAAS,EAAE,OAAO,MAAM,CAAA;CAAE,CAAC;AAI3E,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@honeybbq/teamspeak-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "TeamSpeak 3 client SDK for Node.js — a clean-room TypeScript port of the Go reference implementation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"client",
|
|
@@ -71,14 +71,14 @@
|
|
|
71
71
|
"@noble/curves": "^2.0.1"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
-
"@types/node": "^
|
|
75
|
-
"oxfmt": "^0.
|
|
74
|
+
"@types/node": "^26.1.1",
|
|
75
|
+
"oxfmt": "^0.68.0",
|
|
76
76
|
"oxlint": "^1.59.0",
|
|
77
77
|
"tsx": "^4.21.0",
|
|
78
78
|
"typescript": "^6.0.2",
|
|
79
79
|
"vite": "^8.0.8",
|
|
80
80
|
"vite-plugin-dts": "^5.0.0",
|
|
81
|
-
"vitest": "^
|
|
81
|
+
"vitest": "^5.0.0"
|
|
82
82
|
},
|
|
83
83
|
"engines": {
|
|
84
84
|
"node": ">=20.19"
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
var e=[[`\\`,`\\\\`],[`/`,`\\/`],[` `,`\\s`],[`|`,`\\p`],[`\x07`,`\\a`],[`\b`,`\\b`],[`\f`,`\\f`],[`
|
|
2
|
-
`,`\\n`],[`\r`,`\\r`],[` `,`\\t`],[`\v`,`\\v`]];function t(t){let n=t;for(let[t,r]of e)n=n.split(t).join(r);return n}function n(e){let t=``,n=0;for(;n<e.length;)if(e[n]===`\\`&&n+1<e.length)switch(e[n+1]){case`\\`:t+=`\\`,n+=2;break;case`/`:t+=`/`,n+=2;break;case`s`:t+=` `,n+=2;break;case`p`:t+=`|`,n+=2;break;case`a`:t+=`\x07`,n+=2;break;case`b`:t+=`\b`,n+=2;break;case`f`:t+=`\f`,n+=2;break;case`n`:t+=`
|
|
3
|
-
`,n+=2;break;case`r`:t+=`\r`,n+=2;break;case`t`:t+=` `,n+=2;break;case`v`:t+=`\v`,n+=2;break;default:t+=e[n]??``,n++;break}else t+=e[n]??``,n++;return t}function r(e,n){let r=[t(e)];for(let[e,i]of Object.entries(n))r.push(`${e}=${t(i)}`);return r.join(` `)}function i(e,n){let r=[t(e)];for(let[e,i]of n)r.push(`${e}=${t(i)}`);return r.join(` `)}Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return r}});
|
|
4
|
-
//# sourceMappingURL=command-CUPNiKRl.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"crypto-CwIMggQG.js","names":["#key","#cmac","#cachedKeys","#getSharedSecret"],"sources":["../src/crypto/eax.ts","../src/crypto/crypt.ts"],"sourcesContent":["import { createCipheriv, timingSafeEqual } from \"node:crypto\";\nimport { EAXTagMismatchError } from \"../errors.js\";\n\nconst EAX_TAG_SIZE = 8;\nconst EAX_BLOCK_SIZE = 16;\n\n/**\n * AES-EAX AEAD implementation for TS3 (64-bit tag, AES-128).\n * Uses AES-CMAC for authentication and AES-CTR for encryption.\n */\nexport class EAX {\n readonly #key: Uint8Array;\n\n constructor(key: Uint8Array) {\n if (key.length !== 16) throw new Error(\"EAX requires a 16-byte key\");\n this.#key = key;\n }\n\n encrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n plaintext: Uint8Array,\n ): [ciphertext: Uint8Array, tag: Uint8Array] {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n\n const ciphertext = aesCtr(this.#key, nStar, plaintext);\n\n const cStar = this.#cmac(2, ciphertext);\n\n const tag = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n tag[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n return [ciphertext, tag];\n }\n\n decrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n ): Uint8Array {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n const cStar = this.#cmac(2, ciphertext);\n\n const expected = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n expected[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n if (!timingSafeEqual(Buffer.from(expected), Buffer.from(tag.slice(0, EAX_TAG_SIZE)))) {\n throw new EAXTagMismatchError();\n }\n\n return aesCtr(this.#key, nStar, ciphertext);\n }\n\n /**\n * AES-CMAC per RFC 4493:\n * input = [0…0 tag] ++ data (one block prefix)\n */\n #cmac(tagByte: number, data: Uint8Array): Uint8Array {\n const input = new Uint8Array(EAX_BLOCK_SIZE + data.length);\n // first block: zeros then tag byte at the last position\n input[EAX_BLOCK_SIZE - 1] = tagByte;\n input.set(data, EAX_BLOCK_SIZE);\n\n return aesCmac(this.#key, input);\n }\n}\n\n// ---- AES-CTR ----------------------------------------------------------------\n\nfunction aesCtr(key: Uint8Array, iv: Uint8Array, data: Uint8Array): Uint8Array {\n const cipher = createCipheriv(\"aes-128-ctr\", Buffer.from(key), Buffer.from(iv));\n return Buffer.concat([cipher.update(Buffer.from(data)), cipher.final()]);\n}\n\n// ---- AES-CMAC (RFC 4493) ----------------------------------------------------\n\nfunction aesEcb(key: Uint8Array, block: Uint8Array): Uint8Array {\n // Node.js does not expose ECB directly; simulate via CTR with zero IV and\n // a zero-input (CTR of 0-block XOR with input = ECB)\n const cipher = createCipheriv(\"aes-128-ecb\", Buffer.from(key), null);\n cipher.setAutoPadding(false);\n return Buffer.concat([cipher.update(Buffer.from(block)), cipher.final()]);\n}\n\nfunction xorBlock(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n for (let i = 0; i < EAX_BLOCK_SIZE; i++) out[i] = a[i]! ^ b[i]!;\n return out;\n}\n\nfunction shiftLeft1(b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n let carry = 0;\n for (let i = EAX_BLOCK_SIZE - 1; i >= 0; i--) {\n const shifted = ((b[i]! << 1) | carry) & 0xff;\n carry = b[i]! >> 7;\n out[i] = shifted;\n }\n return out;\n}\n\nconst RB = new Uint8Array(EAX_BLOCK_SIZE);\nRB[EAX_BLOCK_SIZE - 1] = 0x87;\n\nfunction generateSubkeys(key: Uint8Array): [Uint8Array, Uint8Array] {\n const zero = new Uint8Array(EAX_BLOCK_SIZE);\n const L = aesEcb(key, zero);\n\n let K1 = shiftLeft1(L);\n if ((L[0]! & 0x80) !== 0) K1 = xorBlock(K1, RB);\n\n let K2 = shiftLeft1(K1);\n if ((K1[0]! & 0x80) !== 0) K2 = xorBlock(K2, RB);\n\n return [K1, K2];\n}\n\nexport function aesCmac(key: Uint8Array, message: Uint8Array): Uint8Array {\n const [K1, K2] = generateSubkeys(key);\n\n const n = Math.max(1, Math.ceil(message.length / EAX_BLOCK_SIZE));\n const lastBlockComplete = message.length > 0 && message.length % EAX_BLOCK_SIZE === 0;\n\n let X: Uint8Array = new Uint8Array(EAX_BLOCK_SIZE);\n\n for (let i = 0; i < n - 1; i++) {\n const block = message.slice(i * EAX_BLOCK_SIZE, (i + 1) * EAX_BLOCK_SIZE);\n X = Uint8Array.from(aesEcb(key, xorBlock(X, block)));\n }\n\n const lastBlock = new Uint8Array(EAX_BLOCK_SIZE);\n const lastStart = (n - 1) * EAX_BLOCK_SIZE;\n const lastSlice = message.slice(lastStart);\n lastBlock.set(lastSlice);\n\n let Mn: Uint8Array;\n if (lastBlockComplete) {\n Mn = xorBlock(lastBlock, K1);\n } else {\n if (lastSlice.length < EAX_BLOCK_SIZE) lastBlock[lastSlice.length] = 0x80;\n Mn = xorBlock(lastBlock, K2);\n }\n\n return Uint8Array.from(aesEcb(key, xorBlock(X, Mn)));\n}\n","import { createHash, createECDH } from \"node:crypto\";\nimport { FakeSignatureMismatchError } from \"../errors.js\";\nimport type { Identity } from \"./identity.js\";\nimport { importPublicKey } from \"./identity.js\";\nimport { EAX } from \"./eax.js\";\n\nconst FAKE_SIGNATURE_SIZE = 8;\nconst IV_ALPHA_SIZE = 10;\nconst INIT1_PACKET_TYPE = 8;\nconst PACKET_TYPE_MASK = 0x0f;\n\nconst INIT1_MAC = Buffer.from(\"TS3INIT1\");\n\nexport interface KeyNonce {\n key: Uint8Array;\n nonce: Uint8Array;\n gen: number;\n}\n\n/** Precomputed dummy key/nonce matching the TS3 client pre-crypto placeholder. */\nconst DUMMY_KEY = Buffer.from(\"c:\\\\windows\\\\syste\");\nconst DUMMY_NONCE = Buffer.from(\"m\\\\firewall32.cpl\");\n\nexport class Crypt {\n readonly identity: Identity;\n\n ivStruct: Uint8Array = new Uint8Array(0);\n fakeSignature: Uint8Array = new Uint8Array(FAKE_SIGNATURE_SIZE);\n alphaTmp: Uint8Array = new Uint8Array(0);\n cryptoInitComplete = false;\n\n readonly #cachedKeys = new Map<bigint, KeyNonce>();\n\n constructor(identity: Identity) {\n this.identity = identity;\n }\n\n solveRsaChallenge(data: Uint8Array, offset: number, level: number): Uint8Array {\n if (level < 0 || level > 1_000_000) {\n throw new Error(\"RSA challenge level out of range\");\n }\n\n const xBytes = data.slice(offset, offset + 64);\n const nBytes = data.slice(offset + 64, offset + 128);\n\n let y = bytesToBigInt(xBytes);\n const n = bytesToBigInt(nBytes);\n\n for (let i = 0; i < level; i++) {\n y = (y * y) % n;\n }\n\n return bigIntToBytes(y, 64);\n }\n\n initCrypto(alpha: string, beta: string, omega: string): void {\n const alphaBytes = Buffer.from(alpha, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n\n const serverPubKey = importPublicKey(omegaBytes);\n const sharedSecret = this.#getSharedSecret(serverPubKey);\n\n this.setSharedSecret(alphaBytes, betaBytes, sharedSecret);\n }\n\n setSharedSecret(alpha: Uint8Array, beta: Uint8Array, sharedKey: Uint8Array): void {\n this.ivStruct = new Uint8Array(IV_ALPHA_SIZE + beta.length);\n for (let i = 0; i < IV_ALPHA_SIZE; i++) {\n const a = sharedKey[i];\n const b = alpha[i];\n this.ivStruct[i] = ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n for (let i = 0; i < beta.length; i++) {\n const a = sharedKey[IV_ALPHA_SIZE + i];\n const b = beta[i];\n this.ivStruct[IV_ALPHA_SIZE + i] =\n ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n\n const digest = createHash(\"sha1\").update(this.ivStruct).digest();\n this.fakeSignature = new Uint8Array(digest.buffer, digest.byteOffset, FAKE_SIGNATURE_SIZE);\n this.cryptoInitComplete = true;\n }\n\n getKeyNonce(\n fromServer: boolean,\n packetID: number,\n generationID: number,\n packetType: number,\n dummy: boolean,\n ): [key: Uint8Array, nonce: Uint8Array] {\n if (dummy) {\n return [Uint8Array.from(DUMMY_KEY), Uint8Array.from(DUMMY_NONCE)];\n }\n\n const cacheKey = makeCacheKey(fromServer, packetType, generationID);\n let kn = this.#cachedKeys.get(cacheKey);\n\n if (kn === undefined) {\n const tmpToHash = new Uint8Array(6 + this.ivStruct.length);\n tmpToHash[0] = fromServer ? 0x30 : 0x31;\n tmpToHash[1] = packetType & PACKET_TYPE_MASK;\n new DataView(tmpToHash.buffer).setUint32(2, generationID, false);\n tmpToHash.set(this.ivStruct, 6);\n\n const hash = createHash(\"sha256\").update(tmpToHash).digest();\n kn = {\n key: Uint8Array.from(hash.slice(0, 16)),\n nonce: Uint8Array.from(hash.slice(16, 32)),\n gen: generationID,\n };\n this.#cachedKeys.set(cacheKey, kn);\n }\n\n const key = Uint8Array.from(kn.key);\n key[0] = (key[0] !== undefined ? key[0] : 0) ^ ((packetID >> 8) & 0xff);\n key[1] = (key[1] !== undefined ? key[1] : 0) ^ (packetID & 0xff);\n\n return [key, kn.nonce];\n }\n\n encrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n plaintext: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): [ciphertext: Uint8Array, mac: Uint8Array] {\n if (packetType === INIT1_PACKET_TYPE) {\n return [plaintext, INIT1_MAC];\n }\n if (unencrypted) {\n return [plaintext, this.fakeSignature];\n }\n\n const [key, nonce] = this.getKeyNonce(false, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.encrypt(nonce, header, plaintext);\n }\n\n decrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): Uint8Array {\n if (packetType === INIT1_PACKET_TYPE) {\n return ciphertext;\n }\n if (unencrypted) {\n const fsSub = tag.slice(0, FAKE_SIGNATURE_SIZE);\n if (!Buffer.from(fsSub).equals(Buffer.from(this.fakeSignature))) {\n throw new FakeSignatureMismatchError();\n }\n return ciphertext;\n }\n\n const [key, nonce] = this.getKeyNonce(true, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.decrypt(nonce, header, ciphertext, tag);\n }\n\n #getSharedSecret(serverPubKey: import(\"node:crypto\").KeyObject): Uint8Array {\n const privJwk = this.identity.privateKey.export({ format: \"jwk\" }) as {\n d: string;\n };\n const pubJwk = serverPubKey.export({ format: \"jwk\" }) as {\n x: string;\n y: string;\n };\n\n const ecdh = createECDH(\"prime256v1\");\n const dBytes = Buffer.from(privJwk.d, \"base64url\");\n ecdh.setPrivateKey(dBytes);\n\n const xBytes = base64UrlToBytes(pubJwk.x, 32);\n const yBytes = base64UrlToBytes(pubJwk.y, 32);\n const uncompressed = Buffer.alloc(65);\n uncompressed[0] = 0x04;\n xBytes.copy(uncompressed, 1);\n yBytes.copy(uncompressed, 33);\n\n const rawSecret = ecdh.computeSecret(uncompressed);\n return createHash(\"sha1\").update(rawSecret).digest();\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\nfunction makeCacheKey(fromServer: boolean, packetType: number, generationID: number): bigint {\n let key = 0n;\n if (fromServer) key |= 1n << 40n;\n key |= BigInt(packetType & PACKET_TYPE_MASK) << 32n;\n key |= BigInt(generationID);\n return key;\n}\n\nfunction bytesToBigInt(bytes: Uint8Array): bigint {\n let result = 0n;\n for (const b of bytes) result = (result << 8n) | BigInt(b);\n return result;\n}\n\nfunction bigIntToBytes(value: bigint, size: number): Uint8Array {\n const result = new Uint8Array(size);\n let v = value;\n for (let i = size - 1; i >= 0; i--) {\n result[i] = Number(v & 0xffn);\n v >>= 8n;\n }\n return result;\n}\n\nfunction base64UrlToBytes(b64url: string, size: number): Buffer {\n const buf = Buffer.from(b64url, \"base64url\");\n if (buf.length === size) return buf;\n const padded = Buffer.alloc(size);\n buf.copy(padded, size - buf.length);\n return padded;\n}\n"],"mappings":"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"}
|
package/dist/crypto-IbzNNTgO.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require("./primitives-ClIhDdNZ.cjs");let t=require("node:crypto");var n=8,r=16,i=class{#e;constructor(e){if(e.length!==16)throw Error(`EAX requires a 16-byte key`);this.#e=e}encrypt(e,t,r){let i=this.#t(0,e),o=this.#t(1,t),s=a(this.#e,i,r),c=this.#t(2,s),l=new Uint8Array(n);for(let e=0;e<n;e++)l[e]=i[e]^o[e]^c[e];return[s,l]}decrypt(r,i,o,s){let c=this.#t(0,r),l=this.#t(1,i),u=this.#t(2,o),d=new Uint8Array(n);for(let e=0;e<n;e++)d[e]=c[e]^l[e]^u[e];if(!(0,t.timingSafeEqual)(Buffer.from(d),Buffer.from(s.slice(0,n))))throw new e.v;return a(this.#e,c,o)}#t(e,t){let n=new Uint8Array(r+t.length);return n[r-1]=e,n.set(t,r),d(this.#e,n)}};function a(e,n,r){let i=(0,t.createCipheriv)(`aes-128-ctr`,Buffer.from(e),Buffer.from(n));return Buffer.concat([i.update(Buffer.from(r)),i.final()])}function o(e,n){let r=(0,t.createCipheriv)(`aes-128-ecb`,Buffer.from(e),null);return r.setAutoPadding(!1),Buffer.concat([r.update(Buffer.from(n)),r.final()])}function s(e,t){let n=new Uint8Array(r);for(let i=0;i<r;i++)n[i]=e[i]^t[i];return n}function c(e){let t=new Uint8Array(r),n=0;for(let i=r-1;i>=0;i--){let r=(e[i]<<1|n)&255;n=e[i]>>7,t[i]=r}return t}var l=new Uint8Array(r);l[r-1]=135;function u(e){let t=o(e,new Uint8Array(r)),n=c(t);t[0]&128&&(n=s(n,l));let i=c(n);return n[0]&128&&(i=s(i,l)),[n,i]}function d(e,t){let[n,i]=u(e),a=Math.max(1,Math.ceil(t.length/r)),c=t.length>0&&t.length%r===0,l=new Uint8Array(r);for(let n=0;n<a-1;n++){let i=t.slice(n*r,(n+1)*r);l=Uint8Array.from(o(e,s(l,i)))}let d=new Uint8Array(r),f=(a-1)*r,p=t.slice(f);d.set(p);let m;return c?m=s(d,n):(p.length<r&&(d[p.length]=128),m=s(d,i)),Uint8Array.from(o(e,s(l,m)))}var f=8,p=10,m=8,h=15,g=Buffer.from(`TS3INIT1`),_=Buffer.from(`c:\\windows\\syste`),v=Buffer.from(`m\\firewall32.cpl`),y=class{identity;ivStruct=new Uint8Array;fakeSignature=new Uint8Array(f);alphaTmp=new Uint8Array;cryptoInitComplete=!1;#e=new Map;constructor(e){this.identity=e}solveRsaChallenge(e,t,n){if(n<0||n>1e6)throw Error(`RSA challenge level out of range`);let r=e.slice(t,t+64),i=e.slice(t+64,t+128),a=x(r),o=x(i);for(let e=0;e<n;e++)a=a*a%o;return S(a,64)}initCrypto(t,n,r){let i=Buffer.from(t,`base64`),a=Buffer.from(n,`base64`),o=e.m(Buffer.from(r,`base64`)),s=this.#t(o);this.setSharedSecret(i,a,s)}setSharedSecret(e,n,r){this.ivStruct=new Uint8Array(p+n.length);for(let t=0;t<p;t++){let n=r[t],i=e[t];this.ivStruct[t]=((n===void 0?0:n)^(i===void 0?0:i))&255}for(let e=0;e<n.length;e++){let t=r[p+e],i=n[e];this.ivStruct[p+e]=((t===void 0?0:t)^(i===void 0?0:i))&255}let i=(0,t.createHash)(`sha1`).update(this.ivStruct).digest();this.fakeSignature=new Uint8Array(i.buffer,i.byteOffset,f),this.cryptoInitComplete=!0}getKeyNonce(e,n,r,i,a){if(a)return[Uint8Array.from(_),Uint8Array.from(v)];let o=b(e,i,r),s=this.#e.get(o);if(s===void 0){let n=new Uint8Array(6+this.ivStruct.length);n[0]=e?48:49,n[1]=i&h,new DataView(n.buffer).setUint32(2,r,!1),n.set(this.ivStruct,6);let a=(0,t.createHash)(`sha256`).update(n).digest();s={key:Uint8Array.from(a.slice(0,16)),nonce:Uint8Array.from(a.slice(16,32)),gen:r},this.#e.set(o,s)}let c=Uint8Array.from(s.key);return c[0]=(c[0]===void 0?0:c[0])^n>>8&255,c[1]=(c[1]===void 0?0:c[1])^n&255,[c,s.nonce]}encrypt(e,t,n,r,a,o,s){if(e===m)return[a,g];if(s)return[a,this.fakeSignature];let[c,l]=this.getKeyNonce(!1,t,n,e,o);return new i(c).encrypt(l,r,a)}decrypt(t,n,r,a,o,s,c,l){if(t===m)return o;if(l){let t=s.slice(0,f);if(!Buffer.from(t).equals(Buffer.from(this.fakeSignature)))throw new e.y;return o}let[u,d]=this.getKeyNonce(!0,n,r,t,c);return new i(u).decrypt(d,a,o,s)}#t(e){let n=this.identity.privateKey.export({format:`jwk`}),r=e.export({format:`jwk`}),i=(0,t.createECDH)(`prime256v1`),a=Buffer.from(n.d,`base64url`);i.setPrivateKey(a);let o=C(r.x,32),s=C(r.y,32),c=Buffer.alloc(65);c[0]=4,o.copy(c,1),s.copy(c,33);let l=i.computeSecret(c);return(0,t.createHash)(`sha1`).update(l).digest()}};function b(e,t,n){let r=0n;return e&&(r|=1n<<40n),r|=BigInt(t&h)<<32n,r|=BigInt(n),r}function x(e){let t=0n;for(let n of e)t=t<<8n|BigInt(n);return t}function S(e,t){let n=new Uint8Array(t),r=e;for(let e=t-1;e>=0;e--)n[e]=Number(r&255n),r>>=8n;return n}function C(e,t){let n=Buffer.from(e,`base64url`);if(n.length===t)return n;let r=Buffer.alloc(t);return n.copy(r,t-n.length),r}Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return y}});
|
|
2
|
-
//# sourceMappingURL=crypto-IbzNNTgO.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"crypto-IbzNNTgO.cjs","names":["#key","#cmac","#cachedKeys","#getSharedSecret"],"sources":["../src/crypto/eax.ts","../src/crypto/crypt.ts"],"sourcesContent":["import { createCipheriv, timingSafeEqual } from \"node:crypto\";\nimport { EAXTagMismatchError } from \"../errors.js\";\n\nconst EAX_TAG_SIZE = 8;\nconst EAX_BLOCK_SIZE = 16;\n\n/**\n * AES-EAX AEAD implementation for TS3 (64-bit tag, AES-128).\n * Uses AES-CMAC for authentication and AES-CTR for encryption.\n */\nexport class EAX {\n readonly #key: Uint8Array;\n\n constructor(key: Uint8Array) {\n if (key.length !== 16) throw new Error(\"EAX requires a 16-byte key\");\n this.#key = key;\n }\n\n encrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n plaintext: Uint8Array,\n ): [ciphertext: Uint8Array, tag: Uint8Array] {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n\n const ciphertext = aesCtr(this.#key, nStar, plaintext);\n\n const cStar = this.#cmac(2, ciphertext);\n\n const tag = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n tag[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n return [ciphertext, tag];\n }\n\n decrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n ): Uint8Array {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n const cStar = this.#cmac(2, ciphertext);\n\n const expected = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n expected[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n if (!timingSafeEqual(Buffer.from(expected), Buffer.from(tag.slice(0, EAX_TAG_SIZE)))) {\n throw new EAXTagMismatchError();\n }\n\n return aesCtr(this.#key, nStar, ciphertext);\n }\n\n /**\n * AES-CMAC per RFC 4493:\n * input = [0…0 tag] ++ data (one block prefix)\n */\n #cmac(tagByte: number, data: Uint8Array): Uint8Array {\n const input = new Uint8Array(EAX_BLOCK_SIZE + data.length);\n // first block: zeros then tag byte at the last position\n input[EAX_BLOCK_SIZE - 1] = tagByte;\n input.set(data, EAX_BLOCK_SIZE);\n\n return aesCmac(this.#key, input);\n }\n}\n\n// ---- AES-CTR ----------------------------------------------------------------\n\nfunction aesCtr(key: Uint8Array, iv: Uint8Array, data: Uint8Array): Uint8Array {\n const cipher = createCipheriv(\"aes-128-ctr\", Buffer.from(key), Buffer.from(iv));\n return Buffer.concat([cipher.update(Buffer.from(data)), cipher.final()]);\n}\n\n// ---- AES-CMAC (RFC 4493) ----------------------------------------------------\n\nfunction aesEcb(key: Uint8Array, block: Uint8Array): Uint8Array {\n // Node.js does not expose ECB directly; simulate via CTR with zero IV and\n // a zero-input (CTR of 0-block XOR with input = ECB)\n const cipher = createCipheriv(\"aes-128-ecb\", Buffer.from(key), null);\n cipher.setAutoPadding(false);\n return Buffer.concat([cipher.update(Buffer.from(block)), cipher.final()]);\n}\n\nfunction xorBlock(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n for (let i = 0; i < EAX_BLOCK_SIZE; i++) out[i] = a[i]! ^ b[i]!;\n return out;\n}\n\nfunction shiftLeft1(b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n let carry = 0;\n for (let i = EAX_BLOCK_SIZE - 1; i >= 0; i--) {\n const shifted = ((b[i]! << 1) | carry) & 0xff;\n carry = b[i]! >> 7;\n out[i] = shifted;\n }\n return out;\n}\n\nconst RB = new Uint8Array(EAX_BLOCK_SIZE);\nRB[EAX_BLOCK_SIZE - 1] = 0x87;\n\nfunction generateSubkeys(key: Uint8Array): [Uint8Array, Uint8Array] {\n const zero = new Uint8Array(EAX_BLOCK_SIZE);\n const L = aesEcb(key, zero);\n\n let K1 = shiftLeft1(L);\n if ((L[0]! & 0x80) !== 0) K1 = xorBlock(K1, RB);\n\n let K2 = shiftLeft1(K1);\n if ((K1[0]! & 0x80) !== 0) K2 = xorBlock(K2, RB);\n\n return [K1, K2];\n}\n\nexport function aesCmac(key: Uint8Array, message: Uint8Array): Uint8Array {\n const [K1, K2] = generateSubkeys(key);\n\n const n = Math.max(1, Math.ceil(message.length / EAX_BLOCK_SIZE));\n const lastBlockComplete = message.length > 0 && message.length % EAX_BLOCK_SIZE === 0;\n\n let X: Uint8Array = new Uint8Array(EAX_BLOCK_SIZE);\n\n for (let i = 0; i < n - 1; i++) {\n const block = message.slice(i * EAX_BLOCK_SIZE, (i + 1) * EAX_BLOCK_SIZE);\n X = Uint8Array.from(aesEcb(key, xorBlock(X, block)));\n }\n\n const lastBlock = new Uint8Array(EAX_BLOCK_SIZE);\n const lastStart = (n - 1) * EAX_BLOCK_SIZE;\n const lastSlice = message.slice(lastStart);\n lastBlock.set(lastSlice);\n\n let Mn: Uint8Array;\n if (lastBlockComplete) {\n Mn = xorBlock(lastBlock, K1);\n } else {\n if (lastSlice.length < EAX_BLOCK_SIZE) lastBlock[lastSlice.length] = 0x80;\n Mn = xorBlock(lastBlock, K2);\n }\n\n return Uint8Array.from(aesEcb(key, xorBlock(X, Mn)));\n}\n","import { createHash, createECDH } from \"node:crypto\";\nimport { FakeSignatureMismatchError } from \"../errors.js\";\nimport type { Identity } from \"./identity.js\";\nimport { importPublicKey } from \"./identity.js\";\nimport { EAX } from \"./eax.js\";\n\nconst FAKE_SIGNATURE_SIZE = 8;\nconst IV_ALPHA_SIZE = 10;\nconst INIT1_PACKET_TYPE = 8;\nconst PACKET_TYPE_MASK = 0x0f;\n\nconst INIT1_MAC = Buffer.from(\"TS3INIT1\");\n\nexport interface KeyNonce {\n key: Uint8Array;\n nonce: Uint8Array;\n gen: number;\n}\n\n/** Precomputed dummy key/nonce matching the TS3 client pre-crypto placeholder. */\nconst DUMMY_KEY = Buffer.from(\"c:\\\\windows\\\\syste\");\nconst DUMMY_NONCE = Buffer.from(\"m\\\\firewall32.cpl\");\n\nexport class Crypt {\n readonly identity: Identity;\n\n ivStruct: Uint8Array = new Uint8Array(0);\n fakeSignature: Uint8Array = new Uint8Array(FAKE_SIGNATURE_SIZE);\n alphaTmp: Uint8Array = new Uint8Array(0);\n cryptoInitComplete = false;\n\n readonly #cachedKeys = new Map<bigint, KeyNonce>();\n\n constructor(identity: Identity) {\n this.identity = identity;\n }\n\n solveRsaChallenge(data: Uint8Array, offset: number, level: number): Uint8Array {\n if (level < 0 || level > 1_000_000) {\n throw new Error(\"RSA challenge level out of range\");\n }\n\n const xBytes = data.slice(offset, offset + 64);\n const nBytes = data.slice(offset + 64, offset + 128);\n\n let y = bytesToBigInt(xBytes);\n const n = bytesToBigInt(nBytes);\n\n for (let i = 0; i < level; i++) {\n y = (y * y) % n;\n }\n\n return bigIntToBytes(y, 64);\n }\n\n initCrypto(alpha: string, beta: string, omega: string): void {\n const alphaBytes = Buffer.from(alpha, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n\n const serverPubKey = importPublicKey(omegaBytes);\n const sharedSecret = this.#getSharedSecret(serverPubKey);\n\n this.setSharedSecret(alphaBytes, betaBytes, sharedSecret);\n }\n\n setSharedSecret(alpha: Uint8Array, beta: Uint8Array, sharedKey: Uint8Array): void {\n this.ivStruct = new Uint8Array(IV_ALPHA_SIZE + beta.length);\n for (let i = 0; i < IV_ALPHA_SIZE; i++) {\n const a = sharedKey[i];\n const b = alpha[i];\n this.ivStruct[i] = ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n for (let i = 0; i < beta.length; i++) {\n const a = sharedKey[IV_ALPHA_SIZE + i];\n const b = beta[i];\n this.ivStruct[IV_ALPHA_SIZE + i] =\n ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n\n const digest = createHash(\"sha1\").update(this.ivStruct).digest();\n this.fakeSignature = new Uint8Array(digest.buffer, digest.byteOffset, FAKE_SIGNATURE_SIZE);\n this.cryptoInitComplete = true;\n }\n\n getKeyNonce(\n fromServer: boolean,\n packetID: number,\n generationID: number,\n packetType: number,\n dummy: boolean,\n ): [key: Uint8Array, nonce: Uint8Array] {\n if (dummy) {\n return [Uint8Array.from(DUMMY_KEY), Uint8Array.from(DUMMY_NONCE)];\n }\n\n const cacheKey = makeCacheKey(fromServer, packetType, generationID);\n let kn = this.#cachedKeys.get(cacheKey);\n\n if (kn === undefined) {\n const tmpToHash = new Uint8Array(6 + this.ivStruct.length);\n tmpToHash[0] = fromServer ? 0x30 : 0x31;\n tmpToHash[1] = packetType & PACKET_TYPE_MASK;\n new DataView(tmpToHash.buffer).setUint32(2, generationID, false);\n tmpToHash.set(this.ivStruct, 6);\n\n const hash = createHash(\"sha256\").update(tmpToHash).digest();\n kn = {\n key: Uint8Array.from(hash.slice(0, 16)),\n nonce: Uint8Array.from(hash.slice(16, 32)),\n gen: generationID,\n };\n this.#cachedKeys.set(cacheKey, kn);\n }\n\n const key = Uint8Array.from(kn.key);\n key[0] = (key[0] !== undefined ? key[0] : 0) ^ ((packetID >> 8) & 0xff);\n key[1] = (key[1] !== undefined ? key[1] : 0) ^ (packetID & 0xff);\n\n return [key, kn.nonce];\n }\n\n encrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n plaintext: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): [ciphertext: Uint8Array, mac: Uint8Array] {\n if (packetType === INIT1_PACKET_TYPE) {\n return [plaintext, INIT1_MAC];\n }\n if (unencrypted) {\n return [plaintext, this.fakeSignature];\n }\n\n const [key, nonce] = this.getKeyNonce(false, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.encrypt(nonce, header, plaintext);\n }\n\n decrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): Uint8Array {\n if (packetType === INIT1_PACKET_TYPE) {\n return ciphertext;\n }\n if (unencrypted) {\n const fsSub = tag.slice(0, FAKE_SIGNATURE_SIZE);\n if (!Buffer.from(fsSub).equals(Buffer.from(this.fakeSignature))) {\n throw new FakeSignatureMismatchError();\n }\n return ciphertext;\n }\n\n const [key, nonce] = this.getKeyNonce(true, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.decrypt(nonce, header, ciphertext, tag);\n }\n\n #getSharedSecret(serverPubKey: import(\"node:crypto\").KeyObject): Uint8Array {\n const privJwk = this.identity.privateKey.export({ format: \"jwk\" }) as {\n d: string;\n };\n const pubJwk = serverPubKey.export({ format: \"jwk\" }) as {\n x: string;\n y: string;\n };\n\n const ecdh = createECDH(\"prime256v1\");\n const dBytes = Buffer.from(privJwk.d, \"base64url\");\n ecdh.setPrivateKey(dBytes);\n\n const xBytes = base64UrlToBytes(pubJwk.x, 32);\n const yBytes = base64UrlToBytes(pubJwk.y, 32);\n const uncompressed = Buffer.alloc(65);\n uncompressed[0] = 0x04;\n xBytes.copy(uncompressed, 1);\n yBytes.copy(uncompressed, 33);\n\n const rawSecret = ecdh.computeSecret(uncompressed);\n return createHash(\"sha1\").update(rawSecret).digest();\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\nfunction makeCacheKey(fromServer: boolean, packetType: number, generationID: number): bigint {\n let key = 0n;\n if (fromServer) key |= 1n << 40n;\n key |= BigInt(packetType & PACKET_TYPE_MASK) << 32n;\n key |= BigInt(generationID);\n return key;\n}\n\nfunction bytesToBigInt(bytes: Uint8Array): bigint {\n let result = 0n;\n for (const b of bytes) result = (result << 8n) | BigInt(b);\n return result;\n}\n\nfunction bigIntToBytes(value: bigint, size: number): Uint8Array {\n const result = new Uint8Array(size);\n let v = value;\n for (let i = size - 1; i >= 0; i--) {\n result[i] = Number(v & 0xffn);\n v >>= 8n;\n }\n return result;\n}\n\nfunction base64UrlToBytes(b64url: string, size: number): Buffer {\n const buf = Buffer.from(b64url, \"base64url\");\n if (buf.length === size) return buf;\n const padded = Buffer.alloc(size);\n buf.copy(padded, size - buf.length);\n return padded;\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require("./types-ANvuLFWH.cjs"),t=require("./crypt-handshake-D2Rsi2e3.cjs");let n=require("node:dgram");var r=function(e){return e[e.Voice=0]=`Voice`,e[e.VoiceWhisper=1]=`VoiceWhisper`,e[e.Command=2]=`Command`,e[e.CommandLow=3]=`CommandLow`,e[e.Ping=4]=`Ping`,e[e.Pong=5]=`Pong`,e[e.Ack=6]=`Ack`,e[e.AckLow=7]=`AckLow`,e[e.Init1=8]=`Init1`,e}({}),i=function(e){return e[e.Fragmented=16]=`Fragmented`,e[e.NewProtocol=32]=`NewProtocol`,e[e.Compressed=64]=`Compressed`,e[e.Unencrypted=128]=`Unencrypted`,e}({});function a(e){return e.typeFlagged&15}function o(e){return e.typeFlagged&240}function s(e){return(o(e)&128)!=0}function c(e){let t=new Uint8Array(5),n=new DataView(t.buffer);return n.setUint16(0,e.id,!1),n.setUint16(2,e.clientID,!1),t[4]=e.typeFlagged,t}function l(e){return{id:new DataView(e.buffer,e.byteOffset,e.byteLength).getUint16(0,!1),typeFlagged:e[2]}}function u(e){let t=new DataView(e.buffer,e.byteOffset,e.byteLength);return{id:t.getUint16(0,!1),clientID:t.getUint16(2,!1),typeFlagged:e[4]}}var d=class{#e=0;#t=0;#n;#r;constructor(e,t){this.#n=e,this.#r=t}get generation(){return this.#t}advance(e){if(e<=0)return;let t=this.#e+e,n=Math.floor(t/this.#n);n>0&&(this.#t=Math.min(this.#t+n,4294967295)),this.#e=t%this.#n}advanceToExcluded(e){let t=e-this.#e;t<0&&(t+=this.#n),this.advance(t+1)}syncTo(e){let t=e-this.#e;t<0&&(t+=this.#n),this.advance(t)}isInWindow(e){let t=this.#e+this.#r;return t<this.#n?e>=this.#e&&e<t:e>=this.#e||e<t-this.#n}mappedToIndex(e){return this.#i(e)?e+this.#n-this.#e:e-this.#e}isOldPacket(e){return this.mappedToIndex(e)<0}isFuturePacket(e){return this.mappedToIndex(e)>=this.#r}#i(e){return this.#e>this.#n-this.#r&&e<this.#e+this.#r-this.#n}getGeneration(e){return this.#i(e)?this.#t+1:this.#t}reset(){this.#e=0,this.#t=0}},f=4096,p=class{#e=new Int32Array(f);decompress(e){let{headerLen:t,decompressedSize:n,flags:r}=m(e),i=new Uint8Array(n);if(!(r&1))return i.set(e.slice(t,t+n)),i;this.#e.fill(0);let a={control:1,sourcePos:t,destPos:0,nextHashed:0};for(;this.#t(e,a);)if(a.control&1){if(!this.#n(e,i,a))break}else if(this.#r(e,i,n,a))break;return i}#t(e,t){return t.control===1?t.sourcePos+4>e.length?!1:(t.control=(e[t.sourcePos]|e[t.sourcePos+1]<<8|e[t.sourcePos+2]<<16|e[t.sourcePos+3]<<24)>>>0,t.sourcePos+=4,!0):!0}#n(e,t,n){if(n.control=n.control>>>1>>>0,n.sourcePos+2>e.length)return!1;let r=e[n.sourcePos],i=e[n.sourcePos+1];n.sourcePos+=2;let a=r>>4|i<<4,o=r&15;if(o!==0)o+=2;else{if(n.sourcePos>=e.length)return!1;o=e[n.sourcePos],n.sourcePos++}let s=this.#e[a];for(let e=0;e<o;e++)n.destPos<t.length&&s+e<n.destPos&&(t[n.destPos]=t[s+e],n.destPos++);let c=n.destPos+1-o;return this.#i(t,n,c),n.nextHashed=n.destPos,!0}#r(e,t,n,r){let i=Math.max(n,10)-10;if(r.destPos>=i){for(;r.destPos<n;){if(r.control===1){if(r.sourcePos+=4,r.sourcePos>e.length)break;r.control=(e[r.sourcePos-4]|e[r.sourcePos-3]<<8|e[r.sourcePos-2]<<16|e[r.sourcePos-1]<<24)>>>0}if(r.sourcePos>=e.length)break;t[r.destPos++]=e[r.sourcePos++],r.control=r.control>>>1>>>0}return!0}if(r.sourcePos>=e.length||r.destPos>=t.length)return!0;t[r.destPos++]=e[r.sourcePos++],r.control=r.control>>>1>>>0;let a=Math.max(r.destPos-2,0);return this.#i(t,r,a),r.nextHashed<a&&(r.nextHashed=a),!1}#i(e,t,n){for(;t.nextHashed<n&&!(t.nextHashed+3>e.length);){let n=(e[t.nextHashed]|e[t.nextHashed+1]<<8|e[t.nextHashed+2]<<16)>>>0,r=(n>>12^n)&4095;this.#e[r]=t.nextHashed,t.nextHashed++}}};function m(e){if(e.length<3)throw Error(`QuickLZ: data too short`);let t=e[0];if((t>>2&3)!=1)throw Error(`QuickLZ: only level 1 is supported`);let n=t&2?9:3;if(e.length<n)throw Error(`QuickLZ: data too short for header`);let r;return r=t&2?(e[5]|e[6]<<8|e[7]<<16|e[8]<<24)>>>0:e[2],{headerLen:n,decompressedSize:r,flags:t}}var h=500,g=1024,_=5e3,v=6e4,y=1e3,b=5,x=8,S=3,C=500,w=100,T=class{onPacket=null;onClosed=null;#e;#t;#n=null;#r=0;#i=!1;#a=null;#o=null;#s=Date.now();#c=new Uint16Array(9);#l=new Uint32Array(9);#u=new d(65536,g);#d=new d(65536,g);#f=new d(65536,g);#p=new d(65536,g);#m=new Map;#h=new Map;#g=new Map;#_=null;constructor(t,n=e.r){this.#e=t,this.#t=n}setClientID(e){this.#r=e}connect(e){return new Promise((t,r)=>{let[i,a]=e.lastIndexOf(`:`)>0?[e.slice(0,e.lastIndexOf(`:`)),e.slice(e.lastIndexOf(`:`)+1)]:[e,`9987`],o=parseInt(a,10),s=(0,n.createSocket)(`udp4`);s.once(`error`,r),s.connect(o,i,()=>{s.off(`error`,r),this.start(s),t()})})}start(e){this.#n=e,this.#i=!1,this.#s=Date.now(),e.on(`message`,e=>{this.#s=Date.now(),this.#x(new Uint8Array(e.buffer,e.byteOffset,e.byteLength))}),e.on(`error`,e=>{this.#t.error(`udp error`,e),this.#R(e)}),e.on(`close`,()=>this.#R(null)),this.#c[r.Command]=1,this.#c[r.Init1]=101;let n=t.n(this.#e,null);n&&this.#y(r.Init1,n,0);let a=setInterval(()=>{this.#e.cryptoInitComplete&&this.sendPacket(r.Ping,new Uint8Array,i.Unencrypted)},_);this.#a=()=>clearInterval(a);let o=setInterval(()=>this.#I(),w);this.#o=()=>clearInterval(o)}receivedFinalInitAck(){this.#_=null}sendPacket(e,t,n){let i=!this.#e.cryptoInitComplete;if(t.length>487&&e!==r.Voice&&e!==r.VoiceWhisper){this.#v(e,t,n,i);return}this.#y(e,t,n,i)}sendVoicePacket(e,t){let n=this.#c[r.Voice],a=this.#l[r.Voice];this.#c[r.Voice]=n+1&65535,this.#c[r.Voice]===0&&this.#l[r.Voice]++;let o=S+e.length,s=new Uint8Array(o);new DataView(s.buffer).setUint16(0,n,!1),s[2]=t,s.set(e,S);let l=c({typeFlagged:r.Voice|i.Unencrypted,id:n,clientID:this.#r,generationID:a,data:s,receivedAt:0}),u=new Uint8Array(13+o);u.set(this.#e.fakeSignature,0),u.set(l,x),u.set(s,13),this.#b(u)}close(){this.#i||(this.#i=!0,this.#a?.(),this.#o?.(),this.#n?.close())}#v(e,t,n,r){let a=h-b-x,o=0,s=!0;for(;o<t.length;){let c=Math.min(t.length-o,a),l=o+c===t.length,u=n;s!==l&&(u|=i.Fragmented),this.#y(e,t.slice(o,o+c),u,r),o+=c,s=!1}}#y(e,t,n,r=!this.#e.cryptoInitComplete){n=E(e,n);let[a,o]=this.#P(e),s={typeFlagged:e|n,id:a,clientID:this.#r,generationID:o,data:t,receivedAt:0},l=(n&i.Unencrypted)!==0,u=c(s),[d,f]=this.#e.encrypt(e,a,o,u,t,r,l),p=new Uint8Array(13+d.length);p.set(f.slice(0,x),0),p.set(u,x),p.set(d,13),this.#b(p);let m={packet:s,firstSend:Date.now(),lastSend:Date.now(),retryCount:0,nextInterval:C};this.#F(e,s,m)}#b(e){this.#n?.send(Buffer.from(e),e=>{e&&this.#t.warn(`udp send error`,e)})}#x(e){if(e.length<11)return;let t=e.slice(0,x),n=e.slice(x,11),i=e.slice(11),o=l(n),s={...o,clientID:0,generationID:this.#S(o.id,o.typeFlagged&15),data:new Uint8Array,receivedAt:Date.now()},c=this.#C(s,n,i,t);if(c!==null){if(s.data=c.plaintext,a(s)===r.Ping){this.#E(s.id,c.dummyUsed);return}this.#w(s,c.dummyUsed)&&(this.#D(s),this.#N(s))}}#S(e,t){switch(t){case r.Command:return this.#u.getGeneration(e);case r.CommandLow:return this.#d.getGeneration(e);case r.Ack:return this.#f.getGeneration(e);case r.AckLow:return this.#p.getGeneration(e);default:return 0}}#C(e,t,n,s){let c=(o(e)&i.Unencrypted)!==0,l=!this.#e.cryptoInitComplete,u=l,d=a(e),f=e.generationID;try{return{plaintext:this.#e.decrypt(d,e.id,f,t,n,s,l,c),dummyUsed:u}}catch{for(let r of[-1,1]){let i=f+r;if(!(i<0))try{return{plaintext:this.#e.decrypt(d,e.id,i,t,n,s,!1,!1),dummyUsed:!1}}catch{}}if(d===r.Command||d===r.CommandLow||d===r.Ack)try{return{plaintext:this.#e.decrypt(d,e.id,f,t,n,s,!0,c),dummyUsed:!0}}catch{}return null}}#w(e,t){let n=a(e);if(n!==r.Command&&n!==r.CommandLow)return!0;let i=n===r.Command?this.#u:this.#d,o=n===r.Command?r.Ack:r.AckLow;return i.isInWindow(e.id)?(this.#T(e.id,o,t),!0):(i.isOldPacket(e.id)&&this.#T(e.id,o,t),!1)}#T(e,t,n){let r=new Uint8Array(2);new DataView(r.buffer).setUint16(0,e,!1),this.#y(t,r,0,n)}#E(e,t){let n=new Uint8Array(2);new DataView(n.buffer).setUint16(0,e,!1),this.#y(r.Pong,n,i.Unencrypted,t)}#D(e){let t=a(e);if(t!==r.Command&&t!==r.CommandLow){this.onPacket?.(e);return}let n=t===r.Command,i=n?this.#m:this.#h,o=n?this.#u:this.#d;for(i.set(e.id,e),n?this.#A(i,o,!0):this.#A(i,o,!1);;){let e=n?this.#O:this.#k,t=i.get(e);if(t===void 0)break;let r=this.#j(t,i,e,o);if(!r)break;let[a,s]=r;n?this.#O=s:this.#k=s,this.#M(a),this.onPacket?.(a)}}#O=0;#k=0;#A(e,t,n){let r=n?this.#O:this.#k;for(;!e.has(r)&&D(e,r);)r=r+1&65535,t.advance(1);n?this.#O=r:this.#k=r}#j(e,t,n,r){if((o(e)&i.Fragmented)===0)return t.delete(n),r.advance(1),[e,n+1&65535];let a=[],s=0,c=n,l=!1,u=!1;for(;;){let e=t.get(c);if(!e)return null;a.push(e),s+=e.data.length;let n=(o(e)&i.Fragmented)!==0;if(!l){if(l=!0,!n){u=!0;break}}else if(n){u=!0;break}c=c+1&65535}if(!u)return null;let d=new Uint8Array(s),f=0;for(let e of a)d.set(e.data,f),f+=e.data.length,t.delete(n),r.advance(1),n=n+1&65535;return e.data=d,e.typeFlagged&=~i.Fragmented,[e,n]}#M(e){if((o(e)&i.Compressed)!==0)try{e.data=new p().decompress(e.data),e.typeFlagged&=~i.Compressed}catch(t){this.#t.debug(`decompression failed`,{id:e.id,err:t})}}#N(e){let t=a(e);if(t===r.Init1){this.#_=null;return}if((t===r.Ack||t===r.AckLow)&&e.data.length>=2){let n=new DataView(e.data.buffer,e.data.byteOffset).getUint16(0,!1),i=(t===r.Ack?r.Command:r.CommandLow)<<16|n;this.#g.delete(i)}}#P(e){let t=this.#c[e],n=this.#l[e];return e===r.Init1?[t,n]:(this.#c[e]=t+1&65535,this.#c[e]===0&&(this.#l[e]=n+1>>>0),e===r.Command?this.#f.advanceToExcluded(t):e===r.CommandLow&&this.#p.advanceToExcluded(t),[t,n])}#F(e,t,n){if(e===r.Init1){this.#_=n;return}if(e===r.Command||e===r.CommandLow){let r=e<<16|t.id;this.#g.set(r,n)}}#I(){let e=Date.now();if(e-this.#s>v){this.#t.warn(`idle timeout`),this.#R(Error(`idle timeout`));return}this.#_&&this.#L(this.#_,e);for(let[t,n]of this.#g){if(e-n.firstSend>v){this.#g.delete(t),this.#R(Error(`packet ack timeout`));return}this.#L(n,e)}}#L(e,t){if(t-e.lastSend<e.nextInterval)return;e.lastSend=t,e.retryCount++,e.nextInterval=Math.min(e.nextInterval*2,y);let n=!this.#e.cryptoInitComplete,r=(o(e.packet)&i.Unencrypted)!==0,s=c(e.packet),l=a(e.packet),[u,d]=this.#e.encrypt(l,e.packet.id,e.packet.generationID,s,e.packet.data,n,r),f=new Uint8Array(13+u.length);f.set(d.slice(0,x),0),f.set(s,x),f.set(u,13),this.#b(f)}#R(e){this.#i||(this.close(),this.onClosed?.(e))}};function E(e,t){return e===r.Command||e===r.CommandLow?t|i.NewProtocol:t}function D(e,t){let n=Date.now();for(let[r,i]of e)if((r-t+65536&65535)<32768&&n-i.receivedAt>5e3)return!0;return!1}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return u}});
|
|
2
|
-
//# sourceMappingURL=handler-BJdwhtkp.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"handler-BJdwhtkp.cjs","names":["#mod","#receiveWindow","#generation","#mappedBaseOffset","#isNextGen","#hashtable","#ensureControl","#processReference","#processLiteral","#updateHashtable","#crypt","#logger","#clientID","#conn","#closed","#lastMessageReceived","#handleRawPacket","#triggerClose","#packetCounter","#sendPacketRaw","#stopPing","#checkResends","#stopResend","#initPacketCheck","#sendSplitPacket","#generationCounter","#write","#nextPacketIdentity","#trackResend","#resolveGeneration","#decryptPacketData","#sendPong","#handleCommandWindowAndAck","#handlePacketQueue","#updatePostReceiveState","#recvWindowCommand","#recvWindowCommandLow","#sendWindowCommand","#sendWindowCommandLow","#sendAck","#commandQueue","#commandLowQueue","#fastForwardMissingPackets","#_nextCommandID","#_nextCommandLowID","#tryReassemble","#tryDecompress","#ackManager","#doResend"],"sources":["../src/transport/packet.ts","../src/transport/generation-window.ts","../src/transport/quicklz.ts","../src/transport/handler.ts"],"sourcesContent":["export const enum PacketType {\n Voice = 0,\n VoiceWhisper = 1,\n Command = 2,\n CommandLow = 3,\n Ping = 4,\n Pong = 5,\n Ack = 6,\n AckLow = 7,\n Init1 = 8,\n}\n\nexport const enum PacketFlags {\n Fragmented = 0x10,\n NewProtocol = 0x20,\n Compressed = 0x40,\n Unencrypted = 0x80,\n}\n\nexport interface Packet {\n /** Type byte combined with flags (low nibble = type, high nibble = flags). */\n typeFlagged: number;\n id: number;\n clientID: number;\n generationID: number;\n data: Uint8Array;\n receivedAt: number; // Date.now()\n}\n\nexport function packetType(p: Packet): PacketType {\n return (p.typeFlagged & 0x0f) as PacketType;\n}\n\nexport function packetFlags(p: Packet): number {\n return p.typeFlagged & 0xf0;\n}\n\nexport function isUnencrypted(p: Packet): boolean {\n return (packetFlags(p) & PacketFlags.Unencrypted) !== 0;\n}\n\n/** Build the 5-byte client-to-server header: [packetID(2), clientID(2), typeFlagged(1)]. */\nexport function buildC2SHeader(p: Packet): Uint8Array {\n const header = new Uint8Array(5);\n const view = new DataView(header.buffer);\n view.setUint16(0, p.id, false);\n view.setUint16(2, p.clientID, false);\n header[4] = p.typeFlagged;\n return header;\n}\n\n/** Parse a 3-byte server-to-client header. */\nexport function parseS2CHeader(raw: Uint8Array): Pick<Packet, \"id\" | \"typeFlagged\"> {\n const view = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);\n return {\n id: view.getUint16(0, false),\n typeFlagged: raw[2]!,\n };\n}\n\n/** Parse a 5-byte client-to-server header. */\nexport function parseC2SHeader(raw: Uint8Array): Pick<Packet, \"id\" | \"clientID\" | \"typeFlagged\"> {\n const view = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);\n return {\n id: view.getUint16(0, false),\n clientID: view.getUint16(2, false),\n typeFlagged: raw[4]!,\n };\n}\n","export class GenerationWindow {\n #mappedBaseOffset = 0;\n #generation = 0;\n readonly #mod: number;\n readonly #receiveWindow: number;\n\n constructor(mod: number, windowSize: number) {\n this.#mod = mod;\n this.#receiveWindow = windowSize;\n }\n\n get generation(): number {\n return this.#generation;\n }\n\n advance(amount: number): void {\n if (amount <= 0) return;\n const newBaseOffset = this.#mappedBaseOffset + amount;\n const genStep = Math.floor(newBaseOffset / this.#mod);\n if (genStep > 0) {\n this.#generation = Math.min(this.#generation + genStep, 0xffff_ffff);\n }\n this.#mappedBaseOffset = newBaseOffset % this.#mod;\n }\n\n advanceToExcluded(mappedValue: number): void {\n let moveDist = mappedValue - this.#mappedBaseOffset;\n if (moveDist < 0) moveDist += this.#mod;\n this.advance(moveDist + 1);\n }\n\n syncTo(mappedValue: number): void {\n let moveDist = mappedValue - this.#mappedBaseOffset;\n if (moveDist < 0) moveDist += this.#mod;\n this.advance(moveDist);\n }\n\n isInWindow(mappedValue: number): boolean {\n const maxOffset = this.#mappedBaseOffset + this.#receiveWindow;\n if (maxOffset < this.#mod) {\n return mappedValue >= this.#mappedBaseOffset && mappedValue < maxOffset;\n }\n return mappedValue >= this.#mappedBaseOffset || mappedValue < maxOffset - this.#mod;\n }\n\n mappedToIndex(mappedValue: number): number {\n if (this.#isNextGen(mappedValue)) {\n return mappedValue + this.#mod - this.#mappedBaseOffset;\n }\n return mappedValue - this.#mappedBaseOffset;\n }\n\n isOldPacket(mappedValue: number): boolean {\n return this.mappedToIndex(mappedValue) < 0;\n }\n\n isFuturePacket(mappedValue: number): boolean {\n return this.mappedToIndex(mappedValue) >= this.#receiveWindow;\n }\n\n #isNextGen(mappedValue: number): boolean {\n return (\n this.#mappedBaseOffset > this.#mod - this.#receiveWindow &&\n mappedValue < this.#mappedBaseOffset + this.#receiveWindow - this.#mod\n );\n }\n\n getGeneration(mappedValue: number): number {\n if (this.#isNextGen(mappedValue)) return this.#generation + 1;\n return this.#generation;\n }\n\n reset(): void {\n this.#mappedBaseOffset = 0;\n this.#generation = 0;\n }\n}\n","const TABLE_SIZE = 4096;\n\ninterface QlzState {\n control: number;\n sourcePos: number;\n destPos: number;\n nextHashed: number;\n}\n\nexport class Qlz {\n #hashtable = new Int32Array(TABLE_SIZE);\n\n decompress(data: Uint8Array): Uint8Array {\n const { headerLen, decompressedSize, flags } = parseQlzHeader(data);\n\n const dest = new Uint8Array(decompressedSize);\n\n if ((flags & 0x01) === 0) {\n dest.set(data.slice(headerLen, headerLen + decompressedSize));\n return dest;\n }\n\n this.#hashtable.fill(0);\n\n const state: QlzState = {\n control: 1,\n sourcePos: headerLen,\n destPos: 0,\n nextHashed: 0,\n };\n\n while (this.#ensureControl(data, state)) {\n if ((state.control & 1) !== 0) {\n if (!this.#processReference(data, dest, state)) break;\n } else {\n if (this.#processLiteral(data, dest, decompressedSize, state)) break;\n }\n }\n\n return dest;\n }\n\n #ensureControl(data: Uint8Array, st: QlzState): boolean {\n if (st.control !== 1) return true;\n if (st.sourcePos + 4 > data.length) return false;\n st.control =\n (data[st.sourcePos]! |\n (data[st.sourcePos + 1]! << 8) |\n (data[st.sourcePos + 2]! << 16) |\n (data[st.sourcePos + 3]! << 24)) >>>\n 0;\n st.sourcePos += 4;\n return true;\n }\n\n #processReference(data: Uint8Array, dest: Uint8Array, st: QlzState): boolean {\n st.control = (st.control >>> 1) >>> 0;\n if (st.sourcePos + 2 > data.length) return false;\n\n const b1 = data[st.sourcePos]!;\n const b2 = data[st.sourcePos + 1]!;\n st.sourcePos += 2;\n\n const hash = (b1 >> 4) | (b2 << 4);\n let matchlen = b1 & 0x0f;\n if (matchlen !== 0) {\n matchlen += 2;\n } else {\n if (st.sourcePos >= data.length) return false;\n matchlen = data[st.sourcePos]!;\n st.sourcePos++;\n }\n\n const offset = this.#hashtable[hash]!;\n for (let i = 0; i < matchlen; i++) {\n if (st.destPos < dest.length && offset + i < st.destPos) {\n dest[st.destPos] = dest[offset + i]!;\n st.destPos++;\n }\n }\n\n const end = st.destPos + 1 - matchlen;\n this.#updateHashtable(dest, st, end);\n st.nextHashed = st.destPos;\n\n return true;\n }\n\n #processLiteral(\n data: Uint8Array,\n dest: Uint8Array,\n decompressedSize: number,\n st: QlzState,\n ): boolean {\n const threshold = Math.max(decompressedSize, 10) - 10;\n if (st.destPos >= threshold) {\n while (st.destPos < decompressedSize) {\n if (st.control === 1) {\n st.sourcePos += 4;\n if (st.sourcePos > data.length) break;\n st.control =\n (data[st.sourcePos - 4]! |\n (data[st.sourcePos - 3]! << 8) |\n (data[st.sourcePos - 2]! << 16) |\n (data[st.sourcePos - 1]! << 24)) >>>\n 0;\n }\n if (st.sourcePos >= data.length) break;\n dest[st.destPos++] = data[st.sourcePos++]!;\n st.control = (st.control >>> 1) >>> 0;\n }\n return true;\n }\n\n if (st.sourcePos >= data.length || st.destPos >= dest.length) return true;\n\n dest[st.destPos++] = data[st.sourcePos++]!;\n st.control = (st.control >>> 1) >>> 0;\n\n const end = Math.max(st.destPos - 2, 0);\n this.#updateHashtable(dest, st, end);\n if (st.nextHashed < end) st.nextHashed = end;\n\n return false;\n }\n\n #updateHashtable(dest: Uint8Array, st: QlzState, end: number): void {\n while (st.nextHashed < end) {\n if (st.nextHashed + 3 > dest.length) break;\n const v =\n (dest[st.nextHashed]! |\n (dest[st.nextHashed + 1]! << 8) |\n (dest[st.nextHashed + 2]! << 16)) >>>\n 0;\n const hash = ((v >> 12) ^ v) & 0xfff;\n this.#hashtable[hash] = st.nextHashed;\n st.nextHashed++;\n }\n }\n}\n\nfunction parseQlzHeader(data: Uint8Array): {\n headerLen: number;\n decompressedSize: number;\n flags: number;\n} {\n if (data.length < 3) throw new Error(\"QuickLZ: data too short\");\n\n const flags = data[0]!;\n const level = (flags >> 2) & 0x03;\n if (level !== 1) throw new Error(\"QuickLZ: only level 1 is supported\");\n\n const headerLen = (flags & 0x02) !== 0 ? 9 : 3;\n if (data.length < headerLen) throw new Error(\"QuickLZ: data too short for header\");\n\n let decompressedSize: number;\n if ((flags & 0x02) !== 0) {\n decompressedSize = (data[5]! | (data[6]! << 8) | (data[7]! << 16) | (data[8]! << 24)) >>> 0;\n } else {\n decompressedSize = data[2]!;\n }\n\n return { headerLen, decompressedSize, flags };\n}\n","import { createSocket, type Socket as UdpSocket } from \"node:dgram\";\nimport type { Crypt } from \"../crypto/crypt.js\";\nimport type { Logger } from \"../types.js\";\nimport { noopLogger } from \"../types.js\";\nimport {\n type Packet,\n PacketType,\n PacketFlags,\n packetType,\n packetFlags,\n buildC2SHeader,\n parseS2CHeader,\n} from \"./packet.js\";\nimport { GenerationWindow } from \"./generation-window.js\";\nimport { Qlz } from \"./quicklz.js\";\nimport { processInit1 } from \"../handshake/crypt-handshake.js\";\n\nconst MAX_OUT_PACKET_SIZE = 500;\nconst RECEIVE_PACKET_WINDOW_SIZE = 1024;\nconst PING_INTERVAL_MS = 5_000;\nconst PACKET_TIMEOUT_MS = 60_000;\nconst MAX_RETRY_INTERVAL_MS = 1_000;\nconst HEADER_SIZE = 5;\nconst TAG_SIZE = 8;\nconst VOICE_HEADER_SIZE = 3;\nconst RESEND_BASE_INTERVAL_MS = 500;\nconst RESEND_LOOP_INTERVAL_MS = 100;\n\ninterface ResendPacket {\n packet: Packet;\n firstSend: number;\n lastSend: number;\n retryCount: number;\n nextInterval: number;\n}\n\nexport class PacketHandler {\n onPacket: ((p: Packet) => void) | null = null;\n onClosed: ((err: Error | null) => void) | null = null;\n\n readonly #crypt: Crypt;\n readonly #logger: Logger;\n\n #conn: UdpSocket | null = null;\n #clientID = 0;\n #closed = false;\n #stopPing: (() => void) | null = null;\n #stopResend: (() => void) | null = null;\n #lastMessageReceived = Date.now();\n\n #packetCounter = new Uint16Array(9);\n #generationCounter = new Uint32Array(9);\n\n #recvWindowCommand = new GenerationWindow(1 << 16, RECEIVE_PACKET_WINDOW_SIZE);\n #recvWindowCommandLow = new GenerationWindow(1 << 16, RECEIVE_PACKET_WINDOW_SIZE);\n #sendWindowCommand = new GenerationWindow(1 << 16, RECEIVE_PACKET_WINDOW_SIZE);\n #sendWindowCommandLow = new GenerationWindow(1 << 16, RECEIVE_PACKET_WINDOW_SIZE);\n\n #commandQueue = new Map<number, Packet>();\n #commandLowQueue = new Map<number, Packet>();\n #ackManager = new Map<number, ResendPacket>();\n #initPacketCheck: ResendPacket | null = null;\n\n constructor(crypt: Crypt, logger: Logger = noopLogger) {\n this.#crypt = crypt;\n this.#logger = logger;\n }\n\n setClientID(id: number): void {\n this.#clientID = id;\n }\n\n connect(addr: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const [host, portStr] =\n addr.lastIndexOf(\":\") > 0\n ? [addr.slice(0, addr.lastIndexOf(\":\")), addr.slice(addr.lastIndexOf(\":\") + 1)]\n : [addr, \"9987\"];\n const port = parseInt(portStr, 10);\n\n const socket = createSocket(\"udp4\");\n socket.once(\"error\", reject);\n socket.connect(port, host, () => {\n socket.off(\"error\", reject);\n this.start(socket);\n resolve();\n });\n });\n }\n\n start(conn: UdpSocket): void {\n this.#conn = conn;\n this.#closed = false;\n this.#lastMessageReceived = Date.now();\n\n conn.on(\"message\", (msg) => {\n this.#lastMessageReceived = Date.now();\n this.#handleRawPacket(new Uint8Array(msg.buffer, msg.byteOffset, msg.byteLength));\n });\n conn.on(\"error\", (err) => {\n this.#logger.error(\"udp error\", err);\n this.#triggerClose(err);\n });\n conn.on(\"close\", () => this.#triggerClose(null));\n\n this.#packetCounter[PacketType.Command] = 1;\n this.#packetCounter[PacketType.Init1] = 101;\n\n const init1Data = processInit1(this.#crypt, null);\n if (init1Data) this.#sendPacketRaw(PacketType.Init1, init1Data, 0);\n\n // Ping loop\n const pingTimer = setInterval(() => {\n if (this.#crypt.cryptoInitComplete) {\n this.sendPacket(PacketType.Ping, new Uint8Array(0), PacketFlags.Unencrypted);\n }\n }, PING_INTERVAL_MS);\n this.#stopPing = () => clearInterval(pingTimer);\n\n // Resend loop\n const resendTimer = setInterval(() => this.#checkResends(), RESEND_LOOP_INTERVAL_MS);\n this.#stopResend = () => clearInterval(resendTimer);\n }\n\n receivedFinalInitAck(): void {\n this.#initPacketCheck = null;\n }\n\n sendPacket(pType: PacketType, data: Uint8Array, flags: number): void {\n const dummy = !this.#crypt.cryptoInitComplete;\n if (data.length > 487 && pType !== PacketType.Voice && pType !== PacketType.VoiceWhisper) {\n this.#sendSplitPacket(pType, data, flags, dummy);\n return;\n }\n this.#sendPacketRaw(pType, data, flags, dummy);\n }\n\n sendVoicePacket(data: Uint8Array, codec: number): void {\n const pID = this.#packetCounter[PacketType.Voice]!;\n const pGen = this.#generationCounter[PacketType.Voice]!;\n this.#packetCounter[PacketType.Voice] = (pID + 1) & 0xffff;\n if (this.#packetCounter[PacketType.Voice] === 0) {\n this.#generationCounter[PacketType.Voice]!++;\n }\n\n const payloadLen = VOICE_HEADER_SIZE + data.length;\n const voicePayload = new Uint8Array(payloadLen);\n new DataView(voicePayload.buffer).setUint16(0, pID, false);\n voicePayload[2] = codec;\n voicePayload.set(data, VOICE_HEADER_SIZE);\n\n const p: Packet = {\n typeFlagged: PacketType.Voice | PacketFlags.Unencrypted,\n id: pID,\n clientID: this.#clientID,\n generationID: pGen,\n data: voicePayload,\n receivedAt: 0,\n };\n\n const header = buildC2SHeader(p);\n const final = new Uint8Array(TAG_SIZE + HEADER_SIZE + payloadLen);\n final.set(this.#crypt.fakeSignature, 0);\n final.set(header, TAG_SIZE);\n final.set(voicePayload, TAG_SIZE + HEADER_SIZE);\n this.#write(final);\n }\n\n close(): void {\n if (this.#closed) return;\n this.#closed = true;\n this.#stopPing?.();\n this.#stopResend?.();\n this.#conn?.close();\n }\n\n // ---- Private ---------------------------------------------------------------\n\n #sendSplitPacket(pType: PacketType, data: Uint8Array, flags: number, dummy: boolean): void {\n const maxSize = MAX_OUT_PACKET_SIZE - HEADER_SIZE - TAG_SIZE; // 487\n let pos = 0;\n let first = true;\n\n while (pos < data.length) {\n const blockSize = Math.min(data.length - pos, maxSize);\n const last = pos + blockSize === data.length;\n\n let pFlags = flags;\n if (first !== last) pFlags |= PacketFlags.Fragmented;\n\n this.#sendPacketRaw(pType, data.slice(pos, pos + blockSize), pFlags, dummy);\n pos += blockSize;\n first = false;\n }\n }\n\n #sendPacketRaw(\n pType: PacketType,\n data: Uint8Array,\n flags: number,\n dummy = !this.#crypt.cryptoInitComplete,\n ): void {\n flags = applyProtocolFlags(pType, flags);\n const [pID, pGen] = this.#nextPacketIdentity(pType);\n const p: Packet = {\n typeFlagged: pType | flags,\n id: pID,\n clientID: this.#clientID,\n generationID: pGen,\n data,\n receivedAt: 0,\n };\n\n const unencrypted = (flags & PacketFlags.Unencrypted) !== 0;\n const header = buildC2SHeader(p);\n const [ciphertext, tag] = this.#crypt.encrypt(\n pType,\n pID,\n pGen,\n header,\n data,\n dummy,\n unencrypted,\n );\n\n const final = new Uint8Array(TAG_SIZE + HEADER_SIZE + ciphertext.length);\n final.set(tag.slice(0, TAG_SIZE), 0);\n final.set(header, TAG_SIZE);\n final.set(ciphertext, TAG_SIZE + HEADER_SIZE);\n this.#write(final);\n\n const rp: ResendPacket = {\n packet: p,\n firstSend: Date.now(),\n lastSend: Date.now(),\n retryCount: 0,\n nextInterval: RESEND_BASE_INTERVAL_MS,\n };\n this.#trackResend(pType, p, rp);\n }\n\n #write(data: Uint8Array): void {\n this.#conn?.send(Buffer.from(data), (err) => {\n if (err) this.#logger.warn(\"udp send error\", err);\n });\n }\n\n #handleRawPacket(raw: Uint8Array): void {\n if (raw.length < 11) return;\n\n const tag = raw.slice(0, TAG_SIZE);\n const header = raw.slice(TAG_SIZE, TAG_SIZE + 3);\n const ciphertext = raw.slice(TAG_SIZE + 3);\n\n const parsed = parseS2CHeader(header);\n const p: Packet = {\n ...parsed,\n clientID: 0,\n generationID: this.#resolveGeneration(parsed.id, parsed.typeFlagged & 0x0f),\n data: new Uint8Array(0),\n receivedAt: Date.now(),\n };\n\n const decrypted = this.#decryptPacketData(p, header, ciphertext, tag);\n if (decrypted === null) return;\n p.data = decrypted.plaintext;\n\n const pType = packetType(p);\n\n if (pType === PacketType.Ping) {\n this.#sendPong(p.id, decrypted.dummyUsed);\n return;\n }\n\n if (!this.#handleCommandWindowAndAck(p, decrypted.dummyUsed)) return;\n\n this.#handlePacketQueue(p);\n this.#updatePostReceiveState(p);\n }\n\n #resolveGeneration(id: number, pType: number): number {\n switch (pType as PacketType) {\n case PacketType.Command:\n return this.#recvWindowCommand.getGeneration(id);\n case PacketType.CommandLow:\n return this.#recvWindowCommandLow.getGeneration(id);\n case PacketType.Ack:\n return this.#sendWindowCommand.getGeneration(id);\n case PacketType.AckLow:\n return this.#sendWindowCommandLow.getGeneration(id);\n default:\n return 0;\n }\n }\n\n #decryptPacketData(\n p: Packet,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n ): { plaintext: Uint8Array; dummyUsed: boolean } | null {\n const unencrypted = (packetFlags(p) & PacketFlags.Unencrypted) !== 0;\n const dummy = !this.#crypt.cryptoInitComplete;\n let dummyUsed = dummy;\n const pType = packetType(p);\n const gen = p.generationID;\n\n try {\n const plaintext = this.#crypt.decrypt(\n pType,\n p.id,\n gen,\n header,\n ciphertext,\n tag,\n dummy,\n unencrypted,\n );\n return { plaintext, dummyUsed };\n } catch {\n // Try adjacent generations\n for (const offset of [-1, 1]) {\n const guessGen = gen + offset;\n if (guessGen < 0) continue;\n try {\n const plaintext = this.#crypt.decrypt(\n pType,\n p.id,\n guessGen,\n header,\n ciphertext,\n tag,\n false,\n false,\n );\n return { plaintext, dummyUsed: false };\n } catch {\n // continue\n }\n }\n\n // Try dummy fallback for command/ack types\n if (\n pType === PacketType.Command ||\n pType === PacketType.CommandLow ||\n pType === PacketType.Ack\n ) {\n try {\n const plaintext = this.#crypt.decrypt(\n pType,\n p.id,\n gen,\n header,\n ciphertext,\n tag,\n true,\n unencrypted,\n );\n return { plaintext, dummyUsed: true };\n } catch {\n // fall through\n }\n }\n\n return null;\n }\n }\n\n #handleCommandWindowAndAck(p: Packet, dummyUsed: boolean): boolean {\n const pType = packetType(p);\n if (pType !== PacketType.Command && pType !== PacketType.CommandLow) return true;\n\n const win = pType === PacketType.Command ? this.#recvWindowCommand : this.#recvWindowCommandLow;\n const ackType = pType === PacketType.Command ? PacketType.Ack : PacketType.AckLow;\n\n if (!win.isInWindow(p.id)) {\n if (win.isOldPacket(p.id)) {\n this.#sendAck(p.id, ackType, dummyUsed);\n }\n return false;\n }\n this.#sendAck(p.id, ackType, dummyUsed);\n return true;\n }\n\n #sendAck(packetID: number, ackType: PacketType, dummyUsed: boolean): void {\n const ackData = new Uint8Array(2);\n new DataView(ackData.buffer).setUint16(0, packetID, false);\n this.#sendPacketRaw(ackType, ackData, 0, dummyUsed);\n }\n\n #sendPong(pID: number, dummyUsed: boolean): void {\n const pongData = new Uint8Array(2);\n new DataView(pongData.buffer).setUint16(0, pID, false);\n this.#sendPacketRaw(PacketType.Pong, pongData, PacketFlags.Unencrypted, dummyUsed);\n }\n\n #handlePacketQueue(p: Packet): void {\n const pType = packetType(p);\n if (pType !== PacketType.Command && pType !== PacketType.CommandLow) {\n this.onPacket?.(p);\n return;\n }\n\n const isCommand = pType === PacketType.Command;\n const queue = isCommand ? this.#commandQueue : this.#commandLowQueue;\n const win = isCommand ? this.#recvWindowCommand : this.#recvWindowCommandLow;\n\n queue.set(p.id, p);\n\n if (isCommand) {\n this.#fastForwardMissingPackets(queue, win, true);\n } else {\n this.#fastForwardMissingPackets(queue, win, false);\n }\n\n while (true) {\n const current = isCommand ? this.#_nextCommandID : this.#_nextCommandLowID;\n const packet = queue.get(current);\n if (packet === undefined) break;\n\n const result = this.#tryReassemble(packet, queue, current, win);\n if (!result) break;\n\n const [reassembled, newNext] = result;\n if (isCommand) this.#_nextCommandID = newNext;\n else this.#_nextCommandLowID = newNext;\n\n this.#tryDecompress(reassembled);\n this.onPacket?.(reassembled);\n }\n }\n\n #_nextCommandID = 0;\n #_nextCommandLowID = 0;\n\n #fastForwardMissingPackets(\n queue: Map<number, Packet>,\n win: GenerationWindow,\n isCommand: boolean,\n ): void {\n let nextID = isCommand ? this.#_nextCommandID : this.#_nextCommandLowID;\n while (!queue.has(nextID) && hasOldNewerPacket(queue, nextID)) {\n nextID = (nextID + 1) & 0xffff;\n win.advance(1);\n }\n if (isCommand) this.#_nextCommandID = nextID;\n else this.#_nextCommandLowID = nextID;\n }\n\n #tryReassemble(\n startPacket: Packet,\n queue: Map<number, Packet>,\n nextID: number,\n win: GenerationWindow,\n ): [reassembled: Packet, newNextID: number] | null {\n if ((packetFlags(startPacket) & PacketFlags.Fragmented) === 0) {\n queue.delete(nextID);\n win.advance(1);\n return [startPacket, (nextID + 1) & 0xffff];\n }\n\n const fragments: Packet[] = [];\n let totalSize = 0;\n let currID = nextID;\n let startSeen = false;\n let complete = false;\n\n while (true) {\n const frag = queue.get(currID);\n if (!frag) return null;\n fragments.push(frag);\n totalSize += frag.data.length;\n\n const fragmented = (packetFlags(frag) & PacketFlags.Fragmented) !== 0;\n if (!startSeen) {\n startSeen = true;\n if (!fragmented) {\n complete = true;\n break;\n }\n } else if (fragmented) {\n complete = true;\n break;\n }\n currID = (currID + 1) & 0xffff;\n }\n\n if (!complete) return null;\n\n const combined = new Uint8Array(totalSize);\n let pos = 0;\n for (const frag of fragments) {\n combined.set(frag.data, pos);\n pos += frag.data.length;\n queue.delete(nextID);\n win.advance(1);\n nextID = (nextID + 1) & 0xffff;\n }\n\n startPacket.data = combined;\n startPacket.typeFlagged &= ~PacketFlags.Fragmented;\n return [startPacket, nextID];\n }\n\n #tryDecompress(packet: Packet): void {\n if ((packetFlags(packet) & PacketFlags.Compressed) === 0) return;\n try {\n const qlz = new Qlz();\n packet.data = qlz.decompress(packet.data);\n packet.typeFlagged &= ~PacketFlags.Compressed;\n } catch (err) {\n this.#logger.debug(\"decompression failed\", { id: packet.id, err });\n }\n }\n\n #updatePostReceiveState(p: Packet): void {\n const pType = packetType(p);\n\n if (pType === PacketType.Init1) {\n this.#initPacketCheck = null;\n return;\n }\n\n if ((pType === PacketType.Ack || pType === PacketType.AckLow) && p.data.length >= 2) {\n const ackID = new DataView(p.data.buffer, p.data.byteOffset).getUint16(0, false);\n const targetType = pType === PacketType.Ack ? PacketType.Command : PacketType.CommandLow;\n const key = (targetType << 16) | ackID;\n this.#ackManager.delete(key);\n }\n }\n\n #nextPacketIdentity(pType: PacketType): [id: number, gen: number] {\n const pID = this.#packetCounter[pType]!;\n const pGen = this.#generationCounter[pType]!;\n\n if (pType === PacketType.Init1) return [pID, pGen];\n\n this.#packetCounter[pType] = (pID + 1) & 0xffff;\n if (this.#packetCounter[pType] === 0) {\n this.#generationCounter[pType] = (pGen + 1) >>> 0;\n }\n\n if (pType === PacketType.Command) {\n this.#sendWindowCommand.advanceToExcluded(pID);\n } else if (pType === PacketType.CommandLow) {\n this.#sendWindowCommandLow.advanceToExcluded(pID);\n }\n\n return [pID, pGen];\n }\n\n #trackResend(pType: PacketType, p: Packet, rp: ResendPacket): void {\n if (pType === PacketType.Init1) {\n this.#initPacketCheck = rp;\n return;\n }\n if (pType === PacketType.Command || pType === PacketType.CommandLow) {\n const key = (pType << 16) | p.id;\n this.#ackManager.set(key, rp);\n }\n }\n\n #checkResends(): void {\n const now = Date.now();\n\n if (now - this.#lastMessageReceived > PACKET_TIMEOUT_MS) {\n this.#logger.warn(\"idle timeout\");\n this.#triggerClose(new Error(\"idle timeout\"));\n return;\n }\n\n if (this.#initPacketCheck) {\n this.#doResend(this.#initPacketCheck, now);\n }\n\n for (const [key, rp] of this.#ackManager) {\n if (now - rp.firstSend > PACKET_TIMEOUT_MS) {\n this.#ackManager.delete(key);\n this.#triggerClose(new Error(\"packet ack timeout\"));\n return;\n }\n this.#doResend(rp, now);\n }\n }\n\n #doResend(rp: ResendPacket, now: number): void {\n if (now - rp.lastSend < rp.nextInterval) return;\n\n rp.lastSend = now;\n rp.retryCount++;\n rp.nextInterval = Math.min(rp.nextInterval * 2, MAX_RETRY_INTERVAL_MS);\n\n const dummy = !this.#crypt.cryptoInitComplete;\n const unencrypted = (packetFlags(rp.packet) & PacketFlags.Unencrypted) !== 0;\n const header = buildC2SHeader(rp.packet);\n const pType = packetType(rp.packet);\n\n const [ciphertext, tag] = this.#crypt.encrypt(\n pType,\n rp.packet.id,\n rp.packet.generationID,\n header,\n rp.packet.data,\n dummy,\n unencrypted,\n );\n\n const final = new Uint8Array(TAG_SIZE + HEADER_SIZE + ciphertext.length);\n final.set(tag.slice(0, TAG_SIZE), 0);\n final.set(header, TAG_SIZE);\n final.set(ciphertext, TAG_SIZE + HEADER_SIZE);\n this.#write(final);\n }\n\n #triggerClose(err: Error | null): void {\n if (this.#closed) return;\n this.close();\n this.onClosed?.(err);\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\nfunction applyProtocolFlags(pType: PacketType, flags: number): number {\n if (pType === PacketType.Command || pType === PacketType.CommandLow) {\n return flags | PacketFlags.NewProtocol;\n }\n return flags;\n}\n\nfunction hasOldNewerPacket(queue: Map<number, Packet>, nextID: number): boolean {\n const now = Date.now();\n for (const [id, pkg] of queue) {\n const diff = (id - nextID + 0x10000) & 0xffff;\n if (diff < 0x8000 && now - pkg.receivedAt > 5_000) {\n return true;\n }\n }\n return false;\n}\n"],"mappings":"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"}
|