Skip to content

Commit 040341a

Browse files
committed
Fix BigInt, a crash and needing to relog every day
This is done by adding refresh support to ServerScreen. This can cause a slight delay for the first connection. A loading screen should be implemented for this.
1 parent 2540aee commit 040341a

File tree

8 files changed

+120
-47
lines changed

8 files changed

+120
-47
lines changed

index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import { AppRegistry } from 'react-native'
88
import App from './src/App'
99
import { name as appName } from './app.json'
1010

11+
global.BigInt = require('jsbi').BigInt
1112
global.Buffer = require('buffer').Buffer
1213
// global.process = require('process');
1314
global.process.env.NODE_ENV = __DEV__ ? 'development' : 'production'
14-
if (typeof BigInt === 'undefined') global.BigInt = require('big-integer')
1515

1616
// Needed so that 'stream-http' chooses the right default protocol.
1717
global.location = {

package-lock.json

+11-14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@
1919
"@react-navigation/native": "^6.0.2",
2020
"@react-navigation/native-stack": "^6.1.0",
2121
"assert": "^2.0.0",
22-
"big-integer": "^1.6.51",
2322
"browserify-zlib": "^0.2.0",
2423
"buffer": "^6.0.3",
2524
"events": "^3.3.0",
25+
"jsbi": "^3.2.5",
2626
"promise.allsettled": "^1.0.4",
2727
"react": "18.0.0",
2828
"react-native": "0.69.1",

src/minecraft/api/microsoft.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,16 @@ export const refreshMSAuthToken = async (
4343
): Promise<[string, string]> => {
4444
const body = `client_id=${clientId}
4545
&scope=${encodeURIComponent(scope)}
46-
&code=${encodeURIComponent(refreshToken)}
46+
&refresh_token=${encodeURIComponent(refreshToken)}
4747
&grant_type=refresh_token
4848
&redirect_uri=${encodeURIComponent(redirectUri)}`
4949
const req = await fetch(authTokenUrl, {
5050
method: 'POST',
5151
body,
5252
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
5353
})
54-
const res = await req.json()
5554
if (!req.ok) throw new Error('Failed to request auth token from Microsoft!')
55+
const res = await req.json()
5656
// { "expires_in":86400 }
5757
return [res.access_token, res.refresh_token]
5858
}

src/minecraft/api/mojang.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ export const getPlayerCertificates = async (accessToken: string) =>
3030
await fetch(getPlayerCertificatesUrl, {
3131
headers: { Authorization: 'Bearer ' + accessToken },
3232
method: 'POST'
33-
})
33+
}).then(async res => (await res.json()) as Certificate)

