Remove precompiled .js files

This commit is contained in:
q13x 2022-12-20 11:20:28 -08:00
parent 37638f2f33
commit 9965b1370e
11 changed files with 2 additions and 463 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
node_modules
insecureSocks
build

View File

@ -1,2 +0,0 @@
export class ProxiedPlayer {
}

View File

@ -1,19 +0,0 @@
export const config = {
name: "BasedProxy",
port: 80,
maxPlayers: 20,
motd: {
iconURL: null,
l1: "hi",
l2: "lol"
},
server: {
host: "127.0.0.1",
port: 25565
},
security: {
enabled: false,
key: null,
cert: null
}
};

View File

@ -1,22 +0,0 @@
export var EaglerPacketId;
(function (EaglerPacketId) {
EaglerPacketId[EaglerPacketId["IDENTIFY_CLIENT"] = 1] = "IDENTIFY_CLIENT";
EaglerPacketId[EaglerPacketId["IDENTIFY_SERVER"] = 2] = "IDENTIFY_SERVER";
EaglerPacketId[EaglerPacketId["LOGIN"] = 4] = "LOGIN";
EaglerPacketId[EaglerPacketId["LOGIN_ACK"] = 5] = "LOGIN_ACK";
EaglerPacketId[EaglerPacketId["SKIN"] = 7] = "SKIN";
EaglerPacketId[EaglerPacketId["C_READY"] = 8] = "C_READY";
EaglerPacketId[EaglerPacketId["COMPLETE_HANDSHAKE"] = 9] = "COMPLETE_HANDSHAKE";
EaglerPacketId[EaglerPacketId["DISCONNECT"] = 255] = "DISCONNECT";
})(EaglerPacketId || (EaglerPacketId = {}));
export var DisconnectReason;
(function (DisconnectReason) {
DisconnectReason[DisconnectReason["UNEXPECTED_PACKET"] = 1] = "UNEXPECTED_PACKET";
DisconnectReason[DisconnectReason["DUPLICATE_USERNAME"] = 2] = "DUPLICATE_USERNAME";
DisconnectReason[DisconnectReason["BAD_USERNAME"] = 3] = "BAD_USERNAME";
DisconnectReason[DisconnectReason["SERVER_DISCONNECT"] = 4] = "SERVER_DISCONNECT";
DisconnectReason[DisconnectReason["CUSTOM"] = 8] = "CUSTOM";
})(DisconnectReason || (DisconnectReason = {}));
export const MAGIC_BUILTIN_SKIN_BYTES = [0x00, 0x05, 0x01, 0x00, 0x00, 0x00];
export const MAGIC_ENDING_IDENTIFYS_BYTES = [0x00, 0x00, 0x00];
// Afterwards, forward 0x01 (Join Game, Clientbound) and everything after that

View File

