mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
fix(frontend): more turnstile experiments
This commit is contained in:
@@ -11,7 +11,7 @@ import { Form, FormField } from "@/components/__legacy__/ui/form";
|
||||
import { getBehaveAs } from "@/lib/utils";
|
||||
import { LoadingLogin } from "./components/LoadingLogin";
|
||||
import { useLoginPage } from "./useLoginPage";
|
||||
import { Turnstile2 } from "@/components/auth/Turnstile2";
|
||||
import Turnstile from "@/components/auth/Turnstile";
|
||||
|
||||
export default function LoginPage() {
|
||||
const {
|
||||
@@ -29,7 +29,8 @@ export default function LoginPage() {
|
||||
handleProviderLogin,
|
||||
handleCloseNotAllowedModal,
|
||||
handleCaptchaVerify,
|
||||
handleCaptchaReady,
|
||||
setCaptchaWidgetId,
|
||||
captchaResetNonce,
|
||||
} = useLoginPage();
|
||||
|
||||
if (isUserLoading || isLoggedIn) {
|
||||
@@ -87,10 +88,18 @@ export default function LoginPage() {
|
||||
/>
|
||||
|
||||
<div className="flex items-center justify-center">
|
||||
<Turnstile2
|
||||
onVerified={handleCaptchaVerify}
|
||||
onReady={handleCaptchaReady}
|
||||
visible={!captchaToken}
|
||||
<Turnstile
|
||||
siteKey={
|
||||
process.env.NEXT_PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY || ""
|
||||
}
|
||||
onVerify={handleCaptchaVerify}
|
||||
shouldRender={Boolean(
|
||||
isCloudEnv &&
|
||||
!captchaToken &&
|
||||
process.env.NEXT_PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY,
|
||||
)}
|
||||
setWidgetId={setCaptchaWidgetId}
|
||||
resetSignal={captchaResetNonce}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useForm } from "react-hook-form";
|
||||
import z from "zod";
|
||||
import { login, providerLogin } from "./actions";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { TurnstileInstance } from "@marsidev/react-turnstile";
|
||||
// Captcha integration handled via widget ID reset in page
|
||||
|
||||
export function useLoginPage() {
|
||||
const { supabase, user, isUserLoading } = useSupabase();
|
||||
@@ -17,7 +17,8 @@ export function useLoginPage() {
|
||||
const { toast } = useToast();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [captchaToken, setCaptchaToken] = useState<string | null>(null);
|
||||
const [captchaRef, setCaptchaRef] = useState<TurnstileInstance | null>(null);
|
||||
const [captchaWidgetId, setCaptchaWidgetId] = useState<string | null>(null);
|
||||
const [captchaResetNonce, setCaptchaResetNonce] = useState(0);
|
||||
const [isGoogleLoading, setIsGoogleLoading] = useState(false);
|
||||
const [showNotAllowedModal, setShowNotAllowedModal] = useState(false);
|
||||
const isCloudEnv = getBehaveAs() === BehaveAs.CLOUD;
|
||||
@@ -54,7 +55,9 @@ export function useLoginPage() {
|
||||
setFeedback(null);
|
||||
} catch (error) {
|
||||
setCaptchaToken(null);
|
||||
captchaRef?.reset();
|
||||
if (captchaWidgetId && window?.turnstile)
|
||||
window.turnstile.reset(captchaWidgetId);
|
||||
setCaptchaResetNonce((n) => n + 1);
|
||||
setIsGoogleLoading(false);
|
||||
const errorString = JSON.stringify(error);
|
||||
if (errorString.includes("not_allowed")) {
|
||||
@@ -97,7 +100,9 @@ export function useLoginPage() {
|
||||
});
|
||||
|
||||
setCaptchaToken(null);
|
||||
captchaRef?.reset();
|
||||
if (captchaWidgetId && window?.turnstile)
|
||||
window.turnstile.reset(captchaWidgetId);
|
||||
setCaptchaResetNonce((n) => n + 1);
|
||||
return;
|
||||
}
|
||||
setFeedback(null);
|
||||
@@ -107,10 +112,6 @@ export function useLoginPage() {
|
||||
setCaptchaToken(token);
|
||||
}
|
||||
|
||||
function handleCaptchaReady(ref: TurnstileInstance) {
|
||||
if (!captchaRef) setCaptchaRef(ref);
|
||||
}
|
||||
|
||||
return {
|
||||
form,
|
||||
feedback,
|
||||
@@ -126,6 +127,7 @@ export function useLoginPage() {
|
||||
handleProviderLogin,
|
||||
handleCloseNotAllowedModal: () => setShowNotAllowedModal(false),
|
||||
handleCaptchaVerify,
|
||||
handleCaptchaReady,
|
||||
setCaptchaWidgetId,
|
||||
captchaResetNonce,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ export interface TurnstileProps {
|
||||
id?: string;
|
||||
shouldRender?: boolean;
|
||||
setWidgetId?: (id: string | null) => void;
|
||||
// Changing this value will trigger a widget reset safely inside the component
|
||||
resetSignal?: number | string | boolean;
|
||||
}
|
||||
|
||||
export function Turnstile({
|
||||
@@ -25,6 +27,7 @@ export function Turnstile({
|
||||
id = "cf-turnstile",
|
||||
shouldRender = true,
|
||||
setWidgetId,
|
||||
resetSignal,
|
||||
}: TurnstileProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const widgetIdRef = useRef<string | null>(null);
|
||||
@@ -57,16 +60,20 @@ export function Turnstile({
|
||||
|
||||
document.head.appendChild(script);
|
||||
|
||||
return () => {
|
||||
if (document.head.contains(script)) {
|
||||
document.head.removeChild(script);
|
||||
}
|
||||
};
|
||||
// Do not remove the script on unmount to avoid race conditions with
|
||||
// other potential widgets or future mounts.
|
||||
return () => {};
|
||||
}, [onError, shouldRender]);
|
||||
|
||||
// Initialize and render the widget when script is loaded
|
||||
useEffect(() => {
|
||||
if (!loaded || !containerRef.current || !window.turnstile || !shouldRender)
|
||||
if (
|
||||
!loaded ||
|
||||
!containerRef.current ||
|
||||
!window.turnstile ||
|
||||
!shouldRender ||
|
||||
!siteKey
|
||||
)
|
||||
return;
|
||||
|
||||
// Reset any existing widget
|
||||
@@ -123,13 +130,20 @@ export function Turnstile({
|
||||
|
||||
// Method to reset the widget manually
|
||||
useEffect(() => {
|
||||
if (loaded && widgetIdRef.current && window.turnstile && shouldRender) {
|
||||
if (
|
||||
loaded &&
|
||||
widgetIdRef.current &&
|
||||
window.turnstile &&
|
||||
shouldRender &&
|
||||
siteKey
|
||||
) {
|
||||
window.turnstile.reset(widgetIdRef.current);
|
||||
}
|
||||
}, [loaded, shouldRender]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [loaded, shouldRender, resetSignal, siteKey]);
|
||||
|
||||
// If shouldRender is false, don't render anything
|
||||
if (!shouldRender) {
|
||||
if (!shouldRender || !siteKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -145,7 +159,6 @@ export function Turnstile({
|
||||
// Add TypeScript interface to Window to include turnstile property
|
||||
declare global {
|
||||
interface Window {
|
||||
// @ts-expect-error - turnstile is not defined in the window object
|
||||
turnstile?: {
|
||||
render: (
|
||||
container: HTMLElement,
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { BehaveAs, getBehaveAs } from "@/lib/utils";
|
||||
import { Turnstile, TurnstileInstance } from "@marsidev/react-turnstile";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
const TURNSTILE_SITE_KEY =
|
||||
process.env.NEXT_PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY || "";
|
||||
|
||||
type Props = {
|
||||
onVerified: (token: string) => void;
|
||||
onReady: (ref: TurnstileInstance) => void;
|
||||
visible: boolean;
|
||||
};
|
||||
|
||||
export function Turnstile2(props: Props) {
|
||||
const captchaRef = useRef<TurnstileInstance>(null);
|
||||
const behaveAs = getBehaveAs();
|
||||
|
||||
useEffect(() => {
|
||||
if (captchaRef.current) {
|
||||
props.onReady(captchaRef.current);
|
||||
}
|
||||
}, [captchaRef]);
|
||||
|
||||
function handleCaptchaVerify(token: string) {
|
||||
props.onVerified(token);
|
||||
}
|
||||
|
||||
if (behaveAs !== BehaveAs.CLOUD) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!TURNSTILE_SITE_KEY) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={props.visible ? "" : "hidden"}>
|
||||
<Turnstile
|
||||
ref={captchaRef}
|
||||
siteKey={TURNSTILE_SITE_KEY}
|
||||
onSuccess={handleCaptchaVerify}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user