Skip to content
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ yarn-error.log*

# env files (can opt-in for committing if needed)
.env*
.env.local

# vercel
.vercel
Expand Down
30 changes: 30 additions & 0 deletions app/HomeWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"use client"

import { useSession } from "next-auth/react"
import { useRouter } from "next/navigation"
import { useEffect } from "react"

export default function HomeWrapper({ children }: { children: React.ReactNode }) {
const { data: session, status } = useSession()
const router = useRouter()

useEffect(() => {
if (status === "loading") return

if (session?.user?.needsPassword) {
router.replace("/set-password?email=" + session.user.email)
}
Comment on lines +14 to +16

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Do not put user email in the redirect URL.

On Line 15, appending session.user.email to the query string exposes PII in logs/history/referrers. Redirect to /set-password without email and resolve identity from the authenticated session on that page/API.

Proposed patch
-    if (session?.user?.needsPassword) {
-      router.replace("/set-password?email=" + session.user.email)
-    }
+    if (session?.user?.needsPassword) {
+      router.replace("/set-password")
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (session?.user?.needsPassword) {
router.replace("/set-password?email=" + session.user.email)
}
if (session?.user?.needsPassword) {
router.replace("/set-password")
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/HomeWrapper.tsx` around lines 14 - 16, The redirect currently leaks PII
by appending session.user.email in router.replace("/set-password?email=" +
session.user.email); instead change the redirect to
router.replace("/set-password") (or equivalent) so no email is included, and
update the /set-password page/API to read the authenticated user from the
session (using session?.user or your auth helper) to resolve identity and
prefill/validate without any email query parameter; remove any code that reads
the email from query string and rely on session?.user?.email instead.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Freny07 note

}, [session, status, router])

if (status === "loading") {
return (
<div className="flex min-h-screen items-center justify-center">
<p className="text-sm text-muted">Loading...</p>
</div>
)
}

if (session?.user?.needsPassword) return null

return <>{children}</>
}
3 changes: 3 additions & 0 deletions app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@


export { GET, POST } from "@/lib/auth"
10 changes: 10 additions & 0 deletions app/api/rate-limit/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { NextResponse } from "next/server"
import { checkRateLimit } from "@/lib/rateLimit"

export async function POST(req: Request) {
const { email } = await req.json()

const result = checkRateLimit(email)

return NextResponse.json(result)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
}
38 changes: 38 additions & 0 deletions app/api/set-password/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { NextResponse } from "next/server"
import clientPromise from "@/lib/mongodb"
import bcrypt from "bcryptjs"

export async function POST(req: Request) {
try {
const { email, password } = await req.json()

if (!email || !password) {
return NextResponse.json(
{ error: "Missing email or password" },
{ status: 400 }
)
}

const client = await clientPromise
const db = client.db()

const hashedPassword = await bcrypt.hash(password, 10)

await db.collection("users").updateOne(
{ email },
{
$set: {
password: hashedPassword,
},
}
)

return NextResponse.json({ success: true })
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
} catch (err) {
console.error("SET PASSWORD ERROR:", err)
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
)
}
}
13 changes: 9 additions & 4 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Geist, Fraunces } from "next/font/google";
import "./globals.css";
import { Navbar } from "@/components/Navbar";
import { Footer } from "@/components/Footer";
import Providers from "./providers"; // ✅ ADD THIS

const geistSans = Geist({
variable: "--font-geist-sans",
Expand Down Expand Up @@ -42,10 +43,14 @@ export default function RootLayout({
className={`${geistSans.variable} ${fraunces.variable} h-full antialiased`}
>
<body className="min-h-full flex flex-col bg-background text-foreground">
<Navbar />
<main className="flex-1">{children}</main>
<Footer />

<Providers>
<Navbar />
<main className="flex-1">{children}</main>
<Footer />
</Providers>

</body>
</html>
);
}
}
102 changes: 102 additions & 0 deletions app/login/LoginClient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
"use client"

import Link from "next/link"
import { Section } from "@/components/Section"
import { signIn } from "next-auth/react"
import { useState } from "react"

export default function LoginClient() {
const [email, setEmail] = useState("")
const [error, setError] = useState("")

const handleLogin = async (e: React.FormEvent) => {
e.preventDefault()

setError("")

try {
// rate limit check BEFORE signIn
const res = await fetch("/api/rate-limit", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ email }),
})

const data = await res.json()

if (!data.allowed) {
setError("Too many requests. Please try again later.")
return
}

// proceed normally
await signIn("email", {
email,
callbackUrl: "/",
})
} catch (err) {
setError("Something went wrong. Please try again.")
}
}

return (
<Section className="py-20">
<div className="mx-auto max-w-md rounded-xl border border-border bg-background p-8">
<p className="mt-2 text-sm text-muted">
Sign in to access the alumni directory, events, and the job board.
</p>

<form className="mt-6 space-y-4" onSubmit={handleLogin}>
<div>
<label className="text-sm font-medium">Email</label>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="mt-1 h-10 w-full rounded-md border border-border bg-background px-3 text-sm"
/>
</div>

<div>
<label className="text-sm font-medium">Password</label>
<input
type="password"
className="mt-1 h-10 w-full rounded-md border border-border bg-background px-3 text-sm"
/>
</div>

<button
type="submit"
className="inline-flex h-11 w-full items-center justify-center rounded-md bg-brand text-sm font-semibold text-white hover:bg-brand-700"
>
Sign in
</button>
</form>

{/* ERROR MESSAGE (no UI change, just added) */}
{error && (
<p className="mt-2 text-sm text-red-500">
{error}
</p>
)}

<button
type="button"
onClick={() => signIn("google", { callbackUrl: "/" })}
className="mt-4 inline-flex h-11 w-full items-center justify-center rounded-md border border-border text-sm font-semibold"
>
Sign in with Google
</button>

<p className="mt-4 text-center text-sm text-muted">
New to IIITL Alumni?{" "}
<Link href="/register" className="font-medium text-brand">
Create an account
</Link>
</p>
</div>
</Section>
)
}
48 changes: 5 additions & 43 deletions app/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,7 @@
import Link from "next/link";
import { Section } from "@/components/Section";
import LoginClient from "./LoginClient"

export const metadata = { title: "Sign in" };
export const metadata = { title: "Sign in" }

export default function LoginPage() {
return (
<Section className="py-20">
<div className="mx-auto max-w-md rounded-xl border border-border bg-background p-8">
<h1 className="font-serif text-3xl font-semibold">Welcome back</h1>
<p className="mt-2 text-sm text-muted">
Sign in to access the alumni directory, events, and the job board.
</p>
<form className="mt-6 space-y-4">
<div>
<label className="text-sm font-medium">Email</label>
<input
type="email"
className="mt-1 h-10 w-full rounded-md border border-border bg-background px-3 text-sm"
/>
</div>
<div>
<label className="text-sm font-medium">Password</label>
<input
type="password"
className="mt-1 h-10 w-full rounded-md border border-border bg-background px-3 text-sm"
/>
</div>
<button
type="button"
className="inline-flex h-11 w-full items-center justify-center rounded-md bg-brand text-sm font-semibold text-white hover:bg-brand-700"
>
Sign in
</button>
</form>
<p className="mt-4 text-center text-sm text-muted">
New to IIITL Alumni?{" "}
<Link href="/register" className="font-medium text-brand">
Create an account
</Link>
</p>
</div>
</Section>
);
}
export default function Page() {
return <LoginClient />
}
Loading