Handle ban command arguments as array

This provides a much more reliable way to handle arguments with spaces,
such as usernames.

The ban process's stdout and stderr are now redirected to the server,
in case they have output that would be good in the server's logs.
This commit is contained in:
dakrk
2023-10-22 15:42:39 +01:00
parent 43fddbc521
commit 0b0c0a5ed6
3 changed files with 32 additions and 8 deletions

View File

@@ -20,7 +20,7 @@ export default interface IConfig {
node : string;
displayname : string;
motd : string;
bancmd : string;
bancmd : string | string[];
moderatorEnabled : boolean;
usernameblacklist : string[];
maxChatLength : number;

View File

@@ -4,7 +4,9 @@ import {WebSocket} from 'ws';
import {IPData} from './IPData.js';
import IConfig from './IConfig.js';
import RateLimiter from './RateLimiter.js';
import { execaCommand } from 'execa';
import { execa, execaCommand, ExecaSyncError } from 'execa';
import log from './log.js';
export class User {
socket : WebSocket;
nopSendInterval : NodeJS.Timeout;
@@ -100,13 +102,35 @@ export class User {
this.sendMsg(guacutils.encode("chat", "", "You are no longer muted."));
}
private banCmdArgs(arg: string) : string {
return arg.replace(/\$IP/g, this.IP.address).replace(/\$NAME/g, this.username || "");
}
async ban() {
// Prevent the user from taking turns or chatting, in case the ban command takes a while
this.IP.muted = true;
//@ts-ignore
var cmd = this.Config.collabvm.bancmd.replace(/\$IP/g, this.IP.address).replace(/\$NAME/g, this.username);
await execaCommand(cmd);
try {
if (Array.isArray(this.Config.collabvm.bancmd)) {
let args: string[] = this.Config.collabvm.bancmd.map((a: string) => this.banCmdArgs(a));
if (args.length || args[0].length) {
await execa(args.shift()!, args, {stdout: process.stdout, stderr: process.stderr});
this.kick();
} else {
log("ERROR", `Failed to ban ${this.IP.address} (${this.username}): Empty command`);
}
} else if (typeof this.Config.collabvm.bancmd == "string") {
let cmd: string = this.banCmdArgs(this.Config.collabvm.bancmd);
if (cmd.length) {
await execaCommand(cmd, {stdout: process.stdout, stderr: process.stderr});
this.kick();
} else {
log("ERROR", `Failed to ban ${this.IP.address} (${this.username}): Empty command`);
}
}
} catch (e) {
log("ERROR", `Failed to ban ${this.IP.address} (${this.username}): ${(e as ExecaSyncError).shortMessage}`);
}
}
async kick() {

View File

@@ -1,7 +1,7 @@
export default function log(loglevel : string, message : string) {
export default function log(loglevel : string, ...message : string[]) {
console[
(loglevel === "ERROR" || loglevel === "FATAL") ? "error" :
(loglevel === "WARN") ? "warn" :
"log"
](`[${new Date().toLocaleString()}] [${loglevel}] ${message}`);
](`[${new Date().toLocaleString()}] [${loglevel}]`, ...message);
}