mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-08 15:05:46 +01:00
fix: #8991, logout on password reset, dont verify email if password expired
dont allow same password on reset
This commit is contained in:
@@ -46,6 +46,7 @@
|
|||||||
"username-too-long": "Username too long",
|
"username-too-long": "Username too long",
|
||||||
"password-too-long": "Password too long",
|
"password-too-long": "Password too long",
|
||||||
"reset-rate-limited": "Too many password reset requests (rate limited)",
|
"reset-rate-limited": "Too many password reset requests (rate limited)",
|
||||||
|
"reset-same-password": "Please use a password that is different from your current one",
|
||||||
|
|
||||||
"user-banned": "User banned",
|
"user-banned": "User banned",
|
||||||
"user-banned-reason": "Sorry, this account has been banned (Reason: %1)",
|
"user-banned-reason": "Sorry, this account has been banned (Reason: %1)",
|
||||||
|
|||||||
@@ -180,8 +180,9 @@ app.cacheBuster = null;
|
|||||||
message = message.message || message;
|
message = message.message || message;
|
||||||
|
|
||||||
if (message === '[[error:invalid-session]]') {
|
if (message === '[[error:invalid-session]]') {
|
||||||
|
app.handleInvalidSession();
|
||||||
app.logout(false);
|
app.logout(false);
|
||||||
return app.handleInvalidSession();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.alert({
|
app.alert({
|
||||||
|
|||||||
@@ -69,6 +69,9 @@ socket = window.socket;
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on('event:banned', onEventBanned);
|
socket.on('event:banned', onEventBanned);
|
||||||
|
socket.on('event:logout', function () {
|
||||||
|
app.logout();
|
||||||
|
});
|
||||||
socket.on('event:alert', function (params) {
|
socket.on('event:alert', function (params) {
|
||||||
app.alert(params);
|
app.alert(params);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ User.forcePasswordReset = async function (socket, uids) {
|
|||||||
|
|
||||||
await db.setObjectField(uids.map(uid => 'user:' + uid), 'passwordExpiry', Date.now());
|
await db.setObjectField(uids.map(uid => 'user:' + uid), 'passwordExpiry', Date.now());
|
||||||
await user.auth.revokeAllSessions(uids);
|
await user.auth.revokeAllSessions(uids);
|
||||||
|
uids.forEach(uid => sockets.in('uid_' + uid).emit('event:logout'));
|
||||||
};
|
};
|
||||||
|
|
||||||
User.deleteUsers = async function (socket, uids) {
|
User.deleteUsers = async function (socket, uids) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const batch = require('../batch');
|
|||||||
const db = require('../database');
|
const db = require('../database');
|
||||||
const meta = require('../meta');
|
const meta = require('../meta');
|
||||||
const emailer = require('../emailer');
|
const emailer = require('../emailer');
|
||||||
|
const Password = require('../password');
|
||||||
|
|
||||||
const UserReset = module.exports;
|
const UserReset = module.exports;
|
||||||
|
|
||||||
@@ -67,12 +68,28 @@ UserReset.commit = async function (code, password) {
|
|||||||
if (!uid) {
|
if (!uid) {
|
||||||
throw new Error('[[error:reset-code-not-valid]]');
|
throw new Error('[[error:reset-code-not-valid]]');
|
||||||
}
|
}
|
||||||
|
const userData = await db.getObjectFields(
|
||||||
|
'user:' + uid,
|
||||||
|
['password', 'passwordExpiry', 'password:shaWrapped']
|
||||||
|
);
|
||||||
|
const ok = await Password.compare(password, userData.password, !!parseInt(userData['password:shaWrapped'], 10));
|
||||||
|
if (ok) {
|
||||||
|
throw new Error('[[error:reset-same-password]]');
|
||||||
|
}
|
||||||
const hash = await user.hashPassword(password);
|
const hash = await user.hashPassword(password);
|
||||||
|
const data = {
|
||||||
|
password: hash,
|
||||||
|
'password:shaWrapped': 1,
|
||||||
|
};
|
||||||
|
|
||||||
await user.setUserFields(uid, { password: hash, 'email:confirmed': 1, 'password:shaWrapped': 1 });
|
// don't verify email if password reset is due to expiry
|
||||||
|
const isPasswordExpired = userData.passwordExpiry && userData.passwordExpiry < Date.now();
|
||||||
|
if (!isPasswordExpired) {
|
||||||
|
data['email:confirmed'] = 1;
|
||||||
await groups.join('verified-users', uid);
|
await groups.join('verified-users', uid);
|
||||||
await groups.leave('unverified-users', uid);
|
await groups.leave('unverified-users', uid);
|
||||||
|
}
|
||||||
|
await user.setUserFields(uid, data);
|
||||||
await db.deleteObjectField('reset:uid', code);
|
await db.deleteObjectField('reset:uid', code);
|
||||||
await db.sortedSetRemoveBulk([
|
await db.sortedSetRemoveBulk([
|
||||||
['reset:issueDate', code],
|
['reset:issueDate', code],
|
||||||
|
|||||||
29
test/user.js
29
test/user.js
@@ -628,6 +628,35 @@ describe('User', function () {
|
|||||||
},
|
},
|
||||||
], done);
|
], done);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('.should error if same password is used for reset', async function () {
|
||||||
|
const uid = await User.create({ username: 'badmemory', email: 'bad@memory.com', password: '123456' });
|
||||||
|
const code = await User.reset.generate(uid);
|
||||||
|
let err;
|
||||||
|
try {
|
||||||
|
await User.reset.commit(code, '123456');
|
||||||
|
} catch (_err) {
|
||||||
|
err = _err;
|
||||||
|
}
|
||||||
|
assert.strictEqual(err.message, '[[error:reset-same-password]]');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not validate email if password reset is due to expiry', async function () {
|
||||||
|
const uid = await User.create({ username: 'resetexpiry', email: 'reset@expiry.com', password: '123456' });
|
||||||
|
let confirmed = await User.getUserField(uid, 'email:confirmed');
|
||||||
|
let [verified, unverified] = await groups.isMemberOfGroups(uid, ['verified-users', 'unverified-users']);
|
||||||
|
assert.strictEqual(confirmed, 0);
|
||||||
|
assert.strictEqual(verified, false);
|
||||||
|
assert.strictEqual(unverified, true);
|
||||||
|
await User.setUserField(uid, 'passwordExpiry', Date.now());
|
||||||
|
const code = await User.reset.generate(uid);
|
||||||
|
await User.reset.commit(code, '654321');
|
||||||
|
confirmed = await User.getUserField(uid, 'email:confirmed');
|
||||||
|
[verified, unverified] = await groups.isMemberOfGroups(uid, ['verified-users', 'unverified-users']);
|
||||||
|
assert.strictEqual(confirmed, 0);
|
||||||
|
assert.strictEqual(verified, false);
|
||||||
|
assert.strictEqual(unverified, true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('hash methods', function () {
|
describe('hash methods', function () {
|
||||||
|
|||||||
Reference in New Issue
Block a user