-
Notifications
You must be signed in to change notification settings - Fork 111
forgot password page added #289
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 4 commits
b642559
167582a
e2d8350
377b3c0
c4debae
4656046
e341cf7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,24 @@ | ||||||||
| import { NextResponse } from "next/server"; | ||||||||
|
|
||||||||
| export async function POST(req: Request) { | ||||||||
| try { | ||||||||
| const { email } = await req.json(); | ||||||||
|
|
||||||||
| if (!email) { | ||||||||
| return NextResponse.json( | ||||||||
| { message: "Email is required." }, | ||||||||
| { status: 400 }, | ||||||||
| ); | ||||||||
| } | ||||||||
| console.log("Password reset requested for:", email); | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove PII from logs. Logging email addresses constitutes a privacy and compliance violation (GDPR, CCPA). Application logs are often aggregated, stored long-term, and accessible to multiple parties, creating an unnecessary exposure of user PII. 🔒 Proposed fixEither remove the log entirely or use a hashed/anonymized identifier: - console.log("Password reset requested for:", email);
+ // Log without PII for observability
+ console.log("Password reset requested");Or if you need to track requests for debugging, hash the email: + const crypto = require('crypto');
+ const emailHash = crypto.createHash('sha256').update(email).digest('hex').substring(0, 8);
- console.log("Password reset requested for:", email);
+ console.log("Password reset requested, hash:", emailHash);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||
|
|
||||||||
| return NextResponse.json({ | ||||||||
| message: "If the email exists, reset link sent.", | ||||||||
| }); | ||||||||
|
Comment on lines
+15
to
+17
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implement actual password reset logic or clarify scope. The endpoint returns a success message but doesn't generate reset tokens, store them, or send emails. Submitting the form provides user feedback but performs no actual password reset operation. If this stub is intentional (e.g., split into multiple PRs), consider:
If this should be complete:
Would you like help implementing the complete password reset flow, or should this be tracked separately? 🤖 Prompt for AI Agents |
||||||||
| } catch (err) { | ||||||||
| return NextResponse.json( | ||||||||
| { message: "Internal server error." }, | ||||||||
| { status: 500 }, | ||||||||
| ); | ||||||||
| } | ||||||||
| } | ||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| "use client"; | ||
|
|
||
| import { FormEvent, useState } from "react"; | ||
| import Link from "next/link"; | ||
| import { Button } from "@/components/ui/button"; | ||
| import { Input } from "@/components/ui/input"; | ||
| import { Navbar } from "../components/Navbar"; | ||
|
|
||
| export default function ForgotPasswordPage() { | ||
| const [email, setEmail] = useState<string>(""); | ||
| const [loading, setLoading] = useState<boolean>(false); | ||
| const [message, setMessage] = useState<string>(""); | ||
| const [error, setError] = useState<string>(""); | ||
|
|
||
| const handleSubmit = async (e: FormEvent<HTMLFormElement>): Promise<void> => { | ||
| e.preventDefault(); | ||
|
|
||
| if (!email.trim()) { | ||
| setError("Please enter your email address."); | ||
| return; | ||
| } | ||
|
|
||
| setLoading(true); | ||
| setError(""); | ||
| setMessage(""); | ||
|
|
||
| try { | ||
| const response = await fetch("/api/forgot-password", { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| }, | ||
| body: JSON.stringify({ | ||
| email: email.trim(), | ||
| }), | ||
| }); | ||
|
ArshiBansal marked this conversation as resolved.
|
||
|
|
||
| const data: { message?: string } = await response.json(); | ||
|
|
||
| if (!response.ok) { | ||
| throw new Error(data.message || "Something went wrong."); | ||
| } | ||
|
|
||
| setMessage( | ||
| "If an account exists with that email, a password reset link has been sent.", | ||
| ); | ||
|
|
||
| setEmail(""); | ||
| } catch (err) { | ||
| setError( | ||
| err instanceof Error ? err.message : "Failed to send reset email.", | ||
| ); | ||
| } finally { | ||
| setLoading(false); | ||
| } | ||
| }; | ||
|
|
||
| return ( | ||
| <> | ||
| <Navbar /> | ||
|
|
||
| <div className="flex min-h-[calc(100vh-64px)] items-center justify-center px-4"> | ||
| <div className="w-full max-w-md rounded-xl border bg-background p-6 shadow-sm"> | ||
| <div className="mb-6 text-center"> | ||
| <h1 className="text-2xl font-bold">Forgot Password</h1> | ||
|
|
||
| <p className="mt-2 text-sm text-muted-foreground"> | ||
| Enter your email address and we'll send you a password reset link. | ||
|
ArshiBansal marked this conversation as resolved.
|
||
| </p> | ||
| </div> | ||
|
|
||
| <form onSubmit={handleSubmit} className="space-y-4"> | ||
| {error && <p className="text-sm text-red-500">{error}</p>} | ||
|
|
||
| {message && <p className="text-sm text-green-600">{message}</p>} | ||
|
|
||
| <Input | ||
| type="email" | ||
| placeholder="Enter your email" | ||
| value={email} | ||
| onChange={(e) => { | ||
| setEmail(e.target.value); | ||
| setError(""); | ||
| }} | ||
| disabled={loading} | ||
| /> | ||
|
|
||
| <Button | ||
| type="submit" | ||
| className="w-full" | ||
| disabled={loading || !email.trim()} | ||
| > | ||
| {loading ? "Sending Reset Link..." : "Send Reset Link"} | ||
| </Button> | ||
| </form> | ||
|
|
||
| <div className="mt-4 text-center"> | ||
| <Link | ||
| href="/login" | ||
| className="text-sm text-muted-foreground hover:underline" | ||
| > | ||
| Back to Login | ||
| </Link> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </> | ||
| ); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add email format validation.
The handler only checks for email presence, not format. Invalid email formats (e.g.,
"notanemail","@.com") will pass validation. Additionally, the API doesn't trim whitespace while the client does, which could create inconsistencies if the client-side validation is bypassed.✉️ Proposed fix with email validation
🤖 Prompt for AI Agents