From a1c4adc4b1d1defe60d0c28af6cd1321073dd5be Mon Sep 17 00:00:00 2001 From: Denshooter Date: Sat, 22 Feb 2025 21:34:45 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20honeypot=20and=20timestamp?= =?UTF-8?q?=20checks=20to=20form=20submission?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/Contact.tsx | 55 +++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/app/components/Contact.tsx b/app/components/Contact.tsx index 28cfd2f..442b032 100644 --- a/app/components/Contact.tsx +++ b/app/components/Contact.tsx @@ -18,11 +18,14 @@ export default function Contact() { message: "", type: "success", }); + // Record the time when the form is rendered + const [formLoadedTimestamp, setFormLoadedTimestamp] = useState(Date.now()); useEffect(() => { + setFormLoadedTimestamp(Date.now()); setTimeout(() => { setIsVisible(true); - }, 350); // Delay to start the animation after Projects + }, 350); }, []); async function onSubmit(e: React.FormEvent) { @@ -31,16 +34,44 @@ export default function Contact() { const form = e.currentTarget as HTMLFormElement; const formData = new FormData(form); + // Honeypot check: if the hidden field has a value, it's likely a bot. + const honeypot = formData.get("hp-field"); + if (honeypot) { + setBanner({ + show: true, + message: "Bot detected", + type: "error", + }); + setTimeout(() => { + setBanner((prev) => ({ ...prev, show: false })); + }, 3000); + return; + } + + // Time based anti-bot check: + // Read the timestamp from the hidden field and ensure at least 3 seconds have passed. + const timestampStr = formData.get("timestamp") as string; + const timestamp = parseInt(timestampStr, 10); + if (Date.now() - timestamp < 3000) { + setBanner({ + show: true, + message: "Please take your time filling out the form.", + type: "error", + }); + setTimeout(() => { + setBanner((prev) => ({ ...prev, show: false })); + }, 3000); + return; + } + const data: ContactFormData = { name: formData.get("name") as string, email: formData.get("email") as string, message: formData.get("message") as string, }; - // Convert FormData to a plain object const jsonData = JSON.stringify(data); - //prevent multiple submissions const submitButton = form.querySelector("button[type='submit']"); if (submitButton) { submitButton.setAttribute("disabled", "true"); @@ -65,6 +96,7 @@ export default function Contact() { }, 3000); } } + return (
{banner.show && (
{banner.message}
)}
+ {/* Honeypot field: should remain empty */} + + {/* Hidden timestamp field to check how fast the form was filled */} +