import { NextRequest, NextResponse } from 'next/server'; import { db } from '@/lib/db'; import { changePasswordSchema, getClientIp } from '@/lib/validation'; import { getSessionUser, verifyPassword, hashPassword, getCookieToken } from '@/lib/auth'; import { rateLimit } from '@/lib/rate-limit'; import { logActivity } from '@/lib/activity'; export async function POST(request: NextRequest) { try { // ── Rate Limit ──────────────────────────────────────────────────── const ip = getClientIp(request); const { allowed, retryAfterMs } = await rateLimit(`password:${ip}`, 3, 60_000); if (!allowed) { return NextResponse.json( { error: 'Too many password change attempts. Please try again later.' }, { status: 429, headers: { 'Retry-After': String(Math.ceil(retryAfterMs / 1000)) }, } ); } // ── Authenticate User ───────────────────────────────────────────── const token = getCookieToken(request); const user = await getSessionUser(token || ''); if (!user) { return NextResponse.json( { error: 'Authentication required' }, { status: 401 } ); } // ── Parse & Validate Body ───────────────────────────────────────── const body = await request.json(); const parsed = changePasswordSchema.safeParse(body); if (!parsed.success) { return NextResponse.json( { error: parsed.error.issues[0].message }, { status: 400 } ); } const { currentPassword, newPassword } = parsed.data; // ── Verify Current Password ─────────────────────────────────────── const valid = await verifyPassword(currentPassword, user.password); if (!valid) { return NextResponse.json( { error: 'Invalid credentials' }, { status: 401 } ); } // ── Hash New Password ───────────────────────────────────────────── const hashedPassword = await hashPassword(newPassword); // ── Update User Password ────────────────────────────────────────── await db.user.update({ where: { id: user.id }, data: { password: hashedPassword }, }); // ── Invalidate All Sessions (force re-login) ────────────────────── await db.session.deleteMany({ where: { userId: user.id }, }); logActivity(user.id, 'password_change', 'Password changed', 'Account password was updated'); return NextResponse.json({ success: true, message: 'Password updated successfully', }); } catch (error) { console.error('[PASSWORD_CHANGE_ERROR]', error); return NextResponse.json( { error: 'Internal server error' }, { status: 500 } ); } }