@vaitosoi/minejs 0.2.2 → 0.4.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.
Files changed (149) hide show
  1. package/README.md +1 -1
  2. package/assets/minecraft/26.2/packets.json +4758 -0
  3. package/dist/base/buffer.d.ts +2 -0
  4. package/dist/base/buffer.d.ts.map +1 -0
  5. package/dist/base/buffer.js +12 -0
  6. package/dist/base/buffer.js.map +1 -0
  7. package/dist/base/error.d.ts +59 -3
  8. package/dist/base/error.d.ts.map +1 -1
  9. package/dist/base/error.js +123 -7
  10. package/dist/base/error.js.map +1 -1
  11. package/dist/base/http.d.ts +2 -0
  12. package/dist/base/http.d.ts.map +1 -0
  13. package/dist/base/http.js +14 -0
  14. package/dist/base/http.js.map +1 -0
  15. package/dist/base/math.d.ts +22 -1
  16. package/dist/base/math.d.ts.map +1 -1
  17. package/dist/base/math.js +49 -2
  18. package/dist/base/math.js.map +1 -1
  19. package/dist/base/typing.d.ts +7 -1
  20. package/dist/base/typing.d.ts.map +1 -1
  21. package/dist/client/auth.d.ts +41 -7
  22. package/dist/client/auth.d.ts.map +1 -1
  23. package/dist/client/auth.js +96 -39
  24. package/dist/client/auth.js.map +1 -1
  25. package/dist/client/client.d.ts +73 -17
  26. package/dist/client/client.d.ts.map +1 -1
  27. package/dist/client/client.js +111 -44
  28. package/dist/client/client.js.map +1 -1
  29. package/dist/client/tcp.d.ts +17 -206
  30. package/dist/client/tcp.d.ts.map +1 -1
  31. package/dist/client/tcp.js +37 -715
  32. package/dist/client/tcp.js.map +1 -1
  33. package/dist/index.d.ts +12 -12
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +12 -12
  36. package/dist/index.js.map +1 -1
  37. package/dist/message/link.d.ts +10 -0
  38. package/dist/message/link.d.ts.map +1 -0
  39. package/dist/message/link.js +22 -0
  40. package/dist/message/link.js.map +1 -0
  41. package/dist/message/sigCache.d.ts +13 -0
  42. package/dist/message/sigCache.d.ts.map +1 -0
  43. package/dist/message/sigCache.js +26 -0
  44. package/dist/message/sigCache.js.map +1 -0
  45. package/dist/{translator → packet}/decoder.d.ts +14 -1
  46. package/dist/packet/decoder.d.ts.map +1 -0
  47. package/dist/{translator → packet}/decoder.js +24 -3
  48. package/dist/packet/decoder.js.map +1 -0
  49. package/dist/packet/dispatcher.d.ts +53 -0
  50. package/dist/packet/dispatcher.d.ts.map +1 -0
  51. package/dist/packet/dispatcher.js +738 -0
  52. package/dist/packet/dispatcher.js.map +1 -0
  53. package/dist/{translator → packet}/encoder.d.ts +4 -3
  54. package/dist/packet/encoder.d.ts.map +1 -0
  55. package/dist/{translator → packet}/encoder.js +18 -7
  56. package/dist/packet/encoder.js.map +1 -0
  57. package/dist/packet/static.d.ts.map +1 -0
  58. package/dist/packet/static.js.map +1 -0
  59. package/dist/{base → physics}/aabb.d.ts +2 -2
  60. package/dist/physics/aabb.d.ts.map +1 -0
  61. package/dist/{base → physics}/aabb.js +5 -5
  62. package/dist/physics/aabb.js.map +1 -0
  63. package/dist/physics/direction.d.ts.map +1 -0
  64. package/dist/physics/direction.js.map +1 -0
  65. package/dist/{base → physics}/player.d.ts +25 -28
  66. package/dist/physics/player.d.ts.map +1 -0
  67. package/dist/{base → physics}/player.js +81 -68
  68. package/dist/physics/player.js.map +1 -0
  69. package/dist/version/codec.d.ts +18 -0
  70. package/dist/version/codec.d.ts.map +1 -0
  71. package/dist/version/codec.js +235 -0
  72. package/dist/version/codec.js.map +1 -0
  73. package/dist/version/registry.d.ts +236 -0
  74. package/dist/version/registry.d.ts.map +1 -0
  75. package/dist/version/registry.js +284 -0
  76. package/dist/version/registry.js.map +1 -0
  77. package/dist/{base → world}/block.d.ts +5 -5
  78. package/dist/world/block.d.ts.map +1 -0
  79. package/dist/{base → world}/block.js +13 -13
  80. package/dist/world/block.js.map +1 -0
  81. package/dist/{base → world}/entity.d.ts +4 -4
  82. package/dist/world/entity.d.ts.map +1 -0
  83. package/dist/{base → world}/entity.js +6 -6
  84. package/dist/world/entity.js.map +1 -0
  85. package/dist/world/state.d.ts +175 -0
  86. package/dist/world/state.d.ts.map +1 -0
  87. package/dist/world/state.js +163 -0
  88. package/dist/world/state.js.map +1 -0
  89. package/dist/world/tick.d.ts.map +1 -0
  90. package/dist/world/tick.js.map +1 -0
  91. package/package.json +7 -2
  92. package/src/base/buffer.ts +12 -0
  93. package/src/base/error.ts +93 -4
  94. package/src/base/http.ts +10 -0
  95. package/src/base/math.ts +55 -3
  96. package/src/base/typing.ts +9 -1
  97. package/src/client/auth.ts +130 -52
  98. package/src/client/client.ts +182 -50
  99. package/src/client/tcp.ts +45 -967
  100. package/src/index.ts +12 -12
  101. package/src/message/link.ts +17 -0
  102. package/src/message/sigCache.ts +25 -0
  103. package/src/{translator → packet}/decoder.ts +24 -3
  104. package/src/packet/dispatcher.ts +919 -0
  105. package/src/{translator → packet}/encoder.ts +20 -9
  106. package/src/{base → physics}/aabb.ts +5 -5
  107. package/src/{base → physics}/player.ts +106 -65
  108. package/src/version/codec.ts +248 -0
  109. package/src/version/registry.ts +328 -0
  110. package/src/{base → world}/block.ts +12 -11
  111. package/src/{base → world}/entity.ts +5 -5
  112. package/src/world/state.ts +300 -0
  113. package/test/adapter/index.ts +14 -0
  114. package/test/client/index.ts +28 -21
  115. package/test/json/index.ts +3 -0
  116. package/dist/base/aabb.d.ts.map +0 -1
  117. package/dist/base/aabb.js.map +0 -1
  118. package/dist/base/block.d.ts.map +0 -1
  119. package/dist/base/block.js.map +0 -1
  120. package/dist/base/direction.d.ts.map +0 -1
  121. package/dist/base/direction.js.map +0 -1
  122. package/dist/base/entity.d.ts.map +0 -1
  123. package/dist/base/entity.js.map +0 -1
  124. package/dist/base/player.d.ts.map +0 -1
  125. package/dist/base/player.js.map +0 -1
  126. package/dist/base/registry.d.ts +0 -50
  127. package/dist/base/registry.d.ts.map +0 -1
  128. package/dist/base/registry.js +0 -89
  129. package/dist/base/registry.js.map +0 -1
  130. package/dist/base/tick.d.ts.map +0 -1
  131. package/dist/base/tick.js.map +0 -1
  132. package/dist/translator/decoder.d.ts.map +0 -1
  133. package/dist/translator/decoder.js.map +0 -1
  134. package/dist/translator/encoder.d.ts.map +0 -1
  135. package/dist/translator/encoder.js.map +0 -1
  136. package/dist/translator/static.d.ts.map +0 -1
  137. package/dist/translator/static.js.map +0 -1
  138. package/src/base/registry.ts +0 -87
  139. /package/assets/minecraft/{blocks.json → 26.2/blocks.json} +0 -0
  140. /package/assets/minecraft/{entities.json → 26.2/entities.json} +0 -0
  141. /package/dist/{translator → packet}/static.d.ts +0 -0
  142. /package/dist/{translator → packet}/static.js +0 -0
  143. /package/dist/{base → physics}/direction.d.ts +0 -0
  144. /package/dist/{base → physics}/direction.js +0 -0
  145. /package/dist/{base → world}/tick.d.ts +0 -0
  146. /package/dist/{base → world}/tick.js +0 -0
  147. /package/src/{translator → packet}/static.ts +0 -0
  148. /package/src/{base → physics}/direction.ts +0 -0
  149. /package/src/{base → world}/tick.ts +0 -0
