UNPKG

minecraft-mitm

Version:

something like mitmproxy but for minecraft

126 lines (112 loc) 4.78 kB
import net from "net"; import { Packet } from "./packet.js"; import { stages } from "./socketdata.js"; import { Logger } from "./logger.js"; import { compressed } from "./compressed.js"; const VERBOSE_DEBUG = false; export class Client { constructor(remoteAddr, remotePort, protocolVersion) { this.client = new net.Socket(); this.ready = false; this.remoteAddr = remoteAddr; this.remotePort = remotePort; this.compress = false; this.compressSize = -1; this.encrypt = false; this.loggedIn = false; this.protocolVersion = protocolVersion; this.handlerSet = false; this.cbs = []; this.cbsRaw = []; this.compressCb = () => null; this.bannerCb = () => null; if(VERBOSE_DEBUG) this.client.on("data", d => Logger.log("client data", d)); let partial = Buffer.from(""); this.client.on("data", d => { partial = Buffer.concat([partial, d]); while(partial.length > 0) { let vi, D, orig = partial; try { [vi, D] = Packet.readVarInt(partial); } catch(_) { break; } const viL = orig.length - D.length; if(vi > D.length) break; d = partial.subarray(0, vi + viL); partial = partial.subarray(vi + viL); this.cbsRaw.forEach(x => x(d)); try { const pt = new Packet(d, this.compress && compressed(d, this.compressSize)); if(/*this.compress && this.getlen(d) > this.compressSize*/false) { const pack = new Packet(d, true); d = Packet.constructSmart(pack.packetID, pack.data, this.compress, this.compressSize); } else if(pt.packetID == 3 && !this.loggedIn) { this.compress = true; this.compressSize = Packet.readVarInt(pt.data)[0]; this.compressCb(Packet.readVarInt(pt.data)[0]); } else if(pt.packetID == 0 && !this.loggedIn) { try { const str = pt.readString(); this.bannerCb(str); } catch(_) {} } else this.cbs.forEach(x => x(d)); // xD } catch(_) { this.cbs.forEach(x => x(d)); } } }); this.client.connect(remotePort, remoteAddr, () => { this.ready = true; }); } waitTillReady() { return new Promise(resolve => { const f = () => this.ready ? resolve() : setTimeout(f); f(); }) } handshake(nextStage) { const packRaw = Buffer.concat([ Packet.constructVarInt(this.protocolVersion), Packet.constructString(this.remoteAddr), Packet.constructShort(this.remotePort), Packet.constructVarInt(nextStage == stages.STATUS ? 1 : 2) ]); // Logger.log("packraw", packRaw); this.client.write(Packet.construct(0, packRaw)); } getlen(d) { return Packet.readVarInt(Packet.readVarInt(d)[1])[0]; } getBanner() { return new Promise(resolve => { this.bannerCb = d => { try { const j = JSON.parse(d); resolve(j); } catch(_) {} } // let data = Buffer.from(""); // TODO: replace with this.bannerCb // this.client.on("data", dat => { // // Logger.log("resp from serv", dat); // data = Buffer.concat([data, dat]); // while(data.length > 0) { // let vi, D; // try { [vi, D] = Packet.readVarInt(data); } catch(_) { break; } // // const pack = new Packet(data, this.compress && compressed(data, this.compressSize)); // // const v = pack.readVarInt(); // dat = data.subarray(0, vi + Packet.constructVarInt(vi).length); // data = data.subarray(vi + Packet.constructVarInt(vi).length); // const pack = new Packet(dat, this.compress && compressed(dat, this.compressSize)); // resolve(JSON.parse(pack.readString())); // } // }); this.client.write(Packet.construct(0, Buffer.from(""))); }); } setLoggedIn(value) { this.loggedIn = value; } loginStart(username, uuid) { this.client.write(Packet.construct(0, Buffer.concat([Packet.constructString(username), uuid]))); } }