Add rate limits for every message, fix lobby regex, implement tags into database, reword comments, add channel flags

This commit is contained in:
Hri7566 2024-07-10 17:02:42 -04:00
parent bb0516b367
commit 71960104eb
29 changed files with 506 additions and 96 deletions

View File

@ -1,7 +1,6 @@
forceLoad:
- lobby
- test/awkward
lobbySettings:
lobby: true
chat: true
@ -9,17 +8,18 @@ lobbySettings:
visible: true
color: "#73b3cc"
color2: "#273546"
defaultSettings:
chat: true
crownsolo: false
color: "#3b5054"
color2: "#001014"
visible: true
lobbyRegexes:
- "^lobby[1-9]?[1-9]?$"
- "^test/.+$"
lobbyBackdoor: "lolwutsecretlobbybackdoor"
fullChannel: "test/awkward"
- ^lobby[0-9][0-9]$
- ^lobby[0-9]$
- ^lobby$
- ^test/.+$
lobbyBackdoor: lolwutsecretlobbybackdoor
fullChannel: test/awkward
sendLimit: false
sendTags: false

View File

@ -3,28 +3,73 @@ user:
a: 1500
m: 50
ch: 1000
kickban: 250
kickban: 125
t: 7.8125
+ls: 16.666666666666668
-ls: 16.666666666666668
chown: 2000
hi: 50
bye: 50
devices: 50
admin_message: 50
admin message: 50
chains:
userset:
interval: 1800000
num: 1000
chset:
interval: 1800000
num: 1024
n:
interval: 1000
num: 512
crown:
normal:
a: 600
m: 50
ch: 1000
kickban: 250
kickban: 125
t: 7.8125
+ls: 16.666666666666668
-ls: 16.666666666666668
chown: 2000
hi: 50
bye: 50
devices: 50
admin_message: 50
admin message: 50
chains:
userset:
interval: 1800000
num: 1000
chset:
interval: 1800000
num: 1024
n:
interval: 1000
num: 512
admin:
normal:
a: 120
m: 16.666666666666668
ch: 100
kickban: 31.25
kickban: 16.666666666666668
t: 3.90625
+ls: 16.666666666666668
-ls: 16.666666666666668
chown: 500
hi: 50
bye: 50
devices: 50
admin_message: 16.666666666666668
admin message: 16.666666666666668
chains:
userset:
interval: 1800000
interval: 500
num: 1000
chset:
interval: 1800000
num: 1024
n:
interval: 50
num: 512

View File

