mirror of
https://github.com/WorldEditAxe/eaglerproxy.git
synced 2024-11-24 14:36:05 -08:00
Added support for EasyMC auth
This commit is contained in:
parent
fed9ac786c
commit
2059fa8a44
108
src/plugins/EagProxyAAS/auth_easymc.ts
Normal file
108
src/plugins/EagProxyAAS/auth_easymc.ts
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
import mc from "minecraft-protocol";
|
||||||
|
import { Enums } from "../../proxy/Enums.js";
|
||||||
|
|
||||||
|
export async function getTokenProfileEasyMc(token: string): Promise<object> {
|
||||||
|
const fetchOptions = {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({
|
||||||
|
token,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
const res = await fetch(
|
||||||
|
"https://api.easymc.io/v1/token/redeem",
|
||||||
|
fetchOptions
|
||||||
|
);
|
||||||
|
const resJson = await res.json();
|
||||||
|
|
||||||
|
if (resJson.error)
|
||||||
|
throw new Error(Enums.ChatColor.RED + `EasyMC: ${resJson.error}`);
|
||||||
|
if (!resJson)
|
||||||
|
throw new Error(
|
||||||
|
Enums.ChatColor.RED + "EasyMC replied with an empty response!?"
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
resJson.session?.length !== 43 ||
|
||||||
|
resJson.mcName?.length < 3 ||
|
||||||
|
resJson.uuid?.length !== 36
|
||||||
|
)
|
||||||
|
throw new Error(
|
||||||
|
Enums.ChatColor.RED + "Invalid response from EasyMC received!"
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
auth: "mojang",
|
||||||
|
sessionServer: "https://sessionserver.easymc.io",
|
||||||
|
username: resJson.mcName,
|
||||||
|
haveCredentials: true,
|
||||||
|
session: {
|
||||||
|
accessToken: resJson.session,
|
||||||
|
selectedProfile: {
|
||||||
|
name: resJson.mcName,
|
||||||
|
id: resJson.uuid,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function easyMcAuth(client, options) {
|
||||||
|
const fetchOptions = {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({
|
||||||
|
token: options.easyMcToken,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const res = await fetch(
|
||||||
|
"https://api.easymc.io/v1/token/redeem",
|
||||||
|
fetchOptions
|
||||||
|
);
|
||||||
|
const resJson = await res.json();
|
||||||
|
if (resJson.error)
|
||||||
|
throw new Error(Enums.ChatColor.RED + `EasyMC: ${resJson.error}`);
|
||||||
|
if (!resJson)
|
||||||
|
throw new Error(
|
||||||
|
Enums.ChatColor.RED + "EasyMC replied with an empty response!?"
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
resJson.session?.length !== 43 ||
|
||||||
|
resJson.mcName?.length < 3 ||
|
||||||
|
resJson.uuid?.length !== 36
|
||||||
|
)
|
||||||
|
throw new Error(
|
||||||
|
Enums.ChatColor.RED + "Invalid response from EasyMC received!"
|
||||||
|
);
|
||||||
|
const session = {
|
||||||
|
accessToken: resJson.session,
|
||||||
|
selectedProfile: {
|
||||||
|
name: resJson.mcName,
|
||||||
|
id: resJson.uuid,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
options.haveCredentials = true;
|
||||||
|
client.session = session;
|
||||||
|
options.username = client.username = session.selectedProfile.name;
|
||||||
|
options.accessToken = session.accessToken;
|
||||||
|
client.emit("session", session);
|
||||||
|
} catch (error) {
|
||||||
|
client.emit("error", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
options.connect(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEasyMcClientOptions(token: string) {
|
||||||
|
if (token.length !== 20) {
|
||||||
|
throw new Error(
|
||||||
|
Enums.ChatColor.RED +
|
||||||
|
"EasyMC authentication requires an alt token. See https://easymc.io/get ."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
auth: easyMcAuth,
|
||||||
|
easyMcToken: token,
|
||||||
|
sessionServer: "https://sessionserver.easymc.io",
|
||||||
|
username: Buffer.alloc(0),
|
||||||
|
};
|
||||||
|
}
|
338
src/plugins/EagProxyAAS/commands.ts
Normal file
338
src/plugins/EagProxyAAS/commands.ts
Normal file
|
@ -0,0 +1,338 @@
|
||||||
|
import { dirname, join } from "path";
|
||||||
|
import { Enums } from "../../proxy/Enums.js";
|
||||||
|
import { Player } from "../../proxy/Player.js";
|
||||||
|
import { config } from "./config.js";
|
||||||
|
import { ConnectType } from "./types.js";
|
||||||
|
import fs from "fs/promises";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
|
const SEPARATOR = "======================================";
|
||||||
|
const METADATA: {
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
version: string;
|
||||||
|
entry_point: string;
|
||||||
|
requirements: any[];
|
||||||
|
load_after: any[];
|
||||||
|
incompatibilities: any[];
|
||||||
|
} = JSON.parse(
|
||||||
|
(
|
||||||
|
await fs.readFile(
|
||||||
|
join(dirname(fileURLToPath(import.meta.url)), "metadata.json")
|
||||||
|
)
|
||||||
|
).toString()
|
||||||
|
);
|
||||||
|
|
||||||
|
export function sendPluginChatMessage(
|
||||||
|
client: Player,
|
||||||
|
...components: { text: string; color: string; [otherFields: string]: any }[]
|
||||||
|
) {
|
||||||
|
if (components.length == 0)
|
||||||
|
throw new Error("There must be one or more passed components!");
|
||||||
|
else {
|
||||||
|
client.ws.send(
|
||||||
|
client.serializer.createPacketBuffer({
|
||||||
|
name: "chat",
|
||||||
|
params: {
|
||||||
|
message: JSON.stringify({
|
||||||
|
text: "[EagPAAS] ",
|
||||||
|
color: "gold",
|
||||||
|
extra: components,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function handleCommand(sender: Player, cmd: string): void {
|
||||||
|
switch (cmd.toLowerCase().split(/ /gim)[0]) {
|
||||||
|
default:
|
||||||
|
sendPluginChatMessage(sender, {
|
||||||
|
text: `"${cmd.split(/ /gim, 1)[0]}" is not a valid command!`,
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "/eag-help":
|
||||||
|
helpCommand(sender);
|
||||||
|
break;
|
||||||
|
case "/eag-toggleparticles":
|
||||||
|
toggleParticles(sender);
|
||||||
|
break;
|
||||||
|
case "/eag-switchservers":
|
||||||
|
switchServer(cmd, sender);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function helpCommand(sender: Player) {
|
||||||
|
sendPluginChatMessage(sender, {
|
||||||
|
text: SEPARATOR,
|
||||||
|
color: "yellow",
|
||||||
|
});
|
||||||
|
sendPluginChatMessage(sender, {
|
||||||
|
text: "Available Commands:",
|
||||||
|
color: "aqua",
|
||||||
|
});
|
||||||
|
sendPluginChatMessage(sender, {
|
||||||
|
text: "/eag-help",
|
||||||
|
color: "light_green",
|
||||||
|
hoverEvent: {
|
||||||
|
action: "show_text",
|
||||||
|
value: Enums.ChatColor.GOLD + "Click me to run this command!",
|
||||||
|
},
|
||||||
|
clickEvent: {
|
||||||
|
action: "run_command",
|
||||||
|
value: "/eag-help",
|
||||||
|
},
|
||||||
|
extra: [
|
||||||
|
{
|
||||||
|
text: " - Prints out a list of commmands",
|
||||||
|
color: "aqua",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
sendPluginChatMessage(sender, {
|
||||||
|
text: "/eag-toggleparticles",
|
||||||
|
color: "light_green",
|
||||||
|
hoverEvent: {
|
||||||
|
action: "show_text",
|
||||||
|
value: Enums.ChatColor.GOLD + "Click me to run this command!",
|
||||||
|
},
|
||||||
|
clickEvent: {
|
||||||
|
action: "run_command",
|
||||||
|
value: "/eag-toggleparticles",
|
||||||
|
},
|
||||||
|
extra: [
|
||||||
|
{
|
||||||
|
text: " - Toggles whether or not particles should be rendered/shown on the client. Turning this on can potentially boost FPS.",
|
||||||
|
color: "aqua",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
sendPluginChatMessage(sender, {
|
||||||
|
text: `/eag-switchservers <mode: online|offline> <ip>${
|
||||||
|
config.allowCustomPorts ? " [port]" : ""
|
||||||
|
}`,
|
||||||
|
color: "light_green",
|
||||||
|
hoverEvent: {
|
||||||
|
action: "show_text",
|
||||||
|
value: Enums.ChatColor.GOLD + "Click me to paste this command to chat!",
|
||||||
|
},
|
||||||
|
clickEvent: {
|
||||||
|
action: "suggest_command",
|
||||||
|
value: `/eag-switchservers <mode: online|offline> <ip>${
|
||||||
|
config.allowCustomPorts ? " [port]" : ""
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
extra: [
|
||||||
|
{
|
||||||
|
text: " - Switch between servers on-the-fly. Switching to servers in online mode requires logging in via online mode or EasyMC!",
|
||||||
|
color: "aqua",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
sendPluginChatMessage(sender, {
|
||||||
|
text: `Running ${METADATA.name} on version v${METADATA.version}.`,
|
||||||
|
color: "gray",
|
||||||
|
});
|
||||||
|
sendPluginChatMessage(sender, {
|
||||||
|
text: SEPARATOR,
|
||||||
|
color: "yellow",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toggleParticles(sender: Player) {
|
||||||
|
const listener = (sender as any)._particleListener;
|
||||||
|
if (listener != null) {
|
||||||
|
sender.removeListener("vanillaPacket", listener);
|
||||||
|
(sender as any)._particleListener = undefined;
|
||||||
|
sendPluginChatMessage(sender, {
|
||||||
|
text: "Disabled particle hider!",
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
(sender as any)._particleListener = (
|
||||||
|
packet: { name: string; params: any; cancel: boolean },
|
||||||
|
origin: "SERVER" | "CLIENT"
|
||||||
|
) => {
|
||||||
|
if (origin == "SERVER") {
|
||||||
|
if (packet.name == "world_particles") {
|
||||||
|
packet.cancel = true;
|
||||||
|
} else if (packet.name == "world_event") {
|
||||||
|
if (packet.params.effectId >= 2000) {
|
||||||
|
packet.cancel = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
sender.on("vanillaPacket", (sender as any)._particleListener);
|
||||||
|
sendPluginChatMessage(sender, {
|
||||||
|
text: "Enabled particle hider!",
|
||||||
|
color: "green",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function switchServer(cmd: string, sender: Player) {
|
||||||
|
if ((sender as any)._serverSwitchLock) {
|
||||||
|
return sendPluginChatMessage(sender, {
|
||||||
|
text: `There is already a pending server switch - please wait, and be patient!`,
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let split = cmd.split(/ /gim).slice(1),
|
||||||
|
mode = split[0]?.toLowerCase(),
|
||||||
|
ip = split[1],
|
||||||
|
port = split[2];
|
||||||
|
if (mode != "online" && mode != "offline") {
|
||||||
|
return sendPluginChatMessage(sender, {
|
||||||
|
text: `Invalid command usage - please provide a valid mode! `,
|
||||||
|
color: "red",
|
||||||
|
extra: [
|
||||||
|
{
|
||||||
|
text: `/eag-switchservers <mode: online|offline> <ip>${
|
||||||
|
config.allowCustomPorts ? " [port]" : ""
|
||||||
|
}.`,
|
||||||
|
color: "gold",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (ip == null) {
|
||||||
|
return sendPluginChatMessage(sender, {
|
||||||
|
text: `Invalid command usage - please provide a valid IP or hostname (like example.com, 1.2.3.4, etc.)! `,
|
||||||
|
color: "red",
|
||||||
|
extra: [
|
||||||
|
{
|
||||||
|
text: `/eag-switchservers <mode: online|offline> <ip>${
|
||||||
|
config.allowCustomPorts ? " [port]" : ""
|
||||||
|
}.`,
|
||||||
|
color: "gold",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
port != null &&
|
||||||
|
(isNaN(Number(port)) || Number(port) < 1 || Number(port) > 65535)
|
||||||
|
) {
|
||||||
|
return sendPluginChatMessage(sender, {
|
||||||
|
text: `Invalid command usage - a port must be a number above 0 and below 65536! `,
|
||||||
|
color: "red",
|
||||||
|
extra: [
|
||||||
|
{
|
||||||
|
text: `/eag-switchservers <mode: online|offline> <ip>${
|
||||||
|
config.allowCustomPorts ? " [port]" : ""
|
||||||
|
}.`,
|
||||||
|
color: "gold",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (port != null && !config.allowCustomPorts) {
|
||||||
|
return sendPluginChatMessage(sender, {
|
||||||
|
text: `Invalid command usage - custom server ports are disabled on this proxy instance! `,
|
||||||
|
color: "red",
|
||||||
|
extra: [
|
||||||
|
{
|
||||||
|
text: `/eag-switchservers <mode: online|offline> <ip>${
|
||||||
|
config.allowCustomPorts ? " [port]" : ""
|
||||||
|
}.`,
|
||||||
|
color: "gold",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let connectionType =
|
||||||
|
mode == "offline" ? ConnectType.OFFLINE : ConnectType.ONLINE,
|
||||||
|
addr = ip,
|
||||||
|
addrPort = Number(port);
|
||||||
|
if (connectionType == ConnectType.ONLINE) {
|
||||||
|
if ((sender as any)._onlineSession == null) {
|
||||||
|
sendPluginChatMessage(sender, {
|
||||||
|
text: `You either connected to this proxy under offline mode, or your online/EasyMC session has timed out and has become invalid.`,
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
return sendPluginChatMessage(sender, {
|
||||||
|
text: `To switch to online servers, please reconnect and log-in through online/EasyMC mode.`,
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const savedAuth = (sender as any)._onlineSession;
|
||||||
|
sendPluginChatMessage(sender, {
|
||||||
|
text: `(joining server under ${savedAuth.username}/your ${
|
||||||
|
savedAuth.isEasyMC ? "EasyMC" : "Minecraft"
|
||||||
|
} account's username)`,
|
||||||
|
color: "aqua",
|
||||||
|
});
|
||||||
|
sendPluginChatMessage(sender, {
|
||||||
|
text: "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. Reconnect and try again.)",
|
||||||
|
color: "gray",
|
||||||
|
});
|
||||||
|
(sender as any)._serverSwitchLock = true;
|
||||||
|
try {
|
||||||
|
await sender.switchServers({
|
||||||
|
host: addr,
|
||||||
|
port: addrPort,
|
||||||
|
version: "1.8.8",
|
||||||
|
keepAlive: false,
|
||||||
|
skipValidation: true,
|
||||||
|
hideErrors: true,
|
||||||
|
...savedAuth,
|
||||||
|
});
|
||||||
|
(sender as any)._serverSwitchLock = false;
|
||||||
|
} catch (err) {
|
||||||
|
if (sender.state! != Enums.ClientState.DISCONNECTED) {
|
||||||
|
sender.disconnect(
|
||||||
|
Enums.ChatColor.RED +
|
||||||
|
`Something went wrong whilst switching servers: ${err.message}${
|
||||||
|
err.code == "ENOTFOUND"
|
||||||
|
? addr.includes(":")
|
||||||
|
? `\n${Enums.ChatColor.GRAY}Suggestion: Replace the : in your IP with a space.`
|
||||||
|
: "\nIs that IP valid?"
|
||||||
|
: ""
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sendPluginChatMessage(sender, {
|
||||||
|
text: `(joining server under ${sender.username}/Eaglercraft username)`,
|
||||||
|
color: "aqua",
|
||||||
|
});
|
||||||
|
sendPluginChatMessage(sender, {
|
||||||
|
text: "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)",
|
||||||
|
color: "gray",
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
(sender as any)._serverSwitchLock = true;
|
||||||
|
await sender.switchServers({
|
||||||
|
host: addr,
|
||||||
|
port: addrPort,
|
||||||
|
version: "1.8.8",
|
||||||
|
username: sender.username,
|
||||||
|
auth: "offline",
|
||||||
|
keepAlive: false,
|
||||||
|
skipValidation: true,
|
||||||
|
hideErrors: true,
|
||||||
|
});
|
||||||
|
(sender as any)._serverSwitchLock = false;
|
||||||
|
} catch (err) {
|
||||||
|
if (sender.state! != Enums.ClientState.DISCONNECTED) {
|
||||||
|
sender.disconnect(
|
||||||
|
Enums.ChatColor.RED +
|
||||||
|
`Something went wrong whilst switching servers: ${err.message}${
|
||||||
|
err.code == "ENOTFOUND"
|
||||||
|
? addr.includes(":")
|
||||||
|
? `\n${Enums.ChatColor.GRAY}Suggestion: Replace the : in your IP with a space.`
|
||||||
|
: "\nIs that IP valid?"
|
||||||
|
: ""
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user