@@ -23,9 +23,9 @@ import {
23
23
readVarInt ,
24
24
writeVarInt ,
25
25
resolveHostname ,
26
- generateSharedSecret ,
27
26
mcHexDigest ,
28
- protocolMap
27
+ protocolMap ,
28
+ getRandomBytes
29
29
} from './utils'
30
30
import { Certificate , joinMinecraftSession } from './api/mojang'
31
31
@@ -59,6 +59,7 @@ export class ServerConnection extends events.EventEmitter {
59
59
disconnectReason ?: string
60
60
aesDecipher ?: Decipher
61
61
aesCipher ?: Cipher
62
+ msgSalt ?: Buffer
62
63
63
64
constructor ( socket : net . Socket , options : ConnectionOptions ) {
64
65
super ( )
@@ -180,39 +181,44 @@ const initiateConnection = async (opts: ConnectionOptions) => {
180
181
? Buffer . alloc ( 0 ) // Avoid errors shortening.
181
182
: conn . bufferedData . slice ( packet . packetLength )
182
183
// Internally handle login packets.
183
- if ( packet . id === 0x03 && ! conn . loggedIn ) {
184
+ const is119 = conn . options . protocolVersion >= protocolMap [ 1.19 ]
185
+ if ( packet . id === 0x03 && ! conn . loggedIn /* Set Compression */ ) {
184
186
const [ threshold ] = readVarInt ( packet . data )
185
187
conn . compressionThreshold = threshold
186
188
conn . compressionEnabled = threshold >= 0
187
189
} else if ( packet . id === 0x02 && ! conn . loggedIn ) {
188
- conn . loggedIn = true
189
- } else if ( packet . id === 0x21 ) {
190
+ conn . loggedIn = true // Login Success
191
+ } else if (
192
+ // Keep Alive (clientbound)
193
+ ( packet . id === 0x21 && ! is119 ) ||
194
+ ( packet . id === 0x1e && is119 )
195
+ ) {
190
196
conn
191
- . writePacket ( 0x0f , packet . data )
197
+ . writePacket ( is119 ? 0x11 : 0x0f , packet . data )
192
198
. catch ( err => conn . emit ( 'error' , err ) )
193
199
} else if (
200
+ // Disconnect (login) or Disconnect (play)
194
201
( packet . id === 0x00 && ! conn . loggedIn ) ||
195
- ( packet . id === 0x1a &&
196
- conn . loggedIn &&
197
- opts . protocolVersion < protocolMap [ 1.19 ] ) ||
198
- ( packet . id === 0x17 &&
199
- conn . loggedIn &&
200
- opts . protocolVersion >= protocolMap [ 1.19 ] )
202
+ ( packet . id === 0x1a && conn . loggedIn && ! is119 ) ||
203
+ ( packet . id === 0x17 && conn . loggedIn && is119 )
201
204
) {
202
205
const [ chatLength , chatVarIntLength ] = readVarInt ( packet . data )
203
206
conn . disconnectReason = packet . data
204
207
. slice ( chatVarIntLength , chatVarIntLength + chatLength )
205
208
. toString ( 'utf8' )
206
- } else if ( packet . id === 0x01 && ! conn . loggedIn && ! accessToken ) {
207
- conn . disconnectReason =
208
- '{"text":"This server requires a premium account to be logged in!"}'
209
- conn . close ( )
210
209
} else if ( packet . id === 0x01 && ! conn . loggedIn ) {
210
+ /* Encryption Request */
211
+ if ( ! accessToken || ! selectedProfile ) {
212
+ conn . disconnectReason =
213
+ '{"text":"This server requires a premium account to be logged in!"}'
214
+ conn . close ( )
215
+ continue
216
+ }
211
217
// https://wiki.vg/Protocol_Encryption
212
218
const [ serverId , publicKey , verifyToken ] =
213
219
parseEncryptionRequestPacket ( packet )
214
220
; ( async ( ) => {
215
- const secret = await generateSharedSecret ( ) // Generate random 16-byte shared secret.
221
+ const secret = await getRandomBytes ( 16 ) // Generate random 16-byte shared secret.
216
222
// Generate hash.
217
223
const sha1 = createHash ( 'sha1' )
218
224
sha1 . update ( serverId ) // ASCII encoding of the server id string from Encryption Request
@@ -221,8 +227,8 @@ const initiateConnection = async (opts: ConnectionOptions) => {
221
227
const hash = mcHexDigest ( sha1 . digest ( ) )
222
228
// Send hash to Mojang servers.
223
229
const req = await joinMinecraftSession (
224
- accessToken as string ,
225
- selectedProfile as string ,
230
+ accessToken ,
231
+ selectedProfile ,
226
232
hash
227
233
)
228
234
if ( ! req . ok ) {
@@ -244,7 +250,8 @@ const initiateConnection = async (opts: ConnectionOptions) => {
244
250
writeVarInt ( encryptedVerifyToken . byteLength ) ,
245
251
encryptedVerifyToken
246
252
]
247
- if ( opts . protocolVersion >= protocolMap [ 1.19 ] ) {
253
+ if ( is119 ) {
254
+ conn . msgSalt = await getRandomBytes ( 8 )
248
255
response . splice ( 2 , 0 , true )
249
256
}
250
257
const AES_ALG = 'aes-128-cfb8'
0 commit comments