baltica 2.0.8 → 2.0.10

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.
@@ -13,6 +13,7 @@ export declare class Client extends Emitter<ClientEvents> {
13
13
  loginData: LoginData;
14
14
  stopPastLogin: boolean;
15
15
  startGameData: StartGamePacket;
16
+ private isDisconnected;
16
17
  constructor(options: Partial<ClientOptions>);
17
18
  connect(): Promise<void>;
18
19
  private registerHandshakeHandlers;
@@ -20,6 +20,7 @@ class Client extends utils_1.Emitter {
20
20
  loginData;
21
21
  stopPastLogin = false;
22
22
  startGameData;
23
+ isDisconnected = false;
23
24
  constructor(options) {
24
25
  super();
25
26
  this.options = { ...types_1.defaultClientOptions, ...options };
@@ -137,15 +138,22 @@ class Client extends utils_1.Emitter {
137
138
  }
138
139
  close() {
139
140
  try {
140
- this.raknet.close();
141
+ if (this.raknet && typeof this.raknet.close === "function") {
142
+ this.raknet.close();
143
+ }
141
144
  }
142
145
  catch { }
143
146
  this.removeAllListeners();
144
147
  }
145
148
  disconnect(reason = "client disconnect") {
149
+ if (this.isDisconnected)
150
+ return;
151
+ this.isDisconnected = true;
146
152
  this.emit("disconnect", reason);
147
153
  setTimeout(() => {
148
- this.raknet.disconnect();
154
+ if (this.raknet && typeof this.raknet.disconnect === "function") {
155
+ this.raknet.disconnect();
156
+ }
149
157
  this.removeAllListeners();
150
158
  }, 50);
151
159
  }
@@ -221,6 +229,8 @@ class Client extends utils_1.Emitter {
221
229
  this.sendUncompressed(request.serialize(), raknet_1.Priority.High);
222
230
  }
223
231
  send(packet, priority = raknet_1.Priority.Medium, compressionMethod) {
232
+ if (this.isDisconnected)
233
+ return;
224
234
  try {
225
235
  const compressed = this.packetCompressor.compress(packet, compressionMethod);
226
236
  this.raknet.sendReliable(compressed, priority);
@@ -11,6 +11,7 @@ export declare class Player extends Emitter<PlayerEvents> {
11
11
  connection: Connection;
12
12
  username: string;
13
13
  xuid: string;
14
+ private isDisconnected;
14
15
  private privateKey;
15
16
  private publicKeyDER;
16
17
  private clientX509;
@@ -51,6 +51,7 @@ class Player extends utils_1.Emitter {
51
51
  connection;
52
52
  username = "";
53
53
  xuid = "";
54
+ isDisconnected = false;
54
55
  privateKey;
55
56
  publicKeyDER;
56
57
  clientX509;
@@ -184,6 +185,8 @@ class Player extends utils_1.Emitter {
184
185
  }
185
186
  }
186
187
  send(packet, priority = raknet_1.Priority.High, compressionMethod) {
188
+ if (this.isDisconnected)
189
+ return;
187
190
  try {
188
191
  const compressed = this.packetCompressor.compress(packet, compressionMethod);
189
192
  this.connection.send(compressed, priority);
@@ -203,6 +206,9 @@ class Player extends utils_1.Emitter {
203
206
  this.connection.send(buf, priority);
204
207
  }
205
208
  disconnect(reason = "disconnected") {
209
+ if (this.isDisconnected)
210
+ return;
211
+ this.isDisconnected = true;
206
212
  utils_1.Logger.info(`Disconnecting ${this.username || "player"}: ${reason}`);
207
213
  this.connection.disconnect();
208
214
  this.emit("disconnect");
@@ -67,26 +67,45 @@ class PacketEncryptor {
67
67
  return Buffer.from(new Uint8Array(hash.subarray(0, 8)));
68
68
  }
69
69
  encryptPacket(payload) {
70
- if (!this.cipher)
71
- throw new Error("Cipher not initialized");
72
- const checksum = this.computeCheckSum(payload, this.sendCounter);
73
- const toEncrypt = Buffer.concat([payload, checksum]);
74
- const encrypted = this.cipher.update(toEncrypt);
75
- this.sendCounter++;
76
- return Buffer.concat([Buffer.from([0xfe]), encrypted]);
70
+ if (!this.cipher) {
71
+ // Cipher destroyed - return unencrypted
72
+ return Buffer.concat([Buffer.from([0xfe]), payload]);
73
+ }
74
+ try {
75
+ const checksum = this.computeCheckSum(payload, this.sendCounter);
76
+ const toEncrypt = Buffer.concat([payload, checksum]);
77
+ const encrypted = this.cipher.update(toEncrypt);
78
+ this.sendCounter++;
79
+ return Buffer.concat([Buffer.from([0xfe]), encrypted]);
80
+ }
81
+ catch {
82
+ // Cipher in invalid state - return unencrypted
83
+ return Buffer.concat([Buffer.from([0xfe]), payload]);
84
+ }
77
85
  }
78
86
  decryptPacket(encryptedPayload) {
79
- if (!this.decipher)
80
- throw new Error("Decipher not initialized");
81
- const decrypted = this.decipher.update(encryptedPayload);
82
- const packet = decrypted.subarray(0, decrypted.length - 8);
83
- const receivedChecksum = decrypted.subarray(decrypted.length - 8);
84
- const computedChecksum = this.computeCheckSum(packet, this.receiveCounter);
85
- this.receiveCounter++;
86
- if (!receivedChecksum.equals(computedChecksum)) {
87
- throw new Error("Checksum mismatch");
87
+ if (!this.decipher) {
88
+ // Decipher destroyed - return as-is
89
+ return encryptedPayload;
90
+ }
91
+ try {
92
+ const decrypted = this.decipher.update(encryptedPayload);
93
+ const packet = decrypted.subarray(0, decrypted.length - 8);
94
+ const receivedChecksum = decrypted.subarray(decrypted.length - 8);
95
+ const computedChecksum = this.computeCheckSum(packet, this.receiveCounter);
96
+ this.receiveCounter++;
97
+ if (!receivedChecksum.equals(computedChecksum)) {
98
+ throw new Error("Checksum mismatch");
99
+ }
100
+ return packet;
101
+ }
102
+ catch (err) {
103
+ // Re-throw checksum errors, ignore cipher state errors
104
+ if (err instanceof Error && err.message === "Checksum mismatch") {
105
+ throw err;
106
+ }
107
+ return encryptedPayload;
88
108
  }
89
- return packet;
90
109
  }
91
110
  }
92
111
  exports.PacketEncryptor = PacketEncryptor;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baltica",
3
- "version": "2.0.8",
3
+ "version": "2.0.10",
4
4
  "description": "Core baltica package",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",