@ -16,6 +16,7 @@ model User {
name String @default("Anonymous")
color String @default("#ffffff")
flags String @default("{}") // JSON flags object
tag String // JSON tag
}
model ChatHistory {

View File

@ -7,7 +7,8 @@ import {
Participant,
ServerEvents,
IChannelInfo,
Notification
Notification,
UserFlags
} from "../util/types";
import type { Socket } from "../ws/Socket";
import { validateChannelSettings } from "./settings";
@ -17,7 +18,7 @@ import { ChannelList } from "./ChannelList";
import { config } from "./config";
import { saveChatHistory, getChatHistory } from "../data/history";
import { mixin } from "../util/helpers";
import { NoteQuota } from "../ws/ratelimit/NoteQuota";
import { readUser } from "../data/user";
interface CachedKickban {
userId: string;
@ -25,9 +26,17 @@ interface CachedKickban {
endTime: number;
}
interface ExtraPartData {
uuids: string[];
flags: Partial<UserFlags>;
}
type ExtraPart = Participant & ExtraPartData;
export class Channel extends EventEmitter {
private settings: Partial<IChannelSettings>;
private ppl = new Array<Participant & { uuids: string[] }>();
private ppl = new Array<ExtraPart>();
public chatHistory = new Array<ClientEvents["a"]>();
private async loadChatHistory() {
@ -39,6 +48,8 @@ export class Channel extends EventEmitter {
public crown?: Crown;
private flags: Record<string, any> = {};
constructor(
private _id: string,
set?: Partial<IChannelSettings>,
@ -55,6 +66,8 @@ export class Channel extends EventEmitter {
// Validate settings in set
// Set the verified settings
this.logger.debug("lobby me?", this.isLobby());
if (!this.isLobby()) {
if (set) {
//this.logger.debug("Passed settings:", set);
@ -185,6 +198,15 @@ export class Channel extends EventEmitter {
return false;
}
/**
* Determine whether this channel is a lobby with the name "lobby" in it
*/
public isTrueLobby() {
if (this.getID().match("^lobby[0-9][0-9]$") && this.getID().match("^lobby[1-9]$")) return true;
return false;
}
/**
* Change this channel's settings
* @param set Channel settings
@ -265,7 +287,7 @@ export class Channel extends EventEmitter {
* @param socket Socket that is joining
* @returns undefined
*/
public join(socket: Socket): void {
public join(socket: Socket, force: boolean = false): void {
//! /!\ Players are forced to join the same channel on two different tabs!
//? TODO Should this be a bug or a feature?
//this.logger.debug("join triggered");
@ -274,17 +296,28 @@ export class Channel extends EventEmitter {
const part = socket.getParticipant() as Participant;
let hasChangedChannel = false;
let oldChannelID = socket.currentChannelID;
// Is user banned?
if (this.isBanned(part._id)) {
// Send user to ban channel instead
// TODO Send notification for ban
const chs = ChannelList.getList();
for (const ch of chs) {
const chid = ch.getID();
if (chid == config.fullChannel) {
return socket.setChannel(chid)
if (!force) {
// Is user banned?
if (this.isBanned(part._id)) {
// Send user to ban channel instead
// TODO Send notification for ban
const chs = ChannelList.getList();
for (const ch of chs) {
const chid = ch.getID();
if (chid == config.fullChannel) {
return socket.setChannel(chid)
}
}
}
// Is the channel full?
if (this.isFull()) {
// Is this a genuine lobby (not a test/ room)?
if (this.isTrueLobby()) {
const nextID = this.getNextIncrementationFromID();
this.logger.debug("New ID:", nextID);
return socket.setChannel(nextID, undefined, true)
}
}
}
@ -311,7 +344,8 @@ export class Channel extends EventEmitter {
color: part.color,
id: part.id,
tag: part.tag,
uuids: [socket.getUUID()]
uuids: [socket.getUUID()],
flags: socket.getUserFlags() || {}
});
} else {
if (socket.currentChannelID !== config.fullChannel) {
@ -331,7 +365,7 @@ export class Channel extends EventEmitter {
if (hasChangedChannel) {
// Were they in a channel before?
if (socket.currentChannelID) {
// Find the channel they were in
// Find the other channel they were in
const ch = ChannelList.getList().find(
ch => ch._id == socket.currentChannelID
);
@ -340,7 +374,7 @@ export class Channel extends EventEmitter {
if (ch) ch.leave(socket);
}
// Change the thing we checked to point to us now
// You belong here now
socket.currentChannelID = this.getID();
}
@ -443,9 +477,9 @@ export class Channel extends EventEmitter {
public isFull() {
// TODO Use limit setting
// if (this.isLobby() && this.ppl.length >= 20) {
// return true;
// }
if (this.isTrueLobby() && this.ppl.length >= 20) {
return true;
}
return false;
}
@ -472,13 +506,20 @@ export class Channel extends EventEmitter {
* @returns List of people
*/
public getParticipantList() {
return this.ppl.map(p => ({
id: p.id,
_id: p._id,
name: p.name,
color: p.color,
tag: p.tag
}));
const ppl = [];
for (const p of this.ppl) {
if (p.flags.vanish) continue;
ppl.push({
_id: p._id,
name: p.name,
color: p.color,
id: p.id,
tag: config.sendTags ? p.tag : undefined
});
}
return ppl;
}
public getParticipantListUnsanitized() {
@ -626,7 +667,7 @@ export class Channel extends EventEmitter {
}
/**
* Drop the crown (remove from user)
* Drop the crown (reset timer, and, if applicable, remove from user's head)
*/
public dropCrown() {
if (this.crown) {
@ -780,6 +821,11 @@ export class Channel extends EventEmitter {
}
}
/**
* Check if a user is banned here right now
* @param _id User ID
* @returns True if the user is banned, otherwise false
**/
public isBanned(_id: string) {
const now = Date.now();
@ -799,6 +845,9 @@ export class Channel extends EventEmitter {
return false;
}
/**
* Clear the chat and chat history
**/
public async clearChat() {
this.chatHistory = [];
await saveChatHistory(this.getID(), this.chatHistory);
@ -826,6 +875,11 @@ export class Channel extends EventEmitter {
}]);
}
/**
* Send a message in chat
* @param msg Chat message event to send
* @param p Participant who is "sending the message"
**/
public async sendChat(msg: ServerEvents["a"], p: Participant) {
if (!msg.message) return;
@ -848,6 +902,38 @@ export class Channel extends EventEmitter {
this.chatHistory.push(outgoing);
await saveChatHistory(this.getID(), this.chatHistory);
}
/**
* Set a flag on this channel
* @param key Flag ID
* @param val Value of which the flag will be set to
**/
public setFlag(key: string, val: any) {
this.flags[key] = val;
}
/**
* Get a flag on this channel
* @param key Flag ID
* @returns Value of flag
*/
public getFlag(key: string) {
return this.flags[key];
}
/**
* Get the name of this channel where the number at the end is one higher than this one, given it ends with a number
**/
public getNextIncrementationFromID() {
try {
const id = this.getID();
const num = parseInt((id.match(/\d+$/) as string[])[0]);
return `${id.substring(0, id.length - num.toString().length)}${num + 1}`;
} catch (err) {
return config.fullChannel;
}
}
}
export default Channel;

View File

@ -8,6 +8,8 @@ interface ChannelConfig {
lobbyRegexes: string[];
lobbyBackdoor: string;
fullChannel: string;
sendLimit: boolean;
sendTags: boolean;
}
export const config = loadConfig<ChannelConfig>("config/channels.yml", {
@ -27,8 +29,10 @@ export const config = loadConfig<ChannelConfig>("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/.+$"],
// Here's a terrifying fact: Brandon used parseInt to check lobby names
lobbyRegexes: ["^lobby[0-9][0-9]$", "^lobby[0-9]$", "^lobby$", "^test/.+$"],
lobbyBackdoor: "lolwutsecretlobbybackdoor",
fullChannel: "test/awkward"
fullChannel: "test/awkward",
sendLimit: false,
sendTags: false,
});

View File

@ -1,16 +1,41 @@
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
import { Logger } from "../util/Logger";
import { ChannelList } from "./ChannelList";
// Channel forceloader (cringe)
let hasFullChannel = false;
for (const id of config.forceLoad) {
new Channel(id, undefined, undefined, undefined, true);
if (id == config.fullChannel) hasFullChannel = true;
const logger = new Logger("Channel Forceloader");
export function forceloadChannel(id: string) {
try {
logger.info("Forceloading", id);
new Channel(id, undefined, undefined, undefined, true);
return true;
} catch (err) {
return false;
}
}
if (!hasFullChannel) {
new Channel(config.fullChannel, undefined, undefined, undefined, true);
export function unforceloadChannel(id: string) {
const ch = ChannelList.getList().find(ch => ch.getID() == id);
if (!ch) return false;
logger.info("Unloading", id);
ch.destroy();
return true;
}
export function loadDefaultForcedChannels() {
let hasFullChannel = false;
for (const id of config.forceLoad) {
forceloadChannel(id);
if (id == config.fullChannel) hasFullChannel = true;
}
if (!hasFullChannel) {
new Channel(config.fullChannel, undefined, undefined, undefined, true);
}
}

View File

@ -1,20 +1,27 @@
import { User } from "@prisma/client";
import { prisma } from "./prisma";
import { UserFlags } from "../util/types";
import { Tag, UserFlags } from "../util/types";
export async function createUser(
_id: string,
name?: string,
color?: string,
flags?: UserFlags
flags?: UserFlags,
tag?: Tag
) {
return await prisma.user.create({
data: { id: _id, name, color, flags: JSON.stringify(flags) }
data: {
id: _id,
name,
color,
flags: JSON.stringify(flags) || "",
tag: JSON.stringify(tag) || ""
}
});
}
export async function getUsers() {
return await {
return {
users: await prisma.user.findMany(),
count: await prisma.user.count()
}

View File

@ -6,10 +6,12 @@
// If you don't load the server first, bun will literally segfault
import "./ws/server";
import "./channel/forceLoad";
import { loadDefaultForcedChannels } from "./channel/forceLoad";
import { Logger } from "./util/Logger";
const logger = new Logger("Main");
logger.info("Loading default channels...");
loadDefaultForcedChannels();
import "./util/readline";

0
src/util/Logger.ts Executable file → Normal file
View File

51
src/util/types.d.ts vendored
View File

@ -1,18 +1,5 @@
/**
* 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<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
declare type UserFlags = Partial<{
@ -27,9 +14,17 @@ declare type UserFlags = Partial<{
cansetcrowns: number;
// new
"no note quota": number;
"no note rate limit": number;
"no cursor rate limit": number;
"no userset rate limit": number;
mod: number;
admin: number;
vanish: number;
}>;
type ChannelFlags = Partial<{
limit: number;
}>;
declare interface Tag {
@ -110,7 +105,6 @@ declare interface Crown {
endPos: Vector2;
}
// Events copied from Hri7566/mppclone-client typedefs
declare interface ServerEvents {
a: {
m: "a";
@ -238,19 +232,40 @@ declare interface ServerEvents {
remove?: true;
};
tag: {
m: "tag";
_id: string;
tag: {
text: string;
color: string;
};
}
clear_chat: {
m: "clear_chat"
m: "clear_chat";
};
notification: {
m: "notification"
m: "notification";
targetChannel?: string;
targetUser?: string;
} & Notification;
restart: {
m: "restart"
}
m: "restart";
};
forceload: {
m: "forceload";
_id: string;
};
ch_flag: {
m: "ch_flag";
_id?: string;
key: string;
value: any;
};
}
declare interface ClientEvents {

View File

@ -123,7 +123,7 @@ export class Socket extends EventEmitter {
return this.id;
}
public setChannel(_id: string, set?: Partial<IChannelSettings>) {
public setChannel(_id: string, set?: Partial<IChannelSettings>, force: boolean = false) {
if (this.isDestroyed()) return;
if (this.currentChannelID === _id) {
logger.debug("Guy in channel was already in");
@ -155,7 +155,7 @@ export class Socket extends EventEmitter {
this
);
channel.join(this);
channel.join(this, force);
}
}
@ -443,17 +443,25 @@ export class Socket extends EventEmitter {
ch.playNotes(msg, this);
}
private isSubscribedToChannelList = false;
public subscribeToChannelList() {
if (this.isSubscribedToChannelList) return;
ChannelList.subscribe(this.id);
const firstList = ChannelList.getPublicList().map(v =>
v.getInfo(this._id)
);
this.sendChannelList(firstList);
this.isSubscribedToChannelList = true;
}
public unsubscribeFromChannelList() {
if (!this.isSubscribedToChannelList) return;
ChannelList.unsubscribe(this.id);
this.isSubscribedToChannelList = false;
}
public sendChannelList(list: IChannelInfo[], complete: boolean = true) {
@ -476,7 +484,6 @@ export class Socket extends EventEmitter {
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;
@ -514,6 +521,13 @@ export class Socket extends EventEmitter {
html: notif.html
}]);
}
public setTag(text: string, color: string) {
const user = this.getUser();
if (!user) return;
user.tag = JSON.stringify({ text, color });
updateUser(this.getUserID(), user);
}
}
export const socketsBySocketID = new Map<string, Socket>();

View File

@ -0,0 +1,20 @@
import { ChannelList } from "../../../../channel/ChannelList";
import { ServerEventListener } from "../../../../util/types";
export const ch_flag: ServerEventListener<"ch_flag"> = {
id: "ch_flag",
callback: async (msg, socket) => {
// Edit channel flag
let chid = msg._id;
if (typeof chid !== "string") {
const ch = socket.getCurrentChannel();
if (!ch) return;
chid = ch.getID();
}
const ch = ChannelList.getList().find(c => c.getID() == chid);
if (!ch) return;
}
};

View File

@ -0,0 +1,12 @@
import { forceloadChannel } from "../../../../channel/forceLoad";
import { ServerEventListener } from "../../../../util/types";
export const forceload: ServerEventListener<"forceload"> = {
id: "forceload",
callback: async (msg, socket) => {
// Forceload channel
if (typeof msg._id !== "string") return;
forceloadChannel(msg._id);
}
};

View File

@ -0,0 +1,29 @@
import { readUser, updateUser } from "../../../../data/user";
import { ServerEventListener } from "../../../../util/types";
import { findSocketsByUserID } from "../../../Socket";
export const tag: ServerEventListener<"tag"> = {
id: "tag",
callback: async (msg, socket) => {
// Change someone else's tag
const id = msg._id;
const tag = msg.tag;
if (typeof id !== "string") return;
if (typeof tag !== "object") return;
if (typeof tag["text"] !== "string") return;
if (typeof tag.color !== "string") return;
if (!tag.color.match(/^#[0-9a-f]{6}$/i)) return;
const user = await readUser(msg._id);
if (!user) return;
user.tag = JSON.stringify(tag);
await updateUser(id, user);
const toUpdate = findSocketsByUserID(id);
toUpdate.forEach(s => {
s.setTag(msg.tag.text, msg.tag.color);
});
}
};

View File

@ -12,6 +12,10 @@ export const plus_ls: ServerEventListener<"+ls"> = {
// 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.
if (socket.rateLimits) {
if (!socket.rateLimits.normal["+ls"].attempt()) return;
}
socket.subscribeToChannelList();
}
};

View File

@ -4,6 +4,10 @@ export const minus_ls: ServerEventListener<"-ls"> = {
id: "-ls",
callback: (msg, socket) => {
// Stop giving us the latest server forecast
if (socket.rateLimits) {
if (!socket.rateLimits.normal["-ls"].attempt()) return;
}
socket.unsubscribeFromChannelList();
}
};

View File

@ -1,13 +1,13 @@
import { Logger } from "../../../../util/Logger";
import env from "../../../../util/env";
import { ServerEventListener } from "../../../../util/types";
import { config } from "../../../usersConfig";
const logger = new Logger("Admin Message Handler");
export const admin_message: ServerEventListener<"admin message"> = {
id: "admin message",
callback: (msg, socket) => {
// Administrator control message
if (socket.rateLimits)
if (!socket.rateLimits.normal["admin message"].attempt()) return;
if (typeof msg.password !== "string") return;
if (msg.password !== env.ADMIN_PASS) return;

View File

@ -4,6 +4,9 @@ export const bye: ServerEventListener<"bye"> = {
id: "bye",
callback: (msg, socket) => {
// Leave server
if (socket.rateLimits)
if (!socket.rateLimits.normal.bye.attempt()) return;
socket.destroy();
}
};

View File

@ -7,6 +7,9 @@ export const chown: ServerEventListener<"chown"> = {
id: "chown",
callback: (msg, socket) => {
// Change channel ownership
if (socket.rateLimits)
if (!socket.rateLimits.normal["chown"].attempt()) return;
const ch = socket.getCurrentChannel();
if (!ch) return;

View File

@ -4,6 +4,9 @@ export const chset: ServerEventListener<"chset"> = {
id: "chset",
callback: (msg, socket) => {
// Change channel settings
if (socket.rateLimits)
if (!socket.rateLimits.chains.chset.attempt()) return;
if (typeof msg.set == "undefined") return;
const ch = socket.getCurrentChannel();

View File

@ -4,6 +4,9 @@ export const devices: ServerEventListener<"devices"> = {
id: "devices",
callback: (msg, socket) => {
// List of MIDI Devices (or software ports, because nobody can tell the difference)
if (socket.rateLimits)
if (!socket.rateLimits.normal.devices.attempt()) return;
if (socket.gateway.hasSentDevices) return;
socket.gateway.hasSentDevices = true;
}

View File

@ -5,9 +5,10 @@ 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.rateLimits)
if (!socket.rateLimits.normal.hi.attempt()) return;
if (socket.gateway.hasProcessedHi) return;
let part = socket.getParticipant();

View File

@ -4,8 +4,10 @@ export const m: ServerEventListener<"m"> = {
id: "m",
callback: (msg, socket) => {
// Cursor movement
if (!socket.rateLimits) return;
if (!socket.rateLimits.normal.m.attempt()) return;
if (socket.rateLimits) {
if (!socket.rateLimits.normal.m.attempt()) return;
}
if (!msg.x || !msg.y) return;
let x = msg.x;

View File

@ -5,6 +5,9 @@ export const n: ServerEventListener<"n"> = {
id: "n",
callback: (msg, socket) => {
// Piano note
if (socket.rateLimits)
if (!socket.rateLimits.chains.n.attempt()) return;
if (!Array.isArray(msg.n)) return;
if (typeof msg.t !== "number") return;

View File

@ -4,11 +4,15 @@ export const t: ServerEventListener<"t"> = {
id: "t",
callback: (msg, socket) => {
// Ping
if (socket.rateLimits)
if (!socket.rateLimits.normal.t.attempt()) return
if (msg.e) {
if (typeof msg.e !== "number") return;
}
// Pong!
// Pong
socket.sendArray([
{
m: "t",

View File

@ -7,14 +7,26 @@ export interface RateLimitConfigList<
RLC = { num: number; interval: number }
> {
normal: {
m: RL;
a: RL;
m: RL;
ch: RL;
kickban: RL;
t: RL;
"+ls": RL;
"-ls": RL;
chown: RL;
// weird limits
hi: RL;
bye: RL;
devices: RL;
"admin message": RL;
};
chains: {
userset: RLC;
chset: RLC;
n: RLC; // not to be confused with NoteQuota
};
}
@ -37,12 +49,29 @@ export const config = loadConfig<RateLimitsConfig>("config/ratelimits.yml", {
a: 6000 / 4,
m: 1000 / 20,
ch: 1000 / 1,
kickban: 1000 / 4
kickban: 1000 / 8,
t: 1000 / 128,
"+ls": 1000 / 60,
"-ls": 1000 / 60,
chown: 2000,
hi: 1000 / 20,
bye: 1000 / 20,
devices: 1000 / 20,
"admin message": 1000 / 20
},
chains: {
userset: {
interval: 1000 * 60 * 30,
num: 1000
},
chset: {
interval: 1000 * 60 * 30,
num: 1024
},
n: {
interval: 1000,
num: 512
}
}
},
@ -51,12 +80,29 @@ export const config = loadConfig<RateLimitsConfig>("config/ratelimits.yml", {
a: 6000 / 10,
m: 1000 / 20,
ch: 1000 / 1,
kickban: 1000 / 4
kickban: 1000 / 8,
t: 1000 / 128,
"+ls": 1000 / 60,
"-ls": 1000 / 60,
chown: 2000,
hi: 1000 / 20,
bye: 1000 / 20,
devices: 1000 / 20,
"admin message": 1000 / 20
},
chains: {
userset: {
interval: 1000 * 60 * 30,
num: 1000
},
chset: {
interval: 1000 * 60 * 30,
num: 1024
},
n: {
interval: 1000,
num: 512
}
}
},
@ -65,12 +111,29 @@ export const config = loadConfig<RateLimitsConfig>("config/ratelimits.yml", {
a: 6000 / 50,
m: 1000 / 60,
ch: 1000 / 10,
kickban: 1000 / 32
kickban: 1000 / 60,
t: 1000 / 256,
"+ls": 1000 / 60,
"-ls": 1000 / 60,
chown: 500,
hi: 1000 / 20,
bye: 1000 / 20,
devices: 1000 / 20,
"admin message": 1000 / 60
},
chains: {
userset: {
interval: 1000 * 60 * 30,
interval: 500,
num: 1000
},
chset: {
interval: 1000 * 60 * 30,
num: 1024
},
n: {
interval: 50,
num: 512
}
}
}

View File

@ -7,13 +7,32 @@ export const adminLimits: RateLimitConstructorList = {
a: () => new RateLimit(config.admin.normal.a),
m: () => new RateLimit(config.admin.normal.m),
ch: () => new RateLimit(config.admin.normal.ch),
kickban: () => new RateLimit(config.admin.normal.kickban)
kickban: () => new RateLimit(config.crown.normal.kickban),
t: () => new RateLimit(config.crown.normal.t),
"+ls": () => new RateLimit(config.crown.normal["+ls"]),
"-ls": () => new RateLimit(config.crown.normal["-ls"]),
chown: () => new RateLimit(config.crown.normal.chown),
hi: () => new RateLimit(config.crown.normal.hi),
bye: () => new RateLimit(config.crown.normal.bye),
devices: () => new RateLimit(config.crown.normal.devices),
"admin message": () => new RateLimit(config.crown.normal["admin message"])
},
chains: {
userset: () =>
new RateLimitChain(
config.admin.chains.userset.interval,
config.admin.chains.userset.num
),
chset: () =>
new RateLimitChain(
config.crown.chains.chset.interval,
config.crown.chains.userset.num
),
n: () =>
new RateLimitChain(
config.crown.chains.n.interval,
config.crown.chains.userset.num
)
}
};

View File

@ -6,13 +6,33 @@ export const crownLimits: RateLimitConstructorList = {
normal: {
a: () => new RateLimit(config.crown.normal.a),
m: () => new RateLimit(config.crown.normal.m),
ch: () => new RateLimit(config.crown.normal.ch)
ch: () => new RateLimit(config.crown.normal.ch),
kickban: () => new RateLimit(config.crown.normal.kickban),
t: () => new RateLimit(config.crown.normal.t),
"+ls": () => new RateLimit(config.crown.normal["+ls"]),
"-ls": () => new RateLimit(config.crown.normal["-ls"]),
chown: () => new RateLimit(config.crown.normal.chown),
hi: () => new RateLimit(config.crown.normal.hi),
bye: () => new RateLimit(config.crown.normal.bye),
devices: () => new RateLimit(config.crown.normal.devices),
"admin message": () => new RateLimit(config.crown.normal["admin message"])
},
chains: {
userset: () =>
new RateLimitChain(
config.crown.chains.userset.interval,
config.crown.chains.userset.num
),
chset: () =>
new RateLimitChain(
config.crown.chains.chset.interval,
config.crown.chains.userset.num
),
n: () =>
new RateLimitChain(
config.crown.chains.n.interval,
config.crown.chains.userset.num
)
}
};

View File

@ -2,19 +2,37 @@ import { RateLimit } from "../RateLimit";
import { RateLimitChain } from "../RateLimitChain";
import { RateLimitConstructorList, config } from "../config";
// All this does is instantiate rate limits from the config
export const userLimits: RateLimitConstructorList = {
normal: {
a: () => new RateLimit(config.user.normal.a),
m: () => new RateLimit(config.user.normal.m),
ch: () => new RateLimit(config.user.normal.ch),
kickban: () => new RateLimit(config.user.normal.kickban)
kickban: () => new RateLimit(config.user.normal.kickban),
t: () => new RateLimit(config.user.normal.t),
"+ls": () => new RateLimit(config.user.normal["+ls"]),
"-ls": () => new RateLimit(config.user.normal["-ls"]),
chown: () => new RateLimit(config.user.normal.chown),
hi: () => new RateLimit(config.user.normal.hi),
bye: () => new RateLimit(config.user.normal.bye),
devices: () => new RateLimit(config.user.normal.devices),
"admin message": () => new RateLimit(config.user.normal["admin message"])
},
chains: {
userset: () =>
new RateLimitChain(
config.user.chains.userset.interval,
config.user.chains.userset.num
),
chset: () =>
new RateLimitChain(
config.user.chains.chset.interval,
config.user.chains.userset.num
),
n: () =>
new RateLimitChain(
config.user.chains.n.interval,
config.user.chains.userset.num
)
}
};