From 7694178501941611940e7f82497d0a3c00590aa1 Mon Sep 17 00:00:00 2001 From: BeckaL Date: Mon, 8 Apr 2024 16:28:03 +0100 Subject: [PATCH] AUT-2602: Fix lockout units The backend stores and returns lockouts in seconds. We are currently assuming them to be minutes when reading from the backend. This fixes this to ensure that the frontend handles the backend lockout in the same units --- .../enter-email/enter-email-controller.ts | 8 +++- .../tests/enter-email-controller.test.ts | 43 ++++++++++++++++++- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/components/enter-email/enter-email-controller.ts b/src/components/enter-email/enter-email-controller.ts index 94def3e5e..60f79107c 100644 --- a/src/components/enter-email/enter-email-controller.ts +++ b/src/components/enter-email/enter-email-controller.ts @@ -26,7 +26,11 @@ import { renderBadRequest, } from "../../utils/validation"; import { getNewCodePath } from "../security-code-error/security-code-error-controller"; -import { isLocked, timestampNMinutesFromNow } from "../../utils/lock-helper"; +import { + isLocked, + timestampNMinutesFromNow, + timestampNSecondsFromNow, +} from "../../utils/lock-helper"; export const RE_ENTER_EMAIL_TEMPLATE = "enter-email/index-re-enter-email-account.njk"; @@ -238,7 +242,7 @@ function handleBadRequest( function setUpAuthAppLocks(req: any, lockoutArray: LockoutInformation[]) { lockoutArray.forEach(function (lockoutInformation) { if (lockoutInformation.lockType == "codeBlock") { - const lockTime = timestampNMinutesFromNow( + const lockTime = timestampNSecondsFromNow( parseInt(lockoutInformation.lockTTL) ); switch (lockoutInformation.journeyType) { diff --git a/src/components/enter-email/tests/enter-email-controller.test.ts b/src/components/enter-email/tests/enter-email-controller.test.ts index 8fa9e503e..5a7aab402 100644 --- a/src/components/enter-email/tests/enter-email-controller.test.ts +++ b/src/components/enter-email/tests/enter-email-controller.test.ts @@ -9,7 +9,7 @@ import { enterEmailGet, enterEmailPost, } from "../enter-email-controller"; -import { EnterEmailServiceInterface } from "../types"; +import { EnterEmailServiceInterface, LockoutInformation } from "../types"; import { JOURNEY_TYPE, ERROR_CODES } from "../../common/constants"; import { PATH_NAMES } from "../../../app.constants"; import { SendNotificationServiceInterface } from "../../common/send-notification/types"; @@ -24,6 +24,8 @@ import { CheckReauthServiceInterface } from "../../check-reauth-users/types"; describe("enter email controller", () => { let req: RequestOutput; let res: ResponseOutput; + let clock: sinon.SinonFakeTimers; + const date = new Date(2024, 1, 1); beforeEach(() => { req = mockRequest({ @@ -32,9 +34,13 @@ describe("enter email controller", () => { i18n: { language: "en" }, }); res = mockResponse(); + clock = sinon.useFakeTimers({ + now: date.valueOf(), + }); }); afterEach(() => { + clock.restore(); sinon.restore(); }); @@ -163,6 +169,41 @@ describe("enter email controller", () => { expect(fakeService.userExists).to.have.been.calledOnce; }); + it("should set a lock with the correct timestamp when the response contains lockout information", async () => { + const lockTTlInSeconds = 60; + + const lockoutInformation: LockoutInformation = { + lockType: "codeBlock", + lockTTL: lockTTlInSeconds.toString(), + journeyType: "SIGN_IN", + mfaMethodType: "SMS", + }; + const fakeService: EnterEmailServiceInterface = { + userExists: sinon.fake.returns({ + success: true, + data: { + doesUserExist: true, + lockoutInformation: [lockoutInformation], + }, + }), + } as unknown as EnterEmailServiceInterface; + + req.body.email = "test@test.com"; + res.locals.sessionId = "sadl990asdald"; + req.path = PATH_NAMES.ENTER_EMAIL_SIGN_IN; + + await enterEmailPost(fakeService)(req as Request, res as Response); + + const expectedLockTime = new Date( + date.getTime() + lockTTlInSeconds * 1000 + ).toUTCString(); + + expect(req.session.user.wrongCodeEnteredLock).to.eq(expectedLockTime); + + expect(res.redirect).to.have.calledWith("/enter-password"); + expect(fakeService.userExists).to.have.been.calledOnce; + }); + it("should throw error when API call throws error", async () => { const error = new Error("Internal server error"); const fakeService: EnterEmailServiceInterface = {