@@ -20,6 +20,7 @@ import {
2020 OTP_RESOURCE_RATE_LIMIT ,
2121 storeOTP ,
2222} from '@/lib/core/security/otp'
23+ import { afterResponse } from '@/lib/core/utils/after-response'
2324import { generateRequestId , getClientIp } from '@/lib/core/utils/request'
2425import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
2526import { sendEmail } from '@/lib/messaging/email/mailer'
@@ -34,6 +35,45 @@ function otpRequestAccepted() {
3435 return createSuccessResponse ( { message : 'Verification code sent' } )
3536}
3637
38+ async function deliverOtp ( requestId : string , deploymentId : string , title : string , email : string ) {
39+ const resourceRateLimit = await rateLimiter . checkRateLimitDirect (
40+ `chat-otp:resource:${ deploymentId } ` ,
41+ OTP_RESOURCE_RATE_LIMIT ,
42+ { failClosed : true }
43+ )
44+ if ( ! resourceRateLimit . allowed ) {
45+ logger . warn ( `[${ requestId } ] OTP resource rate limit exceeded for chat ${ deploymentId } ` )
46+ return
47+ }
48+
49+ const emailRateLimit = await rateLimiter . checkRateLimitDirect (
50+ `chat-otp:email:${ deploymentId } :${ email . toLowerCase ( ) } ` ,
51+ OTP_EMAIL_RATE_LIMIT ,
52+ { failClosed : true }
53+ )
54+ if ( ! emailRateLimit . allowed ) {
55+ logger . warn ( `[${ requestId } ] OTP email rate limit exceeded for ${ email } on chat ${ deploymentId } ` )
56+ return
57+ }
58+
59+ const otp = generateOTP ( )
60+ await storeOTP ( 'chat' , deploymentId , email , otp )
61+
62+ const emailHtml = await renderOTPEmail ( otp , email , 'email-verification' , title )
63+ const emailResult = await sendEmail ( {
64+ to : email ,
65+ subject : getOtpSubject ( title ) ,
66+ html : emailHtml ,
67+ } )
68+
69+ if ( ! emailResult . success ) {
70+ logger . error ( `[${ requestId } ] Failed to send OTP email:` , emailResult . message )
71+ return
72+ }
73+
74+ logger . info ( `[${ requestId } ] OTP sent to ${ email } for chat ${ deploymentId } ` )
75+ }
76+
3777export const POST = withRouteHandler (
3878 async ( request : NextRequest , context : { params : Promise < { identifier : string } > } ) => {
3979 const { identifier } = await context . params
@@ -92,55 +132,12 @@ export const POST = withRouteHandler(
92132 const allowedEmails : string [ ] = Array . isArray ( deployment . allowedEmails )
93133 ? deployment . allowedEmails
94134 : [ ]
135+ const emailAllowed = isEmailAllowed ( email , allowedEmails )
95136
96- if ( ! isEmailAllowed ( email , allowedEmails ) ) {
97- return otpRequestAccepted ( )
98- }
99-
100- const resourceRateLimit = await rateLimiter . checkRateLimitDirect (
101- `chat-otp:resource:${ deployment . id } ` ,
102- OTP_RESOURCE_RATE_LIMIT ,
103- { failClosed : true }
104- )
105- if ( ! resourceRateLimit . allowed ) {
106- logger . warn ( `[${ requestId } ] OTP resource rate limit exceeded for chat ${ deployment . id } ` )
107- return otpRequestAccepted ( )
108- }
109-
110- const emailRateLimit = await rateLimiter . checkRateLimitDirect (
111- `chat-otp:email:${ deployment . id } :${ email . toLowerCase ( ) } ` ,
112- OTP_EMAIL_RATE_LIMIT ,
113- { failClosed : true }
114- )
115- if ( ! emailRateLimit . allowed ) {
116- logger . warn (
117- `[${ requestId } ] OTP email rate limit exceeded for ${ email } on chat ${ deployment . id } `
118- )
119- return otpRequestAccepted ( )
120- }
121-
122- const otp = generateOTP ( )
123- await storeOTP ( 'chat' , deployment . id , email , otp )
124-
125- const emailHtml = await renderOTPEmail (
126- otp ,
127- email ,
128- 'email-verification' ,
129- deployment . title || 'Chat'
130- )
131-
132- const emailResult = await sendEmail ( {
133- to : email ,
134- subject : getOtpSubject ( deployment . title || 'Chat' ) ,
135- html : emailHtml ,
137+ afterResponse ( async ( ) => {
138+ if ( ! emailAllowed ) return
139+ await deliverOtp ( requestId , deployment . id , deployment . title || 'Chat' , email )
136140 } )
137-
138- if ( ! emailResult . success ) {
139- logger . error ( `[${ requestId } ] Failed to send OTP email:` , emailResult . message )
140- return otpRequestAccepted ( )
141- }
142-
143- logger . info ( `[${ requestId } ] OTP sent to ${ email } for chat ${ deployment . id } ` )
144141 return otpRequestAccepted ( )
145142 } catch ( error ) {
146143 logger . error ( `[${ requestId } ] Error processing OTP request:` , error )
0 commit comments