Files
Andrei 989f231d5a feat: add captcha verification to contact form
Added math-based captcha system to prevent spam on the contact form:
- Created captcha API endpoint with simple arithmetic questions
- Added captcha UI component with refresh functionality
- Integrated captcha verification into contact form submission
- Relaxed spam filters since captcha provides better protection

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-10 17:53:56 +00:00

85 lines
2.5 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import { smtpService } from '@/lib/smtp'
import { verifyCaptcha } from '@/lib/captcha'
import { z } from 'zod'
export const runtime = 'nodejs'
const contactSchema = z.object({
name: z.string().min(1, 'Name is required').max(100),
email: z.string().email('Invalid email address'),
subject: z.string().min(1, 'Subject is required').max(200),
message: z.string().min(10, 'Message must be at least 10 characters').max(5000),
captchaId: z.string().min(1, 'Captcha ID is required'),
captchaAnswer: z.string().min(1, 'Captcha answer is required')
})
export async function POST(request: NextRequest) {
try {
const body = await request.json()
// Validate input
const validationResult = contactSchema.safeParse(body)
if (!validationResult.success) {
return NextResponse.json({
success: false,
error: 'Invalid form data',
details: validationResult.error.errors
}, { status: 400 })
}
const { name, email, subject, message, captchaId, captchaAnswer } = validationResult.data
// Verify captcha
const isValidCaptcha = verifyCaptcha(captchaId, captchaAnswer)
if (!isValidCaptcha) {
return NextResponse.json({
success: false,
error: 'Invalid captcha answer. Please try again.'
}, { status: 400 })
}
// Basic spam prevention - only check for obvious spam
// Allow URLs in messages since users may want to share links
const isSpam = (
(message.includes('bitcoin') || message.includes('cryptocurrency')) &&
(message.includes('http://') || message.includes('https://'))
)
if (isSpam) {
return NextResponse.json({
success: false,
error: 'Message flagged as potential spam'
}, { status: 400 })
}
// Send email using local SMTP server (Maddy)
const emailResult = await smtpService.sendContactForm({
name,
email,
subject,
message
})
if (emailResult.success) {
return NextResponse.json({
success: true,
message: 'Your message has been sent successfully!'
})
} else {
console.error('Contact form email failed:', emailResult.error)
return NextResponse.json({
success: false,
error: 'Failed to send message. Please try again later.'
}, { status: 500 })
}
} catch (error) {
console.error('Contact form error:', error)
return NextResponse.json({
success: false,
error: 'Internal server error'
}, { status: 500 })
}
}