baltica 0.1.17 → 0.1.18
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/dist/client/client.js
CHANGED
|
@@ -176,8 +176,8 @@ class Client extends shared_1.Emitter {
|
|
|
176
176
|
serverBoundLoadingScreen.type =
|
|
177
177
|
protocol_1.ServerboundLoadingScreenType.EndLoadingScreen;
|
|
178
178
|
serverBoundLoadingScreen.hasScreenId = false;
|
|
179
|
-
this.send(init);
|
|
180
179
|
this.send(serverBoundLoadingScreen);
|
|
180
|
+
this.send(init);
|
|
181
181
|
this.emit("SetLocalPlayerAsInitializedPacket", init);
|
|
182
182
|
}
|
|
183
183
|
});
|
|
@@ -43,6 +43,10 @@ export type ClientOptions = {
|
|
|
43
43
|
compressionMethod: CompressionMethod;
|
|
44
44
|
/** Whether to emit unknown packets as buffer */
|
|
45
45
|
emitUnknownPackets: boolean;
|
|
46
|
+
/** Email for direct email/password authentication (requires 2FA disabled) */
|
|
47
|
+
email?: string;
|
|
48
|
+
/** Password for direct email/password authentication (requires 2FA disabled) */
|
|
49
|
+
password?: string;
|
|
46
50
|
};
|
|
47
51
|
/** Default Client Options */
|
|
48
52
|
export declare const defaultClientOptions: ClientOptions;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { authenticate as xboxAuthenticate, live, xnet } from "@xboxreplay/xboxlive-auth";
|
|
2
|
+
import type { AuthenticateResponse, Email } from "@xboxreplay/xboxlive-auth";
|
|
3
|
+
export interface BedrockTokens {
|
|
4
|
+
chains: string[];
|
|
5
|
+
xuid: string;
|
|
6
|
+
gamertag: string;
|
|
7
|
+
userHash: string;
|
|
8
|
+
}
|
|
9
|
+
export interface AuthOptions {
|
|
10
|
+
email: string;
|
|
11
|
+
password: string;
|
|
12
|
+
clientPublicKey: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Authenticates with Xbox Live using email/password and obtains Minecraft Bedrock tokens
|
|
16
|
+
* NOTE: Only works if 2FA is DISABLED on the Microsoft account
|
|
17
|
+
*/
|
|
18
|
+
export declare function authenticateWithCredentials(options: AuthOptions): Promise<BedrockTokens>;
|
|
19
|
+
export { xboxAuthenticate as authenticate, live, xnet };
|
|
20
|
+
export type { AuthenticateResponse, Email };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.xnet = exports.live = exports.authenticate = void 0;
|
|
4
|
+
exports.authenticateWithCredentials = authenticateWithCredentials;
|
|
5
|
+
const xboxlive_auth_1 = require("@xboxreplay/xboxlive-auth");
|
|
6
|
+
Object.defineProperty(exports, "authenticate", { enumerable: true, get: function () { return xboxlive_auth_1.authenticate; } });
|
|
7
|
+
Object.defineProperty(exports, "live", { enumerable: true, get: function () { return xboxlive_auth_1.live; } });
|
|
8
|
+
Object.defineProperty(exports, "xnet", { enumerable: true, get: function () { return xboxlive_auth_1.xnet; } });
|
|
9
|
+
const raknet_1 = require("@sanctumterra/raknet");
|
|
10
|
+
const MINECRAFT_BEDROCK_RELYING_PARTY = "https://multiplayer.minecraft.net/";
|
|
11
|
+
/**
|
|
12
|
+
* Authenticates with Xbox Live using email/password and obtains Minecraft Bedrock tokens
|
|
13
|
+
* NOTE: Only works if 2FA is DISABLED on the Microsoft account
|
|
14
|
+
*/
|
|
15
|
+
async function authenticateWithCredentials(options) {
|
|
16
|
+
const { email, password, clientPublicKey } = options;
|
|
17
|
+
raknet_1.Logger.info("Authenticating with Xbox Live...");
|
|
18
|
+
try {
|
|
19
|
+
const liveToken = await xboxlive_auth_1.live.authenticateWithCredentials({
|
|
20
|
+
email: email,
|
|
21
|
+
password,
|
|
22
|
+
});
|
|
23
|
+
// Exchange for Xbox user token
|
|
24
|
+
const userTokenResp = await xboxlive_auth_1.xnet.exchangeRpsTicketForUserToken(liveToken.access_token, "t");
|
|
25
|
+
const userHash = userTokenResp.DisplayClaims.xui[0].uhs;
|
|
26
|
+
// Get XSTS token for Minecraft Bedrock
|
|
27
|
+
const xstsResp = await xboxlive_auth_1.xnet.exchangeTokenForXSTSToken(userTokenResp.Token, {
|
|
28
|
+
XSTSRelyingParty: MINECRAFT_BEDROCK_RELYING_PARTY,
|
|
29
|
+
sandboxId: "RETAIL",
|
|
30
|
+
});
|
|
31
|
+
const xuid = xstsResp.DisplayClaims.xui[0].xid || "";
|
|
32
|
+
// Get Minecraft Bedrock chains using the client's public key
|
|
33
|
+
const chains = await getMinecraftBedrockChains(xstsResp.Token, userHash, clientPublicKey);
|
|
34
|
+
const gamertag = extractGamertagFromChains(chains);
|
|
35
|
+
raknet_1.Logger.info(`Authenticated as: ${gamertag} (${xuid})`);
|
|
36
|
+
return { chains, xuid, gamertag, userHash };
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
const err = error;
|
|
40
|
+
if (err.attributes?.code === "INVALID_CREDENTIALS_OR_2FA_ENABLED") {
|
|
41
|
+
throw new Error("Authentication failed: Invalid credentials or 2FA is enabled.\n" +
|
|
42
|
+
"Direct email/password login only works with 2FA DISABLED.");
|
|
43
|
+
}
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function getMinecraftBedrockChains(xstsToken, userHash, clientPublicKey) {
|
|
48
|
+
const response = await fetch("https://multiplayer.minecraft.net/authentication", {
|
|
49
|
+
method: "POST",
|
|
50
|
+
headers: {
|
|
51
|
+
"Content-Type": "application/json",
|
|
52
|
+
Authorization: `XBL3.0 x=${userHash};${xstsToken}`,
|
|
53
|
+
"Client-Version": "1.21.130",
|
|
54
|
+
},
|
|
55
|
+
body: JSON.stringify({ identityPublicKey: clientPublicKey }),
|
|
56
|
+
});
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
const text = await response.text();
|
|
59
|
+
throw new Error(`Minecraft Bedrock auth failed: ${response.status} - ${text}`);
|
|
60
|
+
}
|
|
61
|
+
const data = (await response.json());
|
|
62
|
+
return data.chain || [];
|
|
63
|
+
}
|
|
64
|
+
function extractGamertagFromChains(chains) {
|
|
65
|
+
for (const chain of chains) {
|
|
66
|
+
try {
|
|
67
|
+
const [, payload] = chain.split(".");
|
|
68
|
+
if (payload) {
|
|
69
|
+
const decoded = JSON.parse(Buffer.from(payload, "base64").toString());
|
|
70
|
+
if (decoded.extraData?.displayName) {
|
|
71
|
+
return decoded.extraData.displayName;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
/* continue */
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return "";
|
|
80
|
+
}
|
package/dist/shared/auth.js
CHANGED
|
@@ -44,6 +44,7 @@ const node_crypto_1 = require("node:crypto");
|
|
|
44
44
|
const prismarine_auth_1 = require("prismarine-auth");
|
|
45
45
|
const uuid_1345_1 = require("uuid-1345");
|
|
46
46
|
const types_1 = require("./types");
|
|
47
|
+
const authentication_1 = require("./auth/authentication");
|
|
47
48
|
exports.UUID_NAMESPACE = "6ba7b811-9dad-11d1-80b4-00c04fd430c8";
|
|
48
49
|
const PUBLIC_KEY = "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAECRXueJeTDqNRRgJi/vlRufByu/2G0i2Ebt6YMar5QX/R0DIIyrJMcUpruK4QveTfJSTp3Shlq4Gk34cD/4GUWwkv0DVuzeuB+tXija7HBxii03NHDbPAD0AKnLr2wdAp";
|
|
49
50
|
async function createOfflineSession(client) {
|
|
@@ -69,6 +70,11 @@ async function createOfflineSession(client) {
|
|
|
69
70
|
}
|
|
70
71
|
async function authenticate(client) {
|
|
71
72
|
const startTime = Date.now();
|
|
73
|
+
// Check if email/password auth is requested
|
|
74
|
+
if (client.options.email && client.options.password) {
|
|
75
|
+
return authenticateWithEmailPassword(client);
|
|
76
|
+
}
|
|
77
|
+
// Default: use prismarine-auth (device code flow)
|
|
72
78
|
try {
|
|
73
79
|
const authflow = createAuthflow(client);
|
|
74
80
|
const chains = await getMinecraftBedrockToken(authflow, client);
|
|
@@ -87,6 +93,36 @@ async function authenticate(client) {
|
|
|
87
93
|
throw error;
|
|
88
94
|
}
|
|
89
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Authenticate using email/password directly (requires 2FA disabled)
|
|
98
|
+
*/
|
|
99
|
+
async function authenticateWithEmailPassword(client) {
|
|
100
|
+
const startTime = Date.now();
|
|
101
|
+
try {
|
|
102
|
+
if (!client.options.email || !client.options.password) {
|
|
103
|
+
throw new Error("Email and password are required for email/password authentication");
|
|
104
|
+
}
|
|
105
|
+
const tokens = await (0, authentication_1.authenticateWithCredentials)({
|
|
106
|
+
email: client.options.email,
|
|
107
|
+
password: client.options.password,
|
|
108
|
+
clientPublicKey: client.data.loginData.clientX509,
|
|
109
|
+
});
|
|
110
|
+
const profile = {
|
|
111
|
+
name: tokens.gamertag,
|
|
112
|
+
uuid: generateUUID(tokens.gamertag),
|
|
113
|
+
xuid: Number(tokens.xuid) || 0,
|
|
114
|
+
};
|
|
115
|
+
const endTime = Date.now();
|
|
116
|
+
raknet_1.Logger.info(`Authentication with Xbox (email/password) took ${(endTime - startTime) / 1000}s.`);
|
|
117
|
+
setupClientProfile(client, profile, tokens.chains);
|
|
118
|
+
await setupClientChains(client);
|
|
119
|
+
client.emit("session");
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
raknet_1.Logger.error(`Email/password authentication failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
90
126
|
async function getMultiplayerSessionToken(authflow, client) {
|
|
91
127
|
try {
|
|
92
128
|
// @ts-expect-error Method exists at runtime
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "baltica",
|
|
3
3
|
"description": "Library for Minecraft Bedrock Edition community developers.",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.18",
|
|
5
5
|
"minecraft": "1.21.130",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"license": "MIT",
|
|
@@ -21,9 +21,10 @@
|
|
|
21
21
|
}
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@sanctumterra/raknet": "^1.4.
|
|
24
|
+
"@sanctumterra/raknet": "^1.4.7",
|
|
25
25
|
"@serenityjs/binarystream": "^3.0.10",
|
|
26
26
|
"@serenityjs/protocol": "^0.8.14",
|
|
27
|
+
"@xboxreplay/xboxlive-auth": "^5.1.0",
|
|
27
28
|
"jose": "^5.10.0",
|
|
28
29
|
"prismarine-auth": "^2.7.0",
|
|
29
30
|
"uuid-1345": "^1.0.2"
|