@@ -648,6 +648,19 @@ module.exports = function(User) {
648648 err . statusCode = 422 ;
649649 throw err ;
650650 } ;
651+
652+ User . _invalidateAccessTokensOfUsers = function ( userIds , cb ) {
653+ if ( ! Array . isArray ( userIds ) || ! userIds . length )
654+ return process . nextTick ( cb ) ;
655+
656+ var accessTokenRelation = this . relations . accessTokens ;
657+ if ( ! accessTokenRelation )
658+ return process . nextTick ( cb ) ;
659+
660+ var AccessToken = accessTokenRelation . modelTo ;
661+ AccessToken . deleteAll ( { userId : { inq : userIds } } , cb ) ;
662+ } ;
663+
651664 /*!
652665 * Setup an extended user model.
653666 */
@@ -823,6 +836,18 @@ module.exports = function(User) {
823836 if ( ctx . isNewInstance ) return next ( ) ;
824837 if ( ! ctx . where && ! ctx . instance ) return next ( ) ;
825838 var where = ctx . where || { id : ctx . instance . id } ;
839+
840+ var isPartialUpdateChangingPassword = ctx . data && 'password' in ctx . data ;
841+
842+ // Full replace of User instance => assume password change.
843+ // HashPassword returns a different value for each invocation,
844+ // therefore we cannot tell whether ctx.instance.password is the same
845+ // or not.
846+ var isFullReplaceChangingPassword = ! ! ctx . instance ;
847+
848+ ctx . hookState . isPasswordChange = isPartialUpdateChangingPassword ||
849+ isFullReplaceChangingPassword ;
850+
826851 ctx . Model . find ( { where : where } , function ( err , userInstances ) {
827852 if ( err ) return next ( err ) ;
828853 ctx . hookState . originalUserData = userInstances . map ( function ( u ) {
@@ -841,24 +866,26 @@ module.exports = function(User) {
841866 ctx . data . emailVerified = false ;
842867 }
843868 }
869+
844870 next ( ) ;
845871 } ) ;
846872 } ) ;
847873
848874 User . observe ( 'after save' , function afterEmailUpdate ( ctx , next ) {
849- if ( ! ctx . Model . relations . accessTokens ) return next ( ) ;
850- var AccessToken = ctx . Model . relations . accessTokens . modelTo ;
851875 if ( ! ctx . instance && ! ctx . data ) return next ( ) ;
852- var newEmail = ( ctx . instance || ctx . data ) . email ;
853- if ( ! newEmail ) return next ( ) ;
854876 if ( ! ctx . hookState . originalUserData ) return next ( ) ;
855- var idsToExpire = ctx . hookState . originalUserData . filter ( function ( u ) {
856- return u . email !== newEmail ;
877+
878+ var newEmail = ( ctx . instance || ctx . data ) . email ;
879+ var isPasswordChange = ctx . hookState . isPasswordChange ;
880+
881+ if ( ! newEmail && ! isPasswordChange ) return next ( ) ;
882+
883+ var userIdsToExpire = ctx . hookState . originalUserData . filter ( function ( u ) {
884+ return ( newEmail && u . email !== newEmail ) || isPasswordChange ;
857885 } ) . map ( function ( u ) {
858886 return u . id ;
859887 } ) ;
860- if ( ! idsToExpire . length ) return next ( ) ;
861- AccessToken . deleteAll ( { userId : { inq : idsToExpire } } , next ) ;
888+ ctx . Model . _invalidateAccessTokensOfUsers ( userIdsToExpire , next ) ;
862889 } ) ;
863890} ;
864891
0 commit comments