@honeybbq/teamspeak-client 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/address-BR-5unVo.cjs.map +1 -1
- package/dist/address-BfmovVpp.js.map +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/command-BLe-C2L2.js.map +1 -1
- package/dist/command-DAK4pUBP.cjs.map +1 -1
- package/dist/commands.d.ts.map +1 -1
- package/dist/crypt-handshake-CQkQreLx.cjs.map +1 -1
- package/dist/crypt-handshake-DziOY4Lq.js.map +1 -1
- package/dist/crypt-init2-D70ha4LB.js.map +1 -1
- package/dist/crypt-init2-DparLekm.cjs.map +1 -1
- package/dist/crypto/crypt.d.ts.map +1 -1
- package/dist/crypto/eax.d.ts.map +1 -1
- package/dist/crypto/identity.d.ts.map +1 -1
- package/dist/crypto-Bg02m4ZE.js.map +1 -1
- package/dist/crypto-CDlweUL3.cjs.map +1 -1
- package/dist/discovery/resolver.d.ts.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/handler-DI_abe9c.js.map +1 -1
- package/dist/handler-DuwoO5RC.cjs.map +1 -1
- package/dist/handshake/license.d.ts.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +96 -65
- package/dist/index.mjs.map +1 -1
- package/dist/parser-CL33R9tr.cjs.map +1 -1
- package/dist/parser-DZMv3Jm-.js.map +1 -1
- package/dist/primitives-cNNAeFCo.cjs.map +1 -1
- package/dist/primitives-xIr6Tjk4.js.map +1 -1
- package/dist/resolver-6B8dI9gr.js.map +1 -1
- package/dist/resolver-DCcmyWSK.cjs.map +1 -1
- package/dist/throttle.d.ts.map +1 -1
- package/dist/transfer.d.ts.map +1 -1
- package/dist/transport/generation-window.d.ts.map +1 -1
- package/dist/transport/handler.d.ts.map +1 -1
- package/dist/transport/quicklz.d.ts.map +1 -1
- package/package.json +4 -5
- package/dist/address.test.d.ts +0 -2
- package/dist/address.test.d.ts.map +0 -1
- package/dist/api.test.d.ts +0 -2
- package/dist/api.test.d.ts.map +0 -1
- package/dist/command/command.test.d.ts +0 -2
- package/dist/command/command.test.d.ts.map +0 -1
- package/dist/crypto/eax.test.d.ts +0 -2
- package/dist/crypto/eax.test.d.ts.map +0 -1
- package/dist/crypto/identity.test.d.ts +0 -2
- package/dist/crypto/identity.test.d.ts.map +0 -1
- package/dist/handshake.test.d.ts +0 -2
- package/dist/handshake.test.d.ts.map +0 -1
- package/dist/helpers.test.d.ts +0 -2
- package/dist/helpers.test.d.ts.map +0 -1
- package/dist/integration.test.d.ts +0 -12
- package/dist/integration.test.d.ts.map +0 -1
- package/dist/notifications.test.d.ts +0 -2
- package/dist/notifications.test.d.ts.map +0 -1
- package/dist/throttle.test.d.ts +0 -2
- package/dist/throttle.test.d.ts.map +0 -1
- package/dist/transport/generation-window.test.d.ts +0 -2
- package/dist/transport/generation-window.test.d.ts.map +0 -1
- package/dist/transport/packet.test.d.ts +0 -2
- package/dist/transport/packet.test.d.ts.map +0 -1
- package/dist/transport/quicklz.test.d.ts +0 -2
- package/dist/transport/quicklz.test.d.ts.map +0 -1
- package/dist/transport/whisper.test.d.ts +0 -2
- package/dist/transport/whisper.test.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"address-BR-5unVo.cjs","names":[],"sources":["../src/types.ts","../src/address.ts"],"sourcesContent":["// ---- Branded primitive types ------------------------------------------------\n\n/** A TS3-escaped string. Obtained only via escape(). */\nexport type EscapedString = string & { readonly __escaped: unique symbol };\n\n// ---- Event map --------------------------------------------------------------\n\nexport interface TextMessage {\n invokerName: string;\n invokerUID: string;\n message: string;\n invokerGroups: string[];\n targetMode: number;\n targetID: bigint;\n invokerID: number;\n}\n\nexport interface ClientMovedEvent {\n invokerName: string;\n invokerUID: string;\n targetChannelID: bigint;\n reasonID: number;\n id: number;\n invokerID: number;\n}\n\nexport interface ClientLeftViewEvent {\n reasonMsg: string;\n reasonID: number;\n id: number;\n targetID: number;\n}\n\nexport interface ClientInfo {\n nickname: string;\n uid: string;\n serverGroups: string[];\n channelID: bigint;\n type: number;\n id: number;\n}\n\nexport interface ChannelInfo {\n name: string;\n description: string;\n id: bigint;\n parentID: bigint;\n /** ID of the sibling channel this one is sorted after; 0 means first. */\n order: bigint;\n}\n\nexport interface FileUploadInfo {\n fileTransferKey: string;\n seekPosition: bigint;\n clientFileTransferID: number;\n serverFileTransferID: number;\n port: number;\n}\n\nexport interface FileDownloadInfo {\n fileTransferKey: string;\n size: bigint;\n clientFileTransferID: number;\n serverFileTransferID: number;\n port: number;\n}\n\nexport interface FileTransferStatusInfo {\n message: string;\n status: number;\n clientFileTransferID: number;\n}\n\nexport interface PokeEvent {\n invokerName: string;\n invokerUID: string;\n invokerID: number;\n message: string;\n}\n\nexport interface VoiceData {\n clientId: number;\n codec: number;\n data: Uint8Array;\n}\n\n// ---- Typed event map used by Client.on() ------------------------------------\n\nexport interface EventMap {\n textMessage: TextMessage;\n clientEnter: ClientInfo;\n clientLeave: ClientLeftViewEvent;\n clientMoved: ClientMovedEvent;\n poked: PokeEvent;\n voiceData: VoiceData;\n connected: void;\n disconnected: Error | undefined;\n kicked: string;\n}\n\n// ---- Client status ----------------------------------------------------------\n\nexport const enum ClientStatus {\n Disconnected = 0,\n Connecting = 1,\n Connected = 2,\n}\n\n// ---- Middleware types --------------------------------------------------------\n\nexport type CommandMiddleware = (\n next: (cmd: string) => Promise<void>,\n) => (cmd: string) => Promise<void>;\n\nexport type EventMiddleware = (\n next: (evt: EventMap[keyof EventMap]) => void,\n) => (evt: EventMap[keyof EventMap]) => void;\n\n// ---- Logger interface --------------------------------------------------------\n\nexport interface Logger {\n debug(msg: string, ...args: unknown[]): void;\n info(msg: string, ...args: unknown[]): void;\n warn(msg: string, ...args: unknown[]): void;\n error(msg: string, ...args: unknown[]): void;\n}\n\n/** A no-op logger that discards all messages. */\nexport const noopLogger: Logger = {\n debug() {},\n info() {},\n warn() {},\n error() {},\n};\n\n/** A console-backed logger. */\nexport const consoleLogger: Logger = {\n debug: console.debug.bind(console),\n info: console.info.bind(console),\n warn: console.warn.bind(console),\n error: console.error.bind(console),\n};\n\n// ---- Resolved address (from discovery) --------------------------------------\n\nexport interface ResolvedAddr {\n addr: string;\n source: string;\n expiry: Date;\n}\n\n// ---- AddrResolver interface -------------------------------------------------\n\nexport interface AddrResolver {\n resolve(addr: string, signal?: AbortSignal): Promise<ResolvedAddr[]>;\n}\n\n// ---- ClientOptions ----------------------------------------------------------\n\nexport interface ClientOptions {\n logger?: Logger;\n resolver?: AddrResolver;\n commandMiddleware?: CommandMiddleware[];\n eventMiddleware?: EventMiddleware[];\n /** Server password sent during the initial `clientinit` handshake. */\n serverPassword?: string;\n /** Default channel name to join during the initial `clientinit` handshake. */\n defaultChannel?: string;\n /** Password for `defaultChannel`, sent during the initial `clientinit` handshake. */\n defaultChannelPassword?: string;\n}\n","import { isIP } from \"node:net\";\n\nexport interface HostPort {\n host: string;\n port: string;\n}\n\n/** Parse a TeamSpeak address without confusing an IPv6 colon for a port separator. */\nexport function splitHostPort(address: string, defaultPort = \"9987\"): HostPort {\n const input = address.trim();\n if (input.startsWith(\"[\")) {\n const closingBracket = input.indexOf(\"]\");\n if (closingBracket > 0) {\n const host = input.slice(1, closingBracket);\n const suffix = input.slice(closingBracket + 1);\n if (suffix.startsWith(\":\") && /^\\d+$/.test(suffix.slice(1))) {\n return { host, port: suffix.slice(1) };\n }\n if (!suffix) return { host, port: defaultPort };\n }\n }\n\n // A raw IPv6 literal has no unambiguous port separator. Internal callers\n // normally use bracket notation, but accepting the literal with the default\n // port prevents a final IPv6 segment from being mistaken for a port.\n if (isIP(input) === 6) return { host: input, port: defaultPort };\n\n const lastColon = input.lastIndexOf(\":\");\n if (lastColon < 0) return { host: input, port: defaultPort };\n const candidatePort = input.slice(lastColon + 1);\n if (/^\\d+$/.test(candidatePort) && input.indexOf(\":\") === lastColon) {\n return { host: input.slice(0, lastColon), port: candidatePort };\n }\n return { host: input, port: defaultPort };\n}\n\nexport function joinHostPort(host: string, port: string): string {\n const normalizedHost = stripBrackets(host);\n return isIP(normalizedHost) === 6 || normalizedHost.includes(\":\")\n ? `[${normalizedHost}]:${port}`\n : `${normalizedHost}:${port}`;\n}\n\nexport function isIpAddress(host: string): boolean {\n return isIP(stripBrackets(host)) !== 0;\n}\n\nfunction stripBrackets(host: string): string {\n return host.startsWith(\"[\") && host.endsWith(\"]\") ? host.slice(1, -1) : host;\n}\n"],"mappings":"0BAsGA,
|
|
1
|
+
{"version":3,"file":"address-BR-5unVo.cjs","names":["isIP","node_net","ClientStatus","\"Disconnected\"","\"Connecting\"","\"Connected\"","noopLogger","consoleLogger","splitHostPort","input","address","closingBracket","host","suffix","defaultPort","lastColon","candidatePort","joinHostPort","normalizedHost","stripBrackets","port","isIpAddress"],"sources":["../src/types.ts","../src/address.ts"],"sourcesContent":["// ---- Branded primitive types ------------------------------------------------\n\n/** A TS3-escaped string. Obtained only via escape(). */\nexport type EscapedString = string & { readonly __escaped: unique symbol };\n\n// ---- Event map --------------------------------------------------------------\n\nexport interface TextMessage {\n invokerName: string;\n invokerUID: string;\n message: string;\n invokerGroups: string[];\n targetMode: number;\n targetID: bigint;\n invokerID: number;\n}\n\nexport interface ClientMovedEvent {\n invokerName: string;\n invokerUID: string;\n targetChannelID: bigint;\n reasonID: number;\n id: number;\n invokerID: number;\n}\n\nexport interface ClientLeftViewEvent {\n reasonMsg: string;\n reasonID: number;\n id: number;\n targetID: number;\n}\n\nexport interface ClientInfo {\n nickname: string;\n uid: string;\n serverGroups: string[];\n channelID: bigint;\n type: number;\n id: number;\n}\n\nexport interface ChannelInfo {\n name: string;\n description: string;\n id: bigint;\n parentID: bigint;\n /** ID of the sibling channel this one is sorted after; 0 means first. */\n order: bigint;\n}\n\nexport interface FileUploadInfo {\n fileTransferKey: string;\n seekPosition: bigint;\n clientFileTransferID: number;\n serverFileTransferID: number;\n port: number;\n}\n\nexport interface FileDownloadInfo {\n fileTransferKey: string;\n size: bigint;\n clientFileTransferID: number;\n serverFileTransferID: number;\n port: number;\n}\n\nexport interface FileTransferStatusInfo {\n message: string;\n status: number;\n clientFileTransferID: number;\n}\n\nexport interface PokeEvent {\n invokerName: string;\n invokerUID: string;\n invokerID: number;\n message: string;\n}\n\nexport interface VoiceData {\n clientId: number;\n codec: number;\n data: Uint8Array;\n}\n\n// ---- Typed event map used by Client.on() ------------------------------------\n\nexport interface EventMap {\n textMessage: TextMessage;\n clientEnter: ClientInfo;\n clientLeave: ClientLeftViewEvent;\n clientMoved: ClientMovedEvent;\n poked: PokeEvent;\n voiceData: VoiceData;\n connected: void;\n disconnected: Error | undefined;\n kicked: string;\n}\n\n// ---- Client status ----------------------------------------------------------\n\nexport const enum ClientStatus {\n Disconnected = 0,\n Connecting = 1,\n Connected = 2,\n}\n\n// ---- Middleware types --------------------------------------------------------\n\nexport type CommandMiddleware = (\n next: (cmd: string) => Promise<void>,\n) => (cmd: string) => Promise<void>;\n\nexport type EventMiddleware = (\n next: (evt: EventMap[keyof EventMap]) => void,\n) => (evt: EventMap[keyof EventMap]) => void;\n\n// ---- Logger interface --------------------------------------------------------\n\nexport interface Logger {\n debug(msg: string, ...args: unknown[]): void;\n info(msg: string, ...args: unknown[]): void;\n warn(msg: string, ...args: unknown[]): void;\n error(msg: string, ...args: unknown[]): void;\n}\n\n/** A no-op logger that discards all messages. */\nexport const noopLogger: Logger = {\n debug() {},\n info() {},\n warn() {},\n error() {},\n};\n\n/** A console-backed logger. */\nexport const consoleLogger: Logger = {\n debug: console.debug.bind(console),\n info: console.info.bind(console),\n warn: console.warn.bind(console),\n error: console.error.bind(console),\n};\n\n// ---- Resolved address (from discovery) --------------------------------------\n\nexport interface ResolvedAddr {\n addr: string;\n source: string;\n expiry: Date;\n}\n\n// ---- AddrResolver interface -------------------------------------------------\n\nexport interface AddrResolver {\n resolve(addr: string, signal?: AbortSignal): Promise<ResolvedAddr[]>;\n}\n\n// ---- ClientOptions ----------------------------------------------------------\n\nexport interface ClientOptions {\n logger?: Logger;\n resolver?: AddrResolver;\n commandMiddleware?: CommandMiddleware[];\n eventMiddleware?: EventMiddleware[];\n /** Server password sent during the initial `clientinit` handshake. */\n serverPassword?: string;\n /** Default channel name to join during the initial `clientinit` handshake. */\n defaultChannel?: string;\n /** Password for `defaultChannel`, sent during the initial `clientinit` handshake. */\n defaultChannelPassword?: string;\n}\n","import { isIP } from \"node:net\";\n\nexport interface HostPort {\n host: string;\n port: string;\n}\n\n/** Parse a TeamSpeak address without confusing an IPv6 colon for a port separator. */\nexport function splitHostPort(address: string, defaultPort = \"9987\"): HostPort {\n const input = address.trim();\n if (input.startsWith(\"[\")) {\n const closingBracket = input.indexOf(\"]\");\n if (closingBracket > 0) {\n const host = input.slice(1, closingBracket);\n const suffix = input.slice(closingBracket + 1);\n if (suffix.startsWith(\":\") && /^\\d+$/.test(suffix.slice(1))) {\n return { host, port: suffix.slice(1) };\n }\n if (!suffix) return { host, port: defaultPort };\n }\n }\n\n // A raw IPv6 literal has no unambiguous port separator. Internal callers\n // normally use bracket notation, but accepting the literal with the default\n // port prevents a final IPv6 segment from being mistaken for a port.\n if (isIP(input) === 6) return { host: input, port: defaultPort };\n\n const lastColon = input.lastIndexOf(\":\");\n if (lastColon < 0) return { host: input, port: defaultPort };\n const candidatePort = input.slice(lastColon + 1);\n if (/^\\d+$/.test(candidatePort) && input.indexOf(\":\") === lastColon) {\n return { host: input.slice(0, lastColon), port: candidatePort };\n }\n return { host: input, port: defaultPort };\n}\n\nexport function joinHostPort(host: string, port: string): string {\n const normalizedHost = stripBrackets(host);\n return isIP(normalizedHost) === 6 || normalizedHost.includes(\":\")\n ? `[${normalizedHost}]:${port}`\n : `${normalizedHost}:${port}`;\n}\n\nexport function isIpAddress(host: string): boolean {\n return isIP(stripBrackets(host)) !== 0;\n}\n\nfunction stripBrackets(host: string): string {\n return host.startsWith(\"[\") && host.endsWith(\"]\") ? host.slice(1, -1) : host;\n}\n"],"mappings":"0BAsGA,IAAkBE,EAAX,SAAA,EAAA,OACL,GAAA,EAAAC,aAAA,GAAA,eACA,EAAA,EAAAC,WAAA,GAAA,aACA,EAAA,EAAAC,UAAA,GAAA,aACF,EAAA,CAAA,CAAA,EAsBaC,EAAqB,CAChC,OAAQ,CAAC,EACT,MAAO,CAAC,EACR,MAAO,CAAC,EACR,OAAQ,CAAC,CACX,EAGaC,EAAwB,CACnC,MAAO,QAAQ,MAAM,KAAK,OAAO,EACjC,KAAM,QAAQ,KAAK,KAAK,OAAO,EAC/B,KAAM,QAAQ,KAAK,KAAK,OAAO,EAC/B,MAAO,QAAQ,MAAM,KAAK,OAAO,CACnC,ECrIA,SAAgBC,EAAc,EAAiB,EAAc,OAAkB,CAC7E,IAAMC,EAAQC,EAAQ,KAAK,EAC3B,GAAID,EAAM,WAAW,GAAG,EAAG,CACzB,IAAME,EAAiBF,EAAM,QAAQ,GAAG,EACxC,GAAIE,EAAiB,EAAG,CACtB,IAAMC,EAAOH,EAAM,MAAM,EAAGE,CAAc,EACpCE,EAASJ,EAAM,MAAME,EAAiB,CAAC,EAC7C,GAAIE,EAAO,WAAW,GAAG,GAAK,QAAQ,KAAKA,EAAO,MAAM,CAAC,CAAC,EACxD,MAAO,CAAE,OAAM,KAAMA,EAAO,MAAM,CAAC,CAAE,EAEvC,GAAI,CAACA,EAAQ,MAAO,CAAE,OAAM,KAAMC,CAAY,CAChD,CACF,CAKA,IAAA,EAAId,EAAAA,KAAAA,CAAKS,CAAK,IAAM,EAAG,MAAO,CAAE,KAAMA,EAAO,KAAMK,CAAY,EAE/D,IAAMC,EAAYN,EAAM,YAAY,GAAG,EACvC,GAAIM,EAAY,EAAG,MAAO,CAAE,KAAMN,EAAO,KAAMK,CAAY,EAC3D,IAAME,EAAgBP,EAAM,MAAMM,EAAY,CAAC,EAI/C,MAHI,QAAQ,KAAKC,CAAa,GAAKP,EAAM,QAAQ,GAAG,IAAMM,EACjD,CAAE,KAAMN,EAAM,MAAM,EAAGM,CAAS,EAAG,KAAMC,CAAc,EAEzD,CAAE,KAAMP,EAAO,KAAMK,CAAY,CAC1C,CAEA,SAAgBG,EAAa,EAAc,EAAsB,CAC/D,IAAMC,EAAiBC,EAAcP,CAAI,EACzC,OAAA,EAAOZ,EAAAA,KAAAA,CAAKkB,CAAc,IAAM,GAAKA,EAAe,SAAS,GAAG,EAC5D,IAAIA,EAAe,IAAIE,IACvB,GAAGF,EAAe,GAAGE,GAC3B,CAEA,SAAgBC,EAAY,EAAuB,CACjD,OAAA,EAAOrB,EAAAA,KAAAA,CAAKmB,EAAcP,CAAI,CAAC,IAAM,CACvC,CAEA,SAASO,EAAc,EAAsB,CAC3C,OAAOP,EAAK,WAAW,GAAG,GAAKA,EAAK,SAAS,GAAG,EAAIA,EAAK,MAAM,EAAG,EAAE,EAAIA,CAC1E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"address-BfmovVpp.js","names":[],"sources":["../src/types.ts","../src/address.ts"],"sourcesContent":["// ---- Branded primitive types ------------------------------------------------\n\n/** A TS3-escaped string. Obtained only via escape(). */\nexport type EscapedString = string & { readonly __escaped: unique symbol };\n\n// ---- Event map --------------------------------------------------------------\n\nexport interface TextMessage {\n invokerName: string;\n invokerUID: string;\n message: string;\n invokerGroups: string[];\n targetMode: number;\n targetID: bigint;\n invokerID: number;\n}\n\nexport interface ClientMovedEvent {\n invokerName: string;\n invokerUID: string;\n targetChannelID: bigint;\n reasonID: number;\n id: number;\n invokerID: number;\n}\n\nexport interface ClientLeftViewEvent {\n reasonMsg: string;\n reasonID: number;\n id: number;\n targetID: number;\n}\n\nexport interface ClientInfo {\n nickname: string;\n uid: string;\n serverGroups: string[];\n channelID: bigint;\n type: number;\n id: number;\n}\n\nexport interface ChannelInfo {\n name: string;\n description: string;\n id: bigint;\n parentID: bigint;\n /** ID of the sibling channel this one is sorted after; 0 means first. */\n order: bigint;\n}\n\nexport interface FileUploadInfo {\n fileTransferKey: string;\n seekPosition: bigint;\n clientFileTransferID: number;\n serverFileTransferID: number;\n port: number;\n}\n\nexport interface FileDownloadInfo {\n fileTransferKey: string;\n size: bigint;\n clientFileTransferID: number;\n serverFileTransferID: number;\n port: number;\n}\n\nexport interface FileTransferStatusInfo {\n message: string;\n status: number;\n clientFileTransferID: number;\n}\n\nexport interface PokeEvent {\n invokerName: string;\n invokerUID: string;\n invokerID: number;\n message: string;\n}\n\nexport interface VoiceData {\n clientId: number;\n codec: number;\n data: Uint8Array;\n}\n\n// ---- Typed event map used by Client.on() ------------------------------------\n\nexport interface EventMap {\n textMessage: TextMessage;\n clientEnter: ClientInfo;\n clientLeave: ClientLeftViewEvent;\n clientMoved: ClientMovedEvent;\n poked: PokeEvent;\n voiceData: VoiceData;\n connected: void;\n disconnected: Error | undefined;\n kicked: string;\n}\n\n// ---- Client status ----------------------------------------------------------\n\nexport const enum ClientStatus {\n Disconnected = 0,\n Connecting = 1,\n Connected = 2,\n}\n\n// ---- Middleware types --------------------------------------------------------\n\nexport type CommandMiddleware = (\n next: (cmd: string) => Promise<void>,\n) => (cmd: string) => Promise<void>;\n\nexport type EventMiddleware = (\n next: (evt: EventMap[keyof EventMap]) => void,\n) => (evt: EventMap[keyof EventMap]) => void;\n\n// ---- Logger interface --------------------------------------------------------\n\nexport interface Logger {\n debug(msg: string, ...args: unknown[]): void;\n info(msg: string, ...args: unknown[]): void;\n warn(msg: string, ...args: unknown[]): void;\n error(msg: string, ...args: unknown[]): void;\n}\n\n/** A no-op logger that discards all messages. */\nexport const noopLogger: Logger = {\n debug() {},\n info() {},\n warn() {},\n error() {},\n};\n\n/** A console-backed logger. */\nexport const consoleLogger: Logger = {\n debug: console.debug.bind(console),\n info: console.info.bind(console),\n warn: console.warn.bind(console),\n error: console.error.bind(console),\n};\n\n// ---- Resolved address (from discovery) --------------------------------------\n\nexport interface ResolvedAddr {\n addr: string;\n source: string;\n expiry: Date;\n}\n\n// ---- AddrResolver interface -------------------------------------------------\n\nexport interface AddrResolver {\n resolve(addr: string, signal?: AbortSignal): Promise<ResolvedAddr[]>;\n}\n\n// ---- ClientOptions ----------------------------------------------------------\n\nexport interface ClientOptions {\n logger?: Logger;\n resolver?: AddrResolver;\n commandMiddleware?: CommandMiddleware[];\n eventMiddleware?: EventMiddleware[];\n /** Server password sent during the initial `clientinit` handshake. */\n serverPassword?: string;\n /** Default channel name to join during the initial `clientinit` handshake. */\n defaultChannel?: string;\n /** Password for `defaultChannel`, sent during the initial `clientinit` handshake. */\n defaultChannelPassword?: string;\n}\n","import { isIP } from \"node:net\";\n\nexport interface HostPort {\n host: string;\n port: string;\n}\n\n/** Parse a TeamSpeak address without confusing an IPv6 colon for a port separator. */\nexport function splitHostPort(address: string, defaultPort = \"9987\"): HostPort {\n const input = address.trim();\n if (input.startsWith(\"[\")) {\n const closingBracket = input.indexOf(\"]\");\n if (closingBracket > 0) {\n const host = input.slice(1, closingBracket);\n const suffix = input.slice(closingBracket + 1);\n if (suffix.startsWith(\":\") && /^\\d+$/.test(suffix.slice(1))) {\n return { host, port: suffix.slice(1) };\n }\n if (!suffix) return { host, port: defaultPort };\n }\n }\n\n // A raw IPv6 literal has no unambiguous port separator. Internal callers\n // normally use bracket notation, but accepting the literal with the default\n // port prevents a final IPv6 segment from being mistaken for a port.\n if (isIP(input) === 6) return { host: input, port: defaultPort };\n\n const lastColon = input.lastIndexOf(\":\");\n if (lastColon < 0) return { host: input, port: defaultPort };\n const candidatePort = input.slice(lastColon + 1);\n if (/^\\d+$/.test(candidatePort) && input.indexOf(\":\") === lastColon) {\n return { host: input.slice(0, lastColon), port: candidatePort };\n }\n return { host: input, port: defaultPort };\n}\n\nexport function joinHostPort(host: string, port: string): string {\n const normalizedHost = stripBrackets(host);\n return isIP(normalizedHost) === 6 || normalizedHost.includes(\":\")\n ? `[${normalizedHost}]:${port}`\n : `${normalizedHost}:${port}`;\n}\n\nexport function isIpAddress(host: string): boolean {\n return isIP(stripBrackets(host)) !== 0;\n}\n\nfunction stripBrackets(host: string): string {\n return host.startsWith(\"[\") && host.endsWith(\"]\") ? host.slice(1, -1) : host;\n}\n"],"mappings":";;AAsGA,
|
|
1
|
+
{"version":3,"file":"address-BfmovVpp.js","names":["ClientStatus","\"Disconnected\"","\"Connecting\"","\"Connected\"","noopLogger","consoleLogger","splitHostPort","input","address","closingBracket","host","suffix","defaultPort","isIP","lastColon","candidatePort","joinHostPort","normalizedHost","stripBrackets","port","isIpAddress"],"sources":["../src/types.ts","../src/address.ts"],"sourcesContent":["// ---- Branded primitive types ------------------------------------------------\n\n/** A TS3-escaped string. Obtained only via escape(). */\nexport type EscapedString = string & { readonly __escaped: unique symbol };\n\n// ---- Event map --------------------------------------------------------------\n\nexport interface TextMessage {\n invokerName: string;\n invokerUID: string;\n message: string;\n invokerGroups: string[];\n targetMode: number;\n targetID: bigint;\n invokerID: number;\n}\n\nexport interface ClientMovedEvent {\n invokerName: string;\n invokerUID: string;\n targetChannelID: bigint;\n reasonID: number;\n id: number;\n invokerID: number;\n}\n\nexport interface ClientLeftViewEvent {\n reasonMsg: string;\n reasonID: number;\n id: number;\n targetID: number;\n}\n\nexport interface ClientInfo {\n nickname: string;\n uid: string;\n serverGroups: string[];\n channelID: bigint;\n type: number;\n id: number;\n}\n\nexport interface ChannelInfo {\n name: string;\n description: string;\n id: bigint;\n parentID: bigint;\n /** ID of the sibling channel this one is sorted after; 0 means first. */\n order: bigint;\n}\n\nexport interface FileUploadInfo {\n fileTransferKey: string;\n seekPosition: bigint;\n clientFileTransferID: number;\n serverFileTransferID: number;\n port: number;\n}\n\nexport interface FileDownloadInfo {\n fileTransferKey: string;\n size: bigint;\n clientFileTransferID: number;\n serverFileTransferID: number;\n port: number;\n}\n\nexport interface FileTransferStatusInfo {\n message: string;\n status: number;\n clientFileTransferID: number;\n}\n\nexport interface PokeEvent {\n invokerName: string;\n invokerUID: string;\n invokerID: number;\n message: string;\n}\n\nexport interface VoiceData {\n clientId: number;\n codec: number;\n data: Uint8Array;\n}\n\n// ---- Typed event map used by Client.on() ------------------------------------\n\nexport interface EventMap {\n textMessage: TextMessage;\n clientEnter: ClientInfo;\n clientLeave: ClientLeftViewEvent;\n clientMoved: ClientMovedEvent;\n poked: PokeEvent;\n voiceData: VoiceData;\n connected: void;\n disconnected: Error | undefined;\n kicked: string;\n}\n\n// ---- Client status ----------------------------------------------------------\n\nexport const enum ClientStatus {\n Disconnected = 0,\n Connecting = 1,\n Connected = 2,\n}\n\n// ---- Middleware types --------------------------------------------------------\n\nexport type CommandMiddleware = (\n next: (cmd: string) => Promise<void>,\n) => (cmd: string) => Promise<void>;\n\nexport type EventMiddleware = (\n next: (evt: EventMap[keyof EventMap]) => void,\n) => (evt: EventMap[keyof EventMap]) => void;\n\n// ---- Logger interface --------------------------------------------------------\n\nexport interface Logger {\n debug(msg: string, ...args: unknown[]): void;\n info(msg: string, ...args: unknown[]): void;\n warn(msg: string, ...args: unknown[]): void;\n error(msg: string, ...args: unknown[]): void;\n}\n\n/** A no-op logger that discards all messages. */\nexport const noopLogger: Logger = {\n debug() {},\n info() {},\n warn() {},\n error() {},\n};\n\n/** A console-backed logger. */\nexport const consoleLogger: Logger = {\n debug: console.debug.bind(console),\n info: console.info.bind(console),\n warn: console.warn.bind(console),\n error: console.error.bind(console),\n};\n\n// ---- Resolved address (from discovery) --------------------------------------\n\nexport interface ResolvedAddr {\n addr: string;\n source: string;\n expiry: Date;\n}\n\n// ---- AddrResolver interface -------------------------------------------------\n\nexport interface AddrResolver {\n resolve(addr: string, signal?: AbortSignal): Promise<ResolvedAddr[]>;\n}\n\n// ---- ClientOptions ----------------------------------------------------------\n\nexport interface ClientOptions {\n logger?: Logger;\n resolver?: AddrResolver;\n commandMiddleware?: CommandMiddleware[];\n eventMiddleware?: EventMiddleware[];\n /** Server password sent during the initial `clientinit` handshake. */\n serverPassword?: string;\n /** Default channel name to join during the initial `clientinit` handshake. */\n defaultChannel?: string;\n /** Password for `defaultChannel`, sent during the initial `clientinit` handshake. */\n defaultChannelPassword?: string;\n}\n","import { isIP } from \"node:net\";\n\nexport interface HostPort {\n host: string;\n port: string;\n}\n\n/** Parse a TeamSpeak address without confusing an IPv6 colon for a port separator. */\nexport function splitHostPort(address: string, defaultPort = \"9987\"): HostPort {\n const input = address.trim();\n if (input.startsWith(\"[\")) {\n const closingBracket = input.indexOf(\"]\");\n if (closingBracket > 0) {\n const host = input.slice(1, closingBracket);\n const suffix = input.slice(closingBracket + 1);\n if (suffix.startsWith(\":\") && /^\\d+$/.test(suffix.slice(1))) {\n return { host, port: suffix.slice(1) };\n }\n if (!suffix) return { host, port: defaultPort };\n }\n }\n\n // A raw IPv6 literal has no unambiguous port separator. Internal callers\n // normally use bracket notation, but accepting the literal with the default\n // port prevents a final IPv6 segment from being mistaken for a port.\n if (isIP(input) === 6) return { host: input, port: defaultPort };\n\n const lastColon = input.lastIndexOf(\":\");\n if (lastColon < 0) return { host: input, port: defaultPort };\n const candidatePort = input.slice(lastColon + 1);\n if (/^\\d+$/.test(candidatePort) && input.indexOf(\":\") === lastColon) {\n return { host: input.slice(0, lastColon), port: candidatePort };\n }\n return { host: input, port: defaultPort };\n}\n\nexport function joinHostPort(host: string, port: string): string {\n const normalizedHost = stripBrackets(host);\n return isIP(normalizedHost) === 6 || normalizedHost.includes(\":\")\n ? `[${normalizedHost}]:${port}`\n : `${normalizedHost}:${port}`;\n}\n\nexport function isIpAddress(host: string): boolean {\n return isIP(stripBrackets(host)) !== 0;\n}\n\nfunction stripBrackets(host: string): string {\n return host.startsWith(\"[\") && host.endsWith(\"]\") ? host.slice(1, -1) : host;\n}\n"],"mappings":";;AAsGA,IAAkBA,IAAX,yBAAA,GAAA;QACL,EAAA,EAAAC,eAAA,KAAA,gBACA,EAAA,EAAAC,aAAA,KAAA,cACA,EAAA,EAAAC,YAAA,KAAA;AACF,EAAA,CAAA,CAAA,GAsBaC,IAAqB;CAChC,QAAQ,CAAC;CACT,OAAO,CAAC;CACR,OAAO,CAAC;CACR,QAAQ,CAAC;AACX,GAGaC,IAAwB;CACnC,OAAO,QAAQ,MAAM,KAAK,OAAO;CACjC,MAAM,QAAQ,KAAK,KAAK,OAAO;CAC/B,MAAM,QAAQ,KAAK,KAAK,OAAO;CAC/B,OAAO,QAAQ,MAAM,KAAK,OAAO;AACnC;;;ACrIA,SAAgBC,EAAc,GAAiB,IAAc,QAAkB;CAC7E,IAAMC,IAAQC,EAAQ,KAAK;CAC3B,IAAID,EAAM,WAAW,GAAG,GAAG;EACzB,IAAME,IAAiBF,EAAM,QAAQ,GAAG;EACxC,IAAIE,IAAiB,GAAG;GACtB,IAAMC,IAAOH,EAAM,MAAM,GAAGE,CAAc,GACpCE,IAASJ,EAAM,MAAME,IAAiB,CAAC;GAC7C,IAAIE,EAAO,WAAW,GAAG,KAAK,QAAQ,KAAKA,EAAO,MAAM,CAAC,CAAC,GACxD,OAAO;IAAE;IAAM,MAAMA,EAAO,MAAM,CAAC;GAAE;GAEvC,IAAI,CAACA,GAAQ,OAAO;IAAE;IAAM,MAAMC;GAAY;EAChD;CACF;CAKA,IAAIC,EAAKN,CAAK,MAAM,GAAG,OAAO;EAAE,MAAMA;EAAO,MAAMK;CAAY;CAE/D,IAAME,IAAYP,EAAM,YAAY,GAAG;CACvC,IAAIO,IAAY,GAAG,OAAO;EAAE,MAAMP;EAAO,MAAMK;CAAY;CAC3D,IAAMG,IAAgBR,EAAM,MAAMO,IAAY,CAAC;CAI/C,OAHI,QAAQ,KAAKC,CAAa,KAAKR,EAAM,QAAQ,GAAG,MAAMO,IACjD;EAAE,MAAMP,EAAM,MAAM,GAAGO,CAAS;EAAG,MAAMC;CAAc,IAEzD;EAAE,MAAMR;EAAO,MAAMK;CAAY;AAC1C;AAEA,SAAgBI,EAAa,GAAc,GAAsB;CAC/D,IAAMC,IAAiBC,EAAcR,CAAI;CACzC,OAAOG,EAAKI,CAAc,MAAM,KAAKA,EAAe,SAAS,GAAG,IAC5D,IAAIA,EAAe,IAAIE,MACvB,GAAGF,EAAe,GAAGE;AAC3B;AAEA,SAAgBC,EAAY,GAAuB;CACjD,OAAOP,EAAKK,EAAcR,CAAI,CAAC,MAAM;AACvC;AAEA,SAASQ,EAAc,GAAsB;CAC3C,OAAOR,EAAK,WAAW,GAAG,KAAKA,EAAK,SAAS,GAAG,IAAIA,EAAK,MAAM,GAAG,EAAE,IAAIA;AAC1E"}
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,MAAM,EAGX,YAAY,EAEb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAkBvD,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnE,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AAmBD,qBAAa,MAAM;;IAEjB,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC;IAC9B,gBAAgB,CAAC,OAAO,EAAE,aAAa,CAAC;IACxC,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC;IAChC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC;IAClC,gBAAgB,CAAC,IAAI,SAAK;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,MAAM,EAGX,YAAY,EAEb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAkBvD,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnE,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AAmBD,qBAAa,MAAM;;IAEjB,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC;IAC9B,gBAAgB,CAAC,OAAO,EAAE,aAAa,CAAC;IACxC,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC;IAChC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC;IAClC,gBAAgB,CAAC,IAAI,SAAK;IA+B1B,YAAY,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,EAsB1F;IAED,IAAI,MAAM,IAAI,YAAY,CAEzB;IAED,gBAAgB;IAChB,oBAAoB,IAAI,QAAQ,CAAC;QAC/B,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,sBAAsB,EAAE,MAAM,CAAC;KAChC,CAAC,CAED;IAIK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAW7B;IAEK,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAmBhC;IAED,aAAa,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BjD;IAIK,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGlD;IAEK,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhE;IAEK,uBAAuB,CAC3B,GAAG,EAAE,MAAM,EACX,SAAS,SAAS,GACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAuBnC;IAID,EAAE,CAAC,CAAC,SAAS,MAAM,QAAQ,EACzB,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,GAC9E,IAAI,CA+BN;IAED,oBAAoB,CAAC,GAAG,EAAE,EAAE,iBAAiB,EAAE,GAAG,IAAI,CAIrD;IAED,kBAAkB,CAAC,GAAG,EAAE,EAAE,eAAe,EAAE,GAAG,IAAI,CAIjD;IAID,QAAQ,IAAI,MAAM,CAEjB;IAED,SAAS,IAAI,MAAM,CAGlB;IAED,+EAA+E;IAC/E,WAAW,CAAC,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAE5E;IAED,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAE/C;IAIK,sBAAsB,CAC1B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,SAAS,UAAQ,GAChB,OAAO,CAAC,cAAc,CAAC,CAyBzB;IAEK,wBAAwB,CAC5B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,gBAAgB,CAAC,CAyB3B;IAED,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhF;IAED,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpF;IAID,gBAAgB;IAChB,cAAc,IAAI,IAAI,CAOrB;CA+UF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-BLe-C2L2.js","names":[],"sources":["../src/command/command.ts"],"sourcesContent":["import type { EscapedString } from \"../types.js\";\n\nconst ESCAPE_MAP: [string, string][] = [\n [\"\\\\\", \"\\\\\\\\\"],\n [\"/\", \"\\\\/\"],\n [\" \", \"\\\\s\"],\n [\"|\", \"\\\\p\"],\n [\"\\x07\", \"\\\\a\"],\n [\"\\x08\", \"\\\\b\"],\n [\"\\x0C\", \"\\\\f\"],\n [\"\\n\", \"\\\\n\"],\n [\"\\r\", \"\\\\r\"],\n [\"\\t\", \"\\\\t\"],\n [\"\\x0B\", \"\\\\v\"],\n];\n\nexport function escape(s: string): EscapedString {\n let result = s;\n for (const [from, to] of ESCAPE_MAP) {\n result = result.split(from).join(to);\n }\n return result as EscapedString;\n}\n\nexport function unescape(s: string): string {\n // Process escape sequences in a single pass to avoid double-substitution\n let result = \"\";\n let i = 0;\n while (i < s.length) {\n if (s[i] === \"\\\\\" && i + 1 < s.length) {\n const next = s[i + 1];\n switch (next) {\n case \"\\\\\":\n result += \"\\\\\";\n i += 2;\n break;\n case \"/\":\n result += \"/\";\n i += 2;\n break;\n case \"s\":\n result += \" \";\n i += 2;\n break;\n case \"p\":\n result += \"|\";\n i += 2;\n break;\n case \"a\":\n result += \"\\x07\";\n i += 2;\n break;\n case \"b\":\n result += \"\\x08\";\n i += 2;\n break;\n case \"f\":\n result += \"\\x0C\";\n i += 2;\n break;\n case \"n\":\n result += \"\\n\";\n i += 2;\n break;\n case \"r\":\n result += \"\\r\";\n i += 2;\n break;\n case \"t\":\n result += \"\\t\";\n i += 2;\n break;\n case \"v\":\n result += \"\\x0B\";\n i += 2;\n break;\n default:\n result += s[i] ?? \"\";\n i++;\n break;\n }\n } else {\n result += s[i] ?? \"\";\n i++;\n }\n }\n return result;\n}\n\nexport interface Command {\n name: string;\n params: Record<string, string>;\n}\n\n/** Build a TS3 command string from an unordered params map. */\nexport function buildCommand(cmd: string, params: Record<string, string>): string {\n const parts: string[] = [escape(cmd)];\n for (const [k, v] of Object.entries(params)) {\n parts.push(`${k}=${escape(v)}`);\n }\n return parts.join(\" \");\n}\n\n/** Build a TS3 command string preserving parameter order. */\nexport function buildCommandOrdered(\n cmd: string,\n params: ReadonlyArray<readonly [string, string]>,\n): string {\n const parts: string[] = [escape(cmd)];\n for (const [k, v] of params) {\n parts.push(`${k}=${escape(v)}`);\n }\n return parts.join(\" \");\n}\n"],"mappings":";AAEA,
|
|
1
|
+
{"version":3,"file":"command-BLe-C2L2.js","names":["ESCAPE_MAP","escape","result","s","from","to","unescape","i","buildCommand","parts","cmd","k","v","params","buildCommandOrdered"],"sources":["../src/command/command.ts"],"sourcesContent":["import type { EscapedString } from \"../types.js\";\n\nconst ESCAPE_MAP: [string, string][] = [\n [\"\\\\\", \"\\\\\\\\\"],\n [\"/\", \"\\\\/\"],\n [\" \", \"\\\\s\"],\n [\"|\", \"\\\\p\"],\n [\"\\x07\", \"\\\\a\"],\n [\"\\x08\", \"\\\\b\"],\n [\"\\x0C\", \"\\\\f\"],\n [\"\\n\", \"\\\\n\"],\n [\"\\r\", \"\\\\r\"],\n [\"\\t\", \"\\\\t\"],\n [\"\\x0B\", \"\\\\v\"],\n];\n\nexport function escape(s: string): EscapedString {\n let result = s;\n for (const [from, to] of ESCAPE_MAP) {\n result = result.split(from).join(to);\n }\n return result as EscapedString;\n}\n\nexport function unescape(s: string): string {\n // Process escape sequences in a single pass to avoid double-substitution\n let result = \"\";\n let i = 0;\n while (i < s.length) {\n if (s[i] === \"\\\\\" && i + 1 < s.length) {\n const next = s[i + 1];\n switch (next) {\n case \"\\\\\":\n result += \"\\\\\";\n i += 2;\n break;\n case \"/\":\n result += \"/\";\n i += 2;\n break;\n case \"s\":\n result += \" \";\n i += 2;\n break;\n case \"p\":\n result += \"|\";\n i += 2;\n break;\n case \"a\":\n result += \"\\x07\";\n i += 2;\n break;\n case \"b\":\n result += \"\\x08\";\n i += 2;\n break;\n case \"f\":\n result += \"\\x0C\";\n i += 2;\n break;\n case \"n\":\n result += \"\\n\";\n i += 2;\n break;\n case \"r\":\n result += \"\\r\";\n i += 2;\n break;\n case \"t\":\n result += \"\\t\";\n i += 2;\n break;\n case \"v\":\n result += \"\\x0B\";\n i += 2;\n break;\n default:\n result += s[i] ?? \"\";\n i++;\n break;\n }\n } else {\n result += s[i] ?? \"\";\n i++;\n }\n }\n return result;\n}\n\nexport interface Command {\n name: string;\n params: Record<string, string>;\n}\n\n/** Build a TS3 command string from an unordered params map. */\nexport function buildCommand(cmd: string, params: Record<string, string>): string {\n const parts: string[] = [escape(cmd)];\n for (const [k, v] of Object.entries(params)) {\n parts.push(`${k}=${escape(v)}`);\n }\n return parts.join(\" \");\n}\n\n/** Build a TS3 command string preserving parameter order. */\nexport function buildCommandOrdered(\n cmd: string,\n params: ReadonlyArray<readonly [string, string]>,\n): string {\n const parts: string[] = [escape(cmd)];\n for (const [k, v] of params) {\n parts.push(`${k}=${escape(v)}`);\n }\n return parts.join(\" \");\n}\n"],"mappings":";AAEA,IAAMA,IAAiC;CACrC,CAAC,MAAM,MAAM;CACb,CAAC,KAAK,KAAK;CACX,CAAC,KAAK,KAAK;CACX,CAAC,KAAK,KAAK;CACX,CAAC,QAAQ,KAAK;CACd,CAAC,MAAQ,KAAK;CACd,CAAC,MAAQ,KAAK;CACd,CAAC,MAAM,KAAK;CACZ,CAAC,MAAM,KAAK;CACZ,CAAC,KAAM,KAAK;CACZ,CAAC,MAAQ,KAAK;AAChB;AAEA,SAAgBC,EAAO,GAA0B;CAC/C,IAAIC,IAASC;CACb,KAAK,IAAM,CAACC,GAAMC,MAAOL,GACvB,IAASE,EAAO,MAAME,CAAI,CAAC,CAAC,KAAKC,CAAE;CAErC,OAAOH;AACT;AAEA,SAAgBI,EAAS,GAAmB;CAE1C,IAAIJ,IAAS,IACTK,IAAI;CACR,OAAOA,IAAIJ,EAAE,SACX,IAAIA,EAAEI,OAAO,QAAQA,IAAI,IAAIJ,EAAE,QAE7B,QADaA,EAAEI,IAAI,IACnB;EACE,KAAK;GAEH,AADA,KAAU,MACV,KAAK;GACL;EACF,KAAK;GAEH,AADA,KAAU,KACV,KAAK;GACL;EACF,KAAK;GAEH,AADA,KAAU,KACV,KAAK;GACL;EACF,KAAK;GAEH,AADA,KAAU,KACV,KAAK;GACL;EACF,KAAK;GAEH,AADA,KAAU,QACV,KAAK;GACL;EACF,KAAK;GAEH,AADA,KAAU,MACV,KAAK;GACL;EACF,KAAK;GAEH,AADA,KAAU,MACV,KAAK;GACL;EACF,KAAK;GAEH,AADA,KAAU,MACV,KAAK;GACL;EACF,KAAK;GAEH,AADA,KAAU,MACV,KAAK;GACL;EACF,KAAK;GAEH,AADA,KAAU,KACV,KAAK;GACL;EACF,KAAK;GAEH,AADA,KAAU,MACV,KAAK;GACL;EACF,SAEE,AADA,KAAUJ,EAAEI,MAAM,IAClB;CAEJ;MAGA,AADA,KAAUJ,EAAEI,MAAM,IAClB;CAGJ,OAAOL;AACT;AAQA,SAAgBM,EAAa,GAAa,GAAwC;CAChF,IAAMC,IAAkB,CAACR,EAAOS,CAAG,CAAC;CACpC,KAAK,IAAM,CAACC,GAAGC,MAAM,OAAO,QAAQC,CAAM,GACxC,EAAM,KAAK,GAAGF,EAAE,GAAGV,EAAOW,CAAC,GAAG;CAEhC,OAAOH,EAAM,KAAK,GAAG;AACvB;AAGA,SAAgBK,EACd,GACA,GACQ;CACR,IAAML,IAAkB,CAACR,EAAOS,CAAG,CAAC;CACpC,KAAK,IAAM,CAACC,GAAGC,MAAMC,GACnB,EAAM,KAAK,GAAGF,EAAE,GAAGV,EAAOW,CAAC,GAAG;CAEhC,OAAOH,EAAM,KAAK,GAAG;AACvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-DAK4pUBP.cjs","names":[],"sources":["../src/command/command.ts"],"sourcesContent":["import type { EscapedString } from \"../types.js\";\n\nconst ESCAPE_MAP: [string, string][] = [\n [\"\\\\\", \"\\\\\\\\\"],\n [\"/\", \"\\\\/\"],\n [\" \", \"\\\\s\"],\n [\"|\", \"\\\\p\"],\n [\"\\x07\", \"\\\\a\"],\n [\"\\x08\", \"\\\\b\"],\n [\"\\x0C\", \"\\\\f\"],\n [\"\\n\", \"\\\\n\"],\n [\"\\r\", \"\\\\r\"],\n [\"\\t\", \"\\\\t\"],\n [\"\\x0B\", \"\\\\v\"],\n];\n\nexport function escape(s: string): EscapedString {\n let result = s;\n for (const [from, to] of ESCAPE_MAP) {\n result = result.split(from).join(to);\n }\n return result as EscapedString;\n}\n\nexport function unescape(s: string): string {\n // Process escape sequences in a single pass to avoid double-substitution\n let result = \"\";\n let i = 0;\n while (i < s.length) {\n if (s[i] === \"\\\\\" && i + 1 < s.length) {\n const next = s[i + 1];\n switch (next) {\n case \"\\\\\":\n result += \"\\\\\";\n i += 2;\n break;\n case \"/\":\n result += \"/\";\n i += 2;\n break;\n case \"s\":\n result += \" \";\n i += 2;\n break;\n case \"p\":\n result += \"|\";\n i += 2;\n break;\n case \"a\":\n result += \"\\x07\";\n i += 2;\n break;\n case \"b\":\n result += \"\\x08\";\n i += 2;\n break;\n case \"f\":\n result += \"\\x0C\";\n i += 2;\n break;\n case \"n\":\n result += \"\\n\";\n i += 2;\n break;\n case \"r\":\n result += \"\\r\";\n i += 2;\n break;\n case \"t\":\n result += \"\\t\";\n i += 2;\n break;\n case \"v\":\n result += \"\\x0B\";\n i += 2;\n break;\n default:\n result += s[i] ?? \"\";\n i++;\n break;\n }\n } else {\n result += s[i] ?? \"\";\n i++;\n }\n }\n return result;\n}\n\nexport interface Command {\n name: string;\n params: Record<string, string>;\n}\n\n/** Build a TS3 command string from an unordered params map. */\nexport function buildCommand(cmd: string, params: Record<string, string>): string {\n const parts: string[] = [escape(cmd)];\n for (const [k, v] of Object.entries(params)) {\n parts.push(`${k}=${escape(v)}`);\n }\n return parts.join(\" \");\n}\n\n/** Build a TS3 command string preserving parameter order. */\nexport function buildCommandOrdered(\n cmd: string,\n params: ReadonlyArray<readonly [string, string]>,\n): string {\n const parts: string[] = [escape(cmd)];\n for (const [k, v] of params) {\n parts.push(`${k}=${escape(v)}`);\n }\n return parts.join(\" \");\n}\n"],"mappings":"AAEA,
|
|
1
|
+
{"version":3,"file":"command-DAK4pUBP.cjs","names":["ESCAPE_MAP","escape","result","s","from","to","unescape","i","buildCommand","parts","cmd","k","v","params","buildCommandOrdered"],"sources":["../src/command/command.ts"],"sourcesContent":["import type { EscapedString } from \"../types.js\";\n\nconst ESCAPE_MAP: [string, string][] = [\n [\"\\\\\", \"\\\\\\\\\"],\n [\"/\", \"\\\\/\"],\n [\" \", \"\\\\s\"],\n [\"|\", \"\\\\p\"],\n [\"\\x07\", \"\\\\a\"],\n [\"\\x08\", \"\\\\b\"],\n [\"\\x0C\", \"\\\\f\"],\n [\"\\n\", \"\\\\n\"],\n [\"\\r\", \"\\\\r\"],\n [\"\\t\", \"\\\\t\"],\n [\"\\x0B\", \"\\\\v\"],\n];\n\nexport function escape(s: string): EscapedString {\n let result = s;\n for (const [from, to] of ESCAPE_MAP) {\n result = result.split(from).join(to);\n }\n return result as EscapedString;\n}\n\nexport function unescape(s: string): string {\n // Process escape sequences in a single pass to avoid double-substitution\n let result = \"\";\n let i = 0;\n while (i < s.length) {\n if (s[i] === \"\\\\\" && i + 1 < s.length) {\n const next = s[i + 1];\n switch (next) {\n case \"\\\\\":\n result += \"\\\\\";\n i += 2;\n break;\n case \"/\":\n result += \"/\";\n i += 2;\n break;\n case \"s\":\n result += \" \";\n i += 2;\n break;\n case \"p\":\n result += \"|\";\n i += 2;\n break;\n case \"a\":\n result += \"\\x07\";\n i += 2;\n break;\n case \"b\":\n result += \"\\x08\";\n i += 2;\n break;\n case \"f\":\n result += \"\\x0C\";\n i += 2;\n break;\n case \"n\":\n result += \"\\n\";\n i += 2;\n break;\n case \"r\":\n result += \"\\r\";\n i += 2;\n break;\n case \"t\":\n result += \"\\t\";\n i += 2;\n break;\n case \"v\":\n result += \"\\x0B\";\n i += 2;\n break;\n default:\n result += s[i] ?? \"\";\n i++;\n break;\n }\n } else {\n result += s[i] ?? \"\";\n i++;\n }\n }\n return result;\n}\n\nexport interface Command {\n name: string;\n params: Record<string, string>;\n}\n\n/** Build a TS3 command string from an unordered params map. */\nexport function buildCommand(cmd: string, params: Record<string, string>): string {\n const parts: string[] = [escape(cmd)];\n for (const [k, v] of Object.entries(params)) {\n parts.push(`${k}=${escape(v)}`);\n }\n return parts.join(\" \");\n}\n\n/** Build a TS3 command string preserving parameter order. */\nexport function buildCommandOrdered(\n cmd: string,\n params: ReadonlyArray<readonly [string, string]>,\n): string {\n const parts: string[] = [escape(cmd)];\n for (const [k, v] of params) {\n parts.push(`${k}=${escape(v)}`);\n }\n return parts.join(\" \");\n}\n"],"mappings":"AAEA,IAAMA,EAAiC,CACrC,CAAC,KAAM,MAAM,EACb,CAAC,IAAK,KAAK,EACX,CAAC,IAAK,KAAK,EACX,CAAC,IAAK,KAAK,EACX,CAAC,OAAQ,KAAK,EACd,CAAC,KAAQ,KAAK,EACd,CAAC,KAAQ,KAAK,EACd,CAAC;EAAM,KAAK,EACZ,CAAC,KAAM,KAAK,EACZ,CAAC,IAAM,KAAK,EACZ,CAAC,KAAQ,KAAK,CAChB,EAEA,SAAgBC,EAAO,EAA0B,CAC/C,IAAIC,EAASC,EACb,IAAK,GAAM,CAACC,EAAMC,KAAOL,EACvB,EAASE,EAAO,MAAME,CAAI,CAAC,CAAC,KAAKC,CAAE,EAErC,OAAOH,CACT,CAEA,SAAgBI,EAAS,EAAmB,CAE1C,IAAIJ,EAAS,GACTK,EAAI,EACR,KAAOA,EAAIJ,EAAE,QACX,GAAIA,EAAEI,KAAO,MAAQA,EAAI,EAAIJ,EAAE,OAE7B,OADaA,EAAEI,EAAI,GACnB,CACE,IAAK,KACH,GAAU,KACV,GAAK,EACL,MACF,IAAK,IACH,GAAU,IACV,GAAK,EACL,MACF,IAAK,IACH,GAAU,IACV,GAAK,EACL,MACF,IAAK,IACH,GAAU,IACV,GAAK,EACL,MACF,IAAK,IACH,GAAU,OACV,GAAK,EACL,MACF,IAAK,IACH,GAAU,KACV,GAAK,EACL,MACF,IAAK,IACH,GAAU,KACV,GAAK,EACL,MACF,IAAK,IACH,GAAU;EACV,GAAK,EACL,MACF,IAAK,IACH,GAAU,KACV,GAAK,EACL,MACF,IAAK,IACH,GAAU,IACV,GAAK,EACL,MACF,IAAK,IACH,GAAU,KACV,GAAK,EACL,MACF,QACE,GAAUJ,EAAEI,IAAM,GAClB,GAEJ,KAEA,IAAUJ,EAAEI,IAAM,GAClB,IAGJ,OAAOL,CACT,CAQA,SAAgBM,EAAa,EAAa,EAAwC,CAChF,IAAMC,EAAkB,CAACR,EAAOS,CAAG,CAAC,EACpC,IAAK,GAAM,CAACC,EAAGC,KAAM,OAAO,QAAQC,CAAM,EACxCJ,EAAM,KAAK,GAAGE,EAAE,GAAGV,EAAOW,CAAC,GAAG,EAEhC,OAAOH,EAAM,KAAK,GAAG,CACvB,CAGA,SAAgBK,EACd,EACA,EACQ,CACR,IAAML,EAAkB,CAACR,EAAOS,CAAG,CAAC,EACpC,IAAK,GAAM,CAACC,EAAGC,KAAMC,EACnBJ,EAAM,KAAK,GAAGE,EAAE,GAAGV,EAAOW,CAAC,GAAG,EAEhC,OAAOH,EAAM,KAAK,GAAG,CACvB"}
|
package/dist/commands.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,KAAK,GAAG,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CAChC;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,cAAc;;IAWzB,QAAQ,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,KAAK,GAAG,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CAChC;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,cAAc;;IAWzB,QAAQ,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC,CAOxD;IAED,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE3B;IAED;;;OAGG;IACH,qBAAqB,IAAI,IAAI,CAG5B;IAED;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAI3C;IAED,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI,CAU3C;IAED,aAAa,IAAI,IAAI,CAEpB;IAED,KAAK,IAAI,IAAI,CAKZ;CACF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG;IAChE,GAAG,EAAE,KAAK,GAAG,IAAI,CAAC;IAClB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CACnB,CAiBA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAGhE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypt-handshake-CQkQreLx.cjs","names":[],"sources":["../src/handshake/crypt-handshake.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { buildCommandOrdered } from \"../command/command.js\";\nimport type { Crypt } from \"../crypto/crypt.js\";\n\nexport const INIT_VERSION = 1566914096; // 3.5.0 [Stable]\n\nconst INIT_VERSION_LEN = 4;\nconst INIT_TYPE_LEN = 1;\nconst INIT_STEP_LEN = 21;\n\n/**\n * Handle the TS3INIT1 handshake steps.\n * Returns the response bytes to send, or null if nothing should be sent.\n */\nexport function processInit1(crypt: Crypt, data: Uint8Array | null): Uint8Array | null {\n if (data === null || (data.length >= 1 && data[0] === 0x7f)) {\n return buildInit1StartPacket();\n }\n\n switch (data[0]) {\n case 0:\n return buildInit1Step1Packet(data);\n case 1:\n return buildInit1Step2Packet(data);\n case 2:\n return buildInit1Step3Packet(data);\n case 3:\n return buildInit1Step4Packet(crypt, data);\n default:\n return null;\n }\n}\n\nfunction buildInit1StartPacket(): Uint8Array {\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 4 + 4 + 8);\n const view = new DataView(sendData.buffer);\n\n view.setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x00;\n\n const nowSec = Math.floor(Date.now() / 1000);\n const clampedNow = Math.max(0, Math.min(nowSec, 0xffff_ffff));\n view.setUint32(5, clampedNow, false);\n\n const rng = randomBytes(4);\n sendData.set(rng, 9);\n\n return sendData;\n}\n\nfunction buildInit1Step1Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_STEP_LEN) return null;\n\n const sendData = new Uint8Array(INIT_TYPE_LEN + 16 + 4);\n sendData[0] = 0x01;\n\n // TS rand: little-endian uint32 at offset [INIT_VERSION_LEN + INIT_TYPE_LEN + 4]\n const tsRandOffset = INIT_VERSION_LEN + INIT_TYPE_LEN + 4;\n const tsRand =\n data[tsRandOffset]! |\n (data[tsRandOffset + 1]! << 8) |\n (data[tsRandOffset + 2]! << 16) |\n (data[tsRandOffset + 3]! << 24);\n\n new DataView(sendData.buffer).setUint32(INIT_TYPE_LEN + 16, tsRand >>> 0, false);\n return sendData;\n}\n\nfunction buildInit1Step2Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_STEP_LEN) return null;\n\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 16 + 4);\n new DataView(sendData.buffer).setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x02;\n sendData.set(data.slice(1, 21), 5);\n return sendData;\n}\n\nfunction buildInit1Step3Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_VERSION_LEN + INIT_TYPE_LEN + 16 + 4) return null;\n\n const sendData = new Uint8Array(INIT_TYPE_LEN + 64 + 64 + 4 + 100);\n sendData[0] = 0x03;\n sendData[INIT_TYPE_LEN + 64 - 1] = 1;\n sendData[INIT_TYPE_LEN + 64 + 64 - 1] = 1;\n new DataView(sendData.buffer).setUint32(INIT_TYPE_LEN + 64 + 64, 1, false);\n return sendData;\n}\n\nfunction buildInit1Step4Packet(crypt: Crypt, data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_TYPE_LEN + 64 + 64 + 4 + 100) return null;\n\n const level = new DataView(data.buffer, data.byteOffset).getUint32(1 + 128, false);\n const y = crypt.solveRsaChallenge(data, 1, level);\n\n crypt.alphaTmp = new Uint8Array(randomBytes(10));\n\n const alphaB64 = Buffer.from(crypt.alphaTmp).toString(\"base64\");\n const omegaB64 = crypt.identity.publicKeyBase64();\n\n const cmd = buildCommandOrdered(\"clientinitiv\", [\n [\"alpha\", alphaB64],\n [\"omega\", omegaB64],\n [\"ot\", \"1\"],\n [\"ip\", \"\"],\n ]);\n const cmdBytes = Buffer.from(cmd);\n\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 232 + 64 + cmdBytes.length);\n const view = new DataView(sendData.buffer);\n view.setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x04;\n sendData.set(data.slice(1, 233), 5);\n sendData.set(y.slice(0, 64), 5 + 232);\n sendData.set(cmdBytes, 5 + 232 + 64);\n\n return sendData;\n}\n"],"mappings":"uEAIA,
|
|
1
|
+
{"version":3,"file":"crypt-handshake-CQkQreLx.cjs","names":["randomBytes","buildCommandOrdered","require_command","node_crypto","INIT_VERSION","INIT_STEP_LEN","processInit1","data","buildInit1StartPacket","buildInit1Step1Packet","buildInit1Step2Packet","buildInit1Step3Packet","buildInit1Step4Packet","crypt","sendData","view","nowSec","clampedNow","rng","tsRand","level","y","alphaB64","omegaB64","cmd","cmdBytes"],"sources":["../src/handshake/crypt-handshake.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { buildCommandOrdered } from \"../command/command.js\";\nimport type { Crypt } from \"../crypto/crypt.js\";\n\nexport const INIT_VERSION = 1566914096; // 3.5.0 [Stable]\n\nconst INIT_VERSION_LEN = 4;\nconst INIT_TYPE_LEN = 1;\nconst INIT_STEP_LEN = 21;\n\n/**\n * Handle the TS3INIT1 handshake steps.\n * Returns the response bytes to send, or null if nothing should be sent.\n */\nexport function processInit1(crypt: Crypt, data: Uint8Array | null): Uint8Array | null {\n if (data === null || (data.length >= 1 && data[0] === 0x7f)) {\n return buildInit1StartPacket();\n }\n\n switch (data[0]) {\n case 0:\n return buildInit1Step1Packet(data);\n case 1:\n return buildInit1Step2Packet(data);\n case 2:\n return buildInit1Step3Packet(data);\n case 3:\n return buildInit1Step4Packet(crypt, data);\n default:\n return null;\n }\n}\n\nfunction buildInit1StartPacket(): Uint8Array {\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 4 + 4 + 8);\n const view = new DataView(sendData.buffer);\n\n view.setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x00;\n\n const nowSec = Math.floor(Date.now() / 1000);\n const clampedNow = Math.max(0, Math.min(nowSec, 0xffff_ffff));\n view.setUint32(5, clampedNow, false);\n\n const rng = randomBytes(4);\n sendData.set(rng, 9);\n\n return sendData;\n}\n\nfunction buildInit1Step1Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_STEP_LEN) return null;\n\n const sendData = new Uint8Array(INIT_TYPE_LEN + 16 + 4);\n sendData[0] = 0x01;\n\n // TS rand: little-endian uint32 at offset [INIT_VERSION_LEN + INIT_TYPE_LEN + 4]\n const tsRandOffset = INIT_VERSION_LEN + INIT_TYPE_LEN + 4;\n const tsRand =\n data[tsRandOffset]! |\n (data[tsRandOffset + 1]! << 8) |\n (data[tsRandOffset + 2]! << 16) |\n (data[tsRandOffset + 3]! << 24);\n\n new DataView(sendData.buffer).setUint32(INIT_TYPE_LEN + 16, tsRand >>> 0, false);\n return sendData;\n}\n\nfunction buildInit1Step2Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_STEP_LEN) return null;\n\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 16 + 4);\n new DataView(sendData.buffer).setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x02;\n sendData.set(data.slice(1, 21), 5);\n return sendData;\n}\n\nfunction buildInit1Step3Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_VERSION_LEN + INIT_TYPE_LEN + 16 + 4) return null;\n\n const sendData = new Uint8Array(INIT_TYPE_LEN + 64 + 64 + 4 + 100);\n sendData[0] = 0x03;\n sendData[INIT_TYPE_LEN + 64 - 1] = 1;\n sendData[INIT_TYPE_LEN + 64 + 64 - 1] = 1;\n new DataView(sendData.buffer).setUint32(INIT_TYPE_LEN + 64 + 64, 1, false);\n return sendData;\n}\n\nfunction buildInit1Step4Packet(crypt: Crypt, data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_TYPE_LEN + 64 + 64 + 4 + 100) return null;\n\n const level = new DataView(data.buffer, data.byteOffset).getUint32(1 + 128, false);\n const y = crypt.solveRsaChallenge(data, 1, level);\n\n crypt.alphaTmp = new Uint8Array(randomBytes(10));\n\n const alphaB64 = Buffer.from(crypt.alphaTmp).toString(\"base64\");\n const omegaB64 = crypt.identity.publicKeyBase64();\n\n const cmd = buildCommandOrdered(\"clientinitiv\", [\n [\"alpha\", alphaB64],\n [\"omega\", omegaB64],\n [\"ot\", \"1\"],\n [\"ip\", \"\"],\n ]);\n const cmdBytes = Buffer.from(cmd);\n\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 232 + 64 + cmdBytes.length);\n const view = new DataView(sendData.buffer);\n view.setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x04;\n sendData.set(data.slice(1, 233), 5);\n sendData.set(y.slice(0, 64), 5 + 232);\n sendData.set(cmdBytes, 5 + 232 + 64);\n\n return sendData;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypt-handshake-DziOY4Lq.js","names":[],"sources":["../src/handshake/crypt-handshake.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { buildCommandOrdered } from \"../command/command.js\";\nimport type { Crypt } from \"../crypto/crypt.js\";\n\nexport const INIT_VERSION = 1566914096; // 3.5.0 [Stable]\n\nconst INIT_VERSION_LEN = 4;\nconst INIT_TYPE_LEN = 1;\nconst INIT_STEP_LEN = 21;\n\n/**\n * Handle the TS3INIT1 handshake steps.\n * Returns the response bytes to send, or null if nothing should be sent.\n */\nexport function processInit1(crypt: Crypt, data: Uint8Array | null): Uint8Array | null {\n if (data === null || (data.length >= 1 && data[0] === 0x7f)) {\n return buildInit1StartPacket();\n }\n\n switch (data[0]) {\n case 0:\n return buildInit1Step1Packet(data);\n case 1:\n return buildInit1Step2Packet(data);\n case 2:\n return buildInit1Step3Packet(data);\n case 3:\n return buildInit1Step4Packet(crypt, data);\n default:\n return null;\n }\n}\n\nfunction buildInit1StartPacket(): Uint8Array {\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 4 + 4 + 8);\n const view = new DataView(sendData.buffer);\n\n view.setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x00;\n\n const nowSec = Math.floor(Date.now() / 1000);\n const clampedNow = Math.max(0, Math.min(nowSec, 0xffff_ffff));\n view.setUint32(5, clampedNow, false);\n\n const rng = randomBytes(4);\n sendData.set(rng, 9);\n\n return sendData;\n}\n\nfunction buildInit1Step1Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_STEP_LEN) return null;\n\n const sendData = new Uint8Array(INIT_TYPE_LEN + 16 + 4);\n sendData[0] = 0x01;\n\n // TS rand: little-endian uint32 at offset [INIT_VERSION_LEN + INIT_TYPE_LEN + 4]\n const tsRandOffset = INIT_VERSION_LEN + INIT_TYPE_LEN + 4;\n const tsRand =\n data[tsRandOffset]! |\n (data[tsRandOffset + 1]! << 8) |\n (data[tsRandOffset + 2]! << 16) |\n (data[tsRandOffset + 3]! << 24);\n\n new DataView(sendData.buffer).setUint32(INIT_TYPE_LEN + 16, tsRand >>> 0, false);\n return sendData;\n}\n\nfunction buildInit1Step2Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_STEP_LEN) return null;\n\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 16 + 4);\n new DataView(sendData.buffer).setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x02;\n sendData.set(data.slice(1, 21), 5);\n return sendData;\n}\n\nfunction buildInit1Step3Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_VERSION_LEN + INIT_TYPE_LEN + 16 + 4) return null;\n\n const sendData = new Uint8Array(INIT_TYPE_LEN + 64 + 64 + 4 + 100);\n sendData[0] = 0x03;\n sendData[INIT_TYPE_LEN + 64 - 1] = 1;\n sendData[INIT_TYPE_LEN + 64 + 64 - 1] = 1;\n new DataView(sendData.buffer).setUint32(INIT_TYPE_LEN + 64 + 64, 1, false);\n return sendData;\n}\n\nfunction buildInit1Step4Packet(crypt: Crypt, data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_TYPE_LEN + 64 + 64 + 4 + 100) return null;\n\n const level = new DataView(data.buffer, data.byteOffset).getUint32(1 + 128, false);\n const y = crypt.solveRsaChallenge(data, 1, level);\n\n crypt.alphaTmp = new Uint8Array(randomBytes(10));\n\n const alphaB64 = Buffer.from(crypt.alphaTmp).toString(\"base64\");\n const omegaB64 = crypt.identity.publicKeyBase64();\n\n const cmd = buildCommandOrdered(\"clientinitiv\", [\n [\"alpha\", alphaB64],\n [\"omega\", omegaB64],\n [\"ot\", \"1\"],\n [\"ip\", \"\"],\n ]);\n const cmdBytes = Buffer.from(cmd);\n\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 232 + 64 + cmdBytes.length);\n const view = new DataView(sendData.buffer);\n view.setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x04;\n sendData.set(data.slice(1, 233), 5);\n sendData.set(y.slice(0, 64), 5 + 232);\n sendData.set(cmdBytes, 5 + 232 + 64);\n\n return sendData;\n}\n"],"mappings":";;;AAIA,
|
|
1
|
+
{"version":3,"file":"crypt-handshake-DziOY4Lq.js","names":["buildCommandOrdered","INIT_VERSION","INIT_STEP_LEN","processInit1","data","buildInit1StartPacket","buildInit1Step1Packet","buildInit1Step2Packet","buildInit1Step3Packet","buildInit1Step4Packet","crypt","sendData","view","nowSec","clampedNow","rng","randomBytes","tsRand","level","y","alphaB64","omegaB64","cmd","cmdBytes"],"sources":["../src/handshake/crypt-handshake.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { buildCommandOrdered } from \"../command/command.js\";\nimport type { Crypt } from \"../crypto/crypt.js\";\n\nexport const INIT_VERSION = 1566914096; // 3.5.0 [Stable]\n\nconst INIT_VERSION_LEN = 4;\nconst INIT_TYPE_LEN = 1;\nconst INIT_STEP_LEN = 21;\n\n/**\n * Handle the TS3INIT1 handshake steps.\n * Returns the response bytes to send, or null if nothing should be sent.\n */\nexport function processInit1(crypt: Crypt, data: Uint8Array | null): Uint8Array | null {\n if (data === null || (data.length >= 1 && data[0] === 0x7f)) {\n return buildInit1StartPacket();\n }\n\n switch (data[0]) {\n case 0:\n return buildInit1Step1Packet(data);\n case 1:\n return buildInit1Step2Packet(data);\n case 2:\n return buildInit1Step3Packet(data);\n case 3:\n return buildInit1Step4Packet(crypt, data);\n default:\n return null;\n }\n}\n\nfunction buildInit1StartPacket(): Uint8Array {\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 4 + 4 + 8);\n const view = new DataView(sendData.buffer);\n\n view.setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x00;\n\n const nowSec = Math.floor(Date.now() / 1000);\n const clampedNow = Math.max(0, Math.min(nowSec, 0xffff_ffff));\n view.setUint32(5, clampedNow, false);\n\n const rng = randomBytes(4);\n sendData.set(rng, 9);\n\n return sendData;\n}\n\nfunction buildInit1Step1Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_STEP_LEN) return null;\n\n const sendData = new Uint8Array(INIT_TYPE_LEN + 16 + 4);\n sendData[0] = 0x01;\n\n // TS rand: little-endian uint32 at offset [INIT_VERSION_LEN + INIT_TYPE_LEN + 4]\n const tsRandOffset = INIT_VERSION_LEN + INIT_TYPE_LEN + 4;\n const tsRand =\n data[tsRandOffset]! |\n (data[tsRandOffset + 1]! << 8) |\n (data[tsRandOffset + 2]! << 16) |\n (data[tsRandOffset + 3]! << 24);\n\n new DataView(sendData.buffer).setUint32(INIT_TYPE_LEN + 16, tsRand >>> 0, false);\n return sendData;\n}\n\nfunction buildInit1Step2Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_STEP_LEN) return null;\n\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 16 + 4);\n new DataView(sendData.buffer).setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x02;\n sendData.set(data.slice(1, 21), 5);\n return sendData;\n}\n\nfunction buildInit1Step3Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_VERSION_LEN + INIT_TYPE_LEN + 16 + 4) return null;\n\n const sendData = new Uint8Array(INIT_TYPE_LEN + 64 + 64 + 4 + 100);\n sendData[0] = 0x03;\n sendData[INIT_TYPE_LEN + 64 - 1] = 1;\n sendData[INIT_TYPE_LEN + 64 + 64 - 1] = 1;\n new DataView(sendData.buffer).setUint32(INIT_TYPE_LEN + 64 + 64, 1, false);\n return sendData;\n}\n\nfunction buildInit1Step4Packet(crypt: Crypt, data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_TYPE_LEN + 64 + 64 + 4 + 100) return null;\n\n const level = new DataView(data.buffer, data.byteOffset).getUint32(1 + 128, false);\n const y = crypt.solveRsaChallenge(data, 1, level);\n\n crypt.alphaTmp = new Uint8Array(randomBytes(10));\n\n const alphaB64 = Buffer.from(crypt.alphaTmp).toString(\"base64\");\n const omegaB64 = crypt.identity.publicKeyBase64();\n\n const cmd = buildCommandOrdered(\"clientinitiv\", [\n [\"alpha\", alphaB64],\n [\"omega\", omegaB64],\n [\"ot\", \"1\"],\n [\"ip\", \"\"],\n ]);\n const cmdBytes = Buffer.from(cmd);\n\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 232 + 64 + cmdBytes.length);\n const view = new DataView(sendData.buffer);\n view.setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x04;\n sendData.set(data.slice(1, 233), 5);\n sendData.set(y.slice(0, 64), 5 + 232);\n sendData.set(cmdBytes, 5 + 232 + 64);\n\n return sendData;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypt-init2-D70ha4LB.js","names":[],"sources":["../src/handshake/license.ts","../src/handshake/crypt-init2.ts"],"sourcesContent":["import { hash512 } from \"../crypto/identity.js\";\nimport { clampScalar, scalarMultFull, bytesToBigIntLE } from \"../crypto/primitives.js\";\nimport { ed25519 } from \"@noble/curves/ed25519.js\";\n\n// The root key is a 33-byte Ed25519 point\nconst LICENSE_ROOT_KEY = new Uint8Array([\n 0xcd, 0x0d, 0xe2, 0xae, 0xd4, 0x63, 0x45, 0x50, 0x9a, 0x7e, 0x3c, 0xfd, 0x8f, 0x68, 0xb3, 0xdc,\n 0x75, 0x55, 0xb2, 0x9d, 0xcc, 0xec, 0x73, 0xcd, 0x18, 0x75, 0x0f, 0x99, 0x38, 0x12, 0x40, 0x8a,\n]);\n\nconst enum LicenseBlockType {\n Intermediate = 0,\n Server = 2,\n Ts5Server = 8,\n Ephemeral = 32,\n}\n\ninterface LicenseBlock {\n readonly key: Uint8Array; // 32-byte Ed25519 point\n readonly hash: Uint8Array; // SHA-512 truncated to 32 bytes\n properties: Uint8Array[];\n issuer: string;\n notValidBefore: Date;\n notValidAfter: Date;\n blockType: LicenseBlockType;\n serverType: number;\n}\n\nexport class LicenseChain {\n readonly blocks: LicenseBlock[];\n\n constructor(blocks: LicenseBlock[]) {\n this.blocks = blocks;\n }\n\n /**\n * Derive the session key by chaining Ed25519 point arithmetic starting from\n * the root key through each license block.\n */\n deriveKey(): Uint8Array<ArrayBuffer> {\n let round: Uint8Array<ArrayBuffer> = Uint8Array.from(LICENSE_ROOT_KEY);\n for (const block of this.blocks) {\n round = deriveKeyFromBlock(block, round);\n }\n return round;\n }\n}\n\nexport function parseLicenses(data: Uint8Array): LicenseChain {\n if (data.length < 1) throw new Error(\"license too short\");\n if (data[0] !== 1) throw new Error(\"unsupported license version\");\n\n let remaining = data.slice(1);\n const blocks: LicenseBlock[] = [];\n\n while (remaining.length > 0) {\n const { block, consumed } = parseLicenseBlock(remaining);\n blocks.push(block);\n remaining = remaining.slice(consumed);\n }\n\n return new LicenseChain(blocks);\n}\n\nfunction parseLicenseBlock(data: Uint8Array): { block: LicenseBlock; consumed: number } {\n const MIN_BLOCK_LEN = 42;\n if (data.length < MIN_BLOCK_LEN) throw new Error(\"license too short\");\n if (data[0] !== 0) throw new Error(`wrong key kind in license: ${data[0]}`);\n\n const blockType = data[33] as LicenseBlockType;\n\n // Timestamps are seconds since Unix epoch offset by 0x50e22700\n const UNIX_OFFSET = 0x50e22700;\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const notValidBefore = new Date((view.getUint32(34, false) + UNIX_OFFSET) * 1000);\n const notValidAfter = new Date((view.getUint32(38, false) + UNIX_OFFSET) * 1000);\n\n if (notValidAfter < notValidBefore) {\n throw new Error(\"license times are invalid\");\n }\n\n const key = Uint8Array.from(data.slice(1, 33));\n\n const { payload, payloadRead } = parseBlockPayload(blockType, data, MIN_BLOCK_LEN);\n\n const allLen = MIN_BLOCK_LEN + payloadRead;\n const hashInput = data.slice(1, allLen);\n const hashFull = hash512(Uint8Array.from(hashInput));\n const hash = Uint8Array.from(hashFull.slice(0, 32));\n\n return {\n block: {\n key,\n hash,\n properties: payload.properties,\n issuer: payload.issuer,\n notValidBefore,\n notValidAfter,\n blockType,\n serverType: payload.serverType,\n },\n consumed: allLen,\n };\n}\n\ninterface BlockPayload {\n issuer: string;\n serverType: number;\n properties: Uint8Array[];\n read: number;\n}\n\nfunction parseBlockPayload(\n blockType: LicenseBlockType,\n data: Uint8Array,\n minBlockLen: number,\n): { payload: BlockPayload; payloadRead: number } {\n switch (blockType) {\n case LicenseBlockType.Intermediate: {\n const { str, read } = readNullString(data.slice(46));\n return {\n payload: { issuer: str, serverType: 0, properties: [], read: 5 + read },\n payloadRead: 5 + read,\n };\n }\n case LicenseBlockType.Server: {\n const { str, read } = readNullString(data.slice(47));\n return {\n payload: { issuer: str, serverType: data[42] ?? 0, properties: [], read: 6 + read },\n payloadRead: 6 + read,\n };\n }\n case LicenseBlockType.Ts5Server: {\n const propCount = data[43] !== undefined ? data[43] : 0;\n let pos = 44;\n const properties: Uint8Array[] = [];\n for (let i = 0; i < propCount; i++) {\n if (pos >= data.length) throw new Error(\"license too short\");\n const propLen = data[pos++]!;\n if (pos + propLen > data.length) throw new Error(\"license too short\");\n properties.push(Uint8Array.from(data.slice(pos, pos + propLen)));\n pos += propLen;\n }\n return {\n payload: { issuer: \"\", serverType: data[42] ?? 0, properties, read: pos - minBlockLen },\n payloadRead: pos - minBlockLen,\n };\n }\n case LicenseBlockType.Ephemeral:\n return { payload: { issuer: \"\", serverType: 0, properties: [], read: 0 }, payloadRead: 0 };\n default:\n throw new Error(`invalid license block type: ${blockType}`);\n }\n}\n\n/**\n * Scan for a null-terminated string and return its content and the index\n * of the null byte (NOT including it in the count, matching Go behaviour).\n * The parent formulas (`5 + read`, `6 + read`) already add 1 for the null.\n */\nfunction readNullString(data: Uint8Array): { str: string; read: number } {\n for (let i = 0; i < data.length; i++) {\n if (data[i] === 0) {\n return { str: new TextDecoder().decode(data.slice(0, i)), read: i };\n }\n }\n throw new Error(\"non-null-terminated issuer string\");\n}\n\n/**\n * Derive the next key given a parent key and a license block.\n * Mirrors Go's licenseBlock.deriveKey.\n */\nfunction deriveKeyFromBlock(block: LicenseBlock, parent: Uint8Array): Uint8Array<ArrayBuffer> {\n const scalarBytes = Uint8Array.from(block.hash);\n clampScalar(scalarBytes);\n\n // Use raw scalar WITHOUT reducing mod n — NaCl's ge_scalarmult_vartime\n // uses the raw 256-bit scalar. Reducing mod n changes the result when\n // the point has a small-order component (Ed25519 cofactor = 8).\n const scalar = bytesToBigIntLE(scalarBytes);\n\n const pub = ed25519.Point.fromBytes(block.key);\n const negPub = pub.negate();\n\n const par = ed25519.Point.fromBytes(parent);\n const negPar = par.negate();\n\n const res = scalarMultFull(negPub, scalar).add(negPar);\n const raw = res.toBytes();\n const final = new Uint8Array(raw.length) as Uint8Array<ArrayBuffer>;\n final.set(raw);\n final[31] = (final[31] !== undefined ? final[31] : 0) ^ 0x80;\n\n return final;\n}\n","import type { Crypt } from \"../crypto/crypt.js\";\nimport { importPublicKey } from \"../crypto/identity.js\";\nimport { verifySign, getSharedSecret2 } from \"../crypto/primitives.js\";\nimport { parseLicenses } from \"./license.js\";\n\n/**\n * CryptoInit2 performs the second stage of crypto initialization (Ed25519 ECDH).\n * Mirrors Go's handshake.CryptoInit2.\n */\nexport function cryptoInit2(\n crypt: Crypt,\n license: string,\n omega: string,\n proof: string,\n beta: string,\n privateKey: Uint8Array,\n): void {\n if (crypt.alphaTmp.length === 0) {\n throw new Error(\"alpha is not initialized\");\n }\n\n const licenseBytes = Buffer.from(license, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n const proofBytes = Buffer.from(proof, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n\n const serverPubKey = importPublicKey(omegaBytes);\n if (!verifySign(serverPubKey, licenseBytes, proofBytes)) {\n throw new Error(\"init proof is not valid\");\n }\n\n const licenses = parseLicenses(licenseBytes);\n const key = licenses.deriveKey();\n\n const sharedSecret = getSharedSecret2(key, privateKey);\n\n crypt.setSharedSecret(crypt.alphaTmp, betaBytes, sharedSecret);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"crypt-init2-D70ha4LB.js","names":["scalarMultFull","ed25519","hash512","getSharedSecret2","importPublicKey","clampScalar","verifySign","bytesToBigIntLE","LICENSE_ROOT_KEY","LicenseChain","blocks","round","block","deriveKeyFromBlock","parseLicenses","data","remaining","parseLicenseBlock","consumed","blockType","UNIX_OFFSET","view","notValidBefore","notValidAfter","key","parseBlockPayload","allLen","payloadRead","hashInput","hashFull","payload","readNullString","str","read","propCount","pos","properties","i","propLen","minBlockLen","scalarBytes","scalar","negPub","negPar","parent","raw","final","cryptoInit2","crypt","licenseBytes","license","omegaBytes","omega","proofBytes","proof","betaBytes","beta","serverPubKey","sharedSecret","privateKey"],"sources":["../src/handshake/license.ts","../src/handshake/crypt-init2.ts"],"sourcesContent":["import { hash512 } from \"../crypto/identity.js\";\nimport { clampScalar, scalarMultFull, bytesToBigIntLE } from \"../crypto/primitives.js\";\nimport { ed25519 } from \"@noble/curves/ed25519.js\";\n\n// The root key is a 33-byte Ed25519 point\nconst LICENSE_ROOT_KEY = new Uint8Array([\n 0xcd, 0x0d, 0xe2, 0xae, 0xd4, 0x63, 0x45, 0x50, 0x9a, 0x7e, 0x3c, 0xfd, 0x8f, 0x68, 0xb3, 0xdc,\n 0x75, 0x55, 0xb2, 0x9d, 0xcc, 0xec, 0x73, 0xcd, 0x18, 0x75, 0x0f, 0x99, 0x38, 0x12, 0x40, 0x8a,\n]);\n\nconst enum LicenseBlockType {\n Intermediate = 0,\n Server = 2,\n Ts5Server = 8,\n Ephemeral = 32,\n}\n\ninterface LicenseBlock {\n readonly key: Uint8Array; // 32-byte Ed25519 point\n readonly hash: Uint8Array; // SHA-512 truncated to 32 bytes\n properties: Uint8Array[];\n issuer: string;\n notValidBefore: Date;\n notValidAfter: Date;\n blockType: LicenseBlockType;\n serverType: number;\n}\n\nexport class LicenseChain {\n readonly blocks: LicenseBlock[];\n\n constructor(blocks: LicenseBlock[]) {\n this.blocks = blocks;\n }\n\n /**\n * Derive the session key by chaining Ed25519 point arithmetic starting from\n * the root key through each license block.\n */\n deriveKey(): Uint8Array<ArrayBuffer> {\n let round: Uint8Array<ArrayBuffer> = Uint8Array.from(LICENSE_ROOT_KEY);\n for (const block of this.blocks) {\n round = deriveKeyFromBlock(block, round);\n }\n return round;\n }\n}\n\nexport function parseLicenses(data: Uint8Array): LicenseChain {\n if (data.length < 1) throw new Error(\"license too short\");\n if (data[0] !== 1) throw new Error(\"unsupported license version\");\n\n let remaining = data.slice(1);\n const blocks: LicenseBlock[] = [];\n\n while (remaining.length > 0) {\n const { block, consumed } = parseLicenseBlock(remaining);\n blocks.push(block);\n remaining = remaining.slice(consumed);\n }\n\n return new LicenseChain(blocks);\n}\n\nfunction parseLicenseBlock(data: Uint8Array): { block: LicenseBlock; consumed: number } {\n const MIN_BLOCK_LEN = 42;\n if (data.length < MIN_BLOCK_LEN) throw new Error(\"license too short\");\n if (data[0] !== 0) throw new Error(`wrong key kind in license: ${data[0]}`);\n\n const blockType = data[33] as LicenseBlockType;\n\n // Timestamps are seconds since Unix epoch offset by 0x50e22700\n const UNIX_OFFSET = 0x50e22700;\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const notValidBefore = new Date((view.getUint32(34, false) + UNIX_OFFSET) * 1000);\n const notValidAfter = new Date((view.getUint32(38, false) + UNIX_OFFSET) * 1000);\n\n if (notValidAfter < notValidBefore) {\n throw new Error(\"license times are invalid\");\n }\n\n const key = Uint8Array.from(data.slice(1, 33));\n\n const { payload, payloadRead } = parseBlockPayload(blockType, data, MIN_BLOCK_LEN);\n\n const allLen = MIN_BLOCK_LEN + payloadRead;\n const hashInput = data.slice(1, allLen);\n const hashFull = hash512(Uint8Array.from(hashInput));\n const hash = Uint8Array.from(hashFull.slice(0, 32));\n\n return {\n block: {\n key,\n hash,\n properties: payload.properties,\n issuer: payload.issuer,\n notValidBefore,\n notValidAfter,\n blockType,\n serverType: payload.serverType,\n },\n consumed: allLen,\n };\n}\n\ninterface BlockPayload {\n issuer: string;\n serverType: number;\n properties: Uint8Array[];\n read: number;\n}\n\nfunction parseBlockPayload(\n blockType: LicenseBlockType,\n data: Uint8Array,\n minBlockLen: number,\n): { payload: BlockPayload; payloadRead: number } {\n switch (blockType) {\n case LicenseBlockType.Intermediate: {\n const { str, read } = readNullString(data.slice(46));\n return {\n payload: { issuer: str, serverType: 0, properties: [], read: 5 + read },\n payloadRead: 5 + read,\n };\n }\n case LicenseBlockType.Server: {\n const { str, read } = readNullString(data.slice(47));\n return {\n payload: { issuer: str, serverType: data[42] ?? 0, properties: [], read: 6 + read },\n payloadRead: 6 + read,\n };\n }\n case LicenseBlockType.Ts5Server: {\n const propCount = data[43] !== undefined ? data[43] : 0;\n let pos = 44;\n const properties: Uint8Array[] = [];\n for (let i = 0; i < propCount; i++) {\n if (pos >= data.length) throw new Error(\"license too short\");\n const propLen = data[pos++]!;\n if (pos + propLen > data.length) throw new Error(\"license too short\");\n properties.push(Uint8Array.from(data.slice(pos, pos + propLen)));\n pos += propLen;\n }\n return {\n payload: { issuer: \"\", serverType: data[42] ?? 0, properties, read: pos - minBlockLen },\n payloadRead: pos - minBlockLen,\n };\n }\n case LicenseBlockType.Ephemeral:\n return { payload: { issuer: \"\", serverType: 0, properties: [], read: 0 }, payloadRead: 0 };\n default:\n throw new Error(`invalid license block type: ${blockType}`);\n }\n}\n\n/**\n * Scan for a null-terminated string and return its content and the index\n * of the null byte (NOT including it in the count, matching Go behaviour).\n * The parent formulas (`5 + read`, `6 + read`) already add 1 for the null.\n */\nfunction readNullString(data: Uint8Array): { str: string; read: number } {\n for (let i = 0; i < data.length; i++) {\n if (data[i] === 0) {\n return { str: new TextDecoder().decode(data.slice(0, i)), read: i };\n }\n }\n throw new Error(\"non-null-terminated issuer string\");\n}\n\n/**\n * Derive the next key given a parent key and a license block.\n * Mirrors Go's licenseBlock.deriveKey.\n */\nfunction deriveKeyFromBlock(block: LicenseBlock, parent: Uint8Array): Uint8Array<ArrayBuffer> {\n const scalarBytes = Uint8Array.from(block.hash);\n clampScalar(scalarBytes);\n\n // Use raw scalar WITHOUT reducing mod n — NaCl's ge_scalarmult_vartime\n // uses the raw 256-bit scalar. Reducing mod n changes the result when\n // the point has a small-order component (Ed25519 cofactor = 8).\n const scalar = bytesToBigIntLE(scalarBytes);\n\n const pub = ed25519.Point.fromBytes(block.key);\n const negPub = pub.negate();\n\n const par = ed25519.Point.fromBytes(parent);\n const negPar = par.negate();\n\n const res = scalarMultFull(negPub, scalar).add(negPar);\n const raw = res.toBytes();\n const final = new Uint8Array(raw.length) as Uint8Array<ArrayBuffer>;\n final.set(raw);\n final[31] = (final[31] !== undefined ? final[31] : 0) ^ 0x80;\n\n return final;\n}\n","import type { Crypt } from \"../crypto/crypt.js\";\nimport { importPublicKey } from \"../crypto/identity.js\";\nimport { verifySign, getSharedSecret2 } from \"../crypto/primitives.js\";\nimport { parseLicenses } from \"./license.js\";\n\n/**\n * CryptoInit2 performs the second stage of crypto initialization (Ed25519 ECDH).\n * Mirrors Go's handshake.CryptoInit2.\n */\nexport function cryptoInit2(\n crypt: Crypt,\n license: string,\n omega: string,\n proof: string,\n beta: string,\n privateKey: Uint8Array,\n): void {\n if (crypt.alphaTmp.length === 0) {\n throw new Error(\"alpha is not initialized\");\n }\n\n const licenseBytes = Buffer.from(license, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n const proofBytes = Buffer.from(proof, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n\n const serverPubKey = importPublicKey(omegaBytes);\n if (!verifySign(serverPubKey, licenseBytes, proofBytes)) {\n throw new Error(\"init proof is not valid\");\n }\n\n const licenses = parseLicenses(licenseBytes);\n const key = licenses.deriveKey();\n\n const sharedSecret = getSharedSecret2(key, privateKey);\n\n crypt.setSharedSecret(crypt.alphaTmp, betaBytes, sharedSecret);\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypt-init2-DparLekm.cjs","names":[],"sources":["../src/handshake/license.ts","../src/handshake/crypt-init2.ts"],"sourcesContent":["import { hash512 } from \"../crypto/identity.js\";\nimport { clampScalar, scalarMultFull, bytesToBigIntLE } from \"../crypto/primitives.js\";\nimport { ed25519 } from \"@noble/curves/ed25519.js\";\n\n// The root key is a 33-byte Ed25519 point\nconst LICENSE_ROOT_KEY = new Uint8Array([\n 0xcd, 0x0d, 0xe2, 0xae, 0xd4, 0x63, 0x45, 0x50, 0x9a, 0x7e, 0x3c, 0xfd, 0x8f, 0x68, 0xb3, 0xdc,\n 0x75, 0x55, 0xb2, 0x9d, 0xcc, 0xec, 0x73, 0xcd, 0x18, 0x75, 0x0f, 0x99, 0x38, 0x12, 0x40, 0x8a,\n]);\n\nconst enum LicenseBlockType {\n Intermediate = 0,\n Server = 2,\n Ts5Server = 8,\n Ephemeral = 32,\n}\n\ninterface LicenseBlock {\n readonly key: Uint8Array; // 32-byte Ed25519 point\n readonly hash: Uint8Array; // SHA-512 truncated to 32 bytes\n properties: Uint8Array[];\n issuer: string;\n notValidBefore: Date;\n notValidAfter: Date;\n blockType: LicenseBlockType;\n serverType: number;\n}\n\nexport class LicenseChain {\n readonly blocks: LicenseBlock[];\n\n constructor(blocks: LicenseBlock[]) {\n this.blocks = blocks;\n }\n\n /**\n * Derive the session key by chaining Ed25519 point arithmetic starting from\n * the root key through each license block.\n */\n deriveKey(): Uint8Array<ArrayBuffer> {\n let round: Uint8Array<ArrayBuffer> = Uint8Array.from(LICENSE_ROOT_KEY);\n for (const block of this.blocks) {\n round = deriveKeyFromBlock(block, round);\n }\n return round;\n }\n}\n\nexport function parseLicenses(data: Uint8Array): LicenseChain {\n if (data.length < 1) throw new Error(\"license too short\");\n if (data[0] !== 1) throw new Error(\"unsupported license version\");\n\n let remaining = data.slice(1);\n const blocks: LicenseBlock[] = [];\n\n while (remaining.length > 0) {\n const { block, consumed } = parseLicenseBlock(remaining);\n blocks.push(block);\n remaining = remaining.slice(consumed);\n }\n\n return new LicenseChain(blocks);\n}\n\nfunction parseLicenseBlock(data: Uint8Array): { block: LicenseBlock; consumed: number } {\n const MIN_BLOCK_LEN = 42;\n if (data.length < MIN_BLOCK_LEN) throw new Error(\"license too short\");\n if (data[0] !== 0) throw new Error(`wrong key kind in license: ${data[0]}`);\n\n const blockType = data[33] as LicenseBlockType;\n\n // Timestamps are seconds since Unix epoch offset by 0x50e22700\n const UNIX_OFFSET = 0x50e22700;\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const notValidBefore = new Date((view.getUint32(34, false) + UNIX_OFFSET) * 1000);\n const notValidAfter = new Date((view.getUint32(38, false) + UNIX_OFFSET) * 1000);\n\n if (notValidAfter < notValidBefore) {\n throw new Error(\"license times are invalid\");\n }\n\n const key = Uint8Array.from(data.slice(1, 33));\n\n const { payload, payloadRead } = parseBlockPayload(blockType, data, MIN_BLOCK_LEN);\n\n const allLen = MIN_BLOCK_LEN + payloadRead;\n const hashInput = data.slice(1, allLen);\n const hashFull = hash512(Uint8Array.from(hashInput));\n const hash = Uint8Array.from(hashFull.slice(0, 32));\n\n return {\n block: {\n key,\n hash,\n properties: payload.properties,\n issuer: payload.issuer,\n notValidBefore,\n notValidAfter,\n blockType,\n serverType: payload.serverType,\n },\n consumed: allLen,\n };\n}\n\ninterface BlockPayload {\n issuer: string;\n serverType: number;\n properties: Uint8Array[];\n read: number;\n}\n\nfunction parseBlockPayload(\n blockType: LicenseBlockType,\n data: Uint8Array,\n minBlockLen: number,\n): { payload: BlockPayload; payloadRead: number } {\n switch (blockType) {\n case LicenseBlockType.Intermediate: {\n const { str, read } = readNullString(data.slice(46));\n return {\n payload: { issuer: str, serverType: 0, properties: [], read: 5 + read },\n payloadRead: 5 + read,\n };\n }\n case LicenseBlockType.Server: {\n const { str, read } = readNullString(data.slice(47));\n return {\n payload: { issuer: str, serverType: data[42] ?? 0, properties: [], read: 6 + read },\n payloadRead: 6 + read,\n };\n }\n case LicenseBlockType.Ts5Server: {\n const propCount = data[43] !== undefined ? data[43] : 0;\n let pos = 44;\n const properties: Uint8Array[] = [];\n for (let i = 0; i < propCount; i++) {\n if (pos >= data.length) throw new Error(\"license too short\");\n const propLen = data[pos++]!;\n if (pos + propLen > data.length) throw new Error(\"license too short\");\n properties.push(Uint8Array.from(data.slice(pos, pos + propLen)));\n pos += propLen;\n }\n return {\n payload: { issuer: \"\", serverType: data[42] ?? 0, properties, read: pos - minBlockLen },\n payloadRead: pos - minBlockLen,\n };\n }\n case LicenseBlockType.Ephemeral:\n return { payload: { issuer: \"\", serverType: 0, properties: [], read: 0 }, payloadRead: 0 };\n default:\n throw new Error(`invalid license block type: ${blockType}`);\n }\n}\n\n/**\n * Scan for a null-terminated string and return its content and the index\n * of the null byte (NOT including it in the count, matching Go behaviour).\n * The parent formulas (`5 + read`, `6 + read`) already add 1 for the null.\n */\nfunction readNullString(data: Uint8Array): { str: string; read: number } {\n for (let i = 0; i < data.length; i++) {\n if (data[i] === 0) {\n return { str: new TextDecoder().decode(data.slice(0, i)), read: i };\n }\n }\n throw new Error(\"non-null-terminated issuer string\");\n}\n\n/**\n * Derive the next key given a parent key and a license block.\n * Mirrors Go's licenseBlock.deriveKey.\n */\nfunction deriveKeyFromBlock(block: LicenseBlock, parent: Uint8Array): Uint8Array<ArrayBuffer> {\n const scalarBytes = Uint8Array.from(block.hash);\n clampScalar(scalarBytes);\n\n // Use raw scalar WITHOUT reducing mod n — NaCl's ge_scalarmult_vartime\n // uses the raw 256-bit scalar. Reducing mod n changes the result when\n // the point has a small-order component (Ed25519 cofactor = 8).\n const scalar = bytesToBigIntLE(scalarBytes);\n\n const pub = ed25519.Point.fromBytes(block.key);\n const negPub = pub.negate();\n\n const par = ed25519.Point.fromBytes(parent);\n const negPar = par.negate();\n\n const res = scalarMultFull(negPub, scalar).add(negPar);\n const raw = res.toBytes();\n const final = new Uint8Array(raw.length) as Uint8Array<ArrayBuffer>;\n final.set(raw);\n final[31] = (final[31] !== undefined ? final[31] : 0) ^ 0x80;\n\n return final;\n}\n","import type { Crypt } from \"../crypto/crypt.js\";\nimport { importPublicKey } from \"../crypto/identity.js\";\nimport { verifySign, getSharedSecret2 } from \"../crypto/primitives.js\";\nimport { parseLicenses } from \"./license.js\";\n\n/**\n * CryptoInit2 performs the second stage of crypto initialization (Ed25519 ECDH).\n * Mirrors Go's handshake.CryptoInit2.\n */\nexport function cryptoInit2(\n crypt: Crypt,\n license: string,\n omega: string,\n proof: string,\n beta: string,\n privateKey: Uint8Array,\n): void {\n if (crypt.alphaTmp.length === 0) {\n throw new Error(\"alpha is not initialized\");\n }\n\n const licenseBytes = Buffer.from(license, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n const proofBytes = Buffer.from(proof, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n\n const serverPubKey = importPublicKey(omegaBytes);\n if (!verifySign(serverPubKey, licenseBytes, proofBytes)) {\n throw new Error(\"init proof is not valid\");\n }\n\n const licenses = parseLicenses(licenseBytes);\n const key = licenses.deriveKey();\n\n const sharedSecret = getSharedSecret2(key, privateKey);\n\n crypt.setSharedSecret(crypt.alphaTmp, betaBytes, sharedSecret);\n}\n"],"mappings":"6CAKA,IAAM,EAAmB,IAAI,WAAW,CACtC,IAAM,GAAM,IAAM,IAAM,IAAM,GAAM,GAAM,GAAM,IAAM,IAAM,GAAM,IAAM,IAAM,IAAM,IAAM,IAC1F,IAAM,GAAM,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,GAAM,IAAM,GAAM,IAAM,GAAM,GAAM,GAAM,GAC5F,CAAC,EAoBY,EAAb,KAA0B,CACxB,OAEA,YAAY,EAAwB,CAClC,KAAK,OAAS,CAChB,CAMA,WAAqC,CACnC,IAAI,EAAiC,WAAW,KAAK,CAAgB,EACrE,IAAK,IAAM,KAAS,KAAK,OACvB,EAAQ,EAAmB,EAAO,CAAK,EAEzC,OAAO,CACT,CACF,EAEA,SAAgB,EAAc,EAAgC,CAC5D,GAAI,EAAK,OAAS,EAAG,MAAU,MAAM,mBAAmB,EACxD,GAAI,EAAK,KAAO,EAAG,MAAU,MAAM,6BAA6B,EAEhE,IAAI,EAAY,EAAK,MAAM,CAAC,EACtB,EAAyB,CAAC,EAEhC,KAAO,EAAU,OAAS,GAAG,CAC3B,GAAM,CAAE,QAAO,YAAa,EAAkB,CAAS,EACvD,EAAO,KAAK,CAAK,EACjB,EAAY,EAAU,MAAM,CAAQ,CACtC,CAEA,OAAO,IAAI,EAAa,CAAM,CAChC,CAEA,SAAS,EAAkB,EAA6D,CAEtF,GAAI,EAAK,OAAS,GAAe,MAAU,MAAM,mBAAmB,EACpE,GAAI,EAAK,KAAO,EAAG,MAAU,MAAM,8BAA8B,EAAK,IAAI,EAE1E,IAAM,EAAY,EAAK,IAGjB,EAAc,WACd,EAAO,IAAI,SAAS,EAAK,OAAQ,EAAK,WAAY,EAAK,UAAU,EACjE,EAAiB,IAAI,MAAM,EAAK,UAAU,GAAI,EAAK,EAAI,GAAe,GAAI,EAC1E,EAAgB,IAAI,MAAM,EAAK,UAAU,GAAI,EAAK,EAAI,GAAe,GAAI,EAE/E,GAAI,EAAgB,EAClB,MAAU,MAAM,2BAA2B,EAG7C,IAAM,EAAM,WAAW,KAAK,EAAK,MAAM,EAAG,EAAE,CAAC,EAEvC,CAAE,UAAS,eAAgB,EAAkB,EAAW,EAAM,EAAa,EAE3E,EAAS,GAAgB,EACzB,EAAY,EAAK,MAAM,EAAG,CAAM,EAChC,EAAW,EAAA,EAAQ,WAAW,KAAK,CAAS,CAAC,EAGnD,MAAO,CACL,MAAO,CACL,MACA,KALS,WAAW,KAAK,EAAS,MAAM,EAAG,EAAE,CAK7C,EACA,WAAY,EAAQ,WACpB,OAAQ,EAAQ,OAChB,iBACA,gBACA,YACA,WAAY,EAAQ,UACtB,EACA,SAAU,CACZ,CACF,CASA,SAAS,EACP,EACA,EACA,EACgD,CAChD,OAAQ,EAAR,CACE,IAAA,GAAoC,CAClC,GAAM,CAAE,MAAK,QAAS,EAAe,EAAK,MAAM,EAAE,CAAC,EACnD,MAAO,CACL,QAAS,CAAE,OAAQ,EAAK,WAAY,EAAG,WAAY,CAAC,EAAG,KAAM,EAAI,CAAK,EACtE,YAAa,EAAI,CACnB,CACF,CACA,IAAA,GAA8B,CAC5B,GAAM,CAAE,MAAK,QAAS,EAAe,EAAK,MAAM,EAAE,CAAC,EACnD,MAAO,CACL,QAAS,CAAE,OAAQ,EAAK,WAAY,EAAK,KAAO,EAAG,WAAY,CAAC,EAAG,KAAM,EAAI,CAAK,EAClF,YAAa,EAAI,CACnB,CACF,CACA,IAAA,GAAiC,CAC/B,IAAM,EAAY,EAAK,MAAQ,IAAA,GAAuB,EAAX,EAAK,IAC5C,EAAM,GACJ,EAA2B,CAAC,EAClC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAW,IAAK,CAClC,GAAI,GAAO,EAAK,OAAQ,MAAU,MAAM,mBAAmB,EAC3D,IAAM,EAAU,EAAK,KACrB,GAAI,EAAM,EAAU,EAAK,OAAQ,MAAU,MAAM,mBAAmB,EACpE,EAAW,KAAK,WAAW,KAAK,EAAK,MAAM,EAAK,EAAM,CAAO,CAAC,CAAC,EAC/D,GAAO,CACT,CACA,MAAO,CACL,QAAS,CAAE,OAAQ,GAAI,WAAY,EAAK,KAAO,EAAG,aAAY,KAAM,EAAM,CAAY,EACtF,YAAa,EAAM,CACrB,CACF,CACA,IAAA,IACE,MAAO,CAAE,QAAS,CAAE,OAAQ,GAAI,WAAY,EAAG,WAAY,CAAC,EAAG,KAAM,CAAE,EAAG,YAAa,CAAE,EAC3F,QACE,MAAU,MAAM,+BAA+B,GAAW,CAC9D,CACF,CAOA,SAAS,EAAe,EAAiD,CACvE,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,OAAQ,IAC/B,GAAI,EAAK,KAAO,EACd,MAAO,CAAE,IAAK,IAAI,YAAY,CAAC,CAAC,OAAO,EAAK,MAAM,EAAG,CAAC,CAAC,EAAG,KAAM,CAAE,EAGtE,MAAU,MAAM,mCAAmC,CACrD,CAMA,SAAS,EAAmB,EAAqB,EAA6C,CAC5F,IAAM,EAAc,WAAW,KAAK,EAAM,IAAI,EAC9C,EAAA,EAAY,CAAW,EAKvB,IAAM,EAAS,EAAA,EAAgB,CAAW,EAGpC,EADM,EAAA,EAAQ,MAAM,UAAU,EAAM,GAC3B,CAAA,CAAI,OAAO,EAGpB,EADM,EAAA,EAAQ,MAAM,UAAU,CACrB,CAAA,CAAI,OAAO,EAGpB,EADM,EAAA,EAAe,EAAQ,CAAM,CAAC,CAAC,IAAI,CACnC,CAAA,CAAI,QAAQ,EAClB,EAAQ,IAAI,WAAW,EAAI,MAAM,EAIvC,OAHA,EAAM,IAAI,CAAG,EACb,EAAM,KAAO,EAAM,MAAQ,IAAA,GAAwB,EAAZ,EAAM,KAAW,IAEjD,CACT,CC1LA,SAAgB,EACd,EACA,EACA,EACA,EACA,EACA,EACM,CACN,GAAI,EAAM,SAAS,SAAW,EAC5B,MAAU,MAAM,0BAA0B,EAG5C,IAAM,EAAe,OAAO,KAAK,EAAS,QAAQ,EAC5C,EAAa,OAAO,KAAK,EAAO,QAAQ,EACxC,EAAa,OAAO,KAAK,EAAO,QAAQ,EACxC,EAAY,OAAO,KAAK,EAAM,QAAQ,EAEtC,EAAe,EAAA,EAAgB,CAAU,EAC/C,GAAI,CAAC,EAAA,EAAW,EAAc,EAAc,CAAU,EACpD,MAAU,MAAM,yBAAyB,EAI3C,IAAM,EADW,EAAc,CACnB,CAAA,CAAS,UAAU,EAEzB,EAAe,EAAA,EAAiB,EAAK,CAAU,EAErD,EAAM,gBAAgB,EAAM,SAAU,EAAW,CAAY,CAC/D"}
|
|
1
|
+
{"version":3,"file":"crypt-init2-DparLekm.cjs","names":["hash512","bytesToBigIntLE","ed25519","scalarMultFull","importPublicKey","verifySign","getSharedSecret2","require_primitives","LICENSE_ROOT_KEY","LicenseChain","blocks","round","block","deriveKeyFromBlock","parseLicenses","data","remaining","parseLicenseBlock","consumed","blockType","UNIX_OFFSET","view","notValidBefore","notValidAfter","key","parseBlockPayload","allLen","payloadRead","hashInput","hashFull","payload","readNullString","str","read","propCount","pos","properties","i","propLen","minBlockLen","scalarBytes","scalar","negPub","negPar","parent","raw","final","cryptoInit2","crypt","licenseBytes","license","omegaBytes","omega","proofBytes","proof","betaBytes","beta","serverPubKey","sharedSecret","privateKey"],"sources":["../src/handshake/license.ts","../src/handshake/crypt-init2.ts"],"sourcesContent":["import { hash512 } from \"../crypto/identity.js\";\nimport { clampScalar, scalarMultFull, bytesToBigIntLE } from \"../crypto/primitives.js\";\nimport { ed25519 } from \"@noble/curves/ed25519.js\";\n\n// The root key is a 33-byte Ed25519 point\nconst LICENSE_ROOT_KEY = new Uint8Array([\n 0xcd, 0x0d, 0xe2, 0xae, 0xd4, 0x63, 0x45, 0x50, 0x9a, 0x7e, 0x3c, 0xfd, 0x8f, 0x68, 0xb3, 0xdc,\n 0x75, 0x55, 0xb2, 0x9d, 0xcc, 0xec, 0x73, 0xcd, 0x18, 0x75, 0x0f, 0x99, 0x38, 0x12, 0x40, 0x8a,\n]);\n\nconst enum LicenseBlockType {\n Intermediate = 0,\n Server = 2,\n Ts5Server = 8,\n Ephemeral = 32,\n}\n\ninterface LicenseBlock {\n readonly key: Uint8Array; // 32-byte Ed25519 point\n readonly hash: Uint8Array; // SHA-512 truncated to 32 bytes\n properties: Uint8Array[];\n issuer: string;\n notValidBefore: Date;\n notValidAfter: Date;\n blockType: LicenseBlockType;\n serverType: number;\n}\n\nexport class LicenseChain {\n readonly blocks: LicenseBlock[];\n\n constructor(blocks: LicenseBlock[]) {\n this.blocks = blocks;\n }\n\n /**\n * Derive the session key by chaining Ed25519 point arithmetic starting from\n * the root key through each license block.\n */\n deriveKey(): Uint8Array<ArrayBuffer> {\n let round: Uint8Array<ArrayBuffer> = Uint8Array.from(LICENSE_ROOT_KEY);\n for (const block of this.blocks) {\n round = deriveKeyFromBlock(block, round);\n }\n return round;\n }\n}\n\nexport function parseLicenses(data: Uint8Array): LicenseChain {\n if (data.length < 1) throw new Error(\"license too short\");\n if (data[0] !== 1) throw new Error(\"unsupported license version\");\n\n let remaining = data.slice(1);\n const blocks: LicenseBlock[] = [];\n\n while (remaining.length > 0) {\n const { block, consumed } = parseLicenseBlock(remaining);\n blocks.push(block);\n remaining = remaining.slice(consumed);\n }\n\n return new LicenseChain(blocks);\n}\n\nfunction parseLicenseBlock(data: Uint8Array): { block: LicenseBlock; consumed: number } {\n const MIN_BLOCK_LEN = 42;\n if (data.length < MIN_BLOCK_LEN) throw new Error(\"license too short\");\n if (data[0] !== 0) throw new Error(`wrong key kind in license: ${data[0]}`);\n\n const blockType = data[33] as LicenseBlockType;\n\n // Timestamps are seconds since Unix epoch offset by 0x50e22700\n const UNIX_OFFSET = 0x50e22700;\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const notValidBefore = new Date((view.getUint32(34, false) + UNIX_OFFSET) * 1000);\n const notValidAfter = new Date((view.getUint32(38, false) + UNIX_OFFSET) * 1000);\n\n if (notValidAfter < notValidBefore) {\n throw new Error(\"license times are invalid\");\n }\n\n const key = Uint8Array.from(data.slice(1, 33));\n\n const { payload, payloadRead } = parseBlockPayload(blockType, data, MIN_BLOCK_LEN);\n\n const allLen = MIN_BLOCK_LEN + payloadRead;\n const hashInput = data.slice(1, allLen);\n const hashFull = hash512(Uint8Array.from(hashInput));\n const hash = Uint8Array.from(hashFull.slice(0, 32));\n\n return {\n block: {\n key,\n hash,\n properties: payload.properties,\n issuer: payload.issuer,\n notValidBefore,\n notValidAfter,\n blockType,\n serverType: payload.serverType,\n },\n consumed: allLen,\n };\n}\n\ninterface BlockPayload {\n issuer: string;\n serverType: number;\n properties: Uint8Array[];\n read: number;\n}\n\nfunction parseBlockPayload(\n blockType: LicenseBlockType,\n data: Uint8Array,\n minBlockLen: number,\n): { payload: BlockPayload; payloadRead: number } {\n switch (blockType) {\n case LicenseBlockType.Intermediate: {\n const { str, read } = readNullString(data.slice(46));\n return {\n payload: { issuer: str, serverType: 0, properties: [], read: 5 + read },\n payloadRead: 5 + read,\n };\n }\n case LicenseBlockType.Server: {\n const { str, read } = readNullString(data.slice(47));\n return {\n payload: { issuer: str, serverType: data[42] ?? 0, properties: [], read: 6 + read },\n payloadRead: 6 + read,\n };\n }\n case LicenseBlockType.Ts5Server: {\n const propCount = data[43] !== undefined ? data[43] : 0;\n let pos = 44;\n const properties: Uint8Array[] = [];\n for (let i = 0; i < propCount; i++) {\n if (pos >= data.length) throw new Error(\"license too short\");\n const propLen = data[pos++]!;\n if (pos + propLen > data.length) throw new Error(\"license too short\");\n properties.push(Uint8Array.from(data.slice(pos, pos + propLen)));\n pos += propLen;\n }\n return {\n payload: { issuer: \"\", serverType: data[42] ?? 0, properties, read: pos - minBlockLen },\n payloadRead: pos - minBlockLen,\n };\n }\n case LicenseBlockType.Ephemeral:\n return { payload: { issuer: \"\", serverType: 0, properties: [], read: 0 }, payloadRead: 0 };\n default:\n throw new Error(`invalid license block type: ${blockType}`);\n }\n}\n\n/**\n * Scan for a null-terminated string and return its content and the index\n * of the null byte (NOT including it in the count, matching Go behaviour).\n * The parent formulas (`5 + read`, `6 + read`) already add 1 for the null.\n */\nfunction readNullString(data: Uint8Array): { str: string; read: number } {\n for (let i = 0; i < data.length; i++) {\n if (data[i] === 0) {\n return { str: new TextDecoder().decode(data.slice(0, i)), read: i };\n }\n }\n throw new Error(\"non-null-terminated issuer string\");\n}\n\n/**\n * Derive the next key given a parent key and a license block.\n * Mirrors Go's licenseBlock.deriveKey.\n */\nfunction deriveKeyFromBlock(block: LicenseBlock, parent: Uint8Array): Uint8Array<ArrayBuffer> {\n const scalarBytes = Uint8Array.from(block.hash);\n clampScalar(scalarBytes);\n\n // Use raw scalar WITHOUT reducing mod n — NaCl's ge_scalarmult_vartime\n // uses the raw 256-bit scalar. Reducing mod n changes the result when\n // the point has a small-order component (Ed25519 cofactor = 8).\n const scalar = bytesToBigIntLE(scalarBytes);\n\n const pub = ed25519.Point.fromBytes(block.key);\n const negPub = pub.negate();\n\n const par = ed25519.Point.fromBytes(parent);\n const negPar = par.negate();\n\n const res = scalarMultFull(negPub, scalar).add(negPar);\n const raw = res.toBytes();\n const final = new Uint8Array(raw.length) as Uint8Array<ArrayBuffer>;\n final.set(raw);\n final[31] = (final[31] !== undefined ? final[31] : 0) ^ 0x80;\n\n return final;\n}\n","import type { Crypt } from \"../crypto/crypt.js\";\nimport { importPublicKey } from \"../crypto/identity.js\";\nimport { verifySign, getSharedSecret2 } from \"../crypto/primitives.js\";\nimport { parseLicenses } from \"./license.js\";\n\n/**\n * CryptoInit2 performs the second stage of crypto initialization (Ed25519 ECDH).\n * Mirrors Go's handshake.CryptoInit2.\n */\nexport function cryptoInit2(\n crypt: Crypt,\n license: string,\n omega: string,\n proof: string,\n beta: string,\n privateKey: Uint8Array,\n): void {\n if (crypt.alphaTmp.length === 0) {\n throw new Error(\"alpha is not initialized\");\n }\n\n const licenseBytes = Buffer.from(license, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n const proofBytes = Buffer.from(proof, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n\n const serverPubKey = importPublicKey(omegaBytes);\n if (!verifySign(serverPubKey, licenseBytes, proofBytes)) {\n throw new Error(\"init proof is not valid\");\n }\n\n const licenses = parseLicenses(licenseBytes);\n const key = licenses.deriveKey();\n\n const sharedSecret = getSharedSecret2(key, privateKey);\n\n crypt.setSharedSecret(crypt.alphaTmp, betaBytes, sharedSecret);\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypt.d.ts","sourceRoot":"","sources":["../../src/crypto/crypt.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAW9C,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,UAAU,CAAC;IAChB,KAAK,EAAE,UAAU,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AAMD,qBAAa,KAAK;;IAChB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAE5B,QAAQ,EAAE,UAAU,CAAqB;IACzC,aAAa,EAAE,UAAU,CAAuC;IAChE,QAAQ,EAAE,UAAU,CAAqB;IACzC,kBAAkB,UAAS;
|
|
1
|
+
{"version":3,"file":"crypt.d.ts","sourceRoot":"","sources":["../../src/crypto/crypt.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAW9C,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,UAAU,CAAC;IAChB,KAAK,EAAE,UAAU,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AAMD,qBAAa,KAAK;;IAChB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAE5B,QAAQ,EAAE,UAAU,CAAqB;IACzC,aAAa,EAAE,UAAU,CAAuC;IAChE,QAAQ,EAAE,UAAU,CAAqB;IACzC,kBAAkB,UAAS;IAI3B,YAAY,QAAQ,EAAE,QAAQ,EAE7B;IAED,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,CAgB7E;IAED,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAS3D;IAED,eAAe,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,GAAG,IAAI,CAiBhF;IAED,WAAW,CACT,UAAU,EAAE,OAAO,EACnB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,OAAO,GACb,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,CAAC,CA6BtC;IAED,OAAO,CACL,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,UAAU,EACrB,KAAK,EAAE,OAAO,EACd,WAAW,EAAE,OAAO,GACnB,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,CAAC,CAW3C;IAED,OAAO,CACL,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,UAAU,EACtB,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,OAAO,EACd,WAAW,EAAE,OAAO,GACnB,UAAU,CAeZ;CAyBF"}
|
package/dist/crypto/eax.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eax.d.ts","sourceRoot":"","sources":["../../src/crypto/eax.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,qBAAa,GAAG;;
|
|
1
|
+
{"version":3,"file":"eax.d.ts","sourceRoot":"","sources":["../../src/crypto/eax.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,qBAAa,GAAG;;IAGd,YAAY,GAAG,EAAE,UAAU,EAG1B;IAED,OAAO,CACL,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,UAAU,GACpB,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,CAAC,CAc3C;IAED,OAAO,CACL,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,UAAU,EACtB,GAAG,EAAE,UAAU,GACd,UAAU,CAeZ;CAcF;AAoDD,wBAAgB,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,GAAG,UAAU,CA2BxE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/crypto/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AAOrB,qBAAa,QAAQ;IACnB,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/crypto/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AAOrB,qBAAa,QAAQ;IACnB,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IAEf,YAAY,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAGhD;IAED,eAAe,IAAI,MAAM,CAiBxB;IAED,QAAQ,IAAI,MAAM,CAQjB;IAED,aAAa,IAAI,MAAM,CAKtB;IAEK,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAc7E;CACF;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,QAAQ,CA+BtD;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,CAc9D;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG7D;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAEpD;AA+BD;mDACmD;AACnD,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,CAS3D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto-Bg02m4ZE.js","names":[],"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":";;;AAGA,IAAM,IAAe,GACf,IAAiB,IAMV,IAAb,MAAiB;CACf;CAEA,YAAY,GAAiB;EAC3B,IAAI,EAAI,WAAW,IAAI,MAAU,MAAM,4BAA4B;EACnE,KAAK,KAAO;CACd;CAEA,QACE,GACA,GACA,GAC2C;EAC3C,IAAM,IAAQ,KAAK,GAAM,GAAG,CAAK,GAC3B,IAAQ,KAAK,GAAM,GAAG,CAAM,GAE5B,IAAa,EAAO,KAAK,IAAM,GAAO,CAAS,GAE/C,IAAQ,KAAK,GAAM,GAAG,CAAU,GAEhC,IAAM,IAAI,WAAW,CAAY;EACvC,KAAK,IAAI,IAAI,GAAG,IAAI,GAAc,KAChC,EAAI,KAAK,EAAM,KAAM,EAAM,KAAM,EAAM;EAGzC,OAAO,CAAC,GAAY,CAAG;CACzB;CAEA,QACE,GACA,GACA,GACA,GACY;EACZ,IAAM,IAAQ,KAAK,GAAM,GAAG,CAAK,GAC3B,IAAQ,KAAK,GAAM,GAAG,CAAM,GAC5B,IAAQ,KAAK,GAAM,GAAG,CAAU,GAEhC,IAAW,IAAI,WAAW,CAAY;EAC5C,KAAK,IAAI,IAAI,GAAG,IAAI,GAAc,KAChC,EAAS,KAAK,EAAM,KAAM,EAAM,KAAM,EAAM;EAG9C,IAAI,CAAC,EAAgB,OAAO,KAAK,CAAQ,GAAG,OAAO,KAAK,EAAI,MAAM,GAAG,CAAY,CAAC,CAAC,GACjF,MAAM,IAAI,EAAoB;EAGhC,OAAO,EAAO,KAAK,IAAM,GAAO,CAAU;CAC5C;CAMA,GAAM,GAAiB,GAA8B;EACnD,IAAM,IAAQ,IAAI,WAAW,IAAiB,EAAK,MAAM;EAKzD,OAHA,EAAM,MAAsB,GAC5B,EAAM,IAAI,GAAM,CAAc,GAEvB,EAAQ,KAAK,IAAM,CAAK;CACjC;AACF;AAIA,SAAS,EAAO,GAAiB,GAAgB,GAA8B;CAC7E,IAAM,IAAS,EAAe,eAAe,OAAO,KAAK,CAAG,GAAG,OAAO,KAAK,CAAE,CAAC;CAC9E,OAAO,OAAO,OAAO,CAAC,EAAO,OAAO,OAAO,KAAK,CAAI,CAAC,GAAG,EAAO,MAAM,CAAC,CAAC;AACzE;AAIA,SAAS,EAAO,GAAiB,GAA+B;CAG9D,IAAM,IAAS,EAAe,eAAe,OAAO,KAAK,CAAG,GAAG,IAAI;CAEnE,OADA,EAAO,eAAe,EAAK,GACpB,OAAO,OAAO,CAAC,EAAO,OAAO,OAAO,KAAK,CAAK,CAAC,GAAG,EAAO,MAAM,CAAC,CAAC;AAC1E;AAEA,SAAS,EAAS,GAAe,GAA2B;CAC1D,IAAM,IAAM,IAAI,WAAW,CAAc;CACzC,KAAK,IAAI,IAAI,GAAG,IAAI,GAAgB,KAAK,EAAI,KAAK,EAAE,KAAM,EAAE;CAC5D,OAAO;AACT;AAEA,SAAS,EAAW,GAA2B;CAC7C,IAAM,IAAM,IAAI,WAAW,CAAc,GACrC,IAAQ;CACZ,KAAK,IAAI,IAAI,IAAoB,KAAK,GAAG,KAAK;EAC5C,IAAM,KAAY,EAAE,MAAO,IAAK,KAAS;EAEzC,AADA,IAAQ,EAAE,MAAO,GACjB,EAAI,KAAK;CACX;CACA,OAAO;AACT;AAEA,IAAM,IAAK,IAAI,WAAW,CAAc;AACxC,EAAG,MAAsB;AAEzB,SAAS,EAAgB,GAA2C;CAElE,IAAM,IAAI,EAAO,GAAK,IADL,WAAW,CACN,CAAI,GAEtB,IAAK,EAAW,CAAC;CACrB,AAAK,EAAE,KAAM,QAAa,IAAK,EAAS,GAAI,CAAE;CAE9C,IAAI,IAAK,EAAW,CAAE;CAGtB,OAFK,EAAG,KAAM,QAAa,IAAK,EAAS,GAAI,CAAE,IAExC,CAAC,GAAI,CAAE;AAChB;AAEA,SAAgB,EAAQ,GAAiB,GAAiC;CACxE,IAAM,CAAC,GAAI,KAAM,EAAgB,CAAG,GAE9B,IAAI,KAAK,IAAI,GAAG,KAAK,KAAK,EAAQ,SAAS,CAAc,CAAC,GAC1D,IAAoB,EAAQ,SAAS,KAAK,EAAQ,SAAS,MAAmB,GAEhF,IAAgB,IAAI,WAAW,CAAc;CAEjD,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,GAAG,KAAK;EAC9B,IAAM,IAAQ,EAAQ,MAAM,IAAI,IAAiB,IAAI,KAAK,CAAc;EACxE,IAAI,WAAW,KAAK,EAAO,GAAK,EAAS,GAAG,CAAK,CAAC,CAAC;CACrD;CAEA,IAAM,IAAY,IAAI,WAAW,CAAc,GACzC,KAAa,IAAI,KAAK,GACtB,IAAY,EAAQ,MAAM,CAAS;CACzC,EAAU,IAAI,CAAS;CAEvB,IAAI;CAQJ,OAPI,IACF,IAAK,EAAS,GAAW,CAAE,KAEvB,EAAU,SAAS,MAAgB,EAAU,EAAU,UAAU,MACrE,IAAK,EAAS,GAAW,CAAE,IAGtB,WAAW,KAAK,EAAO,GAAK,EAAS,GAAG,CAAE,CAAC,CAAC;AACrD;;;ACjJA,IAAM,IAAsB,GACtB,IAAgB,IAChB,IAAoB,GACpB,IAAmB,IAEnB,IAAY,OAAO,KAAK,UAAU,GASlC,IAAY,OAAO,KAAK,oBAAoB,GAC5C,IAAc,OAAO,KAAK,mBAAmB,GAEtC,IAAb,MAAmB;CACjB;CAEA,2BAAuB,IAAI,WAAY;CACvC,gBAA4B,IAAI,WAAW,CAAmB;CAC9D,2BAAuB,IAAI,WAAY;CACvC,qBAAqB;CAErB,qBAAuB,IAAI,IAAsB;CAEjD,YAAY,GAAoB;EAC9B,KAAK,WAAW;CAClB;CAEA,kBAAkB,GAAkB,GAAgB,GAA2B;EAC7E,IAAI,IAAQ,KAAK,IAAQ,KACvB,MAAU,MAAM,kCAAkC;EAGpD,IAAM,IAAS,EAAK,MAAM,GAAQ,IAAS,EAAE,GACvC,IAAS,EAAK,MAAM,IAAS,IAAI,IAAS,GAAG,GAE/C,IAAI,EAAc,CAAM,GACtB,IAAI,EAAc,CAAM;EAE9B,KAAK,IAAI,IAAI,GAAG,IAAI,GAAO,KACzB,IAAK,IAAI,IAAK;EAGhB,OAAO,EAAc,GAAG,EAAE;CAC5B;CAEA,WAAW,GAAe,GAAc,GAAqB;EAC3D,IAAM,IAAa,OAAO,KAAK,GAAO,QAAQ,GACxC,IAAY,OAAO,KAAK,GAAM,QAAQ,GACtC,IAAa,OAAO,KAAK,GAAO,QAAQ,GAExC,IAAe,EAAgB,CAAU,GACzC,IAAe,KAAK,GAAiB,CAAY;EAEvD,KAAK,gBAAgB,GAAY,GAAW,CAAY;CAC1D;CAEA,gBAAgB,GAAmB,GAAkB,GAA6B;EAChF,KAAK,WAAW,IAAI,WAAW,IAAgB,EAAK,MAAM;EAC1D,KAAK,IAAI,IAAI,GAAG,IAAI,GAAe,KAAK;GACtC,IAAM,IAAI,EAAU,IACd,IAAI,EAAM;GAChB,KAAK,SAAS,OAAO,MAAM,KAAA,IAAgB,IAAJ,MAAU,MAAM,KAAA,IAAgB,IAAJ,MAAU;EAC/E;EACA,KAAK,IAAI,IAAI,GAAG,IAAI,EAAK,QAAQ,KAAK;GACpC,IAAM,IAAI,EAAU,IAAgB,IAC9B,IAAI,EAAK;GACf,KAAK,SAAS,IAAgB,OAC1B,MAAM,KAAA,IAAgB,IAAJ,MAAU,MAAM,KAAA,IAAgB,IAAJ,MAAU;EAC9D;EAEA,IAAM,IAAS,EAAW,MAAM,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,OAAO;EAE/D,AADA,KAAK,gBAAgB,IAAI,WAAW,EAAO,QAAQ,EAAO,YAAY,CAAmB,GACzF,KAAK,qBAAqB;CAC5B;CAEA,YACE,GACA,GACA,GACA,GACA,GACsC;EACtC,IAAI,GACF,OAAO,CAAC,WAAW,KAAK,CAAS,GAAG,WAAW,KAAK,CAAW,CAAC;EAGlE,IAAM,IAAW,EAAa,GAAY,GAAY,CAAY,GAC9D,IAAK,KAAK,GAAY,IAAI,CAAQ;EAEtC,IAAI,MAAO,KAAA,GAAW;GACpB,IAAM,IAAY,IAAI,WAAW,IAAI,KAAK,SAAS,MAAM;GAIzD,AAHA,EAAU,KAAK,IAAa,KAAO,IACnC,EAAU,KAAK,IAAa,GAC5B,IAAI,SAAS,EAAU,MAAM,CAAC,CAAC,UAAU,GAAG,GAAc,EAAK,GAC/D,EAAU,IAAI,KAAK,UAAU,CAAC;GAE9B,IAAM,IAAO,EAAW,QAAQ,CAAC,CAAC,OAAO,CAAS,CAAC,CAAC,OAAO;GAM3D,AALA,IAAK;IACH,KAAK,WAAW,KAAK,EAAK,MAAM,GAAG,EAAE,CAAC;IACtC,OAAO,WAAW,KAAK,EAAK,MAAM,IAAI,EAAE,CAAC;IACzC,KAAK;GACP,GACA,KAAK,GAAY,IAAI,GAAU,CAAE;EACnC;EAEA,IAAM,IAAM,WAAW,KAAK,EAAG,GAAG;EAIlC,OAHA,EAAI,MAAM,EAAI,OAAO,KAAA,IAAqB,IAAT,EAAI,MAAY,KAAY,IAAK,KAClE,EAAI,MAAM,EAAI,OAAO,KAAA,IAAqB,IAAT,EAAI,MAAW,IAAW,KAEpD,CAAC,GAAK,EAAG,KAAK;CACvB;CAEA,QACE,GACA,GACA,GACA,GACA,GACA,GACA,GAC2C;EAC3C,IAAI,MAAe,GACjB,OAAO,CAAC,GAAW,CAAS;EAE9B,IAAI,GACF,OAAO,CAAC,GAAW,KAAK,aAAa;EAGvC,IAAM,CAAC,GAAK,KAAS,KAAK,YAAY,IAAO,GAAU,GAAc,GAAY,CAAK;EAEtF,OAAO,IADS,EAAI,CACb,CAAA,CAAI,QAAQ,GAAO,GAAQ,CAAS;CAC7C;CAEA,QACE,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACY;EACZ,IAAI,MAAe,GACjB,OAAO;EAET,IAAI,GAAa;GACf,IAAM,IAAQ,EAAI,MAAM,GAAG,CAAmB;GAC9C,IAAI,CAAC,OAAO,KAAK,CAAK,CAAC,CAAC,OAAO,OAAO,KAAK,KAAK,aAAa,CAAC,GAC5D,MAAM,IAAI,EAA2B;GAEvC,OAAO;EACT;EAEA,IAAM,CAAC,GAAK,KAAS,KAAK,YAAY,IAAM,GAAU,GAAc,GAAY,CAAK;EAErF,OAAO,IADS,EAAI,CACb,CAAA,CAAI,QAAQ,GAAO,GAAQ,GAAY,CAAG;CACnD;CAEA,GAAiB,GAA2D;EAC1E,IAAM,IAAU,KAAK,SAAS,WAAW,OAAO,EAAE,QAAQ,MAAM,CAAC,GAG3D,IAAS,EAAa,OAAO,EAAE,QAAQ,MAAM,CAAC,GAK9C,IAAO,EAAW,YAAY,GAC9B,IAAS,OAAO,KAAK,EAAQ,GAAG,WAAW;EACjD,EAAK,cAAc,CAAM;EAEzB,IAAM,IAAS,EAAiB,EAAO,GAAG,EAAE,GACtC,IAAS,EAAiB,EAAO,GAAG,EAAE,GACtC,IAAe,OAAO,MAAM,EAAE;EAGpC,AAFA,EAAa,KAAK,GAClB,EAAO,KAAK,GAAc,CAAC,GAC3B,EAAO,KAAK,GAAc,EAAE;EAE5B,IAAM,IAAY,EAAK,cAAc,CAAY;EACjD,OAAO,EAAW,MAAM,CAAC,CAAC,OAAO,CAAS,CAAC,CAAC,OAAO;CACrD;AACF;AAIA,SAAS,EAAa,GAAqB,GAAoB,GAA8B;CAC3F,IAAI,IAAM;CAIV,OAHI,MAAY,KAAO,MAAM,MAC7B,KAAO,OAAO,IAAa,CAAgB,KAAK,KAChD,KAAO,OAAO,CAAY,GACnB;AACT;AAEA,SAAS,EAAc,GAA2B;CAChD,IAAI,IAAS;CACb,KAAK,IAAM,KAAK,GAAO,IAAU,KAAU,KAAM,OAAO,CAAC;CACzD,OAAO;AACT;AAEA,SAAS,EAAc,GAAe,GAA0B;CAC9D,IAAM,IAAS,IAAI,WAAW,CAAI,GAC9B,IAAI;CACR,KAAK,IAAI,IAAI,IAAO,GAAG,KAAK,GAAG,KAE7B,AADA,EAAO,KAAK,OAAO,IAAI,IAAK,GAC5B,MAAM;CAER,OAAO;AACT;AAEA,SAAS,EAAiB,GAAgB,GAAsB;CAC9D,IAAM,IAAM,OAAO,KAAK,GAAQ,WAAW;CAC3C,IAAI,EAAI,WAAW,GAAM,OAAO;CAChC,IAAM,IAAS,OAAO,MAAM,CAAI;CAEhC,OADA,EAAI,KAAK,GAAQ,IAAO,EAAI,MAAM,GAC3B;AACT"}
|
|
1
|
+
{"version":3,"file":"crypto-Bg02m4ZE.js","names":["importPublicKey","EAXTagMismatchError","FakeSignatureMismatchError","EAX_TAG_SIZE","EAX_BLOCK_SIZE","EAX","key","#key","nStar","#cmac","nonce","hStar","header","ciphertext","aesCtr","plaintext","cStar","tag","i","expected","timingSafeEqual","input","data","tagByte","aesCmac","cipher","createCipheriv","iv","aesEcb","block","xorBlock","out","a","b","shiftLeft1","carry","shifted","RB","generateSubkeys","L","K1","K2","n","message","lastBlockComplete","X","lastBlock","lastStart","lastSlice","Mn","FAKE_SIGNATURE_SIZE","IV_ALPHA_SIZE","INIT1_PACKET_TYPE","PACKET_TYPE_MASK","INIT1_MAC","DUMMY_KEY","DUMMY_NONCE","Crypt","identity","level","xBytes","offset","nBytes","y","bytesToBigInt","bigIntToBytes","alphaBytes","alpha","betaBytes","beta","omegaBytes","omega","serverPubKey","sharedSecret","#getSharedSecret","sharedKey","digest","createHash","dummy","cacheKey","makeCacheKey","fromServer","packetType","generationID","kn","#cachedKeys","tmpToHash","hash","packetID","unencrypted","fsSub","privJwk","pubJwk","ecdh","createECDH","dBytes","base64UrlToBytes","yBytes","uncompressed","rawSecret","result","bytes","size","v","value","buf","b64url","padded"],"sources":["../src/crypto/eax.ts","../src/crypto/crypt.ts"],"sourcesContent":["import { createCipheriv, timingSafeEqual } from \"node:crypto\";\nimport { EAXTagMismatchError } from \"../errors.js\";\n\nconst EAX_TAG_SIZE = 8;\nconst EAX_BLOCK_SIZE = 16;\n\n/**\n * AES-EAX AEAD implementation for TS3 (64-bit tag, AES-128).\n * Uses AES-CMAC for authentication and AES-CTR for encryption.\n */\nexport class EAX {\n readonly #key: Uint8Array;\n\n constructor(key: Uint8Array) {\n if (key.length !== 16) throw new Error(\"EAX requires a 16-byte key\");\n this.#key = key;\n }\n\n encrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n plaintext: Uint8Array,\n ): [ciphertext: Uint8Array, tag: Uint8Array] {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n\n const ciphertext = aesCtr(this.#key, nStar, plaintext);\n\n const cStar = this.#cmac(2, ciphertext);\n\n const tag = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n tag[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n return [ciphertext, tag];\n }\n\n decrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n ): Uint8Array {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n const cStar = this.#cmac(2, ciphertext);\n\n const expected = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n expected[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n if (!timingSafeEqual(Buffer.from(expected), Buffer.from(tag.slice(0, EAX_TAG_SIZE)))) {\n throw new EAXTagMismatchError();\n }\n\n return aesCtr(this.#key, nStar, ciphertext);\n }\n\n /**\n * AES-CMAC per RFC 4493:\n * input = [0…0 tag] ++ data (one block prefix)\n */\n #cmac(tagByte: number, data: Uint8Array): Uint8Array {\n const input = new Uint8Array(EAX_BLOCK_SIZE + data.length);\n // first block: zeros then tag byte at the last position\n input[EAX_BLOCK_SIZE - 1] = tagByte;\n input.set(data, EAX_BLOCK_SIZE);\n\n return aesCmac(this.#key, input);\n }\n}\n\n// ---- AES-CTR ----------------------------------------------------------------\n\nfunction aesCtr(key: Uint8Array, iv: Uint8Array, data: Uint8Array): Uint8Array {\n const cipher = createCipheriv(\"aes-128-ctr\", Buffer.from(key), Buffer.from(iv));\n return Buffer.concat([cipher.update(Buffer.from(data)), cipher.final()]);\n}\n\n// ---- AES-CMAC (RFC 4493) ----------------------------------------------------\n\nfunction aesEcb(key: Uint8Array, block: Uint8Array): Uint8Array {\n // Node.js does not expose ECB directly; simulate via CTR with zero IV and\n // a zero-input (CTR of 0-block XOR with input = ECB)\n const cipher = createCipheriv(\"aes-128-ecb\", Buffer.from(key), null);\n cipher.setAutoPadding(false);\n return Buffer.concat([cipher.update(Buffer.from(block)), cipher.final()]);\n}\n\nfunction xorBlock(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n for (let i = 0; i < EAX_BLOCK_SIZE; i++) out[i] = a[i]! ^ b[i]!;\n return out;\n}\n\nfunction shiftLeft1(b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n let carry = 0;\n for (let i = EAX_BLOCK_SIZE - 1; i >= 0; i--) {\n const shifted = ((b[i]! << 1) | carry) & 0xff;\n carry = b[i]! >> 7;\n out[i] = shifted;\n }\n return out;\n}\n\nconst RB = new Uint8Array(EAX_BLOCK_SIZE);\nRB[EAX_BLOCK_SIZE - 1] = 0x87;\n\nfunction generateSubkeys(key: Uint8Array): [Uint8Array, Uint8Array] {\n const zero = new Uint8Array(EAX_BLOCK_SIZE);\n const L = aesEcb(key, zero);\n\n let K1 = shiftLeft1(L);\n if ((L[0]! & 0x80) !== 0) K1 = xorBlock(K1, RB);\n\n let K2 = shiftLeft1(K1);\n if ((K1[0]! & 0x80) !== 0) K2 = xorBlock(K2, RB);\n\n return [K1, K2];\n}\n\nexport function aesCmac(key: Uint8Array, message: Uint8Array): Uint8Array {\n const [K1, K2] = generateSubkeys(key);\n\n const n = Math.max(1, Math.ceil(message.length / EAX_BLOCK_SIZE));\n const lastBlockComplete = message.length > 0 && message.length % EAX_BLOCK_SIZE === 0;\n\n let X: Uint8Array = new Uint8Array(EAX_BLOCK_SIZE);\n\n for (let i = 0; i < n - 1; i++) {\n const block = message.slice(i * EAX_BLOCK_SIZE, (i + 1) * EAX_BLOCK_SIZE);\n X = Uint8Array.from(aesEcb(key, xorBlock(X, block)));\n }\n\n const lastBlock = new Uint8Array(EAX_BLOCK_SIZE);\n const lastStart = (n - 1) * EAX_BLOCK_SIZE;\n const lastSlice = message.slice(lastStart);\n lastBlock.set(lastSlice);\n\n let Mn: Uint8Array;\n if (lastBlockComplete) {\n Mn = xorBlock(lastBlock, K1);\n } else {\n if (lastSlice.length < EAX_BLOCK_SIZE) lastBlock[lastSlice.length] = 0x80;\n Mn = xorBlock(lastBlock, K2);\n }\n\n return Uint8Array.from(aesEcb(key, xorBlock(X, Mn)));\n}\n","import { createHash, createECDH } from \"node:crypto\";\nimport { FakeSignatureMismatchError } from \"../errors.js\";\nimport type { Identity } from \"./identity.js\";\nimport { importPublicKey } from \"./identity.js\";\nimport { EAX } from \"./eax.js\";\n\nconst FAKE_SIGNATURE_SIZE = 8;\nconst IV_ALPHA_SIZE = 10;\nconst INIT1_PACKET_TYPE = 8;\nconst PACKET_TYPE_MASK = 0x0f;\n\nconst INIT1_MAC = Buffer.from(\"TS3INIT1\");\n\nexport interface KeyNonce {\n key: Uint8Array;\n nonce: Uint8Array;\n gen: number;\n}\n\n/** Precomputed dummy key/nonce matching the TS3 client pre-crypto placeholder. */\nconst DUMMY_KEY = Buffer.from(\"c:\\\\windows\\\\syste\");\nconst DUMMY_NONCE = Buffer.from(\"m\\\\firewall32.cpl\");\n\nexport class Crypt {\n readonly identity: Identity;\n\n ivStruct: Uint8Array = new Uint8Array(0);\n fakeSignature: Uint8Array = new Uint8Array(FAKE_SIGNATURE_SIZE);\n alphaTmp: Uint8Array = new Uint8Array(0);\n cryptoInitComplete = false;\n\n readonly #cachedKeys = new Map<bigint, KeyNonce>();\n\n constructor(identity: Identity) {\n this.identity = identity;\n }\n\n solveRsaChallenge(data: Uint8Array, offset: number, level: number): Uint8Array {\n if (level < 0 || level > 1_000_000) {\n throw new Error(\"RSA challenge level out of range\");\n }\n\n const xBytes = data.slice(offset, offset + 64);\n const nBytes = data.slice(offset + 64, offset + 128);\n\n let y = bytesToBigInt(xBytes);\n const n = bytesToBigInt(nBytes);\n\n for (let i = 0; i < level; i++) {\n y = (y * y) % n;\n }\n\n return bigIntToBytes(y, 64);\n }\n\n initCrypto(alpha: string, beta: string, omega: string): void {\n const alphaBytes = Buffer.from(alpha, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n\n const serverPubKey = importPublicKey(omegaBytes);\n const sharedSecret = this.#getSharedSecret(serverPubKey);\n\n this.setSharedSecret(alphaBytes, betaBytes, sharedSecret);\n }\n\n setSharedSecret(alpha: Uint8Array, beta: Uint8Array, sharedKey: Uint8Array): void {\n this.ivStruct = new Uint8Array(IV_ALPHA_SIZE + beta.length);\n for (let i = 0; i < IV_ALPHA_SIZE; i++) {\n const a = sharedKey[i];\n const b = alpha[i];\n this.ivStruct[i] = ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n for (let i = 0; i < beta.length; i++) {\n const a = sharedKey[IV_ALPHA_SIZE + i];\n const b = beta[i];\n this.ivStruct[IV_ALPHA_SIZE + i] =\n ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n\n const digest = createHash(\"sha1\").update(this.ivStruct).digest();\n this.fakeSignature = new Uint8Array(digest.buffer, digest.byteOffset, FAKE_SIGNATURE_SIZE);\n this.cryptoInitComplete = true;\n }\n\n getKeyNonce(\n fromServer: boolean,\n packetID: number,\n generationID: number,\n packetType: number,\n dummy: boolean,\n ): [key: Uint8Array, nonce: Uint8Array] {\n if (dummy) {\n return [Uint8Array.from(DUMMY_KEY), Uint8Array.from(DUMMY_NONCE)];\n }\n\n const cacheKey = makeCacheKey(fromServer, packetType, generationID);\n let kn = this.#cachedKeys.get(cacheKey);\n\n if (kn === undefined) {\n const tmpToHash = new Uint8Array(6 + this.ivStruct.length);\n tmpToHash[0] = fromServer ? 0x30 : 0x31;\n tmpToHash[1] = packetType & PACKET_TYPE_MASK;\n new DataView(tmpToHash.buffer).setUint32(2, generationID, false);\n tmpToHash.set(this.ivStruct, 6);\n\n const hash = createHash(\"sha256\").update(tmpToHash).digest();\n kn = {\n key: Uint8Array.from(hash.slice(0, 16)),\n nonce: Uint8Array.from(hash.slice(16, 32)),\n gen: generationID,\n };\n this.#cachedKeys.set(cacheKey, kn);\n }\n\n const key = Uint8Array.from(kn.key);\n key[0] = (key[0] !== undefined ? key[0] : 0) ^ ((packetID >> 8) & 0xff);\n key[1] = (key[1] !== undefined ? key[1] : 0) ^ (packetID & 0xff);\n\n return [key, kn.nonce];\n }\n\n encrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n plaintext: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): [ciphertext: Uint8Array, mac: Uint8Array] {\n if (packetType === INIT1_PACKET_TYPE) {\n return [plaintext, INIT1_MAC];\n }\n if (unencrypted) {\n return [plaintext, this.fakeSignature];\n }\n\n const [key, nonce] = this.getKeyNonce(false, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.encrypt(nonce, header, plaintext);\n }\n\n decrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): Uint8Array {\n if (packetType === INIT1_PACKET_TYPE) {\n return ciphertext;\n }\n if (unencrypted) {\n const fsSub = tag.slice(0, FAKE_SIGNATURE_SIZE);\n if (!Buffer.from(fsSub).equals(Buffer.from(this.fakeSignature))) {\n throw new FakeSignatureMismatchError();\n }\n return ciphertext;\n }\n\n const [key, nonce] = this.getKeyNonce(true, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.decrypt(nonce, header, ciphertext, tag);\n }\n\n #getSharedSecret(serverPubKey: import(\"node:crypto\").KeyObject): Uint8Array {\n const privJwk = this.identity.privateKey.export({ format: \"jwk\" }) as {\n d: string;\n };\n const pubJwk = serverPubKey.export({ format: \"jwk\" }) as {\n x: string;\n y: string;\n };\n\n const ecdh = createECDH(\"prime256v1\");\n const dBytes = Buffer.from(privJwk.d, \"base64url\");\n ecdh.setPrivateKey(dBytes);\n\n const xBytes = base64UrlToBytes(pubJwk.x, 32);\n const yBytes = base64UrlToBytes(pubJwk.y, 32);\n const uncompressed = Buffer.alloc(65);\n uncompressed[0] = 0x04;\n xBytes.copy(uncompressed, 1);\n yBytes.copy(uncompressed, 33);\n\n const rawSecret = ecdh.computeSecret(uncompressed);\n return createHash(\"sha1\").update(rawSecret).digest();\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\nfunction makeCacheKey(fromServer: boolean, packetType: number, generationID: number): bigint {\n let key = 0n;\n if (fromServer) key |= 1n << 40n;\n key |= BigInt(packetType & PACKET_TYPE_MASK) << 32n;\n key |= BigInt(generationID);\n return key;\n}\n\nfunction bytesToBigInt(bytes: Uint8Array): bigint {\n let result = 0n;\n for (const b of bytes) result = (result << 8n) | BigInt(b);\n return result;\n}\n\nfunction bigIntToBytes(value: bigint, size: number): Uint8Array {\n const result = new Uint8Array(size);\n let v = value;\n for (let i = size - 1; i >= 0; i--) {\n result[i] = Number(v & 0xffn);\n v >>= 8n;\n }\n return result;\n}\n\nfunction base64UrlToBytes(b64url: string, size: number): Buffer {\n const buf = Buffer.from(b64url, \"base64url\");\n if (buf.length === size) return buf;\n const padded = Buffer.alloc(size);\n buf.copy(padded, size - buf.length);\n return padded;\n}\n"],"mappings":"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"}
|