mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
feat: logging password resets and errors into event log
closes #7343, also adds tests for password reset socket calls
This commit is contained in:
@@ -39,6 +39,7 @@
|
|||||||
"username-too-short": "Username too short",
|
"username-too-short": "Username too short",
|
||||||
"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)",
|
||||||
|
|
||||||
"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)",
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
var winston = require('winston');
|
|
||||||
|
|
||||||
var user = require('../user');
|
var user = require('../user');
|
||||||
var topics = require('../topics');
|
var topics = require('../topics');
|
||||||
@@ -102,17 +101,17 @@ SocketUser.reset.send = function (socket, email, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
user.reset.send(email, function (err) {
|
user.reset.send(email, function (err) {
|
||||||
if (err) {
|
events.log({
|
||||||
switch (err.message) {
|
type: 'password-reset',
|
||||||
case '[[error:invalid-email]]':
|
text: err ? err.message : '[[success:success]]',
|
||||||
winston.warn('[user/reset] Invalid email attempt: ' + email + ' by IP ' + socket.ip + (socket.uid ? ' (uid: ' + socket.uid + ')' : ''));
|
ip: socket.ip,
|
||||||
err = null;
|
uid: socket.uid,
|
||||||
break;
|
email: email,
|
||||||
|
});
|
||||||
|
|
||||||
case '[[error:reset-rate-limited]]':
|
const internalErrors = ['[[error:invalid-email]]', '[[error:reset-rate-limited]]'];
|
||||||
err = null;
|
if (err && internalErrors.includes(err.message)) {
|
||||||
break;
|
err = null;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(callback.bind(err), 2500);
|
setTimeout(callback.bind(err), 2500);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ var groups = require('../src/groups');
|
|||||||
var categories = require('../src/categories');
|
var categories = require('../src/categories');
|
||||||
var helpers = require('./helpers');
|
var helpers = require('./helpers');
|
||||||
var meta = require('../src/meta');
|
var meta = require('../src/meta');
|
||||||
|
const events = require('../src/events');
|
||||||
|
|
||||||
var socketAdmin = require('../src/socket.io/admin');
|
var socketAdmin = require('../src/socket.io/admin');
|
||||||
|
|
||||||
@@ -634,4 +635,72 @@ describe('socket.io', function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('password reset', function () {
|
||||||
|
const socketUser = require('../src/socket.io/user');
|
||||||
|
|
||||||
|
it('should not error on valid email', function (done) {
|
||||||
|
socketUser.reset.send({ uid: 0 }, 'regular@test.com', function (err) {
|
||||||
|
assert.ifError(err);
|
||||||
|
|
||||||
|
async.parallel({
|
||||||
|
count: async.apply(db.sortedSetCount.bind(db), 'reset:issueDate', 0, Date.now()),
|
||||||
|
event: async.apply(events.getEvents, '', 0, 0),
|
||||||
|
}, function (err, data) {
|
||||||
|
assert.ifError(err);
|
||||||
|
assert.strictEqual(data.count, 1);
|
||||||
|
|
||||||
|
// Event validity
|
||||||
|
assert.strictEqual(data.event.length, 1);
|
||||||
|
const event = data.event[0];
|
||||||
|
assert.strictEqual(event.type, 'password-reset');
|
||||||
|
assert.strictEqual(event.text, '[[success:success]]');
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not generate code if rate limited', function (done) {
|
||||||
|
socketUser.reset.send({ uid: 0 }, 'regular@test.com', function (err) {
|
||||||
|
assert.ifError(err);
|
||||||
|
|
||||||
|
async.parallel({
|
||||||
|
count: async.apply(db.sortedSetCount.bind(db), 'reset:issueDate', 0, Date.now()),
|
||||||
|
event: async.apply(events.getEvents, '', 0, 0),
|
||||||
|
}, function (err, data) {
|
||||||
|
assert.ifError(err);
|
||||||
|
assert.strictEqual(data.count, 1); // should still equal 1
|
||||||
|
|
||||||
|
// Event validity
|
||||||
|
assert.strictEqual(data.event.length, 1);
|
||||||
|
const event = data.event[0];
|
||||||
|
assert.strictEqual(event.type, 'password-reset');
|
||||||
|
assert.strictEqual(event.text, '[[error:reset-rate-limited]]');
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not error on invalid email (but not generate reset code)', function (done) {
|
||||||
|
socketUser.reset.send({ uid: 0 }, 'irregular@test.com', function (err) {
|
||||||
|
assert.ifError(err);
|
||||||
|
|
||||||
|
db.sortedSetCount('reset:issueDate', 0, Date.now(), function (err, count) {
|
||||||
|
assert.ifError(err);
|
||||||
|
assert.strictEqual(count, 1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error on no email', function (done) {
|
||||||
|
socketUser.reset.send({ uid: 0 }, '', function (err) {
|
||||||
|
assert(err instanceof Error);
|
||||||
|
assert.strictEqual(err.message, '[[error:invalid-data]]');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user