mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
refactor!: align PasscodeType
to MessageTypes
refactor: apply suggestions from code review Co-authored-by: Darcy Ye <darcyye@silverhand.io> refactor(core): fix type names
This commit is contained in:
parent
a24b6df53f
commit
01f718b258
27 changed files with 236 additions and 190 deletions
|
@ -1,5 +1,6 @@
|
||||||
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
import type { Application, Passcode, Resource, Role, Setting } from '@logto/schemas';
|
import type { Application, Passcode, Resource, Role, Setting } from '@logto/schemas';
|
||||||
import { ApplicationType, PasscodeType } from '@logto/schemas';
|
import { ApplicationType } from '@logto/schemas';
|
||||||
|
|
||||||
export * from './connector.js';
|
export * from './connector.js';
|
||||||
export * from './sign-in-experience.js';
|
export * from './sign-in-experience.js';
|
||||||
|
@ -54,7 +55,7 @@ export const mockPasscode: Passcode = {
|
||||||
interactionJti: 'jti',
|
interactionJti: 'jti',
|
||||||
phone: '888 888 8888',
|
phone: '888 888 8888',
|
||||||
email: 'foo@logto.io',
|
email: 'foo@logto.io',
|
||||||
type: PasscodeType.SignIn,
|
type: MessageTypes.SignIn,
|
||||||
code: 'asdfghjkl',
|
code: 'asdfghjkl',
|
||||||
consumed: false,
|
consumed: false,
|
||||||
tryCount: 2,
|
tryCount: 2,
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import type { AllConnector, CreateConnector } from '@logto/connector-kit';
|
import type { AllConnector, CreateConnector, MessageTypes } from '@logto/connector-kit';
|
||||||
import type { Connector, PasscodeType } from '@logto/schemas';
|
import type { Connector } from '@logto/schemas';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export { ConnectorType } from '@logto/schemas';
|
export { ConnectorType } from '@logto/schemas';
|
||||||
|
|
||||||
export type TemplateType = PasscodeType | 'Test';
|
export type TemplateType = MessageTypes;
|
||||||
|
|
||||||
export const socialUserInfoGuard = z.object({
|
export const socialUserInfoGuard = z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { ConnectorType } from '@logto/connector-kit';
|
import { ConnectorType, MessageTypes } from '@logto/connector-kit';
|
||||||
import type { Passcode } from '@logto/schemas';
|
import { Passcode } from '@logto/schemas';
|
||||||
import { PasscodeType } from '@logto/schemas';
|
|
||||||
import { createMockUtils } from '@logto/shared/esm';
|
import { createMockUtils } from '@logto/shared/esm';
|
||||||
import { any } from 'zod';
|
import { any } from 'zod';
|
||||||
|
|
||||||
|
@ -61,7 +60,7 @@ afterEach(() => {
|
||||||
describe('createPasscode', () => {
|
describe('createPasscode', () => {
|
||||||
it('should generate `passcodeLength` digits code for phone and insert to database', async () => {
|
it('should generate `passcodeLength` digits code for phone and insert to database', async () => {
|
||||||
const phone = '13000000000';
|
const phone = '13000000000';
|
||||||
const passcode = await createPasscode('jti', PasscodeType.SignIn, {
|
const passcode = await createPasscode('jti', MessageTypes.SignIn, {
|
||||||
phone,
|
phone,
|
||||||
});
|
});
|
||||||
expect(new RegExp(`^\\d{${passcodeLength}}$`).test(passcode.code)).toBeTruthy();
|
expect(new RegExp(`^\\d{${passcodeLength}}$`).test(passcode.code)).toBeTruthy();
|
||||||
|
@ -70,7 +69,7 @@ describe('createPasscode', () => {
|
||||||
|
|
||||||
it('should generate `passcodeLength` digits code for email and insert to database', async () => {
|
it('should generate `passcodeLength` digits code for email and insert to database', async () => {
|
||||||
const email = 'jony@example.com';
|
const email = 'jony@example.com';
|
||||||
const passcode = await createPasscode('jti', PasscodeType.SignIn, {
|
const passcode = await createPasscode('jti', MessageTypes.SignIn, {
|
||||||
email,
|
email,
|
||||||
});
|
});
|
||||||
expect(new RegExp(`^\\d{${passcodeLength}}$`).test(passcode.code)).toBeTruthy();
|
expect(new RegExp(`^\\d{${passcodeLength}}$`).test(passcode.code)).toBeTruthy();
|
||||||
|
@ -85,7 +84,7 @@ describe('createPasscode', () => {
|
||||||
id: 'id',
|
id: 'id',
|
||||||
interactionJti: jti,
|
interactionJti: jti,
|
||||||
code: '1234',
|
code: '1234',
|
||||||
type: PasscodeType.SignIn,
|
type: MessageTypes.SignIn,
|
||||||
createdAt: Date.now(),
|
createdAt: Date.now(),
|
||||||
phone: '',
|
phone: '',
|
||||||
email,
|
email,
|
||||||
|
@ -93,7 +92,7 @@ describe('createPasscode', () => {
|
||||||
tryCount: 0,
|
tryCount: 0,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
await createPasscode(jti, PasscodeType.SignIn, {
|
await createPasscode(jti, MessageTypes.SignIn, {
|
||||||
email,
|
email,
|
||||||
});
|
});
|
||||||
expect(deletePasscodesByIds).toHaveBeenCalledWith(['id']);
|
expect(deletePasscodesByIds).toHaveBeenCalledWith(['id']);
|
||||||
|
@ -107,7 +106,7 @@ describe('sendPasscode', () => {
|
||||||
interactionJti: 'jti',
|
interactionJti: 'jti',
|
||||||
phone: null,
|
phone: null,
|
||||||
email: null,
|
email: null,
|
||||||
type: PasscodeType.SignIn,
|
type: MessageTypes.SignIn,
|
||||||
code: '1234',
|
code: '1234',
|
||||||
consumed: false,
|
consumed: false,
|
||||||
tryCount: 0,
|
tryCount: 0,
|
||||||
|
@ -140,7 +139,7 @@ describe('sendPasscode', () => {
|
||||||
interactionJti: 'jti',
|
interactionJti: 'jti',
|
||||||
phone: 'phone',
|
phone: 'phone',
|
||||||
email: null,
|
email: null,
|
||||||
type: PasscodeType.SignIn,
|
type: MessageTypes.SignIn,
|
||||||
code: '1234',
|
code: '1234',
|
||||||
consumed: false,
|
consumed: false,
|
||||||
tryCount: 0,
|
tryCount: 0,
|
||||||
|
@ -191,7 +190,7 @@ describe('sendPasscode', () => {
|
||||||
interactionJti: 'jti',
|
interactionJti: 'jti',
|
||||||
phone: 'phone',
|
phone: 'phone',
|
||||||
email: null,
|
email: null,
|
||||||
type: PasscodeType.SignIn,
|
type: MessageTypes.SignIn,
|
||||||
code: '1234',
|
code: '1234',
|
||||||
consumed: false,
|
consumed: false,
|
||||||
tryCount: 0,
|
tryCount: 0,
|
||||||
|
@ -209,17 +208,17 @@ describe('sendPasscode', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('verifyPasscode', () => {
|
describe('verifyPasscode', () => {
|
||||||
const passcode: Passcode = {
|
const passcode = {
|
||||||
id: 'id',
|
id: 'id',
|
||||||
interactionJti: 'jti',
|
interactionJti: 'jti',
|
||||||
phone: 'phone',
|
phone: 'phone',
|
||||||
email: null,
|
email: null,
|
||||||
type: PasscodeType.SignIn,
|
type: MessageTypes.SignIn,
|
||||||
code: '1234',
|
code: '1234',
|
||||||
consumed: false,
|
consumed: false,
|
||||||
tryCount: 0,
|
tryCount: 0,
|
||||||
createdAt: Date.now(),
|
createdAt: Date.now(),
|
||||||
};
|
} satisfies Passcode;
|
||||||
|
|
||||||
it('should mark as consumed on successful verification', async () => {
|
it('should mark as consumed on successful verification', async () => {
|
||||||
findUnconsumedPasscodeByJtiAndType.mockResolvedValue(passcode);
|
findUnconsumedPasscodeByJtiAndType.mockResolvedValue(passcode);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type { EmailConnector, SmsConnector } from '@logto/connector-kit';
|
import type { EmailConnector, MessageTypes, SmsConnector } from '@logto/connector-kit';
|
||||||
import { messageTypesGuard, ConnectorError, ConnectorErrorCodes } from '@logto/connector-kit';
|
import { messageTypesGuard, ConnectorError, ConnectorErrorCodes } from '@logto/connector-kit';
|
||||||
import type { Passcode, PasscodeType } from '@logto/schemas';
|
import type { Passcode } from '@logto/schemas';
|
||||||
import { customAlphabet, nanoid } from 'nanoid';
|
import { customAlphabet, nanoid } from 'nanoid';
|
||||||
|
|
||||||
import { getLogtoConnectors } from '#src/connectors/index.js';
|
import { getLogtoConnectors } from '#src/connectors/index.js';
|
||||||
|
@ -22,7 +22,7 @@ const randomCode = customAlphabet('1234567890', passcodeLength);
|
||||||
|
|
||||||
export const createPasscode = async (
|
export const createPasscode = async (
|
||||||
jti: string,
|
jti: string,
|
||||||
type: PasscodeType,
|
type: MessageTypes,
|
||||||
payload: { phone: string } | { email: string }
|
payload: { phone: string } | { email: string }
|
||||||
) => {
|
) => {
|
||||||
// Disable existing passcodes.
|
// Disable existing passcodes.
|
||||||
|
@ -88,7 +88,7 @@ export const passcodeMaxTryCount = 10;
|
||||||
|
|
||||||
export const verifyPasscode = async (
|
export const verifyPasscode = async (
|
||||||
sessionId: string,
|
sessionId: string,
|
||||||
type: PasscodeType,
|
type: MessageTypes,
|
||||||
code: string,
|
code: string,
|
||||||
payload: { phone: string } | { email: string }
|
payload: { phone: string } | { email: string }
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Passcodes, PasscodeType } from '@logto/schemas';
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
|
import { Passcodes } from '@logto/schemas';
|
||||||
import { convertToIdentifiers, convertToPrimitiveOrSql, excludeAutoSetFields } from '@logto/shared';
|
import { convertToIdentifiers, convertToPrimitiveOrSql, excludeAutoSetFields } from '@logto/shared';
|
||||||
import { createMockPool, createMockQueryResult, sql } from 'slonik';
|
import { createMockPool, createMockQueryResult, sql } from 'slonik';
|
||||||
import { snakeCase } from 'snake-case';
|
import { snakeCase } from 'snake-case';
|
||||||
|
@ -34,7 +35,7 @@ describe('passcode query', () => {
|
||||||
|
|
||||||
it('findUnconsumedPasscodeByJtiAndType', async () => {
|
it('findUnconsumedPasscodeByJtiAndType', async () => {
|
||||||
const jti = 'foo';
|
const jti = 'foo';
|
||||||
const type = PasscodeType.SignIn;
|
const type = MessageTypes.SignIn;
|
||||||
|
|
||||||
const expectSql = sql`
|
const expectSql = sql`
|
||||||
select ${sql.join(Object.values(fields), sql`, `)}
|
select ${sql.join(Object.values(fields), sql`, `)}
|
||||||
|
@ -54,7 +55,7 @@ describe('passcode query', () => {
|
||||||
|
|
||||||
it('findUnconsumedPasscodesByJtiAndType', async () => {
|
it('findUnconsumedPasscodesByJtiAndType', async () => {
|
||||||
const jti = 'foo';
|
const jti = 'foo';
|
||||||
const type = PasscodeType.SignIn;
|
const type = MessageTypes.SignIn;
|
||||||
|
|
||||||
const expectSql = sql`
|
const expectSql = sql`
|
||||||
select ${sql.join(Object.values(fields), sql`, `)}
|
select ${sql.join(Object.values(fields), sql`, `)}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import type { PasscodeType, Passcode, CreatePasscode } from '@logto/schemas';
|
import type { MessageTypes } from '@logto/connector-kit';
|
||||||
|
import type { Passcode, CreatePasscode } from '@logto/schemas';
|
||||||
import { Passcodes } from '@logto/schemas';
|
import { Passcodes } from '@logto/schemas';
|
||||||
import { convertToIdentifiers } from '@logto/shared';
|
import { convertToIdentifiers } from '@logto/shared';
|
||||||
import { sql } from 'slonik';
|
import { sql } from 'slonik';
|
||||||
|
@ -9,14 +10,14 @@ import { DeletionError } from '#src/errors/SlonikError/index.js';
|
||||||
|
|
||||||
const { table, fields } = convertToIdentifiers(Passcodes);
|
const { table, fields } = convertToIdentifiers(Passcodes);
|
||||||
|
|
||||||
export const findUnconsumedPasscodeByJtiAndType = async (jti: string, type: PasscodeType) =>
|
export const findUnconsumedPasscodeByJtiAndType = async (jti: string, type: MessageTypes) =>
|
||||||
envSet.pool.maybeOne<Passcode>(sql`
|
envSet.pool.maybeOne<Passcode>(sql`
|
||||||
select ${sql.join(Object.values(fields), sql`, `)}
|
select ${sql.join(Object.values(fields), sql`, `)}
|
||||||
from ${table}
|
from ${table}
|
||||||
where ${fields.interactionJti}=${jti} and ${fields.type}=${type} and ${fields.consumed} = false
|
where ${fields.interactionJti}=${jti} and ${fields.type}=${type} and ${fields.consumed} = false
|
||||||
`);
|
`);
|
||||||
|
|
||||||
export const findUnconsumedPasscodesByJtiAndType = async (jti: string, type: PasscodeType) =>
|
export const findUnconsumedPasscodesByJtiAndType = async (jti: string, type: MessageTypes) =>
|
||||||
envSet.pool.any<Passcode>(sql`
|
envSet.pool.any<Passcode>(sql`
|
||||||
select ${sql.join(Object.values(fields), sql`, `)}
|
select ${sql.join(Object.values(fields), sql`, `)}
|
||||||
from ${table}
|
from ${table}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { PasscodeType, InteractionEvent } from '@logto/schemas';
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
|
import { InteractionEvent } from '@logto/schemas';
|
||||||
import { createMockUtils } from '@logto/shared/esm';
|
import { createMockUtils } from '@logto/shared/esm';
|
||||||
|
|
||||||
import { createMockLogContext } from '#src/test-utils/koa-audit-log.js';
|
import { createMockLogContext } from '#src/test-utils/koa-audit-log.js';
|
||||||
|
@ -20,27 +21,27 @@ const { sendPasscodeToIdentifier } = await import('./passcode-validation.js');
|
||||||
const sendPasscodeTestCase = [
|
const sendPasscodeTestCase = [
|
||||||
{
|
{
|
||||||
payload: { email: 'email', event: InteractionEvent.SignIn },
|
payload: { email: 'email', event: InteractionEvent.SignIn },
|
||||||
createPasscodeParams: [PasscodeType.SignIn, { email: 'email' }],
|
createPasscodeParams: [MessageTypes.SignIn, { email: 'email' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
payload: { email: 'email', event: InteractionEvent.Register },
|
payload: { email: 'email', event: InteractionEvent.Register },
|
||||||
createPasscodeParams: [PasscodeType.Register, { email: 'email' }],
|
createPasscodeParams: [MessageTypes.Register, { email: 'email' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
payload: { email: 'email', event: InteractionEvent.ForgotPassword },
|
payload: { email: 'email', event: InteractionEvent.ForgotPassword },
|
||||||
createPasscodeParams: [PasscodeType.ForgotPassword, { email: 'email' }],
|
createPasscodeParams: [MessageTypes.ForgotPassword, { email: 'email' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
payload: { phone: 'phone', event: InteractionEvent.SignIn },
|
payload: { phone: 'phone', event: InteractionEvent.SignIn },
|
||||||
createPasscodeParams: [PasscodeType.SignIn, { phone: 'phone' }],
|
createPasscodeParams: [MessageTypes.SignIn, { phone: 'phone' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
payload: { phone: 'phone', event: InteractionEvent.Register },
|
payload: { phone: 'phone', event: InteractionEvent.Register },
|
||||||
createPasscodeParams: [PasscodeType.Register, { phone: 'phone' }],
|
createPasscodeParams: [MessageTypes.Register, { phone: 'phone' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
payload: { phone: 'phone', event: InteractionEvent.ForgotPassword },
|
payload: { phone: 'phone', event: InteractionEvent.ForgotPassword },
|
||||||
createPasscodeParams: [PasscodeType.ForgotPassword, { phone: 'phone' }],
|
createPasscodeParams: [MessageTypes.ForgotPassword, { phone: 'phone' }],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
import type { InteractionEvent } from '@logto/schemas';
|
import type { InteractionEvent } from '@logto/schemas';
|
||||||
import { PasscodeType } from '@logto/schemas';
|
|
||||||
|
|
||||||
import { createPasscode, sendPasscode, verifyPasscode } from '#src/libraries/passcode.js';
|
import { createPasscode, sendPasscode, verifyPasscode } from '#src/libraries/passcode.js';
|
||||||
import type { LogContext } from '#src/middleware/koa-audit-log.js';
|
import type { LogContext } from '#src/middleware/koa-audit-log.js';
|
||||||
|
@ -8,16 +8,16 @@ import type { SendPasscodePayload, PasscodeIdentifierPayload } from '../types/in
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refactor Needed:
|
* Refactor Needed:
|
||||||
* This is a work around to map the latest interaction event type to old PasscodeType
|
* This is a work around to map the latest interaction event type to old MessageTypes
|
||||||
* */
|
* */
|
||||||
const eventToPasscodeTypeMap: Record<InteractionEvent, PasscodeType> = {
|
const eventToMessageTypesMap: Record<InteractionEvent, MessageTypes> = {
|
||||||
SignIn: PasscodeType.SignIn,
|
SignIn: MessageTypes.SignIn,
|
||||||
Register: PasscodeType.Register,
|
Register: MessageTypes.Register,
|
||||||
ForgotPassword: PasscodeType.ForgotPassword,
|
ForgotPassword: MessageTypes.ForgotPassword,
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPasscodeTypeByEvent = (event: InteractionEvent): PasscodeType =>
|
const getMessageTypesByEvent = (event: InteractionEvent): MessageTypes =>
|
||||||
eventToPasscodeTypeMap[event];
|
eventToMessageTypesMap[event];
|
||||||
|
|
||||||
export const sendPasscodeToIdentifier = async (
|
export const sendPasscodeToIdentifier = async (
|
||||||
payload: SendPasscodePayload,
|
payload: SendPasscodePayload,
|
||||||
|
@ -25,12 +25,12 @@ export const sendPasscodeToIdentifier = async (
|
||||||
createLog: LogContext['createLog']
|
createLog: LogContext['createLog']
|
||||||
) => {
|
) => {
|
||||||
const { event, ...identifier } = payload;
|
const { event, ...identifier } = payload;
|
||||||
const passcodeType = getPasscodeTypeByEvent(event);
|
const messageType = getMessageTypesByEvent(event);
|
||||||
|
|
||||||
const log = createLog(`Interaction.${event}.Identifier.VerificationCode.Create`);
|
const log = createLog(`Interaction.${event}.Identifier.VerificationCode.Create`);
|
||||||
log.append(identifier);
|
log.append(identifier);
|
||||||
|
|
||||||
const passcode = await createPasscode(jti, passcodeType, identifier);
|
const passcode = await createPasscode(jti, messageType, identifier);
|
||||||
const { dbEntry } = await sendPasscode(passcode);
|
const { dbEntry } = await sendPasscode(passcode);
|
||||||
|
|
||||||
log.append({ connectorId: dbEntry.id });
|
log.append({ connectorId: dbEntry.id });
|
||||||
|
@ -42,11 +42,11 @@ export const verifyIdentifierByPasscode = async (
|
||||||
createLog: LogContext['createLog']
|
createLog: LogContext['createLog']
|
||||||
) => {
|
) => {
|
||||||
const { event, passcode, ...identifier } = payload;
|
const { event, passcode, ...identifier } = payload;
|
||||||
const passcodeType = getPasscodeTypeByEvent(event);
|
const messageType = getMessageTypesByEvent(event);
|
||||||
|
|
||||||
// TODO: @Simeng maybe we should just log all interaction payload in every request?
|
// TODO: @Simeng maybe we should just log all interaction payload in every request?
|
||||||
const log = createLog(`Interaction.${event}.Identifier.VerificationCode.Submit`);
|
const log = createLog(`Interaction.${event}.Identifier.VerificationCode.Submit`);
|
||||||
log.append(identifier);
|
log.append(identifier);
|
||||||
|
|
||||||
await verifyPasscode(jti, passcodeType, passcode, identifier);
|
await verifyPasscode(jti, messageType, passcode, identifier);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { PasscodeType } from '@logto/schemas';
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
import { addDays, subSeconds } from 'date-fns';
|
import { addDays, subSeconds } from 'date-fns';
|
||||||
import { Provider } from 'oidc-provider';
|
import { Provider } from 'oidc-provider';
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ describe('session -> continueRoutes', () => {
|
||||||
continueSignIn: {
|
continueSignIn: {
|
||||||
userId: mockUser.id,
|
userId: mockUser.id,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
type: PasscodeType.Continue,
|
type: MessageTypes.Continue,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -172,7 +172,7 @@ describe('session -> continueRoutes', () => {
|
||||||
continueSignIn: {
|
continueSignIn: {
|
||||||
userId: mockUser.id,
|
userId: mockUser.id,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
type: PasscodeType.Continue,
|
type: MessageTypes.Continue,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
import type { User } from '@logto/schemas';
|
import type { User } from '@logto/schemas';
|
||||||
import { PasscodeType } from '@logto/schemas';
|
|
||||||
import { addDays, subDays } from 'date-fns';
|
import { addDays, subDays } from 'date-fns';
|
||||||
import { Provider } from 'oidc-provider';
|
import { Provider } from 'oidc-provider';
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ describe('session -> forgotPasswordRoutes', () => {
|
||||||
verification: {
|
verification: {
|
||||||
userId: 'id',
|
userId: 'id',
|
||||||
expiresAt: getTomorrowDate().toISOString(),
|
expiresAt: getTomorrowDate().toISOString(),
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -118,7 +118,7 @@ describe('session -> forgotPasswordRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
expiresAt: getTomorrowDate().toISOString(),
|
expiresAt: getTomorrowDate().toISOString(),
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -134,7 +134,7 @@ describe('session -> forgotPasswordRoutes', () => {
|
||||||
verification: {
|
verification: {
|
||||||
userId: 'id',
|
userId: 'id',
|
||||||
expiresAt: getTomorrowDate().toISOString(),
|
expiresAt: getTomorrowDate().toISOString(),
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -147,7 +147,7 @@ describe('session -> forgotPasswordRoutes', () => {
|
||||||
it('should throw when `verification.expiresAt` is not string', async () => {
|
it('should throw when `verification.expiresAt` is not string', async () => {
|
||||||
interactionDetails.mockResolvedValueOnce({
|
interactionDetails.mockResolvedValueOnce({
|
||||||
result: {
|
result: {
|
||||||
verification: { userId: 'id', expiresAt: 0, flow: PasscodeType.ForgotPassword },
|
verification: { userId: 'id', expiresAt: 0, flow: MessageTypes.ForgotPassword },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const response = await sessionRequest
|
const response = await sessionRequest
|
||||||
|
@ -162,7 +162,7 @@ describe('session -> forgotPasswordRoutes', () => {
|
||||||
verification: {
|
verification: {
|
||||||
userId: 'id',
|
userId: 'id',
|
||||||
expiresAt: 'invalid date string',
|
expiresAt: 'invalid date string',
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -178,7 +178,7 @@ describe('session -> forgotPasswordRoutes', () => {
|
||||||
verification: {
|
verification: {
|
||||||
userId: 'id',
|
userId: 'id',
|
||||||
expiresAt: getYesterdayDate().toISOString(),
|
expiresAt: getYesterdayDate().toISOString(),
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -194,7 +194,7 @@ describe('session -> forgotPasswordRoutes', () => {
|
||||||
verification: {
|
verification: {
|
||||||
userId: 'id',
|
userId: 'id',
|
||||||
expiresAt: getTomorrowDate().toISOString(),
|
expiresAt: getTomorrowDate().toISOString(),
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -211,7 +211,7 @@ describe('session -> forgotPasswordRoutes', () => {
|
||||||
verification: {
|
verification: {
|
||||||
userId: 'id',
|
userId: 'id',
|
||||||
expiresAt: getTomorrowDate().toISOString(),
|
expiresAt: getTomorrowDate().toISOString(),
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { PasscodeType, SignInIdentifier } from '@logto/schemas';
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
|
import { SignInIdentifier } from '@logto/schemas';
|
||||||
import type { MiddlewareType } from 'koa';
|
import type { MiddlewareType } from 'koa';
|
||||||
import type { Provider } from 'oidc-provider';
|
import type { Provider } from 'oidc-provider';
|
||||||
|
|
||||||
|
@ -51,7 +52,7 @@ export const smsSignInAction = <StateT, ContextT extends WithLogContextLegacy, R
|
||||||
smsSessionResultGuard
|
smsSessionResultGuard
|
||||||
);
|
);
|
||||||
|
|
||||||
const type = getPasswordlessRelatedLogType(PasscodeType.SignIn, 'sms');
|
const type = getPasswordlessRelatedLogType(MessageTypes.SignIn, 'sms');
|
||||||
ctx.log(type, verificationStorage);
|
ctx.log(type, verificationStorage);
|
||||||
|
|
||||||
const { phone, expiresAt } = verificationStorage;
|
const { phone, expiresAt } = verificationStorage;
|
||||||
|
@ -96,7 +97,7 @@ export const emailSignInAction = <StateT, ContextT extends WithLogContextLegacy,
|
||||||
emailSessionResultGuard
|
emailSessionResultGuard
|
||||||
);
|
);
|
||||||
|
|
||||||
const type = getPasswordlessRelatedLogType(PasscodeType.SignIn, 'email');
|
const type = getPasswordlessRelatedLogType(MessageTypes.SignIn, 'email');
|
||||||
ctx.log(type, verificationStorage);
|
ctx.log(type, verificationStorage);
|
||||||
|
|
||||||
const { email, expiresAt } = verificationStorage;
|
const { email, expiresAt } = verificationStorage;
|
||||||
|
@ -139,7 +140,7 @@ export const smsRegisterAction = <StateT, ContextT extends WithLogContextLegacy,
|
||||||
smsSessionResultGuard
|
smsSessionResultGuard
|
||||||
);
|
);
|
||||||
|
|
||||||
const type = getPasswordlessRelatedLogType(PasscodeType.Register, 'sms');
|
const type = getPasswordlessRelatedLogType(MessageTypes.Register, 'sms');
|
||||||
ctx.log(type, verificationStorage);
|
ctx.log(type, verificationStorage);
|
||||||
|
|
||||||
const { phone, expiresAt } = verificationStorage;
|
const { phone, expiresAt } = verificationStorage;
|
||||||
|
@ -183,7 +184,7 @@ export const emailRegisterAction = <StateT, ContextT extends WithLogContextLegac
|
||||||
emailSessionResultGuard
|
emailSessionResultGuard
|
||||||
);
|
);
|
||||||
|
|
||||||
const type = getPasswordlessRelatedLogType(PasscodeType.Register, 'email');
|
const type = getPasswordlessRelatedLogType(MessageTypes.Register, 'email');
|
||||||
ctx.log(type, verificationStorage);
|
ctx.log(type, verificationStorage);
|
||||||
|
|
||||||
const { email, expiresAt } = verificationStorage;
|
const { email, expiresAt } = verificationStorage;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* eslint-disable max-lines */
|
/* eslint-disable max-lines */
|
||||||
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
import type { User } from '@logto/schemas';
|
import type { User } from '@logto/schemas';
|
||||||
import { PasscodeType, SignInIdentifier } from '@logto/schemas';
|
import { SignInIdentifier } from '@logto/schemas';
|
||||||
import type { Nullable } from '@silverhand/essentials';
|
import type { Nullable } from '@silverhand/essentials';
|
||||||
import { addDays, addSeconds, subDays } from 'date-fns';
|
import { addDays, addSeconds, subDays } from 'date-fns';
|
||||||
import { Provider } from 'oidc-provider';
|
import { Provider } from 'oidc-provider';
|
||||||
|
@ -107,9 +108,9 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
it('should call sendPasscode (with flow `sign-in`)', async () => {
|
it('should call sendPasscode (with flow `sign-in`)', async () => {
|
||||||
const response = await sessionRequest
|
const response = await sessionRequest
|
||||||
.post('/session/passwordless/sms/send')
|
.post('/session/passwordless/sms/send')
|
||||||
.send({ phone: '13000000000', flow: PasscodeType.SignIn });
|
.send({ phone: '13000000000', flow: MessageTypes.SignIn });
|
||||||
expect(response.statusCode).toEqual(204);
|
expect(response.statusCode).toEqual(204);
|
||||||
expect(createPasscode).toHaveBeenCalledWith('jti', PasscodeType.SignIn, {
|
expect(createPasscode).toHaveBeenCalledWith('jti', MessageTypes.SignIn, {
|
||||||
phone: '13000000000',
|
phone: '13000000000',
|
||||||
});
|
});
|
||||||
expect(sendPasscode).toHaveBeenCalled();
|
expect(sendPasscode).toHaveBeenCalled();
|
||||||
|
@ -117,9 +118,9 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
it('should call sendPasscode (with flow `register`)', async () => {
|
it('should call sendPasscode (with flow `register`)', async () => {
|
||||||
const response = await sessionRequest
|
const response = await sessionRequest
|
||||||
.post('/session/passwordless/sms/send')
|
.post('/session/passwordless/sms/send')
|
||||||
.send({ phone: '13000000000', flow: PasscodeType.Register });
|
.send({ phone: '13000000000', flow: MessageTypes.Register });
|
||||||
expect(response.statusCode).toEqual(204);
|
expect(response.statusCode).toEqual(204);
|
||||||
expect(createPasscode).toHaveBeenCalledWith('jti', PasscodeType.Register, {
|
expect(createPasscode).toHaveBeenCalledWith('jti', MessageTypes.Register, {
|
||||||
phone: '13000000000',
|
phone: '13000000000',
|
||||||
});
|
});
|
||||||
expect(sendPasscode).toHaveBeenCalled();
|
expect(sendPasscode).toHaveBeenCalled();
|
||||||
|
@ -127,9 +128,9 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
it('should call sendPasscode (with flow `forgot-password`)', async () => {
|
it('should call sendPasscode (with flow `forgot-password`)', async () => {
|
||||||
const response = await sessionRequest
|
const response = await sessionRequest
|
||||||
.post('/session/passwordless/sms/send')
|
.post('/session/passwordless/sms/send')
|
||||||
.send({ phone: '13000000000', flow: PasscodeType.ForgotPassword });
|
.send({ phone: '13000000000', flow: MessageTypes.ForgotPassword });
|
||||||
expect(response.statusCode).toEqual(204);
|
expect(response.statusCode).toEqual(204);
|
||||||
expect(createPasscode).toHaveBeenCalledWith('jti', PasscodeType.ForgotPassword, {
|
expect(createPasscode).toHaveBeenCalledWith('jti', MessageTypes.ForgotPassword, {
|
||||||
phone: '13000000000',
|
phone: '13000000000',
|
||||||
});
|
});
|
||||||
expect(sendPasscode).toHaveBeenCalled();
|
expect(sendPasscode).toHaveBeenCalled();
|
||||||
|
@ -137,7 +138,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
it('throw when phone not given in input params', async () => {
|
it('throw when phone not given in input params', async () => {
|
||||||
const response = await sessionRequest
|
const response = await sessionRequest
|
||||||
.post('/session/passwordless/sms/send')
|
.post('/session/passwordless/sms/send')
|
||||||
.send({ flow: PasscodeType.Register });
|
.send({ flow: MessageTypes.Register });
|
||||||
expect(response.statusCode).toEqual(400);
|
expect(response.statusCode).toEqual(400);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -151,9 +152,9 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
it('should call sendPasscode (with flow `sign-in`)', async () => {
|
it('should call sendPasscode (with flow `sign-in`)', async () => {
|
||||||
const response = await sessionRequest
|
const response = await sessionRequest
|
||||||
.post('/session/passwordless/email/send')
|
.post('/session/passwordless/email/send')
|
||||||
.send({ email: 'a@a.com', flow: PasscodeType.SignIn });
|
.send({ email: 'a@a.com', flow: MessageTypes.SignIn });
|
||||||
expect(response.statusCode).toEqual(204);
|
expect(response.statusCode).toEqual(204);
|
||||||
expect(createPasscode).toHaveBeenCalledWith('jti', PasscodeType.SignIn, {
|
expect(createPasscode).toHaveBeenCalledWith('jti', MessageTypes.SignIn, {
|
||||||
email: 'a@a.com',
|
email: 'a@a.com',
|
||||||
});
|
});
|
||||||
expect(sendPasscode).toHaveBeenCalled();
|
expect(sendPasscode).toHaveBeenCalled();
|
||||||
|
@ -161,9 +162,9 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
it('should call sendPasscode (with flow `register`)', async () => {
|
it('should call sendPasscode (with flow `register`)', async () => {
|
||||||
const response = await sessionRequest
|
const response = await sessionRequest
|
||||||
.post('/session/passwordless/email/send')
|
.post('/session/passwordless/email/send')
|
||||||
.send({ email: 'a@a.com', flow: PasscodeType.Register });
|
.send({ email: 'a@a.com', flow: MessageTypes.Register });
|
||||||
expect(response.statusCode).toEqual(204);
|
expect(response.statusCode).toEqual(204);
|
||||||
expect(createPasscode).toHaveBeenCalledWith('jti', PasscodeType.Register, {
|
expect(createPasscode).toHaveBeenCalledWith('jti', MessageTypes.Register, {
|
||||||
email: 'a@a.com',
|
email: 'a@a.com',
|
||||||
});
|
});
|
||||||
expect(sendPasscode).toHaveBeenCalled();
|
expect(sendPasscode).toHaveBeenCalled();
|
||||||
|
@ -171,9 +172,9 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
it('should call sendPasscode (with flow `forgot-password`)', async () => {
|
it('should call sendPasscode (with flow `forgot-password`)', async () => {
|
||||||
const response = await sessionRequest
|
const response = await sessionRequest
|
||||||
.post('/session/passwordless/email/send')
|
.post('/session/passwordless/email/send')
|
||||||
.send({ email: 'a@a.com', flow: PasscodeType.ForgotPassword });
|
.send({ email: 'a@a.com', flow: MessageTypes.ForgotPassword });
|
||||||
expect(response.statusCode).toEqual(204);
|
expect(response.statusCode).toEqual(204);
|
||||||
expect(createPasscode).toHaveBeenCalledWith('jti', PasscodeType.ForgotPassword, {
|
expect(createPasscode).toHaveBeenCalledWith('jti', MessageTypes.ForgotPassword, {
|
||||||
email: 'a@a.com',
|
email: 'a@a.com',
|
||||||
});
|
});
|
||||||
expect(sendPasscode).toHaveBeenCalled();
|
expect(sendPasscode).toHaveBeenCalled();
|
||||||
|
@ -181,7 +182,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
it('throw when email not given in input params', async () => {
|
it('throw when email not given in input params', async () => {
|
||||||
const response = await sessionRequest
|
const response = await sessionRequest
|
||||||
.post('/session/passwordless/email/send')
|
.post('/session/passwordless/email/send')
|
||||||
.send({ flow: PasscodeType.Register });
|
.send({ flow: MessageTypes.Register });
|
||||||
expect(response.statusCode).toEqual(400);
|
expect(response.statusCode).toEqual(400);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -203,14 +204,14 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
|
|
||||||
await sessionRequest
|
await sessionRequest
|
||||||
.post('/session/passwordless/sms/verify')
|
.post('/session/passwordless/sms/verify')
|
||||||
.send({ phone: '13000000000', code: '1234', flow: PasscodeType.SignIn });
|
.send({ phone: '13000000000', code: '1234', flow: MessageTypes.SignIn });
|
||||||
|
|
||||||
expect(interactionResult).toHaveBeenCalledWith(
|
expect(interactionResult).toHaveBeenCalledWith(
|
||||||
expect.anything(),
|
expect.anything(),
|
||||||
expect.anything(),
|
expect.anything(),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
verification: {
|
verification: {
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
phone: '13000000000',
|
phone: '13000000000',
|
||||||
expiresAt: addSeconds(fakeTime, verificationTimeout).toISOString(),
|
expiresAt: addSeconds(fakeTime, verificationTimeout).toISOString(),
|
||||||
},
|
},
|
||||||
|
@ -227,14 +228,14 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
|
|
||||||
await sessionRequest
|
await sessionRequest
|
||||||
.post('/session/passwordless/sms/verify')
|
.post('/session/passwordless/sms/verify')
|
||||||
.send({ phone: '13000000000', code: '1234', flow: PasscodeType.Register });
|
.send({ phone: '13000000000', code: '1234', flow: MessageTypes.Register });
|
||||||
|
|
||||||
expect(interactionResult).toHaveBeenCalledWith(
|
expect(interactionResult).toHaveBeenCalledWith(
|
||||||
expect.anything(),
|
expect.anything(),
|
||||||
expect.anything(),
|
expect.anything(),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
verification: {
|
verification: {
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
phone: '13000000000',
|
phone: '13000000000',
|
||||||
expiresAt: addSeconds(fakeTime, verificationTimeout).toISOString(),
|
expiresAt: addSeconds(fakeTime, verificationTimeout).toISOString(),
|
||||||
},
|
},
|
||||||
|
@ -250,7 +251,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
|
|
||||||
const response = await sessionRequest
|
const response = await sessionRequest
|
||||||
.post('/session/passwordless/sms/verify')
|
.post('/session/passwordless/sms/verify')
|
||||||
.send({ phone: '13000000000', code: '1234', flow: PasscodeType.ForgotPassword });
|
.send({ phone: '13000000000', code: '1234', flow: MessageTypes.ForgotPassword });
|
||||||
|
|
||||||
expect(response.statusCode).toEqual(204);
|
expect(response.statusCode).toEqual(204);
|
||||||
|
|
||||||
|
@ -261,7 +262,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
verification: {
|
verification: {
|
||||||
userId: mockUser.id,
|
userId: mockUser.id,
|
||||||
expiresAt: addSeconds(fakeTime, verificationTimeout).toISOString(),
|
expiresAt: addSeconds(fakeTime, verificationTimeout).toISOString(),
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -271,7 +272,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
findUserByPhone.mockResolvedValueOnce(null);
|
findUserByPhone.mockResolvedValueOnce(null);
|
||||||
const response = await sessionRequest
|
const response = await sessionRequest
|
||||||
.post('/session/passwordless/sms/verify')
|
.post('/session/passwordless/sms/verify')
|
||||||
.send({ phone: '13000000001', code: '1234', flow: PasscodeType.ForgotPassword });
|
.send({ phone: '13000000001', code: '1234', flow: MessageTypes.ForgotPassword });
|
||||||
expect(response.statusCode).toEqual(404);
|
expect(response.statusCode).toEqual(404);
|
||||||
expect(interactionResult).toHaveBeenCalledTimes(0);
|
expect(interactionResult).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
@ -279,7 +280,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
it('throw when code is wrong', async () => {
|
it('throw when code is wrong', async () => {
|
||||||
const response = await sessionRequest
|
const response = await sessionRequest
|
||||||
.post('/session/passwordless/sms/verify')
|
.post('/session/passwordless/sms/verify')
|
||||||
.send({ phone: '13000000000', code: '1231', flow: PasscodeType.SignIn });
|
.send({ phone: '13000000000', code: '1231', flow: MessageTypes.SignIn });
|
||||||
expect(response.statusCode).toEqual(400);
|
expect(response.statusCode).toEqual(400);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -301,14 +302,14 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
|
|
||||||
await sessionRequest
|
await sessionRequest
|
||||||
.post('/session/passwordless/email/verify')
|
.post('/session/passwordless/email/verify')
|
||||||
.send({ email: 'a@a.com', code: '1234', flow: PasscodeType.SignIn });
|
.send({ email: 'a@a.com', code: '1234', flow: MessageTypes.SignIn });
|
||||||
|
|
||||||
expect(interactionResult).toHaveBeenCalledWith(
|
expect(interactionResult).toHaveBeenCalledWith(
|
||||||
expect.anything(),
|
expect.anything(),
|
||||||
expect.anything(),
|
expect.anything(),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
verification: {
|
verification: {
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
email: 'a@a.com',
|
email: 'a@a.com',
|
||||||
expiresAt: addSeconds(fakeTime, verificationTimeout).toISOString(),
|
expiresAt: addSeconds(fakeTime, verificationTimeout).toISOString(),
|
||||||
},
|
},
|
||||||
|
@ -324,14 +325,14 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
|
|
||||||
await sessionRequest
|
await sessionRequest
|
||||||
.post('/session/passwordless/email/verify')
|
.post('/session/passwordless/email/verify')
|
||||||
.send({ email: 'a@a.com', code: '1234', flow: PasscodeType.Register });
|
.send({ email: 'a@a.com', code: '1234', flow: MessageTypes.Register });
|
||||||
|
|
||||||
expect(interactionResult).toHaveBeenCalledWith(
|
expect(interactionResult).toHaveBeenCalledWith(
|
||||||
expect.anything(),
|
expect.anything(),
|
||||||
expect.anything(),
|
expect.anything(),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
verification: {
|
verification: {
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
email: 'a@a.com',
|
email: 'a@a.com',
|
||||||
expiresAt: addSeconds(fakeTime, verificationTimeout).toISOString(),
|
expiresAt: addSeconds(fakeTime, verificationTimeout).toISOString(),
|
||||||
},
|
},
|
||||||
|
@ -347,7 +348,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
|
|
||||||
const response = await sessionRequest
|
const response = await sessionRequest
|
||||||
.post('/session/passwordless/email/verify')
|
.post('/session/passwordless/email/verify')
|
||||||
.send({ email: 'a@a.com', code: '1234', flow: PasscodeType.ForgotPassword });
|
.send({ email: 'a@a.com', code: '1234', flow: MessageTypes.ForgotPassword });
|
||||||
|
|
||||||
expect(response.statusCode).toEqual(204);
|
expect(response.statusCode).toEqual(204);
|
||||||
|
|
||||||
|
@ -358,7 +359,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
verification: {
|
verification: {
|
||||||
userId: mockUser.id,
|
userId: mockUser.id,
|
||||||
expiresAt: addSeconds(fakeTime, verificationTimeout).toISOString(),
|
expiresAt: addSeconds(fakeTime, verificationTimeout).toISOString(),
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -370,7 +371,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
findUserByEmail.mockResolvedValueOnce(null);
|
findUserByEmail.mockResolvedValueOnce(null);
|
||||||
const response = await sessionRequest
|
const response = await sessionRequest
|
||||||
.post('/session/passwordless/email/verify')
|
.post('/session/passwordless/email/verify')
|
||||||
.send({ email: 'b@a.com', code: '1234', flow: PasscodeType.ForgotPassword });
|
.send({ email: 'b@a.com', code: '1234', flow: MessageTypes.ForgotPassword });
|
||||||
expect(response.statusCode).toEqual(404);
|
expect(response.statusCode).toEqual(404);
|
||||||
expect(interactionResult).toHaveBeenCalledTimes(0);
|
expect(interactionResult).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
@ -378,7 +379,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
it('throw when code is wrong', async () => {
|
it('throw when code is wrong', async () => {
|
||||||
const response = await sessionRequest
|
const response = await sessionRequest
|
||||||
.post('/session/passwordless/email/verify')
|
.post('/session/passwordless/email/verify')
|
||||||
.send({ email: 'a@a.com', code: '1231', flow: PasscodeType.SignIn });
|
.send({ email: 'a@a.com', code: '1231', flow: MessageTypes.SignIn });
|
||||||
expect(response.statusCode).toEqual(400);
|
expect(response.statusCode).toEqual(400);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -389,7 +390,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
phone: '13000000000',
|
phone: '13000000000',
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -413,7 +414,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
phone: '13000000000',
|
phone: '13000000000',
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -448,7 +449,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
phone: '13000000000',
|
phone: '13000000000',
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -462,7 +463,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
phone: '13000000000',
|
phone: '13000000000',
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
expiresAt: 'invalid date string',
|
expiresAt: 'invalid date string',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -476,7 +477,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
phone: '13000000000',
|
phone: '13000000000',
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
expiresAt: subDays(Date.now(), 1).toISOString(),
|
expiresAt: subDays(Date.now(), 1).toISOString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -490,7 +491,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
email: 'XX@foo',
|
email: 'XX@foo',
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -504,7 +505,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
phone: '13000000001',
|
phone: '13000000001',
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -523,7 +524,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
phone: '13000000000',
|
phone: '13000000000',
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -571,7 +572,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
email: 'a@a.com',
|
email: 'a@a.com',
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -595,7 +596,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
email: 'a@a.com',
|
email: 'a@a.com',
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -632,7 +633,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
email: 'a@a.com',
|
email: 'a@a.com',
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -645,7 +646,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
interactionDetails.mockResolvedValueOnce({
|
interactionDetails.mockResolvedValueOnce({
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -659,7 +660,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
email: 'b@a.com',
|
email: 'b@a.com',
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -678,7 +679,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
email: 'a@a.com',
|
email: 'a@a.com',
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -725,7 +726,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
phone: '13000000001',
|
phone: '13000000001',
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -747,7 +748,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
phone: '13000000001',
|
phone: '13000000001',
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -782,7 +783,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
phone: '13000000001',
|
phone: '13000000001',
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -795,7 +796,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
interactionDetails.mockResolvedValueOnce({
|
interactionDetails.mockResolvedValueOnce({
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -809,7 +810,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
phone: '13000000000',
|
phone: '13000000000',
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -853,7 +854,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
email: 'b@a.com',
|
email: 'b@a.com',
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -875,7 +876,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
email: 'b@a.com',
|
email: 'b@a.com',
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -910,7 +911,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
email: 'b@a.com',
|
email: 'b@a.com',
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -923,7 +924,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
interactionDetails.mockResolvedValueOnce({
|
interactionDetails.mockResolvedValueOnce({
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -937,7 +938,7 @@ describe('session -> passwordlessRoutes', () => {
|
||||||
result: {
|
result: {
|
||||||
verification: {
|
verification: {
|
||||||
email: 'a@a.com',
|
email: 'a@a.com',
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
expiresAt: getTomorrowIsoString(),
|
expiresAt: getTomorrowIsoString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
import { emailRegEx, phoneRegEx } from '@logto/core-kit';
|
import { emailRegEx, phoneRegEx } from '@logto/core-kit';
|
||||||
import { PasscodeType } from '@logto/schemas';
|
|
||||||
import type { Provider } from 'oidc-provider';
|
import type { Provider } from 'oidc-provider';
|
||||||
import { object, string } from 'zod';
|
import { object, string } from 'zod';
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ import RequestError from '#src/errors/RequestError/index.js';
|
||||||
import { createPasscode, sendPasscode, verifyPasscode } from '#src/libraries/passcode.js';
|
import { createPasscode, sendPasscode, verifyPasscode } from '#src/libraries/passcode.js';
|
||||||
import koaGuard from '#src/middleware/koa-guard.js';
|
import koaGuard from '#src/middleware/koa-guard.js';
|
||||||
import { findUserByEmail, findUserByPhone } from '#src/queries/user.js';
|
import { findUserByEmail, findUserByPhone } from '#src/queries/user.js';
|
||||||
import { passcodeTypeGuard } from '#src/routes/session/types.js';
|
|
||||||
import assertThat from '#src/utils/assert-that.js';
|
import assertThat from '#src/utils/assert-that.js';
|
||||||
|
|
||||||
import type { AnonymousRouterLegacy } from '../types.js';
|
import type { AnonymousRouterLegacy } from '../types.js';
|
||||||
|
@ -17,6 +16,7 @@ import {
|
||||||
smsRegisterAction,
|
smsRegisterAction,
|
||||||
emailRegisterAction,
|
emailRegisterAction,
|
||||||
} from './middleware/passwordless-action.js';
|
} from './middleware/passwordless-action.js';
|
||||||
|
import { flowTypeGuard } from './types.js';
|
||||||
import {
|
import {
|
||||||
assignVerificationResult,
|
assignVerificationResult,
|
||||||
getPasswordlessRelatedLogType,
|
getPasswordlessRelatedLogType,
|
||||||
|
@ -35,7 +35,7 @@ export default function passwordlessRoutes<T extends AnonymousRouterLegacy>(
|
||||||
koaGuard({
|
koaGuard({
|
||||||
body: object({
|
body: object({
|
||||||
phone: string().regex(phoneRegEx),
|
phone: string().regex(phoneRegEx),
|
||||||
flow: passcodeTypeGuard,
|
flow: flowTypeGuard,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
async (ctx, next) => {
|
async (ctx, next) => {
|
||||||
|
@ -61,7 +61,7 @@ export default function passwordlessRoutes<T extends AnonymousRouterLegacy>(
|
||||||
koaGuard({
|
koaGuard({
|
||||||
body: object({
|
body: object({
|
||||||
email: string().regex(emailRegEx),
|
email: string().regex(emailRegEx),
|
||||||
flow: passcodeTypeGuard,
|
flow: flowTypeGuard,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
async (ctx, next) => {
|
async (ctx, next) => {
|
||||||
|
@ -88,7 +88,7 @@ export default function passwordlessRoutes<T extends AnonymousRouterLegacy>(
|
||||||
body: object({
|
body: object({
|
||||||
phone: string().regex(phoneRegEx),
|
phone: string().regex(phoneRegEx),
|
||||||
code: string(),
|
code: string(),
|
||||||
flow: passcodeTypeGuard,
|
flow: flowTypeGuard,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
async (ctx, next) => {
|
async (ctx, next) => {
|
||||||
|
@ -103,7 +103,7 @@ export default function passwordlessRoutes<T extends AnonymousRouterLegacy>(
|
||||||
|
|
||||||
await verifyPasscode(jti, flow, code, { phone });
|
await verifyPasscode(jti, flow, code, { phone });
|
||||||
|
|
||||||
if (flow === PasscodeType.ForgotPassword) {
|
if (flow === MessageTypes.ForgotPassword) {
|
||||||
const user = await findUserByPhone(phone);
|
const user = await findUserByPhone(phone);
|
||||||
assertThat(user, new RequestError({ code: 'user.phone_not_exist', status: 404 }));
|
assertThat(user, new RequestError({ code: 'user.phone_not_exist', status: 404 }));
|
||||||
|
|
||||||
|
@ -113,13 +113,13 @@ export default function passwordlessRoutes<T extends AnonymousRouterLegacy>(
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flow === PasscodeType.SignIn) {
|
if (flow === MessageTypes.SignIn) {
|
||||||
await assignVerificationResult(ctx, provider, { flow, phone });
|
await assignVerificationResult(ctx, provider, { flow, phone });
|
||||||
|
|
||||||
return smsSignInAction(provider)(ctx, next);
|
return smsSignInAction(provider)(ctx, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flow === PasscodeType.Register) {
|
if (flow === MessageTypes.Register) {
|
||||||
await assignVerificationResult(ctx, provider, { flow, phone });
|
await assignVerificationResult(ctx, provider, { flow, phone });
|
||||||
|
|
||||||
return smsRegisterAction(provider)(ctx, next);
|
return smsRegisterAction(provider)(ctx, next);
|
||||||
|
@ -138,7 +138,7 @@ export default function passwordlessRoutes<T extends AnonymousRouterLegacy>(
|
||||||
body: object({
|
body: object({
|
||||||
email: string().regex(emailRegEx),
|
email: string().regex(emailRegEx),
|
||||||
code: string(),
|
code: string(),
|
||||||
flow: passcodeTypeGuard,
|
flow: flowTypeGuard,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
async (ctx, next) => {
|
async (ctx, next) => {
|
||||||
|
@ -152,7 +152,7 @@ export default function passwordlessRoutes<T extends AnonymousRouterLegacy>(
|
||||||
|
|
||||||
await verifyPasscode(jti, flow, code, { email });
|
await verifyPasscode(jti, flow, code, { email });
|
||||||
|
|
||||||
if (flow === PasscodeType.ForgotPassword) {
|
if (flow === MessageTypes.ForgotPassword) {
|
||||||
const user = await findUserByEmail(email);
|
const user = await findUserByEmail(email);
|
||||||
|
|
||||||
assertThat(user, new RequestError({ code: 'user.email_not_exist', status: 404 }));
|
assertThat(user, new RequestError({ code: 'user.email_not_exist', status: 404 }));
|
||||||
|
@ -163,13 +163,13 @@ export default function passwordlessRoutes<T extends AnonymousRouterLegacy>(
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flow === PasscodeType.SignIn) {
|
if (flow === MessageTypes.SignIn) {
|
||||||
await assignVerificationResult(ctx, provider, { flow, email });
|
await assignVerificationResult(ctx, provider, { flow, email });
|
||||||
|
|
||||||
return emailSignInAction(provider)(ctx, next);
|
return emailSignInAction(provider)(ctx, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flow === PasscodeType.Register) {
|
if (flow === MessageTypes.Register) {
|
||||||
await assignVerificationResult(ctx, provider, { flow, email });
|
await assignVerificationResult(ctx, provider, { flow, email });
|
||||||
|
|
||||||
return emailRegisterAction(provider)(ctx, next);
|
return emailRegisterAction(provider)(ctx, next);
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
import { PasscodeType } from '@logto/schemas';
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
|
import { pick } from '@silverhand/essentials';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const passcodeTypeGuard = z.nativeEnum(PasscodeType);
|
export const flowTypeGuard = z.nativeEnum(
|
||||||
|
pick(MessageTypes, 'Continue', 'ForgotPassword', 'Register', 'SignIn')
|
||||||
|
);
|
||||||
|
|
||||||
export const methodGuard = z.enum(['email', 'sms']);
|
export const methodGuard = z.enum(['email', 'sms']);
|
||||||
|
|
||||||
|
@ -12,7 +15,7 @@ export const operationGuard = z.enum(['send', 'verify']);
|
||||||
export type Operation = z.infer<typeof operationGuard>;
|
export type Operation = z.infer<typeof operationGuard>;
|
||||||
|
|
||||||
const smsSessionStorageGuard = z.object({
|
const smsSessionStorageGuard = z.object({
|
||||||
flow: z.literal(PasscodeType.SignIn).or(z.literal(PasscodeType.Register)),
|
flow: z.literal(MessageTypes.SignIn).or(z.literal(MessageTypes.Register)),
|
||||||
expiresAt: z.string(),
|
expiresAt: z.string(),
|
||||||
phone: z.string(),
|
phone: z.string(),
|
||||||
});
|
});
|
||||||
|
@ -22,7 +25,7 @@ export type SmsSessionStorage = z.infer<typeof smsSessionStorageGuard>;
|
||||||
export const smsSessionResultGuard = z.object({ verification: smsSessionStorageGuard });
|
export const smsSessionResultGuard = z.object({ verification: smsSessionStorageGuard });
|
||||||
|
|
||||||
const emailSessionStorageGuard = z.object({
|
const emailSessionStorageGuard = z.object({
|
||||||
flow: z.literal(PasscodeType.SignIn).or(z.literal(PasscodeType.Register)),
|
flow: z.literal(MessageTypes.SignIn).or(z.literal(MessageTypes.Register)),
|
||||||
expiresAt: z.string(),
|
expiresAt: z.string(),
|
||||||
email: z.string(),
|
email: z.string(),
|
||||||
});
|
});
|
||||||
|
@ -34,7 +37,7 @@ export const emailSessionResultGuard = z.object({
|
||||||
});
|
});
|
||||||
|
|
||||||
const forgotPasswordSessionStorageGuard = z.object({
|
const forgotPasswordSessionStorageGuard = z.object({
|
||||||
flow: z.literal(PasscodeType.ForgotPassword),
|
flow: z.literal(MessageTypes.ForgotPassword),
|
||||||
expiresAt: z.string(),
|
expiresAt: z.string(),
|
||||||
userId: z.string(),
|
userId: z.string(),
|
||||||
});
|
});
|
||||||
|
@ -46,7 +49,7 @@ export const forgotPasswordSessionResultGuard = z.object({
|
||||||
});
|
});
|
||||||
|
|
||||||
const continueEmailSessionStorageGuard = z.object({
|
const continueEmailSessionStorageGuard = z.object({
|
||||||
flow: z.literal(PasscodeType.Continue),
|
flow: z.literal(MessageTypes.Continue),
|
||||||
expiresAt: z.string(),
|
expiresAt: z.string(),
|
||||||
email: z.string(),
|
email: z.string(),
|
||||||
});
|
});
|
||||||
|
@ -58,7 +61,7 @@ export const continueEmailSessionResultGuard = z.object({
|
||||||
});
|
});
|
||||||
|
|
||||||
const continueSmsSessionStorageGuard = z.object({
|
const continueSmsSessionStorageGuard = z.object({
|
||||||
flow: z.literal(PasscodeType.Continue),
|
flow: z.literal(MessageTypes.Continue),
|
||||||
expiresAt: z.string(),
|
expiresAt: z.string(),
|
||||||
phone: z.string(),
|
phone: z.string(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import type { PasscodeType, SignInExperience, User } from '@logto/schemas';
|
import type { MessageTypes } from '@logto/connector-kit';
|
||||||
|
import type { SignInExperience, User } from '@logto/schemas';
|
||||||
import { SignInIdentifier } from '@logto/schemas';
|
import { SignInIdentifier } from '@logto/schemas';
|
||||||
import type { LogPayload, LogType } from '@logto/schemas/lib/types/log-legacy.js';
|
import type { LogPayload, LogType } from '@logto/schemas/lib/types/log-legacy.js';
|
||||||
import { logTypeGuard } from '@logto/schemas/lib/types/log-legacy.js';
|
import { logTypeGuard } from '@logto/schemas/lib/types/log-legacy.js';
|
||||||
|
@ -36,7 +37,7 @@ export const getRoutePrefix = (
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getPasswordlessRelatedLogType = (
|
export const getPasswordlessRelatedLogType = (
|
||||||
flow: PasscodeType,
|
flow: MessageTypes,
|
||||||
method: Method,
|
method: Method,
|
||||||
operation?: Operation
|
operation?: Operation
|
||||||
): LogType => {
|
): LogType => {
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@jest/types": "^29.1.2",
|
"@jest/types": "^29.1.2",
|
||||||
|
"@logto/connector-kit": "workspace:1.0.0-beta.30",
|
||||||
"@logto/js": "1.0.0-beta.14",
|
"@logto/js": "1.0.0-beta.14",
|
||||||
"@logto/node": "1.0.0-beta.14",
|
"@logto/node": "1.0.0-beta.14",
|
||||||
"@logto/schemas": "workspace:*",
|
"@logto/schemas": "workspace:*",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { PasscodeType } from '@logto/schemas';
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
|
|
||||||
import api from './api.js';
|
import api from './api.js';
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ export const sendRegisterUserWithEmailPasscode = (email: string, interactionCook
|
||||||
},
|
},
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ export const verifyRegisterUserWithEmailPasscode = (
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
code,
|
code,
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json<RedirectResponse>();
|
.json<RedirectResponse>();
|
||||||
|
@ -107,7 +107,7 @@ export const sendSignInUserWithEmailPasscode = (email: string, interactionCookie
|
||||||
},
|
},
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ export const verifySignInUserWithEmailPasscode = (
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
code,
|
code,
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json<RedirectResponse>();
|
.json<RedirectResponse>();
|
||||||
|
@ -145,7 +145,7 @@ export const sendRegisterUserWithSmsPasscode = (phone: string, interactionCookie
|
||||||
},
|
},
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ export const verifyRegisterUserWithSmsPasscode = (
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
code,
|
code,
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json<RedirectResponse>();
|
.json<RedirectResponse>();
|
||||||
|
@ -183,7 +183,7 @@ export const sendSignInUserWithSmsPasscode = (phone: string, interactionCookie:
|
||||||
},
|
},
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ export const verifySignInUserWithSmsPasscode = (
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
code,
|
code,
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json<RedirectResponse>();
|
.json<RedirectResponse>();
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { sql } from 'slonik';
|
||||||
|
|
||||||
|
import type { AlterationScript } from '../lib/types/alteration.js';
|
||||||
|
|
||||||
|
const alteration: AlterationScript = {
|
||||||
|
up: async (pool) => {
|
||||||
|
await pool.query(sql`
|
||||||
|
alter table passcodes alter column "type" type varchar(32);
|
||||||
|
drop type passcode_type;
|
||||||
|
create index passcodes__interaction_jti_type
|
||||||
|
on passcodes (
|
||||||
|
interaction_jti,
|
||||||
|
type
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
},
|
||||||
|
down: async (pool) => {
|
||||||
|
// We don't handle potential type casting failures here as they need to be handled manually
|
||||||
|
await pool.query(sql`
|
||||||
|
create type passcode_type as enum ('SignIn', 'Register', 'ForgotPassword', 'Continue');
|
||||||
|
drop index passcodes__interaction_jti_type;
|
||||||
|
alter table passcodes alter column "type" type passcode_type using type::passcode_type;
|
||||||
|
`);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default alteration;
|
|
@ -1,14 +1,18 @@
|
||||||
create type passcode_type as enum ('SignIn', 'Register', 'ForgotPassword', 'Continue');
|
|
||||||
|
|
||||||
create table passcodes (
|
create table passcodes (
|
||||||
id varchar(21) not null,
|
id varchar(21) not null,
|
||||||
interaction_jti varchar(128) not null,
|
interaction_jti varchar(128) not null,
|
||||||
phone varchar(32),
|
phone varchar(32),
|
||||||
email varchar(128),
|
email varchar(128),
|
||||||
type passcode_type not null,
|
type varchar(32) not null,
|
||||||
code varchar(6) not null,
|
code varchar(6) not null,
|
||||||
consumed boolean not null default FALSE,
|
consumed boolean not null default FALSE,
|
||||||
try_count int2 not null default 0,
|
try_count int2 not null default 0,
|
||||||
created_at timestamptz not null default(now()),
|
created_at timestamptz not null default(now()),
|
||||||
primary key (id)
|
primary key (id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
create index passcodes__interaction_jti_type
|
||||||
|
on passcodes (
|
||||||
|
interaction_jti,
|
||||||
|
type
|
||||||
|
);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@logto/connector-kit": "workspace:*",
|
||||||
"@logto/core-kit": "workspace:*",
|
"@logto/core-kit": "workspace:*",
|
||||||
"@logto/language-kit": "workspace:*",
|
"@logto/language-kit": "workspace:*",
|
||||||
"@logto/phrases": "workspace:*",
|
"@logto/phrases": "workspace:*",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { PasscodeType } from '@logto/schemas';
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
import ky from 'ky';
|
import ky from 'ky';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -75,7 +75,7 @@ describe('continue API', () => {
|
||||||
expect(ky.post).toBeCalledWith('/api/session/passwordless/email/send', {
|
expect(ky.post).toBeCalledWith('/api/session/passwordless/email/send', {
|
||||||
json: {
|
json: {
|
||||||
email: 'email',
|
email: 'email',
|
||||||
flow: PasscodeType.Continue,
|
flow: MessageTypes.Continue,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -86,7 +86,7 @@ describe('continue API', () => {
|
||||||
expect(ky.post).toBeCalledWith('/api/session/passwordless/sms/send', {
|
expect(ky.post).toBeCalledWith('/api/session/passwordless/sms/send', {
|
||||||
json: {
|
json: {
|
||||||
phone: '111111',
|
phone: '111111',
|
||||||
flow: PasscodeType.Continue,
|
flow: MessageTypes.Continue,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -98,7 +98,7 @@ describe('continue API', () => {
|
||||||
json: {
|
json: {
|
||||||
email: 'email',
|
email: 'email',
|
||||||
code: 'passcode',
|
code: 'passcode',
|
||||||
flow: PasscodeType.Continue,
|
flow: MessageTypes.Continue,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -110,7 +110,7 @@ describe('continue API', () => {
|
||||||
json: {
|
json: {
|
||||||
phone: 'phone',
|
phone: 'phone',
|
||||||
code: 'passcode',
|
code: 'passcode',
|
||||||
flow: PasscodeType.Continue,
|
flow: MessageTypes.Continue,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { PasscodeType } from '@logto/schemas';
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
|
|
||||||
import api from './api';
|
import api from './api';
|
||||||
import { bindSocialAccount } from './social';
|
import { bindSocialAccount } from './social';
|
||||||
|
@ -31,7 +31,7 @@ export const sendContinueSetEmailPasscode = async (email: string) => {
|
||||||
.post(`${passwordlessApiPrefix}/email/send`, {
|
.post(`${passwordlessApiPrefix}/email/send`, {
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
flow: PasscodeType.Continue,
|
flow: MessageTypes.Continue,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json();
|
.json();
|
||||||
|
@ -44,7 +44,7 @@ export const sendContinueSetPhonePasscode = async (phone: string) => {
|
||||||
.post(`${passwordlessApiPrefix}/sms/send`, {
|
.post(`${passwordlessApiPrefix}/sms/send`, {
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
flow: PasscodeType.Continue,
|
flow: MessageTypes.Continue,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json();
|
.json();
|
||||||
|
@ -55,7 +55,7 @@ export const sendContinueSetPhonePasscode = async (phone: string) => {
|
||||||
export const verifyContinueSetEmailPasscode = async (email: string, code: string) => {
|
export const verifyContinueSetEmailPasscode = async (email: string, code: string) => {
|
||||||
await api
|
await api
|
||||||
.post(`${passwordlessApiPrefix}/email/verify`, {
|
.post(`${passwordlessApiPrefix}/email/verify`, {
|
||||||
json: { email, code, flow: PasscodeType.Continue },
|
json: { email, code, flow: MessageTypes.Continue },
|
||||||
})
|
})
|
||||||
.json();
|
.json();
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ export const verifyContinueSetEmailPasscode = async (email: string, code: string
|
||||||
export const verifyContinueSetSmsPasscode = async (phone: string, code: string) => {
|
export const verifyContinueSetSmsPasscode = async (phone: string, code: string) => {
|
||||||
await api
|
await api
|
||||||
.post(`${passwordlessApiPrefix}/sms/verify`, {
|
.post(`${passwordlessApiPrefix}/sms/verify`, {
|
||||||
json: { phone, code, flow: PasscodeType.Continue },
|
json: { phone, code, flow: MessageTypes.Continue },
|
||||||
})
|
})
|
||||||
.json();
|
.json();
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { PasscodeType } from '@logto/schemas';
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
|
|
||||||
import api from './api';
|
import api from './api';
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ export const sendForgotPasswordSmsPasscode = async (phone: string) => {
|
||||||
.post('/api/session/passwordless/sms/send', {
|
.post('/api/session/passwordless/sms/send', {
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json();
|
.json();
|
||||||
|
@ -27,7 +27,7 @@ export const verifyForgotPasswordSmsPasscode = async (phone: string, code: strin
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
code,
|
code,
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json();
|
.json();
|
||||||
|
@ -40,7 +40,7 @@ export const sendForgotPasswordEmailPasscode = async (email: string) => {
|
||||||
.post('/api/session/passwordless/email/send', {
|
.post('/api/session/passwordless/email/send', {
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json();
|
.json();
|
||||||
|
@ -54,7 +54,7 @@ export const verifyForgotPasswordEmailPasscode = async (email: string, code: str
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
code,
|
code,
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json();
|
.json();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { PasscodeType } from '@logto/schemas';
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
import ky from 'ky';
|
import ky from 'ky';
|
||||||
|
|
||||||
import { consent } from './consent';
|
import { consent } from './consent';
|
||||||
|
@ -188,7 +188,7 @@ describe('api', () => {
|
||||||
expect(ky.post).toBeCalledWith('/api/session/passwordless/sms/send', {
|
expect(ky.post).toBeCalledWith('/api/session/passwordless/sms/send', {
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -206,7 +206,7 @@ describe('api', () => {
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
code,
|
code,
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -216,7 +216,7 @@ describe('api', () => {
|
||||||
expect(ky.post).toBeCalledWith('/api/session/passwordless/email/send', {
|
expect(ky.post).toBeCalledWith('/api/session/passwordless/email/send', {
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -234,7 +234,7 @@ describe('api', () => {
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
code,
|
code,
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -278,7 +278,7 @@ describe('api', () => {
|
||||||
expect(ky.post).toBeCalledWith('/api/session/passwordless/sms/send', {
|
expect(ky.post).toBeCalledWith('/api/session/passwordless/sms/send', {
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -289,7 +289,7 @@ describe('api', () => {
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
code,
|
code,
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -299,7 +299,7 @@ describe('api', () => {
|
||||||
expect(ky.post).toBeCalledWith('/api/session/passwordless/email/send', {
|
expect(ky.post).toBeCalledWith('/api/session/passwordless/email/send', {
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -310,7 +310,7 @@ describe('api', () => {
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
code,
|
code,
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -320,7 +320,7 @@ describe('api', () => {
|
||||||
expect(ky.post).toBeCalledWith('/api/session/passwordless/sms/send', {
|
expect(ky.post).toBeCalledWith('/api/session/passwordless/sms/send', {
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -331,7 +331,7 @@ describe('api', () => {
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
code,
|
code,
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -341,7 +341,7 @@ describe('api', () => {
|
||||||
expect(ky.post).toBeCalledWith('/api/session/passwordless/email/send', {
|
expect(ky.post).toBeCalledWith('/api/session/passwordless/email/send', {
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -352,7 +352,7 @@ describe('api', () => {
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
code,
|
code,
|
||||||
flow: PasscodeType.ForgotPassword,
|
flow: MessageTypes.ForgotPassword,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { PasscodeType } from '@logto/schemas';
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
|
|
||||||
import api from './api';
|
import api from './api';
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ export const sendRegisterSmsPasscode = async (phone: string) => {
|
||||||
.post(`${apiPrefix}/passwordless/sms/send`, {
|
.post(`${apiPrefix}/passwordless/sms/send`, {
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json();
|
.json();
|
||||||
|
@ -44,7 +44,7 @@ export const verifyRegisterSmsPasscode = async (phone: string, code: string) =>
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
code,
|
code,
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json<Response>();
|
.json<Response>();
|
||||||
|
@ -54,7 +54,7 @@ export const sendRegisterEmailPasscode = async (email: string) => {
|
||||||
.post(`${apiPrefix}/passwordless/email/send`, {
|
.post(`${apiPrefix}/passwordless/email/send`, {
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json();
|
.json();
|
||||||
|
@ -68,7 +68,7 @@ export const verifyRegisterEmailPasscode = async (email: string, code: string) =
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
code,
|
code,
|
||||||
flow: PasscodeType.Register,
|
flow: MessageTypes.Register,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json<Response>();
|
.json<Response>();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { PasscodeType } from '@logto/schemas';
|
import { MessageTypes } from '@logto/connector-kit';
|
||||||
|
|
||||||
import api from './api';
|
import api from './api';
|
||||||
import { bindSocialAccount } from './social';
|
import { bindSocialAccount } from './social';
|
||||||
|
@ -97,7 +97,7 @@ export const sendSignInSmsPasscode = async (phone: string) => {
|
||||||
.post(`${apiPrefix}/passwordless/sms/send`, {
|
.post(`${apiPrefix}/passwordless/sms/send`, {
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json();
|
.json();
|
||||||
|
@ -115,7 +115,7 @@ export const verifySignInSmsPasscode = async (
|
||||||
json: {
|
json: {
|
||||||
phone,
|
phone,
|
||||||
code,
|
code,
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json<Response>();
|
.json<Response>();
|
||||||
|
@ -132,7 +132,7 @@ export const sendSignInEmailPasscode = async (email: string) => {
|
||||||
.post(`${apiPrefix}/passwordless/email/send`, {
|
.post(`${apiPrefix}/passwordless/email/send`, {
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json();
|
.json();
|
||||||
|
@ -150,7 +150,7 @@ export const verifySignInEmailPasscode = async (
|
||||||
json: {
|
json: {
|
||||||
email,
|
email,
|
||||||
code,
|
code,
|
||||||
flow: PasscodeType.SignIn,
|
flow: MessageTypes.SignIn,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json<Response>();
|
.json<Response>();
|
||||||
|
|
|
@ -460,6 +460,7 @@ importers:
|
||||||
packages/integration-tests:
|
packages/integration-tests:
|
||||||
specifiers:
|
specifiers:
|
||||||
'@jest/types': ^29.1.2
|
'@jest/types': ^29.1.2
|
||||||
|
'@logto/connector-kit': workspace:1.0.0-beta.30
|
||||||
'@logto/js': 1.0.0-beta.14
|
'@logto/js': 1.0.0-beta.14
|
||||||
'@logto/node': 1.0.0-beta.14
|
'@logto/node': 1.0.0-beta.14
|
||||||
'@logto/schemas': workspace:*
|
'@logto/schemas': workspace:*
|
||||||
|
@ -487,6 +488,7 @@ importers:
|
||||||
'@withtyped/server': 0.3.1
|
'@withtyped/server': 0.3.1
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@jest/types': 29.1.2
|
'@jest/types': 29.1.2
|
||||||
|
'@logto/connector-kit': link:../toolkit/connector-kit
|
||||||
'@logto/js': 1.0.0-beta.14
|
'@logto/js': 1.0.0-beta.14
|
||||||
'@logto/node': 1.0.0-beta.14
|
'@logto/node': 1.0.0-beta.14
|
||||||
'@logto/schemas': link:../schemas
|
'@logto/schemas': link:../schemas
|
||||||
|
@ -763,6 +765,7 @@ importers:
|
||||||
|
|
||||||
packages/ui:
|
packages/ui:
|
||||||
specifiers:
|
specifiers:
|
||||||
|
'@logto/connector-kit': workspace:*
|
||||||
'@logto/core-kit': workspace:*
|
'@logto/core-kit': workspace:*
|
||||||
'@logto/language-kit': workspace:*
|
'@logto/language-kit': workspace:*
|
||||||
'@logto/phrases': workspace:*
|
'@logto/phrases': workspace:*
|
||||||
|
@ -817,6 +820,7 @@ importers:
|
||||||
use-debounced-loader: ^0.1.1
|
use-debounced-loader: ^0.1.1
|
||||||
zod: ^3.20.2
|
zod: ^3.20.2
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@logto/connector-kit': link:../toolkit/connector-kit
|
||||||
'@logto/core-kit': link:../toolkit/core-kit
|
'@logto/core-kit': link:../toolkit/core-kit
|
||||||
'@logto/language-kit': link:../toolkit/language-kit
|
'@logto/language-kit': link:../toolkit/language-kit
|
||||||
'@logto/phrases': link:../phrases
|
'@logto/phrases': link:../phrases
|
||||||
|
|
Loading…
Reference in a new issue