Merge pull request #3167 from strongloop/backport/fix-token-invalidation-on-save

Preserve sessions on User.save() making no changes
This commit is contained in:
Miroslav Bajtoš 2017-01-31 16:46:09 +01:00 committed by GitHub
commit 322f6c12bb
2 changed files with 25 additions and 25 deletions

View File

@ -866,30 +866,18 @@ module.exports = function(User) {
next();
});
// Delete old sessions once email is updated
User.observe('before save', function beforeEmailUpdate(ctx, next) {
if (!ctx.Model.app.get('logoutSessionsOnSensitiveChanges')) return next();
User.observe('before save', function prepareForTokenInvalidation(ctx, next) {
var invalidationEnabled = ctx.Model.app &&
ctx.Model.app.get('logoutSessionsOnSensitiveChanges');
if (!invalidationEnabled) return next();
var emailChanged;
if (ctx.isNewInstance) return next();
if (!ctx.where && !ctx.instance) return next();
var pkName = ctx.Model.definition.idName() || 'id';
var isPartialUpdateChangingPassword = ctx.data && 'password' in ctx.data;
// Full replace of User instance => assume password change.
// HashPassword returns a different value for each invocation,
// therefore we cannot tell whether ctx.instance.password is the same
// or not.
var isFullReplaceChangingPassword = !!ctx.instance;
ctx.hookState.isPasswordChange = isPartialUpdateChangingPassword ||
isFullReplaceChangingPassword;
var where;
if (ctx.where) {
where = ctx.where;
} else {
var where = ctx.where;
if (!where) {
where = {};
where[pkName] = ctx.instance[pkName];
}
@ -899,9 +887,11 @@ module.exports = function(User) {
ctx.hookState.originalUserData = userInstances.map(function(u) {
var user = {};
user[pkName] = u[pkName];
user['email'] = u['email'];
user.email = u.email;
user.password = u.password;
return user;
});
var emailChanged;
if (ctx.instance) {
emailChanged = ctx.instance.email !== ctx.hookState.originalUserData[0].email;
if (emailChanged && ctx.Model.settings.emailVerificationRequired) {
@ -920,20 +910,23 @@ module.exports = function(User) {
});
});
User.observe('after save', function afterEmailUpdate(ctx, next) {
if (!ctx.Model.app.get('logoutSessionsOnSensitiveChanges')) return next();
User.observe('after save', function invalidateOtherTokens(ctx, next) {
var invalidationEnabled = ctx.Model.app &&
ctx.Model.app.get('logoutSessionsOnSensitiveChanges');
if (!invalidationEnabled) return next();
if (!ctx.instance && !ctx.data) return next();
if (!ctx.hookState.originalUserData) return next();
var pkName = ctx.Model.definition.idName() || 'id';
var newEmail = (ctx.instance || ctx.data).email;
var isPasswordChange = ctx.hookState.isPasswordChange;
var newPassword = (ctx.instance || ctx.data).password;
if (!newEmail && !isPasswordChange) return next();
if (!newEmail && !newPassword) return next();
var userIdsToExpire = ctx.hookState.originalUserData.filter(function(u) {
return (newEmail && u.email !== newEmail) || isPasswordChange;
return (newEmail && u.email !== newEmail) ||
(newPassword && u.password !== newPassword);
}).map(function(u) {
return u[pkName];
});

View File

@ -2097,6 +2097,13 @@ describe('User', function() {
});
});
it('keeps sessions AS IS when calling save() with no changes', function(done) {
user.save(function(err) {
if (err) return done(err);
assertPreservedTokens(done);
});
});
it('keeps sessions AS IS if firstName is added using `updateOrCreate`', function(done) {
User.updateOrCreate({
pk: user.pk,