mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-27 17:16:14 +01:00
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
This commit is contained in:
@@ -133,5 +133,6 @@
|
|||||||
"timeagoCutoff": 30,
|
"timeagoCutoff": 30,
|
||||||
"necroThreshold": 7,
|
"necroThreshold": 7,
|
||||||
"categoryWatchState": "watching",
|
"categoryWatchState": "watching",
|
||||||
"submitPluginUsage": 1
|
"submitPluginUsage": 1,
|
||||||
|
"maxUserSessions": 10
|
||||||
}
|
}
|
||||||
@@ -8,5 +8,6 @@
|
|||||||
"consent.blank-localised-default": "Leave blank to use NodeBB localised defaults",
|
"consent.blank-localised-default": "Leave blank to use NodeBB localised defaults",
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"cookie-domain": "Session cookie domain",
|
"cookie-domain": "Session cookie domain",
|
||||||
|
"max-user-sessions": "Max active sessions per user",
|
||||||
"blank-default": "Leave blank for default"
|
"blank-default": "Leave blank for default"
|
||||||
}
|
}
|
||||||
@@ -107,9 +107,18 @@ module.exports = function (User) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await cleanExpiredSessions(uid);
|
await cleanExpiredSessions(uid);
|
||||||
|
await revokeSessionsAboveThreshold(uid, meta.config.maxUserSessions);
|
||||||
await db.sortedSetAdd('uid:' + uid + ':sessions', Date.now(), sessionId);
|
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) {
|
User.auth.revokeSession = async function (sessionId, uid) {
|
||||||
winston.verbose('[user.auth] Revoking session ' + sessionId + ' for user ' + uid);
|
winston.verbose('[user.auth] Revoking session ' + sessionId + ' for user ' + uid);
|
||||||
const sessionObj = await getSessionFromStore(sessionId);
|
const sessionObj = await getSessionFromStore(sessionId);
|
||||||
|
|||||||
@@ -53,6 +53,14 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="maxUserSessions">[[admin/settings/cookies:max-user-sessions]]</label>
|
||||||
|
<input class="form-control" id="maxUserSessions" type="number" placeholder="10" data-field="maxUserSessions" /><br />
|
||||||
|
<p class="help-block">
|
||||||
|
[[admin/settings/cookies:blank-default]]
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button id="delete-all-sessions" class="btn btn-danger">Revoke All Sessions</button>
|
<button id="delete-all-sessions" class="btn btn-danger">Revoke All Sessions</button>
|
||||||
<p class="help-block">
|
<p class="help-block">
|
||||||
|
|||||||
Reference in New Issue
Block a user