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 = ({
<>