2016-09-02 17:00:47 -07:00
// This class handles the Account Lockout Policy settings.
2016-11-24 15:47:41 -05:00
import Parse from 'parse/node' ;
2016-09-02 17:00:47 -07:00
export class AccountLockout {
constructor ( user , config ) {
this . _user = user ;
this . _config = config ;
}
/ * *
* set _failed _login _count to value
* /
_setFailedLoginCount ( value ) {
2016-12-07 15:17:05 -08:00
const query = {
2016-11-24 15:47:41 -05:00
username : this . _user . username
2016-09-02 17:00:47 -07:00
} ;
const updateFields = {
_failed _login _count : value
} ;
return this . _config . database . update ( '_User' , query , updateFields ) ;
}
/ * *
* check if the _failed _login _count field has been set
* /
_isFailedLoginCountSet ( ) {
2017-05-14 19:37:42 -04:00
const query = {
username : this . _user . username ,
_failed _login _count : { $exists : true }
} ;
2016-09-02 17:00:47 -07:00
2017-05-14 19:37:42 -04:00
return this . _config . database . find ( '_User' , query )
2016-09-02 17:00:47 -07:00
. then ( users => {
if ( Array . isArray ( users ) && users . length > 0 ) {
2017-05-14 19:37:42 -04:00
return true ;
2016-09-02 17:00:47 -07:00
} else {
2017-05-14 19:37:42 -04:00
return false ;
2016-09-02 17:00:47 -07:00
}
} ) ;
}
/ * *
* if _failed _login _count is NOT set then set it to 0
* else do nothing
* /
_initFailedLoginCount ( ) {
2017-05-14 19:37:42 -04:00
return this . _isFailedLoginCountSet ( )
2016-09-02 17:00:47 -07:00
. then ( failedLoginCountIsSet => {
if ( ! failedLoginCountIsSet ) {
return this . _setFailedLoginCount ( 0 ) ;
}
} ) ;
}
/ * *
* increment _failed _login _count by 1
* /
_incrementFailedLoginCount ( ) {
const query = {
2016-11-24 15:47:41 -05:00
username : this . _user . username
2016-09-02 17:00:47 -07:00
} ;
const updateFields = { _failed _login _count : { _ _op : 'Increment' , amount : 1 } } ;
return this . _config . database . update ( '_User' , query , updateFields ) ;
}
/ * *
2016-12-01 10:24:46 -08:00
* if the failed login count is greater than the threshold
* then sets lockout expiration to 'currenttime + accountPolicy.duration' , i . e . , account is locked out for the next 'accountPolicy.duration' minutes
2016-09-02 17:00:47 -07:00
* else do nothing
* /
_setLockoutExpiration ( ) {
2017-05-14 19:37:42 -04:00
const query = {
username : this . _user . username ,
_failed _login _count : { $gte : this . _config . accountLockout . threshold }
} ;
2016-09-02 17:00:47 -07:00
2017-05-14 19:37:42 -04:00
const now = new Date ( ) ;
2016-09-02 17:00:47 -07:00
2017-05-14 19:37:42 -04:00
const updateFields = {
_account _lockout _expires _at : Parse . _encode ( new Date ( now . getTime ( ) + this . _config . accountLockout . duration * 60 * 1000 ) )
} ;
2016-09-02 17:00:47 -07:00
2017-05-14 19:37:42 -04:00
return this . _config . database . update ( '_User' , query , updateFields )
2016-09-02 17:00:47 -07:00
. catch ( err => {
if ( err && err . code && err . message && err . code === 101 && err . message === 'Object not found.' ) {
2017-05-14 19:37:42 -04:00
return ; // nothing to update so we are good
2016-09-02 17:00:47 -07:00
} else {
2017-05-14 19:37:42 -04:00
throw err ; // unknown error
2016-09-02 17:00:47 -07:00
}
} ) ;
}
/ * *
* if _account _lockout _expires _at > current _time and _failed _login _count > threshold
* reject with account locked error
* else
* resolve
* /
_notLocked ( ) {
2017-05-14 19:37:42 -04:00
const query = {
username : this . _user . username ,
_account _lockout _expires _at : { $gt : Parse . _encode ( new Date ( ) ) } ,
_failed _login _count : { $gte : this . _config . accountLockout . threshold }
} ;
return this . _config . database . find ( '_User' , query )
2016-09-02 17:00:47 -07:00
. then ( users => {
if ( Array . isArray ( users ) && users . length > 0 ) {
2017-05-14 19:37:42 -04:00
throw new Parse . Error ( Parse . Error . OBJECT _NOT _FOUND , 'Your account is locked due to multiple failed login attempts. Please try again after ' + this . _config . accountLockout . duration + ' minute(s)' ) ;
2016-09-02 17:00:47 -07:00
}
} ) ;
}
/ * *
* set and / or increment _failed _login _count
* if _failed _login _count > threshold
* set the _account _lockout _expires _at to current _time + accountPolicy . duration
2016-12-01 10:24:46 -08:00
* else
* do nothing
2016-09-02 17:00:47 -07:00
* /
_handleFailedLoginAttempt ( ) {
2017-05-14 19:37:42 -04:00
return this . _initFailedLoginCount ( )
2016-09-02 17:00:47 -07:00
. then ( ( ) => {
return this . _incrementFailedLoginCount ( ) ;
} )
. then ( ( ) => {
return this . _setLockoutExpiration ( ) ;
} ) ;
}
/ * *
* handle login attempt if the Account Lockout Policy is enabled
* /
handleLoginAttempt ( loginSuccessful ) {
if ( ! this . _config . accountLockout ) {
return Promise . resolve ( ) ;
}
2017-05-14 19:37:42 -04:00
return this . _notLocked ( )
2016-09-02 17:00:47 -07:00
. then ( ( ) => {
if ( loginSuccessful ) {
return this . _setFailedLoginCount ( 0 ) ;
} else {
return this . _handleFailedLoginAttempt ( ) ;
}
} ) ;
}
}
export default AccountLockout ;