Banlist and recent login history

This commit is contained in:
Calvin Montgomery 2013-06-17 23:57:29 -04:00
parent 32af68a68e
commit 449d01180a
7 changed files with 222 additions and 126 deletions

View File

@ -93,7 +93,9 @@ var Channel = function(name) {
};
this.ipbans = {};
this.namebans = {};
this.logins = {};
this.ip_alias = {};
this.name_alias = {};
this.login_hist = [];
this.logger = new Logger.Logger("chanlogs/" + this.name + ".log");
this.i = 0;
this.time = new Date().getTime();
@ -205,10 +207,6 @@ Channel.prototype.loadDump = function() {
this.motd = data.motd;
this.broadcastMotd();
}
data.logins = data.logins || {};
for(var ip in data.logins) {
this.logins[ip] = data.logins[ip];
}
this.setLock(!(data.openqueue || false));
this.chatbuffer = data.chatbuffer || [];
for(var i = 0; i < this.chatbuffer.length; i++) {
@ -242,7 +240,6 @@ Channel.prototype.saveDump = function() {
permissions: this.permissions,
filters: filts,
motd: this.motd,
logins: this.logins,
openqueue: this.openqueue,
chatbuffer: this.chatbuffer,
css: this.css,
@ -323,11 +320,9 @@ Channel.prototype.saveRank = function(user) {
Channel.prototype.getIPRank = function(ip) {
var names = [];
if(this.logins[ip] === undefined || this.logins[ip].length == 0) {
return 0;
}
this.logins[ip].forEach(function(name) {
if(!(ip in this.ip_alias))
this.ip_alias = Database.getAliases(ip);
this.ip_alias[ip].forEach(function(name) {
names.push(name);
});
@ -339,16 +334,6 @@ Channel.prototype.getIPRank = function(ip) {
return rank;
}
Channel.prototype.seen = function(ip, name) {
name = name.toLowerCase();
for(var i = 0; i < this.logins[ip].length; i++) {
if(this.logins[ip][i].toLowerCase() == name) {
return true;
}
}
return false;
}
Channel.prototype.cacheMedia = function(media) {
// Prevent the copy in the playlist from messing with this one
media = media.dup();
@ -362,7 +347,7 @@ Channel.prototype.cacheMedia = function(media) {
return false;
}
Channel.prototype.banName = function(actor, name) {
Channel.prototype.tryNameBan = function(actor, name) {
if(!this.hasPermission(actor, "ban")) {
return false;
}
@ -370,11 +355,6 @@ Channel.prototype.banName = function(actor, name) {
name = name.toLowerCase();
var rank = this.getRank(name);
if(rank < 1) {
actor.socket.emit("errorMsg", {msg: "You can't ban guest names. Use a kick or IP ban."});
return false;
}
if(rank >= actor.rank) {
actor.socket.emit("errorMsg", {msg: "You don't have permission to ban this person."});
return false;
@ -409,47 +389,47 @@ Channel.prototype.unbanName = function(actor, name) {
return Database.channelUnbanName(this.name, name);
}
Channel.prototype.tryIPBan = function(actor, data) {
Channel.prototype.tryIPBan = function(actor, name, range) {
if(!this.hasPermission(actor, "ban")) {
return false;
}
if(typeof data.id != "string") {
return false;
}
if(typeof data.name != "string") {
return false;
}
var ip = this.hideIP(data.id);
if(this.getIPRank(ip) >= actor.rank) {
actor.socket.emit("errorMsg", {msg: "You don't have permission to ban this IP"});
if(typeof name != "string") {
return false;
}
var ips = Database.ipForName(name);
var chan = this;
ips.forEach(function(ip) {
if(chan.getIPRank(ip) >= actor.rank) {
actor.socket.emit("errorMsg", {msg: "You don't have permission to ban IP: x.x." + ip.replace(/\d+\.\d+\.(\d+\.\d+)/, "$1")});
return false;
}
if(data.range) {
ip = ip.replace(/(\d+)\.(\d+)\.(\d+)\.(\d+)/, "$1.$2.$3");
for(var ip2 in this.logins) {
if(ip2.indexOf(ip) == 0 && this.getIPRank(ip2) >= actor.rank) {
actor.socket.emit("errorMsg", {msg: "You don't have permission to ban this IP"});
return false;
if(range) {
ip = ip.replace(/(\d+)\.(\d+)\.(\d+)\.(\d+)/, "$1.$2.$3");
for(var ip2 in chan.ip_alias) {
if(ip2.indexOf(ip) == 0 && chan.getIPRank(ip2) >= actor.rank) {
actor.socket.emit("errorMsg", {msg: "You don't have permission to ban IP: x.x." + ip2.replace(/\d+\.\d+\.(\d+\.\d+)/, "$1")});
return false;
}
}
}
}
this.ipbans[ip] = [data.name, actor.name];
this.broadcastBanlist();
this.logger.log(ip + " (" + data.name + ") was banned by " + actor.name);
chan.ipbans[ip] = [name, actor.name];
chan.broadcastBanlist();
chan.logger.log(ip + " (" + name + ") was banned by " + actor.name);
for(var i = 0; i < this.users.length; i++) {
if(this.users[i].ip.indexOf(ip) == 0) {
this.kick(this.users[i], "Your IP is banned!");
i--;
for(var i = 0; i < chan.users.length; i++) {
if(chan.users[i].ip.indexOf(ip) == 0) {
chan.kick(chan.users[i], "Your IP is banned!");
i--;
}
}
}
if(!this.registered)
return false;
if(!chan.registered)
return false;
// Update database ban table
return Database.channelBan(this.name, ip, data.name, actor.name);
// Update database ban table
return Database.channelBan(chan.name, ip, name, actor.name);
});
}
Channel.prototype.banIP = function(actor, receiver) {
@ -488,8 +468,8 @@ Channel.prototype.unbanIP = function(actor, ip) {
}
Channel.prototype.tryUnban = function(actor, data) {
if(data.id) {
var ip = this.hideIP(data.id);
if(data.ip_hidden) {
var ip = this.hideIP(data.ip_hidden);
this.unbanIP(actor, ip);
}
else if(data.name) {
@ -531,9 +511,6 @@ Channel.prototype.search = function(query, callback) {
/* REGION User interaction */
Channel.prototype.userJoin = function(user) {
if(!(user.ip in this.logins)) {
this.logins[user.ip] = [];
}
var parts = user.ip.split(".");
var slash24 = parts[0] + "." + parts[1] + "." + parts[2];
// GTFO
@ -653,27 +630,29 @@ Channel.prototype.hideIP = function(ip) {
return chars.join("");
}
Channel.prototype.sendLoginHistory = function(user) {
if(user.rank < 2)
return;
user.socket.emit("recentLogins", this.login_hist);
}
Channel.prototype.sendRankStuff = function(user) {
if(this.hasPermission(user, "ban")) {
var ents = [];
for(var ip in this.ipbans) {
if(this.ipbans[ip] != null) {
var name;
if(ip in this.logins) {
name = this.logins[ip].join(", ");
}
else {
name = this.ipbans[ip][0];
}
var id = this.hideIP(ip);
var name = this.ipbans[ip][0];
var ip_hidden = this.hideIP(ip);
var disp = ip;
if(user.rank < Rank.Siteadmin) {
disp = "(Hidden)";
disp = "x.x." + ip.replace(/\d+\.\d+\.(\d+\.\d+)/, "$1");
}
ents.push({
ip: disp,
id: id,
ip_displayed: disp,
ip_hidden: ip_hidden,
name: name,
aliases: this.ip_alias[ip] || [],
banner: this.ipbans[ip][1]
});
}
@ -681,17 +660,20 @@ Channel.prototype.sendRankStuff = function(user) {
for(var name in this.namebans) {
if(this.namebans[name] != null) {
ents.push({
ip: "*",
ip_displayed: "*",
ip_hidden: false,
name: name,
aliases: this.name_alias[name] || [],
banner: this.namebans[name]
});
}
}
user.socket.emit("banlist", {entries: ents});
user.socket.emit("banlist", ents);
}
// TODO get rid of this
if(Rank.hasPermission(user, "seenlogins")) {
var ents = [];
for(var ip in this.logins) {
for(var ip in this.ip_alias) {
var disp = ip;
if(user.rank < Rank.Siteadmin) {
disp = "(Hidden)";
@ -702,7 +684,7 @@ Channel.prototype.sendRankStuff = function(user) {
ents.push({
ip: disp,
id: this.hideIP(ip),
names: this.logins[ip],
names: this.ip_alias[ip],
banned: banned
});
}
@ -797,9 +779,21 @@ Channel.prototype.broadcastUsercount = function() {
}
Channel.prototype.broadcastNewUser = function(user) {
if(!this.seen(user.ip, user.name)) {
this.logins[user.ip].push(user.name);
}
var aliases = Database.getAliases(user.ip);
var chan = this;
this.ip_alias[user.ip] = aliases;
aliases.forEach(function(alias) {
chan.name_alias[alias] = aliases;
});
this.login_hist.unshift({
name: user.name,
aliases: this.ip_alias[user.ip],
time: Date.now()
});
if(this.login_hist.length > 20)
this.login_hist.pop();
if(user.name.toLowerCase() in this.namebans &&
this.namebans[user.name.toLowerCase()] != null) {
this.kick(user, "You're banned!");
@ -850,24 +844,20 @@ Channel.prototype.broadcastBanlist = function() {
var adminents = [];
for(var ip in this.ipbans) {
if(this.ipbans[ip] != null) {
var name;
if(ip in this.logins) {
name = this.logins[ip].join(", ");
}
else {
name = this.ipbans[ip][0];
}
var id = this.hideIP(ip);
var name = this.ipbans[ip][0];
var ip_hidden = this.hideIP(ip);
ents.push({
ip: "(Hidden)",
id: id,
ip_displayed: "x.x." + ip.replace(/\d+\.\d+\.(\d+\.\d+)/, "$1"),
ip_hidden: ip_hidden,
name: name,
aliases: this.ip_alias[ip] || [],
banner: this.ipbans[ip][1]
});
adminents.push({
ip: ip,
id: id,
ip_displayed: ip,
ip_hidden: ip_hidden,
name: name,
aliases: this.ip_alias[ip] || [],
banner: this.ipbans[ip][1]
});
}
@ -875,13 +865,17 @@ Channel.prototype.broadcastBanlist = function() {
for(var name in this.namebans) {
if(this.namebans[name] != null) {
ents.push({
ip: "*",
ip_displayed: "*",
ip_hidden: false,
name: name,
aliases: this.name_alias[name] || [],
banner: this.namebans[name]
});
adminents.push({
ip: "*",
ip_displayed: "*",
ip_hidden: false,
name: name,
aliases: this.name_alias[name] || [],
banner: this.namebans[name]
});
}
@ -889,10 +883,10 @@ Channel.prototype.broadcastBanlist = function() {
for(var i = 0; i < this.users.length; i++) {
if(this.hasPermission(this.users[i], "ban")) {
if(this.users[i].rank >= Rank.Siteadmin) {
this.users[i].socket.emit("banlist", {entries: adminents});
this.users[i].socket.emit("banlist", adminents);
}
else {
this.users[i].socket.emit("banlist", {entries: ents});
this.users[i].socket.emit("banlist", ents);
}
}
}

View File

@ -39,7 +39,7 @@ function handle(chan, user, msg, data) {
handleBan(chan, user, msg.substring(5).split(" "));
}
else if(msg.indexOf("/ipban ") == 0) {
handleIPBan(chan, user, msg.substring(5).split(" "));
handleIPBan(chan, user, msg.substring(7).split(" "));
}
else if(msg.indexOf("/unban ") == 0) {
handleUnban(chan, user, msg.substring(7).split(" "));
@ -77,30 +77,13 @@ function handleKick(chan, user, args) {
}
function handleIPBan(chan, user, args) {
if(chan.hasPermission(user, "ban") && args.length > 0) {
args[0] = args[0].toLowerCase();
var kickee;
for(var i = 0; i < chan.users.length; i++) {
if(chan.users[i].name.toLowerCase() == args[0]) {
kickee = chan.users[i];
break;
}
}
if(kickee && kickee.rank < user.rank) {
chan.logger.log("*** " + user.name + " banned " + args[0]);
args[0] = "";
var reason = args.join(" ");
chan.kick(kickee, "(banned) " + reason);
chan.banIP(user, kickee);
}
}
chan.tryIPBan(user, args[0], args[1]);
// Ban the name too for good measure
chan.tryNameBan(user, args[0]);
}
function handleBan(chan, user, args) {
if(chan.hasPermission(user, "ban") && args.length > 0) {
args[0] = args[0].toLowerCase();
chan.banName(user, args[0]);
}
chan.tryNameBan(user, args[0]);
}
function handleUnban(chan, user, args) {

View File

@ -918,7 +918,6 @@ function recordVisit(ip, name) {
var results = db.querySync(query);
if(!results) {
console.log(results);
Logger.errlog.log("! Failed to record visit");
}
@ -931,11 +930,60 @@ function recordVisit(ip, name) {
");"].join(""),
[ip]
));
console.log(results);
return results;
}
function getAliases(ip) {
var db = getConnection();
if(!db) {
return [];
}
var query = createQuery(
"SELECT name FROM aliases WHERE ip=?",
[ip]
);
var results = db.querySync(query);
if(!results) {
Logger.errlog.log("! Failed to retrieve aliases");
return [];
}
var names = [];
results.fetchAllSync().forEach(function(row) {
names.push(row.name);
});
return names;
}
function ipForName(name) {
var db = getConnection();
if(!db) {
return [];
}
var query = createQuery(
"SELECT ip FROM aliases WHERE name=?",
[name]
);
var results = db.querySync(query);
if(!results) {
Logger.errlog.log("! Failed to retrieve IP for name");
return [];
}
var ips = [];
results.fetchAllSync().forEach(function(row) {
ips.push(row.ip);
});
return ips;
}
exports.setup = setup;
exports.getConnection = getConnection;
exports.createQuery = createQuery;
@ -966,3 +1014,5 @@ exports.loadUserPlaylist = loadUserPlaylist;
exports.saveUserPlaylist = saveUserPlaylist;
exports.deleteUserPlaylist = deleteUserPlaylist;
exports.recordVisit = recordVisit;
exports.getAliases = getAliases;
exports.ipForName = ipForName;

View File

@ -379,6 +379,12 @@ User.prototype.initCallbacks = function() {
}
}.bind(this));
this.socket.on("requestLoginHistory", function() {
if(this.channel != null) {
this.channel.sendLoginHistory(this);
}
}.bind(this));
this.socket.on("requestAcl", function() {
if(this.channel != null) {
this.channel.sendACL(this);

View File

@ -250,26 +250,60 @@ Callbacks = {
banlist: function(entries) {
var tbl = $("#banlist table");
// dumb hack because of jquery UI
// sortable turns tables and lists into a mess of race conditions
if(!tbl.hasClass("table")) {
setTimeout(function() {
Callbacks.banlist(entries);
}, 100);
return;
}
if(tbl.children().length > 1) {
$(tbl.children()[1]).remove();
}
for(var i = 0; i < entries.length; i++) {
var tr = $("<tr/>").appendTo(tbl);
var tr = document.createElement("tr");
var remove = $("<button/>").addClass("btn btn-mini btn-danger")
.appendTo($("<td/>").appendTo(tr));
$("<i/>").addClass("icon-remove-circle").appendTo(remove);
var ip = $("<td/>").text(entries[i].ip).appendTo(tr);
var ip = $("<td/>").text(entries[i].ip_displayed).appendTo(tr);
var name = $("<td/>").text(entries[i].name).appendTo(tr);
var aliases = $("<td/>").text(entries[i].aliases).appendTo(tr);
var aliases = $("<td/>").text(entries[i].aliases.join(", ")).appendTo(tr);
var banner = $("<td/>").text(entries[i].banner).appendTo(tr);
var callback = (function(id, name) { return function() {
var callback = (function(ip, name) { return function() {
socket.emit("unban", {
id: id,
ip: ip,
name: name
});
} })(entries[i].id, entries[i].name);
} })(entries[i].ip_hidden, entries[i].name);
remove.click(callback);
$(tr).appendTo(tbl);
}
},
recentLogins: function(entries) {
var tbl = $("#loginhistory table");
// dumb hack because of jquery UI
// sortable turns tables and lists into a mess of race conditions
if(!tbl.hasClass("table")) {
setTimeout(function() {
Callbacks.recentLogins(entries);
}, 100);
return;
}
if(tbl.children().length > 1) {
$(tbl.children()[1]).remove();
}
for(var i = 0; i < entries.length; i++) {
var tr = document.createElement("tr");
var name = $("<td/>").text(entries[i].name).appendTo(tr);
var aliases = $("<td/>").text(entries[i].aliases.join(", ")).appendTo(tr);
var time = new Date(entries[i].time).toTimeString();
$("<td/>").text(time).appendTo(tr);
$(tr).appendTo(tbl);
}
},

View File

@ -20,6 +20,11 @@
clickHandler("#show_filteredit", "#filteredit");
clickHandler("#show_cssedit", "#cssedit");
clickHandler("#show_jsedit", "#jsedit");
clickHandler("#show_banlist", "#banlist");
clickHandler("#show_loginhistory", "#loginhistory");
$("#show_loginhistory").click(function() {
socket.emit("requestLoginHistory");
});
genPermissionsEditor();

View File

@ -12,7 +12,7 @@
<li id="cssedit_tab"><a href="javascript:void(0);" id="show_cssedit">CSS Editor</a></li>
<li id="jsedit_tab"><a href="javascript:void(0);" id="show_jsedit">JS Editor</a></li>
<li id="banlist_tab"><a href="javascript:void(0);" id="show_banlist">Ban List</a></li>
<li id="recentconn_tab"><a href="javascript:void(0);" id="show_recentconn">Recent Connections</a></li>
<li id="loginhistory_tab"><a href="javascript:void(0);" id="show_loginhistory">Recent Connections</a></li>
</ul>
</div>
<hr>
@ -102,3 +102,27 @@ Filters Here
<textarea rows="10" id="jstext"></textarea>
<button class="btn btn-primary" id="save_js">Save</button>
</div>
<div id="banlist" class="span12">
<table class="table table-striped">
<thead>
<tr>
<th>Unban</th>
<th>IP</th>
<th>Name</th>
<th>Aliases</th>
<th>Banned By</th>
</tr>
</thead>
</table>
</div>
<div id="loginhistory" class="span12">
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Aliases</th>
<th>Time</th>
</tr>
</thead>
</table>
</div>