@@ -1023,6 +1023,136 @@ describe('Auth', () => {
1023
1023
} ) ,
1024
1024
) . rejects . toThrow ( 'Token is either invalid or has expired.' )
1025
1025
} )
1026
+
1027
+ describe ( 'Login Attempts' , ( ) => {
1028
+ async function attemptLogin ( email : string , password : string ) {
1029
+ return payload . login ( {
1030
+ collection : slug ,
1031
+ data : {
1032
+ email,
1033
+ password,
1034
+ } ,
1035
+ overrideAccess : false ,
1036
+ } )
1037
+ }
1038
+
1039
+ it ( 'should reset the login attempts after a successful login' , async ( ) => {
1040
+ // fail 1
1041
+ try {
1042
+ const failedLogin = await attemptLogin ( devUser . email , 'wrong-password' )
1043
+ expect ( failedLogin ) . toBeUndefined ( )
1044
+ } catch ( error ) {
1045
+ expect ( ( error as Error ) . message ) . toBe ( 'The email or password provided is incorrect.' )
1046
+ }
1047
+
1048
+ // successful login 1
1049
+ const successfulLogin = await attemptLogin ( devUser . email , devUser . password )
1050
+ expect ( successfulLogin ) . toBeDefined ( )
1051
+
1052
+ // fail 2
1053
+ try {
1054
+ const failedLogin = await attemptLogin ( devUser . email , 'wrong-password' )
1055
+ expect ( failedLogin ) . toBeUndefined ( )
1056
+ } catch ( error ) {
1057
+ expect ( ( error as Error ) . message ) . toBe ( 'The email or password provided is incorrect.' )
1058
+ }
1059
+
1060
+ // successful login 2 without exceeding attempts
1061
+ const successfulLogin2 = await attemptLogin ( devUser . email , devUser . password )
1062
+ expect ( successfulLogin2 ) . toBeDefined ( )
1063
+
1064
+ const user = await payload . findByID ( {
1065
+ collection : slug ,
1066
+ id : successfulLogin2 . user . id ,
1067
+ overrideAccess : true ,
1068
+ showHiddenFields : true ,
1069
+ } )
1070
+
1071
+ expect ( user . loginAttempts ) . toBe ( 0 )
1072
+ expect ( user . lockUntil ) . toBeNull ( )
1073
+ } )
1074
+
1075
+ it ( 'should lock the user after too many failed login attempts' , async ( ) => {
1076
+ const now = new Date ( )
1077
+ // fail 1
1078
+ try {
1079
+ const failedLogin = await attemptLogin ( devUser . email , 'wrong-password' )
1080
+ expect ( failedLogin ) . toBeUndefined ( )
1081
+ } catch ( error ) {
1082
+ expect ( ( error as Error ) . message ) . toBe ( 'The email or password provided is incorrect.' )
1083
+ }
1084
+
1085
+ // fail 2
1086
+ try {
1087
+ const failedLogin = await attemptLogin ( devUser . email , 'wrong-password' )
1088
+ expect ( failedLogin ) . toBeUndefined ( )
1089
+ } catch ( error ) {
1090
+ expect ( ( error as Error ) . message ) . toBe ( 'The email or password provided is incorrect.' )
1091
+ }
1092
+
1093
+ // fail 3
1094
+ try {
1095
+ const failedLogin = await attemptLogin ( devUser . email , 'wrong-password' )
1096
+ expect ( failedLogin ) . toBeUndefined ( )
1097
+ } catch ( error ) {
1098
+ expect ( ( error as Error ) . message ) . toBe (
1099
+ 'This user is locked due to having too many failed login attempts.' ,
1100
+ )
1101
+ }
1102
+
1103
+ const userQuery = await payload . find ( {
1104
+ collection : slug ,
1105
+ overrideAccess : true ,
1106
+ showHiddenFields : true ,
1107
+ where : {
1108
+ email : {
1109
+ equals : devUser . email ,
1110
+ } ,
1111
+ } ,
1112
+ } )
1113
+
1114
+ expect ( userQuery . docs [ 0 ] ) . toBeDefined ( )
1115
+
1116
+ if ( userQuery . docs [ 0 ] ) {
1117
+ const user = userQuery . docs [ 0 ]
1118
+ expect ( user . loginAttempts ) . toBe ( 2 )
1119
+ expect ( user . lockUntil ) . toBeDefined ( )
1120
+ expect ( typeof user . lockUntil ) . toBe ( 'string' )
1121
+ if ( typeof user . lockUntil === 'string' ) {
1122
+ expect ( new Date ( user . lockUntil ) . getTime ( ) ) . toBeGreaterThan ( now . getTime ( ) )
1123
+ }
1124
+ }
1125
+ } )
1126
+
1127
+ it ( 'should allow force unlocking of a user' , async ( ) => {
1128
+ await payload . unlock ( {
1129
+ collection : slug ,
1130
+ data : {
1131
+ email : devUser . email ,
1132
+ } as any ,
1133
+ overrideAccess : true ,
1134
+ } )
1135
+
1136
+ const userQuery = await payload . find ( {
1137
+ collection : slug ,
1138
+ overrideAccess : true ,
1139
+ showHiddenFields : true ,
1140
+ where : {
1141
+ email : {
1142
+ equals : devUser . email ,
1143
+ } ,
1144
+ } ,
1145
+ } )
1146
+
1147
+ expect ( userQuery . docs [ 0 ] ) . toBeDefined ( )
1148
+
1149
+ if ( userQuery . docs [ 0 ] ) {
1150
+ const user = userQuery . docs [ 0 ]
1151
+ expect ( user . loginAttempts ) . toBe ( 0 )
1152
+ expect ( user . lockUntil ) . toBeNull ( )
1153
+ }
1154
+ } )
1155
+ } )
1026
1156
} )
1027
1157
1028
1158
describe ( 'Email - format validation' , ( ) => {
0 commit comments