Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions backend/utils/antibot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
var { obfuscate } = require("javascript-obfuscator");
var fs = require("fs");
var path = require("path");

var settingsPath = path.resolve(process.cwd(), "../nwotdata/settings.json");
if (!fs.existsSync(settingsPath)) { // Do I even need this?
settingsPath = path.resolve(process.cwd(), "settings_example.json");
}
var settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));

class Antibot {
checkSolves = [];
solves = [];

hash = Math.floor(Math.random() * 999);

constructor() {
this.clientChecks = (settings.antibot && settings.antibot.client_checks) || [];
this.botGlobals = (settings.antibot && settings.antibot.bot_globals) || [];

if (!this.clientChecks.length && !this.botGlobals.length) {
this.enabled = false;
return;
}
this.enabled = true;

for (let i = 0; i < 3; i++) {
this.solves.push(this.clientChecks[Math.floor(Math.random() * this.clientChecks.length)]);
}

for (let i = 0; i < this.solves.length; i++) {
this.checkSolves.push(Math.floor(Math.random() * 999) + "");
}
}

verifyMessage(ws, data) {
if (!this.enabled) return false;
if (!ws.sdata) return false;

if (ws.sdata.antibot_verified) return false;

if (ws.sdata.user && (ws.sdata.user.operator || ws.sdata.user.superuser || ws.sdata.user.staff)) {
ws.sdata.antibot_verified = true;
return false;
}

if (data.kind == "antibot_response") {
if (this.verifyCode(data.code)) {
ws.sdata.antibot_verified = true;
return false;
}
return true;
}

return true;
}

sendChallenge(ws) {
if (!this.enabled) return;
if (!ws.sdata) return;
var code = this.generateCode();
try {
ws.send(JSON.stringify({
kind: "antibot_challenge",
code: code
}));
} catch(e) {}
}

generateCode() {
if (!this.enabled) return null;
let clientChecksCode = this.solves.map((z, i) => {
return `if(${z[0]} == ${JSON.stringify(z[1])}) parts.push("${this.checkSolves[i]}")`;
});

let botGlobalsCode = this.botGlobals.map((g) => {
return `if(typeof ${g} !== "undefined") return 0`;
});

return obfuscate(
`
let parts = [];
${botGlobalsCode.join(";\n")}
${clientChecksCode.join(";\n")}
return ${this.hash}*parts.map(z => z.split("").map(z => z.charCodeAt(0)).reduce((a, b)=>a+b)).reduce((a, b) => a + b);
`,
{
compact: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 1,
numbersToExpressions: true,
simplify: true,
stringArrayShuffle: true,
splitStrings: true,
stringArrayThreshold: 0.52,
},
).getObfuscatedCode();
}

verifyCode(code) {
if (!this.enabled) return true;
let solve = this.hash *
this.checkSolves.map((z) =>
z.split("").map((z) => z.charCodeAt(0)).reduce((a, b) => a + b)
).reduce((a, b) => a + b);

if (solve !== code) {
console.log(
"Antibot failed! Code:",
code,
"Needed:",
solve,
"Hash:",
this.hash,
"Solves:",
this.solves,
);
}
return solve == code;
}
}

module.exports = Antibot;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"description": "OurWorldOfText server",
"dependencies": {
"adm-zip": "^0.5.16",
"javascript-obfuscator": "^5.5.0",
"nodemailer": "^7.0.10",
"pg": "^8.13.1",
"sqlite3": "^5.1.7",
Expand Down
12 changes: 12 additions & 0 deletions runserver.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const utils = require("./backend/utils/utils.js");
const rate_limiter = require("./backend/utils/rate_limiter.js");
const ipaddress = require("./backend/framework/ipaddress.js");
const prompt = require("./backend/utils/prompt.js");
const Antibot = require("./backend/utils/antibot.js");
const restrictions = require("./backend/utils/restrictions.js");
const frameUtils = require("./backend/framework/utils.js");
const serverUtil = require("./backend/framework/server.js");
Expand Down Expand Up @@ -900,6 +901,14 @@ async function initializeServer() {
global_data.checkCSRF = httpServer.checkCSRF;
global_data.createCSRF = httpServer.createCSRF;

var antibot = new Antibot();
if(antibot.enabled) {
console.log("Antibot enabled (" + antibot.clientChecks.length + " checks, " + antibot.botGlobals.length + " bot globals)");
} else {
console.log("Antibot disabled");
}
global_data.antibot = antibot;

if(accountSystem == "local") {
await loadEmail();
}
Expand Down Expand Up @@ -2239,6 +2248,8 @@ async function manageWebsocketConnection(ws, req) {
initial_user_count
}));

global_data.antibot.sendChallenge(ws);

if(client_cursor_pos[world.id]) {
var world_cursors = client_cursor_pos[world.id];
for(var csr_channel in world_cursors) {
Expand Down Expand Up @@ -2304,6 +2315,7 @@ async function manageWebsocketConnection(ws, req) {
}
return send_ws(JSON.stringify(res));
}
if(global_data.antibot.verifyMessage(ws, msg)) return;
// Begin calling a websocket function for the necessary request
if(!websockets.hasOwnProperty(kind)) {
return;
Expand Down