@ -1,67 +0,0 @@
import { readFileSync } from "fs";
import * as https from "https";
import { WebSocketServer } from "ws";
import { ProxiedPlayer } from "./classes.js";
import { config } from "./config.js";
import { handlePacket } from "./listener.js";
import { Logger } from "./logger.js";
import { BRANDING, NETWORK_VERSION, VERSION } from "./meta.js";
import { State } from "./types.js";
import { genUUID } from "./utils.js";
const logger = new Logger("EagXProxy");
const connectionLogger = new Logger("ConnectionHandler");
global.PROXY = {
brand: BRANDING,
version: VERSION,
MOTDVersion: NETWORK_VERSION,
serverName: config.name,
secure: false,
proxyUUID: genUUID(config.name),
MOTD: {
icon: null,
motd: [config.motd.l1, config.motd.l2]
},
playerStats: {
max: config.maxPlayers,
onlineCount: 0
},
wsServer: null,
players: new Map(),
logger: logger,
config: config
};
PROXY.playerStats.onlineCount = PROXY.players.size;
let server;
if (PROXY.config.security.enabled) {
logger.info(`Starting SECURE WebSocket proxy on port ${config.port}...`);
if (process.env.REPL_SLUG) {
logger.warn("You appear to be running the proxy on Repl.it with encryption enabled. Please note that Repl.it by default provides encryption, and enabling encryption may or may not prevent you from connecting to the server.");
}
server = new WebSocketServer({
server: https.createServer({
key: readFileSync(config.security.key),
cert: readFileSync(config.security.cert)
}).listen(config.port)
});
}
else {
logger.info(`Starting INSECURE WebSocket proxy on port ${config.port}...`);
server = new WebSocketServer({
port: config.port
});
}
PROXY.wsServer = server;
server.addListener('connection', c => {
connectionLogger.debug(`[CONNECTION] New inbound WebSocket connection from [/${c._socket.remoteAddress}:${c._socket.remotePort}]. (${c._socket.remotePort} -> ${config.port})`);
const plr = new ProxiedPlayer();
plr.ws = c;
plr.ip = c._socket.remoteAddress;
plr.remotePort = c._socket.remotePort;
plr.state = State.PRE_HANDSHAKE;
c.on('message', msg => {
handlePacket(msg, plr);
});
});
server.on('listening', () => {
logger.info(`Successfully started${config.security.enabled ? " [secure]" : ""} WebSocket proxy on port ${config.port}!`);
});

View File

@ -1,26 +0,0 @@
import { Logger } from "./logger.js";
import { handleMotd } from "./motd.js";
import { State } from "./types.js";
import { doHandshake } from "./utils.js";
const logger = new Logger("PacketHandler");
export function handlePacket(packet, client) {
if (client.state == State.PRE_HANDSHAKE) {
if (packet.toString() === "Accept: MOTD") {
handleMotd(client);
}
else if (!client._handled) {
;
client._handled = true;
doHandshake(client, packet);
}
}
else if (client.state == State.POST_HANDSHAKE) {
if (!client.remoteConnection || client.remoteConnection.socket.closed) {
logger.warn(`Player ${client.username} is marked as post handshake, but is disconnected from the game server? Disconnecting due to illegal state.`);
client.ws.close();
}
else {
client.remoteConnection.writeRaw(packet);
}
}
}

View File

@ -1,54 +0,0 @@
import { Chalk } from "chalk";
const color = new Chalk({ level: 2 });
let global_verbose = false;
export function verboseLogging(newVal) {
global_verbose = (newVal !== null && newVal !== void 0 ? newVal : global_verbose) ? false : true;
}
function jsonLog(type, message) {
return JSON.stringify({
type: type,
message: message
}) + "\n";
}
export class Logger {
constructor(name, verbose) {
this.jsonLog = process.argv.includes("--json") || process.argv.includes("-j");
this.loggerName = name;
if (verbose)
this.verbose = verbose;
else
this.verbose = global_verbose;
}
info(s) {
if (!this.jsonLog)
process.stdout.write(`${color.green("I")} ${color.gray(new Date().toISOString())} ${color.reset(`${color.yellow(`${this.loggerName}:`)} ${s}`)}\n`);
else
process.stdout.write(jsonLog("info", s));
}
warn(s) {
if (!this.jsonLog)
process.stdout.write(`${color.yellow("W")} ${color.gray(new Date().toISOString())} ${color.yellow(`${color.yellow(`${this.loggerName}:`)} ${s}`)}\n`);
else
process.stderr.write(jsonLog("warn", s));
}
error(s) {
if (!this.jsonLog)
process.stderr.write(`* ${color.red("E")} ${color.gray(new Date().toISOString())} ${color.redBright(`${color.red(`${this.loggerName}:`)} ${s}`)}\n`);
else
process.stderr.write(jsonLog("error", s));
}
fatal(s) {
if (!this.jsonLog)
process.stderr.write(`** ${color.red("F!")} ${color.gray(new Date().toISOString())} ${color.bgRedBright(color.redBright(`${color.red(`${this.loggerName}:`)} ${s}`))}\n`);
else
process.stderr.write(jsonLog("fatal", s));
}
debug(s) {
if (this.verbose || global_verbose) {
if (!this.jsonLog)
process.stderr.write(`${color.gray("D")} ${color.gray(new Date().toISOString())} ${color.gray(`${color.gray(`${this.loggerName}:`)} ${s}`)}\n`);
else
process.stderr.write(jsonLog("debug", s));
}
}
}

