| import { NextRequest, NextResponse } from 'next/server'; |
| import { withDb } from '@/lib/api-handler'; |
| import { db } from '@/lib/db'; |
| import { z } from 'zod'; |
| import { getClientIp } from '@/lib/validation'; |
| import { rateLimit } from '@/lib/rate-limit'; |
|
|
| const forgotPasswordSchema = z.object({ |
| email: z.string().email('Please enter a valid email address'), |
| }); |
|
|
| async function handler(request: NextRequest) { |
| try { |
| |
| const ip = getClientIp(request); |
| const { allowed, retryAfterMs } = await rateLimit(`forgot-pw:${ip}`, 3, 15 * 60_000); |
| if (!allowed) { |
| return NextResponse.json( |
| { error: 'Too many reset attempts. Please try again later.' }, |
| { |
| status: 429, |
| headers: { 'Retry-After': String(Math.ceil(retryAfterMs / 1000)) }, |
| } |
| ); |
| } |
|
|
| |
| const body = await request.json(); |
| const parsed = forgotPasswordSchema.safeParse(body); |
| if (!parsed.success) { |
| return NextResponse.json( |
| { error: parsed.error.issues[0].message }, |
| { status: 400 } |
| ); |
| } |
|
|
| const { email } = parsed.data; |
|
|
| |
| const user = await db.user.findUnique({ where: { email } }); |
|
|
| if (user) { |
| |
| const code = String(Math.floor(100000 + Math.random() * 900000)); |
| const expiresAt = new Date(Date.now() + 15 * 60 * 1000); |
|
|
| |
| await db.resetToken.updateMany({ |
| where: { email, usedAt: null }, |
| data: { usedAt: new Date() }, |
| }); |
|
|
| |
| await db.resetToken.create({ |
| data: { |
| email, |
| token: code, |
| expiresAt, |
| }, |
| }); |
|
|
| return NextResponse.json({ |
| message: 'If an account exists with this email, a reset code has been generated.', |
| code, |
| }); |
| } |
|
|
| |
| return NextResponse.json({ |
| message: 'If an account exists with this email, a reset code has been generated.', |
| }); |
| } catch (error) { |
| console.error('[FORGOT_PASSWORD_ERROR]', error); |
| return NextResponse.json( |
| { error: 'Internal server error' }, |
| { status: 500 } |
| ); |
| } |
| } |
|
|
| export const POST = withDb(handler); |