var express = require("express"); var Config = require("./config"); var Logger = require("./logger"); var Channel = require("./channel"); var User = require("./user"); const VERSION = "2.1.0"; function getIP(req) { var raw = req.connection.remoteAddress; var forward = req.header("x-forwarded-for"); if(Config.REVERSE_PROXY && forward) { var ip = forward.split(",")[0]; Logger.syslog.log("REVPROXY " + raw + " => " + ip); return ip; } return raw; } function getSocketIP(socket) { var raw = socket.handshake.address.address; if(Config.REVERSE_PROXY) { if(typeof socket.handshake.headers["x-forwarded-for"] == "string") { var ip = socket.handshake.headers["x-forwarded-for"] .split(",")[0]; Logger.syslog.log("REVPROXY " + raw + " => " + ip); return ip; } } return raw; } var Server = { channels: [], channelLoaded: function (name) { for(var i in this.channels) { if(this.channels[i].name == name) return true; } return false; }, getChannel: function (name) { for(var i in this.channels) { if(this.channels[i].name == name) return this.channels[i]; } var c = new Channel(name, this); this.channels.push(c); return c; }, unloadChannel: function(chan) { if(chan.registered) chan.saveDump(); chan.playlist.die(); for(var i in this.channels) { if(this.channels[i].name == chan.name) { this.channels.splice(i, 1); break; } } for(var i in chan) delete chan[i]; }, app: null, io: null, httpserv: null, ioserv: null, db: null, ips: {}, acp: null, init: function () { this.app = express(); // channel path this.app.get("/r/:channel(*)", function (req, res, next) { var c = req.params.channel; if(!c.match(/^[\w-_]+$/)) res.redirect("/" + c); else res.sendfile(__dirname + "/www/channel.html"); }); // api path this.api = require("./api")(this); this.app.get("/api/:apireq(*)", function (req, res, next) { this.api.handle(req.url.substring(5), req, res); }.bind(this)); // default path this.app.get("/:thing(*)", function (req, res, next) { res.sendfile(__dirname + "/www/" + req.params.thing); }); // fallback this.app.use(function (err, req, res, next) { if(err.status == 404) { res.send(404); } else { next(err); } }); // bind servers this.httpserv = this.app.listen(Config.WEBSERVER_PORT); this.ioserv = express().listen(Config.IO_PORT); // init socket.io this.io = require("socket.io").listen(this.ioserv); this.io.set("log level", 1); this.io.sockets.on("connection", function (socket) { var ip = getSocketIP(socket); socket._ip = ip; if(this.db.checkGlobalBan(ip)) { Logger.syslog.log("Disconnecting " + ip + " - gbanned"); socket.emit("kick", { reason: "You're globally banned." }); socket.disconnect(true); return; } socket.on("disconnect", function () { this.ips[ip]--; }.bind(this)); if(!(ip in this.ips)) this.ips[ip] = 0; this.ips[ip]++; if(this.ips[ip] > Config.MAX_PER_IP) { socket.emit("kick", { reason: "Too many connections from your IP address" }); socket.disconnect(true); return; } // finally a valid user Logger.syslog.log("Accepted socket from /" + socket._ip); new User(socket, this); }.bind(this)); // init database this.db = require("./database"); this.db.setup(Config); this.db.init(); // init ACP this.acp = require("./acp")(this); }, shutdown: function () { Logger.syslog.log("Unloading channels"); for(var i in this.channels) { if(this.channels[i].registered) this.channels[i].saveDump(); } Logger.syslog.log("Goodbye"); process.exit(0); } }; Logger.syslog.log("Starting CyTube v" + VERSION); Server.init(); if(!Config.DEBUG) { process.on("uncaughtException", function (err) { Logger.errlog.log("[SEVERE] Uncaught Exception: " + err); Logger.errlog.log(err.stack); }); process.on("exit", Server.shutdown); process.on("SIGINT", function () { process.exit(0); }); }