94 lines
2.5 KiB
JavaScript
94 lines
2.5 KiB
JavaScript
import express from 'express';
|
|
import rateLimit from 'express-rate-limit';
|
|
import { body, validationResult } from 'express-validator';
|
|
import { sendContactEmail } from '../services/emailService.js';
|
|
|
|
const router = express.Router();
|
|
|
|
// GDPR compliant rate limiting
|
|
const contactLimiter = rateLimit({
|
|
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
max: 3, // Limit each IP to 3 requests per windowMs
|
|
message: {
|
|
error: 'Too many contact requests from this IP, please try again later.',
|
|
retryAfter: 15 * 60,
|
|
},
|
|
standardHeaders: true,
|
|
legacyHeaders: false,
|
|
});
|
|
|
|
// GDPR compliant validation
|
|
const validateContactForm = [
|
|
body('firstName').trim().isLength({ min: 1, max: 50 }).escape(),
|
|
body('lastName').trim().isLength({ min: 1, max: 50 }).escape(),
|
|
body('email').trim().isEmail().normalizeEmail().isLength({ max: 254 }),
|
|
body('subject').trim().isLength({ min: 1, max: 100 }).escape(),
|
|
body('message').trim().isLength({ min: 10, max: 2000 }).escape(),
|
|
body('gdprConsent').equals('true').withMessage('GDPR consent required'),
|
|
body('website').optional().isEmpty(), // Honeypot
|
|
];
|
|
|
|
router.post('/', contactLimiter, validateContactForm, async (req, res) => {
|
|
try {
|
|
const errors = validationResult(req);
|
|
if (!errors.isEmpty()) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: 'Invalid form data.',
|
|
errors: errors.array(),
|
|
});
|
|
}
|
|
|
|
const {
|
|
firstName,
|
|
lastName,
|
|
email,
|
|
subject,
|
|
message,
|
|
gdprConsent,
|
|
website,
|
|
} = req.body;
|
|
|
|
// Honeypot check
|
|
if (website) {
|
|
console.warn('🚨 Spam detected:', req.ip);
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: 'Invalid submission detected.',
|
|
});
|
|
}
|
|
|
|
// GDPR consent check
|
|
if (gdprConsent !== 'true') {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: 'GDPR consent required.',
|
|
});
|
|
}
|
|
|
|
// Send email with minimal logging for GDPR
|
|
await sendContactEmail({
|
|
firstName,
|
|
lastName,
|
|
email,
|
|
subject,
|
|
message,
|
|
senderIP: req.ip,
|
|
userAgent: req.get('User-Agent'),
|
|
});
|
|
|
|
res.json({
|
|
success: true,
|
|
message: "Thank you for your message! I'll get back to you soon.",
|
|
});
|
|
} catch (error) {
|
|
console.error('❌ Contact error:', error.message); // No personal data in logs
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Failed to send message. Please try again later.',
|
|
});
|
|
}
|
|
});
|
|
|
|
export { router as contactRouter };
|