mirror of
https://github.com/WorldEditAxe/eaglerproxy.git
synced 2024-11-13 17:16:04 -08:00
Online mode fix & npm package updates
This commit is contained in:
parent
67c3e0bbda
commit
375a275442
910
package-lock.json
generated
910
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
33
package.json
33
package.json
|
@ -9,22 +9,23 @@
|
|||
"author": "WorldEditAxe, q13x",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@thi.ng/leb128": "^3.0.5",
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/semver": "^7.3.13",
|
||||
"@types/sharp": "^0.31.1",
|
||||
"@types/ws": "^8.5.4",
|
||||
"chalk": "^5.2.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"minecraft-protocol": "^1.40.2",
|
||||
"node-fetch": "^3.3.1",
|
||||
"parse-domain": "^7.0.1",
|
||||
"prismarine-block": "^1.16.3",
|
||||
"prismarine-chunk": "^1.33.0",
|
||||
"prismarine-registry": "^1.6.0",
|
||||
"semver": "^7.3.8",
|
||||
"sharp": "^0.31.3",
|
||||
"ws": "^8.12.0"
|
||||
"@thi.ng/leb128": "3.0.5",
|
||||
"@types/node": "18.11.18",
|
||||
"@types/semver": "7.3.13",
|
||||
"@types/sharp": "0.31.1",
|
||||
"@types/ws": "8.5.4",
|
||||
"chalk": "5.2.0",
|
||||
"dotenv": "16.0.3",
|
||||
"minecraft-protocol": "^1.26.5",
|
||||
"node-fetch": "3.3.1",
|
||||
"parse-domain": "7.0.1",
|
||||
"prismarine-auth": "^2.4.1",
|
||||
"prismarine-block": "1.16.3",
|
||||
"prismarine-chunk": "1.33.0",
|
||||
"prismarine-registry": "1.6.0",
|
||||
"semver": "^7.6.0",
|
||||
"sharp": "^0.33.2",
|
||||
"ws": "8.12.0"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
|
|
|
@ -12,41 +12,23 @@ import XboxTokenManager from "prismarine-auth/src/TokenManagers/XboxTokenManager
|
|||
import MsaTokenManager from "prismarine-auth/src/TokenManagers/MsaTokenManager.js";
|
||||
import BedrockTokenManager from "prismarine-auth/src/TokenManagers/MinecraftBedrockTokenManager.js";
|
||||
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 PrismarineJS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
async function retry(methodFn, beforeRetry, times) {
|
||||
for (let attempts = 0; attempts < times; attempts++) {
|
||||
try {
|
||||
return await methodFn();
|
||||
} catch (err) {
|
||||
if (err instanceof URIError) {
|
||||
throw err;
|
||||
while (times--) {
|
||||
if (times !== 0) {
|
||||
try {
|
||||
return await methodFn();
|
||||
} catch (e) {
|
||||
if (e instanceof URIError) {
|
||||
throw e;
|
||||
} else {
|
||||
// debug(e);
|
||||
}
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
await beforeRetry();
|
||||
} else {
|
||||
return await methodFn();
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
await beforeRetry();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,9 +45,7 @@ export class CustomAuthflow {
|
|||
constructor(username = "", cache, options, codeCallback) {
|
||||
this.username = username;
|
||||
if (options && !options.flow) {
|
||||
throw new Error(
|
||||
"Missing 'flow' argument in options. See docs for more information."
|
||||
);
|
||||
throw new Error("Missing 'flow' argument in options. See docs for more information.");
|
||||
}
|
||||
this.options = options || { flow: "msal" };
|
||||
this.initTokenManagers(username, cache);
|
||||
|
@ -74,48 +54,32 @@ export class CustomAuthflow {
|
|||
|
||||
initTokenManagers(username, cache) {
|
||||
if (this.options.flow === "live" || this.options.flow === "sisu") {
|
||||
if (!this.options.authTitle)
|
||||
throw new Error(
|
||||
`Please specify an "authTitle" in Authflow constructor when using ${this.options.flow} flow`
|
||||
);
|
||||
this.msa = new LiveTokenManager(
|
||||
this.options.authTitle,
|
||||
["service::user.auth.xboxlive.com::MBI_SSL"],
|
||||
cache({ cacheName: this.options.flow, username })
|
||||
);
|
||||
if (!this.options.authTitle) throw new Error(`Please specify an "authTitle" in Authflow constructor when using ${this.options.flow} flow`);
|
||||
this.msa = new LiveTokenManager(this.options.authTitle, ["service::user.auth.xboxlive.com::MBI_SSL"], cache({ cacheName: this.options.flow, username }));
|
||||
this.doTitleAuth = true;
|
||||
} else if (this.options.flow === "msal") {
|
||||
const config = Object.assign(
|
||||
{ ...msalConfig },
|
||||
this.options.authTitle
|
||||
? { auth: { ...msalConfig.auth, clientId: this.options.authTitle } }
|
||||
: {}
|
||||
);
|
||||
this.msa = new MsaTokenManager(
|
||||
config,
|
||||
["XboxLive.signin", "offline_access"],
|
||||
cache({ cacheName: "msal", username })
|
||||
);
|
||||
const config = Object.assign({ ...msalConfig }, this.options.authTitle ? { auth: { ...msalConfig.auth, clientId: this.options.authTitle } } : {});
|
||||
this.msa = new MsaTokenManager(config, ["XboxLive.signin", "offline_access"], cache({ cacheName: "msal", username }));
|
||||
} else {
|
||||
throw new Error(
|
||||
`Unknown flow: ${this.options.flow} (expected "live", "sisu", or "msal")`
|
||||
);
|
||||
throw new Error(`Unknown flow: ${this.options.flow} (expected "live", "sisu", or "msal")`);
|
||||
}
|
||||
|
||||
const keyPair = crypto.generateKeyPairSync("ec", { namedCurve: "P-256" });
|
||||
this.xbl = new XboxTokenManager(
|
||||
keyPair,
|
||||
cache({ cacheName: "xbl", username })
|
||||
);
|
||||
this.xbl = new XboxTokenManager(keyPair, cache({ cacheName: "xbl", username }));
|
||||
this.mba = new BedrockTokenManager(cache({ cacheName: "bed", username }));
|
||||
this.mca = new JavaTokenManager(cache({ cacheName: "mca", username }));
|
||||
}
|
||||
|
||||
static resetTokenCaches(cache) {
|
||||
if (!cache) throw new Error("You must provide a cache directory to reset.");
|
||||
if (fs.existsSync(cache)) {
|
||||
fs.rmSync(cache, { recursive: true });
|
||||
return true;
|
||||
try {
|
||||
if (fs.existsSync(cache)) {
|
||||
fs.rmSync(cache, { recursive: true });
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Failed to clear cache dir", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,70 +94,58 @@ export class CustomAuthflow {
|
|||
console.info(response.message);
|
||||
});
|
||||
|
||||
if (ret.account) {
|
||||
console.info(`[msa] Signed in as ${ret.account.username}`);
|
||||
} else {
|
||||
// We don't get extra account data here per scope
|
||||
console.info("[msa] Signed in with Microsoft");
|
||||
}
|
||||
|
||||
return ret.accessToken;
|
||||
}
|
||||
}
|
||||
|
||||
async getXboxToken(
|
||||
relyingParty = this.options.relyingParty || Endpoints.XboxRelyingParty
|
||||
) {
|
||||
async getXboxToken(relyingParty = this.options.relyingParty || Endpoints.XboxRelyingParty, forceRefresh = false) {
|
||||
const options = { ...this.options, relyingParty };
|
||||
if (await this.xbl.verifyTokens(relyingParty)) {
|
||||
const { data } = await this.xbl.getCachedXstsToken(relyingParty);
|
||||
return data;
|
||||
} else if (options.password) {
|
||||
const xsts = await this.xbl.doReplayAuth(
|
||||
this.username,
|
||||
options.password,
|
||||
options
|
||||
);
|
||||
return xsts;
|
||||
} else {
|
||||
return await retry(
|
||||
async () => {
|
||||
const msaToken = await this.getMsaToken();
|
||||
|
||||
if (options.flow === "sisu") {
|
||||
const deviceToken = await this.xbl.getDeviceToken(options);
|
||||
const sisu = await this.xbl.doSisuAuth(
|
||||
msaToken,
|
||||
deviceToken,
|
||||
options
|
||||
);
|
||||
return sisu;
|
||||
}
|
||||
const { xstsToken, userToken, deviceToken, titleToken } = await this.xbl.getCachedTokens(relyingParty);
|
||||
|
||||
const userToken = await this.xbl.getUserToken(
|
||||
msaToken,
|
||||
options.flow === "msal"
|
||||
);
|
||||
|
||||
if (this.doTitleAuth) {
|
||||
const deviceToken = await this.xbl.getDeviceToken(options);
|
||||
const titleToken = await this.xbl.getTitleToken(
|
||||
msaToken,
|
||||
deviceToken
|
||||
);
|
||||
const xsts = await this.xbl.getXSTSToken(
|
||||
{ userToken, deviceToken, titleToken },
|
||||
options
|
||||
);
|
||||
return xsts;
|
||||
} else {
|
||||
const xsts = await this.xbl.getXSTSToken({ userToken }, options);
|
||||
return xsts;
|
||||
}
|
||||
},
|
||||
() => {
|
||||
this.msa.forceRefresh = true;
|
||||
},
|
||||
2
|
||||
);
|
||||
if (xstsToken.valid && !forceRefresh) {
|
||||
return xstsToken.data;
|
||||
}
|
||||
|
||||
if (options.password) {
|
||||
const xsts = await this.xbl.doReplayAuth(this.username, options.password, options);
|
||||
return xsts;
|
||||
}
|
||||
|
||||
return await retry(
|
||||
async () => {
|
||||
const msaToken = await this.getMsaToken();
|
||||
|
||||
// sisu flow generates user and title tokens differently to other flows and should also be used to refresh them if they are invalid
|
||||
if (options.flow === "sisu" && (!userToken.valid || !deviceToken.valid || !titleToken.valid)) {
|
||||
const dt = await this.xbl.getDeviceToken(options);
|
||||
const sisu = await this.xbl.doSisuAuth(msaToken, dt, options);
|
||||
return sisu;
|
||||
}
|
||||
|
||||
const ut = userToken.token ?? (await this.xbl.getUserToken(msaToken, options.flow === "msal"));
|
||||
const dt = deviceToken.token ?? (await this.xbl.getDeviceToken(options));
|
||||
const tt = titleToken.token ?? (this.doTitleAuth ? await this.xbl.getTitleToken(msaToken, dt) : undefined);
|
||||
|
||||
const xsts = await this.xbl.getXSTSToken({ userToken: ut, deviceToken: dt, titleToken: tt }, options);
|
||||
return xsts;
|
||||
},
|
||||
() => {
|
||||
this.msa.forceRefresh = true;
|
||||
},
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
async getMinecraftJavaToken(options: any = {}) {
|
||||
const response: any = { token: "", entitlements: {}, profile: {} };
|
||||
const response: any = { token: "", entitlements: {} as any, profile: {} as any };
|
||||
if (await this.mca.verifyTokens()) {
|
||||
const { token } = await this.mca.getCachedAccessToken();
|
||||
response.token = token;
|
||||
|
@ -211,15 +163,43 @@ export class CustomAuthflow {
|
|||
}
|
||||
|
||||
if (options.fetchEntitlements) {
|
||||
response.entitlements = await this.mca.fetchEntitlements(response.token);
|
||||
response.entitlements = await this.mca.fetchEntitlements(response.token).catch((e) => {});
|
||||
}
|
||||
if (options.fetchProfile) {
|
||||
response.profile = await this.mca.fetchProfile(response.token);
|
||||
response.profile = await this.mca.fetchProfile(response.token).catch((e) => {});
|
||||
}
|
||||
if (options.fetchCertificates) {
|
||||
response.certificates = await this.mca.fetchCertificates(response.token);
|
||||
response.certificates = await this.mca.fetchCertificates(response.token).catch((e) => []);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
async getMinecraftBedrockToken(publicKey) {
|
||||
// TODO: Fix cache, in order to do cache we also need to cache the ECDH keys so disable it
|
||||
// is this even a good idea to cache?
|
||||
if ((await this.mba.verifyTokens()) && false) {
|
||||
// eslint-disable-line
|
||||
const { chain } = this.mba.getCachedAccessToken();
|
||||
return chain;
|
||||
} else {
|
||||
if (!publicKey) throw new Error("Need to specifiy a ECDH x509 URL encoded public key");
|
||||
return await retry(
|
||||
async () => {
|
||||
const xsts = await this.getXboxToken(Endpoints.BedrockXSTSRelyingParty);
|
||||
const token = await this.mba.getAccessToken(publicKey, xsts);
|
||||
// If we want to auth with a title ID, make sure there's a TitleID in the response
|
||||
const body = JSON.parse(Buffer.from(token.chain[1].split(".")[1], "base64").toString());
|
||||
if (!body.extraData.titleId && this.doTitleAuth) {
|
||||
throw Error("missing titleId in response");
|
||||
}
|
||||
return token.chain;
|
||||
},
|
||||
() => {
|
||||
this.xbl.forceRefresh = true;
|
||||
},
|
||||
2
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user