From 99ed0d353dc565ea0d4a078e9d093a9f60cc5402 Mon Sep 17 00:00:00 2001 From: simeng-li Date: Fri, 26 Jul 2024 10:39:41 +0800 Subject: [PATCH] refactor(core): extract verified interaction guard middleware extract verified interaction guard middleware --- .../src/routes/experience/profile-routes.ts | 70 +++++++++---------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/packages/core/src/routes/experience/profile-routes.ts b/packages/core/src/routes/experience/profile-routes.ts index e417438897ad..d62c862516f2 100644 --- a/packages/core/src/routes/experience/profile-routes.ts +++ b/packages/core/src/routes/experience/profile-routes.ts @@ -4,6 +4,7 @@ import { SignInIdentifier, updateProfileApiPayloadGuard, } from '@logto/schemas'; +import { type MiddlewareType } from 'koa'; import type Router from 'koa-router'; import { z } from 'zod'; @@ -17,6 +18,35 @@ import { identifierCodeVerificationTypeMap } from './classes/verifications/code- import { experienceRoutes } from './const.js'; import { type WithExperienceInteractionContext } from './middleware/koa-experience-interaction.js'; +/** + * @throws {RequestError} with status 400 if current interaction is ForgotPassword + * @throws {RequestError} with status 404 if current interaction is not identified + * @throws {RequestError} with status 403 if MFA verification status is not verified + */ +function verifiedInteractionGuard< + StateT, + ContextT extends WithLogContext, + ResponseT, +>(): MiddlewareType, ResponseT> { + return async (ctx, next) => { + const { experienceInteraction } = ctx; + + // Guard current interaction event is not ForgotPassword + assertThat( + experienceInteraction.interactionEvent !== InteractionEvent.ForgotPassword, + new RequestError({ + code: 'session.not_supported_for_forgot_password', + statue: 400, + }) + ); + + // Guard MFA verification status + await experienceInteraction.guardMfaVerificationStatus(); + + return next(); + }; +} + export default function interactionProfileRoutes( router: Router>, tenant: TenantContext @@ -27,21 +57,9 @@ export default function interactionProfileRoutes( body: updateProfileApiPayloadGuard, status: [204, 400, 403, 404, 422], }), + verifiedInteractionGuard(), async (ctx, next) => { const { experienceInteraction, guard } = ctx; - - // Guard current interaction event is not ForgotPassword - assertThat( - experienceInteraction.interactionEvent !== InteractionEvent.ForgotPassword, - new RequestError({ - code: 'session.not_supported_for_forgot_password', - statue: 400, - }) - ); - - // Guard MFA verification status - await experienceInteraction.guardMfaVerificationStatus(); - const profilePayload = guard.body; switch (profilePayload.type) { @@ -114,21 +132,10 @@ export default function interactionProfileRoutes( router.post( `${experienceRoutes.mfa}/mfa-skipped`, koaGuard({ status: [204, 400, 403, 404, 422] }), + verifiedInteractionGuard(), async (ctx, next) => { const { experienceInteraction, guard } = ctx; - // Guard current interaction event is not ForgotPassword - assertThat( - experienceInteraction.interactionEvent !== InteractionEvent.ForgotPassword, - new RequestError({ - code: 'session.not_supported_for_forgot_password', - statue: 400, - }) - ); - - // Guard current interaction event is identified and MFA verified - await experienceInteraction.guardMfaVerificationStatus(); - await experienceInteraction.mfa.skip(); await experienceInteraction.save(); @@ -147,22 +154,11 @@ export default function interactionProfileRoutes( }), status: [204, 400, 403, 404, 422], }), + verifiedInteractionGuard(), async (ctx, next) => { const { experienceInteraction, guard } = ctx; const { type, verificationId } = guard.body; - // Guard current interaction event is not ForgotPassword - assertThat( - experienceInteraction.interactionEvent !== InteractionEvent.ForgotPassword, - new RequestError({ - code: 'session.not_supported_for_forgot_password', - statue: 400, - }) - ); - - // Guard current interaction event is identified and MFA verified - await experienceInteraction.guardMfaVerificationStatus(); - switch (type) { case MfaFactor.TOTP: { await experienceInteraction.mfa.addTotpByVerificationId(verificationId);