@honeybbq/teamspeak-client 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +208 -0
- package/dist/api.d.ts +17 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/client.d.ts +39 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/command/command.d.ts +12 -0
- package/dist/command/command.d.ts.map +1 -0
- package/dist/command/command.test.d.ts +2 -0
- package/dist/command/command.test.d.ts.map +1 -0
- package/dist/command/index.cjs +1 -0
- package/dist/command/index.d.ts +4 -0
- package/dist/command/index.d.ts.map +1 -0
- package/dist/command/index.mjs +3 -0
- package/dist/command/parser.d.ts +3 -0
- package/dist/command/parser.d.ts.map +1 -0
- package/dist/command-Cu2v-5-K.cjs +4 -0
- package/dist/command-Cu2v-5-K.cjs.map +1 -0
- package/dist/command-caXc4h0n.js +76 -0
- package/dist/command-caXc4h0n.js.map +1 -0
- package/dist/commands.d.ts +48 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/crypt-handshake-CHmvZ2qs.js +55 -0
- package/dist/crypt-handshake-CHmvZ2qs.js.map +1 -0
- package/dist/crypt-handshake-Dbj2cSBZ.cjs +2 -0
- package/dist/crypt-handshake-Dbj2cSBZ.cjs.map +1 -0
- package/dist/crypt-init2-BIbQ7TN0.cjs +2 -0
- package/dist/crypt-init2-BIbQ7TN0.cjs.map +1 -0
- package/dist/crypt-init2-C63eypta.js +165 -0
- package/dist/crypt-init2-C63eypta.js.map +1 -0
- package/dist/crypto/crypt-ops.d.ts +7 -0
- package/dist/crypto/crypt-ops.d.ts.map +1 -0
- package/dist/crypto/crypt.d.ts +22 -0
- package/dist/crypto/crypt.d.ts.map +1 -0
- package/dist/crypto/eax.d.ts +12 -0
- package/dist/crypto/eax.d.ts.map +1 -0
- package/dist/crypto/eax.test.d.ts +2 -0
- package/dist/crypto/eax.test.d.ts.map +1 -0
- package/dist/crypto/identity.d.ts +18 -0
- package/dist/crypto/identity.d.ts.map +1 -0
- package/dist/crypto/identity.test.d.ts +2 -0
- package/dist/crypto/identity.test.d.ts.map +1 -0
- package/dist/crypto/index.cjs +1 -0
- package/dist/crypto/index.d.ts +6 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.mjs +3 -0
- package/dist/crypto/primitives.d.ts +28 -0
- package/dist/crypto/primitives.d.ts.map +1 -0
- package/dist/crypto-C3gBJkh2.cjs +2 -0
- package/dist/crypto-C3gBJkh2.cjs.map +1 -0
- package/dist/crypto-IGJlkTAl.js +165 -0
- package/dist/crypto-IGJlkTAl.js.map +1 -0
- package/dist/discovery/index.cjs +1 -0
- package/dist/discovery/index.d.ts +2 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.mjs +2 -0
- package/dist/discovery/resolver.d.ts +8 -0
- package/dist/discovery/resolver.d.ts.map +1 -0
- package/dist/errors.d.ts +34 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/events.d.ts +10 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/handler-C2vxlHYC.js +458 -0
- package/dist/handler-C2vxlHYC.js.map +1 -0
- package/dist/handler-DQteUMKT.cjs +2 -0
- package/dist/handler-DQteUMKT.cjs.map +1 -0
- package/dist/handshake/crypt-handshake.d.ts +8 -0
- package/dist/handshake/crypt-handshake.d.ts.map +1 -0
- package/dist/handshake/crypt-init2.d.ts +7 -0
- package/dist/handshake/crypt-init2.d.ts.map +1 -0
- package/dist/handshake/index.cjs +1 -0
- package/dist/handshake/index.d.ts +4 -0
- package/dist/handshake/index.d.ts.map +1 -0
- package/dist/handshake/index.mjs +3 -0
- package/dist/handshake/license.d.ts +28 -0
- package/dist/handshake/license.d.ts.map +1 -0
- package/dist/handshake.d.ts +9 -0
- package/dist/handshake.d.ts.map +1 -0
- package/dist/helpers.d.ts +14 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.test.d.ts +2 -0
- package/dist/helpers.test.d.ts.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +761 -0
- package/dist/index.mjs.map +1 -0
- package/dist/integration.test.d.ts +12 -0
- package/dist/integration.test.d.ts.map +1 -0
- package/dist/notifications.d.ts +32 -0
- package/dist/notifications.d.ts.map +1 -0
- package/dist/notifications.test.d.ts +2 -0
- package/dist/notifications.test.d.ts.map +1 -0
- package/dist/parser-CJjP3LlO.js +33 -0
- package/dist/parser-CJjP3LlO.js.map +1 -0
- package/dist/parser-DhAWj-TI.cjs +2 -0
- package/dist/parser-DhAWj-TI.cjs.map +1 -0
- package/dist/primitives-BxtDMP7x.cjs +2 -0
- package/dist/primitives-BxtDMP7x.cjs.map +1 -0
- package/dist/primitives-CmIK1O7L.js +1836 -0
- package/dist/primitives-CmIK1O7L.js.map +1 -0
- package/dist/resolver-DDZWomrF.js +165 -0
- package/dist/resolver-DDZWomrF.js.map +1 -0
- package/dist/resolver-Dey6omBe.cjs +4 -0
- package/dist/resolver-Dey6omBe.cjs.map +1 -0
- package/dist/throttle.d.ts +11 -0
- package/dist/throttle.d.ts.map +1 -0
- package/dist/throttle.test.d.ts +2 -0
- package/dist/throttle.test.d.ts.map +1 -0
- package/dist/transfer.d.ts +34 -0
- package/dist/transfer.d.ts.map +1 -0
- package/dist/transport/generation-window.d.ts +15 -0
- package/dist/transport/generation-window.d.ts.map +1 -0
- package/dist/transport/generation-window.test.d.ts +2 -0
- package/dist/transport/generation-window.test.d.ts.map +1 -0
- package/dist/transport/handler.d.ts +18 -0
- package/dist/transport/handler.d.ts.map +1 -0
- package/dist/transport/index.cjs +1 -0
- package/dist/transport/index.d.ts +6 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.mjs +2 -0
- package/dist/transport/packet.d.ts +36 -0
- package/dist/transport/packet.d.ts.map +1 -0
- package/dist/transport/packet.test.d.ts +2 -0
- package/dist/transport/packet.test.d.ts.map +1 -0
- package/dist/transport/quicklz.d.ts +5 -0
- package/dist/transport/quicklz.d.ts.map +1 -0
- package/dist/transport/quicklz.test.d.ts +2 -0
- package/dist/transport/quicklz.test.d.ts.map +1 -0
- package/dist/types-CGKgXvpG.js +18 -0
- package/dist/types-CGKgXvpG.js.map +1 -0
- package/dist/types-DrnoCdSW.cjs +2 -0
- package/dist/types-DrnoCdSW.cjs.map +1 -0
- package/dist/types.d.ts +114 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +87 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 BBQ
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# @honeybbq/teamspeak-client
|
|
4
|
+
|
|
5
|
+
**A clean-room TeamSpeak client protocol library written in pure TypeScript.**
|
|
6
|
+
|
|
7
|
+
Compatible with TeamSpeak 3, 5 & 6. No proprietary SDK. No copy-pasted code.
|
|
8
|
+
|
|
9
|
+
[](https://github.com/honeybbq/teamspeak-js/actions/workflows/ci.yml)
|
|
10
|
+
[](https://www.npmjs.com/package/@honeybbq/teamspeak-client)
|
|
11
|
+
[](package.json)
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **Full protocol handshake** — ECDH key exchange, RSA puzzle, EAX-encrypted transport
|
|
19
|
+
- **Command & notification system** — Send commands, receive server events
|
|
20
|
+
- **Event-driven API** — Register handlers for text messages, client enter/leave, channel moves, kicks, etc.
|
|
21
|
+
- **Voice data** — Send Opus voice packets (codec 4 & 5)
|
|
22
|
+
- **File transfers** — Upload, download, and delete files on the server
|
|
23
|
+
- **Address resolution** — SRV records, TSDNS, and direct address support
|
|
24
|
+
- **Middleware** — Pluggable command and event middleware chains
|
|
25
|
+
- **Built-in rate limiter** — Token-bucket throttling to prevent server-side flood kicks
|
|
26
|
+
- **Identity management** — Generate, import/export, and upgrade security level of identities
|
|
27
|
+
- **Dual format** — Ships ESM and CJS with full TypeScript declarations
|
|
28
|
+
- **Zero native deps** — Pure TypeScript, no native addons required
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install @honeybbq/teamspeak-client
|
|
34
|
+
# or
|
|
35
|
+
pnpm add @honeybbq/teamspeak-client
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Requires **Node.js 20.19** or later.
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { Client, generateIdentity } from "@honeybbq/teamspeak-client";
|
|
44
|
+
|
|
45
|
+
// Generate a new identity (or load an existing one)
|
|
46
|
+
const identity = generateIdentity(8);
|
|
47
|
+
|
|
48
|
+
// Create the client
|
|
49
|
+
const client = new Client(identity, "localhost", "TSBot");
|
|
50
|
+
|
|
51
|
+
// Register event handlers
|
|
52
|
+
client.on("connected", () => {
|
|
53
|
+
console.log("Connected to server!");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
client.on("textMessage", (msg) => {
|
|
57
|
+
console.log(`[${msg.invokerName}]: ${msg.message}`);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
client.on("disconnected", (err) => {
|
|
61
|
+
console.log("Disconnected:", err?.message ?? "clean");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Connect
|
|
65
|
+
await client.connect();
|
|
66
|
+
|
|
67
|
+
// Wait until connected (with 15s timeout)
|
|
68
|
+
await client.waitConnected(AbortSignal.timeout(15_000));
|
|
69
|
+
|
|
70
|
+
// Stay connected until interrupted
|
|
71
|
+
process.on("SIGINT", async () => {
|
|
72
|
+
await client.disconnect();
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## API Overview
|
|
77
|
+
|
|
78
|
+
### Client Lifecycle
|
|
79
|
+
|
|
80
|
+
| Method | Description |
|
|
81
|
+
| --------------------------------------------- | ----------------------------------- |
|
|
82
|
+
| `new Client(identity, addr, nickname, opts?)` | Create a new client |
|
|
83
|
+
| `connect()` | Initiate connection to the server |
|
|
84
|
+
| `waitConnected(signal?)` | Block until the handshake completes |
|
|
85
|
+
| `disconnect()` | Gracefully disconnect |
|
|
86
|
+
|
|
87
|
+
### Events
|
|
88
|
+
|
|
89
|
+
| Method | Description |
|
|
90
|
+
| ----------------------------- | ---------------------------------- |
|
|
91
|
+
| `on("connected", handler)` | Fires when fully connected |
|
|
92
|
+
| `on("disconnected", handler)` | Fires on disconnect |
|
|
93
|
+
| `on("textMessage", handler)` | Fires on text messages |
|
|
94
|
+
| `on("clientEnter", handler)` | Fires when a client joins |
|
|
95
|
+
| `on("clientLeave", handler)` | Fires when a client leaves |
|
|
96
|
+
| `on("clientMoved", handler)` | Fires when a client moves channels |
|
|
97
|
+
| `on("kicked", handler)` | Fires when the bot is kicked |
|
|
98
|
+
| `on("poke", handler)` | Fires when poked by a client |
|
|
99
|
+
| `on("voice", handler)` | Fires on incoming voice data |
|
|
100
|
+
|
|
101
|
+
### Commands
|
|
102
|
+
|
|
103
|
+
| Function | Description |
|
|
104
|
+
| ---------------------------------------------------- | ------------------------------------------ |
|
|
105
|
+
| `sendTextMessage(client, targetMode, targetID, msg)` | Send a text message |
|
|
106
|
+
| `clientMove(client, clid, channelID, password?)` | Move a client to a channel |
|
|
107
|
+
| `poke(client, clid, message)` | Poke a client |
|
|
108
|
+
| `client.sendVoice(data, codec)` | Send Opus voice data |
|
|
109
|
+
| `listChannels(client)` | List all channels |
|
|
110
|
+
| `listClients(client)` | List all connected clients |
|
|
111
|
+
| `getClientInfo(client, clid)` | Get detailed client information |
|
|
112
|
+
| `client.execCommand(cmd, timeout?)` | Execute a raw command |
|
|
113
|
+
| `client.execCommandWithResponse(cmd, timeout?)` | Execute a command and return response data |
|
|
114
|
+
|
|
115
|
+
### File Transfers
|
|
116
|
+
|
|
117
|
+
| Function | Description |
|
|
118
|
+
| -------------------------------------- | --------------------------------- |
|
|
119
|
+
| `client.fileTransferInitUpload(...)` | Initialize a file upload |
|
|
120
|
+
| `client.fileTransferInitDownload(...)` | Initialize a file download |
|
|
121
|
+
| `fileTransferDeleteFile(client, ...)` | Delete files on the server |
|
|
122
|
+
| `uploadFileData(host, info, reader)` | Transfer file data to the server |
|
|
123
|
+
| `downloadFileData(host, info, writer)` | Receive file data from the server |
|
|
124
|
+
|
|
125
|
+
### Identity
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { generateIdentity, identityFromString } from "@honeybbq/teamspeak-client";
|
|
129
|
+
|
|
130
|
+
// Generate a new identity with security level 8
|
|
131
|
+
const identity = generateIdentity(8);
|
|
132
|
+
|
|
133
|
+
// Export to string for persistent storage
|
|
134
|
+
const exported = identity.exportString();
|
|
135
|
+
|
|
136
|
+
// Import from a previously exported string
|
|
137
|
+
const restored = identityFromString(exported);
|
|
138
|
+
|
|
139
|
+
// Upgrade security level (CPU-intensive)
|
|
140
|
+
identity.upgradeToLevel(10);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Options
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
const client = new Client(identity, "ts.example.com", "Bot", {
|
|
147
|
+
logger: consoleLogger,
|
|
148
|
+
resolver: customResolver,
|
|
149
|
+
commandMiddleware: [loggingMiddleware],
|
|
150
|
+
eventMiddleware: [filterMiddleware],
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Subpath Exports
|
|
155
|
+
|
|
156
|
+
The package provides granular subpath exports for advanced use cases:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import { Identity } from "@honeybbq/teamspeak-client/crypto";
|
|
160
|
+
import { Resolver } from "@honeybbq/teamspeak-client/discovery";
|
|
161
|
+
import { PacketHandler } from "@honeybbq/teamspeak-client/transport";
|
|
162
|
+
import { buildCommand, parseCommand } from "@honeybbq/teamspeak-client/command";
|
|
163
|
+
import { processInit1 } from "@honeybbq/teamspeak-client/handshake";
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Architecture
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
teamspeak-js/
|
|
170
|
+
├── src/
|
|
171
|
+
│ ├── client.ts # Client lifecycle, connection management
|
|
172
|
+
│ ├── api.ts # High-level API (messages, channels, clients)
|
|
173
|
+
│ ├── commands.ts # Command sending and response tracking
|
|
174
|
+
│ ├── events.ts # Event handler registration and middleware
|
|
175
|
+
│ ├── notifications.ts # Server notification parsing and dispatch
|
|
176
|
+
│ ├── handshake.ts # Protocol handshake orchestration
|
|
177
|
+
│ ├── transfer.ts # File transfer operations
|
|
178
|
+
│ ├── throttle.ts # Token-bucket rate limiter
|
|
179
|
+
│ ├── types.ts # Public type definitions
|
|
180
|
+
│ ├── errors.ts # Error classes
|
|
181
|
+
│ ├── crypto/ # ECDH, EAX encryption, identity management
|
|
182
|
+
│ ├── handshake/ # Crypto handshake and license verification
|
|
183
|
+
│ ├── transport/ # UDP packet framing, ACK, compression
|
|
184
|
+
│ ├── command/ # Command builder and parser
|
|
185
|
+
│ └── discovery/ # SRV / TSDNS / direct address resolution
|
|
186
|
+
├── examples/
|
|
187
|
+
│ └── connect.ts # Minimal connection example
|
|
188
|
+
├── vite.config.ts # Build configuration (Vite library mode)
|
|
189
|
+
└── tsconfig.json
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Related
|
|
193
|
+
|
|
194
|
+
- **[teamspeak-go](https://github.com/honeybbq/teamspeak-go)** — The original Go implementation this library is ported from
|
|
195
|
+
|
|
196
|
+
## Acknowledgments
|
|
197
|
+
|
|
198
|
+
Protocol knowledge was primarily informed by the [TSLib](https://github.com/Splamy/TS3AudioBot) implementation in [TS3AudioBot](https://github.com/Splamy/TS3AudioBot) by Splamy. Huge thanks to the TS3AudioBot project and its contributors.
|
|
199
|
+
|
|
200
|
+
## Disclaimer
|
|
201
|
+
|
|
202
|
+
TeamSpeak is a registered trademark of [TeamSpeak Systems GmbH](https://teamspeak.com/). This project is not affiliated with, endorsed by, or associated with TeamSpeak Systems GmbH in any way.
|
|
203
|
+
|
|
204
|
+
This library is a **clean-room implementation** developed from publicly available documentation, protocol analysis of network traffic, and independent research. No proprietary TeamSpeak SDK code, headers, or libraries were used in its creation.
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
[MIT](LICENSE)
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ChannelInfo, ClientInfo } from "./types.js";
|
|
2
|
+
import type { Client } from "./client.js";
|
|
3
|
+
/** Send a text message to a client (targetMode=1), channel (2), or server (3). */
|
|
4
|
+
export declare function sendTextMessage(client: Client, targetMode: number, targetID: bigint, message: string): Promise<void>;
|
|
5
|
+
/** Move a client to a different channel. */
|
|
6
|
+
export declare function clientMove(client: Client, clid: number, channelID: bigint, password?: string): Promise<void>;
|
|
7
|
+
/** Send a poke message to a client. */
|
|
8
|
+
export declare function poke(client: Client, clid: number, message: string): Promise<void>;
|
|
9
|
+
/** Fetch raw clientinfo for a given clid. */
|
|
10
|
+
export declare function getClientInfo(client: Client, clid: number): Promise<Record<string, string>>;
|
|
11
|
+
/** List all channels on the server. */
|
|
12
|
+
export declare function listChannels(client: Client): Promise<ChannelInfo[]>;
|
|
13
|
+
/** List all clients currently connected to the server. */
|
|
14
|
+
export declare function listClients(client: Client): Promise<ClientInfo[]>;
|
|
15
|
+
/** Delete a file on the server. */
|
|
16
|
+
export declare function fileTransferDeleteFile(client: Client, channelID: bigint, paths: string[]): Promise<void>;
|
|
17
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,kFAAkF;AAClF,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,4CAA4C;AAC5C,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,QAAQ,SAAK,GACZ,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,uCAAuC;AACvC,wBAAsB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMvF;AAED,6CAA6C;AAC7C,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAKjG;AAED,uCAAuC;AACvC,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAQzE;AAED,0DAA0D;AAC1D,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAavE;AAED,mCAAmC;AACnC,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,IAAI,CAAC,CASf"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type EventMap, type ClientOptions, type CommandMiddleware, type EventMiddleware, type Logger, ClientStatus } from "./types.js";
|
|
2
|
+
import { Identity, Crypt } from "./crypto/index.js";
|
|
3
|
+
import { PacketHandler } from "./transport/handler.js";
|
|
4
|
+
import type { FileUploadInfo, FileDownloadInfo } from "./types.js";
|
|
5
|
+
import type { Readable, Writable } from "node:stream";
|
|
6
|
+
export { ClientStatus };
|
|
7
|
+
export interface ClientState {
|
|
8
|
+
status: ClientStatus;
|
|
9
|
+
clid: number;
|
|
10
|
+
}
|
|
11
|
+
export declare class Client {
|
|
12
|
+
#private;
|
|
13
|
+
/** @internal */ crypt: Crypt;
|
|
14
|
+
/** @internal */ handler: PacketHandler;
|
|
15
|
+
/** @internal */ logger: Logger;
|
|
16
|
+
/** @internal */ nickname: string;
|
|
17
|
+
/** @internal */ clid: number;
|
|
18
|
+
constructor(identity: Identity, addr: string, nickname: string, options?: ClientOptions);
|
|
19
|
+
get status(): ClientStatus;
|
|
20
|
+
connect(): Promise<void>;
|
|
21
|
+
disconnect(): Promise<void>;
|
|
22
|
+
waitConnected(signal?: AbortSignal): Promise<void>;
|
|
23
|
+
sendCommandNoWait(cmd: string): Promise<void>;
|
|
24
|
+
execCommand(cmd: string, timeoutMs?: number): Promise<void>;
|
|
25
|
+
execCommandWithResponse(cmd: string, timeoutMs?: number): Promise<Record<string, string>[]>;
|
|
26
|
+
on<K extends keyof EventMap>(event: K, handler: EventMap[K] extends void ? () => void : (payload: EventMap[K]) => void): this;
|
|
27
|
+
useCommandMiddleware(...mw: CommandMiddleware[]): this;
|
|
28
|
+
useEventMiddleware(...mw: EventMiddleware[]): this;
|
|
29
|
+
clientID(): number;
|
|
30
|
+
channelID(): bigint;
|
|
31
|
+
sendVoice(data: Uint8Array, codec: number): void;
|
|
32
|
+
fileTransferInitUpload(channelID: bigint, path: string, password: string, size: bigint, overwrite?: boolean): Promise<FileUploadInfo>;
|
|
33
|
+
fileTransferInitDownload(channelID: bigint, path: string, password: string): Promise<FileDownloadInfo>;
|
|
34
|
+
uploadFileData(host: string, info: FileUploadInfo, data: Readable): Promise<void>;
|
|
35
|
+
downloadFileData(host: string, info: FileDownloadInfo, dest: Writable): Promise<void>;
|
|
36
|
+
/** @internal */
|
|
37
|
+
_markConnected(): void;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +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;AAmBvD,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;AAKD,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;gBA6Bd,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB;IAuB3F,IAAI,MAAM,IAAI,YAAY,CAEzB;IAIK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAaxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBjC,aAAa,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAY5C,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7C,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D,uBAAuB,CAC3B,GAAG,EAAE,MAAM,EACX,SAAS,SAAS,GACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IA2BpC,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;IAiCP,oBAAoB,CAAC,GAAG,EAAE,EAAE,iBAAiB,EAAE,GAAG,IAAI;IAMtD,kBAAkB,CAAC,GAAG,EAAE,EAAE,eAAe,EAAE,GAAG,IAAI;IAQlD,QAAQ,IAAI,MAAM;IAIlB,SAAS,IAAI,MAAM;IAKnB,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAM1C,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;IA2BpB,wBAAwB,CAC5B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,gBAAgB,CAAC;IA2B5B,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjF,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrF,gBAAgB;IAChB,cAAc,IAAI,IAAI;CA0RvB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { EscapedString } from "../types.js";
|
|
2
|
+
export declare function escape(s: string): EscapedString;
|
|
3
|
+
export declare function unescape(s: string): string;
|
|
4
|
+
export interface Command {
|
|
5
|
+
name: string;
|
|
6
|
+
params: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
/** Build a TS3 command string from an unordered params map. */
|
|
9
|
+
export declare function buildCommand(cmd: string, params: Record<string, string>): string;
|
|
10
|
+
/** Build a TS3 command string preserving parameter order. */
|
|
11
|
+
export declare function buildCommandOrdered(cmd: string, params: ReadonlyArray<readonly [string, string]>): string;
|
|
12
|
+
//# sourceMappingURL=command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/command/command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAgBjD,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,aAAa,CAM/C;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CA+D1C;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAMhF;AAED,6DAA6D;AAC7D,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAC/C,MAAM,CAMR"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.test.d.ts","sourceRoot":"","sources":["../../src/command/command.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../command-Cu2v-5-K.cjs`),t=require(`../parser-DhAWj-TI.cjs`);exports.buildCommand=e.t,exports.buildCommandOrdered=e.n,exports.escape=e.r,exports.parseCommand=t.t,exports.unescape=e.i;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/command/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnF,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/command/parser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAoCtD"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
var e=[[`\\`,`\\\\`],[`/`,`\\/`],[` `,`\\s`],[`|`,`\\p`],[`\x07`,`\\a`],[`\b`,`\\b`],[`\f`,`\\f`],[`
|
|
2
|
+
`,`\\n`],[`\r`,`\\r`],[` `,`\\t`],[`\v`,`\\v`]];function t(t){let n=t;for(let[t,r]of e)n=n.split(t).join(r);return n}function n(e){let t=``,n=0;for(;n<e.length;)if(e[n]===`\\`&&n+1<e.length)switch(e[n+1]){case`\\`:t+=`\\`,n+=2;break;case`/`:t+=`/`,n+=2;break;case`s`:t+=` `,n+=2;break;case`p`:t+=`|`,n+=2;break;case`a`:t+=`\x07`,n+=2;break;case`b`:t+=`\b`,n+=2;break;case`f`:t+=`\f`,n+=2;break;case`n`:t+=`
|
|
3
|
+
`,n+=2;break;case`r`:t+=`\r`,n+=2;break;case`t`:t+=` `,n+=2;break;case`v`:t+=`\v`,n+=2;break;default:t+=e[n]??``,n++;break}else t+=e[n]??``,n++;return t}function r(e,n){let r=[t(e)];for(let[e,i]of Object.entries(n))r.push(`${e}=${t(i)}`);return r.join(` `)}function i(e,n){let r=[t(e)];for(let[e,i]of n)r.push(`${e}=${t(i)}`);return r.join(` `)}Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return r}});
|
|
4
|
+
//# sourceMappingURL=command-Cu2v-5-K.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-Cu2v-5-K.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,IAAM,EAAiC,CACrC,CAAC,KAAM,OAAO,CACd,CAAC,IAAK,MAAM,CACZ,CAAC,IAAK,MAAM,CACZ,CAAC,IAAK,MAAM,CACZ,CAAC,OAAQ,MAAM,CACf,CAAC,KAAQ,MAAM,CACf,CAAC,KAAQ,MAAM,CACf,CAAC;EAAM,MAAM,CACb,CAAC,KAAM,MAAM,CACb,CAAC,IAAM,MAAM,CACb,CAAC,KAAQ,MAAM,CAChB,CAED,SAAgB,EAAO,EAA0B,CAC/C,IAAI,EAAS,EACb,IAAK,GAAM,CAAC,EAAM,KAAO,EACvB,EAAS,EAAO,MAAM,EAAK,CAAC,KAAK,EAAG,CAEtC,OAAO,EAGT,SAAgB,EAAS,EAAmB,CAE1C,IAAI,EAAS,GACT,EAAI,EACR,KAAO,EAAI,EAAE,QACX,GAAI,EAAE,KAAO,MAAQ,EAAI,EAAI,EAAE,OAE7B,OADa,EAAE,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,GAAU,EAAE,IAAM,GAClB,IACA,WAGJ,GAAU,EAAE,IAAM,GAClB,IAGJ,OAAO,EAST,SAAgB,EAAa,EAAa,EAAwC,CAChF,IAAM,EAAkB,CAAC,EAAO,EAAI,CAAC,CACrC,IAAK,GAAM,CAAC,EAAG,KAAM,OAAO,QAAQ,EAAO,CACzC,EAAM,KAAK,GAAG,EAAE,GAAG,EAAO,EAAE,GAAG,CAEjC,OAAO,EAAM,KAAK,IAAI,CAIxB,SAAgB,EACd,EACA,EACQ,CACR,IAAM,EAAkB,CAAC,EAAO,EAAI,CAAC,CACrC,IAAK,GAAM,CAAC,EAAG,KAAM,EACnB,EAAM,KAAK,GAAG,EAAE,GAAG,EAAO,EAAE,GAAG,CAEjC,OAAO,EAAM,KAAK,IAAI"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
//#region src/command/command.ts
|
|
2
|
+
var e = [
|
|
3
|
+
["\\", "\\\\"],
|
|
4
|
+
["/", "\\/"],
|
|
5
|
+
[" ", "\\s"],
|
|
6
|
+
["|", "\\p"],
|
|
7
|
+
["\x07", "\\a"],
|
|
8
|
+
["\b", "\\b"],
|
|
9
|
+
["\f", "\\f"],
|
|
10
|
+
["\n", "\\n"],
|
|
11
|
+
["\r", "\\r"],
|
|
12
|
+
[" ", "\\t"],
|
|
13
|
+
["\v", "\\v"]
|
|
14
|
+
];
|
|
15
|
+
function t(t) {
|
|
16
|
+
let n = t;
|
|
17
|
+
for (let [t, r] of e) n = n.split(t).join(r);
|
|
18
|
+
return n;
|
|
19
|
+
}
|
|
20
|
+
function n(e) {
|
|
21
|
+
let t = "", n = 0;
|
|
22
|
+
for (; n < e.length;) if (e[n] === "\\" && n + 1 < e.length) switch (e[n + 1]) {
|
|
23
|
+
case "\\":
|
|
24
|
+
t += "\\", n += 2;
|
|
25
|
+
break;
|
|
26
|
+
case "/":
|
|
27
|
+
t += "/", n += 2;
|
|
28
|
+
break;
|
|
29
|
+
case "s":
|
|
30
|
+
t += " ", n += 2;
|
|
31
|
+
break;
|
|
32
|
+
case "p":
|
|
33
|
+
t += "|", n += 2;
|
|
34
|
+
break;
|
|
35
|
+
case "a":
|
|
36
|
+
t += "\x07", n += 2;
|
|
37
|
+
break;
|
|
38
|
+
case "b":
|
|
39
|
+
t += "\b", n += 2;
|
|
40
|
+
break;
|
|
41
|
+
case "f":
|
|
42
|
+
t += "\f", n += 2;
|
|
43
|
+
break;
|
|
44
|
+
case "n":
|
|
45
|
+
t += "\n", n += 2;
|
|
46
|
+
break;
|
|
47
|
+
case "r":
|
|
48
|
+
t += "\r", n += 2;
|
|
49
|
+
break;
|
|
50
|
+
case "t":
|
|
51
|
+
t += " ", n += 2;
|
|
52
|
+
break;
|
|
53
|
+
case "v":
|
|
54
|
+
t += "\v", n += 2;
|
|
55
|
+
break;
|
|
56
|
+
default:
|
|
57
|
+
t += e[n] ?? "", n++;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
else t += e[n] ?? "", n++;
|
|
61
|
+
return t;
|
|
62
|
+
}
|
|
63
|
+
function r(e, n) {
|
|
64
|
+
let r = [t(e)];
|
|
65
|
+
for (let [e, i] of Object.entries(n)) r.push(`${e}=${t(i)}`);
|
|
66
|
+
return r.join(" ");
|
|
67
|
+
}
|
|
68
|
+
function i(e, n) {
|
|
69
|
+
let r = [t(e)];
|
|
70
|
+
for (let [e, i] of n) r.push(`${e}=${t(i)}`);
|
|
71
|
+
return r.join(" ");
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
export { n as i, i as n, t as r, r as t };
|
|
75
|
+
|
|
76
|
+
//# sourceMappingURL=command-caXc4h0n.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-caXc4h0n.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,IAAM,IAAiC;CACrC,CAAC,MAAM,OAAO;CACd,CAAC,KAAK,MAAM;CACZ,CAAC,KAAK,MAAM;CACZ,CAAC,KAAK,MAAM;CACZ,CAAC,QAAQ,MAAM;CACf,CAAC,MAAQ,MAAM;CACf,CAAC,MAAQ,MAAM;CACf,CAAC,MAAM,MAAM;CACb,CAAC,MAAM,MAAM;CACb,CAAC,KAAM,MAAM;CACb,CAAC,MAAQ,MAAM;CAChB;AAED,SAAgB,EAAO,GAA0B;CAC/C,IAAI,IAAS;AACb,MAAK,IAAM,CAAC,GAAM,MAAO,EACvB,KAAS,EAAO,MAAM,EAAK,CAAC,KAAK,EAAG;AAEtC,QAAO;;AAGT,SAAgB,EAAS,GAAmB;CAE1C,IAAI,IAAS,IACT,IAAI;AACR,QAAO,IAAI,EAAE,QACX,KAAI,EAAE,OAAO,QAAQ,IAAI,IAAI,EAAE,OAE7B,SADa,EAAE,IAAI,IACnB;EACE,KAAK;AAEH,GADA,KAAU,MACV,KAAK;AACL;EACF,KAAK;AAEH,GADA,KAAU,KACV,KAAK;AACL;EACF,KAAK;AAEH,GADA,KAAU,KACV,KAAK;AACL;EACF,KAAK;AAEH,GADA,KAAU,KACV,KAAK;AACL;EACF,KAAK;AAEH,GADA,KAAU,QACV,KAAK;AACL;EACF,KAAK;AAEH,GADA,KAAU,MACV,KAAK;AACL;EACF,KAAK;AAEH,GADA,KAAU,MACV,KAAK;AACL;EACF,KAAK;AAEH,GADA,KAAU,MACV,KAAK;AACL;EACF,KAAK;AAEH,GADA,KAAU,MACV,KAAK;AACL;EACF,KAAK;AAEH,GADA,KAAU,KACV,KAAK;AACL;EACF,KAAK;AAEH,GADA,KAAU,MACV,KAAK;AACL;EACF;AAEE,GADA,KAAU,EAAE,MAAM,IAClB;AACA;;KAIJ,CADA,KAAU,EAAE,MAAM,IAClB;AAGJ,QAAO;;AAST,SAAgB,EAAa,GAAa,GAAwC;CAChF,IAAM,IAAkB,CAAC,EAAO,EAAI,CAAC;AACrC,MAAK,IAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,EAAO,CACzC,GAAM,KAAK,GAAG,EAAE,GAAG,EAAO,EAAE,GAAG;AAEjC,QAAO,EAAM,KAAK,IAAI;;AAIxB,SAAgB,EACd,GACA,GACQ;CACR,IAAM,IAAkB,CAAC,EAAO,EAAI,CAAC;AACrC,MAAK,IAAM,CAAC,GAAG,MAAM,EACnB,GAAM,KAAK,GAAG,EAAE,GAAG,EAAO,EAAE,GAAG;AAEjC,QAAO,EAAM,KAAK,IAAI"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface CommandResult {
|
|
2
|
+
err: Error | null;
|
|
3
|
+
data: Record<string, string>[];
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Tracks in-flight commands by return_code.
|
|
7
|
+
*
|
|
8
|
+
* The TS3/TS5 server sends a "welcome sequence" of unsolicited data immediately
|
|
9
|
+
* after the connection handshake (channellist, channelclientlist, etc.). This
|
|
10
|
+
* data arrives on the event loop AFTER we may have registered our first pending
|
|
11
|
+
* RC, which would contaminate our command responses.
|
|
12
|
+
*
|
|
13
|
+
* Solution: gate all row buffering on a `#welcomeComplete` flag. The flag is
|
|
14
|
+
* set when `notifycliententerview` for our own clid arrives — the last event
|
|
15
|
+
* the TS3/TS5 server sends in its welcome sequence. Any data arriving before
|
|
16
|
+
* that is silently discarded.
|
|
17
|
+
*/
|
|
18
|
+
export declare class CommandTracker {
|
|
19
|
+
#private;
|
|
20
|
+
register(): [rc: number, promise: Promise<CommandResult>];
|
|
21
|
+
unregister(rc: number): void;
|
|
22
|
+
/**
|
|
23
|
+
* Called when `notifycliententerview` for our own clid arrives.
|
|
24
|
+
* Marks the welcome sequence as complete and discards any accumulated data.
|
|
25
|
+
*/
|
|
26
|
+
signalWelcomeComplete(): void;
|
|
27
|
+
/**
|
|
28
|
+
* Buffer a data row from the server. Rows arriving before the welcome
|
|
29
|
+
* sequence is complete are silently discarded to prevent contamination.
|
|
30
|
+
*/
|
|
31
|
+
buffer(params: Record<string, string>): void;
|
|
32
|
+
resolve(rc: number, err: Error | null): void;
|
|
33
|
+
discardBuffer(): void;
|
|
34
|
+
reset(): void;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Parse and handle an `error` command from the server.
|
|
38
|
+
* Returns the error (or null on success) and the resolved return_code.
|
|
39
|
+
*/
|
|
40
|
+
export declare function parseServerError(params: Record<string, string>): {
|
|
41
|
+
err: Error | null;
|
|
42
|
+
rc: number | null;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Append a return_code parameter to a command string if not already present.
|
|
46
|
+
*/
|
|
47
|
+
export declare function appendReturnCode(cmd: string, rc: number): string;
|
|
48
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +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;IASzD,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI5B;;;OAGG;IACH,qBAAqB,IAAI,IAAI;IAK7B;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAM5C,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI;IAY5C,aAAa,IAAI,IAAI;IAIrB,KAAK,IAAI,IAAI;CAMd;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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { n as e } from "./command-caXc4h0n.js";
|
|
2
|
+
import { randomBytes as t } from "node:crypto";
|
|
3
|
+
//#region src/handshake/crypt-handshake.ts
|
|
4
|
+
var n = 1566914096, r = 4, i = 1, a = 21;
|
|
5
|
+
function o(e, t) {
|
|
6
|
+
if (t === null || t.length >= 1 && t[0] === 127) return s();
|
|
7
|
+
switch (t[0]) {
|
|
8
|
+
case 0: return c(t);
|
|
9
|
+
case 1: return l(t);
|
|
10
|
+
case 2: return u(t);
|
|
11
|
+
case 3: return d(e, t);
|
|
12
|
+
default: return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function s() {
|
|
16
|
+
let e = new Uint8Array(r + i + 4 + 4 + 8), a = new DataView(e.buffer);
|
|
17
|
+
a.setUint32(0, n, !1), e[4] = 0;
|
|
18
|
+
let o = Math.floor(Date.now() / 1e3), s = Math.max(0, Math.min(o, 4294967295));
|
|
19
|
+
a.setUint32(5, s, !1);
|
|
20
|
+
let c = t(4);
|
|
21
|
+
return e.set(c, 9), e;
|
|
22
|
+
}
|
|
23
|
+
function c(e) {
|
|
24
|
+
if (e.length !== a) return null;
|
|
25
|
+
let t = new Uint8Array(i + 16 + 4);
|
|
26
|
+
t[0] = 1;
|
|
27
|
+
let n = r + i + 4, o = e[n] | e[n + 1] << 8 | e[n + 2] << 16 | e[n + 3] << 24;
|
|
28
|
+
return new DataView(t.buffer).setUint32(i + 16, o >>> 0, !1), t;
|
|
29
|
+
}
|
|
30
|
+
function l(e) {
|
|
31
|
+
if (e.length !== a) return null;
|
|
32
|
+
let t = new Uint8Array(r + i + 16 + 4);
|
|
33
|
+
return new DataView(t.buffer).setUint32(0, n, !1), t[4] = 2, t.set(e.slice(1, 21), 5), t;
|
|
34
|
+
}
|
|
35
|
+
function u(e) {
|
|
36
|
+
if (e.length !== r + i + 16 + 4) return null;
|
|
37
|
+
let t = new Uint8Array(i + 64 + 64 + 4 + 100);
|
|
38
|
+
return t[0] = 3, t[i + 64 - 1] = 1, t[i + 64 + 64 - 1] = 1, new DataView(t.buffer).setUint32(i + 64 + 64, 1, !1), t;
|
|
39
|
+
}
|
|
40
|
+
function d(a, o) {
|
|
41
|
+
if (o.length !== i + 64 + 64 + 4 + 100) return null;
|
|
42
|
+
let s = new DataView(o.buffer, o.byteOffset).getUint32(129, !1), c = a.solveRsaChallenge(o, 1, s);
|
|
43
|
+
a.alphaTmp = new Uint8Array(t(10));
|
|
44
|
+
let l = Buffer.from(a.alphaTmp).toString("base64"), u = a.identity.publicKeyBase64(), d = e("clientinitiv", [
|
|
45
|
+
["alpha", l],
|
|
46
|
+
["omega", u],
|
|
47
|
+
["ot", "1"],
|
|
48
|
+
["ip", ""]
|
|
49
|
+
]), f = Buffer.from(d), p = new Uint8Array(r + i + 232 + 64 + f.length);
|
|
50
|
+
return new DataView(p.buffer).setUint32(0, n, !1), p[4] = 4, p.set(o.slice(1, 233), 5), p.set(c.slice(0, 64), 237), p.set(f, 301), p;
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { o as n, n as t };
|
|
54
|
+
|
|
55
|
+
//# sourceMappingURL=crypt-handshake-CHmvZ2qs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypt-handshake-CHmvZ2qs.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":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require(`./command-Cu2v-5-K.cjs`);let t=require(`node:crypto`);var n=1566914096,r=4,i=1,a=21;function o(e,t){if(t===null||t.length>=1&&t[0]===127)return s();switch(t[0]){case 0:return c(t);case 1:return l(t);case 2:return u(t);case 3:return d(e,t);default:return null}}function s(){let e=new Uint8Array(r+i+4+4+8),a=new DataView(e.buffer);a.setUint32(0,n,!1),e[4]=0;let o=Math.floor(Date.now()/1e3),s=Math.max(0,Math.min(o,4294967295));a.setUint32(5,s,!1);let c=(0,t.randomBytes)(4);return e.set(c,9),e}function c(e){if(e.length!==a)return null;let t=new Uint8Array(i+16+4);t[0]=1;let n=r+i+4,o=e[n]|e[n+1]<<8|e[n+2]<<16|e[n+3]<<24;return new DataView(t.buffer).setUint32(i+16,o>>>0,!1),t}function l(e){if(e.length!==a)return null;let t=new Uint8Array(r+i+16+4);return new DataView(t.buffer).setUint32(0,n,!1),t[4]=2,t.set(e.slice(1,21),5),t}function u(e){if(e.length!==r+i+16+4)return null;let t=new Uint8Array(i+64+64+4+100);return t[0]=3,t[i+64-1]=1,t[i+64+64-1]=1,new DataView(t.buffer).setUint32(i+64+64,1,!1),t}function d(a,o){if(o.length!==i+64+64+4+100)return null;let s=new DataView(o.buffer,o.byteOffset).getUint32(129,!1),c=a.solveRsaChallenge(o,1,s);a.alphaTmp=new Uint8Array((0,t.randomBytes)(10));let l=Buffer.from(a.alphaTmp).toString(`base64`),u=a.identity.publicKeyBase64(),d=e.n(`clientinitiv`,[[`alpha`,l],[`omega`,u],[`ot`,`1`],[`ip`,``]]),f=Buffer.from(d),p=new Uint8Array(r+i+232+64+f.length);return new DataView(p.buffer).setUint32(0,n,!1),p[4]=4,p.set(o.slice(1,233),5),p.set(c.slice(0,64),237),p.set(f,301),p}Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return n}});
|
|
2
|
+
//# sourceMappingURL=crypt-handshake-Dbj2cSBZ.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypt-handshake-Dbj2cSBZ.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":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require(`./primitives-BxtDMP7x.cjs`);var t=new Uint8Array([205,13,226,174,212,99,69,80,154,126,60,253,143,104,179,220,117,85,178,157,204,236,115,205,24,117,15,153,56,18,64,138]),n=function(e){return e[e.Intermediate=0]=`Intermediate`,e[e.Server=2]=`Server`,e[e.Ts5Server=8]=`Ts5Server`,e[e.Ephemeral=32]=`Ephemeral`,e}(n||{}),r=class{blocks;constructor(e){this.blocks=e}deriveKey(){let e=Uint8Array.from(t);for(let t of this.blocks)e=c(t,e);return e}};function i(e){if(e.length<1)throw Error(`license too short`);if(e[0]!==1)throw Error(`unsupported license version`);let t=e.slice(1),n=[];for(;t.length>0;){let{block:e,consumed:r}=a(t);n.push(e),t=t.slice(r)}return new r(n)}function a(t){if(t.length<42)throw Error(`license too short`);if(t[0]!==0)throw Error(`wrong key kind in license: ${t[0]}`);let n=t[33],r=1356998400,i=new DataView(t.buffer,t.byteOffset,t.byteLength),a=new Date((i.getUint32(34,!1)+r)*1e3),s=new Date((i.getUint32(38,!1)+r)*1e3);if(s<a)throw Error(`license times are invalid`);let c=Uint8Array.from(t.slice(1,33)),{payload:l,payloadRead:u}=o(n,t,42),d=42+u,f=t.slice(1,d),p=e.u(Uint8Array.from(f));return{block:{key:c,hash:Uint8Array.from(p.slice(0,32)),properties:l.properties,issuer:l.issuer,notValidBefore:a,notValidAfter:s,blockType:n,serverType:l.serverType},consumed:d}}function o(e,t,r){switch(e){case n.Intermediate:{let{str:e,read:n}=s(t.slice(46));return{payload:{issuer:e,serverType:0,properties:[],read:5+n},payloadRead:5+n}}case n.Server:{let{str:e,read:n}=s(t.slice(47));return{payload:{issuer:e,serverType:t[42]??0,properties:[],read:6+n},payloadRead:6+n}}case n.Ts5Server:{let e=t[43]===void 0?0:t[43],n=44,i=[];for(let r=0;r<e;r++){if(n>=t.length)throw Error(`license too short`);let e=t[n++];if(n+e>t.length)throw Error(`license too short`);i.push(Uint8Array.from(t.slice(n,n+e))),n+=e}return{payload:{issuer:``,serverType:t[42]??0,properties:i,read:n-r},payloadRead:n-r}}case n.Ephemeral:return{payload:{issuer:``,serverType:0,properties:[],read:0},payloadRead:0};default:throw Error(`invalid license block type: ${e}`)}}function s(e){for(let t=0;t<e.length;t++)if(e[t]===0)return{str:new TextDecoder().decode(e.slice(0,t)),read:t};throw Error(`non-null-terminated issuer string`)}function c(t,n){let r=Uint8Array.from(t.hash);e.t(r);let i=l(r)%e.o.Point.CURVE().n,a=e.o.Point.fromBytes(t.key).negate(),o=e.o.Point.fromBytes(n).negate(),s=a.multiply(i).add(o).toBytes(),c=new Uint8Array(s.length);return c.set(s),c[31]=(c[31]===void 0?0:c[31])^128,c}function l(e){let t=0n;for(let n=e.length-1;n>=0;n--)t=t<<8n|BigInt(e[n]);return t}function u(t,n,r,a,o,s){if(t.alphaTmp.length===0)throw Error(`alpha is not initialized`);let c=Buffer.from(n,`base64`),l=Buffer.from(r,`base64`),u=Buffer.from(a,`base64`),d=Buffer.from(o,`base64`);if(!e.a(e.f(l),c,u))throw Error(`init proof is not valid`);let f=e.r(i(c).deriveKey(),s);t.setSharedSecret(t.alphaTmp,d,f)}Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return u}});
|
|
2
|
+
//# sourceMappingURL=crypt-init2-BIbQ7TN0.cjs.map
|