@@ -4,19 +4,10 @@ import {
4
4
NativeModules
5
5
} from 'react-native'
6
6
import events from 'events'
7
- import { createHash , publicEncrypt } from 'react-native-crypto'
8
- import { concatPacketData , Packet , PacketDataTypes } from '../packet'
9
- import {
10
- readVarInt ,
11
- writeVarInt ,
12
- resolveHostname ,
13
- mcHexDigest ,
14
- protocolMap ,
15
- getRandomBytes
16
- } from '../utils'
17
- import { joinMinecraftSession } from '../api/mojang'
18
7
import { ServerConnection , ConnectionOptions } from '.'
19
- import { getLoginPacket , parseEncryptionRequestPacket } from './shared'
8
+ import { concatPacketData , Packet } from '../packet'
9
+ import { getLoginPacket , handleEncryptionRequest } from './shared'
10
+ import { readVarInt , writeVarInt , resolveHostname , protocolMap } from '../utils'
20
11
21
12
const { ConnectionModule } = NativeModules
22
13
@@ -65,6 +56,10 @@ export class NativeServerConnection
65
56
this . eventEmitter . addListener ( 'packet' , ( event : NativePacketEvent ) => {
66
57
console . log ( event )
67
58
if ( event . connectionId !== this . id ) return
59
+ // Handle timeout after 20 seconds of no data. (TODO: Handle this natively.)
60
+ if ( this . disconnectTimer ) clearTimeout ( this . disconnectTimer )
61
+ this . disconnectTimer = setTimeout ( ( ) => this . close ( ) , 20000 )
62
+ // Run after interactions to improve user experience.
68
63
InteractionManager . runAfterInteractions ( ( ) => {
69
64
const packet : Packet = {
70
65
id : event . id ,
@@ -75,16 +70,15 @@ export class NativeServerConnection
75
70
lengthLength : event . lengthLength
76
71
}
77
72
78
- // Internally handle login packets.
79
- // We aren't handling these in native for improved code sharing.
80
- // TODO: Actually share code with the JavaScript back-end.
73
+ // Internally handle login packets. We aren't handling these in native to share code.
81
74
const is1164 = options . protocolVersion >= protocolMap [ '1.16.4' ]
82
75
const is117 = options . protocolVersion >= protocolMap [ 1.17 ]
83
76
const is119 = options . protocolVersion >= protocolMap [ 1.19 ]
84
77
const is1191 = options . protocolVersion >= protocolMap [ '1.19.1' ]
85
78
// Set Compression and Keep Alive are handled in native for now.
86
- if ( packet . id === 0x02 && ! this . loggedIn ) {
87
- this . loggedIn = true // Login Success
79
+ // When modifying this code, apply the same changes to the JavaScript back-end.
80
+ if ( packet . id === 0x02 && ! this . loggedIn /* Login Success */ ) {
81
+ this . loggedIn = true
88
82
} else if (
89
83
// Disconnect (login) or Disconnect (play)
90
84
( packet . id === 0x00 && ! this . loggedIn ) ||
@@ -111,56 +105,19 @@ export class NativeServerConnection
111
105
this . close ( )
112
106
return
113
107
}
114
- // https://wiki.vg/Protocol_Encryption
115
- const [ serverId , publicKey , verifyToken ] =
116
- parseEncryptionRequestPacket ( packet )
117
- ; ( async ( ) => {
118
- const secret = await getRandomBytes ( 16 ) // Generate random 16-byte shared secret.
119
- // Generate hash.
120
- const sha1 = createHash ( 'sha1' )
121
- sha1 . update ( serverId ) // ASCII encoding of the server id string from Encryption Request
122
- sha1 . update ( secret )
123
- sha1 . update ( publicKey ) // Server's encoded public key from Encryption Request
124
- const hash = mcHexDigest ( sha1 . digest ( ) )
125
- // Send hash to Mojang servers.
126
- const req = await joinMinecraftSession (
127
- accessToken ,
128
- selectedProfile ,
129
- hash
130
- )
131
- if ( ! req . ok ) {
132
- throw new Error ( 'Mojang online mode network request failed' )
133
- }
134
- // Encrypt shared secret and verify token with public key.
135
- const pk =
136
- '-----BEGIN PUBLIC KEY-----\n' +
137
- publicKey . toString ( 'base64' ) +
138
- '\n-----END PUBLIC KEY-----'
139
- const ePrms = { key : pk , padding : 1 } // RSA_PKCS1_PADDING
140
- const encryptedSharedSecret = publicEncrypt ( ePrms , secret )
141
- const encryptedVerifyToken = publicEncrypt ( ePrms , verifyToken )
142
- // Send encryption response packet.
143
- // From this point forward, everything is encrypted, including the Login Success packet.
144
- const response : PacketDataTypes [ ] = [
145
- writeVarInt ( encryptedSharedSecret . byteLength ) ,
146
- encryptedSharedSecret ,
147
- writeVarInt ( encryptedVerifyToken . byteLength ) ,
148
- encryptedVerifyToken
149
- ]
150
- if ( is119 ) {
151
- this . msgSalt = await getRandomBytes ( 8 )
152
- response . splice ( 2 , 0 , true )
108
+ handleEncryptionRequest (
109
+ packet ,
110
+ accessToken ,
111
+ selectedProfile ,
112
+ this ,
113
+ is119 ,
114
+ async ( secret : Buffer , response : Buffer ) => {
115
+ // const AES_ALG = 'aes-128-cfb8'
116
+ // conn.aesDecipher = createDecipheriv(AES_ALG, secret, secret)
117
+ await this . writePacket ( 0x01 , response )
118
+ // conn.aesCipher = createCipheriv(AES_ALG, secret, secret)
153
119
}
154
- // const AES_ALG = 'aes-128-cfb8'
155
- // this.aesDecipher = createDecipheriv(AES_ALG, secret, secret)
156
- await this . writePacket ( 0x01 , concatPacketData ( response ) )
157
- // this.aesCipher = createCipheriv(AES_ALG, secret, secret)
158
- } ) ( ) . catch ( e => {
159
- console . error ( e )
160
- this . disconnectReason =
161
- '{"text":"Failed to authenticate with Mojang servers!"}'
162
- this . close ( )
163
- } )
120
+ )
164
121
}
165
122
166
123
this . emit ( 'packet' , packet )
@@ -200,7 +157,7 @@ export class NativeServerConnection
200
157
201
158
const initiateNativeConnection = async ( opts : ConnectionOptions ) => {
202
159
const [ host , port ] = await resolveHostname ( opts . host , opts . port )
203
- const id = await ConnectionModule . createConnection ( {
160
+ const id = await ConnectionModule . openConnection ( {
204
161
loginPacket : getLoginPacket ( opts ) . toString ( 'base64' ) ,
205
162
...opts ,
206
163
host,
0 commit comments