packet-events-js 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +398 -0
- package/package.json +31 -0
- package/src/auth/AuthHandler.js +138 -0
- package/src/auth/MojangAPI.js +186 -0
- package/src/client/MinecraftClient.js +336 -0
- package/src/crypto/Encryption.js +125 -0
- package/src/events/EventEmitter.js +267 -0
- package/src/events/PacketEvent.js +78 -0
- package/src/index.js +18 -0
- package/src/manager/PacketManager.js +258 -0
- package/src/protocol/ConnectionState.js +37 -0
- package/src/protocol/PacketDirection.js +8 -0
- package/src/protocol/ProtocolVersion.js +141 -0
- package/src/protocol/packets/Packet.js +119 -0
- package/src/protocol/packets/PacketRegistry.js +145 -0
- package/src/protocol/packets/handshake/HandshakePacket.js +44 -0
- package/src/protocol/packets/index.js +265 -0
- package/src/protocol/packets/login/DisconnectPacket.js +71 -0
- package/src/protocol/packets/login/EncryptionRequestPacket.js +47 -0
- package/src/protocol/packets/login/EncryptionResponsePacket.js +34 -0
- package/src/protocol/packets/login/LoginStartPacket.js +35 -0
- package/src/protocol/packets/login/LoginSuccessPacket.js +61 -0
- package/src/protocol/packets/login/SetCompressionPacket.js +29 -0
- package/src/protocol/packets/play/ChatPacket.js +238 -0
- package/src/protocol/packets/play/ChunkPacket.js +122 -0
- package/src/protocol/packets/play/EntityPacket.js +302 -0
- package/src/protocol/packets/play/KeepAlivePacket.js +55 -0
- package/src/protocol/packets/play/PlayerPositionPacket.js +266 -0
- package/src/protocol/packets/status/PingPacket.js +29 -0
- package/src/protocol/packets/status/PongPacket.js +29 -0
- package/src/protocol/packets/status/StatusRequestPacket.js +20 -0
- package/src/protocol/packets/status/StatusResponsePacket.js +58 -0
- package/src/protocol/types/NBT.js +594 -0
- package/src/protocol/types/Position.js +125 -0
- package/src/protocol/types/TextComponent.js +355 -0
- package/src/protocol/types/UUID.js +105 -0
- package/src/protocol/types/VarInt.js +144 -0
- package/src/protocol/types/index.js +5 -0
- package/src/utils/Logger.js +207 -0
- package/src/utils/PacketBuffer.js +389 -0
package/README.md
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
# PacketEvents-JS
|
|
2
|
+
|
|
3
|
+
A robust protocol library for **Minecraft Java Edition** written entirely in **pure JavaScript**. Inspired by [PacketEvents](https://github.com/retrooper/packetevents), designed to facilitate the processing and transmission of Minecraft protocol packets with full online mode support.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Pure JavaScript** - No external dependencies, only native Node.js
|
|
8
|
+
- **TCP Connection** - Complete TCP client for Minecraft
|
|
9
|
+
- **Packet System** - Read/write all protocol data types
|
|
10
|
+
- **Event System** - Priority-based events with cancellation and async/await
|
|
11
|
+
- **Compression** - Full zlib compression support
|
|
12
|
+
- **Encryption** - Complete AES-128-CFB8 encryption support for online mode
|
|
13
|
+
- **Online Mode** - Full Mojang/Microsoft authentication support
|
|
14
|
+
- **Offline Mode** - Offline player UUID generation (version 3)
|
|
15
|
+
- **Complete NBT** - Named Binary Tag read/write
|
|
16
|
+
- **Chat Components** - JSON Text Component with colors, formatting, and events
|
|
17
|
+
- **Multi-version** - Support for Minecraft 1.7.2 to 1.21.11 (66 versions)
|
|
18
|
+
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
- Node.js 18.0.0 or higher
|
|
22
|
+
- ES Modules enabled
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install packet-events-js
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Or clone the repository:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
git clone https://github.com/FrannnnDev/PacketEvents-JS.git
|
|
34
|
+
cd PacketEvents-JS
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Basic Usage
|
|
38
|
+
|
|
39
|
+
### Server List Ping
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
import { MinecraftClient, ProtocolVersion } from 'packet-events-js';
|
|
43
|
+
|
|
44
|
+
const client = new MinecraftClient({
|
|
45
|
+
host: 'mc.hypixel.net',
|
|
46
|
+
port: 25565,
|
|
47
|
+
version: ProtocolVersion.V1_21_11
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const status = await client.ping();
|
|
51
|
+
console.log(`Players: ${status.players.online}/${status.players.max}`);
|
|
52
|
+
console.log(`Latency: ${status.latency}ms`);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Connect to Server (Offline Mode)
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
import { MinecraftClient, ProtocolVersion, Logger, LogLevel } from 'packet-events-js';
|
|
59
|
+
import { KeepAliveClientboundPacket, KeepAliveServerboundPacket } from 'packet-events-js/protocol/packets';
|
|
60
|
+
|
|
61
|
+
Logger.setGlobalLevel(LogLevel.DEBUG);
|
|
62
|
+
|
|
63
|
+
const client = new MinecraftClient({
|
|
64
|
+
host: 'localhost',
|
|
65
|
+
port: 25565,
|
|
66
|
+
version: ProtocolVersion.V1_21_11,
|
|
67
|
+
username: 'MyBot',
|
|
68
|
+
offline: true
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
client.onPacket(KeepAliveClientboundPacket, async (event) => {
|
|
72
|
+
const response = new KeepAliveServerboundPacket();
|
|
73
|
+
response.keepAliveId = event.packet.keepAliveId;
|
|
74
|
+
await client.sendPacket(response);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
await client.login();
|
|
78
|
+
console.log(`Connected as ${client.playerName}`);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Encryption API
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
import { MinecraftEncryption, EncryptedConnection } from 'packet-events-js/crypto/Encryption';
|
|
85
|
+
|
|
86
|
+
const keyPair = MinecraftEncryption.generateKeyPair();
|
|
87
|
+
console.log('Public Key:', keyPair.publicKey);
|
|
88
|
+
console.log('Private Key:', keyPair.privateKey);
|
|
89
|
+
|
|
90
|
+
const verifyToken = MinecraftEncryption.generateVerifyToken();
|
|
91
|
+
const sharedSecret = MinecraftEncryption.generateSharedSecret();
|
|
92
|
+
|
|
93
|
+
const encrypted = MinecraftEncryption.encryptRSA(keyPair.publicKey, sharedSecret);
|
|
94
|
+
const decrypted = MinecraftEncryption.decryptRSA(keyPair.privateKey, encrypted);
|
|
95
|
+
|
|
96
|
+
const aesEncrypted = MinecraftEncryption.encryptAES(sharedSecret, Buffer.from('Hello'));
|
|
97
|
+
const aesDecrypted = MinecraftEncryption.decryptAES(sharedSecret, aesEncrypted);
|
|
98
|
+
|
|
99
|
+
const serverHash = MinecraftEncryption.computeServerIdHash('', sharedSecret, keyPair.publicKey);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Auth Handler
|
|
103
|
+
|
|
104
|
+
```javascript
|
|
105
|
+
import { AuthHandler, ClientAuthHandler, AuthMode } from 'packet-events-js/auth/AuthHandler';
|
|
106
|
+
|
|
107
|
+
const serverAuth = new AuthHandler({ mode: AuthMode.ONLINE });
|
|
108
|
+
serverAuth.initialize();
|
|
109
|
+
|
|
110
|
+
const publicKey = serverAuth.getPublicKey();
|
|
111
|
+
const verifyToken = serverAuth.generateVerifyToken();
|
|
112
|
+
|
|
113
|
+
const offlineUUID = serverAuth.generateOfflineUUID('PlayerName');
|
|
114
|
+
|
|
115
|
+
const clientAuth = new ClientAuthHandler({
|
|
116
|
+
accessToken: 'token',
|
|
117
|
+
selectedProfile: { id: 'uuid', name: 'Name' }
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Intercept Packets
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
import { EventPriority } from 'packet-events-js/events/EventEmitter';
|
|
125
|
+
|
|
126
|
+
client.packetManager.on('packetSend', (event) => {
|
|
127
|
+
if (event.packet.packetName === 'SetPlayerPosition') {
|
|
128
|
+
console.log(`Moving to: ${event.packet.x}, ${event.packet.y}, ${event.packet.z}`);
|
|
129
|
+
|
|
130
|
+
if (event.packet.y < 0) {
|
|
131
|
+
event.cancel();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}, { priority: EventPriority.HIGH });
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Create Custom Packets
|
|
138
|
+
|
|
139
|
+
```javascript
|
|
140
|
+
import { Packet } from 'packet-events-js/protocol/packets/Packet';
|
|
141
|
+
import { defaultRegistry } from 'packet-events-js/protocol/packets/PacketRegistry';
|
|
142
|
+
import { ConnectionState } from 'packet-events-js/protocol/ConnectionState';
|
|
143
|
+
import { PacketDirection } from 'packet-events-js/protocol/PacketDirection';
|
|
144
|
+
|
|
145
|
+
class MyCustomPacket extends Packet {
|
|
146
|
+
static get packetId() { return 0x50; }
|
|
147
|
+
static get packetName() { return 'MyPacket'; }
|
|
148
|
+
|
|
149
|
+
constructor() {
|
|
150
|
+
super();
|
|
151
|
+
this.myField = 0;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
read(buffer, context) {
|
|
155
|
+
this.myField = buffer.readVarInt();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
write(buffer, context) {
|
|
159
|
+
buffer.writeVarInt(this.myField);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
defaultRegistry.register({
|
|
164
|
+
packetClass: MyCustomPacket,
|
|
165
|
+
state: ConnectionState.PLAY,
|
|
166
|
+
direction: PacketDirection.CLIENTBOUND,
|
|
167
|
+
packetId: 0x50
|
|
168
|
+
});
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Project Structure
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
PacketEvents-JS/
|
|
175
|
+
├── src/
|
|
176
|
+
│ ├── index.js
|
|
177
|
+
│ ├── auth/
|
|
178
|
+
│ │ ├── AuthHandler.js
|
|
179
|
+
│ │ └── MojangAPI.js
|
|
180
|
+
│ ├── client/
|
|
181
|
+
│ │ └── MinecraftClient.js
|
|
182
|
+
│ ├── crypto/
|
|
183
|
+
│ │ └── Encryption.js
|
|
184
|
+
│ ├── events/
|
|
185
|
+
│ │ ├── EventEmitter.js
|
|
186
|
+
│ │ └── PacketEvent.js
|
|
187
|
+
│ ├── manager/
|
|
188
|
+
│ │ └── PacketManager.js
|
|
189
|
+
│ ├── protocol/
|
|
190
|
+
│ │ ├── ConnectionState.js
|
|
191
|
+
│ │ ├── PacketDirection.js
|
|
192
|
+
│ │ ├── ProtocolVersion.js
|
|
193
|
+
│ │ ├── types/
|
|
194
|
+
│ │ │ ├── VarInt.js
|
|
195
|
+
│ │ │ ├── UUID.js
|
|
196
|
+
│ │ │ ├── Position.js
|
|
197
|
+
│ │ │ ├── NBT.js
|
|
198
|
+
│ │ │ └── TextComponent.js
|
|
199
|
+
│ │ └── packets/
|
|
200
|
+
│ │ ├── Packet.js
|
|
201
|
+
│ │ ├── PacketRegistry.js
|
|
202
|
+
│ │ ├── handshake/
|
|
203
|
+
│ │ ├── status/
|
|
204
|
+
│ │ ├── login/
|
|
205
|
+
│ │ └── play/
|
|
206
|
+
│ └── utils/
|
|
207
|
+
│ ├── PacketBuffer.js
|
|
208
|
+
│ └── Logger.js
|
|
209
|
+
└── examples/
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Main API
|
|
213
|
+
|
|
214
|
+
### MinecraftClient
|
|
215
|
+
|
|
216
|
+
```javascript
|
|
217
|
+
const client = new MinecraftClient({
|
|
218
|
+
host: string,
|
|
219
|
+
port: number,
|
|
220
|
+
version: ProtocolVersion,
|
|
221
|
+
username: string,
|
|
222
|
+
offline: boolean,
|
|
223
|
+
accessToken: string,
|
|
224
|
+
selectedProfile: object,
|
|
225
|
+
registry: PacketRegistry
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
await client.connect();
|
|
229
|
+
await client.ping();
|
|
230
|
+
await client.login();
|
|
231
|
+
await client.sendPacket(packet);
|
|
232
|
+
await client.disconnect();
|
|
233
|
+
|
|
234
|
+
client.isConnected;
|
|
235
|
+
client.isReady;
|
|
236
|
+
client.uuid;
|
|
237
|
+
client.playerName;
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### PacketBuffer
|
|
241
|
+
|
|
242
|
+
```javascript
|
|
243
|
+
import { PacketBuffer } from 'packet-events-js/utils/PacketBuffer';
|
|
244
|
+
|
|
245
|
+
const buffer = PacketBuffer.writer();
|
|
246
|
+
|
|
247
|
+
buffer.writeBoolean(true);
|
|
248
|
+
buffer.writeByte(42);
|
|
249
|
+
buffer.writeShort(1000);
|
|
250
|
+
buffer.writeInt(100000);
|
|
251
|
+
buffer.writeLong(9999999999n);
|
|
252
|
+
buffer.writeFloat(3.14);
|
|
253
|
+
buffer.writeDouble(3.14159265);
|
|
254
|
+
buffer.writeVarInt(12345);
|
|
255
|
+
buffer.writeString("Hello Minecraft");
|
|
256
|
+
buffer.writeUUID(uuid);
|
|
257
|
+
buffer.writePosition(position);
|
|
258
|
+
buffer.writeNBT(nbtCompound);
|
|
259
|
+
|
|
260
|
+
const data = buffer.getBuffer();
|
|
261
|
+
|
|
262
|
+
const reader = PacketBuffer.reader(data);
|
|
263
|
+
const bool = reader.readBoolean();
|
|
264
|
+
const num = reader.readVarInt();
|
|
265
|
+
const str = reader.readString();
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### MinecraftEncryption
|
|
269
|
+
|
|
270
|
+
```javascript
|
|
271
|
+
import { MinecraftEncryption, EncryptedConnection } from 'packet-events-js/crypto/Encryption';
|
|
272
|
+
|
|
273
|
+
const keyPair = MinecraftEncryption.generateKeyPair();
|
|
274
|
+
|
|
275
|
+
const verifyToken = MinecraftEncryption.generateVerifyToken();
|
|
276
|
+
const sharedSecret = MinecraftEncryption.generateSharedSecret();
|
|
277
|
+
|
|
278
|
+
MinecraftEncryption.encryptRSA(publicKey, data);
|
|
279
|
+
MinecraftEncryption.decryptRSA(privateKey, data);
|
|
280
|
+
|
|
281
|
+
MinecraftEncryption.encryptAES(secret, data);
|
|
282
|
+
MinecraftEncryption.decryptAES(secret, data);
|
|
283
|
+
|
|
284
|
+
MinecraftEncryption.computeServerIdHash(serverId, sharedSecret, publicKey);
|
|
285
|
+
|
|
286
|
+
const conn = new EncryptedConnection(sharedSecret);
|
|
287
|
+
conn.enable();
|
|
288
|
+
const encrypted = conn.encrypt(data);
|
|
289
|
+
const decrypted = conn.decrypt(data);
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### AuthHandler
|
|
293
|
+
|
|
294
|
+
```javascript
|
|
295
|
+
import { AuthHandler, ClientAuthHandler, AuthMode } from 'packet-events-js/auth/AuthHandler';
|
|
296
|
+
|
|
297
|
+
AuthMode.ONLINE;
|
|
298
|
+
AuthMode.OFFLINE;
|
|
299
|
+
AuthMode.BUNGEECORD;
|
|
300
|
+
AuthMode.VELOCITY;
|
|
301
|
+
|
|
302
|
+
const handler = new AuthHandler({ mode: AuthMode.ONLINE });
|
|
303
|
+
handler.initialize();
|
|
304
|
+
handler.getPublicKey();
|
|
305
|
+
handler.generateVerifyToken();
|
|
306
|
+
handler.generateOfflineUUID(username);
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### EventEmitter
|
|
310
|
+
|
|
311
|
+
```javascript
|
|
312
|
+
import { EventPriority } from 'packet-events-js/events/EventEmitter';
|
|
313
|
+
|
|
314
|
+
EventPriority.LOWEST;
|
|
315
|
+
EventPriority.LOW;
|
|
316
|
+
EventPriority.NORMAL;
|
|
317
|
+
EventPriority.HIGH;
|
|
318
|
+
EventPriority.HIGHEST;
|
|
319
|
+
EventPriority.MONITOR;
|
|
320
|
+
|
|
321
|
+
emitter.on('event', callback, { priority: EventPriority.HIGH });
|
|
322
|
+
|
|
323
|
+
emitter.on('packet', (event) => {
|
|
324
|
+
event.cancel();
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
await emitter.emitAsync('event', data);
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### TextComponent
|
|
331
|
+
|
|
332
|
+
```javascript
|
|
333
|
+
import { TextComponent, ChatColor } from 'packet-events-js/protocol/types/TextComponent';
|
|
334
|
+
|
|
335
|
+
const message = TextComponent.text('Hello!')
|
|
336
|
+
.color(ChatColor.GREEN)
|
|
337
|
+
.bold()
|
|
338
|
+
.append(
|
|
339
|
+
TextComponent.text(' World')
|
|
340
|
+
.color(ChatColor.YELLOW)
|
|
341
|
+
.italic()
|
|
342
|
+
)
|
|
343
|
+
.clickEvent('run_command', '/help')
|
|
344
|
+
.showText(TextComponent.text('Click for help'));
|
|
345
|
+
|
|
346
|
+
const json = message.toString();
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## Supported Versions
|
|
350
|
+
|
|
351
|
+
66 versions supported from **1.7.2** to **1.21.11**:
|
|
352
|
+
|
|
353
|
+
| Range | Versions |
|
|
354
|
+
|-------|----------|
|
|
355
|
+
| 1.21.x | 1.21.11, 1.21.10, 1.21.9, 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21 |
|
|
356
|
+
| 1.20.x | 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20 |
|
|
357
|
+
| 1.19.x | 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19 |
|
|
358
|
+
| 1.18.x | 1.18.2, 1.18.1, 1.18 |
|
|
359
|
+
| 1.17.x | 1.17.1, 1.17 |
|
|
360
|
+
| 1.16.x | 1.16.5, 1.16.4, 1.16.3, 1.16.2, 1.16.1, 1.16 |
|
|
361
|
+
| 1.15.x | 1.15.2, 1.15.1, 1.15 |
|
|
362
|
+
| 1.14.x | 1.14.4, 1.14.3, 1.14.2, 1.14.1, 1.14 |
|
|
363
|
+
| 1.13.x | 1.13.2, 1.13.1, 1.13 |
|
|
364
|
+
| 1.12.x | 1.12.2, 1.12.1, 1.12 |
|
|
365
|
+
| 1.11.x | 1.11.2, 1.11.1, 1.11 |
|
|
366
|
+
| 1.10.x | 1.10.2, 1.10.1, 1.10 |
|
|
367
|
+
| 1.9.x | 1.9.4, 1.9.3, 1.9.2, 1.9.1, 1.9 |
|
|
368
|
+
| 1.8.x | 1.8.9, 1.8.8, 1.8.7, 1.8.6, 1.8.5, 1.8.4, 1.8.3, 1.8.2, 1.8.1, 1.8 |
|
|
369
|
+
| 1.7.x | 1.7.10, 1.7.9, 1.7.6, 1.7.5, 1.7.4, 1.7.2 |
|
|
370
|
+
|
|
371
|
+
## Examples
|
|
372
|
+
|
|
373
|
+
See the [examples](./examples) folder for complete usage examples:
|
|
374
|
+
|
|
375
|
+
- `basic-client.js` - Basic client connection
|
|
376
|
+
- `server-ping.js` - Server list ping
|
|
377
|
+
- `packet-types.js` - All packet types demonstration
|
|
378
|
+
- `encryption.js` - Encryption usage
|
|
379
|
+
- `authentication.js` - Authentication modes
|
|
380
|
+
- `event-system.js` - Event system usage
|
|
381
|
+
- `packet-buffer.js` - PacketBuffer operations
|
|
382
|
+
- `data-types.js` - Protocol data types
|
|
383
|
+
- `protocol-versions.js` - Protocol version utilities
|
|
384
|
+
- `connection-flows.js` - Connection flow examples
|
|
385
|
+
- `custom-packets.js` - Custom packet creation
|
|
386
|
+
- `packet-interception.js` - Packet interception
|
|
387
|
+
|
|
388
|
+
## References
|
|
389
|
+
|
|
390
|
+
This project is inspired by:
|
|
391
|
+
|
|
392
|
+
- [PacketEvents](https://github.com/retrooper/packetevents) - Original Java library
|
|
393
|
+
- [wiki.vg Protocol](https://wiki.vg/Protocol) - Protocol documentation
|
|
394
|
+
- [MCProtocolLib](https://github.com/GeyserMC/MCProtocolLib) - Reference implementation
|
|
395
|
+
|
|
396
|
+
## License
|
|
397
|
+
|
|
398
|
+
MIT License
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "packet-events-js",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A protocol library for Minecraft Java Edition in pure JavaScript",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"src"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node src/index.js",
|
|
12
|
+
"example": "node examples/basic-client.js",
|
|
13
|
+
"test": "node examples/packet-types.js && node examples/data-types.js && node examples/encryption.js"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"minecraft",
|
|
17
|
+
"protocol",
|
|
18
|
+
"packets",
|
|
19
|
+
"java-edition",
|
|
20
|
+
"networking"
|
|
21
|
+
],
|
|
22
|
+
"author": "",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/FrannnnDev/PacketEvents-JS.git"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18.0.0"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { MinecraftEncryption, EncryptedConnection } from '../crypto/Encryption.js';
|
|
2
|
+
import { MojangAPI } from './MojangAPI.js';
|
|
3
|
+
import { UUID } from '../protocol/types/UUID.js';
|
|
4
|
+
|
|
5
|
+
export const AuthMode = Object.freeze({
|
|
6
|
+
ONLINE: 'online',
|
|
7
|
+
OFFLINE: 'offline',
|
|
8
|
+
BUNGEECORD: 'bungeecord',
|
|
9
|
+
VELOCITY: 'velocity'
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export class AuthHandler {
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
this.mode = options.mode || AuthMode.OFFLINE;
|
|
15
|
+
this.preventProxyConnections = options.preventProxyConnections || false;
|
|
16
|
+
this.velocitySecret = options.velocitySecret || null;
|
|
17
|
+
this.keyPair = null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
initialize() {
|
|
21
|
+
if (this.mode === AuthMode.ONLINE) {
|
|
22
|
+
this.keyPair = MinecraftEncryption.generateKeyPair();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getPublicKey() {
|
|
27
|
+
if (!this.keyPair) return null;
|
|
28
|
+
return this.keyPair.publicKey;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
generateVerifyToken() {
|
|
32
|
+
return MinecraftEncryption.generateVerifyToken();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
decryptVerifyToken(encryptedToken) {
|
|
36
|
+
if (!this.keyPair) throw new Error('No key pair available');
|
|
37
|
+
return MinecraftEncryption.decryptRSA(this.keyPair.privateKey, encryptedToken);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
decryptSharedSecret(encryptedSecret) {
|
|
41
|
+
if (!this.keyPair) throw new Error('No key pair available');
|
|
42
|
+
return MinecraftEncryption.decryptRSA(this.keyPair.privateKey, encryptedSecret);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
computeServerHash(sharedSecret) {
|
|
46
|
+
if (!this.keyPair) throw new Error('No key pair available');
|
|
47
|
+
return MinecraftEncryption.computeServerIdHash('', sharedSecret, this.keyPair.publicKey);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
createEncryptedConnection(sharedSecret) {
|
|
51
|
+
return new EncryptedConnection(sharedSecret);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async verifyPlayer(username, serverHash, clientIP = null) {
|
|
55
|
+
if (this.mode !== AuthMode.ONLINE) {
|
|
56
|
+
return {
|
|
57
|
+
success: true,
|
|
58
|
+
uuid: UUID.offlinePlayerUUID(username).toString(false),
|
|
59
|
+
name: username,
|
|
60
|
+
properties: []
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const ip = this.preventProxyConnections ? clientIP : null;
|
|
65
|
+
return await MojangAPI.hasJoinedServer(username, serverHash, ip);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
generateOfflineUUID(username) {
|
|
69
|
+
return UUID.offlinePlayerUUID(username);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async authenticate(username, encryptedSharedSecret, encryptedVerifyToken, originalVerifyToken, clientIP = null) {
|
|
73
|
+
const verifyToken = this.decryptVerifyToken(encryptedVerifyToken);
|
|
74
|
+
|
|
75
|
+
if (!verifyToken.equals(originalVerifyToken)) {
|
|
76
|
+
return { success: false, reason: 'INVALID_VERIFY_TOKEN' };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const sharedSecret = this.decryptSharedSecret(encryptedSharedSecret);
|
|
80
|
+
|
|
81
|
+
if (sharedSecret.length !== 16) {
|
|
82
|
+
return { success: false, reason: 'INVALID_SHARED_SECRET' };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const serverHash = this.computeServerHash(sharedSecret);
|
|
86
|
+
const verification = await this.verifyPlayer(username, serverHash, clientIP);
|
|
87
|
+
|
|
88
|
+
if (!verification.success) {
|
|
89
|
+
return { success: false, reason: verification.reason || 'AUTHENTICATION_FAILED' };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const encryptedConnection = this.createEncryptedConnection(sharedSecret);
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
success: true,
|
|
96
|
+
uuid: verification.uuid,
|
|
97
|
+
name: verification.name,
|
|
98
|
+
properties: verification.properties || [],
|
|
99
|
+
encryption: encryptedConnection,
|
|
100
|
+
sharedSecret
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export class ClientAuthHandler {
|
|
106
|
+
constructor(options = {}) {
|
|
107
|
+
this.accessToken = options.accessToken || null;
|
|
108
|
+
this.profileId = options.profileId || null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async authenticateWithServer(serverPublicKey, verifyToken, serverId = '') {
|
|
112
|
+
const sharedSecret = MinecraftEncryption.generateSharedSecret();
|
|
113
|
+
|
|
114
|
+
const encryptedSharedSecret = MinecraftEncryption.encryptRSA(serverPublicKey, sharedSecret);
|
|
115
|
+
const encryptedVerifyToken = MinecraftEncryption.encryptRSA(serverPublicKey, verifyToken);
|
|
116
|
+
|
|
117
|
+
const serverHash = MinecraftEncryption.computeServerIdHash(serverId, sharedSecret, serverPublicKey);
|
|
118
|
+
|
|
119
|
+
if (this.accessToken && this.profileId) {
|
|
120
|
+
const result = await MojangAPI.joinServer(this.accessToken, this.profileId, serverHash);
|
|
121
|
+
if (!result.success) {
|
|
122
|
+
return { success: false, reason: result.error || 'JOIN_FAILED' };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const encryptedConnection = new EncryptedConnection(sharedSecret);
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
success: true,
|
|
130
|
+
encryptedSharedSecret,
|
|
131
|
+
encryptedVerifyToken,
|
|
132
|
+
encryption: encryptedConnection,
|
|
133
|
+
sharedSecret
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export default AuthHandler;
|