-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Expand file tree
/
Copy pathroute.ts
More file actions
92 lines (79 loc) · 2.65 KB
/
route.ts
File metadata and controls
92 lines (79 loc) · 2.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import { db } from '@sim/db'
import { user } from '@sim/db/schema'
import { createLogger } from '@sim/logger'
import { eq } from 'drizzle-orm'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
import { auth } from '@/lib/auth'
import { isSameOrigin } from '@/lib/core/utils/validation'
export const dynamic = 'force-dynamic'
const logger = createLogger('ForgetPasswordAPI')
const forgetPasswordSchema = z.object({
email: z
.string({ required_error: 'Email is required' })
.email('Please provide a valid email address'),
redirectTo: z
.string()
.optional()
.or(z.literal(''))
.transform((val) => (val === '' || val === undefined ? undefined : val))
.refine(
(val) => val === undefined || (z.string().url().safeParse(val).success && isSameOrigin(val)),
{
message: 'Redirect URL must be a valid same-origin URL',
}
),
})
export async function POST(request: NextRequest) {
try {
const body = await request.json()
const validationResult = forgetPasswordSchema.safeParse(body)
if (!validationResult.success) {
const firstError = validationResult.error.errors[0]
const errorMessage = firstError?.message || 'Invalid request data'
logger.warn('Invalid forget password request data', {
errors: validationResult.error.format(),
})
return NextResponse.json({ message: errorMessage }, { status: 400 })
}
const { email, redirectTo } = validationResult.data
await auth.api.forgetPassword({
body: {
email,
redirectTo,
},
method: 'POST',
})
const [existingUser] = await db
.select({ id: user.id, name: user.name, email: user.email })
.from(user)
.where(eq(user.email, email))
.limit(1)
if (existingUser) {
recordAudit({
actorId: existingUser.id,
actorName: existingUser.name,
actorEmail: existingUser.email,
action: AuditAction.PASSWORD_RESET_REQUESTED,
resourceType: AuditResourceType.PASSWORD,
resourceId: existingUser.id,
resourceName: existingUser.email ?? undefined,
description: `Password reset requested for ${existingUser.email}`,
request,
})
}
return NextResponse.json({ success: true })
} catch (error) {
logger.error('Error requesting password reset:', { error })
return NextResponse.json(
{
message:
error instanceof Error
? error.message
: 'Failed to send password reset email. Please try again later.',
},
{ status: 500 }
)
}
}