|
1 | 1 | 'use strict';
|
2 | 2 |
|
3 | 3 | const Config = require('../lib/Config');
|
| 4 | +const Definitions = require('../lib/Options/Definitions'); |
| 5 | +const request = require('../lib/request'); |
4 | 6 |
|
5 | 7 | const loginWithWrongCredentialsShouldFail = function (username, password) {
|
6 | 8 | return new Promise((resolve, reject) => {
|
@@ -340,3 +342,125 @@ describe('Account Lockout Policy: ', () => {
|
340 | 342 | });
|
341 | 343 | });
|
342 | 344 | });
|
| 345 | + |
| 346 | +describe('lockout with password reset option', () => { |
| 347 | + let sendPasswordResetEmail; |
| 348 | + |
| 349 | + async function setup(options = {}) { |
| 350 | + const accountLockout = Object.assign( |
| 351 | + { |
| 352 | + duration: 10000, |
| 353 | + threshold: 1, |
| 354 | + }, |
| 355 | + options |
| 356 | + ); |
| 357 | + const config = { |
| 358 | + appName: 'exampleApp', |
| 359 | + accountLockout: accountLockout, |
| 360 | + publicServerURL: 'http://localhost:8378/1', |
| 361 | + emailAdapter: { |
| 362 | + sendVerificationEmail: () => Promise.resolve(), |
| 363 | + sendPasswordResetEmail: () => Promise.resolve(), |
| 364 | + sendMail: () => {}, |
| 365 | + }, |
| 366 | + }; |
| 367 | + await reconfigureServer(config); |
| 368 | + |
| 369 | + sendPasswordResetEmail = spyOn(config.emailAdapter, 'sendPasswordResetEmail').and.callThrough(); |
| 370 | + } |
| 371 | + |
| 372 | + it('accepts valid unlockOnPasswordReset option', async () => { |
| 373 | + const values = [true, false]; |
| 374 | + |
| 375 | + for (const value of values) { |
| 376 | + await expectAsync(setup({ unlockOnPasswordReset: value })).toBeResolved(); |
| 377 | + } |
| 378 | + }); |
| 379 | + |
| 380 | + it('rejects invalid unlockOnPasswordReset option', async () => { |
| 381 | + const values = ['a', 0, {}, [], null]; |
| 382 | + |
| 383 | + for (const value of values) { |
| 384 | + await expectAsync(setup({ unlockOnPasswordReset: value })).toBeRejected(); |
| 385 | + } |
| 386 | + }); |
| 387 | + |
| 388 | + it('uses default value if unlockOnPasswordReset is not set', async () => { |
| 389 | + await expectAsync(setup({ unlockOnPasswordReset: undefined })).toBeResolved(); |
| 390 | + |
| 391 | + const parseConfig = Config.get(Parse.applicationId); |
| 392 | + expect(parseConfig.accountLockout.unlockOnPasswordReset).toBe( |
| 393 | + Definitions.AccountLockoutOptions.unlockOnPasswordReset.default |
| 394 | + ); |
| 395 | + }); |
| 396 | + |
| 397 | + it('allow login for locked account after password reset', async () => { |
| 398 | + await setup({ unlockOnPasswordReset: true }); |
| 399 | + const config = Config.get(Parse.applicationId); |
| 400 | + |
| 401 | + const user = new Parse.User(); |
| 402 | + const username = 'exampleUsername'; |
| 403 | + const password = 'examplePassword'; |
| 404 | + user.setUsername(username); |
| 405 | + user.setPassword(password); |
| 406 | + user.setEmail('[email protected]'); |
| 407 | + await user.signUp(); |
| 408 | + |
| 409 | + await expectAsync(Parse.User.logIn(username, 'incorrectPassword')).toBeRejected(); |
| 410 | + await expectAsync(Parse.User.logIn(username, password)).toBeRejected(); |
| 411 | + |
| 412 | + await Parse.User.requestPasswordReset(user.getEmail()); |
| 413 | + await expectAsync(Parse.User.logIn(username, password)).toBeRejected(); |
| 414 | + |
| 415 | + const link = sendPasswordResetEmail.calls.all()[0].args[0].link; |
| 416 | + const linkUrl = new URL(link); |
| 417 | + const token = linkUrl.searchParams.get('token'); |
| 418 | + const newPassword = 'newPassword'; |
| 419 | + await request({ |
| 420 | + method: 'POST', |
| 421 | + url: `${config.publicServerURL}/apps/test/request_password_reset`, |
| 422 | + body: `new_password=${newPassword}&token=${token}&username=${username}`, |
| 423 | + headers: { |
| 424 | + 'Content-Type': 'application/x-www-form-urlencoded', |
| 425 | + }, |
| 426 | + followRedirects: false, |
| 427 | + }); |
| 428 | + |
| 429 | + await expectAsync(Parse.User.logIn(username, newPassword)).toBeResolved(); |
| 430 | + }); |
| 431 | + |
| 432 | + it('reject login for locked account after password reset (default)', async () => { |
| 433 | + await setup(); |
| 434 | + const config = Config.get(Parse.applicationId); |
| 435 | + |
| 436 | + const user = new Parse.User(); |
| 437 | + const username = 'exampleUsername'; |
| 438 | + const password = 'examplePassword'; |
| 439 | + user.setUsername(username); |
| 440 | + user.setPassword(password); |
| 441 | + user.setEmail('[email protected]'); |
| 442 | + await user.signUp(); |
| 443 | + |
| 444 | + await expectAsync(Parse.User.logIn(username, 'incorrectPassword')).toBeRejected(); |
| 445 | + await expectAsync(Parse.User.logIn(username, password)).toBeRejected(); |
| 446 | + |
| 447 | + await Parse.User.requestPasswordReset(user.getEmail()); |
| 448 | + await expectAsync(Parse.User.logIn(username, password)).toBeRejected(); |
| 449 | + |
| 450 | + const link = sendPasswordResetEmail.calls.all()[0].args[0].link; |
| 451 | + const linkUrl = new URL(link); |
| 452 | + const token = linkUrl.searchParams.get('token'); |
| 453 | + const newPassword = 'newPassword'; |
| 454 | + await request({ |
| 455 | + method: 'POST', |
| 456 | + url: `${config.publicServerURL}/apps/test/request_password_reset`, |
| 457 | + body: `new_password=${newPassword}&token=${token}&username=${username}`, |
| 458 | + headers: { |
| 459 | + 'Content-Type': 'application/x-www-form-urlencoded', |
| 460 | + }, |
| 461 | + followRedirects: false, |
| 462 | + }); |
| 463 | + |
| 464 | + await expectAsync(Parse.User.logIn(username, newPassword)).toBeRejected(); |
| 465 | + }); |
| 466 | +}); |
0 commit comments