@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.
- package/README.md +1 -1
- package/assets/minecraft/26.2/packets.json +4758 -0
- package/dist/base/buffer.d.ts +2 -0
- package/dist/base/buffer.d.ts.map +1 -0
- package/dist/base/buffer.js +12 -0
- package/dist/base/buffer.js.map +1 -0
- package/dist/base/error.d.ts +59 -3
- package/dist/base/error.d.ts.map +1 -1
- package/dist/base/error.js +123 -7
- package/dist/base/error.js.map +1 -1
- package/dist/base/http.d.ts +2 -0
- package/dist/base/http.d.ts.map +1 -0
- package/dist/base/http.js +14 -0
- package/dist/base/http.js.map +1 -0
- package/dist/base/math.d.ts +22 -1
- package/dist/base/math.d.ts.map +1 -1
- package/dist/base/math.js +49 -2
- package/dist/base/math.js.map +1 -1
- package/dist/base/typing.d.ts +7 -1
- package/dist/base/typing.d.ts.map +1 -1
- package/dist/client/auth.d.ts +41 -7
- package/dist/client/auth.d.ts.map +1 -1
- package/dist/client/auth.js +96 -39
- package/dist/client/auth.js.map +1 -1
- package/dist/client/client.d.ts +73 -17
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +111 -44
- package/dist/client/client.js.map +1 -1
- package/dist/client/tcp.d.ts +17 -206
- package/dist/client/tcp.d.ts.map +1 -1
- package/dist/client/tcp.js +37 -715
- package/dist/client/tcp.js.map +1 -1
- package/dist/index.d.ts +12 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -12
- package/dist/index.js.map +1 -1
- package/dist/message/link.d.ts +10 -0
- package/dist/message/link.d.ts.map +1 -0
- package/dist/message/link.js +22 -0
- package/dist/message/link.js.map +1 -0
- package/dist/message/sigCache.d.ts +13 -0
- package/dist/message/sigCache.d.ts.map +1 -0
- package/dist/message/sigCache.js +26 -0
- package/dist/message/sigCache.js.map +1 -0
- package/dist/{translator → packet}/decoder.d.ts +14 -1
- package/dist/packet/decoder.d.ts.map +1 -0
- package/dist/{translator → packet}/decoder.js +24 -3
- package/dist/packet/decoder.js.map +1 -0
- package/dist/packet/dispatcher.d.ts +53 -0
- package/dist/packet/dispatcher.d.ts.map +1 -0
- package/dist/packet/dispatcher.js +738 -0
- package/dist/packet/dispatcher.js.map +1 -0
- package/dist/{translator → packet}/encoder.d.ts +4 -3
- package/dist/packet/encoder.d.ts.map +1 -0
- package/dist/{translator → packet}/encoder.js +18 -7
- package/dist/packet/encoder.js.map +1 -0
- package/dist/packet/static.d.ts.map +1 -0
- package/dist/packet/static.js.map +1 -0
- package/dist/{base → physics}/aabb.d.ts +2 -2
- package/dist/physics/aabb.d.ts.map +1 -0
- package/dist/{base → physics}/aabb.js +5 -5
- package/dist/physics/aabb.js.map +1 -0
- package/dist/physics/direction.d.ts.map +1 -0
- package/dist/physics/direction.js.map +1 -0
- package/dist/{base → physics}/player.d.ts +25 -28
- package/dist/physics/player.d.ts.map +1 -0
- package/dist/{base → physics}/player.js +81 -68
- package/dist/physics/player.js.map +1 -0
- package/dist/version/codec.d.ts +18 -0
- package/dist/version/codec.d.ts.map +1 -0
- package/dist/version/codec.js +235 -0
- package/dist/version/codec.js.map +1 -0
- package/dist/version/registry.d.ts +236 -0
- package/dist/version/registry.d.ts.map +1 -0
- package/dist/version/registry.js +284 -0
- package/dist/version/registry.js.map +1 -0
- package/dist/{base → world}/block.d.ts +5 -5
- package/dist/world/block.d.ts.map +1 -0
- package/dist/{base → world}/block.js +13 -13
- package/dist/world/block.js.map +1 -0
- package/dist/{base → world}/entity.d.ts +4 -4
- package/dist/world/entity.d.ts.map +1 -0
- package/dist/{base → world}/entity.js +6 -6
- package/dist/world/entity.js.map +1 -0
- package/dist/world/state.d.ts +175 -0
- package/dist/world/state.d.ts.map +1 -0
- package/dist/world/state.js +163 -0
- package/dist/world/state.js.map +1 -0
- package/dist/world/tick.d.ts.map +1 -0
- package/dist/world/tick.js.map +1 -0
- package/package.json +7 -2
- package/src/base/buffer.ts +12 -0
- package/src/base/error.ts +93 -4
- package/src/base/http.ts +10 -0
- package/src/base/math.ts +55 -3
- package/src/base/typing.ts +9 -1
- package/src/client/auth.ts +130 -52
- package/src/client/client.ts +182 -50
- package/src/client/tcp.ts +45 -967
- package/src/index.ts +12 -12
- package/src/message/link.ts +17 -0
- package/src/message/sigCache.ts +25 -0
- package/src/{translator → packet}/decoder.ts +24 -3
- package/src/packet/dispatcher.ts +919 -0
- package/src/{translator → packet}/encoder.ts +20 -9
- package/src/{base → physics}/aabb.ts +5 -5
- package/src/{base → physics}/player.ts +106 -65
- package/src/version/codec.ts +248 -0
- package/src/version/registry.ts +328 -0
- package/src/{base → world}/block.ts +12 -11
- package/src/{base → world}/entity.ts +5 -5
- package/src/world/state.ts +300 -0
- package/test/adapter/index.ts +14 -0
- package/test/client/index.ts +28 -21
- package/test/json/index.ts +3 -0
- package/dist/base/aabb.d.ts.map +0 -1
- package/dist/base/aabb.js.map +0 -1
- package/dist/base/block.d.ts.map +0 -1
- package/dist/base/block.js.map +0 -1
- package/dist/base/direction.d.ts.map +0 -1
- package/dist/base/direction.js.map +0 -1
- package/dist/base/entity.d.ts.map +0 -1
- package/dist/base/entity.js.map +0 -1
- package/dist/base/player.d.ts.map +0 -1
- package/dist/base/player.js.map +0 -1
- package/dist/base/registry.d.ts +0 -50
- package/dist/base/registry.d.ts.map +0 -1
- package/dist/base/registry.js +0 -89
- package/dist/base/registry.js.map +0 -1
- package/dist/base/tick.d.ts.map +0 -1
- package/dist/base/tick.js.map +0 -1
- package/dist/translator/decoder.d.ts.map +0 -1
- package/dist/translator/decoder.js.map +0 -1
- package/dist/translator/encoder.d.ts.map +0 -1
- package/dist/translator/encoder.js.map +0 -1
- package/dist/translator/static.d.ts.map +0 -1
- package/dist/translator/static.js.map +0 -1
- package/src/base/registry.ts +0 -87
- /package/assets/minecraft/{blocks.json → 26.2/blocks.json} +0 -0
- /package/assets/minecraft/{entities.json → 26.2/entities.json} +0 -0
- /package/dist/{translator → packet}/static.d.ts +0 -0
- /package/dist/{translator → packet}/static.js +0 -0
- /package/dist/{base → physics}/direction.d.ts +0 -0
- /package/dist/{base → physics}/direction.js +0 -0
- /package/dist/{base → world}/tick.d.ts +0 -0
- /package/dist/{base → world}/tick.js +0 -0
- /package/src/{translator → packet}/static.ts +0 -0
- /package/src/{base → physics}/direction.ts +0 -0
- /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):
|
|
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
|
-
|
|
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
|
}
|
package/src/base/typing.ts
CHANGED
|
@@ -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>;
|
package/src/client/auth.ts
CHANGED
|
@@ -1,21 +1,37 @@
|
|
|
1
1
|
import http from "node:http";
|
|
2
|
-
import
|
|
3
|
-
import net from "node:net";
|
|
2
|
+
import crypto from "node:crypto";
|
|
4
3
|
import { exec } from "node:child_process";
|
|
5
|
-
import { AuthDenied,
|
|
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
|
-
|
|
8
|
+
interface Loopback {
|
|
8
9
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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
|
-
|
|
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 =
|
|
127
|
-
const hashed =
|
|
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
|
-
|
|
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
|
|
141
|
-
const expectState =
|
|
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://
|
|
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 (
|
|
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.
|
|
160
|
-
|
|
161
|
-
|
|
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://
|
|
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(
|
|
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("
|
|
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
|
|
279
|
+
const msTokenResponse = await getJson(msTokenRequest, "microsoft token request") as Record<string, any>;
|
|
206
280
|
if ("error" in msTokenResponse)
|
|
207
|
-
throw new
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
};
|