diff --git a/src/components/common/state-machine/state-machine.ts b/src/components/common/state-machine/state-machine.ts index 441747bc9..2548a456a 100644 --- a/src/components/common/state-machine/state-machine.ts +++ b/src/components/common/state-machine/state-machine.ts @@ -54,6 +54,7 @@ const USER_JOURNEY_EVENTS = { TEMPORARILY_BLOCKED_INTERVENTION: "TEMP_SUSPENSION_INTERVENTION", PERMANENTLY_BLOCKED_INTERVENTION: "PERMANENTLY_BLOCKED_INTERVENTION", PASSWORD_RESET_INTERVENTION: "PASSWORD_RESET_INTERVENTION", + COMMON_PASSWORD_AND_AIS_STATUS: "COMMON_PASSWORD_AND_AIS_STATUS", }; const authStateMachine = createMachine( @@ -209,6 +210,9 @@ const authStateMachine = createMachine( }, [PATH_NAMES.ENTER_PASSWORD_ACCOUNT_EXISTS]: { on: { + [USER_JOURNEY_EVENTS.COMMON_PASSWORD_AND_AIS_STATUS]: [ + PATH_NAMES.RESET_PASSWORD_CHECK_EMAIL, + ], [USER_JOURNEY_EVENTS.CREDENTIALS_VALIDATED]: [ { target: [PATH_NAMES.RESET_PASSWORD_REQUIRED], @@ -355,6 +359,9 @@ const authStateMachine = createMachine( }, [PATH_NAMES.ENTER_PASSWORD]: { on: { + [USER_JOURNEY_EVENTS.COMMON_PASSWORD_AND_AIS_STATUS]: [ + PATH_NAMES.RESET_PASSWORD_CHECK_EMAIL, + ], [USER_JOURNEY_EVENTS.CREDENTIALS_VALIDATED]: [ { target: [PATH_NAMES.RESET_PASSWORD_2FA_SMS], diff --git a/src/components/enter-password/enter-password-controller.ts b/src/components/enter-password/enter-password-controller.ts index 1da8f222e..ef3642bd4 100644 --- a/src/components/enter-password/enter-password-controller.ts +++ b/src/components/enter-password/enter-password-controller.ts @@ -19,8 +19,14 @@ import { MFA_METHOD_TYPE } from "../../app.constants"; import xss from "xss"; import { EnterEmailServiceInterface } from "../enter-email/types"; import { enterEmailService } from "../enter-email/enter-email-service"; -import { support2FABeforePasswordReset, support2hrLockout } from "../../config"; +import { + support2FABeforePasswordReset, + supportAccountInterventions, + support2hrLockout, +} from "../../config"; import { getJourneyTypeFromUserSession } from "../common/journey/journey"; +import { accountInterventionService } from "../account-intervention/account-intervention-service"; +import { AccountInterventionsInterface } from "../account-intervention/types"; const ENTER_PASSWORD_TEMPLATE = "enter-password/index.njk"; const ENTER_PASSWORD_VALIDATION_KEY_OLD = @@ -91,7 +97,8 @@ export function enterPasswordAccountExistsGet( export function enterPasswordPost( fromAccountExists = false, service: EnterPasswordServiceInterface = enterPasswordService(), - mfaCodeService: MfaServiceInterface = mfaService() + mfaCodeService: MfaServiceInterface = mfaService(), + accountInterventionsService: AccountInterventionsInterface = accountInterventionService() ): ExpressRouteFunc { return async function (req: Request, res: Response) { const { email } = req.session.user; @@ -154,6 +161,34 @@ export function enterPasswordPost( userLogin.data.latestTermsAndConditionsAccepted; req.session.user.isPasswordChangeRequired = isPasswordChangeRequired; + if ( + req.session.user.isPasswordChangeRequired && + supportAccountInterventions() + ) { + const accountInterventionsResponse = + await accountInterventionsService.accountInterventionStatus( + sessionId, + email, + req.ip, + clientSessionId, + persistentSessionId + ); + if ( + accountInterventionsResponse.data.passwordResetRequired || + accountInterventionsResponse.data.temporarilySuspended + ) { + return res.redirect( + getNextPathAndUpdateJourney( + req, + req.path, + USER_JOURNEY_EVENTS.COMMON_PASSWORD_AND_AIS_STATUS, + null, + sessionId + ) + ); + } + } + if ( userLogin.data.mfaRequired && userLogin.data.mfaMethodVerified && diff --git a/src/components/enter-password/tests/enter-password-controller.test.ts b/src/components/enter-password/tests/enter-password-controller.test.ts index 684a03592..8a866d07c 100644 --- a/src/components/enter-password/tests/enter-password-controller.test.ts +++ b/src/components/enter-password/tests/enter-password-controller.test.ts @@ -21,6 +21,8 @@ import { import { EnterEmailServiceInterface } from "../../enter-email/types"; import { ERROR_CODES } from "../../common/constants"; import * as journey from "../../common/journey/journey"; +import { accountInterventionsFakeHelper } from "../../../../test/helpers/account-interventions-helpers"; +import { supportAccountInterventions } from "../../../config"; describe("enter password controller", () => { let req: RequestOutput; @@ -33,6 +35,7 @@ describe("enter password controller", () => { log: { info: sinon.fake() }, }); res = mockResponse(); + supportAccountInterventions(); }); afterEach(() => { @@ -342,6 +345,13 @@ describe("enter password controller", () => { }); it("should redirect to reset-password-required when the existing password is common and supportPasswordResetRequired() is enabled", async () => { + const fakeAccountInterventionsService = accountInterventionsFakeHelper( + "test@test.co.uk", + false, + false, + false + ); + const fakeService: EnterPasswordServiceInterface = { loginUser: sinon.fake.returns({ data: { @@ -374,7 +384,8 @@ describe("enter password controller", () => { await enterPasswordPost( false, fakeService, - fakeMfaService + fakeMfaService, + fakeAccountInterventionsService )(req as Request, res as Response); expect(res.redirect).to.have.calledWith( diff --git a/src/components/enter-password/tests/enter-password-support-2fa-before-password-reset-integration.test.ts b/src/components/enter-password/tests/enter-password-support-2fa-before-password-reset-integration.test.ts index b8b3571d5..0d8011b46 100644 --- a/src/components/enter-password/tests/enter-password-support-2fa-before-password-reset-integration.test.ts +++ b/src/components/enter-password/tests/enter-password-support-2fa-before-password-reset-integration.test.ts @@ -14,6 +14,10 @@ import { AxiosResponse } from "axios"; import { createApiResponse } from "../../../utils/http"; import { CheckReauthServiceInterface } from "../../check-reauth-users/types"; import { DefaultApiResponse } from "../../../types"; +import { + noInterventions, + setupAccountInterventionsResponse, +} from "../../../../test/helpers/account-interventions-helpers"; describe("Integration::enter password", () => { let token: string | string[]; @@ -62,7 +66,6 @@ describe("Integration::enter password", () => { return { checkReauthUsers }; }); - process.env.SUPPORT_2FA_B4_PASSWORD_RESET = "1"; app = await require("../../../app").createApp(); baseApi = process.env.FRONTEND_API_BASE_URL; @@ -76,12 +79,16 @@ describe("Integration::enter password", () => { }); beforeEach(() => { + process.env.SUPPORT_2FA_B4_PASSWORD_RESET = "1"; + process.env.SUPPORT_ACCOUNT_INTERVENTIONS = "1"; nock.cleanAll(); }); after(() => { sinon.restore(); app = undefined; + delete process.env.SUPPORT_ACCOUNT_INTERVENTIONS; + delete process.env.SUPPORT_2FA_B4_PASSWORD_RESET; }); it("should return enter password page", (done) => { @@ -146,6 +153,8 @@ describe("Integration::enter password", () => { passwordChangeRequired: true, }); + setupAccountInterventionsResponse(baseApi, noInterventions); + request(app) .post(ENDPOINT) .type("form") @@ -165,6 +174,8 @@ describe("Integration::enter password", () => { passwordChangeRequired: true, }); + setupAccountInterventionsResponse(baseApi, noInterventions); + request(app) .post(ENDPOINT) .type("form")