mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-16 09:46:07 -05:00
Compare commits
5 Commits
docs/podma
...
bently/sec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17480d647c | ||
|
|
1f9a8489f7 | ||
|
|
7366a51d92 | ||
|
|
6b6d3fec11 | ||
|
|
80e9f4008f |
@@ -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 { Form, FormField } from "@/components/__legacy__/ui/form";
|
||||
import LoadingBox from "@/components/__legacy__/ui/loading";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
@@ -21,18 +22,42 @@ function ResetPasswordContent() {
|
||||
const router = useRouter();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [disabled, setDisabled] = useState(false);
|
||||
const [showExpiredMessage, setShowExpiredMessage] = 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
|
||||
// Avoid broad checks like "invalid" which can match unrelated errors (e.g., PKCE errors)
|
||||
const descLower = errorDescription?.toLowerCase() || "";
|
||||
const isExpiredOrUsed =
|
||||
error === "link_expired" ||
|
||||
errorCode === "otp_expired" ||
|
||||
descLower.includes("expired") ||
|
||||
descLower.includes("already") ||
|
||||
descLower.includes("used");
|
||||
|
||||
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]);
|
||||
@@ -82,6 +107,10 @@ function ResetPasswordContent() {
|
||||
[sendEmailForm, toast],
|
||||
);
|
||||
|
||||
function handleShowEmailForm() {
|
||||
setShowExpiredMessage(false);
|
||||
}
|
||||
|
||||
const onChangePassword = useCallback(
|
||||
async (data: z.infer<typeof changePasswordFormSchema>) => {
|
||||
setIsLoading(true);
|
||||
@@ -122,6 +151,17 @@ 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 onRequestNewLink={handleShowEmailForm} />
|
||||
</AuthCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-full min-h-[85vh] w-full flex-col items-center justify-center">
|
||||
<AuthCard title="Reset Password">
|
||||
|
||||
@@ -10,7 +10,7 @@ export async function GET(request: NextRequest) {
|
||||
|
||||
if (!code) {
|
||||
return NextResponse.redirect(
|
||||
`${origin}/reset-password?error=Missing verification code`,
|
||||
`${origin}/reset-password?error=${encodeURIComponent("Missing verification code")}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
// Avoid broad checks like "invalid" which can match unrelated errors (e.g., PKCE errors)
|
||||
const errorMessage = result.error?.toLowerCase() || "";
|
||||
const isExpiredOrUsed =
|
||||
errorMessage.includes("expired") ||
|
||||
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}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -35,7 +48,7 @@ export async function GET(request: NextRequest) {
|
||||
} catch (error) {
|
||||
console.error("Password reset callback error:", error);
|
||||
return NextResponse.redirect(
|
||||
`${origin}/reset-password?error=Password reset failed`,
|
||||
`${origin}/reset-password?error=${encodeURIComponent("Password reset failed")}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Button } from "../atoms/Button/Button";
|
||||
import { Link } from "../atoms/Link/Link";
|
||||
import { Text } from "../atoms/Text/Text";
|
||||
|
||||
interface Props {
|
||||
onRequestNewLink: () => void;
|
||||
}
|
||||
|
||||
export function ExpiredLinkMessage({ onRequestNewLink }: Props) {
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-6">
|
||||
<Text variant="h3" className="text-center">
|
||||
Your reset password link has expired or has already been used
|
||||
</Text>
|
||||
<Text variant="body-medium" className="text-center text-muted-foreground">
|
||||
Click below to request a new password reset link.
|
||||
</Text>
|
||||
<Button variant="primary" onClick={onRequestNewLink} className="w-full">
|
||||
Request a New Link
|
||||
</Button>
|
||||
<div className="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