From 016b125f4964cea640ac6fec71a1382681aa3e00 Mon Sep 17 00:00:00 2001 From: calzoneman Date: Mon, 8 Aug 2016 23:03:16 -0700 Subject: [PATCH 01/10] Initial IP session cookie implementation --- src/io/ioserver.js | 67 +++++++++++++++-------- src/server.js | 5 ++ src/web/middleware/ipsessioncookie.js | 76 +++++++++++++++++++++++++++ src/web/webserver.js | 1 + 4 files changed, 127 insertions(+), 22 deletions(-) create mode 100644 src/web/middleware/ipsessioncookie.js diff --git a/src/io/ioserver.js b/src/io/ioserver.js index 9077f891..603f5b18 100644 --- a/src/io/ioserver.js +++ b/src/io/ioserver.js @@ -15,6 +15,7 @@ var crypto = require("crypto"); var isTorExit = require("../tor").isTorExit; var session = require("../session"); import counters from '../counters'; +import { verifyIPSessionCookie } from '../web/middleware/ipsessioncookie'; var CONNECT_RATE = { burst: 5, @@ -25,33 +26,53 @@ var ipThrottle = {}; // Keep track of number of connections per IP var ipCount = {}; +function parseCookies(socket, accept) { + var req = socket.request; + if (req.headers.cookie) { + cookieParser(req, null, () => { + accept(null, true); + }); + } else { + req.cookies = {}; + req.signedCookies = {}; + accept(null, true); + } +} /** * Called before an incoming socket.io connection is accepted. */ function handleAuth(socket, accept) { - var data = socket.request; - socket.user = false; - if (data.headers.cookie) { - cookieParser(data, null, function () { - var auth = data.signedCookies.auth; - if (!auth) { - return accept(null, true); - } - - session.verifySession(auth, function (err, user) { - if (!err) { - socket.user = { - name: user.name, - global_rank: user.global_rank - }; - } - accept(null, true); - }); - }); - } else { - accept(null, true); + var auth = socket.request.signedCookies.auth; + if (!auth) { + return accept(null, true); } + + session.verifySession(auth, function (err, user) { + if (!err) { + socket.user = { + name: user.name, + global_rank: user.global_rank + }; + } + accept(null, true); + }); +} + +function handleIPSessionCookie(socket, accept) { + var cookie = socket.request.signedCookies['ip-session']; + if (!cookie) { + socket.ipSessionFirstSeen = new Date(); + return accept(null, true); + } + + var sessionMatch = verifyIPSessionCookie(socket._realip, cookie); + if (sessionMatch) { + socket.ipSessionFirstSeen = sessionMatch.date; + } else { + socket.ipSessionFirstSeen = new Date(); + } + accept(null, true); } function throttleIP(sock) { @@ -247,8 +268,10 @@ module.exports = { }; var io = sio.instance = sio(); - io.use(handleAuth); io.use(ipForwardingMiddleware(webConfig)); + io.use(parseCookies); + io.use(handleIPSessionCookie); + io.use(handleAuth); io.on("connection", handleConnection); Config.get("listen").forEach(function (bind) { diff --git a/src/server.js b/src/server.js index 593e21b4..3a5c328a 100644 --- a/src/server.js +++ b/src/server.js @@ -18,6 +18,11 @@ module.exports = { exists || fs.mkdir(chandumppath); }); + var statepath = path.join(__dirname, "../state"); + fs.exists(statepath, function (exists) { + exists || fs.mkdir(statepath); + }); + var gdvttpath = path.join(__dirname, "../google-drive-subtitles"); fs.exists(gdvttpath, function (exists) { exists || fs.mkdir(gdvttpath); diff --git a/src/web/middleware/ipsessioncookie.js b/src/web/middleware/ipsessioncookie.js new file mode 100644 index 00000000..c2cd849b --- /dev/null +++ b/src/web/middleware/ipsessioncookie.js @@ -0,0 +1,76 @@ +import path from 'path'; +import fs from 'fs'; +import crypto from 'crypto'; + +const SALT_PATH = path.resolve(__dirname, '..', '..', '..', 'state', 'ipsessionsalt.json'); + +var SALT; +try { + SALT = require(SALT_PATH); +} catch (error) { + SALT = crypto.randomBytes(32).toString('base64'); + fs.writeFileSync(SALT_PATH, SALT); +} + +function sha256(input) { + var hash = crypto.createHash("sha256"); + hash.update(input); + return hash.digest("base64"); +} + +export function createIPSessionCookie(ip, date) { + const hashInput = [ + ip, + date.getTime(), + SALT + ].join(':'); + + return [ + date.getTime(), + sha256(hashInput) + ].join(':'); +} + +export function verifyIPSessionCookie(ip, cookie) { + const parts = cookie.split(':'); + if (parts.length !== 2) { + return false; + } + + const timestamp = parseInt(parts[0], 10); + if (isNaN(timestamp)) { + return false; + } + + const date = new Date(timestamp); + const expected = createIPSessionCookie(ip, date); + if (expected !== cookie) { + return false; + } + + return { + date: date, + }; +} + +export function ipSessionCookieMiddleware(req, res, next) { + var firstSeen = new Date(); + var hasSession = false; + if (req.signedCookies && req.signedCookies['ip-session']) { + var sessionMatch = verifyIPSessionCookie(req.realIP, req.signedCookies['ip-session']); + if (sessionMatch) { + hasSession = true; + firstSeen = sessionMatch.date; + } + } + + if (!hasSession) { + res.cookie('ip-session', createIPSessionCookie(req.realIP, firstSeen), { + signed: true, + httpOnly: true + }); + } + + req.ipSessionFirstSeen = firstSeen; + next(); +} diff --git a/src/web/webserver.js b/src/web/webserver.js index b428517f..e34a2caf 100644 --- a/src/web/webserver.js +++ b/src/web/webserver.js @@ -146,6 +146,7 @@ module.exports = { } app.use(cookieParser(webConfig.getCookieSecret())); app.use(csrf.init(webConfig.getCookieDomain())); + app.use('/r/:channel', require('./middleware/ipsessioncookie').ipSessionCookieMiddleware); initializeLog(app); require('./middleware/authorize')(app, session); From 6245dc84da805104fad225deb293db17ffbdc690 Mon Sep 17 00:00:00 2001 From: calzoneman Date: Mon, 8 Aug 2016 23:04:34 -0700 Subject: [PATCH 02/10] Minor bug fix --- src/web/middleware/ipsessioncookie.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/middleware/ipsessioncookie.js b/src/web/middleware/ipsessioncookie.js index c2cd849b..e74b1f55 100644 --- a/src/web/middleware/ipsessioncookie.js +++ b/src/web/middleware/ipsessioncookie.js @@ -9,7 +9,7 @@ try { SALT = require(SALT_PATH); } catch (error) { SALT = crypto.randomBytes(32).toString('base64'); - fs.writeFileSync(SALT_PATH, SALT); + fs.writeFileSync(SALT_PATH, JSON.stringify(SALT)); } function sha256(input) { From 701d470494e4ed4d0e3b8d98a36763dea98b71ba Mon Sep 17 00:00:00 2001 From: calzoneman Date: Wed, 27 Jul 2016 23:31:23 -0700 Subject: [PATCH 03/10] Add initial blocking of new users in chat --- src/channel/chat.js | 15 +++++++++++++++ src/io/ioserver.js | 4 +++- src/user.js | 14 ++++++++++++++ www/js/callbacks.js | 16 ++++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/channel/chat.js b/src/channel/chat.js index 16204089..da2117b7 100644 --- a/src/channel/chat.js +++ b/src/channel/chat.js @@ -131,6 +131,21 @@ ChatModule.prototype.handleChatMsg = function (user, data) { // Limit to 240 characters data.msg = data.msg.substring(0, 240); + + const firstSeen = user.getFirstSeenTime(); + // TODO: configurable times + if (firstSeen > Date.now() - 5 * 60 * 1000) { + user.socket.emit("spamFiltered", { + reason: "NEW_USER_CHAT" + }); + return; + } else if ((firstSeen > Date.now() - 24 * 60 * 60 * 1000) && data.msg.match(LINK)) { + user.socket.emit("spamFiltered", { + reason: "NEW_USER_CHAT_LINK" + }); + return; + } + // If channel doesn't permit them, strip ASCII control characters if (!this.channel.modules.options || !this.channel.modules.options.get("allow_ascii_control")) { diff --git a/src/io/ioserver.js b/src/io/ioserver.js index 603f5b18..5afa011c 100644 --- a/src/io/ioserver.js +++ b/src/io/ioserver.js @@ -52,7 +52,8 @@ function handleAuth(socket, accept) { if (!err) { socket.user = { name: user.name, - global_rank: user.global_rank + global_rank: user.global_rank, + registrationTime: new Date(user.time) }; } accept(null, true); @@ -235,6 +236,7 @@ function handleConnection(sock) { user.setFlag(Flags.U_REGISTERED); user.clearFlag(Flags.U_READY); user.account.name = sock.user.name; + user.registrationTime = sock.user.registrationTime; user.refreshAccount(function (err, account) { if (err) { user.clearFlag(Flags.U_REGISTERED); diff --git a/src/user.js b/src/user.js index a538c9b2..e38d5648 100644 --- a/src/user.js +++ b/src/user.js @@ -449,4 +449,18 @@ User.prototype.refreshAccount = function (cb) { }); }; +User.prototype.getFirstSeenTime = function getFirstSeenTime() { + if (this.registrationTime && this.socket.ipReputation && this.socket.ipReputation.first_seen) { + return Math.min(this.registrationTime.getTime(), this.socket.ipReputation.first_seen.getTime()); + } else if (this.registrationTime) { + return this.registrationTime.getTime(); + } else if (this.socket.ipReputation && this.socket.ipReputation.first_seen) { + return this.socket.ipReputation.first_seen.getTime(); + } else { + Logger.errlog.log(`User "${this.getName()}" (IP: ${this.realip}) has neither ` + + "an IP reputation nor a registered account."); + return Date.now(); + } +}; + module.exports = User; diff --git a/www/js/callbacks.js b/www/js/callbacks.js index e894faa4..6b89328e 100644 --- a/www/js/callbacks.js +++ b/www/js/callbacks.js @@ -88,6 +88,22 @@ Callbacks = { scrollChat(); }, + spamFiltered: function(data) { + var message = "Spam Filtered."; + switch (data.reason) { + case "NEW_USER_CHAT": + message = "Your account is too new to chat in this channel. " + + "Please wait a while and try again."; + break; + case "NEW_USER_CHAT_LINK": + message = "Your account is too new to post links in this channel. " + + "Please wait a while and try again."; + break; + } + + errDialog(message); + }, + needPassword: function (wrongpw) { var div = $("
"); $("").text("Channel Password") From 8305c235ebd3266624c84f8f22b7ad2af93a0425 Mon Sep 17 00:00:00 2001 From: calzoneman Date: Sat, 6 Aug 2016 20:44:15 -0700 Subject: [PATCH 04/10] Add initial channel setting for new account chat delay --- src/channel/chat.js | 40 ++++++++++++++++++++++++++---------- src/channel/opts.js | 18 +++++++++++++++- templates/channeloptions.pug | 14 +++++++++++++ www/js/util.js | 4 +++- 4 files changed, 63 insertions(+), 13 deletions(-) diff --git a/src/channel/chat.js b/src/channel/chat.js index da2117b7..83d252a7 100644 --- a/src/channel/chat.js +++ b/src/channel/chat.js @@ -121,6 +121,28 @@ ChatModule.prototype.shadowMutedUsers = function () { }); }; +ChatModule.prototype.restrictNewAccount = function restrictNewAccount(user, data) { + if (user.account.effectiveRank < 2 && this.channel.modules.options) { + const firstSeen = user.getFirstSeenTime(); + const opts = this.channel.modules.options; + // TODO: configurable times + if (firstSeen > Date.now() - opts.get("new_user_chat_delay")) { + user.socket.emit("spamFiltered", { + reason: "NEW_USER_CHAT" + }); + return true; + } else if ((firstSeen > Date.now() - opts.get("new_user_chat_link_delay")) + && data.msg.match(LINK)) { + user.socket.emit("spamFiltered", { + reason: "NEW_USER_CHAT_LINK" + }); + return true; + } + } + + return false; +}; + ChatModule.prototype.handleChatMsg = function (user, data) { var self = this; counters.add("chat:incoming"); @@ -132,17 +154,8 @@ ChatModule.prototype.handleChatMsg = function (user, data) { // Limit to 240 characters data.msg = data.msg.substring(0, 240); - const firstSeen = user.getFirstSeenTime(); - // TODO: configurable times - if (firstSeen > Date.now() - 5 * 60 * 1000) { - user.socket.emit("spamFiltered", { - reason: "NEW_USER_CHAT" - }); - return; - } else if ((firstSeen > Date.now() - 24 * 60 * 60 * 1000) && data.msg.match(LINK)) { - user.socket.emit("spamFiltered", { - reason: "NEW_USER_CHAT_LINK" - }); + // Restrict new accounts/IPs from chatting and posting links + if (this.restrictNewAccount(user, data)) { return; } @@ -188,6 +201,11 @@ ChatModule.prototype.handlePm = function (user, data) { msg: "You must be signed in to send PMs" }); } + + // Restrict new accounts/IPs from chatting and posting links + if (this.restrictNewAccount(user, data)) { + return; + } if (data.msg.match(Config.get("link-domain-blacklist-regex"))) { this.channel.logger.log(user.displayip + " (" + user.getName() + ") was kicked for " + diff --git a/src/channel/opts.js b/src/channel/opts.js index 45455324..14b37728 100644 --- a/src/channel/opts.js +++ b/src/channel/opts.js @@ -25,7 +25,9 @@ function OptionsModule(channel) { allow_dupes: false, // Allow duplicate videos on the playlist torbanned: false, // Block connections from Tor exit nodes allow_ascii_control: false,// Allow ASCII control characters (\x00-\x1f) - playlist_max_per_user: 0 // Maximum number of playlist items per user + playlist_max_per_user: 0, // Maximum number of playlist items per user + new_user_chat_delay: 10 * 60 * 1000, // Minimum account/IP age to chat + new_user_chat_link_delay: 60 * 60 * 1000 // Minimum account/IP age to post links }; } @@ -271,6 +273,20 @@ OptionsModule.prototype.handleSetOptions = function (user, data) { } } + if ("new_user_chat_delay" in data) { + var delay = parseInt(data.new_user_chat_delay); + if (!isNaN(delay) && delay >= 0) { + this.opts.new_user_chat_delay = delay; + } + } + + if ("new_user_chat_link_delay" in data) { + var delay = parseInt(data.new_user_chat_link_delay); + if (!isNaN(delay) && delay >= 0) { + this.opts.new_user_chat_link_delay = delay; + } + } + this.channel.logger.log("[mod] " + user.getName() + " updated channel options"); this.sendOpts(this.channel.users); }; diff --git a/templates/channeloptions.pug b/templates/channeloptions.pug index dfff94e1..6b7e69d8 100644 --- a/templates/channeloptions.pug +++ b/templates/channeloptions.pug @@ -46,6 +46,15 @@ mixin textbox-auto(id, label, placeholder) else input.form-control.cs-textbox(id=id, type="text") +mixin textbox-timeinput-auto(id, label, placeholder) + .form-group + label.control-label.col-sm-4(for=id)= label + .col-sm-8 + if placeholder + input.form-control.cs-textbox-timeinput(id=id, type="text", placeholder=placeholder) + else + input.form-control.cs-textbox-timeinput(id=id, type="text") + mixin miscoptions #cs-miscoptions.tab-pane.active h4 General Settings @@ -63,6 +72,11 @@ mixin miscoptions +rcheckbox-auto("cs-chat_antiflood", "Throttle chat") +textbox-auto("cs-chat_antiflood_burst", "# of messages allowed before throttling") +textbox-auto("cs-chat_antiflood_sustained", "# of messages (after burst) allowed per second") + +textbox-timeinput-auto("cs-new_user_chat_delay", "Delay before new accounts can chat", "0") + .form-group + .col-sm-8.col-sm-offset-4 + span.text-info Restrictions to new accounts can be disabled by setting the delay to 0. + +textbox-timeinput-auto("cs-new_user_chat_link_delay", "Delay before new accounts can post links in chat", "0") .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 98651b47..fb721348 100644 --- a/www/js/util.js +++ b/www/js/util.js @@ -930,6 +930,8 @@ function handleModPermissions() { $("#cs-torbanned").prop("checked", CHANNEL.opts.torbanned); $("#cs-allow_ascii_control").prop("checked", CHANNEL.opts.allow_ascii_control); $("#cs-playlist_max_per_user").val(CHANNEL.opts.playlist_max_per_user || 0); + $("#cs-new_user_chat_delay").val(CHANNEL.opts.new_user_chat_delay || 0); + $("#cs-new_user_chat_link_delay").val(CHANNEL.opts.new_user_chat_link_delay || 0); (function() { if(typeof CHANNEL.opts.maxlength != "number") { $("#cs-maxlength").val(""); @@ -1450,7 +1452,7 @@ function stripImages(msg){ return msg; } return msg.replace(IMAGE_MATCH, function(match,img){ - return CHANNEL.opts.enable_link_regex ? + return CHANNEL.opts.enable_link_regex ? ''+img+'' : img; }); } From 74cb1b3efc5f21a2a447440e619fc7771c3108f2 Mon Sep 17 00:00:00 2001 From: calzoneman Date: Sun, 7 Aug 2016 22:07:52 -0700 Subject: [PATCH 05/10] Implement time parsing/formatting for channel settings --- src/channel/chat.js | 7 +++---- src/channel/opts.js | 8 ++++---- www/js/ui.js | 30 ++++++++++++++++++++++++++++++ www/js/util.js | 29 +++++++++++++++++------------ 4 files changed, 54 insertions(+), 20 deletions(-) diff --git a/src/channel/chat.js b/src/channel/chat.js index 83d252a7..4637cd19 100644 --- a/src/channel/chat.js +++ b/src/channel/chat.js @@ -125,13 +125,12 @@ ChatModule.prototype.restrictNewAccount = function restrictNewAccount(user, data if (user.account.effectiveRank < 2 && this.channel.modules.options) { const firstSeen = user.getFirstSeenTime(); const opts = this.channel.modules.options; - // TODO: configurable times - if (firstSeen > Date.now() - opts.get("new_user_chat_delay")) { + if (firstSeen > Date.now() - opts.get("new_user_chat_delay")*1000) { user.socket.emit("spamFiltered", { reason: "NEW_USER_CHAT" }); return true; - } else if ((firstSeen > Date.now() - opts.get("new_user_chat_link_delay")) + } else if ((firstSeen > Date.now() - opts.get("new_user_chat_link_delay")*1000) && data.msg.match(LINK)) { user.socket.emit("spamFiltered", { reason: "NEW_USER_CHAT_LINK" @@ -201,7 +200,7 @@ ChatModule.prototype.handlePm = function (user, data) { msg: "You must be signed in to send PMs" }); } - + // Restrict new accounts/IPs from chatting and posting links if (this.restrictNewAccount(user, data)) { return; diff --git a/src/channel/opts.js b/src/channel/opts.js index 14b37728..acabee46 100644 --- a/src/channel/opts.js +++ b/src/channel/opts.js @@ -26,8 +26,8 @@ function OptionsModule(channel) { torbanned: false, // Block connections from Tor exit nodes allow_ascii_control: false,// Allow ASCII control characters (\x00-\x1f) playlist_max_per_user: 0, // Maximum number of playlist items per user - new_user_chat_delay: 10 * 60 * 1000, // Minimum account/IP age to chat - new_user_chat_link_delay: 60 * 60 * 1000 // Minimum account/IP age to post links + new_user_chat_delay: 10 * 60, // Minimum account/IP age to chat + new_user_chat_link_delay: 60 * 60 // Minimum account/IP age to post links }; } @@ -274,14 +274,14 @@ OptionsModule.prototype.handleSetOptions = function (user, data) { } if ("new_user_chat_delay" in data) { - var delay = parseInt(data.new_user_chat_delay); + var delay = data.new_user_chat_delay; if (!isNaN(delay) && delay >= 0) { this.opts.new_user_chat_delay = delay; } } if ("new_user_chat_link_delay" in data) { - var delay = parseInt(data.new_user_chat_link_delay); + var delay = data.new_user_chat_link_delay; if (!isNaN(delay) && delay >= 0) { this.opts.new_user_chat_link_delay = delay; } diff --git a/www/js/ui.js b/www/js/ui.js index a5410905..2e6b6869 100644 --- a/www/js/ui.js +++ b/www/js/ui.js @@ -636,6 +636,36 @@ $(".cs-textbox").keyup(function () { }, 1000); }); +$(".cs-textbox-timeinput").keyup(function (event) { + var box = $(this); + var key = box.attr("id").replace("cs-", ""); + var value = box.val(); + var lastkey = Date.now(); + box.data("lastkey", lastkey); + + setTimeout(function () { + if (box.data("lastkey") !== lastkey || box.val() !== value) { + return; + } + + $("#cs-textbox-timeinput-validation-error-" + key).remove(); + $(event.target).parent().removeClass("has-error"); + var data = {}; + try { + data[key] = parseTimeout(value); + } catch (error) { + var msg = "Invalid timespan value '" + value + "'. Please use the format " + + "HH:MM:SS or enter a single number for the number of seconds."; + var validationError = $("

").addClass("text-danger").text(msg) + .attr("id", "cs-textbox-timeinput-validation-error-" + key); + validationError.insertAfter(event.target); + $(event.target).parent().addClass("has-error"); + return; + } + socket.emit("setOptions", data); + }, 1000); +}); + $("#cs-chanlog-refresh").click(function () { socket.emit("readChanLog"); }); diff --git a/www/js/util.js b/www/js/util.js index fb721348..cc8d97de 100644 --- a/www/js/util.js +++ b/www/js/util.js @@ -759,18 +759,23 @@ function applyOpts() { } } -function showPollMenu() { - function parseTimeout(t) { - var m; - if (m = t.match(/^(\d+):(\d+)$/)) { - return parseInt(m[1], 10) * 60 + parseInt(m[2], 10); - } else if (m = t.match(/^(\d+)$/)) { - return parseInt(m[1], 10); - } else { - throw new Error("Invalid timeout value '" + t + "'"); - } +function parseTimeout(t) { + var m; + if (m = t.match(/^(\d+):(\d+):(\d+)$/)) { + // HH:MM:SS + return parseInt(m[1], 10) * 3600 + parseInt(m[2], 10) * 60 + parseInt(m[3], 10); + } else if (m = t.match(/^(\d+):(\d+)$/)) { + // MM:SS + return parseInt(m[1], 10) * 60 + parseInt(m[2], 10); + } else if (m = t.match(/^(\d+)$/)) { + // Seconds + return parseInt(m[1], 10); + } else { + throw new Error("Invalid timeout value '" + t + "'"); } +} +function showPollMenu() { $("#pollwrap .poll-menu").remove(); var menu = $("

").addClass("well poll-menu") .prependTo($("#pollwrap")); @@ -930,8 +935,8 @@ function handleModPermissions() { $("#cs-torbanned").prop("checked", CHANNEL.opts.torbanned); $("#cs-allow_ascii_control").prop("checked", CHANNEL.opts.allow_ascii_control); $("#cs-playlist_max_per_user").val(CHANNEL.opts.playlist_max_per_user || 0); - $("#cs-new_user_chat_delay").val(CHANNEL.opts.new_user_chat_delay || 0); - $("#cs-new_user_chat_link_delay").val(CHANNEL.opts.new_user_chat_link_delay || 0); + $("#cs-new_user_chat_delay").val(formatTime(CHANNEL.opts.new_user_chat_delay || 0)); + $("#cs-new_user_chat_link_delay").val(formatTime(CHANNEL.opts.new_user_chat_link_delay || 0)); (function() { if(typeof CHANNEL.opts.maxlength != "number") { $("#cs-maxlength").val(""); From 0327b3de2eeea8b9b9c2b16268707a4844c67774 Mon Sep 17 00:00:00 2001 From: calzoneman Date: Wed, 10 Aug 2016 22:10:02 -0700 Subject: [PATCH 06/10] Modifications for ip session cookie --- src/user.js | 10 +++++----- src/web/middleware/ipsessioncookie.js | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/user.js b/src/user.js index e38d5648..f1ffb91f 100644 --- a/src/user.js +++ b/src/user.js @@ -450,15 +450,15 @@ User.prototype.refreshAccount = function (cb) { }; User.prototype.getFirstSeenTime = function getFirstSeenTime() { - if (this.registrationTime && this.socket.ipReputation && this.socket.ipReputation.first_seen) { - return Math.min(this.registrationTime.getTime(), this.socket.ipReputation.first_seen.getTime()); + if (this.registrationTime && this.socket.ipSessionFirstSeen) { + return Math.min(this.registrationTime.getTime(), this.socket.ipSessionFirstSeen); } else if (this.registrationTime) { return this.registrationTime.getTime(); - } else if (this.socket.ipReputation && this.socket.ipReputation.first_seen) { - return this.socket.ipReputation.first_seen.getTime(); + } else if (this.socket.ipSessionFirstSeen) { + return this.socket.ipSessionFirstSeen; } else { Logger.errlog.log(`User "${this.getName()}" (IP: ${this.realip}) has neither ` + - "an IP reputation nor a registered account."); + "an IP sesion first seen time nor a registered account."); return Date.now(); } }; diff --git a/src/web/middleware/ipsessioncookie.js b/src/web/middleware/ipsessioncookie.js index e74b1f55..4bef5c0f 100644 --- a/src/web/middleware/ipsessioncookie.js +++ b/src/web/middleware/ipsessioncookie.js @@ -4,6 +4,7 @@ import crypto from 'crypto'; const SALT_PATH = path.resolve(__dirname, '..', '..', '..', 'state', 'ipsessionsalt.json'); +const NO_EXPIRATION = new Date('Fri, 31 Dec 9999 23:59:59 GMT'); var SALT; try { SALT = require(SALT_PATH); @@ -67,7 +68,8 @@ export function ipSessionCookieMiddleware(req, res, next) { if (!hasSession) { res.cookie('ip-session', createIPSessionCookie(req.realIP, firstSeen), { signed: true, - httpOnly: true + httpOnly: true, + expires: NO_EXPIRATION }); } From 05b40b80919e0c65ce15e49e90dc7aa923567425 Mon Sep 17 00:00:00 2001 From: calzoneman Date: Wed, 10 Aug 2016 22:10:17 -0700 Subject: [PATCH 07/10] Bump version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7643b71c..21813f9a 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "Calvin Montgomery", "name": "CyTube", "description": "Online media synchronizer and chat", - "version": "3.19.0", + "version": "3.20.0", "repository": { "url": "http://github.com/calzoneman/sync" }, From 33f775051dfcd4642cb08a2799b8410fd828d5aa Mon Sep 17 00:00:00 2001 From: calzoneman Date: Wed, 10 Aug 2016 22:20:53 -0700 Subject: [PATCH 08/10] Fixes for bot logins --- src/database/accounts.js | 4 ++-- src/user.js | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/database/accounts.js b/src/database/accounts.js index 5128e858..3c0e4846 100644 --- a/src/database/accounts.js +++ b/src/database/accounts.js @@ -134,7 +134,7 @@ module.exports = { callback(err, null); return; } - + if (accts.length >= Config.get("max-accounts-per-ip")) { delete registrationLock[lname]; callback("You have registered too many accounts from this "+ @@ -207,7 +207,7 @@ module.exports = { the hashes match. */ - db.query("SELECT name,password,global_rank FROM `users` WHERE name=?", + db.query("SELECT name,password,global_rank,time FROM `users` WHERE name=?", [name], function (err, rows) { if (err) { diff --git a/src/user.js b/src/user.js index f1ffb91f..e2bd66e8 100644 --- a/src/user.js +++ b/src/user.js @@ -288,6 +288,7 @@ User.prototype.login = function (name, pw) { } self.account.name = user.name; + self.registrationTime = new Date(user.time); self.setFlag(Flags.U_REGISTERED); self.refreshAccount(function (err, account) { if (err) { @@ -451,11 +452,11 @@ User.prototype.refreshAccount = function (cb) { User.prototype.getFirstSeenTime = function getFirstSeenTime() { if (this.registrationTime && this.socket.ipSessionFirstSeen) { - return Math.min(this.registrationTime.getTime(), this.socket.ipSessionFirstSeen); + return Math.min(this.registrationTime.getTime(), this.socket.ipSessionFirstSeen.getTime()); } else if (this.registrationTime) { return this.registrationTime.getTime(); } else if (this.socket.ipSessionFirstSeen) { - return this.socket.ipSessionFirstSeen; + return this.socket.ipSessionFirstSeen.getTime(); } else { Logger.errlog.log(`User "${this.getName()}" (IP: ${this.realip}) has neither ` + "an IP sesion first seen time nor a registered account."); From 17aad006f757a6efcfff0c222943e1d30931f046 Mon Sep 17 00:00:00 2001 From: calzoneman Date: Wed, 10 Aug 2016 22:37:33 -0700 Subject: [PATCH 09/10] Fix startup issue --- src/server.js | 5 ----- src/web/middleware/ipsessioncookie.js | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/server.js b/src/server.js index 3a5c328a..593e21b4 100644 --- a/src/server.js +++ b/src/server.js @@ -18,11 +18,6 @@ module.exports = { exists || fs.mkdir(chandumppath); }); - var statepath = path.join(__dirname, "../state"); - fs.exists(statepath, function (exists) { - exists || fs.mkdir(statepath); - }); - var gdvttpath = path.join(__dirname, "../google-drive-subtitles"); fs.exists(gdvttpath, function (exists) { exists || fs.mkdir(gdvttpath); diff --git a/src/web/middleware/ipsessioncookie.js b/src/web/middleware/ipsessioncookie.js index 4bef5c0f..779c1da2 100644 --- a/src/web/middleware/ipsessioncookie.js +++ b/src/web/middleware/ipsessioncookie.js @@ -2,6 +2,7 @@ import path from 'path'; import fs from 'fs'; import crypto from 'crypto'; +const STATE_FOLDER_PATH = path.resolve(__dirname, '..', '..', '..', 'state'); const SALT_PATH = path.resolve(__dirname, '..', '..', '..', 'state', 'ipsessionsalt.json'); const NO_EXPIRATION = new Date('Fri, 31 Dec 9999 23:59:59 GMT'); @@ -10,6 +11,13 @@ try { SALT = require(SALT_PATH); } catch (error) { SALT = crypto.randomBytes(32).toString('base64'); + try { + fs.mkdirSync(STATE_FOLDER_PATH); + } catch (error) { + if (error.code !== 'EEXIST') { + throw error; + } + } fs.writeFileSync(SALT_PATH, JSON.stringify(SALT)); } From 377512340aa3cab3791d65b7506215bf9374bc29 Mon Sep 17 00:00:00 2001 From: Calvin Montgomery Date: Wed, 24 Aug 2016 19:49:26 -0700 Subject: [PATCH 10/10] Bump package version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 698ae34c..5bf34594 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "Calvin Montgomery", "name": "CyTube", "description": "Online media synchronizer and chat", - "version": "3.20.0", + "version": "3.21.0", "repository": { "url": "http://github.com/calzoneman/sync" },