@@ -10,7 +10,8 @@ import path from "path";
1010import os from "os" ;
1111import dbConnect from "@/lib/db" ;
1212import User , { IUser } from "@/models/User" ;
13- import { checkRateLimit } from "@/lib/rate-limit" ;
13+ import { checkRateLimit , getClientIp } from "@/lib/rate-limit" ;
14+ import { verifyRecaptcha } from "@/lib/recaptcha" ;
1415
1516// Utility functions for format validation
1617const validateEmail = ( email : string ) =>
@@ -206,9 +207,9 @@ const getOrCreateBatchDocument = async () => {
206207
207208export async function POST ( request : Request ) {
208209 try {
209- // Basic IP Rate limiting (5 requests per minute)
210- const ip = request . headers . get ( "x-forwarded-for" ) || "unknown" ;
211- if ( ! checkRateLimit ( ip , 5 , 60 * 1000 ) ) {
210+ // IP rate limiting (5 requests per minute)
211+ const ip = getClientIp ( request ) ;
212+ if ( ! ( await checkRateLimit ( ip , 5 , 60 * 1000 ) ) ) {
212213 return NextResponse . json (
213214 {
214215 message : "Too many requests. Please try again later." ,
@@ -234,6 +235,20 @@ export async function POST(request: Request) {
234235 const data = { ...fields } ;
235236 const { recaptcha_token, password } = data ;
236237
238+ // reCAPTCHA v3 — fail closed (rejects when the token is missing) and check
239+ // the score + action, before any Firebase/Cloudinary/DB writes.
240+ const captcha = await verifyRecaptcha ( recaptcha_token , "register" ) ;
241+ if ( ! captcha . ok ) {
242+ console . warn ( "[registration] reCAPTCHA rejected:" , captcha . reason , captcha . score ) ;
243+ return NextResponse . json (
244+ {
245+ message : "reCAPTCHA validation failed" ,
246+ error : "Security check failed. Please try again." ,
247+ } ,
248+ { status : 400 } ,
249+ ) ;
250+ }
251+
237252 // Check if required resume file is present
238253 if ( ! files . resume ) {
239254 return NextResponse . json (
@@ -493,28 +508,6 @@ export async function POST(request: Request) {
493508 ) ;
494509 }
495510
496- // Validate reCAPTCHA if token provided
497- if ( recaptcha_token ) {
498- const recaptchaSecretKey = process . env . RECAPTCHA_SECRET_KEY ;
499-
500- // Verify reCAPTCHA token
501- const recaptchaResponse = await fetch (
502- `https://www.google.com/recaptcha/api/siteverify?secret=${ recaptchaSecretKey } &response=${ recaptcha_token } ` ,
503- { method : "POST" } ,
504- ) ;
505- const recaptchaResult = await recaptchaResponse . json ( ) ;
506-
507- if ( ! recaptchaResult . success ) {
508- return NextResponse . json (
509- {
510- message : "reCAPTCHA validation failed" ,
511- error : recaptchaResult [ "error-codes" ] ,
512- } ,
513- { status : 400 } ,
514- ) ;
515- }
516- }
517-
518511 // Create user in Firebase Authentication
519512 let authUid : string ;
520513 try {
0 commit comments