Skip to content

Commit

Permalink
Merge pull request #1535 from govuk-one-login/AUT-2602/fix-lockout-units
Browse files Browse the repository at this point in the history
Aut 2602/fix lockout units
  • Loading branch information
BeckaL authored Apr 8, 2024
2 parents 29b2527 + 7694178 commit 769e4d9
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 3 deletions.
8 changes: 6 additions & 2 deletions src/components/enter-email/enter-email-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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) {
Expand Down
43 changes: 42 additions & 1 deletion src/components/enter-email/tests/enter-email-controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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({
Expand All @@ -32,9 +34,13 @@ describe("enter email controller", () => {
i18n: { language: "en" },
});
res = mockResponse();
clock = sinon.useFakeTimers({
now: date.valueOf(),
});
});

afterEach(() => {
clock.restore();
sinon.restore();
});

Expand Down Expand Up @@ -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 = "[email protected]";
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 = {
Expand Down
4 changes: 4 additions & 0 deletions src/utils/lock-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ export function timestampNMinutesFromNow(numberOfMinutes: number) {
return new Date(Date.now() + numberOfMinutes * 60000).toUTCString();
}

export function timestampNSecondsFromNow(numberOfSeconds: number) {

Check warning on line 5 in src/utils/lock-helper.ts

View workflow job for this annotation

GitHub Actions / run-tests

Missing return type on function
return new Date(Date.now() + numberOfSeconds * 1000).toUTCString();
}

export function isLocked(maybeLockTimestamp?: string) {

Check warning on line 9 in src/utils/lock-helper.ts

View workflow job for this annotation

GitHub Actions / run-tests

Missing return type on function
return (
maybeLockTimestamp &&
Expand Down
22 changes: 22 additions & 0 deletions test/unit/utils/lock-helper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { describe } from "mocha";
import {
isLocked,
timestampNMinutesFromNow,
timestampNSecondsFromNow,
} from "../../../src/utils/lock-helper";
import sinon from "sinon";
describe("lockout-helper", () => {
Expand Down Expand Up @@ -40,6 +41,27 @@ describe("lockout-helper", () => {
});
});

describe("timestampNSecondsFromNow", () => {
it("should return the correct timestamp from the current datetime", () => {
const TEST_SCENARIO_PARAMS = [
{
numberOfSeconds: 60,
expectedTimestamp: "Thu, 01 Feb 2024 00:01:00 GMT",
},
{
numberOfSeconds: 1,
expectedTimestamp: "Thu, 01 Feb 2024 00:00:01 GMT",
},
];

TEST_SCENARIO_PARAMS.forEach((params) => {
expect(timestampNSecondsFromNow(params.numberOfSeconds)).to.eq(
params.expectedTimestamp
);
});
});
});

describe("checkIfLocked", () => {
it("should correctly determine if a user is locked", () => {
const TEST_SCENARIO_PARAMS = [
Expand Down

0 comments on commit 769e4d9

Please sign in to comment.