typescriptify it all
This commit is contained in:
parent
c0e1f9c830
commit
8d5aaf4eeb
6 changed files with 261 additions and 100 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -2,3 +2,5 @@ node_modules/
|
||||||
package-lock.json
|
package-lock.json
|
||||||
yarn.lock
|
yarn.lock
|
||||||
config.js
|
config.js
|
||||||
|
config.json
|
||||||
|
dist/
|
|
@ -11,9 +11,14 @@
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
|
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"format": "prettier *.js -w"
|
"format": "prettier src/*.ts -w",
|
||||||
|
"build": "tsc",
|
||||||
|
"serve": "node dist/index.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"prettier": "^3.3.2"
|
"@types/node": "^20.14.8",
|
||||||
|
"@types/ws": "^8.5.10",
|
||||||
|
"prettier": "^3.3.2",
|
||||||
|
"typescript": "^5.5.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
import * as ws from "ws";
|
import * as ws from "ws";
|
||||||
|
|
||||||
const guacutils = {
|
const guacutils = {
|
||||||
parse: (string) => {
|
parse: (string: string) => {
|
||||||
let pos = -1;
|
let pos = -1;
|
||||||
let sections = [];
|
let sections: string[] = [];
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
let len = string.indexOf(".", pos + 1);
|
let len = string.indexOf(".", pos + 1);
|
||||||
|
@ -29,7 +29,7 @@ const guacutils = {
|
||||||
return sections;
|
return sections;
|
||||||
},
|
},
|
||||||
|
|
||||||
encode: (cypher) => {
|
encode: (cypher: string[]) => {
|
||||||
let command = "";
|
let command = "";
|
||||||
|
|
||||||
for (var i = 0; i < cypher.length; i++) {
|
for (var i = 0; i < cypher.length; i++) {
|
||||||
|
@ -41,22 +41,22 @@ const guacutils = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const ConnectionState = Object.freeze({
|
enum ConnectionState {
|
||||||
CLOSED: 0,
|
CLOSED = 0,
|
||||||
CONNECTING: 1,
|
CONNECTING = 1,
|
||||||
CONNECTED: 2,
|
CONNECTED = 2,
|
||||||
});
|
}
|
||||||
|
|
||||||
// System chat messages have a nil username.
|
// System chat messages have a nil username.
|
||||||
function IsSystemChatInstruction(inst) {
|
function IsSystemChatInstruction(inst: string[]) {
|
||||||
return inst[1] == "";
|
return inst[1] == "";
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserData {
|
class UserData {
|
||||||
#_name;
|
private _name: string;
|
||||||
#_rank;
|
private _rank: number;
|
||||||
|
|
||||||
constructor(name, rank) {
|
constructor(name: string, rank: number) {
|
||||||
this._name = name;
|
this._name = name;
|
||||||
this._rank = rank;
|
this._rank = rank;
|
||||||
}
|
}
|
||||||
|
@ -68,12 +68,25 @@ class UserData {
|
||||||
return this._rank;
|
return this._rank;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateRank(new_rank) {
|
UpdateRank(new_rank: number) {
|
||||||
this._rank = new_rank;
|
this._rank = new_rank;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class CollabVMClient {
|
export default abstract class CollabVMClient {
|
||||||
|
abstract OnOpen(): void;
|
||||||
|
abstract OnClose(): void;
|
||||||
|
abstract OnChat(username: string, message: string): void;
|
||||||
|
abstract OnGuacamoleMessage(msg: string[]): void;
|
||||||
|
abstract OnAddUser_Bot(count: number): void;
|
||||||
|
abstract OnRemUser_Bot(count: number): void;
|
||||||
|
|
||||||
|
private _state: ConnectionState;
|
||||||
|
private _users: UserData[];
|
||||||
|
private _ws: ws.WebSocket | undefined;
|
||||||
|
private _username: string | undefined;
|
||||||
|
private _vm: string | undefined;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this._state = ConnectionState.CLOSED;
|
this._state = ConnectionState.CLOSED;
|
||||||
this._users = [];
|
this._users = [];
|
||||||
|
@ -83,14 +96,16 @@ export default class CollabVMClient {
|
||||||
return this._state;
|
return this._state;
|
||||||
}
|
}
|
||||||
|
|
||||||
Connect(uri) {
|
Connect(uri: string) {
|
||||||
this._ws = new ws.WebSocket(uri, "guacamole", {
|
this._ws = new ws.WebSocket(uri, "guacamole", {
|
||||||
origin: "https://computernewb.com",
|
origin: "https://computernewb.com",
|
||||||
});
|
});
|
||||||
this._ws.onopen = this.OnWebSocketOpen.bind(this);
|
this._ws.on("open", () => this.OnWebSocketOpen());
|
||||||
this._ws.onclose = this.OnWebSocketClose.bind(this);
|
this._ws.on("close", () => this.OnWebSocketClose());
|
||||||
this._ws.onerror = this.OnWebSocketError.bind(this);
|
this._ws.on("error", () => this.OnWebSocketError());
|
||||||
this._ws.onmessage = this.OnWebSocketMessage.bind(this);
|
this._ws.on("message", (msg, isBinary) =>
|
||||||
|
this.OnWebSocketMessage(msg, isBinary),
|
||||||
|
);
|
||||||
this._state = ConnectionState.CONNECTING;
|
this._state = ConnectionState.CONNECTING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,25 +116,25 @@ export default class CollabVMClient {
|
||||||
|
|
||||||
OnWebSocketClose() {
|
OnWebSocketClose() {
|
||||||
this._state = ConnectionState.CLOSED;
|
this._state = ConnectionState.CLOSED;
|
||||||
this.OnClose(arguments);
|
this.OnClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
OnWebSocketError() {
|
OnWebSocketError() {
|
||||||
// fire the close handler
|
// fire the close handler
|
||||||
this._state = ConnectionState.CLOSED;
|
this._state = ConnectionState.CLOSED;
|
||||||
this.OnClose(arguments);
|
this.OnClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
Close() {
|
Close() {
|
||||||
this._state = ConnectionState.CLOSED;
|
this._state = ConnectionState.CLOSED;
|
||||||
this._ws.close();
|
this._ws?.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
OnWebSocketMessage(ev) {
|
OnWebSocketMessage(msg: Buffer | ArrayBuffer | Buffer[], isBinary: boolean) {
|
||||||
// cvm server should never send binary data
|
// cvm server should never send binary data
|
||||||
if (typeof ev.data !== "string") return;
|
if (isBinary) return;
|
||||||
|
|
||||||
let message = guacutils.parse(ev.data);
|
let message = guacutils.parse(msg.toString("utf-8"));
|
||||||
if (message.length === 0) return;
|
if (message.length === 0) return;
|
||||||
|
|
||||||
// Hardcoded, we need to keep this to be alive
|
// Hardcoded, we need to keep this to be alive
|
||||||
|
@ -165,11 +180,11 @@ export default class CollabVMClient {
|
||||||
this.OnGuacamoleMessage(message);
|
this.OnGuacamoleMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
OnAddUser(users, count) {
|
OnAddUser(users: string[], count: number) {
|
||||||
//console.log(users);
|
//console.log(users);
|
||||||
for (var i = 0; i < count * 2; i += 2) {
|
for (var i = 0; i < count * 2; i += 2) {
|
||||||
let name = users[i];
|
let name = users[i];
|
||||||
let rank = users[i + 1];
|
let rank = parseInt(users[i + 1]);
|
||||||
|
|
||||||
//console.log(`[${this.GetVM()}] user ${name} rank ${rank}`)
|
//console.log(`[${this.GetVM()}] user ${name} rank ${rank}`)
|
||||||
|
|
||||||
|
@ -188,7 +203,7 @@ export default class CollabVMClient {
|
||||||
this.OnAddUser_Bot(this.GetUserCount());
|
this.OnAddUser_Bot(this.GetUserCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
OnRemUser(users, count) {
|
OnRemUser(users: string[], count: number) {
|
||||||
for (var i = 0; i < count; i++) {
|
for (var i = 0; i < count; i++) {
|
||||||
let saveUserTemp = this.GetUser(users[i]);
|
let saveUserTemp = this.GetUser(users[i]);
|
||||||
this._users = this._users.filter((user) => user.GetName() != users[i]);
|
this._users = this._users.filter((user) => user.GetName() != users[i]);
|
||||||
|
@ -212,7 +227,7 @@ export default class CollabVMClient {
|
||||||
// subtract known bots
|
// subtract known bots
|
||||||
for (var i = len - 1; i != 0; --i) {
|
for (var i = len - 1; i != 0; --i) {
|
||||||
// ?
|
// ?
|
||||||
if (this._users[i] === undefined) return;
|
if (this._users[i] === undefined) break;
|
||||||
|
|
||||||
var name = this._users[i].GetName();
|
var name = this._users[i].GetName();
|
||||||
if (KnownBots.find((elem) => name == elem) !== undefined) {
|
if (KnownBots.find((elem) => name == elem) !== undefined) {
|
||||||
|
@ -232,7 +247,7 @@ export default class CollabVMClient {
|
||||||
this._users;
|
this._users;
|
||||||
}
|
}
|
||||||
|
|
||||||
GetUser(username) {
|
GetUser(username: string) {
|
||||||
let existingUser = this._users.find((elem) => elem.GetName() == username);
|
let existingUser = this._users.find((elem) => elem.GetName() == username);
|
||||||
|
|
||||||
// Apparently this can fail somehow..?
|
// Apparently this can fail somehow..?
|
||||||
|
@ -245,7 +260,7 @@ export default class CollabVMClient {
|
||||||
return this._username;
|
return this._username;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rename(name) {
|
Rename(name: string) {
|
||||||
this._username = name;
|
this._username = name;
|
||||||
this.SendGuacamoleMessage("rename", name);
|
this.SendGuacamoleMessage("rename", name);
|
||||||
}
|
}
|
||||||
|
@ -254,14 +269,14 @@ export default class CollabVMClient {
|
||||||
return this._vm;
|
return this._vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectToVM(vm) {
|
ConnectToVM(vm: string) {
|
||||||
this._vm = vm;
|
this._vm = vm;
|
||||||
this.SendGuacamoleMessage("connect", vm);
|
this.SendGuacamoleMessage("connect", vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
SendGuacamoleMessage() {
|
SendGuacamoleMessage(...args: string[]) {
|
||||||
if (this._state !== ConnectionState.CONNECTED) return;
|
if (this._state !== ConnectionState.CONNECTED) return;
|
||||||
|
|
||||||
this._ws.send(guacutils.encode(Array.prototype.slice.call(arguments)));
|
this._ws?.send(guacutils.encode(args));
|
||||||
}
|
}
|
||||||
}
|
}
|
14
src/config.ts
Normal file
14
src/config.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
export default interface Config {
|
||||||
|
BANNED_ISO: RegExp[];
|
||||||
|
ISO_DIRECTORIES: { [key: string]: string };
|
||||||
|
INSTALLBOT_VMS: {
|
||||||
|
uri: string;
|
||||||
|
id: string;
|
||||||
|
usesIde2: boolean;
|
||||||
|
hasFloppy: boolean;
|
||||||
|
}[];
|
||||||
|
BOT_PREFIX: string;
|
||||||
|
ADMIN_TOKEN: string;
|
||||||
|
kGeneralLimitBaseSeconds: number;
|
||||||
|
kRebootLimitBaseSeconds: number;
|
||||||
|
}
|
|
@ -1,28 +1,39 @@
|
||||||
|
import { readFileSync } from "fs";
|
||||||
import CollabVMClient from "./client.js";
|
import CollabVMClient from "./client.js";
|
||||||
import {
|
import Config from "./config.js";
|
||||||
BANNED_ISO,
|
|
||||||
ISO_DIRECTORIES,
|
|
||||||
INSTALLBOT_VMS,
|
|
||||||
BOT_PREFIX,
|
|
||||||
ADMIN_TOKEN,
|
|
||||||
kGeneralLimitBaseSeconds,
|
|
||||||
kRebootLimitBaseSeconds,
|
|
||||||
} from "./config.js";
|
|
||||||
|
|
||||||
function Log() {
|
let config: Config = JSON.parse(readFileSync("config.json", "utf-8"));
|
||||||
|
|
||||||
|
function Log(...args: string[]) {
|
||||||
// console.log(`[AnyOSBot] [${new Date()}]`, [...arguments].join(' '))
|
// console.log(`[AnyOSBot] [${new Date()}]`, [...arguments].join(' '))
|
||||||
console.log("[AnyOSBot]", [...arguments].join(" "));
|
console.log("[AnyOSBot]", args.join(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HelpCommand {
|
||||||
|
command: string;
|
||||||
|
help: string;
|
||||||
|
usesFloppy?: boolean | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// you people SUCK man (dynamic edition, with less bugs!)
|
// you people SUCK man (dynamic edition, with less bugs!)
|
||||||
// and it actually probably works without hanging or negative seconds this time.
|
// and it actually probably works without hanging or negative seconds this time.
|
||||||
class RateLimit {
|
class RateLimit {
|
||||||
constructor(time, factor, ident) {
|
private _ident: string;
|
||||||
|
private _timeBase: number;
|
||||||
|
private _factor: number;
|
||||||
|
private _msUntil: number;
|
||||||
|
private _n: number;
|
||||||
|
private _limited: boolean;
|
||||||
|
private _siHandle: NodeJS.Timeout | null;
|
||||||
|
|
||||||
|
constructor(time: number, factor: number, ident: string) {
|
||||||
this._ident = ident;
|
this._ident = ident;
|
||||||
this._timeBase = time;
|
this._timeBase = time;
|
||||||
this._msUntil = 0;
|
this._msUntil = 0;
|
||||||
this._n = 1;
|
this._n = 1;
|
||||||
this._factor = factor;
|
this._factor = factor;
|
||||||
|
this._limited = false;
|
||||||
|
this._siHandle = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
GetTime() {
|
GetTime() {
|
||||||
|
@ -46,7 +57,7 @@ class RateLimit {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetUserCount(count) {
|
SetUserCount(count: number) {
|
||||||
if (count == 0) count = 1;
|
if (count == 0) count = 1;
|
||||||
this._n = count;
|
this._n = count;
|
||||||
|
|
||||||
|
@ -57,19 +68,18 @@ class RateLimit {
|
||||||
// TODO: this might work for the dyna ratelimit?
|
// TODO: this might work for the dyna ratelimit?
|
||||||
if (this._limited) return;
|
if (this._limited) return;
|
||||||
|
|
||||||
let self = this;
|
this._msUntil = this.GetMs();
|
||||||
self._msUntil = this.GetMs();
|
|
||||||
Log(
|
Log(
|
||||||
`Ratelimit \"${this._ident}\" started, will be done in ${self._msUntil} ms (${self._msUntil / 1000} seconds)`,
|
`Ratelimit \"${this._ident}\" started, will be done in ${this._msUntil} ms (${this._msUntil / 1000} seconds)`,
|
||||||
);
|
);
|
||||||
self._limited = true;
|
this._limited = true;
|
||||||
|
|
||||||
this._siHandle = setInterval(() => {
|
this._siHandle = setInterval(() => {
|
||||||
self._msUntil -= 1000;
|
this._msUntil -= 1000;
|
||||||
if (self._msUntil <= 0) {
|
if (this._msUntil <= 0) {
|
||||||
Log(`Ratelimit \"${self._ident}\" is done.`);
|
Log(`Ratelimit \"${this._ident}\" is done.`);
|
||||||
clearInterval(self._siHandle);
|
if (this._siHandle !== null) clearInterval(this._siHandle);
|
||||||
self._limited = false;
|
this._limited = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
@ -86,7 +96,14 @@ class RateLimit {
|
||||||
}
|
}
|
||||||
|
|
||||||
class HelperBot extends CollabVMClient {
|
class HelperBot extends CollabVMClient {
|
||||||
constructor(wsUri, vmId, ide2, floppy) {
|
private _wsUri: string;
|
||||||
|
private _vmId: string;
|
||||||
|
private _ide2: boolean;
|
||||||
|
private _hasFloppy: boolean;
|
||||||
|
private GeneralCmdLimit: RateLimit | undefined;
|
||||||
|
private RebootLimit: RateLimit | undefined;
|
||||||
|
|
||||||
|
constructor(wsUri: string, vmId: string, ide2: boolean, floppy: boolean) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this._wsUri = wsUri;
|
this._wsUri = wsUri;
|
||||||
|
@ -109,17 +126,17 @@ class HelperBot extends CollabVMClient {
|
||||||
this.ConnectToVM(this._vmId);
|
this.ConnectToVM(this._vmId);
|
||||||
}
|
}
|
||||||
|
|
||||||
OnClose(ev) {
|
OnClose() {
|
||||||
//console.log(arguments)
|
//console.log(arguments)
|
||||||
// reconnect lol
|
// reconnect lol
|
||||||
|
|
||||||
/* the right way doesnt work thanks to something
|
/* the right way doesnt work thanks to something
|
||||||
Log(`[${this._vmId}]`, `Connection closed, reconnecting in 5 seconds`);
|
Log(`[${this._vmId}]`, `Connection closed, reconnecting in 5 seconds`);
|
||||||
|
|
||||||
let self = this;
|
let this = this;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
Log(`[${this._vmId}]`, `Reconnecting now`);
|
Log(`[${this._vmId}]`, `Reconnecting now`);
|
||||||
self.DoConn();
|
this.DoConn();
|
||||||
}, 1000 * 5)
|
}, 1000 * 5)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -129,21 +146,21 @@ class HelperBot extends CollabVMClient {
|
||||||
// The bot should probably give up after some attempts
|
// The bot should probably give up after some attempts
|
||||||
}
|
}
|
||||||
|
|
||||||
Chat(message) {
|
Chat(message: string) {
|
||||||
this.SendGuacamoleMessage("chat", message);
|
this.SendGuacamoleMessage("chat", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
OnAddUser_Bot(count) {
|
OnAddUser_Bot(count: number) {
|
||||||
this.GeneralCmdLimit.SetUserCount(count);
|
this.GeneralCmdLimit!.SetUserCount(count);
|
||||||
this.RebootLimit.SetUserCount(count);
|
this.RebootLimit!.SetUserCount(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
OnRemUser_Bot(count) {
|
OnRemUser_Bot(count: number) {
|
||||||
this.GeneralCmdLimit.SetUserCount(count);
|
this.GeneralCmdLimit!.SetUserCount(count);
|
||||||
this.RebootLimit.SetUserCount(count);
|
this.RebootLimit!.SetUserCount(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
UserCanBypass(username) {
|
UserCanBypass(username: string) {
|
||||||
let existingUser = this.GetUser(username);
|
let existingUser = this.GetUser(username);
|
||||||
|
|
||||||
// Apparently this can fail somehow..?
|
// Apparently this can fail somehow..?
|
||||||
|
@ -153,12 +170,12 @@ class HelperBot extends CollabVMClient {
|
||||||
return rank == 2 || rank == 3;
|
return rank == 2 || rank == 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
SendMonitorCommand(cmd) {
|
SendMonitorCommand(cmd: string) {
|
||||||
this.SendGuacamoleMessage("admin", "5", this.GetVM(), cmd);
|
this.SendGuacamoleMessage("admin", "5", this.GetVM()!, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConcatPath(isodir, otherPath) {
|
ConcatPath(isodir: string, otherPath: string) {
|
||||||
let isopath = ISO_DIRECTORIES[isodir];
|
let isopath = config.ISO_DIRECTORIES[isodir];
|
||||||
if (isopath === undefined) {
|
if (isopath === undefined) {
|
||||||
// imo crashing and being restarted by systemd is better than not knowing why shit was coming out as undefined
|
// imo crashing and being restarted by systemd is better than not knowing why shit was coming out as undefined
|
||||||
// gotta love javascript
|
// gotta love javascript
|
||||||
|
@ -169,11 +186,11 @@ class HelperBot extends CollabVMClient {
|
||||||
|
|
||||||
// QEMU Abstractions
|
// QEMU Abstractions
|
||||||
|
|
||||||
QemuEjectDevice(devname) {
|
QemuEjectDevice(devname: string) {
|
||||||
this.SendMonitorCommand(`eject ${devname}`);
|
this.SendMonitorCommand(`eject ${devname}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
QemuChangeDevice(devname, source, opts) {
|
QemuChangeDevice(devname: string, source: string, opts: string) {
|
||||||
this.SendMonitorCommand(`change ${devname} "${source}" ${opts}`);
|
this.SendMonitorCommand(`change ${devname} "${source}" ${opts}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,27 +203,27 @@ class HelperBot extends CollabVMClient {
|
||||||
if (this._hasFloppy) this.QemuEjectDevice("vm.floppy");
|
if (this._hasFloppy) this.QemuEjectDevice("vm.floppy");
|
||||||
}
|
}
|
||||||
|
|
||||||
QemuChangeCd(source, opts) {
|
QemuChangeCd(source: string, opts: string) {
|
||||||
if (this._ide2) this.QemuChangeDevice("ide2-cd0", source, opts);
|
if (this._ide2) this.QemuChangeDevice("ide2-cd0", source, opts);
|
||||||
else this.QemuChangeDevice("vm.cd", source, opts);
|
else this.QemuChangeDevice("vm.cd", source, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
QemuChangeFloppy(source) {
|
QemuChangeFloppy(source: string) {
|
||||||
if (this._hasFloppy)
|
if (this._hasFloppy)
|
||||||
this.QemuChangeDevice("vm.floppy", source, "raw read-only");
|
this.QemuChangeDevice("vm.floppy", source, "raw read-only");
|
||||||
}
|
}
|
||||||
|
|
||||||
OnChat(username, message) {
|
OnChat(username: string, message: string) {
|
||||||
//console.log(`${username}> ${message}`);
|
//console.log(`${username}> ${message}`);
|
||||||
|
|
||||||
if (username == this.GetUsername()) return;
|
if (username == this.GetUsername()) return;
|
||||||
|
|
||||||
if (message[0] === BOT_PREFIX) {
|
if (message[0] === config.BOT_PREFIX) {
|
||||||
this.HandleCommands(username, message);
|
this.HandleCommands(username, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleCommands(username, message) {
|
HandleCommands(username: string, message: string) {
|
||||||
{
|
{
|
||||||
let user = this.GetUser(username);
|
let user = this.GetUser(username);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
|
@ -224,7 +241,7 @@ class HelperBot extends CollabVMClient {
|
||||||
|
|
||||||
// Little code fragment to make rate limiting
|
// Little code fragment to make rate limiting
|
||||||
// more portable.
|
// more portable.
|
||||||
const DoLimit = (limit) => {
|
const DoLimit = (limit: RateLimit) => {
|
||||||
//console.log(`[AnyOSBot] [${this._vmId}] ${this.GetUserCount()} users online (${this.GetUserCountFull()} actual)`)
|
//console.log(`[AnyOSBot] [${this._vmId}] ${this.GetUserCount()} users online (${this.GetUserCountFull()} actual)`)
|
||||||
|
|
||||||
//if(this._vmId !== 'vm0b0t') {
|
//if(this._vmId !== 'vm0b0t') {
|
||||||
|
@ -249,18 +266,18 @@ class HelperBot extends CollabVMClient {
|
||||||
};
|
};
|
||||||
|
|
||||||
// generate a help HTML string for the help
|
// generate a help HTML string for the help
|
||||||
const generateHelp = (arr) => {
|
const generateHelp = (arr: HelpCommand[]) => {
|
||||||
let str = "<h4>AnyOSInstallBot Help:</h4><ul>";
|
let str = "<h4>AnyOSInstallBot Help:</h4><ul>";
|
||||||
for (var cmd of arr) {
|
for (var cmd of arr) {
|
||||||
// remove commands which depend on the floppy on a VM without floppy
|
// remove commands which depend on the floppy on a VM without floppy
|
||||||
if (cmd.usesFloppy && !this._hasFloppy) continue;
|
if (cmd.usesFloppy && !this._hasFloppy) continue;
|
||||||
str += `<li><b>${BOT_PREFIX}${cmd.command}</b> - ${cmd.help}</li>`;
|
str += `<li><b>${config.BOT_PREFIX}${cmd.command}</b> - ${cmd.help}</li>`;
|
||||||
}
|
}
|
||||||
str += "</ul>";
|
str += "</ul>";
|
||||||
return str;
|
return str;
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateList = (title, arr) => {
|
const generateList = (title: string, arr: string[]) => {
|
||||||
let str = `<h4>${title}</h4><ul>`;
|
let str = `<h4>${title}</h4><ul>`;
|
||||||
for (var cmd of arr) {
|
for (var cmd of arr) {
|
||||||
str += `<li>${cmd}</li>`;
|
str += `<li>${cmd}</li>`;
|
||||||
|
@ -277,7 +294,7 @@ class HelperBot extends CollabVMClient {
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case "help":
|
case "help":
|
||||||
if (!DoLimit(this.GeneralCmdLimit)) return;
|
if (!DoLimit(this.GeneralCmdLimit!)) return;
|
||||||
this.SendGuacamoleMessage(
|
this.SendGuacamoleMessage(
|
||||||
"admin",
|
"admin",
|
||||||
"21",
|
"21",
|
||||||
|
@ -331,7 +348,7 @@ class HelperBot extends CollabVMClient {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "network":
|
case "network":
|
||||||
if (!DoLimit(this.GeneralCmdLimit)) return;
|
if (!DoLimit(this.GeneralCmdLimit!)) return;
|
||||||
|
|
||||||
switch (this._vmId) {
|
switch (this._vmId) {
|
||||||
case "vm7":
|
case "vm7":
|
||||||
|
@ -359,14 +376,14 @@ class HelperBot extends CollabVMClient {
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this.chat("This VM should already have internet.");
|
this.Chat("This VM should already have internet.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "certerror":
|
case "certerror":
|
||||||
if (!DoLimit(this.GeneralCmdLimit)) return;
|
if (!DoLimit(this.GeneralCmdLimit!)) return;
|
||||||
|
|
||||||
//if(this._vmId == 'vm0b0t') {
|
//if(this._vmId == 'vm0b0t') {
|
||||||
// this.SendGuacamoleMessage("admin", "21", "<h1>fuck off retard why are you trying to get collabnet on vm0</h1>");
|
// this.SendGuacamoleMessage("admin", "21", "<h1>fuck off retard why are you trying to get collabnet on vm0</h1>");
|
||||||
|
@ -391,13 +408,13 @@ class HelperBot extends CollabVMClient {
|
||||||
case "httpcd":
|
case "httpcd":
|
||||||
case "httpflp":
|
case "httpflp":
|
||||||
{
|
{
|
||||||
if (!DoLimit(this.GeneralCmdLimit)) return;
|
if (!DoLimit(this.GeneralCmdLimit!)) return;
|
||||||
|
|
||||||
let arg = message.slice(message.indexOf(" ") + 1);
|
let arg = message.slice(message.indexOf(" ") + 1);
|
||||||
let ext = arg.slice(arg.lastIndexOf(".") + 1);
|
let ext = arg.slice(arg.lastIndexOf(".") + 1);
|
||||||
if (arg.indexOf("..") !== -1) return;
|
if (arg.indexOf("..") !== -1) return;
|
||||||
for (var ii = 0; ii < BANNED_ISO.length; ii++) {
|
for (var ii = 0; ii < config.BANNED_ISO.length; ii++) {
|
||||||
if (BANNED_ISO[ii].test(arg)) {
|
if (config.BANNED_ISO[ii].test(arg)) {
|
||||||
this.Chat("That ISO is currently blacklisted.");
|
this.Chat("That ISO is currently blacklisted.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -541,7 +558,7 @@ class HelperBot extends CollabVMClient {
|
||||||
|
|
||||||
case "eject":
|
case "eject":
|
||||||
{
|
{
|
||||||
if (!DoLimit(this.GeneralCmdLimit)) return;
|
if (!DoLimit(this.GeneralCmdLimit!)) return;
|
||||||
|
|
||||||
let arg = message.slice(message.indexOf(" ") + 1);
|
let arg = message.slice(message.indexOf(" ") + 1);
|
||||||
|
|
||||||
|
@ -560,7 +577,7 @@ class HelperBot extends CollabVMClient {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "reboot":
|
case "reboot":
|
||||||
if (!DoLimit(this.RebootLimit)) return;
|
if (!DoLimit(this.RebootLimit!)) return;
|
||||||
|
|
||||||
// this.Chat("hold on fellas");
|
// this.Chat("hold on fellas");
|
||||||
// return;
|
// return;
|
||||||
|
@ -568,7 +585,7 @@ class HelperBot extends CollabVMClient {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "bootset":
|
case "bootset":
|
||||||
if (!DoLimit(this.GeneralCmdLimit)) return;
|
if (!DoLimit(this.GeneralCmdLimit!)) return;
|
||||||
|
|
||||||
//this.Chat("sorry, severe autism not allowed right now");
|
//this.Chat("sorry, severe autism not allowed right now");
|
||||||
//return;
|
//return;
|
||||||
|
@ -591,20 +608,20 @@ class HelperBot extends CollabVMClient {
|
||||||
// this.GeneralCmdLimit = new RateLimit(25 * 1000);
|
// this.GeneralCmdLimit = new RateLimit(25 * 1000);
|
||||||
//else
|
//else
|
||||||
this.GeneralCmdLimit = new RateLimit(
|
this.GeneralCmdLimit = new RateLimit(
|
||||||
kGeneralLimitBaseSeconds * 1000,
|
config.kGeneralLimitBaseSeconds * 1000,
|
||||||
2,
|
2,
|
||||||
`General commands/${this._vmId}`,
|
`General commands/${this._vmId}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
//this.EjectLimit = new RateLimit(30 * 1000);
|
//this.EjectLimit = new RateLimit(30 * 1000);
|
||||||
this.RebootLimit = new RateLimit(
|
this.RebootLimit = new RateLimit(
|
||||||
kRebootLimitBaseSeconds * 1000,
|
config.kRebootLimitBaseSeconds * 1000,
|
||||||
3,
|
3,
|
||||||
`!reboot/${this._vmId}`,
|
`!reboot/${this._vmId}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
OnGuacamoleMessage(message) {
|
OnGuacamoleMessage(message: string[]) {
|
||||||
if (message[0] == "connect") {
|
if (message[0] == "connect") {
|
||||||
if (message[1] == "0") {
|
if (message[1] == "0") {
|
||||||
Log(`[${this._vmId}]`, `Failed to connect to VM`);
|
Log(`[${this._vmId}]`, `Failed to connect to VM`);
|
||||||
|
@ -616,7 +633,7 @@ class HelperBot extends CollabVMClient {
|
||||||
Log(`[${this._vmId}]`, `Connected to VM`);
|
Log(`[${this._vmId}]`, `Connected to VM`);
|
||||||
|
|
||||||
// I'm fucking lazy
|
// I'm fucking lazy
|
||||||
this.SendGuacamoleMessage("login", ADMIN_TOKEN);
|
this.SendGuacamoleMessage("login", config.ADMIN_TOKEN);
|
||||||
this.CreateRateLimits();
|
this.CreateRateLimits();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,7 +653,7 @@ class HelperBot extends CollabVMClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let vm of INSTALLBOT_VMS) {
|
for (let vm of config.INSTALLBOT_VMS) {
|
||||||
// initalize this bot instance
|
// initalize this bot instance
|
||||||
new HelperBot(vm.uri, vm.id, vm.usesIde2, vm.hasFloppy).DoConn();
|
new HelperBot(vm.uri, vm.id, vm.usesIde2, vm.hasFloppy).DoConn();
|
||||||
}
|
}
|
108
tsconfig.json
Normal file
108
tsconfig.json
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||||
|
|
||||||
|
/* Projects */
|
||||||
|
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||||
|
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||||
|
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||||
|
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||||
|
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||||
|
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||||
|
|
||||||
|
/* Language and Environment */
|
||||||
|
"target": "ES2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||||
|
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||||
|
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||||
|
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||||
|
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||||
|
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||||
|
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||||
|
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||||
|
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||||
|
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||||
|
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||||
|
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||||
|
|
||||||
|
/* Modules */
|
||||||
|
"module": "ES2022", /* Specify what module code is generated. */
|
||||||
|
"rootDir": "./src", /* Specify the root folder within your source files. */
|
||||||
|
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||||
|
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||||
|
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||||
|
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||||
|
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||||
|
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||||
|
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||||
|
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||||
|
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
|
||||||
|
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
||||||
|
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
||||||
|
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
||||||
|
// "resolveJsonModule": true, /* Enable importing .json files. */
|
||||||
|
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
|
||||||
|
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||||
|
|
||||||
|
/* JavaScript Support */
|
||||||
|
"allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||||
|
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||||
|
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||||
|
|
||||||
|
/* Emit */
|
||||||
|
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||||
|
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||||
|
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||||
|
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||||
|
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||||
|
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||||
|
"outDir": "./dist", /* Specify an output folder for all emitted files. */
|
||||||
|
// "removeComments": true, /* Disable emitting comments. */
|
||||||
|
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||||
|
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||||
|
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||||
|
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||||
|
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||||
|
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||||
|
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||||
|
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||||
|
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||||
|
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||||
|
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||||
|
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||||
|
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||||
|
|
||||||
|
/* Interop Constraints */
|
||||||
|
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||||
|
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
|
||||||
|
// "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */
|
||||||
|
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||||
|
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
||||||
|
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||||
|
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||||
|
|
||||||
|
/* Type Checking */
|
||||||
|
"strict": true, /* Enable all strict type-checking options. */
|
||||||
|
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||||
|
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||||
|
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||||
|
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||||
|
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||||
|
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||||
|
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||||
|
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||||
|
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||||
|
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||||
|
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||||
|
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||||
|
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||||
|
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||||
|
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||||
|
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||||
|
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||||
|
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||||
|
|
||||||
|
/* Completeness */
|
||||||
|
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||||
|
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue