From b0ee92600c4904c276d4249c8320642aecf024be Mon Sep 17 00:00:00 2001 From: vimark Date: Wed, 30 Aug 2023 00:19:40 +1200 Subject: [PATCH 1/3] Added logout functionality to allow users to log out from all devices and locations. --- app.js | 1 + controllers/user.js | 21 +++++++++++++++++++++ models/Session.js | 21 +++++++++++++++++++++ views/account/profile.pug | 15 ++++++++++++++- 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 models/Session.js diff --git a/app.js b/app.js index 898d6d45de..4345857657 100644 --- a/app.js +++ b/app.js @@ -156,6 +156,7 @@ app.get('/account', passportConfig.isAuthenticated, userController.getAccount); app.post('/account/profile', passportConfig.isAuthenticated, userController.postUpdateProfile); app.post('/account/password', passportConfig.isAuthenticated, userController.postUpdatePassword); app.post('/account/delete', passportConfig.isAuthenticated, userController.postDeleteAccount); +app.post('/account/logout-everywhere', passportConfig.isAuthenticated, userController.postLogoutEverywhere); app.get('/account/unlink/:provider', passportConfig.isAuthenticated, userController.getOauthUnlink); /** diff --git a/controllers/user.js b/controllers/user.js index 46e720822e..8328f4612d 100644 --- a/controllers/user.js +++ b/controllers/user.js @@ -6,6 +6,7 @@ const _ = require('lodash'); const validator = require('validator'); const mailChecker = require('mailchecker'); const User = require('../models/User'); +const Session = require('../models/Session'); const randomBytesAsync = promisify(crypto.randomBytes); @@ -542,3 +543,23 @@ exports.postForgot = (req, res, next) => { .then(() => res.redirect('/forgot')) .catch(next); }; + +/** + * POST /account/logout-everywhere + * Logout current user from all devices + */ +exports.postLogoutEverywhere = async (req, res, next) => { + const userId = req.user.id; + try { + await Session.removeSessionByUserId(userId); + req.logout((err) => { + if (err) { + return next(err); + } + req.flash('info', { msg: 'You have been logged out of all sessions.' }); + res.redirect('/'); + }); + } catch (err) { + return next(err); + } +}; diff --git a/models/Session.js b/models/Session.js new file mode 100644 index 0000000000..a214909fad --- /dev/null +++ b/models/Session.js @@ -0,0 +1,21 @@ +const mongoose = require('mongoose'); + +const sessionSchema = new mongoose.Schema({ + session: String, + expires: Date, +}); + +sessionSchema.statics = { + /** + * Removes all sessions for a given user + * @param {string} userId + * @returns {Promise} + */ + removeSessionByUserId(userId) { + return this.deleteMany({ session: { $regex: userId } }); + } +}; + +const Session = mongoose.model('Session', sessionSchema); + +module.exports = Session; diff --git a/views/account/profile.pug b/views/account/profile.pug index ae353ef8f7..373381b82c 100644 --- a/views/account/profile.pug +++ b/views/account/profile.pug @@ -73,6 +73,19 @@ block content i.fas.fa-lock.fa-sm.iconpadding | Change Password + .pb-2.mt-2.mb-4.border-bottom + h3 Logout Everywhere + + form(action='/account/logout-everywhere', method='POST') + input(type='hidden', name='_csrf', value=_csrf) + .form-group + p.offset-sm-3.col-md-7.pl-2 This will log you out of all devices and locations. + + .offset-sm-3.col-md-7.pl-2 + button.btn.btn-danger(type='submit') + i.fas.fa-sm.iconpadding.fa-sign-out-alt + | Logout everywhere + .pb-2.mt-2.mb-4.border-bottom h3 Delete Account @@ -131,4 +144,4 @@ block content if user.quickbooks p.mb-1: a.text-danger(href='/account/unlink/quickbooks') Unlink your QuickBooks account else - p.mb-1: a(href='/auth/quickbooks') Link your QuickBooks account \ No newline at end of file + p.mb-1: a(href='/auth/quickbooks') Link your QuickBooks account From be6116b4561d70ddd6369ef22b52eb45d3aa5245 Mon Sep 17 00:00:00 2001 From: vimark Date: Wed, 30 Aug 2023 00:21:33 +1200 Subject: [PATCH 2/3] Changed mode of .husky/pre-commit to 100755. --- .husky/pre-commit | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .husky/pre-commit diff --git a/.husky/pre-commit b/.husky/pre-commit old mode 100644 new mode 100755 From f4a9918f200b1b0c2e7c2be320ecf56604f03e1f Mon Sep 17 00:00:00 2001 From: vimark Date: Wed, 30 Aug 2023 16:39:49 +1200 Subject: [PATCH 3/3] Remove only valid sessions and while improving performance for using index --- models/Session.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/models/Session.js b/models/Session.js index a214909fad..165a16e62d 100644 --- a/models/Session.js +++ b/models/Session.js @@ -7,12 +7,15 @@ const sessionSchema = new mongoose.Schema({ sessionSchema.statics = { /** - * Removes all sessions for a given user + * Removes all valid sessions for a given user * @param {string} userId * @returns {Promise} */ removeSessionByUserId(userId) { - return this.deleteMany({ session: { $regex: userId } }); + return this.deleteMany({ + expires: { $gt: new Date() }, + session: { $regex: userId } + }); } };