mirror of https://github.com/calzoneman/sync.git
Work on banlist
This commit is contained in:
parent
501a22556a
commit
637ece4044
|
@ -97,8 +97,6 @@ function Channel(name) {
|
|||
html: "" // Filtered MOTD text (XSS removed; \n replaced by <br>)
|
||||
};
|
||||
self.filters = DEFAULT_FILTERS;
|
||||
self.ipbans = {};
|
||||
self.namebans = {};
|
||||
self.logger = new Logger.Logger(path.join(__dirname, "../chanlogs",
|
||||
self.uniqueName + ".log"));
|
||||
self.css = ""; // Up to 20KB of inline CSS
|
||||
|
@ -442,19 +440,9 @@ Channel.prototype.getIPRank = function (ip, callback) {
|
|||
*/
|
||||
Channel.prototype.join = function (user, password) {
|
||||
var self = this;
|
||||
self.whenReady(function () {
|
||||
if (self.opts.password !== false && user.rank < 2) {
|
||||
if (password !== self.opts.password) {
|
||||
user.socket.emit("needPassword", typeof password === "undefined");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
user.socket.emit("cancelNeedPassword");
|
||||
var range = user.ip.replace(/(\d+)\.(\d+)\.(\d+)\.(\d+)/, "$1.$2.$3");
|
||||
if (user.ip in self.ipbans || range in self.ipbans ||
|
||||
user.name.toLowerCase() in self.namebans) {
|
||||
user.kick("You're banned!");
|
||||
var afterIPBanCheck = function () {
|
||||
if (self.dead) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -467,27 +455,12 @@ Channel.prototype.join = function (user, password) {
|
|||
self.sendUsercount(self.users);
|
||||
|
||||
user.whenLoggedIn(function () {
|
||||
var lname = user.name.toLowerCase();
|
||||
for (var i = 0; i < self.users.length; i++) {
|
||||
if (self.users[i].name.toLowerCase() === lname && self.users[i] !== user) {
|
||||
self.users[i].kick("Duplicate login");
|
||||
}
|
||||
}
|
||||
|
||||
self.getRank(user.name, function (err, rank) {
|
||||
if (self.dead) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
user.rank = user.global_rank;
|
||||
db.channels.isNameBanned(self.name, user.name, function (err, banned) {
|
||||
if (!err && banned) {
|
||||
user.kick("You're banned!");
|
||||
} else {
|
||||
user.rank = Math.max(rank, user.global_rank);
|
||||
afterLogin();
|
||||
}
|
||||
|
||||
user.socket.emit("rank", user.rank);
|
||||
self.sendUserJoin(self.users, user);
|
||||
self.sendUserlist([user]);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -505,6 +478,50 @@ Channel.prototype.join = function (user, password) {
|
|||
|
||||
self.logger.log("+++ " + user.ip + " joined");
|
||||
Logger.syslog.log(user.ip + " joined channel " + self.name);
|
||||
};
|
||||
|
||||
var afterLogin = function () {
|
||||
if (self.dead) {
|
||||
return;
|
||||
}
|
||||
|
||||
var lname = user.name.toLowerCase();
|
||||
for (var i = 0; i < self.users.length; i++) {
|
||||
if (self.users[i].name.toLowerCase() === lname && self.users[i] !== user) {
|
||||
self.users[i].kick("Duplicate login");
|
||||
}
|
||||
}
|
||||
|
||||
self.getRank(user.name, function (err, rank) {
|
||||
if (err) {
|
||||
user.rank = user.global_rank;
|
||||
} else {
|
||||
user.rank = Math.max(rank, user.global_rank);
|
||||
}
|
||||
|
||||
user.socket.emit("rank", user.rank);
|
||||
self.sendUserJoin(self.users, user);
|
||||
self.sendUserlist([user]);
|
||||
});
|
||||
};
|
||||
|
||||
self.whenReady(function () {
|
||||
if (self.opts.password !== false && user.rank < 2) {
|
||||
if (password !== self.opts.password) {
|
||||
user.socket.emit("needPassword", typeof password === "undefined");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
user.socket.emit("cancelNeedPassword");
|
||||
db.channels.isIPBanned(self.name, user.ip, function (err, banned) {
|
||||
if (!err && banned) {
|
||||
user.kick("You're banned!");
|
||||
return;
|
||||
} else {
|
||||
afterIPBanCheck();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -622,6 +639,13 @@ Channel.prototype.handleNameBan = function (actor, name, reason) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!self.registered) {
|
||||
actor.socket.emit("errorMsg", {
|
||||
msg: "Banning is only supported in registered channels"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
name = name.toLowerCase();
|
||||
if (name == actor.name.toLowerCase()) {
|
||||
actor.socket.emit("costanza", {
|
||||
|
@ -655,12 +679,6 @@ Channel.prototype.handleNameBan = function (actor, name, reason) {
|
|||
}
|
||||
|
||||
reason = reason.substring(0, 255);
|
||||
self.namebans[name] = {
|
||||
ip: "*",
|
||||
name: name,
|
||||
bannedby: actor.name,
|
||||
reason: reason
|
||||
};
|
||||
|
||||
// If in the channel already, kick the banned user
|
||||
for (var i = 0; i < self.users.length; i++) {
|
||||
|
@ -672,7 +690,15 @@ Channel.prototype.handleNameBan = function (actor, name, reason) {
|
|||
self.logger.log("*** " + actor.name + " namebanned " + name);
|
||||
self.sendModMessage(actor.name + " banned " + name, self.permissions.ban);
|
||||
|
||||
if (!self.registered) {
|
||||
db.channels.isNameBanned(self.name, name, function (err, banned) {
|
||||
if (!err && banned) {
|
||||
actor.socket.emit("errorMsg", {
|
||||
msg: name + " is already banned"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.dead) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -680,6 +706,7 @@ Channel.prototype.handleNameBan = function (actor, name, reason) {
|
|||
db.channels.ban(self.name, "*", name, reason, actor.name);
|
||||
// TODO send banlist?
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -690,18 +717,65 @@ Channel.prototype.handleUnbanName = function (actor, name) {
|
|||
return;
|
||||
}
|
||||
|
||||
delete this.namebans[name];
|
||||
this.logger.log("*** " + actor.name + " un-namebanned " + name);
|
||||
this.sendModMessage(actor.name + " unbanned " + name, this.permissions.ban);
|
||||
|
||||
if (!this.registered) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log("*** " + actor.name + " un-namebanned " + name);
|
||||
this.sendModMessage(actor.name + " unbanned " + name, this.permissions.ban);
|
||||
|
||||
db.channels.unbanName(this.name, name);
|
||||
// TODO send banlist?
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes a ban by ID
|
||||
*/
|
||||
Channel.prototype.handleUnban = function (actor, data) {
|
||||
var self = this;
|
||||
if (!this.hasPermission(actor, "ban")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof data.id !== "number") {
|
||||
data.id = parseInt(data.id);
|
||||
if (isNaN(data.id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
data.actor = actor.name;
|
||||
|
||||
if (!self.registered) {
|
||||
return;
|
||||
}
|
||||
|
||||
db.channels.unbanId(self.name, data.id, function (err, res) {
|
||||
if (err) {
|
||||
actor.socket.emit("errorMsg", {
|
||||
msg: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
self.sendUnban(self.users, data);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends an unban packet
|
||||
*/
|
||||
Channel.prototype.sendUnban = function (users, data) {
|
||||
var self = this;
|
||||
users.forEach(function (u) {
|
||||
if (self.hasPermission(u, "ban")) {
|
||||
u.socket.emit("banlistRemove", data);
|
||||
}
|
||||
});
|
||||
self.logger.log("*** " + data.actor + " unbanned " + data.name);
|
||||
self.sendModMessage(data.actor + " unbanned " + data.name, self.permissions.ban);
|
||||
};
|
||||
|
||||
/**
|
||||
* Bans all IP addresses associated with a username
|
||||
*/
|
||||
|
@ -715,6 +789,13 @@ Channel.prototype.handleBanAllIP = function (actor, name, reason, range) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!self.registered) {
|
||||
actor.socket.emit("errorMsg", {
|
||||
msg: "Banning is not supported for unregistered rooms"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
name = name.toLowerCase();
|
||||
if (name === actor.name.toLowerCase()) {
|
||||
actor.socket.emit("costanza", {
|
||||
|
@ -774,13 +855,6 @@ Channel.prototype.banIP = function (actor, ip, name, reason, range) {
|
|||
return;
|
||||
}
|
||||
|
||||
self.ipbans[ip] = {
|
||||
ip: ip,
|
||||
name: name,
|
||||
bannedby: actor.name,
|
||||
reason: reason
|
||||
};
|
||||
|
||||
self.logger.log("*** " + actor.name + " banned " + ip + " (" + name + ")");
|
||||
self.sendModMessage(actor.name + " banned " + ip + " (" + name + ")", self.permissions.ban);
|
||||
// If in the channel already, kick the banned user
|
||||
|
@ -795,30 +869,25 @@ Channel.prototype.banIP = function (actor, ip, name, reason, range) {
|
|||
return;
|
||||
}
|
||||
|
||||
db.channels.isIPBanned(self.name, ip, function (err, banned) {
|
||||
if (!err && banned) {
|
||||
var disp = actor.global_rank >= 255 ? ip : util.maskIP(ip);
|
||||
actor.socket.emit("errorMsg", {
|
||||
msg: disp + " is alraedy banned"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.dead) {
|
||||
return;
|
||||
}
|
||||
|
||||
// channel, ip, name, reason, ban actor
|
||||
db.channels.ban(self.name, ip, name, reason, actor.name);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes an IP ban
|
||||
*/
|
||||
Channel.prototype.handleUnbanIP = function (actor, ip) {
|
||||
if (!this.hasPermission(actor, "ban")) {
|
||||
return;
|
||||
}
|
||||
|
||||
var record = this.ipbans[ip];
|
||||
delete this.ipbans[ip];
|
||||
this.logger.log("*** " + actor.name + " unbanned " + ip + " (" + record.name + ")");
|
||||
this.sendModMessage(actor.name + " unbanned " + util.maskIP(ip) + " (" + record.name + ")", this.permissions.ban);
|
||||
|
||||
if (!this.registered) {
|
||||
return;
|
||||
}
|
||||
|
||||
db.channels.unbanIP(this.name, ip);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends the banlist
|
||||
|
@ -828,33 +897,27 @@ Channel.prototype.sendBanlist = function (users) {
|
|||
|
||||
var bans = [];
|
||||
var unmaskedbans = [];
|
||||
for (var ip in self.ipbans) {
|
||||
bans.push({
|
||||
ip: util.maskIP(ip),
|
||||
name: self.ipbans[ip].name,
|
||||
reason: self.ipbans[ip].reason,
|
||||
bannedby: self.ipbans[ip].bannedby
|
||||
});
|
||||
unmaskedbans.push({
|
||||
ip: ip,
|
||||
name: self.ipbans[ip].name,
|
||||
reason: self.ipbans[ip].reason,
|
||||
bannedby: self.ipbans[ip].bannedby
|
||||
});
|
||||
db.channels.listBans(self.name, function (err, banlist) {
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var name in self.namebans) {
|
||||
console.log(banlist);
|
||||
|
||||
for (var i = 0; i < banlist.length; i++) {
|
||||
bans.push({
|
||||
ip: "*",
|
||||
name: name,
|
||||
reason: self.namebans[name].reason,
|
||||
bannedby: self.namebans[name].bannedby
|
||||
id: banlist[i].id,
|
||||
ip: banlist[i].ip === "*" ? "*" : util.maskIP(banlist[i].ip),
|
||||
name: banlist[i].name,
|
||||
reason: banlist[i].reason,
|
||||
bannedby: banlist[i].bannedby
|
||||
});
|
||||
unmaskedbans.push({
|
||||
ip: "*",
|
||||
name: name,
|
||||
reason: self.namebans[name].reason,
|
||||
bannedby: self.namebans[name].bannedby
|
||||
id: banlist[i].id,
|
||||
ip: banlist[i].ip,
|
||||
name: banlist[i].name,
|
||||
reason: banlist[i].reason,
|
||||
bannedby: banlist[i].bannedby
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -869,6 +932,7 @@ Channel.prototype.sendBanlist = function (users) {
|
|||
u.socket.emit("banlist", bans);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1122,11 +1186,6 @@ Channel.prototype.sendUserJoin = function (users, user) {
|
|||
|
||||
user.meta.aliases = aliases;
|
||||
|
||||
if (user.name.toLowerCase() in self.namebans) {
|
||||
user.kick("You're banned!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.isShadowMuted(user.name)) {
|
||||
user.meta.muted = true;
|
||||
user.meta.shadowmuted = true;
|
||||
|
|
|
@ -27,11 +27,12 @@ function createLibraryTable(name, callback) {
|
|||
|
||||
function createBansTable(name, callback) {
|
||||
db.query("CREATE TABLE `chan_" + name + "_bans` (" +
|
||||
"`id` INT NOT NULL AUTO_INCREMENT," +
|
||||
"`ip` VARCHAR(39) NOT NULL," +
|
||||
"`name` VARCHAR(20) NOT NULL," +
|
||||
"`bannedby` VARCHAR(20) NOT NULL," +
|
||||
"`reason` VARCHAR(255) NOT NULL," +
|
||||
"PRIMARY KEY (`ip`, `name`))" +
|
||||
"PRIMARY KEY (`id`), UNIQUE (`name`, `ip`))" +
|
||||
"CHARACTER SET utf8", callback);
|
||||
}
|
||||
|
||||
|
@ -311,32 +312,9 @@ module.exports = {
|
|||
chan.name = res[0].name;
|
||||
chan.canonical_name = chan.name.toLowerCase();
|
||||
chan.registered = true;
|
||||
|
||||
// Load bans
|
||||
db.query("SELECT * FROM `chan_" + chan.name + "_bans`", function (err, rows) {
|
||||
if (chan.dead) {
|
||||
callback("Channel is dead", null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var r = rows[i];
|
||||
if (r.ip === "*") {
|
||||
chan.namebans[r.name] = r;
|
||||
} else {
|
||||
chan.ipbans[r.ip] = r;
|
||||
}
|
||||
}
|
||||
|
||||
chan.logger.log("*** Loaded channel from database");
|
||||
callback(null, true);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -557,6 +535,60 @@ module.exports = {
|
|||
"VALUES (?, ?, ?, ?)", [ip, name, note, bannedby], callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if an IP address or range is banned
|
||||
*/
|
||||
isIPBanned: function (chan, ip, callback) {
|
||||
if (typeof callback !== "function") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!valid(chan)) {
|
||||
callback("Invalid channel name", null);
|
||||
return;
|
||||
}
|
||||
|
||||
db.query("SELECT * FROM `chan_" + chan + "_bans` WHERE ip LIKE ?", [ip+"%"],
|
||||
function (err, rows) {
|
||||
callback(err, err ? false : rows.length > 0);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if a username is banned
|
||||
*/
|
||||
isNameBanned: function (chan, name, callback) {
|
||||
if (typeof callback !== "function") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!valid(chan)) {
|
||||
callback("Invalid channel name", null);
|
||||
return;
|
||||
}
|
||||
|
||||
db.query("SELECT * FROM `chan_" + chan + "_bans` WHERE name=?", [name],
|
||||
function (err, rows) {
|
||||
callback(err, err ? false : rows.length > 0);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Lists all bans
|
||||
*/
|
||||
listBans: function (chan, callback) {
|
||||
if (typeof callback !== "function") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!valid(chan)) {
|
||||
callback("Invalid channel name", null);
|
||||
return;
|
||||
}
|
||||
|
||||
db.query("SELECT * FROM `chan_" + chan + "_bans` WHERE 1", callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes a ban from the banlist
|
||||
*/
|
||||
|
@ -589,5 +621,22 @@ module.exports = {
|
|||
|
||||
db.query("DELETE FROM `chan_" + chan + "_bans` WHERE ip=?",
|
||||
[ip], callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes a ban from the banlist
|
||||
*/
|
||||
unbanId: function (chan, id, callback) {
|
||||
if (typeof callback !== "function") {
|
||||
callback = blackHole;
|
||||
}
|
||||
|
||||
if (!valid(chan)) {
|
||||
callback("Invalid channel name", null);
|
||||
return;
|
||||
}
|
||||
|
||||
db.query("DELETE FROM `chan_" + chan + "_bans` WHERE id=?",
|
||||
[id], callback);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -227,6 +227,10 @@ User.prototype.initChannelCallbacks = function () {
|
|||
self.channel.handleSetRank(self, data);
|
||||
});
|
||||
|
||||
wrapTypecheck("unban", function (data) {
|
||||
self.channel.handleUnban(self, data);
|
||||
});
|
||||
|
||||
wrapTypecheck("chatMsg", function (data) {
|
||||
if (typeof data.msg !== "string") {
|
||||
return;
|
||||
|
|
|
@ -169,40 +169,11 @@ function addUserDropdown(entry) {
|
|||
$("<strong/>").text(name).appendTo(menu);
|
||||
$("<br/>").appendTo(menu);
|
||||
|
||||
/* rank selector (admin+ only)
|
||||
to prevent odd behaviour, this selector is only visible
|
||||
when the selected user has a normal rank (e.g. not a guest
|
||||
or a non-moderator leader
|
||||
*/
|
||||
if(CLIENT.rank >= 3 && CLIENT.rank > rank && rank > 0 && rank != 1.5) {
|
||||
var sel = $("<select/>")
|
||||
.addClass("form-control")
|
||||
.appendTo(menu);
|
||||
$("<option/>").attr("value", "1").text("Regular User")
|
||||
.appendTo(sel);
|
||||
$("<option/>").attr("value", "2").text("Moderator")
|
||||
.appendTo(sel);
|
||||
if(CLIENT.rank > 3) {
|
||||
$("<option/>").attr("value", "3").text("Channel Admin")
|
||||
.appendTo(sel);
|
||||
if(rank > 3) {
|
||||
$("<option/>").attr("value", ""+rank)
|
||||
.text("Current Rank (" + rank + ")")
|
||||
.appendTo(sel);
|
||||
}
|
||||
}
|
||||
sel.change(function () {
|
||||
socket.emit("setChannelRank", {
|
||||
user: name,
|
||||
rank: parseInt(sel.val())
|
||||
});
|
||||
});
|
||||
sel.val(""+rank);
|
||||
}
|
||||
var btngroup = $("<div/>").addClass("btn-group-vertical").appendTo(menu);
|
||||
|
||||
/* ignore button */
|
||||
var ignore = $("<button/>").addClass("btn btn-xs btn-default btn-block")
|
||||
.appendTo(menu)
|
||||
var ignore = $("<button/>").addClass("btn btn-xs btn-default")
|
||||
.appendTo(btngroup)
|
||||
.click(function () {
|
||||
if(IGNORED.indexOf(name) == -1) {
|
||||
ignore.text("Unignore User");
|
||||
|
@ -220,8 +191,8 @@ function addUserDropdown(entry) {
|
|||
|
||||
/* gib/remove leader (moderator+ only) */
|
||||
if(CLIENT.rank >= 2) {
|
||||
var ldr = $("<button/>").addClass("btn btn-xs btn-default btn-block")
|
||||
.appendTo(menu);
|
||||
var ldr = $("<button/>").addClass("btn btn-xs btn-default")
|
||||
.appendTo(btngroup);
|
||||
if(leader) {
|
||||
ldr.text("Remove Leader");
|
||||
ldr.click(function () {
|
||||
|
@ -241,34 +212,34 @@ function addUserDropdown(entry) {
|
|||
|
||||
/* kick button */
|
||||
if(hasPermission("kick")) {
|
||||
$("<button/>").addClass("btn btn-xs btn-default btn-block")
|
||||
$("<button/>").addClass("btn btn-xs btn-default")
|
||||
.text("Kick")
|
||||
.click(function () {
|
||||
socket.emit("chatMsg", {
|
||||
msg: "/kick " + name
|
||||
});
|
||||
})
|
||||
.appendTo(menu);
|
||||
.appendTo(btngroup);
|
||||
}
|
||||
|
||||
/* ban buttons */
|
||||
if(hasPermission("ban")) {
|
||||
$("<button/>").addClass("btn btn-xs btn-default btn-block")
|
||||
$("<button/>").addClass("btn btn-xs btn-default")
|
||||
.text("Name Ban")
|
||||
.click(function () {
|
||||
socket.emit("chatMsg", {
|
||||
msg: "/ban " + name
|
||||
});
|
||||
})
|
||||
.appendTo(menu);
|
||||
$("<button/>").addClass("btn btn-xs btn-default btn-block")
|
||||
.appendTo(btngroup);
|
||||
$("<button/>").addClass("btn btn-xs btn-default")
|
||||
.text("IP Ban")
|
||||
.click(function () {
|
||||
socket.emit("chatMsg", {
|
||||
msg: "/ipban " + name
|
||||
});
|
||||
})
|
||||
.appendTo(menu);
|
||||
.appendTo(btngroup);
|
||||
}
|
||||
|
||||
entry.contextmenu(function(ev) {
|
||||
|
@ -1798,6 +1769,12 @@ function formatCSBanlist() {
|
|||
}
|
||||
var unban = $("<button/>").addClass("btn btn-xs btn-danger")
|
||||
.appendTo($("<td/>").appendTo(tr));
|
||||
unban.click(function () {
|
||||
socket.emit("unban", {
|
||||
id: entry.id,
|
||||
name: entry.name
|
||||
});
|
||||
});
|
||||
$("<span/>").addClass("glyphicon glyphicon-remove-circle").appendTo(unban);
|
||||
$("<td/>").text(entry.ip).appendTo(tr);
|
||||
$("<td/>").text(entry.name).appendTo(tr);
|
||||
|
|
Loading…
Reference in New Issue