mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-08 13:55:06 -05:00
Compare commits
1 Commits
fix/execut
...
bently/sec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47815a1afb |
@@ -2,6 +2,7 @@
|
||||
import { Button } from "@/components/atoms/Button/Button";
|
||||
import { Input } from "@/components/atoms/Input/Input";
|
||||
import { AuthCard } from "@/components/auth/AuthCard";
|
||||
import { ExpiredLinkMessage } from "@/components/auth/ExpiredLinkMessage";
|
||||
import Turnstile from "@/components/auth/Turnstile";
|
||||
import { Form, FormField } from "@/components/__legacy__/ui/form";
|
||||
import LoadingBox from "@/components/__legacy__/ui/loading";
|
||||
@@ -25,18 +26,41 @@ function ResetPasswordContent() {
|
||||
const [disabled, setDisabled] = useState(false);
|
||||
const [sendEmailCaptchaKey, setSendEmailCaptchaKey] = useState(0);
|
||||
const [changePasswordCaptchaKey, setChangePasswordCaptchaKey] = useState(0);
|
||||
const [showExpiredMessage, setShowExpiredMessage] = useState(false);
|
||||
const [linkSent, setLinkSent] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const error = searchParams.get("error");
|
||||
if (error) {
|
||||
toast({
|
||||
title: "Password Reset Failed",
|
||||
description: error,
|
||||
variant: "destructive",
|
||||
});
|
||||
const errorCode = searchParams.get("error_code");
|
||||
const errorDescription = searchParams.get("error_description");
|
||||
|
||||
if (error || errorCode) {
|
||||
// Check if this is an expired/used link error
|
||||
const isExpiredOrUsed =
|
||||
error === "link_expired" ||
|
||||
errorCode === "otp_expired" ||
|
||||
error === "access_denied" ||
|
||||
errorDescription?.toLowerCase().includes("expired") ||
|
||||
errorDescription?.toLowerCase().includes("invalid");
|
||||
|
||||
if (isExpiredOrUsed) {
|
||||
setShowExpiredMessage(true);
|
||||
} else {
|
||||
// Show toast for other errors
|
||||
const errorMessage =
|
||||
errorDescription || error || "Password reset failed";
|
||||
toast({
|
||||
title: "Password Reset Failed",
|
||||
description: errorMessage,
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
|
||||
// Clear all error params from URL
|
||||
const newUrl = new URL(window.location.href);
|
||||
newUrl.searchParams.delete("error");
|
||||
newUrl.searchParams.delete("error_code");
|
||||
newUrl.searchParams.delete("error_description");
|
||||
router.replace(newUrl.pathname + newUrl.search);
|
||||
}
|
||||
}, [searchParams, toast, router]);
|
||||
@@ -113,6 +137,7 @@ function ResetPasswordContent() {
|
||||
return;
|
||||
}
|
||||
setDisabled(true);
|
||||
setLinkSent(true);
|
||||
toast({
|
||||
title: "Email Sent",
|
||||
description:
|
||||
@@ -123,6 +148,11 @@ function ResetPasswordContent() {
|
||||
[sendEmailForm, sendEmailTurnstile, resetSendEmailCaptcha, toast],
|
||||
);
|
||||
|
||||
const handleSendNewLink = useCallback(() => {
|
||||
// Show the normal form to collect email and CAPTCHA
|
||||
setShowExpiredMessage(false);
|
||||
}, []);
|
||||
|
||||
const onChangePassword = useCallback(
|
||||
async (data: z.infer<typeof changePasswordFormSchema>) => {
|
||||
setIsLoading(true);
|
||||
@@ -183,6 +213,21 @@ function ResetPasswordContent() {
|
||||
);
|
||||
}
|
||||
|
||||
// Show expired link message if detected
|
||||
if (showExpiredMessage && !user) {
|
||||
return (
|
||||
<div className="flex h-full min-h-[85vh] w-full flex-col items-center justify-center">
|
||||
<AuthCard title="Reset Password">
|
||||
<ExpiredLinkMessage
|
||||
onSendNewLink={handleSendNewLink}
|
||||
isLoading={isLoading}
|
||||
linkSent={linkSent}
|
||||
/>
|
||||
</AuthCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-full min-h-[85vh] w-full flex-col items-center justify-center">
|
||||
<AuthCard title="Reset Password">
|
||||
|
||||
@@ -26,8 +26,21 @@ export async function GET(request: NextRequest) {
|
||||
const result = await exchangePasswordResetCode(supabase, code);
|
||||
|
||||
if (!result.success) {
|
||||
// Check for expired or used link errors
|
||||
const errorMessage = result.error?.toLowerCase() || "";
|
||||
const isExpiredOrUsed =
|
||||
errorMessage.includes("expired") ||
|
||||
errorMessage.includes("invalid") ||
|
||||
errorMessage.includes("otp_expired") ||
|
||||
errorMessage.includes("already") ||
|
||||
errorMessage.includes("used");
|
||||
|
||||
const errorParam = isExpiredOrUsed
|
||||
? "link_expired"
|
||||
: encodeURIComponent(result.error || "Password reset failed");
|
||||
|
||||
return NextResponse.redirect(
|
||||
`${origin}/reset-password?error=${encodeURIComponent(result.error || "Password reset failed")}`,
|
||||
`${origin}/reset-password?error=${errorParam}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Button } from "../atoms/Button/Button";
|
||||
import { Link } from "../atoms/Link/Link";
|
||||
import { Text } from "../atoms/Text/Text";
|
||||
|
||||
interface Props {
|
||||
onSendNewLink: () => void;
|
||||
isLoading?: boolean;
|
||||
linkSent?: boolean;
|
||||
}
|
||||
|
||||
export function ExpiredLinkMessage({
|
||||
onSendNewLink,
|
||||
isLoading = false,
|
||||
linkSent = false,
|
||||
}: Props) {
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-6">
|
||||
<Text variant="h3" className="text-center">
|
||||
This password reset link has expired or already been used
|
||||
</Text>
|
||||
<div className="flex flex-col gap-4 text-center">
|
||||
<Text variant="large" className="text-center text-muted-foreground">
|
||||
Don't worry – this can happen if the link is opened more than
|
||||
once or has timed out.
|
||||
</Text>
|
||||
<Text variant="large" className="text-center text-muted-foreground">
|
||||
Click below to request a new password reset link.
|
||||
</Text>
|
||||
</div>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={onSendNewLink}
|
||||
loading={isLoading}
|
||||
disabled={linkSent}
|
||||
className="w-full max-w-sm"
|
||||
>
|
||||
{linkSent ? "Link Sent!" : "Send Me a New Link"}
|
||||
</Button>
|
||||
<div className="mt-2 flex items-center gap-1">
|
||||
<Text variant="small" className="text-muted-foreground">
|
||||
Already have access?
|
||||
</Text>
|
||||
<Link href="/login" variant="secondary">
|
||||
Log in here
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user