View File

@ -1,3 +0,0 @@
export const BRANDING = Object.freeze("EaglerXProxy");
export const VERSION = "1.0.0";
export const NETWORK_VERSION = Object.freeze(BRANDING + "/" + VERSION);

34
motd.js
View File

@ -1,34 +0,0 @@
export function handleMotd(player) {
const names = [];
for (const [username, player] of PROXY.players) {
if (names.length > 0) {
names.push(`(and ${PROXY.players.size - names.length} more)`);
break;
}
else {
names.push(username);
}
}
player.ws.send(JSON.stringify({
brand: PROXY.brand,
cracked: true,
data: {
cache: true,
icon: PROXY.MOTD.icon ? true : false,
max: PROXY.playerStats.max,
motd: PROXY.MOTD.motd,
online: PROXY.playerStats.onlineCount,
players: names
},
name: PROXY.serverName,
secure: false,
time: Date.now(),
type: "motd",
uuid: PROXY.proxyUUID,
vers: PROXY.MOTDVersion
}));
if (PROXY.MOTD.icon) {
player.ws.send(PROXY.MOTD.icon);
}
player.ws.close();
}

View File

@ -1,6 +0,0 @@
export var State;
(function (State) {
State[State["PRE_HANDSHAKE"] = 0] = "PRE_HANDSHAKE";
State[State["POST_HANDSHAKE"] = 1] = "POST_HANDSHAKE";
State[State["DISCONNECTED"] = 2] = "DISCONNECTED";
})(State || (State = {}));

229
utils.js
View File

