From ee2d6c4dde13cfe5303b22160157458e61829dd6 Mon Sep 17 00:00:00 2001 From: Hri7566 Date: Sat, 3 Aug 2024 06:50:56 -0400 Subject: [PATCH] Add ID generation methods, add tags to userset updates --- .env.template | 1 + README.md | 7 +++-- config/channels.yml | 23 ++------------- config/notifications.yml | 2 ++ config/ratelimits.yml | 2 ++ config/users.yml | 39 +++++++++++++++++++------ prisma/schema.prisma | 1 + src/channel/Channel.ts | 4 ++- src/util/env.ts | 4 ++- src/util/id.ts | 47 +++++++++++++++++++++++-------- src/ws/Socket.ts | 7 +++-- src/ws/events/user/handlers/hi.ts | 8 +++--- src/ws/usersConfig.ts | 6 +++- 13 files changed, 99 insertions(+), 52 deletions(-) diff --git a/.env.template b/.env.template index 9194ad5..c47dcfc 100644 --- a/.env.template +++ b/.env.template @@ -2,3 +2,4 @@ DATABASE_URL="file:./db.sqlite" PORT=8443 ADMIN_PASS= SALT= +COLOR_SALT= diff --git a/README.md b/README.md index bfc29d5..113e3f1 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ Brandon's server originally used MongoDB for storing user data, but there are to - Usernames/colors - Allowing color changing can be toggled in the config, similar to MPP.com - Default user parameters can be set + - Configurable ID and color generation methods - Channels - Channel list - Channel settings @@ -46,6 +47,8 @@ Brandon's server originally used MongoDB for storing user data, but there are to - Server must be setup as a pm2/docker/systemd process for automatic restarting - Ability to change tags - Similar to the MPP.net server, but uses a Brandon-style admin message + - Ability to rename channels + - Chat clearing similar to MPP.net ## TODO @@ -67,6 +70,7 @@ Brandon's server originally used MongoDB for storing user data, but there are to - Test every frontend - Test fishing bot - Remote console +- Modify frontend to use templating ## Backlog/Notes @@ -75,7 +79,6 @@ Brandon's server originally used MongoDB for storing user data, but there are to - Split script.js into multiple files - Implement tags as a server option, toggles code on frontend - Same with color changing -- Bun memory usage can skyrocket - Reload config files on save - Expose API? @@ -115,7 +118,7 @@ such as enabling the color changing option in the userset modal menu, or sending $ cp .env.template .env ``` - Edit `.env` to your needs. + Edit `.env` to your needs. Some variables are required for certain features to work. - Edit the files in the `config` folder to match your needs diff --git a/config/channels.yml b/config/channels.yml index 05d6b74..f03e95c 100644 --- a/config/channels.yml +++ b/config/channels.yml @@ -1,9 +1,8 @@ -# Which channels to load on startup. +# Channel config file + forceLoad: - lobby - test/awkward - -# Default channel settings for lobby channels. lobbySettings: lobby: true chat: true @@ -11,36 +10,20 @@ lobbySettings: visible: true color: "#73b3cc" color2: "#273546" - -# Default channel settings for normal user-created channels. -# Note that this allows for channel settings users can't set, like visible and lobby. defaultSettings: chat: true crownsolo: false color: "#3b5054" color2: "#001014" visible: true - -# Regex patterns for lobby channel names. -# Any channel name that matches any of these patterns will be considered a lobby channel on instantiation. lobbyRegexes: - ^lobby[0-9][0-9]$ - ^lobby[0-9]$ - ^lobby$ - ^lobbyNaN$ - ^test/.+$ - -# The channel to use for the lobby backdoor. lobbyBackdoor: lolwutsecretlobbybackdoor - -# The channel that users get sent to when they are banned from a channel/join a channel they are already banned in/join a channel that is full and not a regular lobby. -# This will not be used for real lobby channels. (channels that start with "lobby" and may have numbers on the end) fullChannel: test/awkward - -# Whether or not to publish channel user limits in the channel list. sendLimit: false - -# Whether to give a user the crown when they join a channel they were already the owner of when they left. -# Reportedly, this is a feature on the original server, but it's not working there. -# This is corrected in MPP.net's server. chownOnRejoin: true +sendTags: false diff --git a/config/notifications.yml b/config/notifications.yml index 361f27b..3b994da 100644 --- a/config/notifications.yml +++ b/config/notifications.yml @@ -1,3 +1,5 @@ +# Notification config file + # Whether to allow HTML in notifications. # This is a security risk, so only enable this if you trust your admins. allowXSS: true diff --git a/config/ratelimits.yml b/config/ratelimits.yml index 536d998..b33a993 100644 --- a/config/ratelimits.yml +++ b/config/ratelimits.yml @@ -1,3 +1,5 @@ +# Rate limit config file + # Difference between rate limits and rate limit chains: # Rate limits will not allow anything to be sent until the rate limit interval has passed. # Rate limit chains, on the other hand, will allow messages to be sent until the rate limit chain's limit has been reached. diff --git a/config/users.yml b/config/users.yml index 89f09f2..54512d7 100644 --- a/config/users.yml +++ b/config/users.yml @@ -1,24 +1,29 @@ +# User data config file + # The default username for new users. defaultName: Anonymous # The default user flags for new users. +# These flags control arbitrary data that could be checked by any part of the code. +# This is an internal feature available on MPP.com, but not MPP.net. defaultFlags: volume: 100 # Whether or not to allow users to change their color. -# Brandon's server has this set to false, but multiple users have reported it to be on before 2016. +# Based on some reports, the MPP.com server stopped allowing this around 2016. enableColorChanging: true -# Allows custom data inside note messages. -# This was in the original server, but not in MPP.net's server. -# This only exists for backwards compatibility with scripts like nagalun's drarwing script. +# Whether to allow custom data inside note messages. +# This was in the original server, but not in MPP.net's server do to stricter sanitization. +# This only exists for backwards compatibility with scripts like nagalun's drawing script. enableCustomNoteData: true # Whether or not to enable tags that are sent publicly. -# This won't prevent admins from changing tags internally, but it will not be sent to clients. +# This won't prevent admins from changing tags internally, but they will not be sent to clients if set to false. enableTags: true # This is the user data that the server will use to send admin chat messages with. +# This is a feature available on MPP.com, but was unknown to the MPP.net developers, therefore not implemented on MPP.net. adminParticipant: _id: "0" name: mpp @@ -30,12 +35,28 @@ adminParticipant: enableAdminEval: true # The token validation scheme. Valid values are "none", "jwt" and "uuid". -# This server will still validate existing tokens generated with other schemes if not set to "none". -tokenAuth: none +# This server will still validate existing tokens generated with other schemes if not set to "none", mimicking MPP.net's server. +# This is set to "none" by default because MPP.com does not have a token system. +tokenAuth: jwt -# The browser challenge scheme. Valid values are "none", "obf" and "basic". +# The browser challenge scheme. Valid options are "none", "obf" and "basic". # This is to change what is sent in the "b" message. # "none" will disable the browser challenge, # "obf" will sent an obfuscated function to the client, # and "basic" will just send a simple function that expects a boolean. -browserChallenge: none +browserChallenge: basic + +# Scheme for generating user IDs. +# Valid options are "random", "sha256", "mpp" and "uuid". +# "random" will generate a random ID. As of writing, this is in use by MPP.com's server, but likely a mistake or poor workaround. +# "sha256" will generate a hash of the user's IP address and the server's SALT with the SHA256 algorithm. +# "mpp" will generate a hash of the user's IP address in the same way that MPP.com and MPP.net do. This is the default. +# "uuid" will generate a UUID for the user ID. +idGeneration: mpp + +# Scheme for generating user colors. +# Valid options are "random", "sha256", "mpp" and "white". +# "random" will generate a random color for the user. This is not a known feature of any other server. +# "sha256" will generate a color based on a hash of the user's ID. +# "mpp" will generate a color based on the user's ID with a separate salt variable. This salt must be provided in the "COLOR_SALT" environment variable in the .env file. +colorGeneration: mpp diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d061a64..0ada6d6 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -18,6 +18,7 @@ model User { flags String @default("{}") // JSON flags object tag String // JSON tag tokens String @default("[]") // JSON tokens + group String @default("default") // Permission group } model ChatHistory { diff --git a/src/channel/Channel.ts b/src/channel/Channel.ts index 9d0c6a7..acf2624 100644 --- a/src/channel/Channel.ts +++ b/src/channel/Channel.ts @@ -53,7 +53,9 @@ export class Channel extends EventEmitter { } private async deleteChatHistory() { - await deleteChatHistory(this.getID()); + try { + await deleteChatHistory(this.getID()); + } catch (err) { } } public logger: Logger; diff --git a/src/util/env.ts b/src/util/env.ts index 7aac039..b1fbd34 100644 --- a/src/util/env.ts +++ b/src/util/env.ts @@ -1,5 +1,6 @@ import { createEnv } from "@t3-oss/env-core"; import { z } from "zod"; +import { config } from "../ws/usersConfig"; // Best way to do env ever export const env = createEnv({ @@ -7,7 +8,8 @@ export const env = createEnv({ PORT: z.coerce.number(), HOST: z.union([z.string().url(), z.string().ip()]).optional(), SALT: z.string().min(10), - ADMIN_PASS: z.string() + ADMIN_PASS: z.string(), + COLOR_SALT: config.colorGeneration == "mpp" ? z.string().min(10) : z.string().optional(), }, isServer: true, // Bun loads process.env automatically so we don't have to use modules diff --git a/src/util/id.ts b/src/util/id.ts index a5db5ab..714b4fc 100644 --- a/src/util/id.ts +++ b/src/util/id.ts @@ -1,5 +1,6 @@ import { createHash, randomBytes } from "crypto"; import env from "./env"; import { spoop_text } from "./helpers"; +import { config } from "../ws/usersConfig"; export function createID() { // Maybe I could make this funnier than it needs to be... @@ -21,24 +22,46 @@ export function createID() { } export function createUserID(ip: string) { - return createHash("sha256") - .update(ip) - .update(env.SALT) - .digest("hex") - .substring(0, 24); + if (config.idGeneration == "random") { + return createID(); + } else if (config.idGeneration == "sha256") { + return createHash("sha256") + .update(ip) + .update(env.SALT) + .digest("hex") + .substring(0, 24); + } else if (config.idGeneration == "mpp") { + return createHash("md5") + .update("::ffff:" + ip + env.SALT) + .digest("hex") + .substring(0, 24); + } } export function createSocketID() { return crypto.randomUUID(); } -export function createColor(ip: string) { - return ( - "#" + - createHash("sha256") - .update(ip) +export function createColor(_id: string) { + if (config.colorGeneration == "random") { + return "#" + Math.floor(Math.random() * 16777215).toString(16); + } else if (config.colorGeneration == "sha256") { + return "#" + createHash("sha256") + .update(_id) .update(env.SALT) .digest("hex") - .substring(24, 24 + 6) - ); + .substring(24, 24 + 6); + } else if (config.colorGeneration == "mpp") { + const hash = createHash("md5"); + hash.update(_id + env.COLOR_SALT); + const output = hash.digest(); + + const r = output.readUInt8(0) - 0x40; + const g = output.readUInt8(1) + 0x20; + const b = output.readUInt8(2); + + return "#" + r.toString(16) + g.toString(16) + b.toString(16); + } else if (config.colorGeneration == "white") { + return "#ffffff"; + } } diff --git a/src/ws/Socket.ts b/src/ws/Socket.ts index 5e37411..d3f456c 100644 --- a/src/ws/Socket.ts +++ b/src/ws/Socket.ts @@ -143,12 +143,14 @@ export class Socket extends EventEmitter { // Send a challenge to the browser for MPP.net frontends if (config.browserChallenge == "basic") { + // Basic function this.sendArray([{ m: "b", code: `~return true;` }]); } else if (config.browserChallenge == "obf") { - + // Obfuscated challenge building + // TODO } })(); @@ -524,7 +526,8 @@ export class Socket extends EventEmitter { id: part.id, name: part.name, x: cursorPos.x, - y: cursorPos.y + y: cursorPos.y, + tag: config.enableTags ? part.tag : undefined } ]); } diff --git a/src/ws/events/user/handlers/hi.ts b/src/ws/events/user/handlers/hi.ts index b9e7b95..56fa878 100644 --- a/src/ws/events/user/handlers/hi.ts +++ b/src/ws/events/user/handlers/hi.ts @@ -50,11 +50,11 @@ export const hi: ServerEventListener<"hi"> = { // Validate the token const valid = await validateToken(socket.getUserID(), msg.token); if (!valid) { - socket.ban(60000, "Invalid token"); - return; + //socket.ban(60000, "Invalid token"); + //return; + } else { + token = msg.token; } - - token = msg.token; } } diff --git a/src/ws/usersConfig.ts b/src/ws/usersConfig.ts index 707c145..685bef2 100644 --- a/src/ws/usersConfig.ts +++ b/src/ws/usersConfig.ts @@ -11,6 +11,8 @@ export interface UsersConfig { enableAdminEval: boolean; tokenAuth: "jwt" | "uuid" | "none"; browserChallenge: "none" | "obf" | "basic"; + idGeneration: "random" | "sha256" | "mpp" | "uuid"; + colorGeneration: "random" | "sha256" | "mpp" | "white"; } export const usersConfigPath = "config/users.yml"; @@ -31,7 +33,9 @@ export const defaultUsersConfig: UsersConfig = { }, enableAdminEval: false, tokenAuth: "none", - browserChallenge: "none" + browserChallenge: "none", + idGeneration: "mpp", + colorGeneration: "mpp" }; // Importing this elsewhere causes bun to segfault