src/minecraft/chatToJsx.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ const parseChatToJsx = (
177177
) => {
178178
if (typeof chat !== 'string' && (chat as TranslatedChat).translate) {
179179
const translatedChat = chat as TranslatedChat
180+
if (!translatedChat.with) translatedChat.with = []
180181
const translation = translations[translatedChat.translate]
181182
?.split('%s')
182183
?.map((text, index) => [{ text }, translatedChat.with[index]])

src/screens/ServerScreen.tsx

+98-23
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,22 @@ import AccountsContext from '../context/accountsContext'
2929
import ConnectionContext from '../context/connectionContext'
3030
import { resolveHostname, protocolMap } from '../minecraft/utils'
3131
import initiateConnection from '../minecraft/connection'
32+
import {
33+
refreshMSAuthToken,
34+
getXboxLiveTokenAndUserHash,
35+
getXstsTokenAndUserHash,
36+
authenticateWithXsts
37+
} from '../minecraft/api/microsoft'
38+
import { Certificate, getPlayerCertificates } from '../minecraft/api/mojang'
39+
import { refresh } from '../minecraft/api/yggdrasil'
3240
import {
3341
ChatToJsx,
3442
lightColorMap,
3543
mojangColorMap,
3644
parseValidJson
3745
} from '../minecraft/chatToJsx'
3846
import useDarkMode from '../context/useDarkMode'
47+
import config from '../../config.json'
3948

4049
const parseIp = (ipAddress: string): [string, number] => {
4150
const splitAddr = ipAddress.split(':')
@@ -48,10 +57,15 @@ const parseIp = (ipAddress: string): [string, number] => {
4857
return [splitAddr.join(':'), port]
4958
}
5059

60+
interface Session {
61+
certificate?: Certificate
62+
accessToken: string
63+
}
64+
5165
const ServerScreen = () => {
5266
const darkMode = useDarkMode()
5367
const { servers, setServers } = useContext(ServersContext)
54-
const { accounts } = useContext(AccountsContext)
68+
const { accounts, setAccounts } = useContext(AccountsContext)
5569
const { connection, setConnection, setDisconnectReason } =
5670
useContext(ConnectionContext)
5771
const initiatingConnection = useRef(false)
@@ -70,6 +84,7 @@ const ServerScreen = () => {
7084
// false - no route, null - unknown err, undefined - pinging
7185
[ip: string]: LegacyPing | Ping | false | null | undefined
7286
}>({})
87+
const [sessions, setSessions] = useState<{ [uuid: string]: Session }>({})
7388

7489
useEffect(() => {
7590
if (Object.keys(pingResponses).length > 0) {
@@ -103,12 +118,14 @@ const ServerScreen = () => {
103118
}, [servers, pingResponses])
104119

105120
const invalidServerName = newServerName.length > 32
121+
106122
const openEditServerDialog = (server: string) => {
107123
setEditServerDialogOpen(server)
108124
setNewServerName(server)
109125
setServerVersion(servers[server].version)
110126
setIpAddr(servers[server].address)
111127
}
128+
112129
const cancelAddServer = () => {
113130
setEditServerDialogOpen(false)
114131
setServerVersion('auto')
@@ -117,12 +134,14 @@ const ServerScreen = () => {
117134
setIpAddrRed(false)
118135
setServerNameRed(false)
119136
}
137+
120138
const deleteServer = () => {
121139
if (typeof editServerDialogOpen !== 'string') return cancelAddServer()
122140
delete servers[editServerDialogOpen]
123141
setServers(servers)
124142
cancelAddServer()
125143
}
144+
126145
const editServer = () => {
127146
const edit = typeof editServerDialogOpen === 'string'
128147
if (
@@ -142,6 +161,7 @@ const ServerScreen = () => {
142161
setPingResponses({})
143162
cancelAddServer()
144163
}
164+
145165
const connectToServer = async (server: string) => {
146166
if (initiatingConnection.current) return
147167
if (!connection) {
@@ -173,31 +193,86 @@ const ServerScreen = () => {
173193
reason: 'EnderChat only supports 1.16.4 and newer (for now).'
174194
})
175195
}
176-
// TODO: Refresh token before trying to connect.
177196
const uuid = accounts[activeAccount].type ? activeAccount : undefined
178-
const newConn = await initiateConnection({
179-
host,
180-
port,
181-
username: accounts[activeAccount].username,
182-
protocolVersion,
183-
selectedProfile: uuid,
184-
accessToken: accounts[activeAccount].accessToken
185-
})
186-
const onCloseOrError: () => void = () => {
187-
setConnection(undefined)
188-
if (newConn.disconnectReason) {
189-
setDisconnectReason({
190-
server,
191-
reason: parseValidJson(newConn.disconnectReason)
192-
})
197+
198+
// Create an updated "session" containing access tokens and certificates.
199+
// LOW-TODO: Creating a session would be better with a loading screen, since Microsoft Login is slow.
200+
// Maybe setConnection(null) to bring up ChatScreen while still being in a logged out state?
201+
let session = sessions[activeAccount]
202+
const is119 = protocolVersion >= protocolMap[1.19]
203+
if (uuid && (!session || (!session.certificate && is119))) {
204+
// LOW-TODO: Certificates and access tokens should be updated regularly.
205+
try {
206+
// Create a session with the latest access token.
207+
const account = accounts[activeAccount]
208+
if (!session && accounts[activeAccount].type === 'microsoft') {
209+
const [msAccessToken, msRefreshToken] = await refreshMSAuthToken(
210+
accounts[activeAccount].microsoftRefreshToken || '',
211+
config.clientId,
212+
config.scope
213+
)
214+
const [xlt, xuh] = await getXboxLiveTokenAndUserHash(msAccessToken)
215+
const [xstsToken] = await getXstsTokenAndUserHash(xlt)
216+
const accessToken = await authenticateWithXsts(xstsToken, xuh)
217+
session = { accessToken }
218+
setAccounts({
219+
[activeAccount]: {
220+
...account,
221+
accessToken,
222+
microsoftAccessToken: msAccessToken,
223+
microsoftRefreshToken: msRefreshToken
224+
}
225+
})
226+
} else if (!session && accounts[activeAccount].type === 'mojang') {
227+
const { accessToken, clientToken } = await refresh(
228+
accounts[activeAccount].accessToken || '',
229+
accounts[activeAccount].clientToken || '',
230+
false
231+
)
232+
session = { accessToken }
233+
setAccounts({
234+
[activeAccount]: { ...account, accessToken, clientToken }
235+
})
236+
}
237+
// If connecting to 1.19, get player certificates.
238+
if (!session.certificate && is119) {
239+
const token = session.accessToken
240+
session.certificate = await getPlayerCertificates(token)
241+
}
242+
setSessions({ [activeAccount]: session })
243+
} catch (e) {
244+
const reason =
245+
'Failed to create session! You may need to re-login with your Microsoft Account in the Accounts tab.'
246+
setDisconnectReason({ server, reason })
247+
initiatingConnection.current = false
248+
return
249+
}
250+
}
251+
252+
// Connect to server after setting up the session.
253+
try {
254+
const newConn = await initiateConnection({
255+
host,
256+
port,
257+
username: accounts[activeAccount].username,
258+
protocolVersion,
259+
selectedProfile: uuid,
260+
accessToken: session?.accessToken,
261+
certificate: session?.certificate // TODO: Chat Signing toggle?
262+
})
263+
const onCloseOrError = () => {
264+
setConnection(undefined)
265+
if (newConn.disconnectReason) {
266+
const reason = parseValidJson(newConn.disconnectReason)
267+
setDisconnectReason({ server, reason })
268+
}
193269
}
270+
newConn.on('close', onCloseOrError)
271+
newConn.on('error', onCloseOrError)
272+
setConnection({ serverName: server, connection: newConn })
273+
} catch (e) {
274+
setDisconnectReason({ server, reason: 'Failed to connect to server!' })
194275
}
195-
newConn.on('close', onCloseOrError)
196-
newConn.on('error', onCloseOrError)
197-
setConnection({
198-
serverName: server,
199-
connection: newConn
200-
})
201276
initiatingConnection.current = false
202277
}
203278
}

yarn.lock

+5-5
Original file line numberDiff line numberDiff line change
@@ -2517,11 +2517,6 @@
25172517
dependencies:
25182518
"tweetnacl" "^0.14.3"
25192519

2520-
"big-integer@^1.6.51":
2521-
"integrity" "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg=="
2522-
"resolved" "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz"
2523-
"version" "1.6.51"
2524-
25252520
"bl@^4.1.0":
25262521
"integrity" "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="
25272522
"resolved" "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz"
@@ -5428,6 +5423,11 @@
54285423
"argparse" "^1.0.7"
54295424
"esprima" "^4.0.0"
54305425

5426+
"jsbi@^3.2.5":
5427+
"integrity" "sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ=="
5428+
"resolved" "https://registry.npmjs.org/jsbi/-/jsbi-3.2.5.tgz"
5429+
"version" "3.2.5"
5430+
54315431
"jsbn@~0.1.0":
54325432
"integrity" "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
54335433
"resolved" "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz"

0 commit comments

Comments
 (0)