Add honeypot protection to contact forms

This commit is contained in:
Codex Agent
2026-01-23 15:38:34 +01:00
parent 531c666cf0
commit f19a83d4ee
10 changed files with 312 additions and 106 deletions

View File

@@ -6,15 +6,40 @@ import MarketingLayout from '@/layouts/mainWebsite';
import { Loader2, CheckCircle2 } from 'lucide-react';
import { motion, useReducedMotion } from 'framer-motion';
interface HoneypotPayload {
enabled: boolean;
nameFieldName: string;
validFromFieldName: string;
encryptedValidFrom: string;
}
type ContactFormData = {
name: string;
email: string;
message: string;
[key: string]: string;
};
const Kontakt: React.FC = () => {
const { data, setData, post, processing, errors, reset } = useForm({
const { honeypot, flash } = usePage<{ flash?: { success?: string }; honeypot?: HoneypotPayload }>().props;
const honeypotDefaults = React.useMemo(() => {
if (!honeypot?.enabled) {
return {};
}
return {
[honeypot.nameFieldName]: '',
[honeypot.validFromFieldName]: honeypot.encryptedValidFrom,
};
}, [honeypot?.enabled, honeypot?.encryptedValidFrom, honeypot?.nameFieldName, honeypot?.validFromFieldName]);
const { data, setData, post, processing, errors, reset } = useForm<ContactFormData>({
name: '',
email: '',
message: '',
nickname: '',
...honeypotDefaults,
});
const { flash } = usePage<{ flash?: { success?: string } }>().props;
const { t } = useTranslation('marketing');
const { localizedPath } = useLocalizedRoutes();
const shouldReduceMotion = useReducedMotion();
@@ -51,16 +76,26 @@ const Kontakt: React.FC = () => {
</div>
)}
<form key={`kontakt-form-${Object.keys(errors).length}`} onSubmit={handleSubmit} className="space-y-4">
<input
type="text"
name="nickname"
value={data.nickname}
onChange={(e) => setData('nickname', e.target.value)}
className="hidden"
tabIndex={-1}
autoComplete="off"
aria-hidden
/>
{honeypot?.enabled ? (
<div className="hidden" aria-hidden>
<input
type="text"
name={honeypot.nameFieldName}
id={honeypot.nameFieldName}
value={data[honeypot.nameFieldName] ?? ''}
onChange={(event) => setData(honeypot.nameFieldName, event.target.value)}
autoComplete="off"
tabIndex={-1}
/>
<input
type="text"
name={honeypot.validFromFieldName}
value={data[honeypot.validFromFieldName] ?? honeypot.encryptedValidFrom}
readOnly
tabIndex={-1}
/>
</div>
) : null}
<div>
<label htmlFor="name" className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2 font-sans-marketing">{t('kontakt.name')}</label>
<input