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 = $("