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.
@@ -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
+ }
@@ -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.17",
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.0",
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"