2
1
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2023-12-13 21:00:40 +01:00

Disable user validation and errors on login

fixes #3658

- Catch any errors from user.save() events during login
- Prevent validation from happening at all when only updating status/last_login
- Fixes a problem I introduced with errors which are arrays in logError
This commit is contained in:
Hannah Wolfe 2014-08-07 18:50:23 +01:00
parent 4b83dfd6ab
commit 8d46705dbb
2 changed files with 46 additions and 9 deletions

View file

@ -84,15 +84,20 @@ errors = {
},
logError: function (err, context, help) {
var self = this,
origArgs = _.toArray(arguments).slice(1),
stack,
msgs;
if (_.isArray(err)) {
_.each(err, function (e) {
errors.logError(e);
var newArgs = [e].concat(origArgs);
errors.logError.apply(self, newArgs);
});
return;
}
var stack = err ? err.stack : null,
msgs;
stack = err ? err.stack : null;
err = _.isString(err) ? err : (_.isObject(err) ? err.message : 'An unknown error occurred.');

View file

@ -7,6 +7,7 @@ var _ = require('lodash'),
http = require('http'),
crypto = require('crypto'),
validator = require('validator'),
validation = require('../data/validation'),
Role = require('./role').Role,
tokenSecurity = {},
@ -55,6 +56,17 @@ User = ghostBookshelf.Model.extend({
}
},
// For the user model ONLY it is possible to disable validations.
// This is used to bypass validation during the credential check, and must never be done with user-provided data
// Should be removed when #3691 is done
validate: function () {
var opts = arguments[1];
if (opts && _.has(opts, 'validate') && opts.validate === false) {
return;
}
return validation.validateSchema(this.tableName, this.toJSON());
},
// Get the user from the options object
contextUser: function (options) {
// Default to context user
@ -561,7 +573,7 @@ User = ghostBookshelf.Model.extend({
return when.reject();
},
setWarning: function (user) {
setWarning: function (user, options) {
var status = user.get('status'),
regexp = /warn-(\d+)/i,
level;
@ -577,7 +589,7 @@ User = ghostBookshelf.Model.extend({
user.set('status', 'warn-' + level);
}
}
return when(user.save()).then(function () {
return when(user.save(options)).then(function () {
return 5 - level;
});
},
@ -598,16 +610,36 @@ User = ghostBookshelf.Model.extend({
if (user.get('status') !== 'locked') {
return nodefn.call(bcrypt.compare, object.password, user.get('password')).then(function (matched) {
if (!matched) {
return when(self.setWarning(user)).then(function (remaining) {
return when(self.setWarning(user, {validate: false})).then(function (remaining) {
s = (remaining > 1) ? 's' : '';
return when.reject(new errors.UnauthorizedError('Your password is incorrect.<br>' +
remaining + ' attempt' + s + ' remaining!'));
// Use comma structure, not .catch, because we don't want to catch incorrect passwords
}, function (error) {
// If we get a validation or other error during this save, catch it and log it, but don't
// cause a login error because of it. The user validation is not important here.
errors.logError(
error,
'Error thrown from user update during login',
'Visit and save your profile after logging in to check for problems.'
);
return when.reject(new errors.UnauthorizedError('Your password is incorrect.'));
});
}
return when(user.set({status : 'active', last_login : new Date()}).save()).then(function (user) {
return user;
});
return when(user.set({status : 'active', last_login : new Date()}).save({validate: false}))
.catch(function (error) {
// If we get a validation or other error during this save, catch it and log it, but don't
// cause a login error because of it. The user validation is not important here.
errors.logError(
error,
'Error thrown from user update during login',
'Visit and save your profile after logging in to check for problems.'
);
return user;
});
}, errors.logAndThrowError);
}
return when.reject(new errors.NoPermissionError('Your account is locked due to too many ' +