irc-bot/bot.js

270 lines
8.3 KiB
JavaScript

#!/usr/bin/env node
const fs = require("fs");
const irc = require("irc");
const Summon = require("./spells/summon");
// const Banish = require("./spells/summon");
const botName = "BabiliBot"
const client = new irc.Client("localhost", botName, {
channels: [
"#bots"
],
localAddress: "127.0.0.1",
port: 6667,
userName: "aewens",
floodProtection: true,
floodProtectionDelay: 1000,
autoConnect: false,
stripColors: true,
encoding: "utf-8",
debug: true
});
client.config = JSON.parse(fs.readFileSync("config.json", "utf8"));
client.config.botName = botName;
client.spells = [
Summon,
// Banish
];
// NOTE - For my personal copy, jan6 will remain here until #chaos is mine
client.blacklist = JSON.parse(fs.readFileSync("blacklist.json", "utf8"));
// Format:
// {
// timestamp: Date.now(),
// spell: spell.name
// }
client.memory = [];
const contains = (text, test) => {
return text.indexOf(test) > -1;
}
const logBlacklisters = (from, message) => {
const blacklistLog = `${from} tried to issue ${message}\n`;
fs.appendFile("blacklist.log", blacklistLog, (err) => {
if (err) throw err;
console.log("Blacklist", blacklistLog);
});
}
const addBlacklister = (from, message) => {
// Log reason for adding to the blacklist
const blacklistReason = `${from} was added for spamming ${message}\n`;
fs.appendFile("blacklisters.log", blacklistReason, (err) => {
if (err) throw err;
console.log("Blacklist", blacklistReason);
});
// Apply to current session
client.blacklist[from] = {
reason: `Your actions triggered auto-banishment`,
when: Date.now()
};
// Apply to future sessions
const blacklist = JSON.stringify(client.blacklist);
fs.writeFile("blacklist.json", blacklist, (err) => {
if (err) throw err;
console.log("Added to blacklist:", from);
});
}
const castSpell = (client, from, to, incantation) => {
let casted = false;
client.spells.forEach((_spell) => {
const spell = new _spell(client, from, to, incantation);
const vars = spell.varsUsed;
let response = null;
// Only the author can use these spells
if (spell.locked && from !== client.config.author) {
client.say(to, "Blasfemo! That spell is forbidden to you.");
return false;
}
if (vars > 0) {
// Note: Handle variables in spells
const spellName = spell.spell;
const splitIncantation = incantation.split(spellName);
const variable = splitIncantation[1].trim().split(" ");
spell.incantation = incantation.split(splitIncantation[1])[0];
response = spell.test.apply(spell, variable.splice(0, vars));
} else {
response = spell.test();
}
if (spell.casted) {
casted = true;
client.memory.push({
timestamp: Date.now(),
spell: spell.name
});
if (response.say) {
client.say(to, response.content);
}
}
});
if (!casted) {
client.say(to, `${from}, malsagxulo! That spell does not exist.`);
}
}
// For those who cannot handle Esperanto, plebeyoj!
const useCheatCode = (client, from, to, cheatCode) => {
let cheatCodes = {};
let variables = "";
// Handle variables in cheat code
if (cheatCode.indexOf(" ") > -1) {
splitCheatCode = cheatCode.split(" ");
variables = splitCheatCode.slice(1).join(" ");
cheatCode = splitCheatCode[0];
}
// Generate cheat code
client.spells.forEach((_spell) => {
const spell = new _spell(client, from, "");
cheatCodes[spell.cheatCode] = `${spell.spell} ${variables}`;
});
if (contains(Object.keys(cheatCodes), cheatCode)) {
castSpell(client, from, to, cheatCodes[cheatCode]);
}
}
const checkBlacklist = (client, from, to, message) => {
const now = Date.now();
const lastUsed = client.memory.slice(-1).pop();
const lastTimestamp = lastUsed ? lastUsed.timestamp : 0;
const blacklisters = Object.keys(client.blacklist);
if (contains(blacklisters, from)) {
const blacklistInfo = blacklisters[from];
const reason = blacklistInfo.reason;
// Log the blacklisters for later scrutiny
logBlacklisters(from, message);
client.action(to, `is ignoring ${from} because: ${reason}. Malsaĝa!`);
return false;
}
// Add to blacklist if abusing bot
if (now < lastTimestamp + client.config.timeout) {
// Add exception for author of bot
if (from !== client.config.author) {
addBlacklister(from, message);
let banished = `Malpermesante ${from}!`;
banished = `${banished} Your actions triggered auto-banishment.`;
banished = `${banished} I will no longer heed your words.`
client.say(to, banished);
return false;
}
}
return true;
}
client.addListener("message", (from, to, _message) => {
console.log(`${from} => ${to}: ${_message}`);
const message = _message.toLowerCase();
const triggerWord = client.config.triggerWord;
const address = botName.toLowerCase();
const triggers = {
"!cast": {
vars: " <spell>",
description: "Used to issue an Esperanto spell."
},
"!summon": {
vars: " <user> <reason:optional>",
description: "Used to send a summoning email to <user>@tilde.team."
},
"!help BabiliBot": {
vars: "",
description: "PMs user this message."
},
// "!spells": {
// vars: "",
// description: "PMs spell list to user"
// }
};
const triggerNames = Object.keys(triggers);
if (message.startsWith(triggerWord)) {
// NOTE: entry for !cast <spell>
const incantation = message.split(triggerWord)[1].trim();
const check = checkBlacklist(client, from, to, incantation);
if (check) {
castSpell(client, from, to, incantation);
}
} else if (message.startsWith(address)) {
// NOTE: Use the English spells of !cast
let cheatCode = message.split(address)[1];
// Why punish formality?
if (cheatCode.startsWith(": ")) {
cheatCode = cheatCode.split(": ")[1];
} else if (cheatCode.startsWith(", ")) {
cheatCode = cheatCode.split(", ")[1];
}
cheatCode = cheatCode.trim();
const check = checkBlacklist(client, from, to, cheatCode);
if (check) {
useCheatCode(client, from, to, cheatCode);
}
} else if (message.startsWith("!summon ")) {
// NOTE: alias for !cast kunvoki - by popular demand
const cheatCode = message.slice(1).trim();
const check = checkBlacklist(client, from, to, cheatCode);
if (check) {
useCheatCode(client, from, to, cheatCode);
}
} else if (message.startsWith("!botlist")) {
// NOTE: To adhere to https://tilde.team/wiki/?page=irc-bots
let botlist = `${botName} | <${client.config.author}>`;
botlist = `${botlist} | the Esperanto speaking chat bot`;
botlist = `${botlist} | ${triggerNames.join(", ")}`;
client.say(to, botlist);
} else if (message.startsWith(`!help ${address}`)) {
// NOTE: Help information PM'd to requester
client.say(to, `Komprenita, sending help info to ${from}`);
client.say(from, `I answer have ${triggers.length} commands:`);
triggerNames.forEach((name) => {
const trigger = triggers[name];
let helpText = `${name} ${trigger.vars}`;
helpText = `${helpText} | ${trigger.description}`;
client.say(from, helpText);
});
client.say(from, "I also respond to: `BabiliBot, <command>`");
}
});
client.addListener("pm", (from, message) => {
console.log(`${from} => ME: ${message}`);
});
client.addListener("error", (message) => {
console.error(`error: ${message}`, message);
});
client.addListener("registered", () => {
// client.say("NickServ", `RECOVER ${botName} ${client.config.password}`);
client.say("NickServ", `IDENTIFY ${client.config.password}`);
});
client.connect();
client.join("#bots");