diff --git a/lib/api.js b/lib/api.js index de03ad85..cf7fe407 100644 --- a/lib/api.js +++ b/lib/api.js @@ -74,8 +74,48 @@ module.exports = function (Server) { loaded: false }; - if(Server.isChannelLoaded(name)) - data = getChannelData(Server.getChannel(name)); + var needPassword = false; + var chan = null; + if (Server.isChannelLoaded(name)) { + chan = Server.getChannel(name); + data = getChannelData(chan); + needPassword = chan.opts.password; + } + + if (needPassword !== false) { + var pw = req.query.password; + if (pw !== needPassword) { + var uname = req.cookies.cytube_uname; + var session = req.cookies.cytube_session; + Server.db.userLoginSession(uname, session, function (err, row) { + if (err) { + res.status(403); + res.type("application/json"); + res.jsonp({ + error: "Password required to view this channel" + }); + return; + } + + if (chan !== null) { + chan.getRank(uname, function (err, rank) { + if (err || rank < 2) { + res.status(403); + res.type("application/json"); + res.jsonp({ + error: "Password required to view this channel" + }); + return; + } + + res.type("application/json"); + res.jsonp(data); + }); + } + }); + return; + } + } res.type("application/json"); res.jsonp(data); @@ -127,7 +167,7 @@ module.exports = function (Server) { var channels = []; for(var key in Server.channels) { var channel = Server.channels[key]; - if(channel.opts.show_public) + if(channel.opts.show_public && channel.opts.password === false) channels.push(getChannelData(channel)); } diff --git a/lib/channel.js b/lib/channel.js index e6af0b23..1c7001ba 100644 --- a/lib/channel.js +++ b/lib/channel.js @@ -99,6 +99,7 @@ var Channel = function(name) { }, show_public: false, enable_link_regex: true, + password: false }; self.filters = [ new Filter("monospace", "`([^`]+)`", "g", "$1"), @@ -800,23 +801,51 @@ Channel.prototype.search = function(query, callback) { /* REGION User interaction */ +Channel.prototype.addPendingJoin = function (user, password) { + var self = this; + if (!("pendingJoins" in self)) { + self.pendingJoins = []; + } + for (var i = 0; i < self.pendingJoins.length; i++) { + if (self.pendingJoins[i].user === user) { + return; + } + } + self.pendingJoins.push({ + user: user, + pw: password + }); +}; + Channel.prototype.handlePendingJoins = function () { var self = this; self.pendingJoins.forEach(function (u) { - self.userJoin(u); + self.userJoin(u.user, u.pw); }); delete self["pendingJoins"]; }; -Channel.prototype.userJoin = function(user) { +Channel.prototype.userJoin = function(user, password) { var self = this; if (!self.ready) { - if (!("pendingJoins" in self)) { - self.pendingJoins = []; - } - self.pendingJoins.push(user); + self.addPendingJoin(user, password); return; } + + if (this.opts.password !== false && + this.opts.password !== password && + user.rank < 2) { + user.socket.emit("needPassword", password !== undefined && + this.opts.password !== password); + return; + } + + user.channel = this; + if (("pendingChannel" in user)) { + user.socket.emit("cancelNeedPassword"); + delete user["pendingChannel"]; + } + var parts = user.ip.split("."); var slash24 = parts[0] + "." + parts[1] + "." + parts[2]; // GTFO @@ -2117,7 +2146,8 @@ Channel.prototype.tryUpdateOptions = function(user, data) { pagetitle: true, externalcss: true, externaljs: true, - show_public: true + show_public: true, + password: true }; if ("allow_voteskip" in data) { @@ -2198,6 +2228,12 @@ Channel.prototype.tryUpdateOptions = function(user, data) { this.opts.enable_link_regex = Boolean(data.enable_link_regex); } + if ("password" in data && user.rank >= 3) { + var pw = data.password+""; + pw = pw === "" ? false : pw; + this.opts.password = pw; + } + this.logger.log("%%% " + user.name + " updated channel options"); this.broadcastOpts(); } diff --git a/lib/user.js b/lib/user.js index 5810931e..0fe5872d 100644 --- a/lib/user.js +++ b/lib/user.js @@ -28,6 +28,7 @@ var User = function (socket) { this.rank = -1 this.global_rank = -1; this.channel = null; + this.pendingChannel = null; this.name = ""; this.meta = { afk: false, @@ -54,6 +55,10 @@ User.prototype.inChannel = function () { return this.channel !== null && !this.channel.dead; }; +User.prototype.inPendingChannel = function () { + return this.pendingChannel != null && !this.pendingChannel.dead; +}; + // Throttling/cooldown User.prototype.noflood = function (name, hz) { var time = new Date().getTime(); @@ -144,7 +149,7 @@ User.prototype.initCallbacks = function () { self.socket.on("joinChannel", function (data) { data = (typeof data !== "object") ? {} : data; - if (self.inChannel()) + if (self.inChannel() || self.inPendingChannel()) return; if (typeof data.name != "string") { return; @@ -158,14 +163,21 @@ User.prototype.initCallbacks = function () { return; } data.name = data.name.toLowerCase(); - self.channel = self.server.getChannel(data.name); + self.pendingChannel = self.server.getChannel(data.name); if (self.loggedIn) { - self.channel.getRank(self.name, function (err, rank) { + // TODO fix + self.pendingChannel.getRank(self.name, function (err, rank) { if (!err && rank > self.rank) self.rank = rank; }); } - self.channel.userJoin(self); + self.pendingChannel.userJoin(self); + }); + + self.socket.on("channelPassword", function (pw) { + if (!self.inChannel() && self.inPendingChannel()) { + self.pendingChannel.userJoin(self, pw); + } }); self.socket.on("login", function (data) { @@ -755,10 +767,13 @@ User.prototype.login = function (name, pw, session) { self.channel.logger.log(self.ip + " logged in as " + name); self.channel.broadcastNewUser(self); + } else if (self.inPendingChannel()) { + self.pendingChannel.userJoin(self); } }; - if (self.inChannel()) { - self.channel.getRank(name, function (err, rank) { + if (self.inChannel() || self.inPendingChannel()) { + var chan = self.channel != null ? self.channel : self.pendingChannel; + chan.getRank(name, function (err, rank) { if (!err) { self.saverank = true; self.rank = rank; diff --git a/www/assets/js/callbacks.js b/www/assets/js/callbacks.js index 412448ee..08421e02 100644 --- a/www/assets/js/callbacks.js +++ b/www/assets/js/callbacks.js @@ -46,6 +46,9 @@ Callbacks = { socket.emit("joinChannel", { name: CHANNEL.name }); + if (CHANNEL.opts.password) { + socket.emit("channelPassword", CHANNEL.opts.password); + } if(NAME && SESSION) { socket.emit("login", { name: NAME, @@ -127,26 +130,44 @@ Callbacks = { scrollChat(); }, + needPassword: function (wrongpw) { + var div = $("
"); + $("").text("Channel Password") + .appendTo(div); + if (wrongpw) { + $("
").appendTo(div); + $("").addClass("text-error") + .text("Wrong Password") + .appendTo(div); + } + + var pwbox = $("").addClass("input-block-level") + .attr("type", "password") + .appendTo(div); + var submit = $("