From 8fddbc3e6ed4049126f8417786700c2f9939b616 Mon Sep 17 00:00:00 2001 From: calzoneman Date: Thu, 14 Aug 2014 21:42:13 -0500 Subject: [PATCH 1/8] Add IP cloaking; make tor bans channel specific --- config.template.yaml | 2 - lib/acp.js | 2 +- lib/channel/channel.js | 40 +++++++++-------- lib/channel/kickban.js | 54 ++++++++++++++--------- lib/channel/opts.js | 7 ++- lib/channel/poll.js | 4 +- lib/channel/voteskip.js | 4 +- lib/config.js | 1 - lib/io/ioserver.js | 82 ++++++++++++++++++++++------------- lib/{torblocker.js => tor.js} | 35 ++++++--------- lib/user.js | 33 +++++++------- lib/utilities.js | 69 ++++++++++++++++++----------- templates/channeloptions.jade | 1 + www/js/util.js | 1 + 14 files changed, 193 insertions(+), 142 deletions(-) rename lib/{torblocker.js => tor.js} (74%) diff --git a/config.template.yaml b/config.template.yaml index 3d506f6b..f148a5ca 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -115,8 +115,6 @@ max-channels-per-user: 5 max-accounts-per-ip: 5 # Minimum number of seconds between guest logins from the same IP guest-login-delay: 60 -# Block known Tor IP addresses -enable-tor-blocker: true # Configure statistics tracking stats: diff --git a/lib/acp.js b/lib/acp.js index 08933d39..b860e780 100644 --- a/lib/acp.js +++ b/lib/acp.js @@ -17,7 +17,7 @@ var Config = require("./config"); var Server = require("./server"); function eventUsername(user) { - return user.getName() + "@" + user.ip; + return user.getName() + "@" + user.realip; } function handleAnnounce(user, data) { diff --git a/lib/channel/channel.js b/lib/channel/channel.js index d3c3e812..5f0e6fed 100644 --- a/lib/channel/channel.js +++ b/lib/channel/channel.js @@ -330,10 +330,24 @@ Channel.prototype.acceptUser = function (user) { user.autoAFK(); user.socket.on("readChanLog", this.handleReadLog.bind(this, user)); - Logger.syslog.log(user.ip + " joined " + this.name); - this.logger.log("[login] Accepted connection from " + user.longip); + Logger.syslog.log(user.realip + " joined " + this.name); + if (user.socket._isUsingTor) { + if (this.modules.options && this.modules.options.get("torbanned")) { + user.kick("This channel has banned connections from Tor."); + user.socket.disconnect(true); + this.logger.log("[login] Blocked connection from Tor exit at " + + user.displayip); + return; + } + + this.logger.log("[login] Accepted connection from Tor exit at " + + user.displayip); + } else { + this.logger.log("[login] Accepted connection from " + user.displayip); + } + if (user.is(Flags.U_LOGGED_IN)) { - this.logger.log("[login] " + user.longip + " authenticated as " + user.getName()); + this.logger.log("[login] " + user.displayip + " authenticated as " + user.getName()); } var self = this; @@ -367,7 +381,7 @@ Channel.prototype.partUser = function (user) { return; } - this.logger.log("[login] " + user.longip + " (" + user.getName() + ") " + + this.logger.log("[login] " + user.displayip + " (" + user.getName() + ") " + "disconnected."); user.channel = null; /* Should be unnecessary because partUser only occurs if the socket dies */ @@ -412,7 +426,7 @@ Channel.prototype.packUserData = function (user) { muted: user.is(Flags.U_MUTED), smuted: user.is(Flags.U_SMUTED), aliases: user.account.aliases, - ip: util.maskIP(user.longip) + ip: user.displayip } }; @@ -425,7 +439,7 @@ Channel.prototype.packUserData = function (user) { muted: user.is(Flags.U_MUTED), smuted: user.is(Flags.U_SMUTED), aliases: user.account.aliases, - ip: user.ip + ip: user.realip } }; @@ -534,7 +548,7 @@ Channel.prototype.sendUserJoin = function (users, user) { user.account.aliases.join(",") + ")", 2); }; -Channel.prototype.readLog = function (shouldMaskIP, cb) { +Channel.prototype.readLog = function (cb) { var maxLen = 102400; var file = this.logger.filename; this.activeLock.lock(); @@ -558,16 +572,6 @@ Channel.prototype.readLog = function (shouldMaskIP, cb) { buffer += data; }); read.on("end", function () { - if (shouldMaskIP) { - buffer = buffer.replace( - /(?:^|\s)(\d+\.\d+\.\d+)\.\d+/g, - "$1.x" - ).replace( - /(?:^|\s)((?:[0-9a-f]+:){3}[0-9a-f]+):(?:[0-9a-f]+:){3}[0-9a-f]+/g, - "$1:x:x:x:x" - ); - } - cb(null, buffer); self.activeLock.release(); }); @@ -589,7 +593,7 @@ Channel.prototype.handleReadLog = function (user) { } var shouldMaskIP = user.account.globalRank < 255; - this.readLog(shouldMaskIP, function (err, data) { + this.readLog(function (err, data) { if (err) { user.socket.emit("readChanLog", { success: false, diff --git a/lib/channel/kickban.js b/lib/channel/kickban.js index b645a71d..268425c3 100644 --- a/lib/channel/kickban.js +++ b/lib/channel/kickban.js @@ -24,36 +24,48 @@ function KickBanModule(channel) { KickBanModule.prototype = Object.create(ChannelModule.prototype); +function checkIPBan(cname, ip, cb) { + db.channels.isIPBanned(cname, ip, function (err, banned) { + if (err) { + cb(false); + } else { + cb(banned); + } + }); +} + +function checkNameBan(cname, name, cb) { + db.channels.isNameBanned(cname, name, function (err, banned) { + if (err) { + cb(false); + } else { + cb(banned); + } + }); +} + KickBanModule.prototype.onUserPreJoin = function (user, data, cb) { if (!this.channel.is(Flags.C_REGISTERED)) { return cb(null, ChannelModule.PASSTHROUGH); } var cname = this.channel.name; - db.channels.isIPBanned(cname, user.longip, function (err, banned) { - if (err) { - cb(null, ChannelModule.PASSTHROUGH); - } else if (!banned) { - if (user.is(Flags.U_LOGGED_IN)) { - checkNameBan(); - } else { - cb(null, ChannelModule.PASSTHROUGH); - } - } else { + checkIPBan(cname, user.realip, function (banned) { + if (banned) { cb(null, ChannelModule.DENY); user.kick("Your IP address is banned from this channel."); + } else { + checkNameBan(cname, user.getName(), function (banned) { + if (banned) { + cb(null, ChannelModule.DENY); + user.kick("Your username is banned from this channel."); + } else { + cb(null, ChannelModule.PASSTHROUGH); + } + }); } }); - function checkNameBan() { - db.channels.isNameBanned(cname, user.getName(), function (err, banned) { - if (err) { - cb(null, ChannelModule.PASSTHROUGH); - } else { - cb(null, banned ? ChannelModule.DENY : ChannelModule.PASSTHROUGH); - } - }); - } }; KickBanModule.prototype.onUserPostJoin = function (user) { @@ -98,7 +110,7 @@ KickBanModule.prototype.sendBanlist = function (users) { for (var i = 0; i < banlist.length; i++) { bans.push({ id: banlist[i].id, - ip: banlist[i].ip === "*" ? "*" : util.maskIP(banlist[i].ip), + ip: banlist[i].ip === "*" ? "*" : util.cloakIP(banlist[i].ip), name: banlist[i].name, reason: banlist[i].reason, bannedby: banlist[i].bannedby @@ -381,7 +393,7 @@ KickBanModule.prototype.kickBanTarget = function (name, ip) { name = name.toLowerCase(); for (var i = 0; i < this.channel.users.length; i++) { if (this.channel.users[i].getLowerName() === name || - this.channel.users[i].longip === ip) { + this.channel.users[i].realip === ip) { this.channel.users[i].kick("You're banned!"); } } diff --git a/lib/channel/opts.js b/lib/channel/opts.js index 84950c83..d2d4f67a 100644 --- a/lib/channel/opts.js +++ b/lib/channel/opts.js @@ -22,7 +22,8 @@ function OptionsModule(channel) { show_public: false, // List the channel on the index page enable_link_regex: true, // Use the built-in link filter password: false, // Channel password (false -> no password required for entry) - allow_dupes: false // Allow duplicate videos on the playlist + allow_dupes: false, // Allow duplicate videos on the playlist + torbanned: false // Block connections from Tor exit nodes }; } @@ -245,6 +246,10 @@ OptionsModule.prototype.handleSetOptions = function (user, data) { this.opts.allow_dupes = Boolean(data.allow_dupes); } + if ("torbanned" in data && user.account.effectiveRank >= 3) { + this.opts.torbanned = Boolean(data.torbanned); + } + this.channel.logger.log("[mod] " + user.getName() + " updated channel options"); this.sendOpts(this.channel.users); }; diff --git a/lib/channel/poll.js b/lib/channel/poll.js index f6991327..274b02b6 100644 --- a/lib/channel/poll.js +++ b/lib/channel/poll.js @@ -67,7 +67,7 @@ PollModule.prototype.onUserPostJoin = function (user) { PollModule.prototype.onUserPart = function(user) { if (this.poll) { - this.poll.unvote(user.ip); + this.poll.unvote(user.realip); this.sendPollUpdate(this.channel.users); } }; @@ -142,7 +142,7 @@ PollModule.prototype.handleVote = function (user, data) { } if (this.poll) { - this.poll.vote(user.ip, data.option); + this.poll.vote(user.realip, data.option); this.sendPollUpdate(this.channel.users); } }; diff --git a/lib/channel/voteskip.js b/lib/channel/voteskip.js index cf25ded6..5d85074c 100644 --- a/lib/channel/voteskip.js +++ b/lib/channel/voteskip.js @@ -19,7 +19,7 @@ VoteskipModule.prototype.onUserPart = function(user) { return; } - this.unvote(user.ip); + this.unvote(user.realip); this.update(); }; @@ -40,7 +40,7 @@ VoteskipModule.prototype.handleVoteskip = function (user) { this.poll = new Poll("[server]", "voteskip", ["skip"], false); } - this.poll.vote(user.ip, 0); + this.poll.vote(user.realip, 0); var title = ""; if (this.channel.modules.playlist.current) { diff --git a/lib/config.js b/lib/config.js index a7d6b855..24fe7888 100644 --- a/lib/config.js +++ b/lib/config.js @@ -69,7 +69,6 @@ var defaults = { "max-channels-per-user": 5, "max-accounts-per-ip": 5, "guest-login-delay": 60, - "enable-tor-blocker": true, stats: { interval: 3600000, "max-age": 86400000 diff --git a/lib/io/ioserver.js b/lib/io/ioserver.js index aa327ed6..33c4ce44 100644 --- a/lib/io/ioserver.js +++ b/lib/io/ioserver.js @@ -11,6 +11,8 @@ var Account = require("../account"); var typecheck = require("json-typecheck"); var net = require("net"); var util = require("../utilities"); +var crypto = require("crypto"); +var isTorExit = require("../tor").isTorExit; var CONNECT_RATE = { burst: 5, @@ -43,27 +45,8 @@ function handleAuth(data, accept) { } } -/** - * Called after a connection is accepted - */ -function handleConnection(sock) { - var ip = sock.handshake.address.address; - var longip = ip; - sock._ip = ip; - if (net.isIPv6(ip)) { - longip = util.expandIPv6(ip); - } - sock._longip = longip; - var srv = Server.getServer(); - if (srv.torblocker && srv.torblocker.shouldBlockIP(ip)) { - sock.emit("kick", { - reason: "This server does not allow connections from Tor. "+ - "Please log in with your regular internet connection." - }); - Logger.syslog.log("Blocked Tor IP: " + ip); - sock.disconnect(true); - return; - } +function throttleIP(sock) { + var ip = sock._realip; if (!(ip in ipThrottle)) { ipThrottle[ip] = $util.newRateLimiter(); @@ -75,16 +58,14 @@ function handleConnection(sock) { reason: "Your IP address is connecting too quickly. Please "+ "wait 10 seconds before joining again." }); - return; + return true; } - // Check for global ban on the IP - if (db.isGlobalIPBanned(ip)) { - Logger.syslog.log("Rejecting " + ip + " - global banned"); - sock.emit("kick", { reason: "Your IP is globally banned." }); - sock.disconnect(true); - return; - } + return false; +} + +function ipLimitReached(sock) { + var ip = sock._realip; sock.on("disconnect", function () { ipCount[ip]--; @@ -106,9 +87,9 @@ function handleConnection(sock) { sock.disconnect(true); return; } +} - Logger.syslog.log("Accepted socket from " + ip); - +function addTypecheckedFunctions(sock) { sock.typecheckedOn = function (msg, template, cb) { sock.on(msg, function (data) { typecheck(data, template, function (err, data) { @@ -136,6 +117,44 @@ function handleConnection(sock) { }); }); }; +} + +/** + * Called after a connection is accepted + */ +function handleConnection(sock) { + var ip = sock.handshake.address.address; + if (net.isIPv6(ip)) { + ip = util.expandIPv6(ip); + } + sock._realip = ip; + sock._displayip = $util.cloakIP(ip); + + if (isTorExit(ip)) { + sock._isUsingTor = true; + } + + var srv = Server.getServer(); + + if (throttleIP(ip)) { + return; + } + + // Check for global ban on the IP + if (db.isGlobalIPBanned(ip)) { + Logger.syslog.log("Rejecting " + ip + " - global banned"); + sock.emit("kick", { reason: "Your IP is globally banned." }); + sock.disconnect(true); + return; + } + + if (ipLimitReached(sock)) { + return; + } + + Logger.syslog.log("Accepted socket from " + ip); + + addTypecheckedFunctions(sock); var user = new User(sock); if (sock.handshake.user) { @@ -148,6 +167,7 @@ function handleConnection(sock) { user.setFlag(Flags.U_READY); return; } + user.socket.emit("login", { success: true, name: user.getName(), diff --git a/lib/torblocker.js b/lib/tor.js similarity index 74% rename from lib/torblocker.js rename to lib/tor.js index f7b324c4..095f143c 100644 --- a/lib/torblocker.js +++ b/lib/tor.js @@ -24,8 +24,8 @@ function retrieveIPs(cb) { var d = domain.create(); d.on("error", function (err) { - if (err.trace) - Logger.errlog.log(err.trace()); + if (err.stack) + Logger.errlog.log(err.stack); else Logger.errlog.log(err); }); @@ -63,26 +63,17 @@ function getTorIPs(cb) { }); } -module.exports = function () { - var x = { - ipList: [], - shouldBlockIP: function (ip) { - return this.ipList.indexOf(ip) >= 0; - } - }; +var _ipList = []; +getTorIPs(function (err, ips) { + if (err) { + Logger.errlog.log(err); + return; + } - var init = function () { - getTorIPs(function (err, ips) { - if (err) { - Logger.errlog.log(err); - return; - } + Logger.syslog.log("Loaded Tor IP list"); + _ipList = ips; +}); - Logger.syslog.log("Loaded Tor IP list"); - x.ipList = ips; - }); - }; - - init(); - return x; +exports.isTorExit = function (ip) { + return this._ipList.indexOf(ip) >= 0; }; diff --git a/lib/user.js b/lib/user.js index fe84790b..47e455e5 100644 --- a/lib/user.js +++ b/lib/user.js @@ -14,9 +14,10 @@ function User(socket) { MakeEmitter(self); self.flags = 0; self.socket = socket; - self.ip = socket._ip; - self.longip = socket._longip; - self.account = Account.default(self.longip); + self.realip = socket._realip; + self.displayip = socket._displayip; + self.hostmask = socket._hostmask; + self.account = Account.default(self.realip); self.channel = null; self.queueLimiter = util.newRateLimiter(); self.chatLimiter = util.newRateLimiter(); @@ -65,7 +66,7 @@ function User(socket) { self.kick("Attempted initACP from non privileged user. This incident " + "will be reported."); Logger.eventlog.log("[acp] Attempted initACP from socket client " + - self.getName() + "@" + self.ip); + self.getName() + "@" + self.realip); } }); }); @@ -176,7 +177,7 @@ User.prototype.setAFK = function (afk) { if (afk) { this.setFlag(Flags.U_AFK); if (this.channel.modules.voteskip) { - this.channel.modules.voteskip.unvote(this.ip); + this.channel.modules.voteskip.unvote(this.realip); } } else { this.clearFlag(Flags.U_AFK); @@ -255,7 +256,7 @@ User.prototype.login = function (name, pw) { if (err) { if (err === "Invalid username/password combination") { Logger.eventlog.log("[loginfail] Login failed (bad password): " + name - + "@" + self.ip); + + "@" + self.realip); } self.socket.emit("login", { @@ -283,11 +284,11 @@ User.prototype.login = function (name, pw) { success: true, name: user.name }); - db.recordVisit(self.longip, self.getName()); + db.recordVisit(self.realip, self.getName()); self.socket.emit("rank", self.account.effectiveRank); - Logger.syslog.log(self.ip + " logged in as " + user.name); + Logger.syslog.log(self.realip + " logged in as " + user.name); if (self.inChannel()) { - self.channel.logger.log(self.longip + " logged in as " + user.name); + self.channel.logger.log(self.displayip + " logged in as " + user.name); } self.setFlag(Flags.U_LOGGED_IN); self.clearFlag(Flags.U_LOGGING_IN); @@ -300,8 +301,8 @@ var lastguestlogin = {}; User.prototype.guestLogin = function (name) { var self = this; - if (self.ip in lastguestlogin) { - var diff = (Date.now() - lastguestlogin[self.ip]) / 1000; + if (self.realip in lastguestlogin) { + var diff = (Date.now() - lastguestlogin[self.realip]) / 1000; if (diff < Config.get("guest-login-delay")) { self.socket.emit("login", { success: false, @@ -355,7 +356,7 @@ User.prototype.guestLogin = function (name) { } // Login succeeded - lastguestlogin[self.ip] = Date.now(); + lastguestlogin[self.realip] = Date.now(); var opts = { name: name }; if (self.inChannel()) { @@ -373,11 +374,11 @@ User.prototype.guestLogin = function (name) { name: name, guest: true }); - db.recordVisit(self.longip, self.getName()); + db.recordVisit(self.realip, self.getName()); self.socket.emit("rank", 0); - Logger.syslog.log(self.ip + " signed in as " + name); + Logger.syslog.log(self.realip + " signed in as " + name); if (self.inChannel()) { - self.channel.logger.log(self.longip + " signed in as " + name); + self.channel.logger.log(self.displayip + " signed in as " + name); } self.setFlag(Flags.U_LOGGED_IN); self.emit("login", self.account); @@ -422,7 +423,7 @@ User.prototype.refreshAccount = function (opts, cb) { opts.registered = this.is(Flags.U_REGISTERED); var self = this; var old = this.account; - Account.getAccount(name, this.longip, opts, function (err, account) { + Account.getAccount(name, this.realip, opts, function (err, account) { if (!err) { /* Update account if anything changed in the meantime */ for (var key in old) { diff --git a/lib/utilities.js b/lib/utilities.js index 9990e6f8..fa36fde1 100644 --- a/lib/utilities.js +++ b/lib/utilities.js @@ -78,31 +78,6 @@ return salt.join(''); }, - root.maskIP = function (ip) { - if (net.isIPv4(ip)) { - /* Full /32 IPv4 address */ - return ip.replace(/^(\d+\.\d+\.\d+)\.\d+/, "$1.x"); - } else if (net.isIPv4(ip + ".0")) { - /* /24 IPv4 range */ - return ip + ".0/24"; - } else if (net.isIPv4(ip + ".0.0")) { - /* /16 IPv4 widerange */ - return ip + ".0.0/16"; - } else if (net.isIPv6(ip)) { - /* /128 IPv6 address */ - return ip.replace(/^((?:[0-9a-f]+:){3}[0-9a-f]+):(?:[0-9a-f]+:){3}[0-9a-f]+$/, - "$1:x:x:x:x"); - } else if (net.isIPv6(ip + ":0:0:0:0")) { - /* /64 IPv6 range */ - return ip + "::0/64"; - } else if (net.isIPv6(ip + ":0:0:0:0:0")) { - /* /48 IPv6 widerange */ - return ip + "::0/48"; - } else { - return ip; - } - }, - root.getIPRange = function (ip) { if (net.isIPv6(ip)) { return root.expandIPv6(ip) @@ -291,4 +266,48 @@ shasum.update(data); return shasum.digest("hex"); } + + root.cloakIP = function (ip) { + if (ip.match(/\d+\.\d+(\.\d+)?(\.\d+)?/)) { + return cloakIPv4(ip); + } else if (ip.match(/([0-9a-f]{1,4}\:){1,7}[0-9a-f]{1,4}/)) { + return cloakIPv6(ip); + } else { + return ip; + } + + function iphash(ip, segment, len) { + var md5 = crypto.createHash("md5"); + md5.update(ip); + md5.update(segment); + return md5.digest("base64").substring(0, len); + } + + function cloakIPv4(ip) { + var parts = ip.split("."); + + parts = parts.map(function (segment, i) { + if (i < 2) return segment; + + return iphash(ip, segment + i, 3); + }); + + while (parts.length < 4) parts.push("*"); + return parts.join("."); + } + + function cloakIPv6(ip) { + var parts = ip.split(":"); + parts.splice(4, 4); + + parts = parts.map(function (segment, i) { + if (i < 2) return segment; + + return iphash(ip, segment + i, 4); + }); + + while (parts.length < 4) parts.push("*"); + return parts.join(":"); + } + } })(); diff --git a/templates/channeloptions.jade b/templates/channeloptions.jade index cb2913a7..c6aa231a 100644 --- a/templates/channeloptions.jade +++ b/templates/channeloptions.jade @@ -75,6 +75,7 @@ mixin adminoptions mixin textbox-auto("cs-externalcss", "External CSS", "Stylesheet URL") mixin textbox-auto("cs-externaljs", "External Javascript", "Script URL") mixin rcheckbox-auto("cs-show_public", "List channel publicly") + mixin rcheckbox-auto("cs-torbanned", "Block connections from Tor") .form-group .col-sm-8.col-sm-offset-4 span.text-info Changes are automatically saved. diff --git a/www/js/util.js b/www/js/util.js index 16294cc0..0b50521e 100644 --- a/www/js/util.js +++ b/www/js/util.js @@ -864,6 +864,7 @@ function handleModPermissions() { $("#cs-allow_voteskip").prop("checked", CHANNEL.opts.allow_voteskip); $("#cs-voteskip_ratio").val(CHANNEL.opts.voteskip_ratio); $("#cs-allow_dupes").val(CHANNEL.opts.allow_dupes); + $("#cs-torbanned").val(CHANNEL.opts.torbanned); (function() { if(typeof CHANNEL.opts.maxlength != "number") { $("#cs-maxlength").val(""); From 6b9968a489a635bfe5d3632c96fa55f5fd931e4b Mon Sep 17 00:00:00 2001 From: calzoneman Date: Thu, 14 Aug 2014 21:44:33 -0500 Subject: [PATCH 2/8] Remove torblocker dependency --- lib/server.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/server.js b/lib/server.js index 6b671b4e..e8731c6c 100644 --- a/lib/server.js +++ b/lib/server.js @@ -55,7 +55,6 @@ var Server = function () { self.announcement = null; self.httplog = null; self.infogetter = null; - self.torblocker = null; self.servers = {}; self.ioServers = {}; @@ -109,11 +108,6 @@ var Server = function () { // background tasks init ---------------------------------------------- require("./bgtask")(self); - - // tor blocker init --------------------------------------------------- - if (Config.get("enable-tor-blocker")) { - self.torblocker = require("./torblocker")(); - } }; Server.prototype.getHTTPIP = function (req) { From c5a52d2ce5e20323c516c0cddb24f3ca3b77d05a Mon Sep 17 00:00:00 2001 From: calzoneman Date: Thu, 14 Aug 2014 21:45:25 -0500 Subject: [PATCH 3/8] Fix wrong scope on ipList --- lib/tor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tor.js b/lib/tor.js index 095f143c..09e00e0e 100644 --- a/lib/tor.js +++ b/lib/tor.js @@ -75,5 +75,5 @@ getTorIPs(function (err, ips) { }); exports.isTorExit = function (ip) { - return this._ipList.indexOf(ip) >= 0; + return _ipList.indexOf(ip) >= 0; }; From 722c55e0da4a729ff5993a3cef8042dbc5454b3b Mon Sep 17 00:00:00 2001 From: calzoneman Date: Thu, 14 Aug 2014 21:50:34 -0500 Subject: [PATCH 4/8] Remove reference to maskIP --- lib/channel/kickban.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/channel/kickban.js b/lib/channel/kickban.js index 268425c3..1680d44a 100644 --- a/lib/channel/kickban.js +++ b/lib/channel/kickban.js @@ -310,7 +310,7 @@ KickBanModule.prototype.banName = function (actor, name, reason, cb) { KickBanModule.prototype.banIP = function (actor, ip, name, reason, cb) { var self = this; reason = reason.substring(0, 255); - var masked = util.maskIP(ip); + var masked = util.cloakIP(ip); var chan = this.channel; var error = function (what) { @@ -340,7 +340,7 @@ KickBanModule.prototype.banIP = function (actor, ip, name, reason, cb) { chan.logger.log("[mod] " + actor.getName() + " banned " + ip + " (" + name + ")"); if (chan.modules.chat) { chan.modules.chat.sendModMessage(actor.getName() + " banned " + - util.maskIP(ip) + " (" + name + ")", + util.cloakIP(ip) + " (" + name + ")", chan.modules.permissions.permissions.ban); } }).then(function () { From 25ab4b62e5fa1c46a61855ae09d397f7ee461806 Mon Sep 17 00:00:00 2001 From: calzoneman Date: Thu, 14 Aug 2014 21:57:38 -0500 Subject: [PATCH 5/8] Update cloaking function so the banlist looks right --- lib/utilities.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/utilities.js b/lib/utilities.js index fa36fde1..276daf12 100644 --- a/lib/utilities.js +++ b/lib/utilities.js @@ -276,20 +276,22 @@ return ip; } - function iphash(ip, segment, len) { + function iphash(data, len) { var md5 = crypto.createHash("md5"); - md5.update(ip); - md5.update(segment); + md5.update(data); return md5.digest("base64").substring(0, len); } function cloakIPv4(ip) { var parts = ip.split("."); + var accumulator = ""; parts = parts.map(function (segment, i) { if (i < 2) return segment; - return iphash(ip, segment + i, 3); + var part = iphash(accumulator + segment + i, 3); + accumulator += segment; + return part; }); while (parts.length < 4) parts.push("*"); @@ -299,11 +301,14 @@ function cloakIPv6(ip) { var parts = ip.split(":"); parts.splice(4, 4); + var accumulator = ""; parts = parts.map(function (segment, i) { if (i < 2) return segment; - return iphash(ip, segment + i, 4); + var part = iphash(accumulator + segment + i, 4); + accumulator += segment; + return part; }); while (parts.length < 4) parts.push("*"); From c255133a2b5bd9990bde7fde82ff122bc76665ac Mon Sep 17 00:00:00 2001 From: calzoneman Date: Thu, 14 Aug 2014 22:02:58 -0500 Subject: [PATCH 6/8] Fix wrong argument being passed --- lib/io/ioserver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/io/ioserver.js b/lib/io/ioserver.js index 33c4ce44..8c8b2b94 100644 --- a/lib/io/ioserver.js +++ b/lib/io/ioserver.js @@ -136,7 +136,7 @@ function handleConnection(sock) { var srv = Server.getServer(); - if (throttleIP(ip)) { + if (throttleIP(sock)) { return; } From b82583a79c05ba32f581f58a4919a83b0c680d17 Mon Sep 17 00:00:00 2001 From: calzoneman Date: Thu, 14 Aug 2014 22:07:06 -0500 Subject: [PATCH 7/8] Remove IP leak from ban log message --- lib/channel/kickban.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/channel/kickban.js b/lib/channel/kickban.js index 1680d44a..33c88f90 100644 --- a/lib/channel/kickban.js +++ b/lib/channel/kickban.js @@ -337,10 +337,11 @@ KickBanModule.prototype.banIP = function (actor, ip, name, reason, cb) { return Q.nfcall(db.channels.ban, chan.name, ip, name, reason, actor.getName()); }).then(function () { - chan.logger.log("[mod] " + actor.getName() + " banned " + ip + " (" + name + ")"); + var cloaked = util.cloakIP(ip); + chan.logger.log("[mod] " + actor.getName() + " banned " + cloaked + " (" + name + ")"); if (chan.modules.chat) { chan.modules.chat.sendModMessage(actor.getName() + " banned " + - util.cloakIP(ip) + " (" + name + ")", + cloaked + " (" + name + ")", chan.modules.permissions.permissions.ban); } }).then(function () { From 0f2b93e5c5a5a38382d4dd9e9c1ff320f0f75071 Mon Sep 17 00:00:00 2001 From: calzoneman Date: Fri, 15 Aug 2014 11:41:09 -0500 Subject: [PATCH 8/8] Increment version number --- lib/server.js | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/server.js b/lib/server.js index e8731c6c..1282145b 100644 --- a/lib/server.js +++ b/lib/server.js @@ -9,7 +9,7 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -const VERSION = "3.3.2"; +const VERSION = "3.4.0"; var singleton = null; var Config = require("./config"); diff --git a/package.json b/package.json index 90daf688..c3aefe54 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "Calvin Montgomery", "name": "CyTube", "description": "Online media synchronizer and chat", - "version": "3.3.2", + "version": "3.4.0", "repository": { "url": "http://github.com/calzoneman/sync" },