From 7699296f11ab52dc7c5c1bd337601cc82bd118d5 Mon Sep 17 00:00:00 2001 From: EYHN Date: Mon, 28 Oct 2024 18:06:52 +0000 Subject: [PATCH] feat(core): captcha service (#8616) --- .../frontend/apps/electron/renderer/app.tsx | 10 ++ .../affine/auth/after-sign-in-send-email.tsx | 36 ++--- .../affine/auth/after-sign-up-send-email.tsx | 34 +++-- .../affine/auth/sign-in-with-password.tsx | 59 +++++---- .../src/components/affine/auth/sign-in.tsx | 60 +++++---- .../components/affine/auth/use-captcha.tsx | 125 ++++-------------- .../frontend/core/src/modules/cloud/index.ts | 11 ++ .../src/modules/cloud/provider/validator.ts | 12 ++ .../core/src/modules/cloud/services/auth.ts | 10 +- .../src/modules/cloud/services/captcha.ts | 75 +++++++++++ .../i18n/src/i18n-completenesses.json | 2 +- tests/kit/utils/cloud.ts | 2 +- 12 files changed, 246 insertions(+), 190 deletions(-) create mode 100644 packages/frontend/core/src/modules/cloud/provider/validator.ts create mode 100644 packages/frontend/core/src/modules/cloud/services/captcha.ts diff --git a/packages/frontend/apps/electron/renderer/app.tsx b/packages/frontend/apps/electron/renderer/app.tsx index 3971c39256..bc4dce229e 100644 --- a/packages/frontend/apps/electron/renderer/app.tsx +++ b/packages/frontend/apps/electron/renderer/app.tsx @@ -6,6 +6,7 @@ import { Telemetry } from '@affine/core/components/telemetry'; import { router } from '@affine/core/desktop/router'; import { configureCommonModules } from '@affine/core/modules'; import { configureAppTabsHeaderModule } from '@affine/core/modules/app-tabs-header'; +import { ValidatorProvider } from '@affine/core/modules/cloud'; import { I18nProvider } from '@affine/core/modules/i18n'; import { configureElectronStateStorageImpls } from '@affine/core/modules/storage'; import { CustomThemeModifier } from '@affine/core/modules/theme-editor'; @@ -75,6 +76,15 @@ framework.impl(ClientSchemaProvider, { return appInfo?.schema; }, }); +framework.impl(ValidatorProvider, { + async validate(_challenge, resource) { + const token = await apis?.ui?.getChallengeResponse(resource); + if (!token) { + throw new Error('Challenge failed'); + } + return token; + }, +}); const frameworkProvider = framework.provider(); // setup application lifecycle events, and emit application start event diff --git a/packages/frontend/core/src/components/affine/auth/after-sign-in-send-email.tsx b/packages/frontend/core/src/components/affine/auth/after-sign-in-send-email.tsx index d2e4b68d41..91d931660a 100644 --- a/packages/frontend/core/src/components/affine/auth/after-sign-in-send-email.tsx +++ b/packages/frontend/core/src/components/affine/auth/after-sign-in-send-email.tsx @@ -7,14 +7,14 @@ import { } from '@affine/component/auth-components'; import { Button } from '@affine/component/ui/button'; import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks'; -import { AuthService } from '@affine/core/modules/cloud'; +import { AuthService, CaptchaService } from '@affine/core/modules/cloud'; import { Trans, useI18n } from '@affine/i18n'; -import { useService } from '@toeverything/infra'; +import { useLiveData, useService } from '@toeverything/infra'; import { useCallback, useEffect, useState } from 'react'; import type { AuthPanelProps } from './index'; import * as style from './style.css'; -import { Captcha, useCaptcha } from './use-captcha'; +import { Captcha } from './use-captcha'; export const AfterSignInSendEmail = ({ setAuthData: setAuth, @@ -37,21 +37,23 @@ export const AfterSignInSendEmail = ({ const t = useI18n(); const authService = useService(AuthService); + const captchaService = useService(CaptchaService); - const [verifyToken, challenge] = useCaptcha(); + const verifyToken = useLiveData(captchaService.verifyToken$); + const needCaptcha = useLiveData(captchaService.needCaptcha$); + const challenge = useLiveData(captchaService.challenge$); const onResendClick = useAsyncCallback(async () => { setIsSending(true); try { - if (verifyToken) { - setResendCountDown(60); - await authService.sendEmailMagicLink( - email, - verifyToken, - challenge, - redirectUrl - ); - } + setResendCountDown(60); + captchaService.revalidate(); + await authService.sendEmailMagicLink( + email, + verifyToken, + challenge, + redirectUrl + ); } catch (err) { console.error(err); notify.error({ @@ -59,7 +61,7 @@ export const AfterSignInSendEmail = ({ }); } setIsSending(false); - }, [authService, challenge, email, redirectUrl, verifyToken]); + }, [authService, captchaService, challenge, email, redirectUrl, verifyToken]); const onSignInWithPasswordClick = useCallback(() => { setAuth({ state: 'signInWithPassword' }); @@ -89,8 +91,10 @@ export const AfterSignInSendEmail = ({ <>