From 2d22402cb040231b2a3735aac5b13ac873b842a3 Mon Sep 17 00:00:00 2001 From: Evert Date: Sun, 25 Sep 2016 16:09:55 +0300 Subject: [PATCH] simple webirc integration, debug mode --- .gitignore | 1 + README.md | 5 ++- client.config.example.toml | 1 + public/css/main.css | 4 +-- public/js/main.js | 6 ++-- public/main.styl | 4 +-- server/irc.js | 13 ++++--- server/webirc.js | 45 +++++++++++++++++++++++++ teemant.js | 69 ++++++++++++++++++++++++++++++++------ 9 files changed, 126 insertions(+), 22 deletions(-) create mode 100644 server/webirc.js diff --git a/.gitignore b/.gitignore index 48936ad..fd3c3e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /node_modules/ /build/ /client.config.toml +/webirc.data.json diff --git a/README.md b/README.md index 0e826b2..ef0ceb6 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,13 @@ This application requires [node.js](https://nodejs.org/) to be installed. The client will be accessible at http://localhost:8080/ +### WebIRC + +The server will look for passwords in `webirc.data.json`. The format is: `"server-ip-address": "server webirc password"` + ###The (non-complete) TODO List (of things left to do) * [HIGH] Settings menu -* [HIGH] WebIRC protocol integration * [MEDIUM] Theme engine * [NORMAL] CAP negotiation * [LOW] Better input diff --git a/client.config.example.toml b/client.config.example.toml index 99398af..68f5fa2 100644 --- a/client.config.example.toml +++ b/client.config.example.toml @@ -1,5 +1,6 @@ [server] port=8080 + debug=true [client] username="teemant" diff --git a/public/css/main.css b/public/css/main.css index e86dea1..5fb74ab 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -180,7 +180,7 @@ body { bottom: 46px; } .ircclient #chat .ircwrapper .chatarea .smsc-nicklistbtn { - background-image: url("/image/users.svg"); + background-image: url("image/users.svg"); background-repeat: no-repeat; background-size: contain; width: 46px; @@ -313,7 +313,7 @@ body { box-shadow: inset 4px 4px 8px #d8d8d8; } .ircclient #chat .ircwrapper .input .sendbutton { - background-image: url("/image/send.svg"); + background-image: url("image/send.svg"); background-repeat: no-repeat; background-size: contain; width: 32px; diff --git a/public/js/main.js b/public/js/main.js index d1a1b1c..0096590 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -602,7 +602,8 @@ class Buffer { appendMessage(meta) { let mesgConstr = composer.message[irc.chatType](meta.time, meta.sender, meta.message, meta.type); - if((meta.type == "privmsg" || meta.type == "notice") && meta.message.indexOf(irc.serverData[this.server].my_nick) != -1) + if((meta.type == "privmsg" || meta.type == "notice" || meta.type == "action") && + meta.message.indexOf(irc.serverData[this.server].my_nick) != -1) addClass(mesgConstr, "mentioned"); clientdom.letterbox.appendChild(mesgConstr); @@ -630,7 +631,8 @@ class Buffer { this.appendMessage(mesg); } else { this.unreadCount += 1; - if((type == "privmsg" || type == "notice") && message.indexOf(irc.serverData[this.server].my_nick) != -1) + if((type == "privmsg" || type == "notice" || type == "action") && + message.indexOf(irc.serverData[this.server].my_nick) != -1) console.log("TODO: notify user of mentioned"); } diff --git a/public/main.styl b/public/main.styl index f097024..f3de904 100644 --- a/public/main.styl +++ b/public/main.styl @@ -161,7 +161,7 @@ body width: 100%; bottom: 46px; .smsc-nicklistbtn - background-image: url(/image/users.svg); + background-image: url(image/users.svg); background-repeat: no-repeat; background-size: contain; width: 46px; @@ -277,7 +277,7 @@ body border-left: 0 box-shadow: inset 4px 4px 8px #d8d8d8 .sendbutton - background-image: url(/image/send.svg); + background-image: url(image/send.svg); background-repeat: no-repeat; background-size: contain; width: 32px; diff --git a/server/irc.js b/server/irc.js index 5b6c51b..91ab37e 100644 --- a/server/irc.js +++ b/server/irc.js @@ -2,6 +2,7 @@ let EventEmitter = require('events').EventEmitter; let net = require('net'); let configuration = require(__dirname+"/config"); let parse = require(__dirname+"/parser"); +let webirc = require(__dirname+"/webirc"); if (!String.prototype.format) { String.prototype.format = function() { @@ -18,7 +19,6 @@ class IRCConnectionHandler { } handleUserLine(data) { - console.log(data); switch(data.command) { case "kick": case "part": @@ -68,7 +68,6 @@ class IRCConnectionHandler { } handleServerLine(line) { - console.log(line); if(this.conn.queue["supportsmsg"] && line.command != "005") { delete this.conn.queue["supportsmsg"]; @@ -334,7 +333,7 @@ class IRCConnectionHandler { } class IRCConnection extends EventEmitter { - constructor(providedInfo) { + constructor(providedInfo, userInfo) { super(); this.config = { @@ -349,6 +348,8 @@ class IRCConnection extends EventEmitter { address: "0.0.0.0" }; + this.userInfo = userInfo; + for(let a in providedInfo) { this.config[a] = providedInfo[a]; } @@ -429,7 +430,11 @@ class IRCConnection extends EventEmitter { if (this.config.password) this.socket.write('PASS {0}\r\n'.format(this.config.password)); - // TODO: WebIRC + let serverpass = webirc.get_password(this.config.address); + + if(serverpass) + this.socket.write('WEBIRC {0} cgiirc {1} {2}\r\n'.format(serverpass, this.userInfo.hostname, this.userInfo.ipaddr)); + this.socket.write('USER {0} 8 * :{1}\r\n'.format(this.config.username, this.config.realname)); this.socket.write('NICK {0}\r\n'.format(this.config.nickname)); } diff --git a/server/webirc.js b/server/webirc.js new file mode 100644 index 0000000..ed88d23 --- /dev/null +++ b/server/webirc.js @@ -0,0 +1,45 @@ +let dns = require("dns"); +let fs = require("fs"); +let path = require("path"); +let config = require(__dirname+'/config'); +let webirc_data_path = path.resolve(__dirname+'/../webirc.data.json'); + +let webirc_data = {}; + +function writeToFile() { + fs.writeFile(webirc_data_path, JSON.stringify(webirc_data, null, '\t'), function (err) {if (err) throw err;}); +} + +function reload() { + try { + fs.accessSync(webirc_data_path, fs.F_OK); + + webirc_data = require(webirc_data_path); + + if (require.cache && require.cache[webirc_data_path]) { + delete require.cache[webirc_data_path]; + } + } catch(e) { + writeToFile(); + } +} + +function get_password(server_ip) { + if(webirc_data[server_ip] != null) + return webirc_data[server_ip]; + + return null; +} + +module.exports = { + reload: reload, + get_password: get_password, + writeToFile: writeToFile +} + +process.on('SIGUSR1', () => { + console.log("!!! Received SIGUSR1; Reloading webirc data.. !!!"); + reload(); +}); + +reload(); diff --git a/teemant.js b/teemant.js index dc136f3..adeae76 100755 --- a/teemant.js +++ b/teemant.js @@ -6,7 +6,7 @@ let sockio = require("socket.io"); let dns = require("dns"); let app = express(); -let pubdir = path.join(__dirname+"/public"); +let pubdir = path.join(__dirname, "public"); let config = require(__dirname+'/server/config'); let ircclient = require(__dirname+'/server/irc'); @@ -14,6 +14,8 @@ let port = config.server.port || 8080; let connections = {}; +process.stdin.resume(); + app.get("/", function(req, res){ res.sendFile(pubdir+"/index.html"); }); @@ -21,31 +23,54 @@ app.get("/", function(req, res){ app.use(express.static(__dirname + '/public')); let io = sockio.listen(app.listen(port, function() { - console.log("*** Listening on port " + port); + console.log("*** Listening on http://localhost:" + port + "/"); })); -function resolveHostname(hostname) { +function resolveHostname(ipaddr) { let promise = new Promise(function(resolve, reject) { - dns.lookup(hostname, function(err, address, family) { + dns.reverse(ipaddr, function(err, hostnames) { if(err != null) return reject(err); - resolve(address); + resolve(hostnames); }); }); return promise; } io.sockets.on('connection', function (socket) { - console.log('clientID: '+socket.id+' connection: ', socket.request.connection._peername); - connections[socket.id] = {} + let userip = socket.handshake.headers['x-real-ip'] || socket.handshake.headers['x-forwarded-for'] || + socket.request.connection._peername.address || "127.0.0.1"; + + if(config.server.debug) + console.log('clientID: '+socket.id+' from: ', userip); + + // New object for connections + connections[socket.id] = { + host: { + ipaddr: userip, + hostname: "localhost" + } + } + + // Get the hostname of the connecting user + let hostQuery = resolveHostname(userip); + hostQuery.then((arr) => { + if(arr.length > 0) + connections[socket.id].host.hostname = arr[0]; + if(config.server.debug) + console.log("Hostname of "+socket.id+" was determined to be "+connections[socket.id].host.hostname); + }).catch((err) => { console.log("Host resolve for "+socket.id+" failed: ", err); }); socket.on('disconnect', function() { - for (let d in connections[socket.id]) + for (let d in connections[socket.id]) { + if(connections[socket.id][d].ipaddr) continue; if(connections[socket.id][d].connected == true) connections[socket.id][d].disconnect(); + } delete connections[socket.id]; - console.log('clientID: '+socket.id+' disconnect'); + if(config.server.debug) + console.log('clientID: '+socket.id+' disconnect'); }); socket.on('error', (e) => { @@ -57,14 +82,19 @@ io.sockets.on('connection', function (socket) { if(!serv) return; if(serv.authenticated == false) return; + if(config.server.debug) + console.log("["+socket.id+"] ->", data); + serv.handler.handleUserLine(data); }) socket.on('irc_create', function(connectiondata) { - console.log(socket.id+" created irc connection: ", connectiondata); + if(config.server.debug) + console.log(socket.id+" created irc connection: ", connectiondata); + socket.emit('act_client', {type: 'connect_message', message: "Connecting to server..", error: false}); - let newConnection = new ircclient(connectiondata); + let newConnection = new ircclient(connectiondata, connections[socket.id].host); newConnection.connect(); connections[socket.id][connectiondata.server] = newConnection; @@ -75,6 +105,12 @@ io.sockets.on('connection', function (socket) { max_channel_length: newConnection.data.max_channel_length}); }); + if(config.server.debug) { + newConnection.on('line', function(line) { + console.log("["+socket.id+"] <-", line); + }); + } + newConnection.on('connerror', (data) => { let message = "An error occured"; let inconnect = true; @@ -110,3 +146,14 @@ io.sockets.on('connection', function (socket) { }); }); }); + +process.on('SIGINT', () => { + console.log('!!! Received SIGINT; Terminating all IRC connections and exiting.. !!!'); + for(let c in connections) { + for(let ircconn in connections[c]) { + if(connections[c][ircconn].ipaddr) continue; + connections[c][ircconn].disconnect(); + } + } + process.exit(); +});