From 275ad3823f800909c50f98a93eba7935b5f657f6 Mon Sep 17 00:00:00 2001 From: Hri7566 Date: Wed, 31 Jan 2024 05:09:25 -0500 Subject: [PATCH] Update everything --- prisma/schema.prisma | 5 +++ src/channel/Channel.ts | 5 +-- src/channel/ChannelList.ts | 1 + src/channel/Crown.ts | 1 + src/channel/config.ts | 1 + src/channel/forceLoad.ts | 2 + src/channel/index.ts | 2 + src/channel/settings.ts | 2 + src/index.ts | 2 + src/util/Logger.ts | 2 +- src/util/config.ts | 11 ++++++ src/util/env.ts | 2 + src/util/helpers.ts | 17 +++++++++ src/util/id.ts | 20 +++++++++- src/util/motd.ts | 1 + src/util/readline/index.ts | 1 + src/util/types.d.ts | 13 +++++++ src/ws/Gateway.ts | 13 +++++++ src/ws/Socket.ts | 23 +++++++++--- src/ws/events.inc.ts | 4 ++ src/ws/events.ts | 4 ++ src/ws/events/admin/handlers/color.ts | 2 +- src/ws/events/admin/handlers/name.ts | 1 + src/ws/events/admin/handlers/user_flag.ts | 1 + src/ws/events/admin/index.ts | 8 ++-- src/ws/events/user/handlers/+ls.ts | 9 +++++ src/ws/events/user/handlers/-ls.ts | 1 + src/ws/events/user/handlers/a.ts | 4 ++ src/ws/events/user/handlers/admin_message.ts | 2 + src/ws/events/user/handlers/ch.ts | 2 + src/ws/events/user/handlers/chset.ts | 3 ++ src/ws/events/user/handlers/devices.ts | 2 +- src/ws/events/user/handlers/hi.ts | 3 ++ src/ws/events/user/handlers/m.ts | 5 ++- src/ws/events/user/handlers/n.ts | 16 ++++++-- src/ws/events/user/handlers/t.ts | 1 + src/ws/events/user/handlers/userset.ts | 9 +++++ src/ws/events/user/index.ts | 39 ++++++++++++++------ src/ws/message.ts | 4 +- src/ws/ratelimit/NoteQuota.ts | 3 ++ src/ws/ratelimit/RateLimit.ts | 1 + src/ws/ratelimit/RateLimitChain.ts | 1 + src/ws/ratelimit/config.ts | 6 ++- src/ws/ratelimit/limits/admin.ts | 3 +- src/ws/ratelimit/limits/crown.ts | 3 +- src/ws/ratelimit/limits/user.ts | 3 ++ src/ws/server.ts | 32 ++++++++++++++++ src/ws/usersConfig.ts | 6 +++ test/channel/Channel.test.ts | 15 -------- test/ws/FakeSocket.ts | 1 - 50 files changed, 265 insertions(+), 53 deletions(-) delete mode 100644 test/channel/Channel.test.ts delete mode 100644 test/ws/FakeSocket.ts diff --git a/prisma/schema.prisma b/prisma/schema.prisma index bc1c45f..0ba4116 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -16,3 +16,8 @@ model User { color String @default("#ffffff") flags String @default("{}") // JSON flags object } + +model ChatHistory { + id String @id @unique @map("_id") + messages String @default("[]") // JSON messages +} diff --git a/src/channel/Channel.ts b/src/channel/Channel.ts index a70c044..1668294 100644 --- a/src/channel/Channel.ts +++ b/src/channel/Channel.ts @@ -8,7 +8,7 @@ import { ServerEvents, IChannelInfo } from "../util/types"; -import { Socket } from "../ws/Socket"; +import type { Socket } from "../ws/Socket"; import { validateChannelSettings } from "./settings"; import { findSocketByPartID, socketsBySocketID } from "../ws/Socket"; import Crown from "./Crown"; @@ -185,8 +185,6 @@ export class Channel extends EventEmitter { (typeof set.color2 == "undefined" || set.color2 === this.settings.color2) ) { - this.logger.debug("Setting color 2 from first color:", set.color); - this.logger.debug("Red:", parseInt(set.color.substring(1, 2), 16)); const r = Math.max( 0, parseInt(set.color.substring(1, 3), 16) - 0x40 @@ -201,7 +199,6 @@ export class Channel extends EventEmitter { ); set.color2 = `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`; - this.logger.debug("Color 2 is now:", set.color2); } if (this.isLobby() && !admin) return; diff --git a/src/channel/ChannelList.ts b/src/channel/ChannelList.ts index c96b950..86dbbfb 100644 --- a/src/channel/ChannelList.ts +++ b/src/channel/ChannelList.ts @@ -2,6 +2,7 @@ import { type Socket, findSocketByPartID } from "../ws/Socket"; import type Channel from "./Channel"; const onChannelUpdate = (channel: Channel) => { + // If this shit ever manages to handle over 10 people I'd be impressed const info = channel.getInfo(); // const ppl = channel.getParticipantList(); if (info.settings.visible !== true) return; diff --git a/src/channel/Crown.ts b/src/channel/Crown.ts index 41368bc..157aef1 100644 --- a/src/channel/Crown.ts +++ b/src/channel/Crown.ts @@ -1,6 +1,7 @@ import { Participant, Vector2 } from "../util/types"; import { Socket } from "../ws/Socket"; +// shiny hat export class Crown { public userId: string | undefined; public participantId: string | undefined; diff --git a/src/channel/config.ts b/src/channel/config.ts index 5ed7912..94cc61e 100644 --- a/src/channel/config.ts +++ b/src/channel/config.ts @@ -27,6 +27,7 @@ export const config = loadConfig("config/channels.yml", { color2: "#001014", visible: true }, + // Here's a terrifying fact: Brandon used parseInt to check lobby names in the OG server code lobbyRegexes: ["^lobby[0-9][0-9]$", "^lobby[1-9]$", "^test/.+$"], lobbyBackdoor: "lolwutsecretlobbybackdoor", fullChannel: "test/awkward" diff --git a/src/channel/forceLoad.ts b/src/channel/forceLoad.ts index 606bbd0..9c545e6 100644 --- a/src/channel/forceLoad.ts +++ b/src/channel/forceLoad.ts @@ -1,6 +1,8 @@ import { Channel } from "./Channel"; import { config } from "./config"; +// This shit was moved here to try to fix the unit tests segfaulting but it didn't work + // Channel forceloader (cringe) let hasFullChannel = false; diff --git a/src/channel/index.ts b/src/channel/index.ts index 2f9faa1..faad04b 100644 --- a/src/channel/index.ts +++ b/src/channel/index.ts @@ -4,4 +4,6 @@ import validateChannelSettings, { validate as validateChannelSetting } from "./settings"; +// I don't even know if I bothered to use this file + export { Channel, Crown, validateChannelSettings, validateChannelSetting }; diff --git a/src/channel/settings.ts b/src/channel/settings.ts index 9fdb584..0dc9f1c 100644 --- a/src/channel/settings.ts +++ b/src/channel/settings.ts @@ -3,6 +3,8 @@ import { IChannelSettings } from "../util/types"; type Validator = "boolean" | "string" | "number" | ((val: unknown) => boolean); +// This record contains the exact data Brandon used to check channel settings, down to the regex. +// It also contains things that might be useful to other people in the future (things that make me vomit) const validationRecord: Record = { // Brandon lobby: "boolean", diff --git a/src/index.ts b/src/index.ts index 03cfaf2..41533d2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,6 +4,7 @@ * by Hri7566 */ +// If you don't load the server first, bun will literally segfault import "./ws/server"; import "./channel/forceLoad"; import { Logger } from "./util/Logger"; @@ -12,4 +13,5 @@ const logger = new Logger("Main"); import "./util/readline"; +// Does this really even need to be here? logger.info("Ready"); diff --git a/src/util/Logger.ts b/src/util/Logger.ts index 1a568a8..dc17870 100755 --- a/src/util/Logger.ts +++ b/src/util/Logger.ts @@ -14,7 +14,7 @@ export class Logger { ...args ); - // Fix the readline prompt (spooky code) + // Fix the readline prompt (spooky cringe code) if ((globalThis as unknown as any).rl) (globalThis as unknown as any).rl.prompt(); } diff --git a/src/util/config.ts b/src/util/config.ts index df48126..8ede627 100644 --- a/src/util/config.ts +++ b/src/util/config.ts @@ -2,6 +2,16 @@ import { existsSync, readFileSync, writeFileSync } from "fs"; import { parse, stringify } from "yaml"; import { z } from "zod"; +/** + * This file uses the synchronous functions from the fs + * module because these functions should only be used + * to load configs at the beginning of runtime + * + * Hint: This means you shouldn't load configs in the + * middle of doing other shit, only when you start the + * program. + */ + /** * Load a YAML config file and set default values if config path is nonexistent * @@ -64,6 +74,7 @@ export function loadConfig(configPath: string, defaultConfig: T): T { * @param config */ export function writeConfig(configPath: string, config: T) { + // Write config to disk unconditionally writeFileSync( configPath, stringify(config, { diff --git a/src/util/env.ts b/src/util/env.ts index 183d1aa..7aac039 100644 --- a/src/util/env.ts +++ b/src/util/env.ts @@ -1,6 +1,7 @@ import { createEnv } from "@t3-oss/env-core"; import { z } from "zod"; +// Best way to do env ever export const env = createEnv({ server: { PORT: z.coerce.number(), @@ -9,6 +10,7 @@ export const env = createEnv({ ADMIN_PASS: z.string() }, isServer: true, + // Bun loads process.env automatically so we don't have to use modules runtimeEnv: process.env }); diff --git a/src/util/helpers.ts b/src/util/helpers.ts index 2fc6029..8b3e380 100644 --- a/src/util/helpers.ts +++ b/src/util/helpers.ts @@ -40,3 +40,20 @@ export function darken(hex: string) { .padStart(2, "0")}${newB.toString(16).padStart(2, "0")}`; } catch (err) {} } + +// Brandon made this literally eons ago and it's fucking hilarious +export function spoop_text(message: string) { + var old = message; + message = ""; + for (var i = 0; i < old.length; i++) { + if (Math.random() < 0.9) { + message += String.fromCharCode( + old.charCodeAt(i) + Math.floor(Math.random() * 20 - 10) + ); + //message[i] = String.fromCharCode(Math.floor(Math.random() * 255)); + } else { + message += old[i]; + } + } + return message; +} diff --git a/src/util/id.ts b/src/util/id.ts index 1bbbb12..7af38a4 100644 --- a/src/util/id.ts +++ b/src/util/id.ts @@ -1,8 +1,24 @@ import { createHash, randomBytes } from "crypto"; import env from "./env"; +import { spoop_text } from "./helpers"; export function createID() { - return randomBytes(12).toString("hex"); + // Maybe I could make this funnier than it needs to be... + // return randomBytes(12).toString("hex"); + + let weirdness = ""; + while (weirdness.length < 24) { + const time = new Date().toString(); + const randomShit = spoop_text(time); // looks like this: We]%Cau&:,\u0018403*"32>8,B15&GP[2)='7\u0019-@etyhlw\u0017QqXqiime&Khhe- + + let index1 = Math.floor(Math.random() * randomShit.length); + let index2 = Math.floor(Math.random() * randomShit.length); + + weirdness += randomShit.substring(index1, index2); + } + + // Get 12 bytes + return Buffer.from(weirdness.substring(0, 12)).toString("hex"); } export function createUserID(ip: string) { @@ -25,6 +41,6 @@ export function createColor(ip: string) { .update(env.SALT) .update("color") .digest("hex") - .substring(0, 6) + .substring(0, 24 + 6) ); } diff --git a/src/util/motd.ts b/src/util/motd.ts index 1e73601..ffd9784 100644 --- a/src/util/motd.ts +++ b/src/util/motd.ts @@ -1,3 +1,4 @@ +// bruh export function getMOTD() { return "This site makes a lot of sound! You may want to adjust the volume before continuing."; } diff --git a/src/util/readline/index.ts b/src/util/readline/index.ts index 9911ad8..d68ca78 100644 --- a/src/util/readline/index.ts +++ b/src/util/readline/index.ts @@ -21,4 +21,5 @@ rl.on("SIGINT", () => { process.exit(); }); +// Fucking cringe but it works (globalThis as unknown as any).rl = rl; diff --git a/src/util/types.d.ts b/src/util/types.d.ts index a7a5b42..ef9d531 100644 --- a/src/util/types.d.ts +++ b/src/util/types.d.ts @@ -1,5 +1,18 @@ +/** + * Typedefs + */ + import { Socket } from "../ws/Socket"; +/** + * Halfway through this file, the same types have appeared again + * + * I am not a decent enough person to go looking down there, so + * good luck when you get there. Somehow I forgot what is even + * in this file, so don't come and ask me why something isn't + * defined correctly here. + */ + declare type Omit = Pick>; declare type UserFlags = Partial<{ diff --git a/src/ws/Gateway.ts b/src/ws/Gateway.ts index fbe6fc2..b15e103 100644 --- a/src/ws/Gateway.ts +++ b/src/ws/Gateway.ts @@ -1,3 +1,16 @@ +/** + * I made this thing to keep track of what sockets + * have and haven't done yet so we know if they + * should be doing certain things. + * + * For instance, being logged in in the first place, + * or if they're on shitty McDonalds WiFi and they + * lost connection for over a minute, or if they + * decided that they're going to put their browser + * in a chokehold and force it to load weird shit... + * or, you know, maybe I could log their user agent + * and IP address instead sometime in the future. + */ export class Gateway { public hasProcessedHi: boolean = false; public hasSentDevices: boolean = false; diff --git a/src/ws/Socket.ts b/src/ws/Socket.ts index 9169994..5516e58 100644 --- a/src/ws/Socket.ts +++ b/src/ws/Socket.ts @@ -15,7 +15,7 @@ import { UserFlags, Vector2 } from "../util/types"; -import { User } from "@prisma/client"; +import type { User } from "@prisma/client"; import { createUser, readUser, updateUser } from "../data/user"; import { eventGroups } from "./events"; import { Gateway } from "./Gateway"; @@ -55,10 +55,7 @@ export class Socket extends EventEmitter { public currentChannelID: string | undefined; private cursorPos: Vector2 = { x: 200, y: 100 }; - constructor( - private ws: ServerWebSocket, - public socketID: string - ) { + constructor(private ws: ServerWebSocket, public socketID: string) { super(); this.ip = ws.remoteAddress; // Participant ID @@ -432,6 +429,22 @@ export class Socket extends EventEmitter { } ]); } + + public isOwner() { + const channel = this.getCurrentChannel(); + const part = this.getParticipant(); + + // this looks cool + if (!channel) return false; + if (!channel.crown) return false; + if (!channel.crown.userId) return false; + if (!channel.crown.participantId) return false; + if (!part) return; + if (!part.id) return; + if (channel.crown.participantId !== part.id) return false; + + return true; + } } export const socketsBySocketID = new Map(); diff --git a/src/ws/events.inc.ts b/src/ws/events.inc.ts index 4f15916..7413751 100644 --- a/src/ws/events.inc.ts +++ b/src/ws/events.inc.ts @@ -1,4 +1,8 @@ // Bun hoists import so we are kinda forced to use require here... // Maybe bun should have a setting for that :/ + +// This feels really dirty and months have passed... guess who's fixing it? +// Nobody is. It's going to stay like this. + require("./events/user"); require("./events/admin"); diff --git a/src/ws/events.ts b/src/ws/events.ts index 7bc771b..8e4c6b6 100644 --- a/src/ws/events.ts +++ b/src/ws/events.ts @@ -8,6 +8,10 @@ export class EventGroup { this.eventList.push(listener); } + public addMany(...listeners: ServerEventListener[]) { + listeners.forEach(l => this.add(l)); + } + public remove(listener: ServerEventListener) { this.eventList.splice(this.eventList.indexOf(listener), 1); } diff --git a/src/ws/events/admin/handlers/color.ts b/src/ws/events/admin/handlers/color.ts index 2a3773e..6c8a77e 100644 --- a/src/ws/events/admin/handlers/color.ts +++ b/src/ws/events/admin/handlers/color.ts @@ -5,7 +5,7 @@ import { findSocketsByUserID } from "../../../Socket"; export const color: ServerEventListener<"color"> = { id: "color", callback: async (msg, socket) => { - // TODO color + // I'm not allowed to use this feature on MPP.net for a really stupid reason const id = msg._id; const color = msg.color; diff --git a/src/ws/events/admin/handlers/name.ts b/src/ws/events/admin/handlers/name.ts index 94a4f1f..cd11201 100644 --- a/src/ws/events/admin/handlers/name.ts +++ b/src/ws/events/admin/handlers/name.ts @@ -5,6 +5,7 @@ import { findSocketsByUserID } from "../../../Socket"; export const name: ServerEventListener<"name"> = { id: "name", callback: async (msg, socket) => { + // Change someone else's name but it's an annoying admin feature const id = msg._id; const name = msg.name; diff --git a/src/ws/events/admin/handlers/user_flag.ts b/src/ws/events/admin/handlers/user_flag.ts index af30a28..1580406 100644 --- a/src/ws/events/admin/handlers/user_flag.ts +++ b/src/ws/events/admin/handlers/user_flag.ts @@ -5,6 +5,7 @@ import { findSocketsByUserID } from "../../../Socket"; export const user_flag: ServerEventListener<"user_flag"> = { id: "user_flag", callback: async (msg, socket) => { + // User flag modification (changing some real specific shit) if (typeof msg._id !== "string") return; if (typeof msg.key !== "string") return; if (typeof msg.value == "undefined") return; diff --git a/src/ws/events/admin/index.ts b/src/ws/events/admin/index.ts index 38bf1d6..aea81f7 100644 --- a/src/ws/events/admin/index.ts +++ b/src/ws/events/admin/index.ts @@ -6,8 +6,10 @@ import { color } from "./handlers/color"; import { name } from "./handlers/name"; import { user_flag } from "./handlers/user_flag"; -EVENT_GROUP_ADMIN.add(color); -EVENT_GROUP_ADMIN.add(name); -EVENT_GROUP_ADMIN.add(user_flag); +// EVENT_GROUP_ADMIN.add(color); +// EVENT_GROUP_ADMIN.add(name); +// EVENT_GROUP_ADMIN.add(user_flag); + +EVENT_GROUP_ADMIN.addMany(color, name, user_flag); eventGroups.push(EVENT_GROUP_ADMIN); diff --git a/src/ws/events/user/handlers/+ls.ts b/src/ws/events/user/handlers/+ls.ts index d804c88..41addeb 100644 --- a/src/ws/events/user/handlers/+ls.ts +++ b/src/ws/events/user/handlers/+ls.ts @@ -3,6 +3,15 @@ import { ServerEventListener } from "../../../../util/types"; export const plus_ls: ServerEventListener<"+ls"> = { id: "+ls", callback: (msg, socket) => { + // Give us the latest news on literally everything + // that's happening in the server. In fact, I want + // to know when someone clicks a button instantly, + // so I can stalk other users by watching the room + // count go up somewhere else when I watch someone + // leave the channel I'm reading their messages in + // and when I see their cursor disappear I'll know + // precisely where they went to follow them and to + // annoy them in chat when I see them again. socket.subscribeToChannelList(); } }; diff --git a/src/ws/events/user/handlers/-ls.ts b/src/ws/events/user/handlers/-ls.ts index 6044111..00b66ad 100644 --- a/src/ws/events/user/handlers/-ls.ts +++ b/src/ws/events/user/handlers/-ls.ts @@ -3,6 +3,7 @@ import { ServerEventListener } from "../../../../util/types"; export const minus_ls: ServerEventListener<"-ls"> = { id: "-ls", callback: (msg, socket) => { + // Stop giving us the latest server forecast socket.unsubscribeFromChannelList(); } }; diff --git a/src/ws/events/user/handlers/a.ts b/src/ws/events/user/handlers/a.ts index 0b9f7df..de146a9 100644 --- a/src/ws/events/user/handlers/a.ts +++ b/src/ws/events/user/handlers/a.ts @@ -7,11 +7,15 @@ export const a: ServerEventListener<"a"> = { const flags = socket.getUserFlags(); if (!flags) return; + // Why did I write this statement so weird if (!flags["no chat rate limit"] || flags["no chat rate limit"] == 0) if (!socket.rateLimits?.normal.a.attempt()) return; const ch = socket.getCurrentChannel(); if (!ch) return; + // msg.m + // Permission denied: msg.m + // sudo msg.m ch.emit("message", msg, socket); } }; diff --git a/src/ws/events/user/handlers/admin_message.ts b/src/ws/events/user/handlers/admin_message.ts index 654ecbe..72a2165 100644 --- a/src/ws/events/user/handlers/admin_message.ts +++ b/src/ws/events/user/handlers/admin_message.ts @@ -11,6 +11,8 @@ export const admin_message: ServerEventListener<"admin message"> = { if (typeof msg.password !== "string") return; if (msg.password !== env.ADMIN_PASS) return; + // Probably shouldn't be using password auth in 2024 + // Maybe I'll setup a dashboard instead some day socket.admin.emit(msg.msg.m, msg.msg, socket, true); } }; diff --git a/src/ws/events/user/handlers/ch.ts b/src/ws/events/user/handlers/ch.ts index fe92514..3f2c484 100644 --- a/src/ws/events/user/handlers/ch.ts +++ b/src/ws/events/user/handlers/ch.ts @@ -5,6 +5,8 @@ export const ch: ServerEventListener<"ch"> = { callback: (msg, socket) => { // Switch channel if (!msg._id) return; + + // So technical and convoluted... socket.setChannel(msg._id, msg.set); } }; diff --git a/src/ws/events/user/handlers/chset.ts b/src/ws/events/user/handlers/chset.ts index cf38125..da8be3e 100644 --- a/src/ws/events/user/handlers/chset.ts +++ b/src/ws/events/user/handlers/chset.ts @@ -5,8 +5,11 @@ export const chset: ServerEventListener<"chset"> = { callback: (msg, socket) => { // Change channel settings if (typeof msg.set == "undefined") return; + const ch = socket.getCurrentChannel(); if (!ch) return; + + // Edit room now ch.changeSettings(msg.set, false); } }; diff --git a/src/ws/events/user/handlers/devices.ts b/src/ws/events/user/handlers/devices.ts index 459904c..68ce49e 100644 --- a/src/ws/events/user/handlers/devices.ts +++ b/src/ws/events/user/handlers/devices.ts @@ -3,7 +3,7 @@ import { ServerEventListener } from "../../../../util/types"; export const devices: ServerEventListener<"devices"> = { id: "devices", callback: (msg, socket) => { - // List of MIDI Devices + // List of MIDI Devices (or software ports, because nobody can tell the difference) if (socket.gateway.hasSentDevices) return; socket.gateway.hasSentDevices = true; } diff --git a/src/ws/events/user/handlers/hi.ts b/src/ws/events/user/handlers/hi.ts index 71a9a5b..43dcd31 100644 --- a/src/ws/events/user/handlers/hi.ts +++ b/src/ws/events/user/handlers/hi.ts @@ -5,6 +5,9 @@ export const hi: ServerEventListener<"hi"> = { callback: (msg, socket) => { // Handshake message // TODO Hi message tokens + // I'm not actually sure if I'm up for doing tokens, + // but if someone wants to submit a pull request, I + // look forward to watching you do all the work if (socket.gateway.hasProcessedHi) return; let part = socket.getParticipant(); diff --git a/src/ws/events/user/handlers/m.ts b/src/ws/events/user/handlers/m.ts index 06362f4..fbfa419 100644 --- a/src/ws/events/user/handlers/m.ts +++ b/src/ws/events/user/handlers/m.ts @@ -4,15 +4,18 @@ export const m: ServerEventListener<"m"> = { id: "m", callback: (msg, socket) => { // Cursor movement - if (!socket.rateLimits?.normal.m.attempt()) return; + if (!socket.rateLimits) return; + if (!socket.rateLimits.normal.m.attempt()) return; if (!msg.x || !msg.y) return; let x = msg.x; let y = msg.y; + // Make it numbers if (typeof msg.x == "string") x = parseFloat(msg.x); if (typeof msg.y == "string") y = parseFloat(msg.y); + // Move the laggy piece of shit socket.setCursorPos(x, y); } }; diff --git a/src/ws/events/user/handlers/n.ts b/src/ws/events/user/handlers/n.ts index 195f26e..67c3622 100644 --- a/src/ws/events/user/handlers/n.ts +++ b/src/ws/events/user/handlers/n.ts @@ -8,6 +8,10 @@ export const n: ServerEventListener<"n"> = { if (!Array.isArray(msg.n)) return; if (typeof msg.t !== "number") return; + // This should've been here months ago + const channel = socket.getCurrentChannel(); + if (!channel) return; + // Check note properties for (const n of msg.n) { if (typeof n.n != "string") return; @@ -29,9 +33,15 @@ export const n: ServerEventListener<"n"> = { let amount = msg.n.length; - // TODO Check crownsolo - if (socket.noteQuota.spend(amount)) { - socket.playNotes(msg); + const crownsolo = channel.getSetting("crownsolo"); + + if ((crownsolo && socket.isOwner()) || !crownsolo) { + // Shiny hat exists and we have shiny hat + // or there is no shiny hat + if (socket.noteQuota.spend(amount)) { + // make noise + socket.playNotes(msg); + } } } }; diff --git a/src/ws/events/user/handlers/t.ts b/src/ws/events/user/handlers/t.ts index 3bbb7d9..6f5a7e5 100644 --- a/src/ws/events/user/handlers/t.ts +++ b/src/ws/events/user/handlers/t.ts @@ -8,6 +8,7 @@ export const t: ServerEventListener<"t"> = { if (typeof msg.e !== "number") return; } + // Pong! socket.sendArray([ { m: "t", diff --git a/src/ws/events/user/handlers/userset.ts b/src/ws/events/user/handlers/userset.ts index 49926b9..f935797 100644 --- a/src/ws/events/user/handlers/userset.ts +++ b/src/ws/events/user/handlers/userset.ts @@ -5,6 +5,15 @@ export const userset: ServerEventListener<"userset"> = { callback: (msg, socket) => { // Change username/color if (!socket.rateLimits?.chains.userset.attempt()) return; + // You can disable color in the config because + // Brandon's/jacored's server doesn't allow color changes, + // and that's the OG server, but folks over at MPP.net + // said otherwise because they're dumb roleplayers + // or something and don't understand the unique value + // of the fishing bot and how it allows you to change colors + // without much control, giving it the feeling of value... + // Kinda reminds me of crypto. + // Also, Brandon's server had color changing on before. if (!msg.set.name && !msg.set.color) return; socket.userset(msg.set.name, msg.set.color); } diff --git a/src/ws/events/user/index.ts b/src/ws/events/user/index.ts index d6e3bc1..2bd6cce 100644 --- a/src/ws/events/user/index.ts +++ b/src/ws/events/user/index.ts @@ -14,16 +14,33 @@ import { minus_ls } from "./handlers/-ls"; import { admin_message } from "./handlers/admin_message"; import { chset } from "./handlers/chset"; -EVENTGROUP_USER.add(hi); -EVENTGROUP_USER.add(devices); -EVENTGROUP_USER.add(ch); -EVENTGROUP_USER.add(m); -EVENTGROUP_USER.add(a); -EVENTGROUP_USER.add(userset); -EVENTGROUP_USER.add(n); -EVENTGROUP_USER.add(plus_ls); -EVENTGROUP_USER.add(minus_ls); -EVENTGROUP_USER.add(admin_message); -EVENTGROUP_USER.add(chset); +// Imagine not having an "addMany" function... + +// EVENTGROUP_USER.add(hi); +// EVENTGROUP_USER.add(devices); +// EVENTGROUP_USER.add(ch); +// EVENTGROUP_USER.add(m); +// EVENTGROUP_USER.add(a); +// EVENTGROUP_USER.add(userset); +// EVENTGROUP_USER.add(n); +// EVENTGROUP_USER.add(plus_ls); +// EVENTGROUP_USER.add(minus_ls); +// EVENTGROUP_USER.add(admin_message); +// EVENTGROUP_USER.add(chset); + +// Imagine it looks exactly the same and calls the same function underneath +EVENTGROUP_USER.addMany( + hi, + devices, + ch, + m, + a, + userset, + n, + plus_ls, + minus_ls, + admin_message, + chset +); eventGroups.push(EVENTGROUP_USER); diff --git a/src/ws/message.ts b/src/ws/message.ts index 2447952..f71acf0 100644 --- a/src/ws/message.ts +++ b/src/ws/message.ts @@ -2,7 +2,9 @@ import { Logger } from "../util/Logger"; import { Socket } from "./Socket"; import { hasOwn } from "../util/helpers"; -const logger = new Logger("Message Handler"); +// const logger = new Logger("Message Handler"); +// this one sounds cooler +const logger = new Logger("The Messenger"); export function handleMessage(socket: Socket, text: string) { try { diff --git a/src/ws/ratelimit/NoteQuota.ts b/src/ws/ratelimit/NoteQuota.ts index 834ae33..f90327d 100644 --- a/src/ws/ratelimit/NoteQuota.ts +++ b/src/ws/ratelimit/NoteQuota.ts @@ -1,3 +1,6 @@ +// This is some convoluted dark magic I copied from some old mpp server I wrote +// No fucking clue where it came from or how it works internally, but I typedefized it +// It's just a bunch of rate limits in a chain... like a RateLimitChain...... hmmmm....... export class NoteQuota { public allowance = 8000; public max = 24000; diff --git a/src/ws/ratelimit/RateLimit.ts b/src/ws/ratelimit/RateLimit.ts index 9623ddd..2332411 100644 --- a/src/ws/ratelimit/RateLimit.ts +++ b/src/ws/ratelimit/RateLimit.ts @@ -1,3 +1,4 @@ +// Thank you Brandon for this thing export class RateLimit { public after: number = 0; constructor(private interval_ms: number = 0) {} diff --git a/src/ws/ratelimit/RateLimitChain.ts b/src/ws/ratelimit/RateLimitChain.ts index f3be911..5649d7c 100644 --- a/src/ws/ratelimit/RateLimitChain.ts +++ b/src/ws/ratelimit/RateLimitChain.ts @@ -1,5 +1,6 @@ import { RateLimit } from "./RateLimit"; +// Thank you Brandon for this other thing export class RateLimitChain { public chain: RateLimit[] = []; diff --git a/src/ws/ratelimit/config.ts b/src/ws/ratelimit/config.ts index 2cb8381..d79b32c 100644 --- a/src/ws/ratelimit/config.ts +++ b/src/ws/ratelimit/config.ts @@ -47,7 +47,8 @@ export const config = loadConfig("config/ratelimits.yml", { crown: { normal: { a: 6000 / 10, - m: 1000 / 20 + m: 1000 / 20, + ch: 1000 / 1 }, chains: { userset: { @@ -59,7 +60,8 @@ export const config = loadConfig("config/ratelimits.yml", { admin: { normal: { a: 6000 / 50, - m: 1000 / 60 + m: 1000 / 60, + ch: 1000 / 10 }, chains: { userset: { diff --git a/src/ws/ratelimit/limits/admin.ts b/src/ws/ratelimit/limits/admin.ts index 7650f26..75a83a6 100644 --- a/src/ws/ratelimit/limits/admin.ts +++ b/src/ws/ratelimit/limits/admin.ts @@ -5,7 +5,8 @@ import { RateLimitConstructorList, config } from "../config"; export const adminLimits: RateLimitConstructorList = { normal: { a: () => new RateLimit(config.admin.normal.a), - m: () => new RateLimit(config.admin.normal.m) + m: () => new RateLimit(config.admin.normal.m), + ch: () => new RateLimit(config.admin.normal.ch) }, chains: { userset: () => diff --git a/src/ws/ratelimit/limits/crown.ts b/src/ws/ratelimit/limits/crown.ts index be67be9..977fd75 100644 --- a/src/ws/ratelimit/limits/crown.ts +++ b/src/ws/ratelimit/limits/crown.ts @@ -5,7 +5,8 @@ import { RateLimitConstructorList, config } from "../config"; export const crownLimits: RateLimitConstructorList = { normal: { a: () => new RateLimit(config.crown.normal.a), - m: () => new RateLimit(config.crown.normal.m) + m: () => new RateLimit(config.crown.normal.m), + ch: () => new RateLimit(config.crown.normal.ch) }, chains: { userset: () => diff --git a/src/ws/ratelimit/limits/user.ts b/src/ws/ratelimit/limits/user.ts index 5860721..5904696 100644 --- a/src/ws/ratelimit/limits/user.ts +++ b/src/ws/ratelimit/limits/user.ts @@ -2,6 +2,9 @@ import { RateLimit } from "../RateLimit"; import { RateLimitChain } from "../RateLimitChain"; import { RateLimitConstructorList, config } from "../config"; +// I have no idea why these things exist but I made it apparently +// All it does it construct the rate limits from the config instead +// of using random numbers I found on the internet export const userLimits: RateLimitConstructorList = { normal: { a: () => new RateLimit(config.user.normal.a), diff --git a/src/ws/server.ts b/src/ws/server.ts index 9282ff0..ce98922 100644 --- a/src/ws/server.ts +++ b/src/ws/server.ts @@ -10,7 +10,15 @@ import nunjucks from "nunjucks"; const logger = new Logger("WebSocket Server"); +/** + * Get a rendered version of the index file + * @returns Response with html in it + */ async function getIndex() { + // This tiny function took like an hour to write because + // nobody realistically uses templates in 2024 and documents + // it well enough to say what library they used + const index = Bun.file("./public/index.html"); const rendered = nunjucks.renderString(await index.text(), { @@ -19,6 +27,7 @@ async function getIndex() { const response = new Response(rendered); response.headers.set("Content-Type", "text/html"); + return response; } @@ -30,11 +39,21 @@ export const app = Bun.serve({ return; } else { const url = new URL(req.url).pathname; + + // lol // const ip = decoder.decode(res.getRemoteAddressAsText()); // logger.debug(`${req.getMethod()} ${url} ${ip}`); // res.writeStatus(`200 OK`).end("HI!"); + + // I have no clue if this is even safe... + // wtf do I do when the user types "/../.env" in the URL? + // From my testing, nothing out of the ordinary happens... + // but just in case, if you find something wrong with URLs, + // this is the most likely culprit + const file = path.join("./public/", url); + // Time for unreadable blocks of confusion try { if (fs.lstatSync(file).isFile()) { const data = Bun.file(file); @@ -54,20 +73,33 @@ export const app = Bun.serve({ }, websocket: { open: ws => { + // We got one! const socket = new Socket(ws, createSocketID()); + + // Reel 'em in... (ws as unknown as any).socket = socket; // logger.debug("Connection at " + socket.getIP()); + // Let's put it in the dinner bucket. socketsBySocketID.set(socket.socketID, socket); }, message: (ws, message) => { + // "Let's make it binary" said all websocket developers for some reason const msg = message.toString(); + + // Let's find out wtf they even sent handleMessage((ws as unknown as any).socket, msg); }, close: (ws, code, message) => { // logger.debug("Close called"); + + // This usually gets called when someone leaves, + // but it's also used internally just in case + // some dickhead can't close their tab like a + // normal person. + const socket = (ws as unknown as any).socket as Socket; if (socket) { socket.destroy(); diff --git a/src/ws/usersConfig.ts b/src/ws/usersConfig.ts index d29a293..749e907 100644 --- a/src/ws/usersConfig.ts +++ b/src/ws/usersConfig.ts @@ -20,6 +20,12 @@ export const defaultUsersConfig = { }; // Importing this elsewhere causes bun to segfault + +// Now that I look back at this, using this elsewhere +// before calling other things tends to make bun segfault? +// Not dealing with it. The code somehow runs, and I'm not +// going to fuck with the order of loading things until bun +// pushes an update and fucks all this stuff up. export const config = loadConfig( usersConfigPath, defaultUsersConfig diff --git a/test/channel/Channel.test.ts b/test/channel/Channel.test.ts deleted file mode 100644 index e6509a4..0000000 --- a/test/channel/Channel.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { test, expect } from "bun:test"; -import { Channel } from "../../src/channel/Channel"; - -test("Channel is created correctly", () => { - const channel = new Channel("my room"); - expect(channel.getID()).toBe("my room"); - - const info = channel.getInfo(); - expect(info.id).toBe("my room"); - expect(info._id).toBe("my room"); - expect(info.count).toBe(0); - - const ppl = channel.getParticipantList(); - expect(ppl).toBeEmpty(); -}); diff --git a/test/ws/FakeSocket.ts b/test/ws/FakeSocket.ts deleted file mode 100644 index 949be65..0000000 --- a/test/ws/FakeSocket.ts +++ /dev/null @@ -1 +0,0 @@ -export class FakeSocket {}