0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-06 22:40:14 -05:00

add isPasswordCorrect fn to User Model (#7573)

refs #7432
- clean code!
- less code!
This commit is contained in:
Katharina Irrgang 2016-10-14 19:46:22 +02:00 committed by Hannah Wolfe
parent ca7b5643d5
commit 25b0c9eb9a

View file

@ -582,50 +582,62 @@ User = ghostBookshelf.Model.extend({
},
// Finds the user by email, and checks the password
// @TODO: shorten this function and rename...
check: function check(object) {
var self = this,
s;
return this.getByEmail(object.email).then(function then(user) {
if (!user) {
return Promise.reject(new errors.NotFoundError({message: i18n.t('errors.models.user.noUserWithEnteredEmailAddr')}));
}
if (user.get('status') !== 'locked') {
return bcryptCompare(object.password, user.get('password')).then(function then(matched) {
if (!matched) {
return Promise.resolve(self.setWarning(user, {validate: false})).then(function then(remaining) {
if (remaining === 0) {
// If remaining attempts = 0, the account has been locked, so show a locked account message
return Promise.reject(new errors.NoPermissionError({message: i18n.t('errors.models.user.accountLocked')}));
}
return self.isPasswordCorrect({plainPassword: object.password, hashedPassword: user.get('password')})
.then(function then() {
return Promise.resolve(user.set({status: 'active', last_login: new Date()}).save({validate: false}))
.catch(function handleError(err) {
// 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.
logging.error(new errors.GhostError({
err: err,
context: i18n.t('errors.models.user.userUpdateError.context'),
help: i18n.t('errors.models.user.userUpdateError.help')
}));
s = (remaining > 1) ? 's' : '';
return Promise.reject(new errors.UnauthorizedError({message: i18n.t('errors.models.user.incorrectPasswordAttempts', {remaining: remaining, s: s})}));
return user;
});
})
.catch(function onError(err) {
if (err.code !== 'PASSWORD_INCORRECT') {
return Promise.reject(err);
}
// Use comma structure, not .catch, because we don't want to catch incorrect passwords
}, function handleError(err) {
return Promise.reject(new errors.UnauthorizedError({
err: err,
context: i18n.t('errors.models.user.incorrectPassword'),
help: i18n.t('errors.models.user.userUpdateError.help')
}));
});
}
return Promise.resolve(self.setWarning(user, {validate: false}))
.then(function then(remaining) {
if (remaining === 0) {
// If remaining attempts = 0, the account has been locked, so show a locked account message
return Promise.reject(new errors.NoPermissionError({
message: i18n.t('errors.models.user.accountLocked')
}));
}
return Promise.resolve(user.set({status: 'active', last_login: new Date()}).save({validate: false}))
.catch(function handleError(err) {
// 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.
logging.error(new errors.GhostError({
err: err,
context: i18n.t('errors.models.user.userUpdateError.context'),
help: i18n.t('errors.models.user.userUpdateError.help')
}));
s = (remaining > 1) ? 's' : '';
return Promise.reject(new errors.UnauthorizedError({
message: i18n.t('errors.models.user.incorrectPasswordAttempts', {remaining: remaining, s: s})
}));
}, function handleError(err) {
// ^ Use comma structure, not .catch, because we don't want to catch incorrect passwords
return user;
});
});
return Promise.reject(new errors.UnauthorizedError({
err: err,
context: i18n.t('errors.models.user.incorrectPassword'),
help: i18n.t('errors.models.user.userUpdateError.help')
}));
});
});
}
return Promise.reject(new errors.NoPermissionError({message: i18n.t('errors.models.user.accountLocked')}));
}, function handleError(error) {
if (error.message === 'NotFound' || error.message === 'EmptyResponse') {
@ -636,6 +648,30 @@ User = ghostBookshelf.Model.extend({
});
},
isPasswordCorrect: function isPasswordCorrect(object) {
var plainPassword = object.plainPassword,
hashedPassword = object.hashedPassword;
if (!plainPassword || !hashedPassword) {
return Promise.reject(new errors.ValidationError({
message: i18n.t('errors.models.user.passwordRequiredForOperation')
}));
}
return bcryptCompare(plainPassword, hashedPassword)
.then(function (matched) {
if (matched) {
return;
}
return Promise.reject(new errors.ValidationError({
message: i18n.t('errors.models.user.incorrectPassword'),
help: i18n.t('errors.models.user.userUpdateError.help'),
code: 'PASSWORD_INCORRECT'
}));
});
},
/**
* Naive change password method
* @param {Object} object
@ -647,6 +683,7 @@ User = ghostBookshelf.Model.extend({
ne2Password = object.ne2Password,
userId = parseInt(object.user_id),
oldPassword = object.oldPassword,
isLoggedInUser = object.user_id === options.context.user,
user;
// If the two passwords do not match
@ -654,28 +691,20 @@ User = ghostBookshelf.Model.extend({
return Promise.reject(new errors.ValidationError({message: i18n.t('errors.models.user.newPasswordsDoNotMatch')}));
}
// If the old password is empty when changing current user's password
if (userId === options.context.user && _.isEmpty(oldPassword)) {
return Promise.reject(new errors.ValidationError({message: i18n.t('errors.models.user.passwordRequiredForOperation')}));
}
return self.forge({id: userId}).fetch({require: true})
.then(function then(_user) {
user = _user;
return self.forge({id: userId}).fetch({require: true}).then(function then(_user) {
user = _user;
// If the user is the current user, check old password
if (userId === options.context.user) {
return bcryptCompare(oldPassword, user.get('password'));
}
// If user is admin and changing another user's password, old password isn't compared to the old one
return true;
}).then(function then(matched) {
if (!matched) {
return Promise.reject(new errors.ValidationError({message: i18n.t('errors.models.user.incorrectPassword')}));
}
return user.save({password: newPassword});
});
if (isLoggedInUser) {
return self.isPasswordCorrect({
plainPassword: oldPassword,
hashedPassword: user.get('password')
});
}
})
.then(function then() {
return user.save({password: newPassword});
});
},
generateResetToken: function generateResetToken(email, expires, dbHash) {