@honeybbq/teamspeak-client 0.2.2 → 0.2.3
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/command/index.cjs +1 -1
- package/dist/command/index.mjs +2 -2
- package/dist/{command-caXc4h0n.js → command-CTDmBXd_.js} +1 -1
- package/dist/{command-caXc4h0n.js.map → command-CTDmBXd_.js.map} +1 -1
- package/dist/{command-Cu2v-5-K.cjs → command-CUPNiKRl.cjs} +2 -2
- package/dist/{command-Cu2v-5-K.cjs.map → command-CUPNiKRl.cjs.map} +1 -1
- package/dist/crypt-handshake-D2Rsi2e3.cjs +2 -0
- package/dist/{crypt-handshake-Dbj2cSBZ.cjs.map → crypt-handshake-D2Rsi2e3.cjs.map} +1 -1
- package/dist/crypt-handshake-DIj51kno.js +55 -0
- package/dist/{crypt-handshake-CHmvZ2qs.js.map → crypt-handshake-DIj51kno.js.map} +1 -1
- package/dist/{crypt-init2-DWX7Tp-_.js → crypt-init2-C2X9oK4i.js} +24 -26
- package/dist/{crypt-init2-DWX7Tp-_.js.map → crypt-init2-C2X9oK4i.js.map} +1 -1
- package/dist/crypt-init2-CazdFwqF.cjs +2 -0
- package/dist/{crypt-init2-C2oihZ7e.cjs.map → crypt-init2-CazdFwqF.cjs.map} +1 -1
- package/dist/crypto/index.cjs +1 -1
- package/dist/crypto/index.mjs +2 -2
- package/dist/{crypto-VC7n6YJb.js → crypto-CwIMggQG.js} +4 -4
- package/dist/{crypto-VC7n6YJb.js.map → crypto-CwIMggQG.js.map} +1 -1
- package/dist/{crypto-2veVY1fC.cjs → crypto-IbzNNTgO.cjs} +2 -2
- package/dist/{crypto-2veVY1fC.cjs.map → crypto-IbzNNTgO.cjs.map} +1 -1
- package/dist/discovery/index.cjs +1 -1
- package/dist/discovery/index.mjs +1 -1
- package/dist/handler-BJdwhtkp.cjs +2 -0
- package/dist/{handler-CqCD93f0.cjs.map → handler-BJdwhtkp.cjs.map} +1 -1
- package/dist/{handler-C_JhqGTd.js → handler-BP38rMNl.js} +18 -18
- package/dist/{handler-C_JhqGTd.js.map → handler-BP38rMNl.js.map} +1 -1
- package/dist/handshake/index.cjs +1 -1
- package/dist/handshake/index.mjs +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +11 -11
- package/dist/index.mjs.map +1 -1
- package/dist/{parser-DhAWj-TI.cjs → parser-B6cGUByG.cjs} +2 -2
- package/dist/{parser-DhAWj-TI.cjs.map → parser-B6cGUByG.cjs.map} +1 -1
- package/dist/{parser-CJjP3LlO.js → parser-BPzO8py_.js} +2 -2
- package/dist/{parser-CJjP3LlO.js.map → parser-BPzO8py_.js.map} +1 -1
- package/dist/primitives-Bt-L4BZa.js +1483 -0
- package/dist/primitives-Bt-L4BZa.js.map +1 -0
- package/dist/primitives-ClIhDdNZ.cjs +2 -0
- package/dist/primitives-ClIhDdNZ.cjs.map +1 -0
- package/dist/{resolver-DDD2FFhD.cjs → resolver-B7jho9CP.cjs} +3 -3
- package/dist/{resolver-DDD2FFhD.cjs.map → resolver-B7jho9CP.cjs.map} +1 -1
- package/dist/{resolver-Br0QefWx.js → resolver-BDCF2KbM.js} +2 -2
- package/dist/{resolver-Br0QefWx.js.map → resolver-BDCF2KbM.js.map} +1 -1
- package/dist/transport/index.cjs +1 -1
- package/dist/transport/index.mjs +1 -1
- package/dist/{types-DrnoCdSW.cjs → types-ANvuLFWH.cjs} +2 -2
- package/dist/{types-DrnoCdSW.cjs.map → types-ANvuLFWH.cjs.map} +1 -1
- package/dist/{types-CGKgXvpG.js → types-Xm1vrW4s.js} +1 -1
- package/dist/{types-CGKgXvpG.js.map → types-Xm1vrW4s.js.map} +1 -1
- package/package.json +3 -3
- package/dist/crypt-handshake-CHmvZ2qs.js +0 -55
- package/dist/crypt-handshake-Dbj2cSBZ.cjs +0 -2
- package/dist/crypt-init2-C2oihZ7e.cjs +0 -2
- package/dist/handler-CqCD93f0.cjs +0 -2
- package/dist/primitives-BIAYfJ2Y.js +0 -1842
- package/dist/primitives-BIAYfJ2Y.js.map +0 -1
- package/dist/primitives-bj-ml31v.cjs +0 -2
- package/dist/primitives-bj-ml31v.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto-VC7n6YJb.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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"}
|
|
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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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(
|
|
2
|
-
//# sourceMappingURL=crypto-
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto-2veVY1fC.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
|
+
{"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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"}
|
package/dist/discovery/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../resolver-B7jho9CP.cjs");exports.Resolver=e.t;
|
package/dist/discovery/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as e } from "../resolver-
|
|
1
|
+
import { t as e } from "../resolver-BDCF2KbM.js";
|
|
2
2
|
export { e as Resolver };
|
|
@@ -0,0 +1,2 @@
|
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler-CqCD93f0.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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"}
|
|
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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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as e } from "./types-
|
|
2
|
-
import { n as t } from "./crypt-handshake-
|
|
1
|
+
import { r as e } from "./types-Xm1vrW4s.js";
|
|
2
|
+
import { n as t } from "./crypt-handshake-DIj51kno.js";
|
|
3
3
|
import { createSocket as n } from "node:dgram";
|
|
4
4
|
//#region src/transport/packet.ts
|
|
5
5
|
var r = /* @__PURE__ */ function(e) {
|
|
@@ -14,10 +14,10 @@ function o(e) {
|
|
|
14
14
|
return e.typeFlagged & 240;
|
|
15
15
|
}
|
|
16
16
|
function s(e) {
|
|
17
|
-
return (o(e) &
|
|
17
|
+
return (o(e) & 128) != 0;
|
|
18
18
|
}
|
|
19
19
|
function c(e) {
|
|
20
|
-
let t = new Uint8Array(5), n = new DataView(t.buffer);
|
|
20
|
+
let t = /* @__PURE__ */ new Uint8Array(5), n = new DataView(t.buffer);
|
|
21
21
|
return n.setUint16(0, e.id, !1), n.setUint16(2, e.clientID, !1), t[4] = e.typeFlagged, t;
|
|
22
22
|
}
|
|
23
23
|
function l(e) {
|
|
@@ -168,8 +168,8 @@ var h = 500, g = 1024, _ = 5e3, v = 6e4, y = 1e3, b = 5, x = 8, S = 3, C = 500,
|
|
|
168
168
|
#a = null;
|
|
169
169
|
#o = null;
|
|
170
170
|
#s = Date.now();
|
|
171
|
-
#c = new Uint16Array(9);
|
|
172
|
-
#l = new Uint32Array(9);
|
|
171
|
+
#c = /* @__PURE__ */ new Uint16Array(9);
|
|
172
|
+
#l = /* @__PURE__ */ new Uint32Array(9);
|
|
173
173
|
#u = new d(65536, g);
|
|
174
174
|
#d = new d(65536, g);
|
|
175
175
|
#f = new d(65536, g);
|
|
@@ -201,7 +201,7 @@ var h = 500, g = 1024, _ = 5e3, v = 6e4, y = 1e3, b = 5, x = 8, S = 3, C = 500,
|
|
|
201
201
|
let n = t(this.#e, null);
|
|
202
202
|
n && this.#y(r.Init1, n, 0);
|
|
203
203
|
let a = setInterval(() => {
|
|
204
|
-
this.#e.cryptoInitComplete && this.sendPacket(r.Ping, new Uint8Array(), i.Unencrypted);
|
|
204
|
+
this.#e.cryptoInitComplete && this.sendPacket(r.Ping, /* @__PURE__ */ new Uint8Array(), i.Unencrypted);
|
|
205
205
|
}, _);
|
|
206
206
|
this.#a = () => clearInterval(a);
|
|
207
207
|
let o = setInterval(() => this.#I(), w);
|
|
@@ -230,8 +230,8 @@ var h = 500, g = 1024, _ = 5e3, v = 6e4, y = 1e3, b = 5, x = 8, S = 3, C = 500,
|
|
|
230
230
|
generationID: a,
|
|
231
231
|
data: s,
|
|
232
232
|
receivedAt: 0
|
|
233
|
-
}), u = new Uint8Array(
|
|
234
|
-
u.set(this.#e.fakeSignature, 0), u.set(l, x), u.set(s,
|
|
233
|
+
}), u = new Uint8Array(13 + o);
|
|
234
|
+
u.set(this.#e.fakeSignature, 0), u.set(l, x), u.set(s, 13), this.#b(u);
|
|
235
235
|
}
|
|
236
236
|
close() {
|
|
237
237
|
this.#i || (this.#i = !0, this.#a?.(), this.#o?.(), this.#n?.close());
|
|
@@ -252,8 +252,8 @@ var h = 500, g = 1024, _ = 5e3, v = 6e4, y = 1e3, b = 5, x = 8, S = 3, C = 500,
|
|
|
252
252
|
generationID: o,
|
|
253
253
|
data: t,
|
|
254
254
|
receivedAt: 0
|
|
255
|
-
}, l = (n & i.Unencrypted) !== 0, u = c(s), [d, f] = this.#e.encrypt(e, a, o, u, t, r, l), p = new Uint8Array(
|
|
256
|
-
p.set(f.slice(0, x), 0), p.set(u, x), p.set(d,
|
|
255
|
+
}, 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);
|
|
256
|
+
p.set(f.slice(0, x), 0), p.set(u, x), p.set(d, 13), this.#b(p);
|
|
257
257
|
let m = {
|
|
258
258
|
packet: s,
|
|
259
259
|
firstSend: Date.now(),
|
|
@@ -270,11 +270,11 @@ var h = 500, g = 1024, _ = 5e3, v = 6e4, y = 1e3, b = 5, x = 8, S = 3, C = 500,
|
|
|
270
270
|
}
|
|
271
271
|
#x(e) {
|
|
272
272
|
if (e.length < 11) return;
|
|
273
|
-
let t = e.slice(0, x), n = e.slice(x,
|
|
273
|
+
let t = e.slice(0, x), n = e.slice(x, 11), i = e.slice(11), o = l(n), s = {
|
|
274
274
|
...o,
|
|
275
275
|
clientID: 0,
|
|
276
276
|
generationID: this.#S(o.id, o.typeFlagged & 15),
|
|
277
|
-
data: new Uint8Array(),
|
|
277
|
+
data: /* @__PURE__ */ new Uint8Array(),
|
|
278
278
|
receivedAt: Date.now()
|
|
279
279
|
}, c = this.#C(s, n, i, t);
|
|
280
280
|
if (c !== null) {
|
|
@@ -327,11 +327,11 @@ var h = 500, g = 1024, _ = 5e3, v = 6e4, y = 1e3, b = 5, x = 8, S = 3, C = 500,
|
|
|
327
327
|
return i.isInWindow(e.id) ? (this.#T(e.id, o, t), !0) : (i.isOldPacket(e.id) && this.#T(e.id, o, t), !1);
|
|
328
328
|
}
|
|
329
329
|
#T(e, t, n) {
|
|
330
|
-
let r = new Uint8Array(2);
|
|
330
|
+
let r = /* @__PURE__ */ new Uint8Array(2);
|
|
331
331
|
new DataView(r.buffer).setUint16(0, e, !1), this.#y(t, r, 0, n);
|
|
332
332
|
}
|
|
333
333
|
#E(e, t) {
|
|
334
|
-
let n = new Uint8Array(2);
|
|
334
|
+
let n = /* @__PURE__ */ new Uint8Array(2);
|
|
335
335
|
new DataView(n.buffer).setUint16(0, e, !1), this.#y(r.Pong, n, i.Unencrypted, t);
|
|
336
336
|
}
|
|
337
337
|
#D(e) {
|
|
@@ -434,8 +434,8 @@ var h = 500, g = 1024, _ = 5e3, v = 6e4, y = 1e3, b = 5, x = 8, S = 3, C = 500,
|
|
|
434
434
|
#L(e, t) {
|
|
435
435
|
if (t - e.lastSend < e.nextInterval) return;
|
|
436
436
|
e.lastSend = t, e.retryCount++, e.nextInterval = Math.min(e.nextInterval * 2, y);
|
|
437
|
-
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(
|
|
438
|
-
f.set(d.slice(0, x), 0), f.set(s, x), f.set(u,
|
|
437
|
+
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);
|
|
438
|
+
f.set(d.slice(0, x), 0), f.set(s, x), f.set(u, 13), this.#b(f);
|
|
439
439
|
}
|
|
440
440
|
#R(e) {
|
|
441
441
|
this.#i || (this.close(), this.onClosed?.(e));
|
|
@@ -452,4 +452,4 @@ function D(e, t) {
|
|
|
452
452
|
//#endregion
|
|
453
453
|
export { r as a, o as c, l as d, i, a as l, p as n, c as o, d as r, s, T as t, u };
|
|
454
454
|
|
|
455
|
-
//# sourceMappingURL=handler-
|
|
455
|
+
//# sourceMappingURL=handler-BP38rMNl.js.map
|