Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(core): use template type for code verification #6687

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TemplateType } from '@logto/connector-kit';
import {
adminConsoleApplicationId,
adminTenantId,
Expand Down Expand Up @@ -88,7 +89,7 @@ describe('ExperienceInteraction class', () => {
type: SignInIdentifier.Email,
value: mockEmail,
},
interactionEvent: InteractionEvent.Register,
templateType: TemplateType.Register,
verified: true,
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TemplateType } from '@logto/connector-kit';
import {
InteractionEvent,
type SignInExperience,
Expand Down Expand Up @@ -68,7 +69,7 @@ const verificationCodeVerificationRecords = Object.freeze({
type: SignInIdentifier.Email,
value: `foo@${emailDomain}`,
},
InteractionEvent.SignIn
TemplateType.SignIn
),
[SignInIdentifier.Phone]: createNewCodeVerificationRecord(
mockTenant.libraries,
Expand All @@ -77,7 +78,7 @@ const verificationCodeVerificationRecords = Object.freeze({
type: SignInIdentifier.Phone,
value: 'value',
},
InteractionEvent.SignIn
TemplateType.SignIn
),
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TemplateType, type ToZodObject } from '@logto/connector-kit';
import {
InteractionEvent,
type InteractionEvent,
SignInIdentifier,
VerificationType,
type User,
Expand All @@ -27,12 +27,9 @@
};

/**
* To make the typescript type checking work. A valid TemplateType is required.
* This is a work around to map the latest interaction event type to old TemplateType.
*
* @remark This is a temporary solution until the connector-kit is updated to use the latest interaction event types.
* Utility method to convert interaction event to template type.
**/
const getTemplateTypeByEvent = (event: InteractionEvent): TemplateType =>
export const getTemplateTypeByEvent = (event: InteractionEvent): TemplateType =>
eventToTemplateTypeMap[event];

/** This util method convert the interaction identifier to passcode library payload format */
Expand Down Expand Up @@ -64,7 +61,7 @@
id: string;
type: T;
identifier: VerificationCodeIdentifierOf<T>;
interactionEvent: InteractionEvent;
templateType: TemplateType;
verified: boolean;
};

Expand All @@ -83,13 +80,9 @@
public readonly identifier: VerificationCodeIdentifierOf<T>;

/**
* The interaction event that triggered the verification.
* This will be used to determine the template type for the verification code.
*
* @remark
* `InteractionEvent.ForgotPassword` triggered verification results can not used as a verification record for other events.
* The template type for sending the verification code, the connector will use this to get the correct template.
*/
public readonly interactionEvent: InteractionEvent;
public readonly templateType: TemplateType;
public abstract readonly type: T;
protected verified: boolean;

Expand All @@ -98,11 +91,11 @@
private readonly queries: Queries,
data: CodeVerificationRecordData<T>
) {
const { id, identifier, verified, interactionEvent } = data;
const { id, identifier, verified, templateType } = data;

this.id = id;
this.identifier = identifier;
this.interactionEvent = interactionEvent;
this.templateType = templateType;
this.verified = verified;
}

Expand All @@ -123,7 +116,7 @@

const verificationCode = await createPasscode(
this.id,
getTemplateTypeByEvent(this.interactionEvent),
this.templateType,

Check warning on line 119 in packages/core/src/routes/experience/classes/verifications/code-verification.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/routes/experience/classes/verifications/code-verification.ts#L119

Added line #L119 was not covered by tests
getPasscodeIdentifierPayload(this.identifier)
);

Expand All @@ -148,7 +141,7 @@

await verifyPasscode(
this.id,
getTemplateTypeByEvent(this.interactionEvent),
this.templateType,

Check warning on line 144 in packages/core/src/routes/experience/classes/verifications/code-verification.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/routes/experience/classes/verifications/code-verification.ts#L144

Added line #L144 was not covered by tests
code,
getPasscodeIdentifierPayload(identifier)
);
Expand Down Expand Up @@ -178,13 +171,13 @@
}

toJson(): CodeVerificationRecordData<T> {
const { id, type, identifier, interactionEvent, verified } = this;
const { id, type, identifier, templateType, verified } = this;

return {
id,
type,
identifier,
interactionEvent,
templateType,
verified,
};
}
Expand All @@ -194,7 +187,7 @@

const basicCodeVerificationRecordDataGuard = z.object({
id: z.string(),
interactionEvent: z.nativeEnum(InteractionEvent),
templateType: z.nativeEnum(TemplateType),
verified: z.boolean(),
});

