@@ -645,6 +645,19 @@ module.exports = function(User) {
645645 err . statusCode = 422 ;
646646 throw err ;
647647 } ;
648+
649+ User . _invalidateAccessTokensOfUsers = function ( userIds , cb ) {
650+ if ( ! Array . isArray ( userIds ) || ! userIds . length )
651+ return process . nextTick ( cb ) ;
652+
653+ var accessTokenRelation = this . relations . accessTokens ;
654+ if ( ! accessTokenRelation )
655+ return process . nextTick ( cb ) ;
656+
657+ var AccessToken = accessTokenRelation . modelTo ;
658+ AccessToken . deleteAll ( { userId : { inq : userIds } } , cb ) ;
659+ } ;
660+
648661 /*!
649662 * Setup an extended user model.
650663 */
@@ -809,8 +822,20 @@ module.exports = function(User) {
809822 var emailChanged ;
810823 if ( ctx . isNewInstance ) return next ( ) ;
811824 if ( ! ctx . where && ! ctx . instance ) return next ( ) ;
812- var where = ctx . where || { id : ctx . instance . id } ;
813- ctx . Model . find ( { where : where } , function ( err , userInstances ) {
825+
826+ var isPartialUpdateChangingPassword = ctx . data && 'password' in ctx . data ;
827+
828+ // Full replace of User instance => assume password change.
829+ // HashPassword returns a different value for each invocation,
830+ // therefore we cannot tell whether ctx.instance.password is the same
831+ // or not.
832+ var isFullReplaceChangingPassword = ! ! ctx . instance ;
833+
834+ ctx . hookState . isPasswordChange = isPartialUpdateChangingPassword ||
835+ isFullReplaceChangingPassword ;
836+
837+ var where = ctx . where || { id : ctx . instance . id } ;
838+ ctx . Model . find ( { where : where } , function ( err , userInstances ) {
814839 if ( err ) return next ( err ) ;
815840 ctx . hookState . originalUserData = userInstances . map ( function ( u ) {
816841 return { id : u . id , email : u . email } ;
@@ -828,24 +853,26 @@ module.exports = function(User) {
828853 ctx . data . emailVerified = false ;
829854 }
830855 }
856+
831857 next ( ) ;
832858 } ) ;
833859 } ) ;
834860
835861 User . observe ( 'after save' , function afterEmailUpdate ( ctx , next ) {
836- if ( ! ctx . Model . relations . accessTokens ) return next ( ) ;
837- var AccessToken = ctx . Model . relations . accessTokens . modelTo ;
838862 if ( ! ctx . instance && ! ctx . data ) return next ( ) ;
839- var newEmail = ( ctx . instance || ctx . data ) . email ;
840- if ( ! newEmail ) return next ( ) ;
841863 if ( ! ctx . hookState . originalUserData ) return next ( ) ;
842- var idsToExpire = ctx . hookState . originalUserData . filter ( function ( u ) {
843- return u . email !== newEmail ;
864+
865+ var newEmail = ( ctx . instance || ctx . data ) . email ;
866+ var isPasswordChange = ctx . hookState . isPasswordChange ;
867+
868+ if ( ! newEmail && ! isPasswordChange ) return next ( ) ;
869+
870+ var userIdsToExpire = ctx . hookState . originalUserData . filter ( function ( u ) {
871+ return ( newEmail && u . email !== newEmail ) || isPasswordChange ;
844872 } ) . map ( function ( u ) {
845873 return u . id ;
846874 } ) ;
847- if ( ! idsToExpire . length ) return next ( ) ;
848- AccessToken . deleteAll ( { userId : { inq : idsToExpire } } , next ) ;
875+ ctx . Model . _invalidateAccessTokensOfUsers ( userIdsToExpire , next ) ;
849876 } ) ;
850877} ;
851878
0 commit comments