From ede7a71db7fe4163a0994512b401a629ce6c06b8 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 11 Nov 2016 16:47:59 -0500 Subject: [PATCH] Fixes #5186 On socket.io connection, all clients join a room pertaining to their express session id. We use this room to keep track of any sessions in different browser windows (but the same cookie jar), so if a login/logout occurs, we can throw a session mismatch modal. This room can also be used to emit messages across windows/tabs... --- public/src/app.js | 8 ++++++++ public/src/client/login.js | 9 +++++++++ src/controllers/authentication.js | 13 ++++++++++++- src/socket.io/index.js | 1 + 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/public/src/app.js b/public/src/app.js index 8ac3e1ebff..ba1f6d39ff 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -88,6 +88,14 @@ app.cacheBuster = null; app.logout = function () { $(window).trigger('action:app.logout'); + + /* + Set session refresh flag (otherwise the session check will trip and throw invalid session modal) + We know the session is/will be invalid (uid mismatch) because the user is logging out + */ + app.flags = app.flags || {}; + app.flags._sessionRefresh = true; + $.ajax(config.relative_path + '/logout', { type: 'POST', headers: { diff --git a/public/src/client/login.js b/public/src/client/login.js index f798347c73..1de1218fd0 100644 --- a/public/src/client/login.js +++ b/public/src/client/login.js @@ -23,6 +23,14 @@ define('forum/login', ['translator'], function (translator) { } submitEl.addClass('disabled'); + + /* + Set session refresh flag (otherwise the session check will trip and throw invalid session modal) + We know the session is/will be invalid (uid mismatch) because the user is attempting a login + */ + app.flags = app.flags || {}; + app.flags._sessionRefresh = true; + formEl.ajaxSubmit({ headers: { 'x-csrf-token': config.csrf_token @@ -37,6 +45,7 @@ define('forum/login', ['translator'], function (translator) { errorEl.find('p').translateText(data.responseText); errorEl.show(); submitEl.removeClass('disabled'); + app.flags._sessionRefresh = false; // Select the entire password if that field has focus if ($('#password:focus').size()) { diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index 260a0e7281..1d45b2cbd5 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -15,6 +15,8 @@ var plugins = require('../plugins'); var utils = require('../../public/src/utils'); var Password = require('../password'); +var sockets = require('../socket.io'); + var authenticationController = {}; authenticationController.register = function (req, res, next) { @@ -326,6 +328,10 @@ authenticationController.onSuccessfulLogin = function (req, uid, callback) { if (err) { return callback(err); } + + // Force session check for all connected socket.io clients with the same session id + sockets.in('sess_' + req.sessionID).emit('checkSession', uid); + plugins.fireHook('action:user.loggedIn', uid); callback(); }); @@ -405,7 +411,9 @@ authenticationController.localLogin = function (req, username, password, next) { authenticationController.logout = function (req, res, next) { if (req.user && parseInt(req.user.uid, 10) > 0 && req.sessionID) { var uid = parseInt(req.user.uid, 10); - user.auth.revokeSession(req.sessionID, uid, function (err) { + var sessionID = req.sessionID; + + user.auth.revokeSession(sessionID, uid, function (err) { if (err) { return next(err); } @@ -416,6 +424,9 @@ authenticationController.logout = function (req, res, next) { plugins.fireHook('static:user.loggedOut', {req: req, res: res, uid: uid}, function () { res.status(200).send(''); + + // Force session check for all connected socket.io clients with the same session id + sockets.in('sess_' + sessionID).emit('checkSession', 0); }); }); } else { diff --git a/src/socket.io/index.js b/src/socket.io/index.js index 41f6739d36..38e73c1cc1 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -57,6 +57,7 @@ var ratelimit = require('../middleware/ratelimit'); socket.join('online_guests'); } + socket.join('sess_' + socket.request.signedCookies[nconf.get('sessionKey')]); io.sockets.sockets[socket.id].emit('checkSession', socket.uid); }