From b3ed26ac2ce9b16b2c0ed95929e7fedf012d1b8d Mon Sep 17 00:00:00 2001 From: cryptoethic <44468286+cryptoethic@users.noreply.github.com> Date: Thu, 8 Oct 2020 23:33:18 +0200 Subject: [PATCH] feat: revoke user sessions above threshold (#8731) * feat: revoke user sessions above threshold * fix: removed translations from en-US * fix: defined default maxUserSessions in install\data\defaults.json --- install/data/defaults.json | 3 ++- public/language/en-GB/admin/settings/cookies.json | 1 + src/user/auth.js | 9 +++++++++ src/views/admin/settings/cookies.tpl | 8 ++++++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/install/data/defaults.json b/install/data/defaults.json index 8fd574fb3a..ec5137ac49 100644 --- a/install/data/defaults.json +++ b/install/data/defaults.json @@ -133,5 +133,6 @@ "timeagoCutoff": 30, "necroThreshold": 7, "categoryWatchState": "watching", - "submitPluginUsage": 1 + "submitPluginUsage": 1, + "maxUserSessions": 10 } \ No newline at end of file diff --git a/public/language/en-GB/admin/settings/cookies.json b/public/language/en-GB/admin/settings/cookies.json index a6244febdd..1ffd2dced4 100644 --- a/public/language/en-GB/admin/settings/cookies.json +++ b/public/language/en-GB/admin/settings/cookies.json @@ -8,5 +8,6 @@ "consent.blank-localised-default": "Leave blank to use NodeBB localised defaults", "settings": "Settings", "cookie-domain": "Session cookie domain", + "max-user-sessions": "Max active sessions per user", "blank-default": "Leave blank for default" } \ No newline at end of file diff --git a/src/user/auth.js b/src/user/auth.js index da8551d831..10a943b088 100644 --- a/src/user/auth.js +++ b/src/user/auth.js @@ -107,9 +107,18 @@ module.exports = function (User) { return; } await cleanExpiredSessions(uid); + await revokeSessionsAboveThreshold(uid, meta.config.maxUserSessions); await db.sortedSetAdd('uid:' + uid + ':sessions', Date.now(), sessionId); }; + async function revokeSessionsAboveThreshold(uid, maxUserSessions) { + const activeSessions = await db.getSortedSetRange('uid:' + uid + ':sessions', 0, -1); + if (activeSessions.length > maxUserSessions) { + const sessionsToRevoke = activeSessions.slice(0, activeSessions.length - maxUserSessions); + await Promise.all(sessionsToRevoke.map(sessionId => User.auth.revokeSession(sessionId, uid))); + } + } + User.auth.revokeSession = async function (sessionId, uid) { winston.verbose('[user.auth] Revoking session ' + sessionId + ' for user ' + uid); const sessionObj = await getSessionFromStore(sessionId); diff --git a/src/views/admin/settings/cookies.tpl b/src/views/admin/settings/cookies.tpl index 94cec56bb6..367c86d257 100644 --- a/src/views/admin/settings/cookies.tpl +++ b/src/views/admin/settings/cookies.tpl @@ -53,6 +53,14 @@

+
+ +
+

+ [[admin/settings/cookies:blank-default]] +

+
+