mirror of
https://github.com/WorldEditAxe/eaglerproxy.git
synced 2024-12-22 07:14:13 -08:00
shut up prismarine libraries' hardcoded loggers
This commit is contained in:
parent
3e6f59b9e0
commit
9f6b0d5692
225
src/plugins/EagProxyAAS/CustomAuthflow.ts
Normal file
225
src/plugins/EagProxyAAS/CustomAuthflow.ts
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
import fs from "fs";
|
||||||
|
import path from "path";
|
||||||
|
import crypto from "crypto";
|
||||||
|
|
||||||
|
import { createHash } from "prismarine-auth/src/common/Util.js";
|
||||||
|
import Constants from "prismarine-auth/src/common/Constants.js";
|
||||||
|
const { Endpoints, msalConfig } = Constants;
|
||||||
|
|
||||||
|
import LiveTokenManager from "prismarine-auth/src/TokenManagers/LiveTokenManager.js";
|
||||||
|
import JavaTokenManager from "prismarine-auth/src/TokenManagers/MinecraftJavaTokenManager.js";
|
||||||
|
import XboxTokenManager from "prismarine-auth/src/TokenManagers/XboxTokenManager.js";
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||||
|
await beforeRetry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CustomAuthflow {
|
||||||
|
username: string;
|
||||||
|
options: any;
|
||||||
|
codeCallback: any;
|
||||||
|
msa: any;
|
||||||
|
doTitleAuth: boolean;
|
||||||
|
xbl: any;
|
||||||
|
mba: any;
|
||||||
|
mca: any;
|
||||||
|
|
||||||
|
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."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.options = options || { flow: "msal" };
|
||||||
|
this.initTokenManagers(username, cache);
|
||||||
|
this.codeCallback = codeCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 })
|
||||||
|
);
|
||||||
|
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 })
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
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.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMsaToken() {
|
||||||
|
if (await this.msa.verifyTokens()) {
|
||||||
|
const { token } = await this.msa.getAccessToken();
|
||||||
|
return token;
|
||||||
|
} else {
|
||||||
|
const ret = await this.msa.authDeviceCode((response) => {
|
||||||
|
if (this.codeCallback) return this.codeCallback(response);
|
||||||
|
console.info("[msa] First time signing in. Please authenticate now:");
|
||||||
|
console.info(response.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret.accessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getXboxToken(
|
||||||
|
relyingParty = this.options.relyingParty || Endpoints.XboxRelyingParty
|
||||||
|
) {
|
||||||
|
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 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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMinecraftJavaToken(options: any = {}) {
|
||||||
|
const response: any = { token: "", entitlements: {}, profile: {} };
|
||||||
|
if (await this.mca.verifyTokens()) {
|
||||||
|
const { token } = await this.mca.getCachedAccessToken();
|
||||||
|
response.token = token;
|
||||||
|
} else {
|
||||||
|
await retry(
|
||||||
|
async () => {
|
||||||
|
const xsts = await this.getXboxToken(Endpoints.PCXSTSRelyingParty);
|
||||||
|
response.token = await this.mca.getAccessToken(xsts);
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
this.xbl.forceRefresh = true;
|
||||||
|
},
|
||||||
|
2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.fetchEntitlements) {
|
||||||
|
response.entitlements = await this.mca.fetchEntitlements(response.token);
|
||||||
|
}
|
||||||
|
if (options.fetchProfile) {
|
||||||
|
response.profile = await this.mca.fetchProfile(response.token);
|
||||||
|
}
|
||||||
|
if (options.fetchCertificates) {
|
||||||
|
response.certificates = await this.mca.fetchCertificates(response.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import { randomUUID } from "crypto";
|
import { randomUUID } from "crypto";
|
||||||
import EventEmitter from "events";
|
import EventEmitter from "events";
|
||||||
import pauth from "prismarine-auth";
|
import pauth from "prismarine-auth";
|
||||||
import debug from "debug";
|
import { CustomAuthflow } from "./CustomAuthflow.js";
|
||||||
|
|
||||||
const { Authflow, Titles } = pauth;
|
const { Authflow, Titles } = pauth;
|
||||||
const Enums = PLUGIN_MANAGER.Enums;
|
const Enums = PLUGIN_MANAGER.Enums;
|
||||||
|
@ -34,7 +34,7 @@ class InMemoryCache {
|
||||||
export function auth(): EventEmitter {
|
export function auth(): EventEmitter {
|
||||||
const emitter = new EventEmitter();
|
const emitter = new EventEmitter();
|
||||||
const userIdentifier = randomUUID();
|
const userIdentifier = randomUUID();
|
||||||
const flow = new Authflow(
|
const flow = new CustomAuthflow(
|
||||||
userIdentifier,
|
userIdentifier,
|
||||||
({ username, cacheName }) => new InMemoryCache(),
|
({ username, cacheName }) => new InMemoryCache(),
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@ import metadata from "./metadata.json" assert { type: "json" };
|
||||||
import { config } from "./config.js";
|
import { config } from "./config.js";
|
||||||
import { createServer } from "minecraft-protocol";
|
import { createServer } from "minecraft-protocol";
|
||||||
import { ClientState, ConnectionState, ServerGlobals } from "./types.js";
|
import { ClientState, ConnectionState, ServerGlobals } from "./types.js";
|
||||||
import { handleConnect, setSG } from "./utils.js";
|
import { handleConnect, hushConsole, setSG } from "./utils.js";
|
||||||
|
|
||||||
const PluginManager = PLUGIN_MANAGER;
|
const PluginManager = PLUGIN_MANAGER;
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@ const MineProtocol = PluginManager.MineProtocol;
|
||||||
const EaglerSkins = PluginManager.EaglerSkins;
|
const EaglerSkins = PluginManager.EaglerSkins;
|
||||||
const Util = PluginManager.Util;
|
const Util = PluginManager.Util;
|
||||||
|
|
||||||
|
hushConsole();
|
||||||
|
|
||||||
const logger = new Logger("EaglerProxyAAS");
|
const logger = new Logger("EaglerProxyAAS");
|
||||||
logger.info(`Starting ${metadata.name} v${metadata.version}...`);
|
logger.info(`Starting ${metadata.name} v${metadata.version}...`);
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|
|
@ -23,6 +23,14 @@ const logger = new PLUGIN_MANAGER.Logger("PlayerHandler");
|
||||||
|
|
||||||
let SERVER: ServerGlobals = null;
|
let SERVER: ServerGlobals = null;
|
||||||
|
|
||||||
|
export function hushConsole() {
|
||||||
|
const ignoredMethod = () => {};
|
||||||
|
global.console.info = ignoredMethod;
|
||||||
|
global.console.warn = ignoredMethod;
|
||||||
|
global.console.error = ignoredMethod;
|
||||||
|
global.console.debug = ignoredMethod;
|
||||||
|
}
|
||||||
|
|
||||||
export function setSG(svr: ServerGlobals) {
|
export function setSG(svr: ServerGlobals) {
|
||||||
SERVER = svr;
|
SERVER = svr;
|
||||||
}
|
}
|
||||||
|
@ -479,11 +487,6 @@ export async function onConnect(client: ClientState) {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
sendCustomMessage(
|
|
||||||
client.gameClient,
|
|
||||||
"Attempting to switch servers, please wait... (if you don't get connected to the target server after a while, the server might not be a Minecraft server at all)",
|
|
||||||
"gray"
|
|
||||||
);
|
|
||||||
const player = PLUGIN_MANAGER.proxy.players.get(
|
const player = PLUGIN_MANAGER.proxy.players.get(
|
||||||
client.gameClient.username
|
client.gameClient.username
|
||||||
);
|
);
|
||||||
|
@ -782,11 +785,6 @@ export async function onConnect(client: ClientState) {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
sendCustomMessage(
|
|
||||||
client.gameClient,
|
|
||||||
"Attempting to switch servers, please wait... (if you don't get connected to the target server for a while, the server might be online only)",
|
|
||||||
"gray"
|
|
||||||
);
|
|
||||||
const player = PLUGIN_MANAGER.proxy.players.get(
|
const player = PLUGIN_MANAGER.proxy.players.get(
|
||||||
client.gameClient.username
|
client.gameClient.username
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user