Skip to content

Commit

Permalink
refactor(core): extract verified interaction guard middleware
Browse files Browse the repository at this point in the history
extract verified interaction guard middleware
  • Loading branch information
simeng-li committed Jul 26, 2024
1 parent 5ff7d63 commit 99ed0d3
Showing 1 changed file with 33 additions and 37 deletions.
70 changes: 33 additions & 37 deletions packages/core/src/routes/experience/profile-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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<StateT, WithExperienceInteractionContext<ContextT>, 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();

Check warning on line 46 in packages/core/src/routes/experience/profile-routes.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/routes/experience/profile-routes.ts#L32-L46

Added lines #L32 - L46 were not covered by tests
};
}

export default function interactionProfileRoutes<T extends WithLogContext>(
router: Router<unknown, WithExperienceInteractionContext<T>>,
tenant: TenantContext
Expand All @@ -27,21 +57,9 @@ export default function interactionProfileRoutes<T extends WithLogContext>(
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) {
Expand Down Expand Up @@ -114,21 +132,10 @@ export default function interactionProfileRoutes<T extends WithLogContext>(
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();

Expand All @@ -147,22 +154,11 @@ export default function interactionProfileRoutes<T extends WithLogContext>(
}),
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);
Expand Down

0 comments on commit 99ed0d3

Please sign in to comment.