From 50170cfcbfd35951889856f30e2d4d65fe819142 Mon Sep 17 00:00:00 2001 From: wangsijie Date: Thu, 27 Oct 2022 11:50:48 +0800 Subject: [PATCH] feat(core): enable forgot password check (#2257) --- .../core/src/__mocks__/sign-in-experience.ts | 2 +- .../src/routes/sign-in-experience.test.ts | 24 +++++++++++++++++-- .../core/src/routes/sign-in-experience.ts | 17 ++++++++++++- .../schemas/src/seeds/sign-in-experience.ts | 1 + packages/ui/src/__mocks__/logto.tsx | 4 ++-- 5 files changed, 42 insertions(+), 6 deletions(-) diff --git a/packages/core/src/__mocks__/sign-in-experience.ts b/packages/core/src/__mocks__/sign-in-experience.ts index 6b3fc5c3b..8bfe31cdf 100644 --- a/packages/core/src/__mocks__/sign-in-experience.ts +++ b/packages/core/src/__mocks__/sign-in-experience.ts @@ -70,7 +70,7 @@ export const mockSignInExperience: SignInExperience = { }, socialSignInConnectorTargets: ['github', 'facebook', 'wechat'], signInMode: SignInMode.SignInAndRegister, - forgotPassword: true, + forgotPassword: false, }; export const mockColor: Color = { diff --git a/packages/core/src/routes/sign-in-experience.test.ts b/packages/core/src/routes/sign-in-experience.test.ts index 7b78f3022..65db72106 100644 --- a/packages/core/src/routes/sign-in-experience.test.ts +++ b/packages/core/src/routes/sign-in-experience.test.ts @@ -1,5 +1,5 @@ import type { SignInExperience, CreateSignInExperience, TermsOfUse } from '@logto/schemas'; -import { SignInMethodState } from '@logto/schemas'; +import { ConnectorType, SignInMethodState } from '@logto/schemas'; import { mockFacebookConnector, @@ -13,6 +13,7 @@ import { mockSignUp, mockSignIn, mockLanguageInfo, + mockAliyunSmsConnector, } from '@/__mocks__'; import * as signInExpLib from '@/lib/sign-in-experience'; import * as signInLib from '@/lib/sign-in-experience/sign-in'; @@ -27,6 +28,7 @@ const logtoConnectors = [ mockGithubConnector, mockGoogleConnector, mockWechatConnector, + mockAliyunSmsConnector, ]; const getLogtoConnectors = jest.fn(async () => logtoConnectors); @@ -106,6 +108,18 @@ describe('PATCH /sign-in-exp', () => { }); }); + it('should not allow forgot password without enabled passwordless connector', async () => { + getLogtoConnectors.mockResolvedValueOnce( + logtoConnectors.filter( + ({ type }) => type !== ConnectorType.Sms && type !== ConnectorType.Email + ) + ); + const response = await signInExperienceRequester + .patch('/sign-in-exp') + .send({ forgotPassword: true }); + expect(response.status).toEqual(400); + }); + it('should succeed to update when the input is valid', async () => { const termsOfUse: TermsOfUse = { enabled: false }; const socialSignInConnectorTargets = ['github', 'facebook', 'wechat']; @@ -128,7 +142,12 @@ describe('PATCH /sign-in-exp', () => { signIn: mockSignIn, forgotPassword: true, }); - const connectors = [mockFacebookConnector, mockGithubConnector, mockWechatConnector]; + const connectors = [ + mockFacebookConnector, + mockGithubConnector, + mockWechatConnector, + mockAliyunSmsConnector, + ]; expect(validateBranding).toHaveBeenCalledWith(mockBranding); expect(validateLanguageInfo).toHaveBeenCalledWith(mockLanguageInfo); @@ -151,6 +170,7 @@ describe('PATCH /sign-in-exp', () => { signInMethods: mockSignInMethods, socialSignInConnectorTargets, signIn: mockSignIn, + forgotPassword: true, }, }); }); diff --git a/packages/core/src/routes/sign-in-experience.ts b/packages/core/src/routes/sign-in-experience.ts index 8899eb4c0..f8df41f48 100644 --- a/packages/core/src/routes/sign-in-experience.ts +++ b/packages/core/src/routes/sign-in-experience.ts @@ -1,6 +1,7 @@ import { ConnectorType, SignInExperiences } from '@logto/schemas'; import { getLogtoConnectors } from '@/connectors'; +import RequestError from '@/errors/RequestError'; import { validateBranding, validateLanguageInfo, @@ -15,6 +16,7 @@ import { findDefaultSignInExperience, updateDefaultSignInExperience, } from '@/queries/sign-in-experience'; +import assertThat from '@/utils/assert-that'; import type { AuthedRouter } from './types'; @@ -37,7 +39,8 @@ export default function signInExperiencesRoutes(router: /* eslint-disable complexity */ async (ctx, next) => { const { socialSignInConnectorTargets, ...rest } = ctx.guard.body; - const { branding, languageInfo, termsOfUse, signInMethods, signUp, signIn } = rest; + const { branding, languageInfo, termsOfUse, signInMethods, signUp, signIn, forgotPassword } = + rest; if (branding) { validateBranding(branding); @@ -81,6 +84,18 @@ export default function signInExperiencesRoutes(router: validateSignIn(signIn, signInExperience.signUp, enabledConnectors); } + if (forgotPassword) { + assertThat( + enabledConnectors.some( + ({ type }) => type === ConnectorType.Sms || type === ConnectorType.Email + ), + new RequestError({ + code: 'sign_in_experiences.enabled_connector_not_found', + type: [ConnectorType.Email, ConnectorType.Sms].join(','), + }) + ); + } + // Update socialSignInConnectorTargets only when social sign-in is enabled. const signInExperience = signInMethods && isEnabled(signInMethods.social) diff --git a/packages/schemas/src/seeds/sign-in-experience.ts b/packages/schemas/src/seeds/sign-in-experience.ts index 654b7c601..e1a69f51e 100644 --- a/packages/schemas/src/seeds/sign-in-experience.ts +++ b/packages/schemas/src/seeds/sign-in-experience.ts @@ -65,6 +65,7 @@ export const defaultSignInExperience: Readonly = { }, socialSignInConnectorTargets: [], signInMode: SignInMode.SignInAndRegister, + forgotPassword: false, }; export const adminConsoleSignInExperience: CreateSignInExperience = { diff --git a/packages/ui/src/__mocks__/logto.tsx b/packages/ui/src/__mocks__/logto.tsx index b57a1d2e8..a9fdb8b17 100644 --- a/packages/ui/src/__mocks__/logto.tsx +++ b/packages/ui/src/__mocks__/logto.tsx @@ -216,7 +216,7 @@ export const mockSignInExperience: SignInExperience = { }, socialSignInConnectorTargets: ['BE8QXN0VsrOH7xdWFDJZ9', 'lcXT4o2GSjbV9kg2shZC7'], signInMode: SignInMode.SignInAndRegister, - forgotPassword: true, + forgotPassword: false, }; export const mockSignInExperienceSettings: SignInExperienceSettings = { @@ -228,5 +228,5 @@ export const mockSignInExperienceSettings: SignInExperienceSettings = { secondarySignInMethods: ['email', 'sms', 'social'], socialConnectors, signInMode: SignInMode.SignInAndRegister, - forgotPassword: true, + forgotPassword: false, };