Add kickban, improve command line

This commit is contained in:
Hri7566 2024-02-01 08:25:24 -05:00
parent 275ad3823f
commit 2f3311be1f
8 changed files with 153 additions and 13 deletions

View File

@ -11,6 +11,7 @@ crown:
normal:
a: 600
m: 50
ch: 1000
chains:
userset:
interval: 1800000,
@ -19,6 +20,7 @@ admin:
normal:
a: 120
m: 16.6666666667
ch: 100
chains:
userset:
interval: 1800000,

View File

@ -1,4 +1,4 @@
import EventEmitter from "events";
import EventEmitter, { on } from "events";
import { Logger } from "../util/Logger";
import {
ChannelSettingValue,
@ -15,12 +15,19 @@ import Crown from "./Crown";
import { ChannelList } from "./ChannelList";
import { config } from "./config";
interface CachedKickban {
userId: string;
startTime: number;
endTime: number;
}
export class Channel extends EventEmitter {
private settings: Partial<IChannelSettings> = config.defaultSettings;
private ppl = new Array<Participant>();
public logger: Logger;
public chatHistory = new Array<ClientEvents["a"]>();
public bans = new Array<CachedKickban>();
public crown?: Crown;
@ -233,7 +240,7 @@ export class Channel extends EventEmitter {
* @param socket Socket that is joining
* @returns undefined
*/
public join(socket: Socket) {
public join(socket: Socket): void {
//! /!\ Players are forced to join the same channel on two different tabs!
//? TODO Should this be a bug or a feature?
@ -243,6 +250,18 @@ export class Channel extends EventEmitter {
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) {
if (ch.getID() == config.fullChannel) {
return ch.join(socket);
}
}
}
// Is user in this channel?
if (this.hasUser(part._id)) {
// Alreay in channel, don't add to list, but tell them they're here
@ -370,10 +389,11 @@ export class Channel extends EventEmitter {
* Get this channel's information
* @returns Channel info object (includes ID, number of users, settings, and the crown)
*/
public getInfo() {
public getInfo(_id?: string) {
return {
_id: this.getID(),
id: this.getID(),
banned: _id ? this.isBanned(_id) : false,
count: this.ppl.length,
settings: this.settings,
crown: this.crown
@ -561,6 +581,57 @@ export class Channel extends EventEmitter {
this.emit("update", this);
}
}
/**
* Kickban a poor soul for t milliseconds.
* @param _id User ID to ban
* @param t Time in millseconds to ban for
**/
public kickban(_id: string, t: number = 1000 * 60 * 30) {
const now = Date.now();
if (!this.hasUser(_id)) return;
const part = this.ppl.find(p => p._id == _id);
if (!part) return;
this.bans.push({
userId: _id,
startTime: now,
endTime: now + t
});
const socket = findSocketByPartID(part.id);
if (!socket) return;
const banChannel = ChannelList.getList().find(
ch => ch.getID() == config.fullChannel
);
if (!banChannel) return;
banChannel.join(socket);
this.emit("update", this);
}
public isBanned(_id: string) {
const now = Date.now();
for (const ban of this.bans) {
if (ban.endTime <= now) {
// Remove old ban and skip
this.bans.splice(this.bans.indexOf(ban), 1);
continue;
}
// Check if they are banned
if (ban.userId == _id) {
return true;
}
}
return false;
}
}
export default Channel;

View File

@ -18,6 +18,14 @@ const onChannelUpdate = (channel: Channel) => {
return;
}
const part = channel.getParticipantList().find(p => p.id == partId);
if (part) {
info.banned = channel.isBanned(part._id);
} else {
info.banned = false;
}
socket.sendChannelList([info], false);
}
};

View File

@ -39,8 +39,7 @@ export function createColor(ip: string) {
createHash("sha256")
.update(ip)
.update(env.SALT)
.update("color")
.digest("hex")
.substring(0, 24 + 6)
.substring(24, 24 + 6)
);
}

View File

@ -1,16 +1,33 @@
import { ChannelList } from "../../channel/ChannelList";
import { deleteUser } from "../../data/user";
import Command from "./Command";
Command.addCommand(
new Command(["help", "h", "commands", "cmds"], "help", msg => {
return (
"Commands: " +
Command.commands.map(cmd => cmd.aliases[0]).join(" | ")
);
if (!msg.args[1]) {
return (
"Commands: " +
Command.commands.map(cmd => cmd.aliases[0]).join(" | ")
);
} else {
let foundCommand: Command | undefined;
for (const command of Command.commands) {
for (const alias of command.aliases) {
if (msg.args[1] == alias) {
foundCommand = command;
}
}
}
if (!foundCommand) return `No such command "${msg.args[1]}"`;
return "Usage: " + foundCommand.usage;
}
})
);
Command.addCommand(
new Command(["memory", "mem"], "mem", msg => {
new Command(["memory", "mem"], "memory", msg => {
const mem = process.memoryUsage();
return `Memory: ${(mem.heapUsed / 1000 / 1000).toFixed(2)} MB used / ${(
mem.heapTotal /
@ -25,3 +42,20 @@ Command.addCommand(
process.exit();
})
);
Command.addCommand(
new Command(["userdel", "deluser"], "userdel <id>", async msg => {
await deleteUser(msg.args[1]);
})
);
Command.addCommand(
new Command(["list", "ls"], "list", async msg => {
return (
"Channels:\n- " +
ChannelList.getList()
.map(ch => ch.getID())
.join("\n- ")
);
})
);

View File

@ -55,7 +55,10 @@ export class Socket extends EventEmitter {
public currentChannelID: string | undefined;
private cursorPos: Vector2<CursorValue> = { x: 200, y: 100 };
constructor(private ws: ServerWebSocket<unknown>, public socketID: string) {
constructor(
private ws: ServerWebSocket<unknown>,
public socketID: string
) {
super();
this.ip = ws.remoteAddress; // Participant ID
@ -406,7 +409,7 @@ export class Socket extends EventEmitter {
public subscribeToChannelList() {
ChannelList.subscribe(this.id);
const firstList = ChannelList.getPublicList().map(v => v.getInfo());
const firstList = ChannelList.getPublicList().map(v => v.getInfo(this._id));
this.sendChannelList(firstList);
}
@ -445,6 +448,16 @@ export class Socket extends EventEmitter {
return true;
}
public kickban(_id: string, ms: number) {
const channel = this.getCurrentChannel();
if (!channel) return;
if (this.isOwner()) {
channel.kickban(_id, ms);
}
}
}
export const socketsBySocketID = new Map<string, Socket>();

View File

@ -0,0 +1,11 @@
import { ServerEventListener } from "../../../../util/types";
export const kickban: ServerEventListener<"kickban"> = {
id: "kickban",
callback: (msg, socket) => {
// Kickban asshole from channel
if (!msg._id) return;
if (!msg.ms) return;
socket.kickban(msg._id, msg.ms);
}
};

View File

@ -13,6 +13,7 @@ import { plus_ls } from "./handlers/+ls";
import { minus_ls } from "./handlers/-ls";
import { admin_message } from "./handlers/admin_message";
import { chset } from "./handlers/chset";
import { kickban } from "./handlers/kickban";
// Imagine not having an "addMany" function...
@ -40,7 +41,8 @@ EVENTGROUP_USER.addMany(
plus_ls,
minus_ls,
admin_message,
chset
chset,
kickban
);
eventGroups.push(EVENTGROUP_USER);