From a44ce9d23e0c279b8b09b806bc24a8fc6bf84f32 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 1 Mar 2025 00:10:05 +0200 Subject: [PATCH] this bot has to be rewritten sometime soon --- bun.lockb | Bin 14199 -> 47887 bytes index.ts | 112 +++++++++++++++--------- package.json | 2 + rcon.ts | 235 --------------------------------------------------- 4 files changed, 75 insertions(+), 274 deletions(-) delete mode 100644 rcon.ts diff --git a/bun.lockb b/bun.lockb index 2f27a09a609d0f1bf2fa923830500f93bef7778f..78c147291c05907f7f2f667939fef382ee3a424a 100755 GIT binary patch literal 47887 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 delta 2647 zcmd5;Yiv|S6rP!G*}a8@wiM`-b_)fX!lm17cUvB}jS^bef&~iOE`eB}NJ*(ed4@*| zmGD;D!=pR|5sVNu0U9D2NF;%XD1?XssTc}~mMA130f`a)&fQ%CKQNg1!`Yns?KgAg z%$ak~oVjm5P!DT1>ghAHPuW+^I6Shg;QY;+MMD=)T)(ycLi4RlYn%(xuB|?`tRB~fJ^W$!0OkhRn*Q9;vVdEsYA!y+5xkw7FN!gTU%W<1;!(x7>WKHtN;w_AVf0o zPIzF!&_ZqC?AW}TX;o9Jgt!QOJNPkcU;~eUydlFTL?_^aS{O&`58(~Krl4X=jC}{T z%R7d$h@eVK2Fm#b3yT%Axo)T%U8{k z{3(XE9F7;lj-WkB9(7t#Yl@*_!YJNhXcG~IVHgV|hr^?GhtYP2p&o=$E5?Rcgcu$e z!@Lz1@~0ZwQFIPQr=&faC;T_CTuRagtBi1p?`3F{u=yekTgVaN(cTARWkuJbJX$IO z<~JGq(3XI)rX)v-M>`3|J}Ne=I$CLaZ$p(>skOJEtwg{)0nG@HI%Oq)nxQN<+71|L zqgKE=8^!lA)KMGx`xx4NME0eSG0lw_W`bF%0;Z>H6yMiS`!w?RbyH-NCee}NZqh92 zSVpkmeF<1F8zXbrFdJhhI^MSjGDL{(W?uk#W)cL!=Cm-|zd^R#FF5Z7u+DVJi3#jp zRuEl51B~oQPOzU32kRk>Cguh)56F6WNl)5~g#mfw8H`4a3qumNMevLh`T>!Z~!JN*D=r}S|?%FVXZhH+lmg)W1& zgAFb9$|zb>>Z9fyJKYBBN_pdbROGhPJLA2w8{Go?9c5Rd-~G-eJ6XAu`9 zZXwPYgi2<%R6JSdbkJaFZ@N>LN~f2`#Gx1n9CN|R#|g>F$ypykY0EMUPCHJ=K@iUW zfe;*9bCDjv1PG@&pD`Vh2C46j2U>L+FH*;Ar$Bl_SdAA%o|^u!k0@4L!3CR(g+xP8 zsZHN;RhWk#71(sj24rX1EuMpl|3sJjI0ih9%5KhwPMv9(YXTc(CEgwGBEDz%?h%O) zHWmj7EzWvR>%@ceUU>uTJUh*Ggy(U!l@Y**A*335@(fCD7;feL^8e}v zcR~UF@QrjnC#JOg%6+Snlihlzo-M>^y4&E24PBwVF0MVXXWxki$Ld*6upV*aXiSxROHv_U7L*>S)%|KYbIdPc!smY&5g^O2R#VR^$w?VGY>0VQmXlNQR^JSs8tC9(L|*Uqkv z{w0;;hadKP%u2g9#~Pt;lE#7l4SkLb%~Nt&R;KRE(sSE`>9v|aPtXDdqN=8LZbfyq zURyb9e&rl`xVaBja%@R zv_;RJb@Puxn!P1I{wfX%e+s>soAb3?*!l6%;9^(ZbY{!+mK9seBwgB((BeJZADcT= JM9U{P{|)?e=Gy=O diff --git a/index.ts b/index.ts index 85f9368..faa9cba 100644 --- a/index.ts +++ b/index.ts @@ -1,9 +1,14 @@ -import { Client, Events, GatewayIntentBits, TextChannel } from "discord.js"; -import { Rcon } from "./rcon"; +import { Client, Events, GatewayIntentBits, Message, TextChannel } from "discord.js"; +import { Rcon } from "rconts"; import config from "./config.json" assert { type: "json" }; -const rcon = new Rcon(config.rcon.host, config.rcon.port, config.rcon.password); -let rconReconnectTimeout: Timer | null | undefined; +const rcon = new Rcon({ + host: config.rcon.host, + port: config.rcon.port, + password: config.rcon.password +}); +let ignoreDeletion: Set = new Set(); + const client = new Client({ intents: [ @@ -13,33 +18,56 @@ const client = new Client({ ], }); -rcon.on("connect", () => { +rcon.on("connected", () => { console.log("RCON connected."); }); -rcon.on("auth", () => { - console.log("RCON authenicated."); -}); +async function whitelist(message: Message, username: string) { + const response = await rcon.exec("whitelist add " + username); + let deleteThisMessage; -rcon.on("end", () => { - console.log("RCON ended. Reconnecting in 2000ms.") - if(rconReconnectTimeout) { - clearTimeout(rconReconnectTimeout); + if (response == "That player does not exist") { + try { + ignoreDeletion.add(message.id); + await message.delete(); + + } catch { + + } + deleteThisMessage = await message.channel.send( + `<@${message.author.id}>, you have not been whitelisted. Please join the server at least once, and then resend your IGN.` + ); + } else if (response.includes("Incorrect argument for")) { + try { + ignoreDeletion.add(message.id); + await message.delete(); + + } catch { + + } + + deleteThisMessage = await message.channel.send( + `<@${message.author.id}>, your message was invalid. Include ONLY your username, nothing else.` + ); } - rconReconnectTimeout = setTimeout(() => { - rcon.connect() - }, 2000) -}) + if(deleteThisMessage) { + setTimeout(async () => { + await deleteThisMessage.delete(); + }, 5000); + } + console.log("[whitelist] response for", username, "is", response); +} + client.once(Events.ClientReady, async (readyClient) => { console.log(`Ready! Logged in as ${readyClient.user.tag}`); - let playerUsernames: string[] = []; + let playerUsernames: Map = new Map(); const channel = (await client.channels.fetch(config.channel)) as TextChannel; const messages = await channel.messages.fetch(); for await (const f of messages) { - playerUsernames = playerUsernames.concat(f[1].content.split("\n")); + playerUsernames.set(f[1], f[1].content.split("\n")); if (!f[1].reactions.resolve("✅")) await f[1].react("✅"); let member = f[1].member; try { @@ -51,21 +79,22 @@ client.once(Events.ClientReady, async (readyClient) => { if (member.nickname !== f[1].content.split("\n")[0]) { try { await member.setNickname(f[1].content.split("\n")[0], "whitelisted"); - } catch {} + } catch { } } } } - for (let i = 0; i < playerUsernames.length; i++) { - setTimeout(() => { - rcon.send("whitelist add " + playerUsernames[i]); - }, i * 20); + for await (let u of playerUsernames) { + for await(let name of u[1]) { + await whitelist(u[0], name); + } } console.log("Mass-whitelisted."); }); client.on(Events.MessageCreate, async (message) => { + if ( message.channelId == config.channel && message.author!.id != client.user!.id @@ -96,19 +125,24 @@ client.on(Events.MessageCreate, async (message) => { if (config.changeNicknames) { try { await member.setNickname(playerUsernames[0]); - } catch {} + } catch { } } - for (let i = 0; i < playerUsernames.length; i++) { - setTimeout(() => { - rcon.send("whitelist add " + playerUsernames[i]); - }, i * 20); + for await (let name of playerUsernames) { + await whitelist(message, name) } - await message.react("✅"); + try { + await message.react("✅"); + } catch { + } } }); client.on(Events.MessageDelete, async (message) => { + if (ignoreDeletion.has(message.id)) { + ignoreDeletion.delete(message.id); + return; + } if ( message.channelId == config.channel && message.author!.id != client.user!.id @@ -122,17 +156,17 @@ client.on(Events.MessageDelete, async (message) => { if (config.changeNicknames) { try { await member.setNickname(null, "unwhitelisted"); - } catch {} - setTimeout(async () => { - await deleteThisMessage.delete(); - }, 5000); - } - const usernames = message.content?.split("\n") || []; + } catch { } - for (let i = 0; i < usernames.length; i++) { - setTimeout(() => { - rcon.send("whitelist remove " + usernames[i]); - }, i * 20); + } + setTimeout(async () => { + await deleteThisMessage.delete(); + }, 5000); + const playerUsernames = message.content?.split("\n") || []; + + for await (let name of playerUsernames) { + const response = await rcon.exec("whitelist remove " + name); + console.log("[delete-whitelist] response for", name, "is", response); } } } diff --git a/package.json b/package.json index 6499df5..83f63d8 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,8 @@ "dependencies": { "bufferutil": "^4.0.8", "discord.js": "^14.15.3", + "node-gyp": "^11.1.0", + "rconts": "git+https://git.sad.ovh/sophie/rconts.git#8f6d5a48330a35f7e4e288b5a3f0104e249aa575", "utf-8-validate": "^6.0.4", "zlib-sync": "^0.1.9" } diff --git a/rcon.ts b/rcon.ts deleted file mode 100644 index e30dfb3..0000000 --- a/rcon.ts +++ /dev/null @@ -1,235 +0,0 @@ -import EventEmitter from "events"; -import * as net from "net"; -import * as dgram from "dgram"; -import { Buffer } from "buffer"; -import type TypedEmitter from "typed-emitter"; - -type Events = { - error: (error: Error) => void; - auth: () => void; - response: (response: string) => void; - connect: () => void; - end: () => void; - done: () => void; -}; - -export const PacketType = { - COMMAND: 0x02, - AUTH: 0x03, - RESPONSE_VALUE: 0x00, - RESPONSE_AUTH: 0x02, -}; - -interface Options { - tcp?: boolean; - challenge?: boolean; - id?: number; -} -export class Rcon extends (EventEmitter as new () => TypedEmitter) { - private host: string; - private port: number; - private password: string; - private rconId: number; - private hasAuthed: boolean; - private outstandingData: Uint8Array | null; - private tcp: boolean; - private challenge: boolean; - private _challengeToken: string; - private _tcpSocket!: net.Socket; - private _udpSocket!: dgram.Socket; - - constructor(host: string, port: number, password: string, options?: Options) { - super(); - options = options || {}; - this.host = host; - this.port = port; - this.password = password; - this.rconId = options.id || 0x0012d4a6; // This is arbitrary in most cases - this.hasAuthed = false; - this.outstandingData = null; - this.tcp = options.tcp ? options.tcp : true; - this.challenge = options.challenge ? options.challenge : true; - this._challengeToken = ""; - } - - public send = (data: string, cmd?: number, id?: number): void => { - let sendBuf: Buffer; - if (this.tcp) { - cmd = cmd || PacketType.COMMAND; - id = id || this.rconId; - - const length = Buffer.byteLength(data); - sendBuf = Buffer.alloc(length + 14); - sendBuf.writeInt32LE(length + 10, 0); - sendBuf.writeInt32LE(id, 4); - sendBuf.writeInt32LE(cmd, 8); - sendBuf.write(data, 12); - sendBuf.writeInt16LE(0, length + 12); - } else { - if (this.challenge && !this._challengeToken) { - this.emit("error", new Error("Not authenticated")); - return; - } - let str = "rcon "; - if (this._challengeToken) str += this._challengeToken + " "; - if (this.password) str += this.password + " "; - str += data + "\n"; - sendBuf = Buffer.alloc(4 + Buffer.byteLength(str)); - sendBuf.writeInt32LE(-1, 0); - sendBuf.write(str, 4); - } - this._sendSocket(sendBuf); - }; - - private _sendSocket = (buf: Buffer) => { - if (this._tcpSocket) { - this._tcpSocket.write(buf.toString("binary"), "binary"); - } else if (this._udpSocket) { - this._udpSocket.send(buf, 0, buf.length, this.port, this.host); - } - }; - - public connect = (): void => { - if (this.tcp) { - this._tcpSocket = net.createConnection(this.port, this.host); - this._tcpSocket.on("data", (data) => { - this._tcpSocketOnData(data); - }); - this._tcpSocket.on("connect", () => { - this.socketOnConnect(); - }); - this._tcpSocket.on("error", (err) => { - //this.emit("error", err); - this.socketOnEnd() - }); - this._tcpSocket.on("end", () => { - this.socketOnEnd(); - }); - } else { - this._udpSocket = dgram.createSocket("udp4"); - this._udpSocket - .on("message", (data) => { - this._udpSocketOnData(data); - }) - .on("listening", () => { - this.socketOnConnect(); - }) - .on("error", (err) => { - this.emit("error", err); - }) - .on("close", () => { - this.socketOnEnd(); - }); - this._udpSocket.bind(0); - } - }; - - public disconnect = (): void => { - if (this._tcpSocket) this._tcpSocket.end(); - if (this._udpSocket) this._udpSocket.close(); - }; - - public setTimeout = (timeout: number, callback: () => void): void => { - if (!this._tcpSocket) return; - this._tcpSocket.setTimeout(timeout, () => { - this._tcpSocket.end(); - if (callback) callback(); - }); - }; - - private _udpSocketOnData = (data: Buffer) => { - const a = data.readUInt32LE(0); - if (a === 0xffffffff) { - const str = data.toString("utf-8", 4); - const tokens = str.split(" "); - if ( - tokens.length === 3 && - tokens[0] === "challenge" && - tokens[1] === "rcon" - ) { - this._challengeToken = tokens[2] - .substring(0, tokens[2].length - 1) - .trim(); - this.hasAuthed = true; - this.emit("auth"); - } else { - this.emit("response", str.substring(1, str.length - 2)); - } - } else { - this.emit("error", new Error("Received malformed packet")); - } - }; - - private _tcpSocketOnData = (data: Buffer) => { - if (this.outstandingData != null) { - data = Buffer.concat( - [this.outstandingData, data], - this.outstandingData.length + data.length - ); - this.outstandingData = null; - } - - while (data.length) { - const len = data.readInt32LE(0); - if (!len) return; - - const id = data.readInt32LE(4); - const type = data.readInt32LE(8); - - if (len >= 10 && data.length >= len + 4) { - if (id === this.rconId) { - if (!this.hasAuthed && type === PacketType.RESPONSE_AUTH) { - this.hasAuthed = true; - this.emit("auth"); - } else if (type === PacketType.RESPONSE_VALUE) { - // Read just the body of the packet (truncate the last null byte) - // See https://developer.valvesoftware.com/wiki/Source_RCON_Protocol for details - let str = data.toString("utf8", 12, 12 + len - 10); - - if (str.charAt(str.length - 1) === "\n") { - // Emit the response without the newline. - str = str.substring(0, str.length - 1); - } - - this.emit("response", str); - } - } else { - this.emit("error", new Error("Authentication failed")); - } - - data = data.slice(12 + len - 8); - } else { - // Keep a reference to the chunk if it doesn't represent a full packet - this.outstandingData = data; - break; - } - } - }; - - public socketOnConnect = (): void => { - this.emit("connect"); - - if (this.tcp) { - this.send(this.password, PacketType.AUTH); - } else if (this.challenge) { - const str = "challenge rcon\n"; - const sendBuf = Buffer.alloc(str.length + 4); - sendBuf.writeInt32LE(-1, 0); - sendBuf.write(str, 4); - this._sendSocket(sendBuf); - } else { - const sendBuf = Buffer.alloc(5); - sendBuf.writeInt32LE(-1, 0); - sendBuf.writeUInt8(0, 4); - this._sendSocket(sendBuf); - - this.hasAuthed = true; - this.emit("auth"); - } - }; - - public socketOnEnd = (): void => { - this.emit("end"); - this.hasAuthed = false; - }; -}