Skip to content

Instantly share code, notes, and snippets.

@boxmein
Last active December 11, 2015 18:49
Show Gist options
  • Save boxmein/4644761 to your computer and use it in GitHub Desktop.
Save boxmein/4644761 to your computer and use it in GitHub Desktop.
An IRC bot in Javascript which uses node.js. Incomplete.
@echo off
:a
cls
node irc-bot.js
echo Fix me!
pause
goto a
// @language ECMASCRIPT5
// When everything falls apart
// Just don't back down
// Just keep running
// Just look ahead
// You might be losing but you're not dead
var net = require("net");
var http = require("http");
var sys = require("sys");
// IRC bot core
var irc = {
client: new net.Socket(),
PORT: 6667,
HOST: "irc.freenode.net",
textlogging: true, // If we log regular messages like <nick/#chan> Message
onConnected: function() { // we are connected!
output.log("irc.onConnected", "Connection successful");
output.announce("Press q + enter to exit program.");
setTimeout(function() {
irc.raw("NICK " + config.nickname);
irc.raw("USER " + config.nickname + " 8 * :" + config.realname);
irc.raw("JOIN " + config.channels);
}, 7000);
},
handleCommands: function(ircdata) {
output.inn(ircdata.sender + "(in " + ircdata.channel +") called for: " + ircdata.message);
// IRC message's first word without the # and the \r\n, if existent
// Also performs some changes
// 1. args ["#command", "arg0", "arg1" ...] -> args ["arg0", "arg1" ...]
// 2. .command = "command"
// 3. remove foreigns from commands
ircdata.command = ircdata.args.shift().substring(1).trim().replace(/[^A-Za-z]+?/gi, "");
// commands.cmdlist is now chief in executive for testing whether a command exists
if (typeof(commands.cmdlist[ircdata.command]) != "undefined") {
commands[ircdata.command](ircdata);
}
else
output.err("irc.onData", ircdata.command+" is not a command.");
},
onData: function(data) {
if (data.indexOf("PRIVMSG ") != -1) { // Channel message
var arr = data.split(' '); // Creates an array with
var result = arr.splice(0,3);// ["hostmask", "command", "channel", "mess age"]
result.push(arr.join(' '));
var ircdata = {
hostmask : result[0].substring(1), // Sender's hostmask
channel : result[2], // Sender's channel
sender : result[0].substring(1, result[0].indexOf("!")), // Sender's handle
message : result[3].substring(1).trim(), // Full message
};
if (irc.textlogging)
output.chanmsg(ircdata);
ircdata.args = ircdata.message.split(" ");
if (ircdata.message.indexOf(commands.prefix) == 0) {
irc.handleCommands(ircdata);
}
}
else if(data.indexOf("PING") != -1) { // Ping-pong handling
irc.raw("PONG", true); // Disables its logging.
}
},
onConnectionClose: function() { // If the server disconnects us
output.err("irc.onConnectionClose", "Disconnected ()");
process.exit(0);
},
// // // // // //
// IRC wrappers
// // // // // //
ctcp: function(channel, data) { // to send CTCP data which must end in \x01
irc.raw("PRIVMSG " + channel + " :\x01" + data + "\x01");
},
action: function(channel, action) { // to send a /me action
irc.ctcp(channel, "ACTION "+ action);
},
privmsg: function(channel, message) { // To send a regular message to #chan or user
irc.raw("PRIVMSG " + channel + " :" + message);
},
notice: function(channel, message) {
irc.raw("NOTICE " + channel + " :" + message);
},
join: function(channel) { // To join a channel
irc.raw("JOIN " + channel);
},
part: function(channel) { // To leave a channel
irc.raw("PART " + channel + " :" + config.partmsg);
},
quit: function() {
irc.raw("QUIT :"+config.quitmsg);
process.exit(0);
},
raw: function(data, hide) { // To send raw IRC data (hide hides the sending box, optionally)
irc.client.write(data + "\n", "ascii", function() {
if(!hide)
console.log("[>>] " + data);
});
}
};
var commands = {
prefix: "#",
crypt: function(ircdata) {
if (ircdata.args.length < 3)
{
// Send the help text
ircdata.args[0] = "crypt";
commands.help(ircdata);
return;
}
var subcommand = ircdata.args[0];
if (typeof crypto[subcommand] == "undefined") {
output.err("commands.crypt", "No such crypt subcommand: " + subcommand);
commands._respond("No such crypto method: " + subcommand);
return;
}
output.log("commands.crypt", "found crypto subcommand: " + subcommand);
output.log("commands.crypt", "calling with key: " + ircdata.args[1] + " & plain: " + ircdata.args[2]);
commands._respond(ircdata, crypto[subcommand](ircdata.args[1], ircdata.args[2]));
},
eat: function(ircdata) { // eat <user> | eat - eats the user or the sender
output.log("commands.eat", "Eating an user.");
irc.action(ircdata.channel, "eats " + (
ircdata.args[0] != ""
? ircdata.args[0].trim()
: ircdata.sender) );
},
time: function(ircdata) { // time - shows time in my zone
var d = new Date(Date.now());
output.log("commands.time", "Doing commands.time");
commands._respond(ircdata, d.getHours() + ":" + d.getMinutes());
},
list: function(ircdata) { // list - lists all commands
var keys = [];
for (var k in commands.cmdlist)
keys.push(k);
commands._respond(ircdata, "" + keys.join(", ").trim());
},
ping: function(ircdata) { // ping - responds with pong
commands._respond(ircdata, "pong!")
},
help: function(ircdata) { // help - helps with the functionality
var requested = (ircdata.args[0] || "help").trim();
if(typeof(commands.cmdlist[requested]) != "undefined"
&& requested.indexOf("_") == -1) {
output.log("commands.help", "command was found");
commands._respond(ircdata, commands.cmdlist[requested]);
}
else
output.log("commands.help", "command was either not found or empty string");
},
version: function(ircdata) { // version - id string
commands._respond(ircdata, "boxmein's bot in node.js : https://gist.github.com/4644761");
},
isowner: function(ircdata) { // isowner - if the sender is the owner of the bot.
commands._respond(ircdata, commands._isowner(ircdata));
},
js: function(ircdata) { // js <code> - makes javascript
output.log("commands.js", "JS METHOD CALL STARTED");
if (commands._isowner(ircdata)) {
output.log("commands.js", "Sender is the owner! Executing...");
output.log("commands.js", "JS: " + ircdata.args.join(" "));
var response = "";
try {
response = "[return]: " + eval("(function() {" + ircdata.args.join(" ") + "})();");
}
catch (error) {
response = "[Broken syntax]";
}
output.log("commands.js", response);
commands._respond(ircdata, response);
output.log("commands.js", "JS METHOD CALL ENDED");
}
},
stm: function(ircdata) { // sendtomniip <nick> <msg> - makes a HTTP request as mniip's
output.log("commands.sendtomniip", "Starting HTTP request");
if (ircdata.args[0] != "") {
var message = "";
if (ircdata.args.length > 2) {
message = ircdata.args.splice(1, ircdata.args.length -1).join(" ");
output.log("commands.sendtomniip", "(0) message: " + message);
}
else if(ircdata.args[1] != "" && ircdata.args[1] != undefined) {
message = ircdata.args[1];
output.log("commands.sendtomniip", "(1) message: " + message);
}
else {
message = "disregard that, I suck cocks"; // http://bash.org/?5775
}
var req = http.request(
// Object with all the details
{
hostname: "mniip.com",
path: "/bot.lua?nick=" + ircdata.args[0] + "&msg=" + encodeURIComponent(message),
method: "GET",
headers: {
"User-Agent": "boxnode@" + ircdata.channel,
"X-Powered-By": "lolcats"
}
},
// When the response comes by
function(response) {
output.log("commands.sendtomniip", "Status: " + response.statusCode);
output.log("commands.sendtomniip", "Headers: " + JSON.stringify(response.headers, null, "\t"));
// Might need to be in here
req.on("error", function(evt) {
output.err("commands.sendtomniip", evt.message);
});
});
req.end();
}
output.log("commands.sendtomniip", "Ending function body");
},
// _functions are meant to be used not as commands, but as utilities
_respond: function(ircdata, message) {
if (ircdata.channel.indexOf("#") == -1) { // If recipient is an user, send notices
irc.notice(ircdata.channel, message);
}
else
irc.privmsg(ircdata.channel, ircdata.sender + ": " + message);
},
_isowner: function(ircdata) {
var isowner = (ircdata.hostmask.indexOf(config.owner) != -1);
output.log("commands._isowner", "user "+ircdata.sender+ (isowner ? " is owner" : " isn't owner"));
return isowner;
},
_add: function(commandname, helptext, callback) {
commands.cmdlist[commandname] = helptext; // Add its help text
commands[commandname] = callback; // Add function body
},
cmdlist: {
// Using this list is mandatory now!
"help": "help <cmd> - shows you help on a command",
"eat" : "eat <user> | eat - eats another user or you",
"time": "time - gives my current time",
"list": "list - lists all commands",
"ping": "ping - Responds with pong ASAP",
"help": "help <command> - help text on a topic",
"js": "js <javascript> - run javascript [owner only]",
"version": "version - gives you version and my gist link",
"isowner": "isowner - check whether or not you're the owner",
"stm": "stm <nick> <message> - send a message to make xsbot say it out",
"crypt": "crypt <method=otp,caesar,rot13> <key/shift> <plaintext> - Encrypt text"
},
};
var output = {
log: function(sender, message) {
if(!config.silent) console.log("[LL] " + sender + ": " + message);
},
err: function(sender, message) {
console.log("[EE] " + sender + ": " + message);
},
out: function(sender, message) {
if(!config.silent) console.log("[>>] " + sender + ": " + message);
},
inn: function(message) { // typo is on purpose
if(!config.silent) console.log("[<<] " + message);
},
announce: function(message) {
if (!config.silent) console.log("[--] --- " + message + " ---")
},
chanmsg: function(ircdata) {
if (!config.silent) console.log("[##]<{0}/{1}> {2}".format(ircdata.sender, ircdata.channel, ircdata.message));
}
}
var config = {
// For prefix, see commands
silent: false, // Hides log and channel messages, leaves errors
partmsg: "",
quitmsg: "",
nickname: "",
realname: "",
channels: "",
owner: "" // Use a part of the hostmask
};
var crypto = {
otp: function(pad, message) {
var newstr = "";
if (pad.length >= message.length) {
message = message.toUpperCase();
pad = pad.toUpperCase();
for (var i = 0; i < message.length; i++) {
newstr += String.fromCharCode( ( (message.charCodeAt(i) - 65) + (pad.charCodeAt(i) - 65) ) % 26 + 65 );
}
output.log("crypto.otp", "OTP: " + newstr);
output.log("crypto.otp", "Pad: " + pad);
return newstr;
}
else
output.err("crypto.otp", "Pad is shorter than the message");
},
caesar: function(offset, message) {
message = message.toUpperCase();
var newstr = "";
try {
offset = parseInt(offset);
}
catch (error) {
output.err("crypto.caesar", "couldn't parse integer: " + offset);
output.log("crypto.caesar", "error: " + error);
offset = 5
}
for (var i = 0; i < message.length; i++) {
newstr += String.fromCharCode((message.charCodeAt(i) - 65 + offset) % 26 + 65);
}
output.log("crypto.caesar", "Shift complete: " + newstr);
return newstr;
},
rot13: function(notused, message) {
return crypto.caesar(13, message);
}
};
String.prototype.trim = function() { // woo stackoverflow
return this.replace(/^\s+|\s+$/g, "");
};
//first, checks if it isn't implemented yet
if (!String.prototype.format) {
String.prototype.format = function() {
var args = arguments;
return this.replace(/{(\d+)}/g, function(match, number) {
return typeof args[number] != 'undefined'
? args[number]
: match
;
});
};
}
irc.client.setEncoding("ascii");
irc.client.setNoDelay();
irc.client.connect(irc.PORT, irc.HOST, irc.onConnected);
var stdin = process.openStdin();
irc.client.on("data", irc.onData);
irc.client.on("close", irc.onConnectionClose);
stdin.on('data', function(data) {
// feel free to add commands here.
data = data.toString().trim();
if (data == "")
return;
var args = data.split(" ");
var cmd = args.shift();
// output.log("stdin.onData", "received input: " + data);
if(cmd == "say")
irc.privmsg(args.shift(), args.join(" "));
else if(cmd == "raw")
irc.raw(args.join(" "));
else if(cmd == "join")
irc.join(args.shift());
else if(cmd == "part")
irc.part(args.shift());
else if(cmd == "quit")
irc.quit();
else if(cmd == "tlogging")
irc.textlogging = !irc.textlogging;
else if(cmd == "help")
{
console.log(
"[--] Help:\n" +
"[--] say <chan> <msg> - sends message to channel\n" +
"[--] raw <RAW> - sends raw IRC\n[--] join <chan> - joins a channel\n" +
"[--] part <chan> - parts a channel\n[--] quit - quits the server\n" +
"[--] tlogging - toggles text logging");
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment