diff --git a/README.md b/README.md index c99640d..29db016 100644 --- a/README.md +++ b/README.md @@ -66,27 +66,27 @@ This has always been the future intention of this project. ## TODO -- Change `socketsBySocketID` to `socketsByUUID` -- Channel data saving -- Permission groups and permissions - - Probable permission groups: owner, admin, mod, trialmod, default - - Setup tags for each permission group -- MPP.com data message +- [ ] Channel data saving (I forget what this means) +- [ ] Token generation +- [ ] Permission groups and permissions + - [x] Probable permission groups: owner, admin, mod, trialmod, default + - [ ] Setup tags for each permission group +- [ ] MPP.com data message - Implement based on `spooky.js` given there is no official documentation -- No cussing setting -- Full server-wide event bus - - Channel events - - Socket events - - User data events - - Permission-related events -- Redo ratelimits -- Redo all of the validations with Zod +- [ ] No cussing setting +- [ ] Full server-wide event bus + - [ ] Channel events + - [ ] Socket events + - [ ] User data events + - [ ] Permission-related events +- [ ] Redo ratelimits +- [ ] Redo all of the validations with Zod - This probably means making Zod schemas for every single message type - Also user and channel data -- Test every frontend -- Test fishing bot -- Remote console -- Modify frontend to use templating +- [ ] Test every frontend +- [ ] Test fishing bot +- [ ] Remote console +- [ ] Modify frontend to use templating ## Backlog/Notes diff --git a/bun.lockb b/bun.lockb index 370a23d..9796992 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/config/permissions.yml b/config/permissions.yml index c4df6ea..5cc41a7 100644 --- a/config/permissions.yml +++ b/config/permissions.yml @@ -1,3 +1,13 @@ +owner: + - clearChat + - vanish + - chsetAnywhere + - chownAnywhere + - usersetOthers + - siteBan + - siteBanAnyReason + - siteBanAnyDuration + admin: - clearChat - vanish @@ -7,3 +17,19 @@ admin: - siteBan - siteBanAnyReason - siteBanAnyDuration + +mod: + - clearChat + - vanish + - chsetAnywhere + - chownAnywhere + - usersetOthers + - siteBan + - siteBanAnyReason + +trialmod: + - clearChat + - vanish + - chsetAnywhere + - chownAnywhere + - siteBan diff --git a/src/channel/Channel.ts b/src/channel/Channel.ts index 140ecf4..9c79184 100644 --- a/src/channel/Channel.ts +++ b/src/channel/Channel.ts @@ -1,11 +1,10 @@ import EventEmitter from "events"; import { Logger } from "../util/Logger"; import type { - ChannelSettingValue, IChannelSettings, - ClientEvents, + OutgoingSocketEvents, Participant, - ServerEvents, + IncomingSocketEvents, IChannelInfo, Notification, UserFlags, @@ -57,7 +56,7 @@ export class Channel extends EventEmitter { private settings: Partial; private ppl = new Array(); - public chatHistory = new Array(); + public chatHistory = new Array(); private async loadChatHistory() { try { @@ -242,7 +241,7 @@ export class Channel extends EventEmitter { const BANNED_WORDS = ["AMIGHTYWIND", "CHECKLYHQ"]; - this.on("a", async (msg: ServerEvents["a"], socket: Socket) => { + this.on("a", async (msg: IncomingSocketEvents["a"], socket: Socket) => { try { if (typeof msg.message !== "string") return; @@ -284,7 +283,7 @@ export class Channel extends EventEmitter { const part = socket.getParticipant() as Participant; - const outgoing: ClientEvents["a"] = { + const outgoing: OutgoingSocketEvents["a"] = { m: "a", a: msg.message, t: Date.now(), @@ -847,8 +846,8 @@ export class Channel extends EventEmitter { * Send messages to everyone in this channel * @param arr List of events to send to clients */ - public sendArray( - arr: ClientEvents[EventID][], + public sendArray( + arr: OutgoingSocketEvents[EventID][], blockPartID?: string ) { const sentSocketIDs = new Array(); @@ -875,7 +874,7 @@ export class Channel extends EventEmitter { * @param socket Socket that is sending notes * @returns undefined */ - public playNotes(msg: ServerEvents["n"], socket?: Socket) { + public playNotes(msg: IncomingSocketEvents["n"], socket?: Socket) { if (this.isDestroyed()) return; let pianoPartID = usersConfig.adminParticipant.id; @@ -885,7 +884,7 @@ export class Channel extends EventEmitter { pianoPartID = part.id; } - const clientMsg: ClientEvents["n"] = { + const clientMsg: OutgoingSocketEvents["n"] = { m: "n", n: msg.n, t: msg.t, @@ -1230,7 +1229,7 @@ export class Channel extends EventEmitter { * @param msg Chat message event to send * @param p Participant who is "sending the message" **/ - public async sendChat(msg: ServerEvents["a"], p: Participant) { + public async sendChat(msg: IncomingSocketEvents["a"], p: Participant) { if (!msg.message) return; if (msg.message.length > 512) return; @@ -1241,7 +1240,7 @@ export class Channel extends EventEmitter { .replace(/(\p{Mc}{5})\p{Mc}+/gu, "$1") .trim(); - const outgoing: ClientEvents["a"] = { + const outgoing: OutgoingSocketEvents["a"] = { m: "a", a: msg.message, t: Date.now(), diff --git a/src/event/bus.ts b/src/event/bus.ts new file mode 100644 index 0000000..f0c099d --- /dev/null +++ b/src/event/bus.ts @@ -0,0 +1,9 @@ +import EventEmitter from "events"; + +class EventBus extends EventEmitter { + constructor() { + super(); + } +} + +export const eventBus = new EventBus(); diff --git a/src/util/types.d.ts b/src/util/types.d.ts index 5b5cb77..abe7f0b 100644 --- a/src/util/types.d.ts +++ b/src/util/types.d.ts @@ -107,7 +107,7 @@ declare interface Crown { endPos: Vector2; } -declare interface ServerEvents { +declare interface IncomingSocketEvents { hi: { m: "hi"; token?: string; @@ -209,7 +209,7 @@ declare interface ServerEvents { "admin message": { m: "admin message"; password: string; - msg: ServerEvents[keyof ServerEvents]; + msg: IncomingSocketEvents[keyof IncomingSocketEvents]; }; b: { @@ -310,7 +310,7 @@ declare interface ServerEvents { }; } -declare interface ClientEvents { +declare interface OutgoingSocketEvents { a: { m: "a"; a: string; @@ -407,11 +407,11 @@ declare interface ClientEvents { }; } -type EventID = ServerEvents[keyof ServerEvents]["m"]; +type EventID = IncomingSocketEvents[keyof IncomingSocketEvents]["m"]; declare type ServerEventListener = { id: E; - callback: (msg: ServerEvents[E], socket: Socket) => Promise; + callback: (msg: IncomingSocketEvents[E], socket: Socket) => Promise; }; declare type Vector2 = { diff --git a/src/ws/Socket.ts b/src/ws/Socket.ts index eceb9de..6d546c6 100644 --- a/src/ws/Socket.ts +++ b/src/ws/Socket.ts @@ -9,9 +9,9 @@ import EventEmitter from "events"; import type { IChannelInfo, IChannelSettings, - ClientEvents, + OutgoingSocketEvents, Participant, - ServerEvents, + IncomingSocketEvents, UserFlags, Vector2, Notification, @@ -295,8 +295,8 @@ export class Socket extends EventEmitter { * Send this socket an array of messages * @param arr Array of messages to send **/ - public sendArray( - arr: ClientEvents[EventID][] + public sendArray( + arr: OutgoingSocketEvents[EventID][] ) { if (this.isDestroyed() || !this.ws) return; this.ws.send(JSON.stringify(arr)); @@ -646,7 +646,7 @@ export class Socket extends EventEmitter { * Make this socket play a note in the channel they are in * @param msg Note message from client **/ - public playNotes(msg: ServerEvents["n"]) { + public playNotes(msg: IncomingSocketEvents["n"]) { const ch = this.getCurrentChannel(); if (!ch) return; ch.playNotes(msg, this); diff --git a/src/ws/events.ts b/src/ws/events.ts index 856064a..36f0368 100644 --- a/src/ws/events.ts +++ b/src/ws/events.ts @@ -1,4 +1,8 @@ -import type { EventID, ServerEventListener, ServerEvents } from "../util/types"; +import type { + EventID, + ServerEventListener, + IncomingSocketEvents +} from "../util/types"; export class EventGroup { public eventList = new Array>(); diff --git a/src/ws/events/user/handlers/a.ts b/src/ws/events/user/handlers/a.ts index 08c6dcb..33d0c49 100644 --- a/src/ws/events/user/handlers/a.ts +++ b/src/ws/events/user/handlers/a.ts @@ -1,10 +1,17 @@ import { Socket } from "../../../Socket"; -import { ServerEventListener, ServerEvents } from "../../../../util/types"; +import { + ServerEventListener, + IncomingSocketEvents +} from "../../../../util/types"; // https://stackoverflow.com/questions/64509631/is-there-a-regex-to-match-all-unicode-emojis -const emojiRegex = /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/g; +const emojiRegex = + /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/g; -function populateSocketChatGatewayFlags(msg: ServerEvents["a"], socket: Socket) { +function populateSocketChatGatewayFlags( + msg: IncomingSocketEvents["a"], + socket: Socket +) { socket.gateway.hasSentChatMessage = true; if (msg.message.toUpperCase() == msg.message) { diff --git a/src/ws/events/user/handlers/hi.ts b/src/ws/events/user/handlers/hi.ts index 78bb0a8..cd20d76 100644 --- a/src/ws/events/user/handlers/hi.ts +++ b/src/ws/events/user/handlers/hi.ts @@ -2,7 +2,7 @@ import { getUserPermissions } from "~/data/permissions"; import { Logger } from "~/util/Logger"; import { getMOTD } from "~/util/motd"; import { createToken, getToken, validateToken } from "~/util/token"; -import type { ServerEventListener, ServerEvents } from "~/util/types"; +import type { ServerEventListener, IncomingSocketEvents } from "~/util/types"; import type { Socket } from "~/ws/Socket"; import { config, usersConfigPath } from "~/ws/usersConfig";