@ -1,229 +0,0 @@
import { v3 } from "uuid";
import { encodeULEB128 as encodeVarInt, decodeULEB128 as decodeVarInt, decodeSLEB128 as decodeSVarInt } from "@thi.ng/leb128";
import { DisconnectReason, EaglerPacketId, MAGIC_ENDING_IDENTIFYS_BYTES } from "./eaglerPacketDef.js";
import { Logger } from "./logger.js";
import { State } from "./types.js";
import { toBuffer } from "uuid-buffer";
import * as mc from "minecraft-protocol";
import { config } from "./config.js";
const MAGIC_UUID = "a7e774bc-7ea4-11ed-9a58-1f9e14304a59";
const logger = new Logger("LoginHandler");
const USERNAME_REGEX = /[^0-9^a-z^A-Z^_]/gi;
export function genUUID(user) {
return v3(user, MAGIC_UUID);
}
export function bufferizeUUID(uuid) {
return toBuffer(uuid);
}
export function validateUsername(user) {
if (user.length > 20)
throw new Error("Username is too long!");
if (!!user.match(USERNAME_REGEX))
throw new Error("Invalid username. Username can only contain alphanumeric characters, and the underscore (_) character.");
}
export function disconnect(player, message, code) {
if (player.state == State.POST_HANDSHAKE) {
const messageLen = encodeVarInt(message.length);
const d = Buffer.alloc(1 + messageLen.length + message.length);
d.set([0x40, ...messageLen, ...Buffer.from(message)]);
player.ws.send(d);
player.ws.close();
}
else {
const messageLen = encodeVarInt(message.length), codeEnc = encodeVarInt(code !== null && code !== void 0 ? code : DisconnectReason.CUSTOM);
const d = Buffer.alloc(1 + codeEnc.length + messageLen.length + message.length);
d.set([0xff, ...codeEnc, ...messageLen, ...Buffer.from(message)]);
player.ws.send(d);
player.ws.close();
}
}
export function awaitPacket(ws, id) {
return new Promise((res, rej) => {
let resolved = false;
const msgCb = (msg) => {
if (id != null && msg[0] == id) {
resolved = true;
ws.removeEventListener('message', msgCb);
ws.removeEventListener('close', discon);
ws.setMaxListeners(ws.getMaxListeners() - 2 < 0 ? 5 : ws.getMaxListeners() - 2);
res(msg);
}
else if (id == null) {
resolved = true;
ws.removeEventListener('message', msgCb);
ws.removeEventListener('close', discon);
ws.setMaxListeners(ws.getMaxListeners() - 2 < 0 ? 5 : ws.getMaxListeners() - 2);
res(msg);
}
};
const discon = () => {
resolved = true;
ws.removeEventListener('message', msgCb);
ws.removeEventListener('close', discon);
ws.setMaxListeners(ws.getMaxListeners() - 2 < 0 ? 5 : ws.getMaxListeners() - 2);
rej("Connection closed");
};
ws.setMaxListeners(ws.getMaxListeners() + 2);
ws.on('message', msgCb);
ws.on('close', discon);
setTimeout(() => {
ws.removeEventListener('message', msgCb);
ws.removeEventListener('close', discon);
ws.setMaxListeners(ws.getMaxListeners() - 2 < 0 ? 5 : ws.getMaxListeners() - 2);
rej("Timed out");
}, 10000);
});
}
export function loginServer(ip, port, client) {
return new Promise((res, rej) => {
let receivedCompression = false;
const mcClient = mc.createClient({
host: ip,
port: port,
auth: 'offline',
version: '1.8.8',
username: client.username
});
mcClient.on('error', err => {
mcClient.end();
rej(err);
});
mcClient.on('end', () => {
client.ws.close();
});
mcClient.on('connect', () => {
client.remoteConnection = mcClient;
logger.info(`Player ${client.username} has been connected to the server.`);
res();
});
mcClient.on('raw', p => {
if (p[0] == 0x03 && !receivedCompression) {
receivedCompression = true;
const compT = {
id: null,
thres: null
};
const id = decodeVarInt(p);
compT.id = Number(id[0]);
const thres = decodeSVarInt(p.subarray(id[1]));
compT.thres = thres[0];
client.compressionThreshold = compT.thres;
client.ws.send(p);
}
else {
client.ws.send(p);
}
});
});
}
export async function doHandshake(client, initialPacket) {
client.ws.on('close', () => {
client.state = State.DISCONNECTED;
if (client.remoteConnection) {
client.remoteConnection.end();
}
PROXY.players.delete(client.username);
PROXY.playerStats.onlineCount -= 1;
logger.info(`Client [/${client.ip}:${client.remotePort}]${client.username ? ` (${client.username})` : ""} disconnected from the server.`);
});
if (PROXY.players.size + 1 > PROXY.playerStats.max) {
disconnect(client, "The proxy is full!", DisconnectReason.CUSTOM);
return;
}
const identifyC = {
id: null,
brandingLen: null,
branding: null,
verLen: null,
ver: null
};
if (true) {
// save namespace by nesting func declarations in a if true statement
const Iid = decodeVarInt(initialPacket);
identifyC.id = Number(Iid[0]);
const brandingLen = decodeVarInt(initialPacket.subarray(Iid[1] + 2));
identifyC.brandingLen = Number(brandingLen[0]);
identifyC.branding = initialPacket.subarray(brandingLen[1] + Iid[1] + 2, brandingLen[1] + Iid[1] + Number(brandingLen[0]) + 2).toString();
const verLen = decodeVarInt(initialPacket.subarray(brandingLen[1] + Iid[1] + Number(brandingLen[0]) + 2));
identifyC.verLen = Number(verLen[0]);
identifyC.ver = initialPacket.subarray(brandingLen[1] + Number(brandingLen[0]) + Iid[1] + verLen[1] + 2).toString();
}
if (true) {
const brandingLen = encodeVarInt(PROXY.brand.length), brand = PROXY.brand;
const verLen = encodeVarInt(PROXY.version.length), version = PROXY.version;
const buff = Buffer.alloc(2 + MAGIC_ENDING_IDENTIFYS_BYTES.length + brandingLen.length + brand.length + verLen.length + version.length);
buff.set([EaglerPacketId.IDENTIFY_SERVER, 0x01, ...brandingLen, ...Buffer.from(brand), ...verLen, ...Buffer.from(version), ...Buffer.from(MAGIC_ENDING_IDENTIFYS_BYTES)]);
client.ws.send(buff);
}
client.clientBrand = identifyC.branding;
const login = await awaitPacket(client.ws);
const loginP = {
id: null,
usernameLen: null,
username: null,
randomStrLen: null,
randomStr: null,
nullByte: null
};
if (login[0] === EaglerPacketId.LOGIN) {
const Iid = decodeVarInt(login);
loginP.id = Number(Iid[0]);
const usernameLen = decodeVarInt(login.subarray(loginP[1]));
loginP.usernameLen = Number(usernameLen[0]);
loginP.username = login.subarray(Iid[1] + usernameLen[1], Iid[1] + usernameLen[1] + loginP.usernameLen).toString();
const randomStrLen = decodeVarInt(login.subarray(Iid[1] + usernameLen[1] + loginP.usernameLen));
loginP.randomStrLen = Number(randomStrLen[0]);
loginP.randomStr = login.subarray(Iid[1] + usernameLen[1] + loginP.usernameLen + randomStrLen[1], Iid[1] + usernameLen[1] + loginP.usernameLen + randomStrLen[1] + loginP.randomStrLen).toString();
client.username = loginP.username;
client.uuid = genUUID(client.username);
try {
validateUsername(client.username);
}
catch (err) {
disconnect(client, err.message, DisconnectReason.BAD_USERNAME);
return;
}
if (PROXY.players.has(client.username)) {
disconnect(client, `Duplicate username: ${client.username}. Please connect under a different username.`, DisconnectReason.DUPLICATE_USERNAME);
return;
}
PROXY.players.set(client.username, client);
if (true) {
const usernameLen = encodeVarInt(client.username.length), username = client.username;
const uuidLen = encodeVarInt(client.uuid.length), uuid = client.uuid;
const buff = Buffer.alloc(1 + usernameLen.length + username.length + uuidLen.length + uuid.length);
buff.set([EaglerPacketId.LOGIN_ACK, ...usernameLen, ...Buffer.from(username), ...uuidLen, ...Buffer.from(uuid)]);
client.ws.send(buff);
if (true) {
const [skin, ready] = await Promise.all([awaitPacket(client.ws, EaglerPacketId.SKIN), awaitPacket(client.ws, EaglerPacketId.C_READY)]);
if (ready[0] != 0x08) {
logger.error(`Client [/${client.ip}:${client.remotePort}] sent an unexpected packet! Disconnecting.`);
disconnect(client, "Received bad packet", DisconnectReason.UNEXPECTED_PACKET);
client.ws.close();
return;
}
const buff = Buffer.alloc(1);
buff.set([EaglerPacketId.COMPLETE_HANDSHAKE]);
client.ws.send(buff);
client.state = State.POST_HANDSHAKE;
PROXY.playerStats.onlineCount += 1;
logger.info(`Client [/${client.ip}:${client.remotePort}] authenticated as player "${client.username}" and passed handshake. Connecting!`);
try {
await loginServer(config.server.host, config.server.port, client);
}
catch (err) {
logger.error(`Could not connect to remote server at [/${config.server.host}:${config.server.port}]: ${err}`);
disconnect(client, "Failed to connect to server. Please try again later.", DisconnectReason.CUSTOM);
client.state = State.DISCONNECTED;
client.ws.close();
return;
}
}
}
}
else {
logger.error(`Client [/${client.ip}:${client.remotePort}] sent an unexpected packet! Disconnecting.`);
disconnect(client, "Received bad packet", DisconnectReason.UNEXPECTED_PACKET);
client.ws.close();
}
}