Improve strictness of data checking

This commit is contained in:
calzoneman 2013-10-12 18:59:50 -05:00
parent 51d89b99e8
commit 2744b3a20d
3 changed files with 136 additions and 52 deletions

View File

@ -1,3 +1,8 @@
Sat Oct 12 18:58 2013 CDT
* lib/user.js, lib/channel.js: Improve strictness of data checking
to prevent errors from incoming bad data. Kick users who send
bad data or attempt channel moderation with insufficient rank.
Sat Oct 12 18:24 2013 CDT Sat Oct 12 18:24 2013 CDT
* lib/user.js: Fix bad chatMsg packet causing exceptions * lib/user.js: Fix bad chatMsg packet causing exceptions

View File

@ -362,8 +362,10 @@ Channel.prototype.readLog = function (filterIp, callback) {
} }
Channel.prototype.tryReadLog = function (user) { Channel.prototype.tryReadLog = function (user) {
if(user.rank < 3) if(user.rank < 3) {
user.kick("Attempted readChanLog with insufficient permission");
return; return;
}
var filterIp = true; var filterIp = true;
if(user.global_rank >= 255) if(user.global_rank >= 255)
@ -623,6 +625,7 @@ Channel.prototype.tryNameBan = function(actor, name) {
Channel.prototype.unbanName = function(actor, name) { Channel.prototype.unbanName = function(actor, name) {
var self = this; var self = this;
if(!self.hasPermission(actor, "ban")) { if(!self.hasPermission(actor, "ban")) {
actor.kick("Attempted unban with insufficient permission");
return false; return false;
} }
@ -730,8 +733,10 @@ Channel.prototype.tryIPBan = function(actor, name, range) {
Channel.prototype.unbanIP = function(actor, ip) { Channel.prototype.unbanIP = function(actor, ip) {
var self = this; var self = this;
if(!self.hasPermission(actor, "ban")) if(!self.hasPermission(actor, "ban")) {
actor.kick("Attempted unban with insufficient permission");
return false; return false;
}
self.ipbans[ip] = null; self.ipbans[ip] = null;
self.users.forEach(function(u) { self.users.forEach(function(u) {
@ -748,11 +753,11 @@ Channel.prototype.unbanIP = function(actor, ip) {
} }
Channel.prototype.tryUnban = function(actor, data) { Channel.prototype.tryUnban = function(actor, data) {
if(data.ip_hidden) { if(typeof data.ip_hidden === "string") {
var ip = this.hideIP(data.ip_hidden); var ip = this.hideIP(data.ip_hidden);
this.unbanIP(actor, ip); this.unbanIP(actor, ip);
} }
if(data.name) { if(typeof data.name === "string") {
this.unbanName(actor, data.name); this.unbanName(actor, data.name);
} }
} }
@ -1318,9 +1323,11 @@ Channel.prototype.tryQueue = function(user, data) {
return; return;
} }
if(typeof data.pos !== "string") { if(typeof data.pos !== "string") {
user.kick("Bad queue packet");
return; return;
} }
if(typeof data.id !== "string" && data.id !== false) { if(typeof data.id !== "string" && data.id !== false) {
user.kick("Bad queue packet");
return; return;
} }
@ -1580,6 +1587,7 @@ Channel.prototype.tryQueuePlaylist = function(user, data) {
if(typeof data.name !== "string" || if(typeof data.name !== "string" ||
typeof data.pos !== "string") { typeof data.pos !== "string") {
user.kick("Bad queuePlaylist packet");
return; return;
} }
@ -1639,6 +1647,7 @@ Channel.prototype.trySetTemp = function(user, data) {
return; return;
} }
if(typeof data.uid != "number" || typeof data.temp != "boolean") { if(typeof data.uid != "number" || typeof data.temp != "boolean") {
user.kick("Bad setTemp packet");
return; return;
} }
@ -1667,8 +1676,10 @@ Channel.prototype.tryDequeue = function(user, data) {
if(!this.hasPermission(user, "playlistdelete")) if(!this.hasPermission(user, "playlistdelete"))
return; return;
if(typeof data !== "number") if(typeof data !== "number") {
user.kick("Bad delete packet");
return; return;
}
var plitem = this.playlist.items.find(data); var plitem = this.playlist.items.find(data);
if(plitem && plitem.media) if(plitem && plitem.media)
@ -1682,6 +1693,7 @@ Channel.prototype.tryUncache = function(user, data) {
return; return;
} }
if(typeof data.id != "string") { if(typeof data.id != "string") {
user.kick("Bad uncache packet");
return; return;
} }
if (!self.registered) if (!self.registered)
@ -1723,6 +1735,7 @@ Channel.prototype.tryJumpTo = function(user, data) {
} }
if(typeof data !== "number") { if(typeof data !== "number") {
user.kick("Bad jumpTo packet");
return; return;
} }
@ -1776,11 +1789,14 @@ Channel.prototype.tryShufflequeue = function(user) {
Channel.prototype.tryUpdate = function(user, data) { Channel.prototype.tryUpdate = function(user, data) {
if(this.leader != user) { if(this.leader != user) {
user.kick("Received mediaUpdate from non-leader");
return; return;
} }
if(typeof data.id !== "string" || typeof data.currentTime !== "number") if(typeof data.id !== "string" || typeof data.currentTime !== "number") {
return; user.kick("Bad mediaUpdate packet");
return;
}
if(this.playlist.current === null) { if(this.playlist.current === null) {
return; return;
@ -1832,8 +1848,10 @@ Channel.prototype.tryMove = function(user, data) {
return; return;
} }
if(typeof data.from !== "number" || (typeof data.after !== "number" && typeof data.after !== "string")) if(typeof data.from !== "number" || (typeof data.after !== "number" && typeof data.after !== "string")) {
user.kick("Bad moveMedia packet");
return; return;
}
this.move(data, user); this.move(data, user);
} }
@ -1845,7 +1863,8 @@ Channel.prototype.tryOpenPoll = function(user, data) {
return; return;
} }
if(!data.title || !data.opts) { if(typeof data.title !== "string" || !(data.opts instanceof Array)) {
user.kick("Invalid newPoll packet");
return; return;
} }
@ -1878,6 +1897,7 @@ Channel.prototype.tryVote = function(user, data) {
return; return;
} }
if(typeof data.option !== "number") { if(typeof data.option !== "number") {
user.kick("Bad vote packet");
return; return;
} }
@ -1952,8 +1972,10 @@ Channel.prototype.tryToggleLock = function(user) {
} }
Channel.prototype.tryRemoveFilter = function(user, f) { Channel.prototype.tryRemoveFilter = function(user, f) {
if(!this.hasPermission(user, "filteredit")) if(!this.hasPermission(user, "filteredit")) {
return false; user.kick("Attempted removeFilter with insufficient permission");
return;
}
this.logger.log("%%% " + user.name + " removed filter: " + f.name); this.logger.log("%%% " + user.name + " removed filter: " + f.name);
this.removeFilter(f); this.removeFilter(f);
@ -1989,6 +2011,13 @@ Channel.prototype.updateFilter = function(filter, emit) {
Channel.prototype.tryUpdateFilter = function(user, f) { Channel.prototype.tryUpdateFilter = function(user, f) {
if(!this.hasPermission(user, "filteredit")) { if(!this.hasPermission(user, "filteredit")) {
user.kick("Attempted updateFilter with insufficient permission");
return;
}
if (typeof f.source !== "string" || typeof f.flags !== "string" ||
typeof f.replace !== "string") {
user.kick("Bad updateFilter packet");
return; return;
} }
@ -2006,8 +2035,8 @@ Channel.prototype.tryUpdateFilter = function(user, f) {
return; return;
} }
var filter = new Filter(f.name, f.source, f.flags, f.replace); var filter = new Filter(f.name, f.source, f.flags, f.replace);
filter.active = f.active; filter.active = !!f.active;
filter.filterlinks = f.filterlinks; filter.filterlinks = !!f.filterlinks;
this.logger.log("%%% " + user.name + " updated filter: " + f.name); this.logger.log("%%% " + user.name + " updated filter: " + f.name);
this.updateFilter(filter); this.updateFilter(filter);
} }
@ -2026,16 +2055,21 @@ Channel.prototype.moveFilter = function(data) {
} }
Channel.prototype.tryMoveFilter = function(user, data) { Channel.prototype.tryMoveFilter = function(user, data) {
if(!this.hasPermission(user, "filteredit")) if(!this.hasPermission(user, "filteredit")) {
user.kick("Attempted moveFilter with insufficient permission");
return; return;
}
if(typeof data.to !== "number" || typeof data.from !== "number") if(typeof data.to !== "number" || typeof data.from !== "number") {
user.kick("Bad moveFilter packet");
return; return;
}
this.moveFilter(data); this.moveFilter(data);
} }
Channel.prototype.tryUpdatePermissions = function(user, perms) { Channel.prototype.tryUpdatePermissions = function(user, perms) {
if(user.rank < 3) { if(user.rank < 3) {
user.kick("Attempted setPermissions with insufficient permission");
return; return;
} }
for(var key in perms) { for(var key in perms) {
@ -2047,6 +2081,7 @@ Channel.prototype.tryUpdatePermissions = function(user, perms) {
Channel.prototype.tryUpdateOptions = function(user, data) { Channel.prototype.tryUpdateOptions = function(user, data) {
if(user.rank < 2) { if(user.rank < 2) {
user.kick("Attempted setOptions with insufficient permission");
return; return;
} }
@ -2083,9 +2118,14 @@ Channel.prototype.tryUpdateOptions = function(user, data) {
Channel.prototype.trySetCSS = function(user, data) { Channel.prototype.trySetCSS = function(user, data) {
if(user.rank < 3) { if(user.rank < 3) {
user.kick("Attempted setChannelCSS with insufficient permission");
return; return;
} }
if (typeof data.css !== "string") {
user.kick("Bad setChannelCSS packet");
return;
}
var css = data.css || ""; var css = data.css || "";
if(css.length > 20000) { if(css.length > 20000) {
css = css.substring(0, 20000); css = css.substring(0, 20000);
@ -2100,6 +2140,11 @@ Channel.prototype.trySetCSS = function(user, data) {
Channel.prototype.trySetJS = function(user, data) { Channel.prototype.trySetJS = function(user, data) {
if(user.rank < 3) { if(user.rank < 3) {
user.kick("Attempted setChannelJS with insufficient permission");
return;
}
if (typeof data.js !== "string") {
user.kick("Bad setChannelJS packet");
return; return;
} }
@ -2131,6 +2176,12 @@ Channel.prototype.updateMotd = function(motd) {
Channel.prototype.tryUpdateMotd = function(user, data) { Channel.prototype.tryUpdateMotd = function(user, data) {
if(!this.hasPermission(user, "motdedit")) { if(!this.hasPermission(user, "motdedit")) {
user.kick("Attempted setMotd with insufficient permission");
return;
}
if (typeof data.motd !== "string") {
user.kick("Bad setMotd packet");
return; return;
} }
@ -2241,11 +2292,15 @@ Channel.prototype.sendMessage = function(username, msg, msgclass, data) {
Channel.prototype.trySetRank = function(user, data) { Channel.prototype.trySetRank = function(user, data) {
var self = this; var self = this;
if(user.rank < 2) if(user.rank < 2) {
user.kick("Attempted setChannelRank with insufficient permission");
return; return;
}
if(typeof data.user !== "string" || typeof data.rank !== "number") if(typeof data.user !== "string" || typeof data.rank !== "number") {
user.kick("Bad setChannelRank packet");
return; return;
}
if(data.rank >= user.rank) if(data.rank >= user.rank)
return; return;
@ -2337,10 +2392,12 @@ Channel.prototype.changeLeader = function(name) {
Channel.prototype.tryChangeLeader = function(user, data) { Channel.prototype.tryChangeLeader = function(user, data) {
if(user.rank < 2) { if(user.rank < 2) {
user.kick("Attempted assignLeader with insufficient permission");
return; return;
} }
if(data.name == undefined) { if(typeof data.name !== "string") {
user.kick("Bad assignLeader packet");
return; return;
} }

View File

@ -119,6 +119,11 @@ User.prototype.autoAFK = function () {
}, self.channel.opts.afk_timeout * 1000); }, self.channel.opts.afk_timeout * 1000);
}; };
User.prototype.kick = function (reason) {
this.socket.emit("kick", { reason: reason });
this.socket.disconnect(true);
};
User.prototype.initCallbacks = function () { User.prototype.initCallbacks = function () {
var self = this; var self = this;
self.socket.on("disconnect", function () { self.socket.on("disconnect", function () {
@ -128,19 +133,19 @@ User.prototype.initCallbacks = function () {
}); });
self.socket.on("joinChannel", function (data) { self.socket.on("joinChannel", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) if (self.inChannel())
return; return;
if (typeof data.name != "string") if (typeof data.name != "string") {
self.kick("Bad joinChannel packet");
return; return;
}
if (!data.name.match(/^[\w-_]{1,30}$/)) { if (!data.name.match(/^[\w-_]{1,30}$/)) {
self.socket.emit("errorMsg", { self.socket.emit("errorMsg", {
msg: "Invalid channel name. Channel names may consist of"+ msg: "Invalid channel name. Channel names may consist of"+
" 1-30 characters in the set a-z, A-Z, 0-9, -, and _" " 1-30 characters in the set a-z, A-Z, 0-9, -, and _"
}); });
self.socket.emit("kick", { self.kick("Invalid channel name");
reason: "Bad channel name"
});
return; return;
} }
data.name = data.name.toLowerCase(); data.name = data.name.toLowerCase();
@ -156,9 +161,10 @@ User.prototype.initCallbacks = function () {
}); });
self.socket.on("login", function (data) { self.socket.on("login", function (data) {
var name = data.name || ""; data = (typeof data !== "object") ? {} : data;
var pw = data.pw || ""; var name = (typeof data.name === "string") ? data.name : "";
var session = data.session || ""; var pw = (typeof data.pw === "string") ? data.pw : "";
var session = (typeof data.session === "string") ? data.session : "";
if (pw.length > 100) if (pw.length > 100)
pw = pw.substring(0, 100); pw = pw.substring(0, 100);
@ -186,52 +192,32 @@ User.prototype.initCallbacks = function () {
}); });
self.socket.on("assignLeader", function (data) { self.socket.on("assignLeader", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryChangeLeader(self, data); self.channel.tryChangeLeader(self, data);
} }
}); });
self.socket.on("promote", function (data) {
if (self.inChannel()) {
self.channel.tryPromoteUser(self, data);
}
});
self.socket.on("demote", function (data) {
if (self.inChannel()) {
self.channel.tryDemoteUser(self, data);
}
});
self.socket.on("setChannelRank", function (data) { self.socket.on("setChannelRank", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.trySetRank(self, data); self.channel.trySetRank(self, data);
} }
}); });
self.socket.on("banName", function (data) {
if (self.inChannel()) {
self.channel.banName(self, data.name || "");
}
});
self.socket.on("banIP", function (data) {
if (self.inChannel()) {
self.channel.tryIPBan(self, data);
}
});
self.socket.on("unban", function (data) { self.socket.on("unban", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryUnban(self, data); self.channel.tryUnban(self, data);
} }
}); });
self.socket.on("chatMsg", function (data) { self.socket.on("chatMsg", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
if (typeof data.msg !== "string") { if (typeof data.msg !== "string") {
self.socket.emit("kick", { self.socket.emit("kick", {
reason: "Invalid chatMsg packet!" reason: "Invalid chatMsg packet"
}); });
self.socket.disconnect(true); self.socket.disconnect(true);
return; return;
@ -245,6 +231,7 @@ User.prototype.initCallbacks = function () {
}); });
self.socket.on("newPoll", function (data) { self.socket.on("newPoll", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryOpenPoll(self, data); self.channel.tryOpenPoll(self, data);
} }
@ -263,36 +250,42 @@ User.prototype.initCallbacks = function () {
}); });
self.socket.on("queue", function (data) { self.socket.on("queue", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryQueue(self, data); self.channel.tryQueue(self, data);
} }
}); });
self.socket.on("setTemp", function (data) { self.socket.on("setTemp", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.trySetTemp(self, data); self.channel.trySetTemp(self, data);
} }
}); });
self.socket.on("delete", function (data) { self.socket.on("delete", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryDequeue(self, data); self.channel.tryDequeue(self, data);
} }
}); });
self.socket.on("uncache", function (data) { self.socket.on("uncache", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryUncache(self, data); self.channel.tryUncache(self, data);
} }
}); });
self.socket.on("moveMedia", function (data) { self.socket.on("moveMedia", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryMove(self, data); self.channel.tryMove(self, data);
} }
}); });
self.socket.on("jumpTo", function (data) { self.socket.on("jumpTo", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryJumpTo(self, data); self.channel.tryJumpTo(self, data);
} }
@ -323,14 +316,20 @@ User.prototype.initCallbacks = function () {
}); });
self.socket.on("mediaUpdate", function (data) { self.socket.on("mediaUpdate", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryUpdate(self, data); self.channel.tryUpdate(self, data);
} }
}); });
self.socket.on("searchMedia", function (data) { self.socket.on("searchMedia", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
if (data.source == "yt") { if (typeof data.query !== "string") {
self.kick("Bad searchMedia packet");
return;
}
if (data.source === "yt") {
var searchfn = InfoGetter.Getters.ytSearch; var searchfn = InfoGetter.Getters.ytSearch;
searchfn(data.query.split(" "), function (e, vids) { searchfn(data.query.split(" "), function (e, vids) {
if (!e) { if (!e) {
@ -358,6 +357,7 @@ User.prototype.initCallbacks = function () {
}); });
self.socket.on("vote", function (data) { self.socket.on("vote", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryVote(self, data); self.channel.tryVote(self, data);
} }
@ -378,52 +378,64 @@ User.prototype.initCallbacks = function () {
if (!self.inChannel()) { if (!self.inChannel()) {
return; return;
} }
if (self.rank < 10) {
self.kick("Attempted unregisterChannel with insufficient permission");
return;
}
self.channel.unregister(self); self.channel.unregister(self);
}); });
self.socket.on("setOptions", function (data) { self.socket.on("setOptions", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryUpdateOptions(self, data); self.channel.tryUpdateOptions(self, data);
} }
}); });
self.socket.on("setPermissions", function (data) { self.socket.on("setPermissions", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryUpdatePermissions(self, data); self.channel.tryUpdatePermissions(self, data);
} }
}); });
self.socket.on("setChannelCSS", function (data) { self.socket.on("setChannelCSS", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.trySetCSS(self, data); self.channel.trySetCSS(self, data);
} }
}); });
self.socket.on("setChannelJS", function (data) { self.socket.on("setChannelJS", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.trySetJS(self, data); self.channel.trySetJS(self, data);
} }
}); });
self.socket.on("updateFilter", function (data) { self.socket.on("updateFilter", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryUpdateFilter(self, data); self.channel.tryUpdateFilter(self, data);
} }
}); });
self.socket.on("removeFilter", function (data) { self.socket.on("removeFilter", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryRemoveFilter(self, data); self.channel.tryRemoveFilter(self, data);
} }
}); });
self.socket.on("moveFilter", function (data) { self.socket.on("moveFilter", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryMoveFilter(self, data); self.channel.tryMoveFilter(self, data);
} }
}); });
self.socket.on("setMotd", function (data) { self.socket.on("setMotd", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryUpdateMotd(self, data); self.channel.tryUpdateMotd(self, data);
} }
@ -456,12 +468,14 @@ User.prototype.initCallbacks = function () {
}); });
self.socket.on("voteskip", function (data) { self.socket.on("voteskip", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryVoteskip(self); self.channel.tryVoteskip(self);
} }
}); });
self.socket.on("listPlaylists", function (data) { self.socket.on("listPlaylists", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.name === "" || self.rank < 1) { if (self.name === "" || self.rank < 1) {
self.socket.emit("listPlaylists", { self.socket.emit("listPlaylists", {
pllist: [], pllist: [],
@ -483,6 +497,11 @@ User.prototype.initCallbacks = function () {
}); });
self.socket.on("savePlaylist", function (data) { self.socket.on("savePlaylist", function (data) {
data = (typeof data !== "object") ? {} : data;
if (typeof data.name !== "string") {
self.kick("Bad savePlaylist packet");
return;
}
if (self.rank < 1) { if (self.rank < 1) {
self.socket.emit("savePlaylist", { self.socket.emit("savePlaylist", {
success: false, success: false,
@ -533,13 +552,16 @@ User.prototype.initCallbacks = function () {
}); });
self.socket.on("queuePlaylist", function (data) { self.socket.on("queuePlaylist", function (data) {
data = (typeof data !== "object") ? {} : data;
if (self.inChannel()) { if (self.inChannel()) {
self.channel.tryQueuePlaylist(self, data); self.channel.tryQueuePlaylist(self, data);
} }
}); });
self.socket.on("deletePlaylist", function (data) { self.socket.on("deletePlaylist", function (data) {
data = (typeof data !== "object") ? {} : data;
if (typeof data.name != "string") { if (typeof data.name != "string") {
self.kick("Bad deletePlaylist packet");
return; return;
} }