package/src/base/math.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { createHash } from "node:crypto";
1
+ import { createHash, randomBytes } from "node:crypto";
2
2
 
3
3
  /** @hidden */
4
4
  export const Epsilon = 1.0e-7; // 1^-7
@@ -9,17 +9,39 @@ export const Epsilon = 1.0e-7; // 1^-7
9
9
  * Use for offline account
10
10
  *
11
11
  * @hidden
12
+ * @see https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/UUID.java#L165
12
13
  */
13
- export function computeUUID(playerName: string): Buffer {
14
+ export function computeUUID(playerName: string): string {
14
15
  const md5 = createHash("md5").update(playerName).digest();
15
16
  md5[6]! &= 0x0f; /* clear version */
16
17
  md5[6]! |= 0x30; /* set to version 3 */
17
18
  md5[8]! &= 0x3f; /* clear variant */
18
19
  md5[8]! |= 0x80; /* set to IETF variant */
20
+ return md5.toString("hex");
21
+ }
19
22
 
20
- return md5;
23
+ /**
24
+ * Create random UUID but in bytes
25
+ *
26
+ * @hidden
27
+ * @see https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/UUID.java#L144
28
+ */
29
+ export function randomUUIDBytes(): Buffer {
30
+ const buffer = randomBytes(16);
31
+ buffer[6]! &= 0x0f; /* clear version */
32
+ buffer[6]! |= 0x40; /* set to version 4 */
33
+ buffer[8]! &= 0x3f; /* clear variant */
34
+ buffer[8]! |= 0x80; /* set to IETF variant */
35
+ return buffer;
21
36
  }
22
37
 
38
+ /**
39
+ * Transform UUID string into Buffer
40
+ *
41
+ * @hidden
42
+ */
43
+ export const uuidToBuffer = (uuid: string) => Buffer.from(uuid.replaceAll("-", ""), "hex");
44
+
23
45
  /** @hidden */
24
46
  export const minBigInt = (...args: bigint[]) => args.reduce((min, val) => val < min ? val : min);
25
47
 
@@ -60,4 +82,34 @@ export function clamp(a: number, min: number, max: number) {
60
82
  if (a < min) return min;
61
83
  if (a > max) return max;
62
84
  return a;
85
+ }
86
+
87
+ /**
88
+ * Compute SHA1 for authenticating client with Mojang server
89
+ *
90
+ * @see https://gist.github.com/andrewrk/4425843?permalink_comment_id=5445918#gistcomment-5445918
91
+ * @hidden
92
+ */
93
+ export function minecraftSha1(
94
+ serverId: string,
95
+ sharedSecret: Buffer,
96
+ publicKey: Buffer,
97
+ ): string {
98
+ const sha1 = createHash('sha1');
99
+ sha1.update(Buffer.from(serverId, 'ascii'));
100
+ sha1.update(sharedSecret);
101
+ sha1.update(publicKey);
102
+
103
+ return mcHexDigest(sha1.digest());
104
+ }
105
+
106
+ /**
107
+ * Compute the hex digest
108
+ *
109
+ * @see https://gist.github.com/andrewrk/4425843?permalink_comment_id=5445918#gistcomment-5445918
110
+ * @hidden
111
+ */
112
+ function mcHexDigest(digest: Buffer | Uint8Array): string {
113
+ const bigint = BigInt(`0x${digest.toString('hex')}`);
114
+ return BigInt.asIntN(digest.length * 8, bigint).toString(16);
63
115
  }
@@ -1,2 +1,10 @@
1
1
  /** @hidden */
2
- export type If<Condition extends boolean, True, False = null> = Condition extends true ? True : False;
2
+ export type If<Condition extends boolean, True, False = null> = Condition extends true ? True : Condition extends false ? False : True | False;
3
+
4
+
5
+ /**
6
+ * Representing a TextComponent
7
+ *
8
+ * @see https://minecraft.wiki/w/Text_component_format
9
+ */
10
+ export type TextComponent = Record<string, any>;
@@ -1,21 +1,37 @@
1
1
  import http from "node:http";
2
- import cryto from "node:crypto";
3
- import net from "node:net";
2
+ import crypto from "node:crypto";
4
3
  import { exec } from "node:child_process";
5
- import { AuthDenied, AuthError, AuthTokenExpired, CantGetMsAccessToken, ProfileError, ProfileNotFound, XboxError } from "../base/error";
4
+ import { AuthDenied, OAuthError, AuthTokenExpired, CantGetMsAccessToken, ProfileError, ProfileNotFound, XboxError, AuthClientError, MinecraftError } from "../base/error";
5
+ import { minecraftSha1 } from "../base/math";
6
+ import { getJson } from "../base/http";
6
7
 
7
- export interface AuthOption {
8
+ interface Loopback {
8
9
  /**
9
- * `"loopback"` - open a browser to login
10
- * `"device_code"` - provide a device code to login
10
+ * This method will provide you a url to click on and do the authentication.
11
+ *
12
+ * This will require an opening port in order to receive the response from Microsoft. If you cant, considering using `device_code` method.
13
+ */
14
+ method: "loopback",
15
+
16
+ /**
17
+ * The opening port for listening the response
11
18
  */
12
- method: "loopback" | "device_code",
19
+ port: number
13
20
 
14
21
  /**
15
22
  * Automatedly open browser or print a URL to click on.
16
23
  */
17
24
  openBrowser: boolean,
25
+ }
18
26
 
27
+ interface DeviceCode {
28
+ /**
29
+ * This method will provide you a device code, then you have to type this code in the given URL.
30
+ */
31
+ method: "device_code",
32
+ }
33
+
34
+ export type AuthOption = (Loopback | DeviceCode) & {
19
35
  /**
20
36
  * The Client ID
21
37
  *
@@ -101,17 +117,6 @@ function open(url: string, log: (message: string) => any) {
101
117
  }
102
118
  }
103
119
 
104
- // Got this from https://github.com/sindresorhus/get-port/blob/main/index.js#L47
105
- const getFreePort = () => new Promise<number>((resolve) => {
106
- const server = net.createServer();
107
- server.listen(0, () => {
108
- const port = (server.address() as net.AddressInfo).port;
109
- server.close(() =>
110
- resolve(port)
111
- );
112
- });
113
- });
114
-
115
120
  const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));
116
121
 
117
122
  /**
@@ -121,34 +126,100 @@ export class AuthClient {
121
126
  private readonly codeVerifier: string;
122
127
  private readonly codeChallenge: string;
123
128
  // private refreshToken?: string;
129
+ private accessToken: string = "";
130
+ private uuid: string = "";
124
131
 
125
132
  constructor(private option: AuthOption) {
126
- const codeVerifier = cryto.randomBytes(32).toString("hex");
127
- const hashed = cryto.hash("sha256", codeVerifier, "base64url");
133
+ const codeVerifier = crypto.randomBytes(32).toString("hex");
134
+ const hashed = crypto.createHash("sha256").update(codeVerifier).digest("base64url");
128
135
  this.option.log ||= console.log;
129
136
 
130
137
  this.codeVerifier = codeVerifier;
131
138
  this.codeChallenge = hashed;
132
139
  }
133
140
 
134
- public async auth() {
141
+ /**
142
+ * Send a auth notify to Minecraft server, after receive Encryption Request
143
+ *
144
+ * @see https://minecraft.wiki/w/Java_Edition_protocol/Encryption#Authentication
145
+ */
146
+ public async sendAuth(
147
+ // Sever things
148
+ serverId: string,
149
+ sharedSecret: Buffer,
150
+ publicKey: Buffer,
151
+ ) {
152
+ const hash = minecraftSha1(serverId, sharedSecret, publicKey);
153
+ const response = await fetch(
154
+ "https://sessionserver.mojang.com/session/minecraft/join",
155
+ {
156
+ method: "POST",
157
+ headers: {
158
+ "Content-Type": "application/json"
159
+ },
160
+ body: JSON.stringify({
161
+ accessToken: this.accessToken,
162
+ selectedProfile: this.uuid,
163
+ serverId: hash,
164
+ })
165
+ }
166
+ );
167
+ console.log({
168
+ accessToken: this.accessToken,
169
+ selectedProfile: this.uuid,
170
+ serverId: hash,
171
+ });
172
+ if (response.status === 204) return;
173
+ const json = await getJson(response, "send auth request") as Record<string, string>;
174
+ throw new AuthClientError(json["error"]! + ("errorMessage" in json ? `: ${json["errorMessage"]}` : ""));
175
+ }
176
+
177
+ /**
178
+ * Get player key pair for signing stuff
179
+ *
180
+ * @see https://minecraft.wiki/w/Mojang_API#Get_keypair_for_signature
181
+ */
182
+ public async getKeyPair() {
183
+ const response = await fetch(
184
+ "https://api.minecraftservices.com/player/certificates",
185
+ {
186
+ headers: {
187
+ Authorization: `Bearer ${this.accessToken}`
188
+ }
189
+ }
190
+ );
191
+ if (response.status !== 200) throw new AuthClientError("can't get the auth key", await response.text());
192
+ const json = await getJson(response, "get key pair") as any;
193
+ console.log(json);
194
+ return {
195
+ publicKey: String(json["keyPair"]["publicKey"]),
196
+ signature: String(json["publicKeySignatureV2"]),
197
+ expiresAt: Number(json["expiresAt"]),
198
+ };
199
+ }
200
+
201
+
202
+ /**
203
+ * Get player UUID
204
+ */
205
+ public async getUUID() {
135
206
  if (this.option.method === "loopback") return this.loopback();
136
207
  else return this.deviceCode();
137
208
  }
138
209
 
139
210
  private async loopback() {
140
- const freePort = await getFreePort();
141
- const expectState = cryto.randomBytes(8).toString("hex");
211
+ const option = this.option as Loopback;
212
+ const expectState = crypto.randomBytes(8).toString("hex");
142
213
  const authUrl = new URL("https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize");
143
214
  authUrl.searchParams.append("client_id", this.option.client_id);
144
215
  authUrl.searchParams.append("response_type", "code");
145
- authUrl.searchParams.append("redirect_uri", `http://127.0.0.1:${freePort}`);
216
+ authUrl.searchParams.append("redirect_uri", `http://localhost:${option.port}`);
146
217
  authUrl.searchParams.append("scope", "XboxLive.signin offline_access");
147
218
  authUrl.searchParams.append("code_challenge", this.codeChallenge);
148
219
  authUrl.searchParams.append("code_challenge_method", "S256");
149
220
  authUrl.searchParams.append("state", expectState);
150
221
 
151
- if (this.option.openBrowser === true)
222
+ if (option.openBrowser === true)
152
223
  open(authUrl.toString(), this.option.log!);
153
224
  else
154
225
  this.option.log!(`please open this url in your browser: ${authUrl.toString()}`);
@@ -156,32 +227,35 @@ export class AuthClient {
156
227
  const msAuthToken = await new Promise<string | null>((resolve) => {
157
228
  const server = http.createServer((req, res) => {
158
229
  const end = (html: string, result: any = null) => {
159
- res.end(html);
160
- server.close();
161
- return resolve(result);
230
+ if (res.writable)
231
+ res.end(html);
232
+ if (server.listening) {
233
+ server.close();
234
+ return resolve(result);
235
+ }
162
236
  };
163
237
 
164
- const url = new URL(req.url || "", `http://127.0.0.1:${freePort}`);
238
+ const url = new URL(req.url || "", `http://localhost:${option.port}`);
165
239
  const error = url.searchParams.get("error");
166
240
  if (error) {
167
241
  const description = url.searchParams.get("error_description")!;
168
- end(ErrorHTML.replace("{error}", error).replace("{error_description}", description));
242
+ return end(ErrorHTML.replace("{error}", error).replace("{error_description}", description));
169
243
  }
170
244
 
171
245
  const code = url.searchParams.get("code");
172
246
  if (!code)
173
- end(InvalidHTML.replace("{reason}", "Missing <code>code</code> parameter"));
247
+ return end(InvalidHTML.replace("{reason}", "Missing <code>code</code> parameter"));
174
248
 
175
249
  const state = url.searchParams.get("state");
176
250
  if (!state)
177
- end(InvalidHTML.replace("{reason}", "Missing <code>state</code> parameter"));
251
+ return end(InvalidHTML.replace("{reason}", "Missing <code>state</code> parameter"));
178
252
  if (state !== expectState)
179
- end(InvalidHTML.replace("{reason}", "Mismatch state"));
253
+ return end(InvalidHTML.replace("{reason}", "Mismatch state"));
180
254
 
181
255
  return end(SuccessHTML, code);
182
256
  });
183
257
 
184
- server.listen(freePort);
258
+ server.listen(option.port);
185
259
  });
186
260
 
187
261
  if (!msAuthToken)
@@ -190,9 +264,9 @@ export class AuthClient {
190
264
  const msTokenUrl = new URL("https://login.microsoftonline.com/consumers/oauth2/v2.0/token");
191
265
  const msTokenBody = new URLSearchParams();
192
266
  msTokenBody.append("client_id", this.option.client_id);
193
- msTokenBody.append("code", msAuthToken);
194
267
  msTokenBody.append("scope", "XboxLive.signin offline_access");
195
- msTokenBody.append("redirect_uri", `http://127.0.0.1:${freePort}`);
268
+ msTokenBody.append("code", msAuthToken);
269
+ msTokenBody.append("redirect_uri", `http://localhost:${option.port}`);
196
270
  msTokenBody.append("grant_type", "authorization_code");
197
271
  msTokenBody.append("code_verifier", this.codeVerifier);
198
272
  const msTokenRequest = await fetch(msTokenUrl, {
@@ -202,9 +276,9 @@ export class AuthClient {
202
276
  method: "POST",
203
277
  body: msTokenBody.toString()
204
278
  });
205
- const msTokenResponse = await msTokenRequest.json() as Record<string, any>;
279
+ const msTokenResponse = await getJson(msTokenRequest, "microsoft token request") as Record<string, any>;
206
280
  if ("error" in msTokenResponse)
207
- throw new AuthError(msTokenResponse["error"]);
281
+ throw new OAuthError(msTokenResponse["error"]);
208
282
  const msToken = msTokenResponse["access_token"];
209
283
 
210
284
  return this.getMcToken(msToken);
@@ -231,7 +305,7 @@ export class AuthClient {
231
305
  this.option.log!(message);
232
306
 
233
307
  let msToken;
234
- const msTokenUrl = new URL("https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token");
308
+ const msTokenUrl = new URL("https://login.microsoftonline.com/consumers/oauth2/v2.0/token");
235
309
  const msTokenBody = new URLSearchParams();
236
310
  msTokenBody.set("grant_type", "urn:ietf:params:oauth:grant-type:device_code");
237
311
  msTokenBody.set("client_id", this.option.client_id);
@@ -240,9 +314,10 @@ export class AuthClient {
240
314
  await sleep(interval * 1000);
241
315
  const msTokenRequest = await fetch(msTokenUrl, {
242
316
  headers: {
243
- "Content-Type": "application/x-www-form-urlencoded"
317
+ "Content-Type": "application/x-www-form-urlencoded",
244
318
  },
245
- method: "POST"
319
+ method: "POST",
320
+ body: msTokenBody.toString()
246
321
  });
247
322
  const msTokenResponse = await msTokenRequest.json() as Record<string, any>;
248
323
  if ("error" in msTokenResponse)
@@ -251,7 +326,7 @@ export class AuthClient {
251
326
  case "slow_down": interval += 5; continue;
252
327
  case "auth_denied": throw new AuthDenied();
253
328
  case "expired_token": throw new AuthTokenExpired();
254
- default: throw new AuthError(msTokenResponse["error"]);
329
+ default: throw new OAuthError(msTokenResponse["error"]);
255
330
  }
256
331
  else {
257
332
  msToken = msTokenResponse["access_token"];
@@ -263,10 +338,9 @@ export class AuthClient {
263
338
  throw new CantGetMsAccessToken();
264
339
 
265
340
  return this.getMcToken(msToken);
266
- }
341
+ }
267
342
 
268
343
  private async getMcToken(msToken: string): Promise<{
269
- token: string,
270
344
  uuid: string,
271
345
  name: string
272
346
  }> {
@@ -287,14 +361,14 @@ export class AuthClient {
287
361
  }),
288
362
  method: "POST"
289
363
  });
290
- const xboxReponse = await xboxRequest.json() as Record<string, any>;
364
+ const xboxReponse = await getJson(xboxRequest, "xbox request") as Record<string, any>;
291
365
  const xboxToken = xboxReponse["Token"];
292
366
  const userHash = xboxReponse["DisplayClaims"]["xui"][0]["uhs"];
293
367
 
294
368
  const xboxSecurityRequest = await fetch("https://xsts.auth.xboxlive.com/xsts/authorize", {
295
369
  headers: {
296
370
  "Content-Type": "application/json",
297
- Accept: "application/json"
371
+ "Accept": "application/json",
298
372
  },
299
373
  body: JSON.stringify({
300
374
  "Properties": {
@@ -306,7 +380,7 @@ export class AuthClient {
306
380
  }),
307
381
  method: "POST"
308
382
  });
309
- const xboxSecurityReponse = await xboxSecurityRequest.json() as Record<string, any>;
383
+ const xboxSecurityReponse = await getJson(xboxSecurityRequest, "xbox security request") as Record<string, any>;
310
384
  if ("XErr" in xboxSecurityReponse)
311
385
  throw new XboxError(xboxSecurityReponse["XErr"]);
312
386
  const xboxSecurityToken = xboxSecurityReponse["Token"];
@@ -314,14 +388,17 @@ export class AuthClient {
314
388
  const minecraftRequest = await fetch("https://api.minecraftservices.com/authentication/login_with_xbox", {
315
389
  headers: {
316
390
  "Content-Type": "application/json",
317
- Accept: "application/json"
391
+ "Accept": "application/json",
392
+ 'User-Agent': 'MinecraftLauncher/2.2.10675'
318
393
  },
319
394
  body: JSON.stringify({
320
- "identityToken": `XBL3.0 x=${userHash};${xboxSecurityToken}"`
395
+ "identityToken": `XBL3.0 x=${userHash};${xboxSecurityToken}`,
321
396
  }),
322
397
  method: "POST"
323
398
  });
324
- const minecraftResponse = await minecraftRequest.json() as Record<string, any>;
399
+ const minecraftResponse = await getJson(minecraftRequest, "minecraft request") as Record<string, any>;
400
+ if ("errorMessage" in minecraftResponse)
401
+ throw new MinecraftError(minecraftResponse["errorMessage"]);
325
402
  const minecraftToken = minecraftResponse["access_token"];
326
403
 
327
404
  const mcProfileRequest = await fetch("https://api.minecraftservices.com/minecraft/profile", {
@@ -330,15 +407,16 @@ export class AuthClient {
330
407
  },
331
408
  method: "GET"
332
409
  });
333
- const mcProfileResponse = await mcProfileRequest.json() as Record<string, any>;
410
+ const mcProfileResponse = await getJson(mcProfileRequest, "minecraft profile request") as Record<string, any>;
334
411
  if ("error" in mcProfileResponse) {
335
412
  if (mcProfileResponse["error"] === "NOT_FOUND")
336
413
  throw new ProfileNotFound();
337
414
  else throw new ProfileError(mcProfileResponse["error"], mcProfileResponse["errorMessage"]);
338
415
  }
339
416
 
417
+ this.accessToken = minecraftToken;
418
+ this.uuid = mcProfileResponse["id"];
340
419
  return {
341
- token: minecraftToken,
342
420
  uuid: mcProfileResponse["id"],
343
421
  name: mcProfileResponse["name"]
344
422
  };