Add internal banning (cvmban) using MySQL
This commit is contained in:
@@ -52,18 +52,35 @@ vncPort = 5900
|
|||||||
# rebootCmd = ""
|
# rebootCmd = ""
|
||||||
# restoreCmd = ""
|
# restoreCmd = ""
|
||||||
|
|
||||||
|
[mysql]
|
||||||
|
# Configures the MySQL database. This is ONLY required if you use the internal cvmban banning system (configured below)
|
||||||
|
enabled = false
|
||||||
|
host = "127.0.0.1"
|
||||||
|
username = "root"
|
||||||
|
password = "hunter2"
|
||||||
|
database = "cvmts"
|
||||||
|
|
||||||
|
# This section configures banning users. Note that if you leave this default, banning will NOT function and will be as effective as a kick.
|
||||||
|
[bans]
|
||||||
|
# If defined, a command that is run to ban a user from the VM.
|
||||||
|
# Use $IP to specify an ip and (optionally) use $NAME to specify a username
|
||||||
|
# bancmd = ""
|
||||||
|
# If true, enables the internal banning of users using the above MySQL database
|
||||||
|
cvmban = false
|
||||||
|
|
||||||
[collabvm]
|
[collabvm]
|
||||||
node = "acoolvm"
|
node = "acoolvm"
|
||||||
displayname = "A <b>Really</b> Cool CollabVM Instance"
|
displayname = "A <b>Really</b> Cool CollabVM Instance"
|
||||||
motd = "welcome!"
|
motd = "welcome!"
|
||||||
# Maximum amount of active connections allowed from the same IP.
|
# Maximum amount of active connections allowed from the same IP.
|
||||||
maxConnections = 3
|
maxConnections = 3
|
||||||
# Command used to ban an IP.
|
# Moderator rank enabled
|
||||||
# Use $IP to specify an ip and (optionally) use $NAME to specify a username
|
|
||||||
bancmd = "iptables -A INPUT -s $IP -j REJECT"
|
|
||||||
moderatorEnabled = true
|
moderatorEnabled = true
|
||||||
|
# List of disallowed usernames
|
||||||
usernameblacklist = []
|
usernameblacklist = []
|
||||||
|
# Maximum length of a chat message
|
||||||
maxChatLength = 100
|
maxChatLength = 100
|
||||||
|
# Maximum messages in the chat history buffer before old messages are overwritten
|
||||||
maxChatHistoryLength = 10
|
maxChatHistoryLength = 10
|
||||||
# Limit the amount of users allowed in the turn queue at the same time from the same IP
|
# Limit the amount of users allowed in the turn queue at the same time from the same IP
|
||||||
turnlimit = {enabled = true, maximum = 1}
|
turnlimit = {enabled = true, maximum = 1}
|
||||||
|
|||||||
@@ -16,8 +16,10 @@
|
|||||||
"@cvmts/cvm-rs": "*",
|
"@cvmts/cvm-rs": "*",
|
||||||
"@maxmind/geoip2-node": "^5.0.0",
|
"@maxmind/geoip2-node": "^5.0.0",
|
||||||
"execa": "^8.0.1",
|
"execa": "^8.0.1",
|
||||||
|
"ip-address": "^9.0.5",
|
||||||
"mnemonist": "^0.39.5",
|
"mnemonist": "^0.39.5",
|
||||||
"msgpackr": "^1.10.2",
|
"msgpackr": "^1.10.2",
|
||||||
|
"mysql2": "^3.11.0",
|
||||||
"pino": "^9.3.1",
|
"pino": "^9.3.1",
|
||||||
"sharp": "^0.33.3",
|
"sharp": "^0.33.3",
|
||||||
"toml": "^3.0.0",
|
"toml": "^3.0.0",
|
||||||
|
|||||||
81
cvmts/src/BanManager.ts
Normal file
81
cvmts/src/BanManager.ts
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import { ExecaSyncError, execa, execaCommand } from "execa";
|
||||||
|
import { BanConfig } from "./IConfig";
|
||||||
|
import pino from "pino";
|
||||||
|
import { Database } from "./Database";
|
||||||
|
import { Address6 } from "ip-address";
|
||||||
|
import { isIP } from "net";
|
||||||
|
|
||||||
|
export class BanManager {
|
||||||
|
private cfg: BanConfig;
|
||||||
|
private logger: pino.Logger;
|
||||||
|
private db: Database | undefined;
|
||||||
|
|
||||||
|
constructor(config: BanConfig, db: Database | undefined) {
|
||||||
|
this.cfg = config;
|
||||||
|
this.logger = pino({
|
||||||
|
name: "CVMTS.BanManager"
|
||||||
|
});
|
||||||
|
this.db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
private formatIP(ip: string) {
|
||||||
|
switch (isIP(ip)) {
|
||||||
|
case 4:
|
||||||
|
// If IPv4, just return as-is
|
||||||
|
return ip;
|
||||||
|
case 6: {
|
||||||
|
// If IPv6, return the /64 equivalent
|
||||||
|
let addr = new Address6(ip);
|
||||||
|
addr.subnetMask = 64;
|
||||||
|
return addr.startAddress().canonicalForm() + '/64';
|
||||||
|
}
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
// Invalid IP
|
||||||
|
throw new Error("Invalid IP address (what the hell did you even do???)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async BanUser(ip: string, username: string) {
|
||||||
|
ip = this.formatIP(ip);
|
||||||
|
// If cvmban enabled, write to DB
|
||||||
|
if (this.cfg.cvmban) {
|
||||||
|
if (!this.db) throw new Error("CVMBAN enabled but Database is undefined");
|
||||||
|
await this.db.banIP(ip, username);
|
||||||
|
}
|
||||||
|
// If ban command enabled, run it
|
||||||
|
try {
|
||||||
|
if (Array.isArray(this.cfg.bancmd)) {
|
||||||
|
let args: string[] = this.cfg.bancmd.map((a: string) => this.banCmdArgs(a, ip, username));
|
||||||
|
if (args.length || args[0].length) {
|
||||||
|
this.logger.info(`Running "${JSON.stringify(args)}"`);
|
||||||
|
await execa(args.shift()!, args, { stdout: process.stdout, stderr: process.stderr });
|
||||||
|
}
|
||||||
|
} else if (typeof this.cfg.bancmd == 'string') {
|
||||||
|
let cmd: string = this.banCmdArgs(this.cfg.bancmd, ip, username);
|
||||||
|
if (cmd.length) {
|
||||||
|
// Run through JSON.stringify for char escaping
|
||||||
|
this.logger.info(`Running ${JSON.stringify(cmd)}`);
|
||||||
|
await execaCommand(cmd, { stdout: process.stdout, stderr: process.stderr });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`Failed to ban ${ip} (${username}): ${(e as ExecaSyncError).shortMessage}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async isIPBanned(ip: string) {
|
||||||
|
ip = this.formatIP(ip);
|
||||||
|
if (!this.db) return false;
|
||||||
|
if (await this.db.isIPBanned(ip)) {
|
||||||
|
this.logger.info(`Banned IP ${ip} tried connecting.`);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private banCmdArgs(arg: string, ip: string, username: string): string {
|
||||||
|
return arg.replace(/\$IP/g, ip).replace(/\$NAME/g, username);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ import { CollabVMProtocolMessage, CollabVMProtocolMessageType } from '@cvmts/col
|
|||||||
|
|
||||||
import { Size, Rect } from './VMDisplay.js';
|
import { Size, Rect } from './VMDisplay.js';
|
||||||
import pino from 'pino';
|
import pino from 'pino';
|
||||||
|
import { BanManager } from './BanManager.js';
|
||||||
|
|
||||||
// Instead of strange hacks we can just use nodejs provided
|
// Instead of strange hacks we can just use nodejs provided
|
||||||
// import.meta properties, which have existed since LTS if not before
|
// import.meta properties, which have existed since LTS if not before
|
||||||
@@ -90,9 +91,12 @@ export default class CollabVMServer {
|
|||||||
// Geoip
|
// Geoip
|
||||||
private geoipReader: ReaderModel | null;
|
private geoipReader: ReaderModel | null;
|
||||||
|
|
||||||
|
// Ban manager
|
||||||
|
private banmgr: BanManager;
|
||||||
|
|
||||||
private logger = pino({ name: 'CVMTS.Server' });
|
private logger = pino({ name: 'CVMTS.Server' });
|
||||||
|
|
||||||
constructor(config: IConfig, vm: VM, auth: AuthManager | null, geoipReader: ReaderModel | null) {
|
constructor(config: IConfig, vm: VM, banmgr: BanManager, auth: AuthManager | null, geoipReader: ReaderModel | null) {
|
||||||
this.Config = config;
|
this.Config = config;
|
||||||
this.ChatHistory = new CircularBuffer<ChatHistory>(Array, this.Config.collabvm.maxChatHistoryLength);
|
this.ChatHistory = new CircularBuffer<ChatHistory>(Array, this.Config.collabvm.maxChatHistoryLength);
|
||||||
this.TurnQueue = new Queue<User>();
|
this.TurnQueue = new Queue<User>();
|
||||||
@@ -147,6 +151,8 @@ export default class CollabVMServer {
|
|||||||
this.auth = auth;
|
this.auth = auth;
|
||||||
|
|
||||||
this.geoipReader = geoipReader;
|
this.geoipReader = geoipReader;
|
||||||
|
|
||||||
|
this.banmgr = banmgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addUser(user: User) {
|
public addUser(user: User) {
|
||||||
@@ -530,7 +536,8 @@ export default class CollabVMServer {
|
|||||||
if (client.rank !== Rank.Admin && (client.rank !== Rank.Moderator || !this.Config.collabvm.moderatorPermissions.ban)) return;
|
if (client.rank !== Rank.Admin && (client.rank !== Rank.Moderator || !this.Config.collabvm.moderatorPermissions.ban)) return;
|
||||||
var user = this.clients.find((c) => c.username === msgArr[2]);
|
var user = this.clients.find((c) => c.username === msgArr[2]);
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
user.ban();
|
this.logger.info(`Banning ${user.username!} (${user.IP.address}) by request of ${client.username!}`);
|
||||||
|
user.ban(this.banmgr);
|
||||||
case '13':
|
case '13':
|
||||||
// Force Vote
|
// Force Vote
|
||||||
if (msgArr.length !== 3) return;
|
if (msgArr.length !== 3) return;
|
||||||
|
|||||||
44
cvmts/src/Database.ts
Normal file
44
cvmts/src/Database.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import pino, { Logger } from "pino";
|
||||||
|
import { MySQLConfig } from "./IConfig";
|
||||||
|
import * as mysql from 'mysql2/promise';
|
||||||
|
|
||||||
|
export class Database {
|
||||||
|
cfg: MySQLConfig;
|
||||||
|
logger: Logger;
|
||||||
|
db: mysql.Pool;
|
||||||
|
constructor(config: MySQLConfig) {
|
||||||
|
this.cfg = config;
|
||||||
|
this.logger = pino({
|
||||||
|
name: "CVMTS.Database"
|
||||||
|
});
|
||||||
|
this.db = mysql.createPool({
|
||||||
|
host: this.cfg.host,
|
||||||
|
user: this.cfg.username,
|
||||||
|
password: this.cfg.password,
|
||||||
|
database: this.cfg.database,
|
||||||
|
connectionLimit: 5,
|
||||||
|
multipleStatements: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
// Make sure tables exist
|
||||||
|
let conn = await this.db.getConnection();
|
||||||
|
await conn.execute("CREATE TABLE IF NOT EXISTS bans (ip VARCHAR(43) PRIMARY KEY NOT NULL, username VARCHAR(20) NOT NULL, reason TEXT DEFAULT NULL, timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP);");
|
||||||
|
conn.release();
|
||||||
|
this.logger.info("MySQL successfully initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
async banIP(ip: string, username: string, reason: string | null = null) {
|
||||||
|
let conn = await this.db.getConnection();
|
||||||
|
await conn.execute("INSERT INTO bans (ip, username, reason) VALUES (?, ?, ?);", [ip, username, reason]);
|
||||||
|
conn.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
async isIPBanned(ip: string): Promise<boolean> {
|
||||||
|
let conn = await this.db.getConnection();
|
||||||
|
let res = (await conn.query('SELECT COUNT(ip) AS cnt FROM bans WHERE ip = ?', [ip])) as mysql.RowDataPacket;
|
||||||
|
conn.release();
|
||||||
|
return res[0][0]['cnt'] !== 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,12 +40,13 @@ export default interface IConfig {
|
|||||||
snapshots: boolean;
|
snapshots: boolean;
|
||||||
};
|
};
|
||||||
vncvm: VNCVMDef;
|
vncvm: VNCVMDef;
|
||||||
|
mysql: MySQLConfig;
|
||||||
|
bans: BanConfig;
|
||||||
collabvm: {
|
collabvm: {
|
||||||
node: string;
|
node: string;
|
||||||
displayname: string;
|
displayname: string;
|
||||||
motd: string;
|
motd: string;
|
||||||
maxConnections: number;
|
maxConnections: number;
|
||||||
bancmd: string | string[];
|
|
||||||
moderatorEnabled: boolean;
|
moderatorEnabled: boolean;
|
||||||
usernameblacklist: string[];
|
usernameblacklist: string[];
|
||||||
maxChatLength: number;
|
maxChatLength: number;
|
||||||
@@ -71,6 +72,19 @@ export default interface IConfig {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MySQLConfig {
|
||||||
|
enabled: boolean;
|
||||||
|
host: string;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
database: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BanConfig {
|
||||||
|
bancmd: string | string[] | undefined;
|
||||||
|
cvmban: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Permissions {
|
export interface Permissions {
|
||||||
restore: boolean;
|
restore: boolean;
|
||||||
reboot: boolean;
|
reboot: boolean;
|
||||||
|
|||||||
@@ -6,23 +6,31 @@ import TCPClient from './TCPClient.js';
|
|||||||
import { IPDataManager } from '../IPData.js';
|
import { IPDataManager } from '../IPData.js';
|
||||||
import { User } from '../User.js';
|
import { User } from '../User.js';
|
||||||
import pino from 'pino';
|
import pino from 'pino';
|
||||||
|
import { BanManager } from '../BanManager.js';
|
||||||
|
|
||||||
export default class TCPServer extends EventEmitter implements NetworkServer {
|
export default class TCPServer extends EventEmitter implements NetworkServer {
|
||||||
listener: Server;
|
listener: Server;
|
||||||
Config: IConfig;
|
Config: IConfig;
|
||||||
logger = pino({name: 'CVMTS.TCPServer'});
|
logger = pino({name: 'CVMTS.TCPServer'});
|
||||||
clients: TCPClient[];
|
clients: TCPClient[];
|
||||||
|
private banmgr: BanManager;
|
||||||
|
|
||||||
constructor(config: IConfig) {
|
constructor(config: IConfig, banmgr: BanManager) {
|
||||||
super();
|
super();
|
||||||
this.Config = config;
|
this.Config = config;
|
||||||
this.listener = new Server();
|
this.listener = new Server();
|
||||||
this.clients = [];
|
this.clients = [];
|
||||||
this.listener.on('connection', (socket) => this.onConnection(socket));
|
this.listener.on('connection', (socket) => this.onConnection(socket));
|
||||||
|
this.banmgr = banmgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private onConnection(socket: Socket) {
|
private async onConnection(socket: Socket) {
|
||||||
this.logger.info(`New TCP connection from ${socket.remoteAddress}`);
|
this.logger.info(`New TCP connection from ${socket.remoteAddress}`);
|
||||||
|
if (await this.banmgr.isIPBanned(socket.remoteAddress!)) {
|
||||||
|
socket.write("6.banned;");
|
||||||
|
socket.destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
var client = new TCPClient(socket);
|
var client = new TCPClient(socket);
|
||||||
this.clients.push(client);
|
this.clients.push(client);
|
||||||
this.emit('connect', new User(client, IPDataManager.GetIPData(client.getIP()), this.Config));
|
this.emit('connect', new User(client, IPDataManager.GetIPData(client.getIP()), this.Config));
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { execa, execaCommand, ExecaSyncError } from 'execa';
|
|||||||
import NetworkClient from './NetworkClient.js';
|
import NetworkClient from './NetworkClient.js';
|
||||||
import { CollabVMCapabilities } from '@cvmts/collab-vm-1.2-binary-protocol';
|
import { CollabVMCapabilities } from '@cvmts/collab-vm-1.2-binary-protocol';
|
||||||
import pino from 'pino';
|
import pino from 'pino';
|
||||||
|
import { BanManager } from './BanManager.js';
|
||||||
|
|
||||||
export class User {
|
export class User {
|
||||||
socket: NetworkClient;
|
socket: NetworkClient;
|
||||||
@@ -133,35 +134,11 @@ export class User {
|
|||||||
this.sendMsg(cvm.guacEncode('chat', '', 'You are no longer muted.'));
|
this.sendMsg(cvm.guacEncode('chat', '', 'You are no longer muted.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private banCmdArgs(arg: string): string {
|
async ban(banmgr: BanManager) {
|
||||||
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
|
// Prevent the user from taking turns or chatting, in case the ban command takes a while
|
||||||
this.IP.muted = true;
|
this.IP.muted = true;
|
||||||
|
await banmgr.BanUser(this.IP.address, this.username || '');
|
||||||
try {
|
await this.kick();
|
||||||
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 {
|
|
||||||
this.logger.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 {
|
|
||||||
this.logger.error(`Failed to ban ${this.IP.address} (${this.username}): Empty command`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
this.logger.error(`Failed to ban ${this.IP.address} (${this.username}): ${(e as ExecaSyncError).shortMessage}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async kick() {
|
async kick() {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { IPDataManager } from '../IPData.js';
|
|||||||
import WSClient from './WSClient.js';
|
import WSClient from './WSClient.js';
|
||||||
import { User } from '../User.js';
|
import { User } from '../User.js';
|
||||||
import pino from 'pino';
|
import pino from 'pino';
|
||||||
|
import { BanManager } from '../BanManager.js';
|
||||||
|
|
||||||
export default class WSServer extends EventEmitter implements NetworkServer {
|
export default class WSServer extends EventEmitter implements NetworkServer {
|
||||||
private httpServer: http.Server;
|
private httpServer: http.Server;
|
||||||
@@ -16,8 +17,9 @@ export default class WSServer extends EventEmitter implements NetworkServer {
|
|||||||
private clients: WSClient[];
|
private clients: WSClient[];
|
||||||
private Config: IConfig;
|
private Config: IConfig;
|
||||||
private logger = pino({ name: 'CVMTS.WSServer' });
|
private logger = pino({ name: 'CVMTS.WSServer' });
|
||||||
|
private banmgr: BanManager;
|
||||||
|
|
||||||
constructor(config: IConfig) {
|
constructor(config: IConfig, banmgr: BanManager) {
|
||||||
super();
|
super();
|
||||||
this.Config = config;
|
this.Config = config;
|
||||||
this.clients = [];
|
this.clients = [];
|
||||||
@@ -29,6 +31,7 @@ export default class WSServer extends EventEmitter implements NetworkServer {
|
|||||||
res.write('This server only accepts WebSocket connections.');
|
res.write('This server only accepts WebSocket connections.');
|
||||||
res.end();
|
res.end();
|
||||||
});
|
});
|
||||||
|
this.banmgr = banmgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
start(): void {
|
start(): void {
|
||||||
@@ -41,7 +44,7 @@ export default class WSServer extends EventEmitter implements NetworkServer {
|
|||||||
this.httpServer.close();
|
this.httpServer.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private httpOnUpgrade(req: http.IncomingMessage, socket: internal.Duplex, head: Buffer) {
|
private async httpOnUpgrade(req: http.IncomingMessage, socket: internal.Duplex, head: Buffer) {
|
||||||
var killConnection = () => {
|
var killConnection = () => {
|
||||||
socket.write('HTTP/1.1 400 Bad Request\n\n400 Bad Request');
|
socket.write('HTTP/1.1 400 Bad Request\n\n400 Bad Request');
|
||||||
socket.destroy();
|
socket.destroy();
|
||||||
@@ -120,6 +123,12 @@ export default class WSServer extends EventEmitter implements NetworkServer {
|
|||||||
ip = req.socket.remoteAddress;
|
ip = req.socket.remoteAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (await this.banmgr.isIPBanned(ip)) {
|
||||||
|
socket.write("HTTP/1.1 403 Forbidden\n\nYou have been banned.");
|
||||||
|
socket.destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.wsServer.handleUpgrade(req, socket, head, (ws: WebSocket) => {
|
this.wsServer.handleUpgrade(req, socket, head, (ws: WebSocket) => {
|
||||||
this.wsServer.emit('connection', ws, req);
|
this.wsServer.emit('connection', ws, req);
|
||||||
this.onConnection(ws, req, ip);
|
this.onConnection(ws, req, ip);
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import VM from './VM.js';
|
|||||||
import VNCVM from './VNCVM/VNCVM.js';
|
import VNCVM from './VNCVM/VNCVM.js';
|
||||||
import GeoIPDownloader from './GeoIPDownloader.js';
|
import GeoIPDownloader from './GeoIPDownloader.js';
|
||||||
import pino from 'pino';
|
import pino from 'pino';
|
||||||
|
import { Database } from './Database.js';
|
||||||
|
import { BanManager } from './BanManager.js';
|
||||||
|
|
||||||
let logger = pino();
|
let logger = pino();
|
||||||
|
|
||||||
@@ -52,6 +54,20 @@ async function start() {
|
|||||||
}
|
}
|
||||||
// Init the auth manager if enabled
|
// Init the auth manager if enabled
|
||||||
let auth = Config.auth.enabled ? new AuthManager(Config.auth.apiEndpoint, Config.auth.secretKey) : null;
|
let auth = Config.auth.enabled ? new AuthManager(Config.auth.apiEndpoint, Config.auth.secretKey) : null;
|
||||||
|
// Database and ban manager
|
||||||
|
if (Config.bans.cvmban && !Config.mysql.enabled) {
|
||||||
|
logger.error("MySQL must be configured to use cvmban.");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
if (!Config.bans.cvmban && !Config.bans.bancmd) {
|
||||||
|
logger.warn("Neither cvmban nor ban command are configured. Bans will not function.");
|
||||||
|
}
|
||||||
|
let db = undefined;
|
||||||
|
if (Config.mysql.enabled) {
|
||||||
|
db = new Database(Config.mysql);
|
||||||
|
await db.init();
|
||||||
|
}
|
||||||
|
let banmgr = new BanManager(Config.bans, db);
|
||||||
switch (Config.vm.type) {
|
switch (Config.vm.type) {
|
||||||
case 'qemu': {
|
case 'qemu': {
|
||||||
// Fire up the VM
|
// Fire up the VM
|
||||||
@@ -79,14 +95,14 @@ async function start() {
|
|||||||
|
|
||||||
await VM.Start();
|
await VM.Start();
|
||||||
// Start up the server
|
// Start up the server
|
||||||
var CVM = new CollabVMServer(Config, VM, auth, geoipReader);
|
var CVM = new CollabVMServer(Config, VM, banmgr, auth, geoipReader);
|
||||||
|
|
||||||
var WS = new WSServer(Config);
|
var WS = new WSServer(Config, banmgr);
|
||||||
WS.on('connect', (client: User) => CVM.addUser(client));
|
WS.on('connect', (client: User) => CVM.addUser(client));
|
||||||
WS.start();
|
WS.start();
|
||||||
|
|
||||||
if (Config.tcp.enabled) {
|
if (Config.tcp.enabled) {
|
||||||
var TCP = new TCPServer(Config);
|
var TCP = new TCPServer(Config, banmgr);
|
||||||
TCP.on('connect', (client: User) => CVM.addUser(client));
|
TCP.on('connect', (client: User) => CVM.addUser(client));
|
||||||
TCP.start();
|
TCP.start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
"@parcel/packager-ts": "2.12.0",
|
"@parcel/packager-ts": "2.12.0",
|
||||||
"@parcel/transformer-sass": "2.12.0",
|
"@parcel/transformer-sass": "2.12.0",
|
||||||
"@parcel/transformer-typescript-types": "2.12.0",
|
"@parcel/transformer-typescript-types": "2.12.0",
|
||||||
|
"@types/jsbn": "^1.2.33",
|
||||||
"@types/node": "^20.14.10",
|
"@types/node": "^20.14.10",
|
||||||
"parcel": "^2.12.0",
|
"parcel": "^2.12.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
|
|||||||
Reference in New Issue
Block a user