Expand Down Expand Up @@ -273,7 +266,7 @@
identifier:
| VerificationCodeIdentifier<SignInIdentifier.Email>
| VerificationCodeIdentifier<SignInIdentifier.Phone>,
interactionEvent: InteractionEvent
templateType: TemplateType
) => {
const { type } = identifier;

Expand All @@ -283,7 +276,7 @@
id: generateStandardId(),
type: VerificationType.EmailVerificationCode,
identifier,
interactionEvent,
templateType,
verified: false,
});
}
Expand All @@ -292,7 +285,7 @@
id: generateStandardId(),
type: VerificationType.PhoneVerificationCode,
identifier,
interactionEvent,
templateType,
verified: false,
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
import type ExperienceInteraction from '../classes/experience-interaction.js';
import { withSentinel } from '../classes/libraries/sentinel-guard.js';
import { codeVerificationIdentifierRecordTypeMap } from '../classes/utils.js';
import { createNewCodeVerificationRecord } from '../classes/verifications/code-verification.js';
import {
createNewCodeVerificationRecord,
getTemplateTypeByEvent,
} from '../classes/verifications/code-verification.js';
import { experienceRoutes } from '../const.js';
import { type ExperienceInteractionRouterContext } from '../types.js';

Expand Down Expand Up @@ -68,7 +71,7 @@
libraries,
queries,
identifier,
interactionEvent
getTemplateTypeByEvent(interactionEvent)

Check warning on line 74 in packages/core/src/routes/experience/verification-routes/verification-code.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/routes/experience/verification-routes/verification-code.ts#L74

Added line #L74 was not covered by tests
);

await codeVerification.sendVerificationCode();
Expand Down
14 changes: 6 additions & 8 deletions packages/core/src/routes/verification/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TemplateType } from '@logto/connector-kit';
import {
AdditionalIdentifier,
InteractionEvent,
SentinelActivityAction,
SignInIdentifier,
verificationCodeIdentifierGuard,
Expand Down Expand Up @@ -81,25 +81,23 @@
const { identifier } = ctx.guard.body;

const user = await queries.users.findUserById(userId);
const isNewIdentifier =
(identifier.type === SignInIdentifier.Email && identifier.value === user.primaryEmail) ||
(identifier.type === SignInIdentifier.Phone && identifier.value === user.primaryPhone);

Check warning on line 86 in packages/core/src/routes/verification/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/routes/verification/index.ts#L84-L86

Added lines #L84 - L86 were not covered by tests

const codeVerification = createNewCodeVerificationRecord(
libraries,
queries,
identifier,
// TODO(LOG-10148): Add new event
InteractionEvent.SignIn
isNewIdentifier ? TemplateType.BindNewIdentifier : TemplateType.UserPermissionValidation

Check warning on line 92 in packages/core/src/routes/verification/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/routes/verification/index.ts#L92

Added line #L92 was not covered by tests
);

await codeVerification.sendVerificationCode();

await insertVerificationRecord(
codeVerification,
queries,
// If the identifier is the primary email or phone, the verification record is associated with the user.
(identifier.type === SignInIdentifier.Email && identifier.value === user.primaryEmail) ||
(identifier.type === SignInIdentifier.Phone && identifier.value === user.primaryPhone)
? userId
: undefined
isNewIdentifier ? userId : undefined

Check warning on line 100 in packages/core/src/routes/verification/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/routes/verification/index.ts#L100

Added line #L100 was not covered by tests
);

ctx.body = { verificationRecordId: codeVerification.id };
Expand Down
6 changes: 6 additions & 0 deletions packages/toolkit/connector-kit/src/types/passwordless.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export enum VerificationCodeType {
Register = 'Register',
ForgotPassword = 'ForgotPassword',
Generic = 'Generic',
UserPermissionValidation = 'UserPermissionValidation',
BindNewIdentifier = 'BindNewIdentifier',
/** @deprecated Use `Generic` type template for sending test sms/email use case */
Test = 'Test',
}
Expand All @@ -28,6 +30,10 @@ export enum TemplateType {
OrganizationInvitation = 'OrganizationInvitation',
/** The template for generic usage. */
Generic = 'Generic',
/** The template for validating user permission for sensitive operations. */
UserPermissionValidation = 'UserPermissionValidation',
/** The template for binding a new identifier to an existing account. */
BindNewIdentifier = 'BindNewIdentifier',
}

export const templateTypeGuard = z.nativeEnum(TemplateType);
Expand Down
Loading