@honeybbq/teamspeak-client 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/address-BR-5unVo.cjs.map +1 -1
- package/dist/address-BfmovVpp.js.map +1 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/client.d.ts +16 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/command/index.cjs +1 -1
- package/dist/command/index.mjs +1 -1
- package/dist/command/parser.d.ts.map +1 -1
- package/dist/command-BLe-C2L2.js.map +1 -1
- package/dist/command-DAK4pUBP.cjs.map +1 -1
- package/dist/commands.d.ts.map +1 -1
- package/dist/crypt-handshake-CQkQreLx.cjs.map +1 -1
- package/dist/crypt-handshake-DziOY4Lq.js.map +1 -1
- package/dist/{crypt-init2-D70ha4LB.js → crypt-init2-BcGT--df.js} +2 -2
- package/dist/crypt-init2-BcGT--df.js.map +1 -0
- package/dist/{crypt-init2-DparLekm.cjs → crypt-init2-Bkee1YxV.cjs} +2 -2
- package/dist/crypt-init2-Bkee1YxV.cjs.map +1 -0
- package/dist/crypto/crypt.d.ts.map +1 -1
- package/dist/crypto/eax.d.ts.map +1 -1
- package/dist/crypto/identity.d.ts +13 -1
- package/dist/crypto/identity.d.ts.map +1 -1
- package/dist/crypto/index.cjs +1 -1
- package/dist/crypto/index.d.ts +2 -1
- package/dist/crypto/index.d.ts.map +1 -1
- package/dist/crypto/index.mjs +3 -3
- package/dist/{crypto-CDlweUL3.cjs → crypto-BfDd9DP6.cjs} +2 -2
- package/dist/crypto-BfDd9DP6.cjs.map +1 -0
- package/dist/{crypto-Bg02m4ZE.js → crypto-DLV3oH5F.js} +12 -12
- package/dist/crypto-DLV3oH5F.js.map +1 -0
- package/dist/discovery/resolver.d.ts.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/{handler-DI_abe9c.js → handler-BpdZFsKo.js} +104 -102
- package/dist/handler-BpdZFsKo.js.map +1 -0
- package/dist/handler-aywHvv7I.cjs +2 -0
- package/dist/handler-aywHvv7I.cjs.map +1 -0
- package/dist/handshake/index.cjs +1 -1
- package/dist/handshake/index.mjs +1 -1
- package/dist/handshake/license.d.ts.map +1 -1
- package/dist/handshake.d.ts +9 -0
- package/dist/handshake.d.ts.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +314 -279
- package/dist/index.mjs.map +1 -1
- package/dist/{parser-DZMv3Jm-.js → parser-BX8NEiBe.js} +4 -4
- package/dist/parser-BX8NEiBe.js.map +1 -0
- package/dist/parser-BfwYH2fT.cjs +2 -0
- package/dist/parser-BfwYH2fT.cjs.map +1 -0
- package/dist/{primitives-xIr6Tjk4.js → primitives-CdX74Rgu.js} +194 -190
- package/dist/primitives-CdX74Rgu.js.map +1 -0
- package/dist/primitives-DkwW7wcP.cjs +2 -0
- package/dist/primitives-DkwW7wcP.cjs.map +1 -0
- package/dist/resolver-6B8dI9gr.js.map +1 -1
- package/dist/resolver-DCcmyWSK.cjs.map +1 -1
- package/dist/throttle.d.ts.map +1 -1
- package/dist/transfer.d.ts.map +1 -1
- package/dist/transport/generation-window.d.ts.map +1 -1
- package/dist/transport/handler.d.ts +9 -1
- 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/quicklz.d.ts.map +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -6
- package/dist/address.test.d.ts +0 -2
- package/dist/address.test.d.ts.map +0 -1
- package/dist/api.test.d.ts +0 -2
- package/dist/api.test.d.ts.map +0 -1
- package/dist/command/command.test.d.ts +0 -2
- package/dist/command/command.test.d.ts.map +0 -1
- package/dist/crypt-init2-D70ha4LB.js.map +0 -1
- package/dist/crypt-init2-DparLekm.cjs.map +0 -1
- package/dist/crypto/eax.test.d.ts +0 -2
- package/dist/crypto/eax.test.d.ts.map +0 -1
- package/dist/crypto/identity.test.d.ts +0 -2
- package/dist/crypto/identity.test.d.ts.map +0 -1
- package/dist/crypto-Bg02m4ZE.js.map +0 -1
- package/dist/crypto-CDlweUL3.cjs.map +0 -1
- package/dist/handler-DI_abe9c.js.map +0 -1
- package/dist/handler-DuwoO5RC.cjs +0 -2
- package/dist/handler-DuwoO5RC.cjs.map +0 -1
- package/dist/handshake.test.d.ts +0 -2
- package/dist/handshake.test.d.ts.map +0 -1
- package/dist/helpers.test.d.ts +0 -2
- package/dist/helpers.test.d.ts.map +0 -1
- package/dist/integration.test.d.ts +0 -12
- package/dist/integration.test.d.ts.map +0 -1
- package/dist/notifications.test.d.ts +0 -2
- package/dist/notifications.test.d.ts.map +0 -1
- package/dist/parser-CL33R9tr.cjs +0 -2
- package/dist/parser-CL33R9tr.cjs.map +0 -1
- package/dist/parser-DZMv3Jm-.js.map +0 -1
- package/dist/primitives-cNNAeFCo.cjs +0 -2
- package/dist/primitives-cNNAeFCo.cjs.map +0 -1
- package/dist/primitives-xIr6Tjk4.js.map +0 -1
- package/dist/throttle.test.d.ts +0 -2
- package/dist/throttle.test.d.ts.map +0 -1
- package/dist/transport/generation-window.test.d.ts +0 -2
- package/dist/transport/generation-window.test.d.ts.map +0 -1
- package/dist/transport/packet.test.d.ts +0 -2
- package/dist/transport/packet.test.d.ts.map +0 -1
- package/dist/transport/quicklz.test.d.ts +0 -2
- package/dist/transport/quicklz.test.d.ts.map +0 -1
- package/dist/transport/whisper.test.d.ts +0 -2
- package/dist/transport/whisper.test.d.ts.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b as e, m as t, y as n } from "./primitives-CdX74Rgu.js";
|
|
2
2
|
import { createCipheriv as r, createECDH as i, createHash as a, timingSafeEqual as o } from "node:crypto";
|
|
3
3
|
//#region src/crypto/eax.ts
|
|
4
4
|
var s = 8, c = 16, l = class {
|
|
@@ -12,10 +12,10 @@ var s = 8, c = 16, l = class {
|
|
|
12
12
|
for (let e = 0; e < s; e++) c[e] = r[e] ^ i[e] ^ o[e];
|
|
13
13
|
return [a, c];
|
|
14
14
|
}
|
|
15
|
-
decrypt(e,
|
|
16
|
-
let a = this.#t(0, e), c = this.#t(1,
|
|
15
|
+
decrypt(e, t, r, i) {
|
|
16
|
+
let a = this.#t(0, e), c = this.#t(1, t), l = this.#t(2, r), d = new Uint8Array(s);
|
|
17
17
|
for (let e = 0; e < s; e++) d[e] = a[e] ^ c[e] ^ l[e];
|
|
18
|
-
if (!o(Buffer.from(d), Buffer.from(i.slice(0, s)))) throw new
|
|
18
|
+
if (!o(Buffer.from(d), Buffer.from(i.slice(0, s)))) throw new n();
|
|
19
19
|
return u(this.#e, a, r);
|
|
20
20
|
}
|
|
21
21
|
#t(e, t) {
|
|
@@ -81,8 +81,8 @@ var _ = 8, v = 10, y = 8, b = 15, x = Buffer.from("TS3INIT1"), S = Buffer.from("
|
|
|
81
81
|
for (let e = 0; e < n; e++) a = a * a % o;
|
|
82
82
|
return D(a, 64);
|
|
83
83
|
}
|
|
84
|
-
initCrypto(
|
|
85
|
-
let i = Buffer.from(
|
|
84
|
+
initCrypto(e, n, r) {
|
|
85
|
+
let i = Buffer.from(e, "base64"), a = Buffer.from(n, "base64"), o = Buffer.from(r, "base64"), s = t(o), c = this.#t(s);
|
|
86
86
|
this.setSharedSecret(i, a, c);
|
|
87
87
|
}
|
|
88
88
|
setSharedSecret(e, t, n) {
|
|
@@ -120,14 +120,14 @@ var _ = 8, v = 10, y = 8, b = 15, x = Buffer.from("TS3INIT1"), S = Buffer.from("
|
|
|
120
120
|
let [s, c] = this.getKeyNonce(!1, t, n, e, a);
|
|
121
121
|
return new l(s).encrypt(c, r, i);
|
|
122
122
|
}
|
|
123
|
-
decrypt(
|
|
124
|
-
if (
|
|
123
|
+
decrypt(t, n, r, i, a, o, s, c) {
|
|
124
|
+
if (t === y) return a;
|
|
125
125
|
if (c) {
|
|
126
|
-
let
|
|
127
|
-
if (!Buffer.from(
|
|
126
|
+
let t = o.slice(0, _);
|
|
127
|
+
if (!Buffer.from(t).equals(Buffer.from(this.fakeSignature))) throw new e();
|
|
128
128
|
return a;
|
|
129
129
|
}
|
|
130
|
-
let [u, d] = this.getKeyNonce(!0,
|
|
130
|
+
let [u, d] = this.getKeyNonce(!0, n, r, t, s);
|
|
131
131
|
return new l(u).decrypt(d, i, a, o);
|
|
132
132
|
}
|
|
133
133
|
#t(e) {
|
|
@@ -162,4 +162,4 @@ function O(e, t) {
|
|
|
162
162
|
//#endregion
|
|
163
163
|
export { l as n, g as r, w as t };
|
|
164
164
|
|
|
165
|
-
//# sourceMappingURL=crypto-
|
|
165
|
+
//# sourceMappingURL=crypto-DLV3oH5F.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto-DLV3oH5F.js","names":["FakeSignatureMismatchError","importPublicKey","EAXTagMismatchError","EAX_TAG_SIZE","EAX_BLOCK_SIZE","EAX","key","#key","nStar","#cmac","nonce","hStar","header","ciphertext","aesCtr","plaintext","cStar","tag","i","expected","timingSafeEqual","input","data","tagByte","aesCmac","cipher","createCipheriv","iv","aesEcb","block","xorBlock","out","a","b","shiftLeft1","carry","shifted","RB","generateSubkeys","L","K1","K2","n","message","lastBlockComplete","X","lastBlock","lastStart","lastSlice","Mn","FAKE_SIGNATURE_SIZE","IV_ALPHA_SIZE","INIT1_PACKET_TYPE","PACKET_TYPE_MASK","INIT1_MAC","DUMMY_KEY","DUMMY_NONCE","Crypt","identity","level","xBytes","offset","nBytes","y","bytesToBigInt","bigIntToBytes","alphaBytes","alpha","betaBytes","beta","omegaBytes","omega","serverPubKey","sharedSecret","#getSharedSecret","sharedKey","digest","createHash","dummy","cacheKey","makeCacheKey","fromServer","packetType","generationID","kn","#cachedKeys","tmpToHash","hash","packetID","unencrypted","fsSub","privJwk","pubJwk","ecdh","createECDH","dBytes","base64UrlToBytes","yBytes","uncompressed","rawSecret","result","bytes","size","v","value","buf","b64url","padded"],"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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/discovery/resolver.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQhD,qBAAa,QAAQ;;
|
|
1
|
+
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/discovery/resolver.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQhD,qBAAa,QAAQ;;IAGnB,YAAY,IAAI,GAAE,MAAmB,EAAI;IAEnC,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CA+C9E;CAgEF"}
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,cAAe,SAAQ,KAAK;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAGlD;CACF;AAED,qBAAa,WAAY,SAAQ,cAAc;IAC7C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAE/B,YAAY,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAK5C;CACF;AAED,qBAAa,mBAAoB,SAAQ,cAAc;IACrD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,YAAY,OAAO,EAAE,MAAM,EAI1B;CACF;AAED,qBAAa,qBAAsB,SAAQ,cAAc;IACvD,cAGC;CACF;AAED,qBAAa,mBAAoB,SAAQ,cAAc;IACrD,cAGC;CACF;AAED,qBAAa,0BAA2B,SAAQ,cAAc;IAC5D,cAGC;CACF;AAED,qBAAa,iBAAkB,SAAQ,cAAc;IACnD,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAGlD;CACF;AAED,qBAAa,wBAAyB,SAAQ,cAAc;IAC1D,cAGC;CACF;AAED,qBAAa,eAAgB,SAAQ,cAAc;IACjD,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAGlD;CACF;AAED,qBAAa,oBAAqB,SAAQ,cAAc;IACtD,YAAY,OAAO,SAA4B,EAG9C;CACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { o as e, r as t } from "./address-BfmovVpp.js";
|
|
2
2
|
import { n } from "./crypt-handshake-DziOY4Lq.js";
|
|
3
|
-
import {
|
|
3
|
+
import { lookup as r } from "node:dns/promises";
|
|
4
4
|
import { createSocket as i } from "node:dgram";
|
|
5
5
|
//#region src/transport/packet.ts
|
|
6
6
|
var a = /* @__PURE__ */ function(e) {
|
|
@@ -163,85 +163,87 @@ var _ = 1024, v = 5e3, y = 6e4, b = 1e3, x = 8, S = 3, C = 5, w = 500, T = 100,
|
|
|
163
163
|
onClosed = null;
|
|
164
164
|
#e;
|
|
165
165
|
#t;
|
|
166
|
-
#n
|
|
167
|
-
#r =
|
|
168
|
-
#i =
|
|
169
|
-
#a =
|
|
166
|
+
#n;
|
|
167
|
+
#r = null;
|
|
168
|
+
#i = 0;
|
|
169
|
+
#a = !1;
|
|
170
170
|
#o = null;
|
|
171
|
-
#s =
|
|
172
|
-
#c =
|
|
173
|
-
#l = /* @__PURE__ */ new
|
|
174
|
-
#u = new
|
|
171
|
+
#s = null;
|
|
172
|
+
#c = Date.now();
|
|
173
|
+
#l = /* @__PURE__ */ new Uint16Array(9);
|
|
174
|
+
#u = /* @__PURE__ */ new Uint32Array(9);
|
|
175
175
|
#d = new p(65536, _);
|
|
176
176
|
#f = new p(65536, _);
|
|
177
177
|
#p = new p(65536, _);
|
|
178
|
-
#m =
|
|
178
|
+
#m = new p(65536, _);
|
|
179
179
|
#h = /* @__PURE__ */ new Map();
|
|
180
180
|
#g = /* @__PURE__ */ new Map();
|
|
181
|
-
#_ =
|
|
182
|
-
|
|
183
|
-
|
|
181
|
+
#_ = /* @__PURE__ */ new Map();
|
|
182
|
+
#v = null;
|
|
183
|
+
constructor(t, n = e, r) {
|
|
184
|
+
this.#e = t, this.#t = n, this.#n = r;
|
|
184
185
|
}
|
|
185
186
|
setClientID(e) {
|
|
186
|
-
this.#
|
|
187
|
+
this.#i = e;
|
|
187
188
|
}
|
|
188
|
-
connect(e) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
189
|
+
async connect(e) {
|
|
190
|
+
let { host: n, port: a } = t(e), o = parseInt(a, 10), { address: s, family: c } = await r(n), l = c === 6, u = this.#n ? this.#n(l ? 6 : 4) : i(l ? "udp6" : "udp4");
|
|
191
|
+
await new Promise((e, t) => {
|
|
192
|
+
let n = (e) => {
|
|
193
|
+
u.close(), t(e);
|
|
192
194
|
};
|
|
193
|
-
|
|
194
|
-
|
|
195
|
+
u.once("error", n), u.connect(o, s, () => {
|
|
196
|
+
u.off("error", n), this.start(u), e();
|
|
195
197
|
});
|
|
196
198
|
});
|
|
197
199
|
}
|
|
198
200
|
start(e) {
|
|
199
|
-
this.#
|
|
200
|
-
this.#
|
|
201
|
+
this.#r = e, this.#a = !1, this.#c = Date.now(), e.on("message", (e) => {
|
|
202
|
+
this.#c = Date.now(), this.#S(new Uint8Array(e.buffer, e.byteOffset, e.byteLength));
|
|
201
203
|
}), e.on("error", (e) => {
|
|
202
|
-
this.#t.error("udp error", e), this.#
|
|
203
|
-
}), e.on("close", () => this.#
|
|
204
|
+
this.#t.error("udp error", e), this.#z(e);
|
|
205
|
+
}), e.on("close", () => this.#z(null)), this.#l[a.Command] = 1, this.#l[a.Init1] = 101;
|
|
204
206
|
let t = n(this.#e, null);
|
|
205
|
-
t && this.#
|
|
207
|
+
t && this.#b(a.Init1, t, 0);
|
|
206
208
|
let r = setInterval(() => {
|
|
207
209
|
this.#e.cryptoInitComplete && this.sendPacket(a.Ping, /* @__PURE__ */ new Uint8Array(), o.Unencrypted);
|
|
208
210
|
}, v);
|
|
209
|
-
this.#
|
|
210
|
-
let i = setInterval(() => this.#
|
|
211
|
-
this.#
|
|
211
|
+
this.#o = () => clearInterval(r);
|
|
212
|
+
let i = setInterval(() => this.#L(), T);
|
|
213
|
+
this.#s = () => clearInterval(i);
|
|
212
214
|
}
|
|
213
215
|
receivedFinalInitAck() {
|
|
214
|
-
this.#
|
|
216
|
+
this.#v = null;
|
|
215
217
|
}
|
|
216
218
|
sendPacket(e, t, n) {
|
|
217
219
|
let r = !this.#e.cryptoInitComplete;
|
|
218
220
|
if (t.length > 487 && e !== a.Voice && e !== a.VoiceWhisper) {
|
|
219
|
-
this.#
|
|
221
|
+
this.#y(e, t, n, r);
|
|
220
222
|
return;
|
|
221
223
|
}
|
|
222
|
-
this.#
|
|
224
|
+
this.#b(e, t, n, r);
|
|
223
225
|
}
|
|
224
226
|
sendVoicePacket(e, t) {
|
|
225
|
-
let n = this.#
|
|
226
|
-
this.#
|
|
227
|
+
let n = this.#l[a.Voice], r = this.#u[a.Voice];
|
|
228
|
+
this.#l[a.Voice] = n + 1 & 65535, this.#l[a.Voice] === 0 && this.#u[a.Voice]++;
|
|
227
229
|
let i = S + e.length, s = new Uint8Array(i);
|
|
228
230
|
new DataView(s.buffer).setUint16(0, n, !1), s[2] = t, s.set(e, S);
|
|
229
231
|
let c = u({
|
|
230
232
|
typeFlagged: a.Voice | o.Unencrypted,
|
|
231
233
|
id: n,
|
|
232
|
-
clientID: this.#
|
|
234
|
+
clientID: this.#i,
|
|
233
235
|
generationID: r,
|
|
234
236
|
data: s,
|
|
235
237
|
receivedAt: 0
|
|
236
238
|
}), l = new Uint8Array(13 + i);
|
|
237
|
-
l.set(this.#e.fakeSignature, 0), l.set(c, x), l.set(s, 13), this.#
|
|
239
|
+
l.set(this.#e.fakeSignature, 0), l.set(c, x), l.set(s, 13), this.#x(l);
|
|
238
240
|
}
|
|
239
241
|
sendWhisperPacket(e, t, n) {
|
|
240
242
|
if (t.length === 0) throw Error("whisper requires at least one target");
|
|
241
243
|
if (t.length > 32) throw Error("too many whisper targets");
|
|
242
244
|
if (t.some((e) => !Number.isInteger(e) || e < 0 || e > 65535)) throw RangeError("invalid whisper target");
|
|
243
|
-
let r = this.#
|
|
244
|
-
this.#
|
|
245
|
+
let r = this.#l[a.VoiceWhisper], i = this.#u[a.VoiceWhisper];
|
|
246
|
+
this.#l[a.VoiceWhisper] = r + 1 & 65535, this.#l[a.VoiceWhisper] === 0 && (this.#u[a.VoiceWhisper] = i + 1 >>> 0);
|
|
245
247
|
let s = C + t.length * 2 + e.length, c = new Uint8Array(s), l = new DataView(c.buffer);
|
|
246
248
|
l.setUint16(0, r, !1), c[2] = n, c[3] = 0, c[4] = t.length;
|
|
247
249
|
for (let e = 0; e < t.length; e++) l.setUint16(C + e * 2, t[e], !1);
|
|
@@ -249,34 +251,34 @@ var _ = 1024, v = 5e3, y = 6e4, b = 1e3, x = 8, S = 3, C = 5, w = 500, T = 100,
|
|
|
249
251
|
let d = u({
|
|
250
252
|
typeFlagged: a.VoiceWhisper | o.Unencrypted,
|
|
251
253
|
id: r,
|
|
252
|
-
clientID: this.#
|
|
254
|
+
clientID: this.#i,
|
|
253
255
|
generationID: i,
|
|
254
256
|
data: c,
|
|
255
257
|
receivedAt: 0
|
|
256
258
|
}), f = new Uint8Array(13 + s);
|
|
257
|
-
f.set(this.#e.fakeSignature, 0), f.set(d, x), f.set(c, 13), this.#
|
|
259
|
+
f.set(this.#e.fakeSignature, 0), f.set(d, x), f.set(c, 13), this.#x(f);
|
|
258
260
|
}
|
|
259
261
|
close() {
|
|
260
|
-
this.#
|
|
262
|
+
this.#a || (this.#a = !0, this.#o?.(), this.#s?.(), this.#r?.close());
|
|
261
263
|
}
|
|
262
|
-
#
|
|
264
|
+
#y(e, t, n, r) {
|
|
263
265
|
let i = 0, a = !0;
|
|
264
266
|
for (; i < t.length;) {
|
|
265
267
|
let s = Math.min(t.length - i, 487), c = i + s === t.length, l = n;
|
|
266
|
-
a !== c && (l |= o.Fragmented), this.#
|
|
268
|
+
a !== c && (l |= o.Fragmented), this.#b(e, t.slice(i, i + s), l, r), i += s, a = !1;
|
|
267
269
|
}
|
|
268
270
|
}
|
|
269
|
-
#
|
|
271
|
+
#b(e, t, n, r = !this.#e.cryptoInitComplete) {
|
|
270
272
|
n = D(e, n);
|
|
271
|
-
let [i, a] = this.#
|
|
273
|
+
let [i, a] = this.#F(e), s = {
|
|
272
274
|
typeFlagged: e | n,
|
|
273
275
|
id: i,
|
|
274
|
-
clientID: this.#
|
|
276
|
+
clientID: this.#i,
|
|
275
277
|
generationID: a,
|
|
276
278
|
data: t,
|
|
277
279
|
receivedAt: 0
|
|
278
280
|
}, c = (n & o.Unencrypted) !== 0, l = u(s), [d, f] = this.#e.encrypt(e, i, a, l, t, r, c), p = new Uint8Array(13 + d.length);
|
|
279
|
-
p.set(f.slice(0, x), 0), p.set(l, x), p.set(d, 13), this.#
|
|
281
|
+
p.set(f.slice(0, x), 0), p.set(l, x), p.set(d, 13), this.#x(p);
|
|
280
282
|
let m = {
|
|
281
283
|
packet: s,
|
|
282
284
|
firstSend: Date.now(),
|
|
@@ -284,45 +286,45 @@ var _ = 1024, v = 5e3, y = 6e4, b = 1e3, x = 8, S = 3, C = 5, w = 500, T = 100,
|
|
|
284
286
|
retryCount: 0,
|
|
285
287
|
nextInterval: w
|
|
286
288
|
};
|
|
287
|
-
this.#
|
|
289
|
+
this.#I(e, s, m);
|
|
288
290
|
}
|
|
289
|
-
#
|
|
290
|
-
if (this.#
|
|
291
|
-
this.#
|
|
291
|
+
#x(e) {
|
|
292
|
+
if (this.#r) try {
|
|
293
|
+
this.#r.send(Buffer.from(e), (e) => {
|
|
292
294
|
e && this.#t.warn("udp send error", e);
|
|
293
295
|
});
|
|
294
296
|
} catch (e) {
|
|
295
297
|
let t = e instanceof Error ? e : Error(String(e));
|
|
296
|
-
this.#t.error("udp send failed", t), this.#
|
|
298
|
+
this.#t.error("udp send failed", t), this.#z(t);
|
|
297
299
|
}
|
|
298
300
|
}
|
|
299
|
-
#
|
|
301
|
+
#S(e) {
|
|
300
302
|
if (e.length < 11) return;
|
|
301
303
|
let t = e.slice(0, x), n = e.slice(x, 11), r = e.slice(11), i = d(n), o = {
|
|
302
304
|
...i,
|
|
303
305
|
clientID: 0,
|
|
304
|
-
generationID: this.#
|
|
306
|
+
generationID: this.#C(i.id, i.typeFlagged & 15),
|
|
305
307
|
data: /* @__PURE__ */ new Uint8Array(),
|
|
306
308
|
receivedAt: Date.now()
|
|
307
|
-
}, c = this.#
|
|
309
|
+
}, c = this.#w(o, n, r, t);
|
|
308
310
|
if (c !== null) {
|
|
309
311
|
if (o.data = c.plaintext, s(o) === a.Ping) {
|
|
310
|
-
this.#
|
|
312
|
+
this.#D(o.id, c.dummyUsed);
|
|
311
313
|
return;
|
|
312
314
|
}
|
|
313
|
-
this.#
|
|
315
|
+
this.#T(o, c.dummyUsed) && (this.#O(o), this.#P(o));
|
|
314
316
|
}
|
|
315
317
|
}
|
|
316
|
-
#
|
|
318
|
+
#C(e, t) {
|
|
317
319
|
switch (t) {
|
|
318
|
-
case a.Command: return this.#
|
|
319
|
-
case a.CommandLow: return this.#
|
|
320
|
-
case a.Ack: return this.#
|
|
321
|
-
case a.AckLow: return this.#
|
|
320
|
+
case a.Command: return this.#d.getGeneration(e);
|
|
321
|
+
case a.CommandLow: return this.#f.getGeneration(e);
|
|
322
|
+
case a.Ack: return this.#p.getGeneration(e);
|
|
323
|
+
case a.AckLow: return this.#m.getGeneration(e);
|
|
322
324
|
default: return 0;
|
|
323
325
|
}
|
|
324
326
|
}
|
|
325
|
-
#
|
|
327
|
+
#w(e, t, n, r) {
|
|
326
328
|
let i = (c(e) & o.Unencrypted) !== 0, l = !this.#e.cryptoInitComplete, u = l, d = s(e), f = e.generationID;
|
|
327
329
|
try {
|
|
328
330
|
return {
|
|
@@ -348,44 +350,44 @@ var _ = 1024, v = 5e3, y = 6e4, b = 1e3, x = 8, S = 3, C = 5, w = 500, T = 100,
|
|
|
348
350
|
return null;
|
|
349
351
|
}
|
|
350
352
|
}
|
|
351
|
-
#
|
|
353
|
+
#T(e, t) {
|
|
352
354
|
let n = s(e);
|
|
353
355
|
if (n !== a.Command && n !== a.CommandLow) return !0;
|
|
354
|
-
let r = n === a.Command ? this.#
|
|
355
|
-
return r.isInWindow(e.id) ? (this.#
|
|
356
|
+
let r = n === a.Command ? this.#d : this.#f, i = n === a.Command ? a.Ack : a.AckLow;
|
|
357
|
+
return r.isInWindow(e.id) ? (this.#E(e.id, i, t), !0) : (r.isOldPacket(e.id) && this.#E(e.id, i, t), !1);
|
|
356
358
|
}
|
|
357
|
-
#
|
|
359
|
+
#E(e, t, n) {
|
|
358
360
|
let r = /* @__PURE__ */ new Uint8Array(2);
|
|
359
|
-
new DataView(r.buffer).setUint16(0, e, !1), this.#
|
|
361
|
+
new DataView(r.buffer).setUint16(0, e, !1), this.#b(t, r, 0, n);
|
|
360
362
|
}
|
|
361
|
-
#
|
|
363
|
+
#D(e, t) {
|
|
362
364
|
let n = /* @__PURE__ */ new Uint8Array(2);
|
|
363
|
-
new DataView(n.buffer).setUint16(0, e, !1), this.#
|
|
365
|
+
new DataView(n.buffer).setUint16(0, e, !1), this.#b(a.Pong, n, o.Unencrypted, t);
|
|
364
366
|
}
|
|
365
|
-
#
|
|
367
|
+
#O(e) {
|
|
366
368
|
let t = s(e);
|
|
367
369
|
if (t !== a.Command && t !== a.CommandLow) {
|
|
368
370
|
this.onPacket?.(e);
|
|
369
371
|
return;
|
|
370
372
|
}
|
|
371
|
-
let n = t === a.Command, r = n ? this.#
|
|
372
|
-
for (r.set(e.id, e), n ? this.#
|
|
373
|
-
let e = n ? this.#
|
|
373
|
+
let n = t === a.Command, r = n ? this.#h : this.#g, i = n ? this.#d : this.#f;
|
|
374
|
+
for (r.set(e.id, e), n ? this.#j(r, i, !0) : this.#j(r, i, !1);;) {
|
|
375
|
+
let e = n ? this.#k : this.#A, t = r.get(e);
|
|
374
376
|
if (t === void 0) break;
|
|
375
|
-
let a = this.#
|
|
377
|
+
let a = this.#M(t, r, e, i);
|
|
376
378
|
if (!a) break;
|
|
377
379
|
let [o, s] = a;
|
|
378
|
-
n ? this.#
|
|
380
|
+
n ? this.#k = s : this.#A = s, this.#N(o), this.onPacket?.(o);
|
|
379
381
|
}
|
|
380
382
|
}
|
|
381
|
-
#O = 0;
|
|
382
383
|
#k = 0;
|
|
383
|
-
#A
|
|
384
|
-
|
|
384
|
+
#A = 0;
|
|
385
|
+
#j(e, t, n) {
|
|
386
|
+
let r = n ? this.#k : this.#A;
|
|
385
387
|
for (; !e.has(r) && O(e, r);) r = r + 1 & 65535, t.advance(1);
|
|
386
|
-
n ? this.#
|
|
388
|
+
n ? this.#k = r : this.#A = r;
|
|
387
389
|
}
|
|
388
|
-
#
|
|
390
|
+
#M(e, t, n, r) {
|
|
389
391
|
if ((c(e) & o.Fragmented) === 0) return t.delete(n), r.advance(1), [e, n + 1 & 65535];
|
|
390
392
|
let i = [], a = 0, s = n, l = !1, u = !1;
|
|
391
393
|
for (;;) {
|
|
@@ -409,7 +411,7 @@ var _ = 1024, v = 5e3, y = 6e4, b = 1e3, x = 8, S = 3, C = 5, w = 500, T = 100,
|
|
|
409
411
|
for (let e of i) d.set(e.data, f), f += e.data.length, t.delete(n), r.advance(1), n = n + 1 & 65535;
|
|
410
412
|
return e.data = d, e.typeFlagged &= ~o.Fragmented, [e, n];
|
|
411
413
|
}
|
|
412
|
-
#
|
|
414
|
+
#N(e) {
|
|
413
415
|
if ((c(e) & o.Compressed) !== 0) try {
|
|
414
416
|
e.data = new h().decompress(e.data), e.typeFlagged &= ~o.Compressed;
|
|
415
417
|
} catch (t) {
|
|
@@ -419,54 +421,54 @@ var _ = 1024, v = 5e3, y = 6e4, b = 1e3, x = 8, S = 3, C = 5, w = 500, T = 100,
|
|
|
419
421
|
});
|
|
420
422
|
}
|
|
421
423
|
}
|
|
422
|
-
#
|
|
424
|
+
#P(e) {
|
|
423
425
|
let t = s(e);
|
|
424
426
|
if (t === a.Init1) {
|
|
425
|
-
this.#
|
|
427
|
+
this.#v = null;
|
|
426
428
|
return;
|
|
427
429
|
}
|
|
428
430
|
if ((t === a.Ack || t === a.AckLow) && e.data.length >= 2) {
|
|
429
431
|
let n = new DataView(e.data.buffer, e.data.byteOffset).getUint16(0, !1), r = (t === a.Ack ? a.Command : a.CommandLow) << 16 | n;
|
|
430
|
-
this.#
|
|
432
|
+
this.#_.delete(r);
|
|
431
433
|
}
|
|
432
434
|
}
|
|
433
|
-
#
|
|
434
|
-
let t = this.#
|
|
435
|
-
return e === a.Init1 ? [t, n] : (this.#
|
|
435
|
+
#F(e) {
|
|
436
|
+
let t = this.#l[e], n = this.#u[e];
|
|
437
|
+
return e === a.Init1 ? [t, n] : (this.#l[e] = t + 1 & 65535, this.#l[e] === 0 && (this.#u[e] = n + 1 >>> 0), e === a.Command ? this.#p.advanceToExcluded(t) : e === a.CommandLow && this.#m.advanceToExcluded(t), [t, n]);
|
|
436
438
|
}
|
|
437
|
-
#
|
|
439
|
+
#I(e, t, n) {
|
|
438
440
|
if (e === a.Init1) {
|
|
439
|
-
this.#
|
|
441
|
+
this.#v = n;
|
|
440
442
|
return;
|
|
441
443
|
}
|
|
442
444
|
if (e === a.Command || e === a.CommandLow) {
|
|
443
445
|
let r = e << 16 | t.id;
|
|
444
|
-
this.#
|
|
446
|
+
this.#_.set(r, n);
|
|
445
447
|
}
|
|
446
448
|
}
|
|
447
|
-
#
|
|
449
|
+
#L() {
|
|
448
450
|
let e = Date.now();
|
|
449
|
-
if (e - this.#
|
|
450
|
-
this.#t.warn("idle timeout"), this.#
|
|
451
|
+
if (e - this.#c > y) {
|
|
452
|
+
this.#t.warn("idle timeout"), this.#z(/* @__PURE__ */ Error("idle timeout"));
|
|
451
453
|
return;
|
|
452
454
|
}
|
|
453
|
-
this.#
|
|
454
|
-
for (let [t, n] of this.#
|
|
455
|
+
this.#v && this.#R(this.#v, e);
|
|
456
|
+
for (let [t, n] of this.#_) {
|
|
455
457
|
if (e - n.firstSend > y) {
|
|
456
|
-
this.#
|
|
458
|
+
this.#_.delete(t), this.#z(/* @__PURE__ */ Error("packet ack timeout"));
|
|
457
459
|
return;
|
|
458
460
|
}
|
|
459
|
-
this.#
|
|
461
|
+
this.#R(n, e);
|
|
460
462
|
}
|
|
461
463
|
}
|
|
462
|
-
#
|
|
464
|
+
#R(e, t) {
|
|
463
465
|
if (t - e.lastSend < e.nextInterval) return;
|
|
464
466
|
e.lastSend = t, e.retryCount++, e.nextInterval = Math.min(e.nextInterval * 2, b);
|
|
465
467
|
let n = !this.#e.cryptoInitComplete, r = (c(e.packet) & o.Unencrypted) !== 0, i = u(e.packet), a = s(e.packet), [l, d] = this.#e.encrypt(a, e.packet.id, e.packet.generationID, i, e.packet.data, n, r), f = new Uint8Array(13 + l.length);
|
|
466
|
-
f.set(d.slice(0, x), 0), f.set(i, x), f.set(l, 13), this.#
|
|
468
|
+
f.set(d.slice(0, x), 0), f.set(i, x), f.set(l, 13), this.#x(f);
|
|
467
469
|
}
|
|
468
|
-
#
|
|
469
|
-
this.#
|
|
470
|
+
#z(e) {
|
|
471
|
+
this.#a || (this.close(), this.onClosed?.(e));
|
|
470
472
|
}
|
|
471
473
|
};
|
|
472
474
|
function D(e, t) {
|
|
@@ -480,4 +482,4 @@ function O(e, t) {
|
|
|
480
482
|
//#endregion
|
|
481
483
|
export { a, c, d, o as i, s as l, h as n, u as o, p as r, l as s, E as t, f as u };
|
|
482
484
|
|
|
483
|
-
//# sourceMappingURL=handler-
|
|
485
|
+
//# sourceMappingURL=handler-BpdZFsKo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-BpdZFsKo.js","names":["noopLogger","splitHostPort","PacketType","\"Voice\"","\"VoiceWhisper\"","\"Command\"","\"CommandLow\"","\"Ping\"","\"Pong\"","\"Ack\"","\"AckLow\"","\"Init1\"","PacketFlags","\"Fragmented\"","\"NewProtocol\"","\"Compressed\"","\"Unencrypted\"","packetType","p","packetFlags","isUnencrypted","buildC2SHeader","header","view","parseS2CHeader","raw","parseC2SHeader","GenerationWindow","#mod","mod","#receiveWindow","windowSize","#generation","amount","newBaseOffset","#mappedBaseOffset","genStep","moveDist","mappedValue","maxOffset","#isNextGen","TABLE_SIZE","Qlz","parseQlzHeader","data","dest","decompressedSize","flags","headerLen","#hashtable","state","#ensureControl","#processReference","#processLiteral","st","b1","b2","hash","matchlen","offset","i","end","#updateHashtable","threshold","v","RECEIVE_PACKET_WINDOW_SIZE","PING_INTERVAL_MS","PACKET_TIMEOUT_MS","MAX_RETRY_INTERVAL_MS","TAG_SIZE","VOICE_HEADER_SIZE","WHISPER_HEADER_SIZE","RESEND_BASE_INTERVAL_MS","RESEND_LOOP_INTERVAL_MS","PacketHandler","#crypt","crypt","#logger","logger","#socketFactory","socketFactory","#clientID","id","addr","portNumber","port","lookup","host","family6","family","socket","createSocket","onError","reject","error","address","resolve","#conn","conn","#closed","#lastMessageReceived","#handleRawPacket","msg","err","#triggerClose","#packetCounter","init1Data","processInit1","#sendPacketRaw","pingTimer","#stopPing","resendTimer","#checkResends","#stopResend","#initPacketCheck","dummy","pType","#sendSplitPacket","pID","pGen","#generationCounter","payloadLen","voicePayload","codec","final","#write","targetClientIds","whisperPayload","index","pos","first","blockSize","last","pFlags","applyProtocolFlags","#nextPacketIdentity","unencrypted","ciphertext","tag","rp","#trackResend","normalized","parsed","#resolveGeneration","decrypted","#decryptPacketData","#sendPong","#handleCommandWindowAndAck","#handlePacketQueue","#updatePostReceiveState","#recvWindowCommand","#recvWindowCommandLow","#sendWindowCommand","#sendWindowCommandLow","dummyUsed","gen","guessGen","win","ackType","#sendAck","ackData","packetID","pongData","isCommand","queue","#commandQueue","#commandLowQueue","#fastForwardMissingPackets","current","#_nextCommandID","#_nextCommandLowID","packet","result","#tryReassemble","reassembled","newNext","#tryDecompress","nextID","hasOldNewerPacket","startPacket","fragments","totalSize","currID","startSeen","complete","frag","fragmented","combined","ackID","key","#ackManager","now","#doResend","pkg"],"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 { lookup } from \"node:dns/promises\";\nimport { splitHostPort } from \"../address.js\";\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 WHISPER_HEADER_SIZE = 5;\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\n/**\n * Creates the UDP socket the client talks through.\n *\n * Receives the resolved address family (4 or 6) and returns a socket of that\n * family. Supplying one lets an application route through a proxy or tunnel,\n * or drive the client from something other than a real socket.\n */\nexport type SocketFactory = (family: 4 | 6) => UdpSocket;\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 readonly #socketFactory: SocketFactory | undefined;\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, socketFactory?: SocketFactory) {\n this.#crypt = crypt;\n this.#logger = logger;\n this.#socketFactory = socketFactory;\n }\n\n setClientID(id: number): void {\n this.#clientID = id;\n }\n\n async connect(addr: string): Promise<void> {\n const { host, port } = splitHostPort(addr);\n const portNumber = parseInt(port, 10);\n\n // Resolve before choosing a socket family. `isIP()` only recognises literal\n // addresses and returns 0 for every hostname, so picking the family from it\n // sent every hostname to a udp4 socket — and a udp4 socket handed a name\n // that resolves to IPv6 drops the datagrams with no error at all. On a\n // stock macOS/Linux box `localhost` resolves to ::1 first, so that path\n // silently never connected. Let DNS decide, then match the family.\n const { address, family } = await lookup(host);\n\n const family6 = family === 6;\n const socket = this.#socketFactory\n ? this.#socketFactory(family6 ? 6 : 4)\n : createSocket(family6 ? \"udp6\" : \"udp4\");\n\n await new Promise<void>((resolve, reject) => {\n const onError = (error: Error) => {\n socket.close();\n reject(error);\n };\n socket.once(\"error\", onError);\n // Connect to the resolved address, not the original host, so the socket\n // cannot end up talking to a different family than it was created for.\n socket.connect(portNumber, address, () => {\n socket.off(\"error\", onError);\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 /** Send an unencrypted TeamSpeak voice whisper packet to up to 32 clients. */\n sendWhisperPacket(data: Uint8Array, targetClientIds: number[], codec: number): void {\n if (targetClientIds.length === 0) throw new Error(\"whisper requires at least one target\");\n if (targetClientIds.length > 32) throw new Error(\"too many whisper targets\");\n if (targetClientIds.some((id) => !Number.isInteger(id) || id < 0 || id > 0xffff)) {\n throw new RangeError(\"invalid whisper target\");\n }\n\n const pID = this.#packetCounter[PacketType.VoiceWhisper]!;\n const pGen = this.#generationCounter[PacketType.VoiceWhisper]!;\n this.#packetCounter[PacketType.VoiceWhisper] = (pID + 1) & 0xffff;\n if (this.#packetCounter[PacketType.VoiceWhisper] === 0) {\n this.#generationCounter[PacketType.VoiceWhisper] = (pGen + 1) >>> 0;\n }\n\n const payloadLen = WHISPER_HEADER_SIZE + targetClientIds.length * 2 + data.length;\n const whisperPayload = new Uint8Array(payloadLen);\n const view = new DataView(whisperPayload.buffer);\n view.setUint16(0, pID, false);\n whisperPayload[2] = codec;\n whisperPayload[3] = 0;\n whisperPayload[4] = targetClientIds.length;\n for (let index = 0; index < targetClientIds.length; index++) {\n view.setUint16(WHISPER_HEADER_SIZE + index * 2, targetClientIds[index]!, false);\n }\n whisperPayload.set(data, WHISPER_HEADER_SIZE + targetClientIds.length * 2);\n\n const packet: Packet = {\n typeFlagged: PacketType.VoiceWhisper | PacketFlags.Unencrypted,\n id: pID,\n clientID: this.#clientID,\n generationID: pGen,\n data: whisperPayload,\n receivedAt: 0,\n };\n const header = buildC2SHeader(packet);\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(whisperPayload, 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 if (!this.#conn) return;\n try {\n this.#conn.send(Buffer.from(data), (err) => {\n if (err) this.#logger.warn(\"udp send error\", err);\n });\n } catch (error: unknown) {\n const normalized = error instanceof Error ? error : new Error(String(error));\n // dgram can throw synchronously for an invalid family/address pair. A\n // malformed remote target must close this session, never escape from an\n // async socket callback and terminate the gateway process.\n this.#logger.error(\"udp send failed\", normalized);\n this.#triggerClose(normalized);\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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"}
|