From d63ff0a17052994426dd2f770fb6b0aaf8e3d7d5 Mon Sep 17 00:00:00 2001 From: Thatsaphorn Atchariyaphap Date: Sun, 29 Jun 2025 18:35:28 +0900 Subject: [PATCH] Enable hCaptcha verification and dynamic gateway host detection in contact API route. --- .run/npm-dev.run.xml | 1 + frontend/app/api/contact/route.ts | 80 +++++++++++++++++++------------ 2 files changed, 50 insertions(+), 31 deletions(-) diff --git a/.run/npm-dev.run.xml b/.run/npm-dev.run.xml index 828d585..bb1ac28 100644 --- a/.run/npm-dev.run.xml +++ b/.run/npm-dev.run.xml @@ -8,6 +8,7 @@ + diff --git a/frontend/app/api/contact/route.ts b/frontend/app/api/contact/route.ts index 4144b9c..0c4688a 100644 --- a/frontend/app/api/contact/route.ts +++ b/frontend/app/api/contact/route.ts @@ -1,54 +1,72 @@ -import {NextRequest, NextResponse} from 'next/server'; +import {NextRequest, NextResponse} from 'next/server' -const HCAPTCHA_SECRET = process.env.HCAPTCHA_SECRET ?? ''; -const SHARED_API_KEY = process.env.SHARED_API_KEY ?? ''; +const HCAPTCHA_SECRET = process.env.HCAPTCHA_SECRET ?? '' +const SHARED_API_KEY = process.env.SHARED_API_KEY ?? '' + +// Detect whether to use localhost or Docker gateway +const useLocalGatewayEnv = process.env.USE_LOCAL_GATEWAY +const useLocalGateway = useLocalGatewayEnv?.toLowerCase() === 'true' +const gatewayHost = useLocalGateway ? 'http://localhost:8080' : 'http://gateway:8080' export async function POST(req: NextRequest) { try { - const body = await req.json(); - const origin = req.headers.get("origin") || "http://localhost:3000"; - const captchaToken = body.captcha; + const body = await req.json() + const origin = req.headers.get('origin') || 'http://localhost:3000' + const captchaToken = body.captcha if (!captchaToken) { - return NextResponse.json({success: false, error: 'Captcha is required'}, {status: 400}); + return NextResponse.json( + {success: false, error: 'Captcha is required'}, + {status: 400} + ) } - // Step 1: Verify hCaptcha token with their API - // const verifyResponse = await fetch('https://api.hcaptcha.com/siteverify', { - // method: 'POST', - // headers: {'Content-Type': 'application/x-www-form-urlencoded'}, - // body: new URLSearchParams({ - // secret: HCAPTCHA_SECRET, - // response: captchaToken, - // }), - // }); - // - // const captchaResult = await verifyResponse.json(); - // - // if (!captchaResult.success) { - // return NextResponse.json({success: false, error: 'Captcha verification failed'}, {status: 403}); - // } + // Step 1: Verify hCaptcha token + const verifyResponse = await fetch('https://api.hcaptcha.com/siteverify', { + method: 'POST', + headers: {'Content-Type': 'application/x-www-form-urlencoded'}, + body: new URLSearchParams({ + secret: HCAPTCHA_SECRET, + response: captchaToken, + }), + }) - // Step 2: Forward valid contact request to Spring Boot backend - const backendRes = await fetch('http://localhost:8080/api/contact', { + const captchaResult = await verifyResponse.json() + console.log('[ContactAPI] hCaptcha result:', captchaResult) + + if (!captchaResult.success) { + return NextResponse.json( + {success: false, error: 'Captcha verification failed'}, + {status: 403} + ) + } + + // Step 2: Forward to backend service + const backendRes = await fetch(`${gatewayHost}/api/contact`, { method: 'POST', headers: { - "Origin": origin, + Origin: origin, 'Content-Type': 'application/json', 'X-Frontend-Key': SHARED_API_KEY, }, body: JSON.stringify(body), - }); + }) - const backendText = await backendRes.text(); + const backendText = await backendRes.text() if (!backendRes.ok) { - return NextResponse.json({success: false, error: backendText}, {status: backendRes.status}); + return NextResponse.json( + {success: false, error: backendText}, + {status: backendRes.status} + ) } - return NextResponse.json({success: true, message: backendText}); + return NextResponse.json({success: true, message: backendText}) } catch (err: any) { - console.error('[ContactAPI] error:', err); - return NextResponse.json({success: false, error: err.message}, {status: 500}); + console.error('[ContactAPI] error:', err) + return NextResponse.json( + {success: false, error: err.message}, + {status: 500} + ) } }