diff --git a/src/lib/components/UKMPEmailForm.svelte b/src/lib/components/UKMPEmailForm.svelte index 83795308b..785166644 100644 --- a/src/lib/components/UKMPEmailForm.svelte +++ b/src/lib/components/UKMPEmailForm.svelte @@ -3,6 +3,8 @@ import { micromark } from 'micromark' import LoadingSpinner from './LoadingSpinner.svelte' import Link from '$lib/components/Link.svelte' + import Turnstile from '$lib/components/Turnstile.svelte' + import { turnstileSiteKey } from '$lib/turnstile' import { slide } from 'svelte/transition' interface Props { @@ -44,6 +46,16 @@ ${userPostcode.toUpperCase()}`) let submitStatus: 'idle' | 'success' | 'error' = $state('idle') let errorMessage = $state('') let confirmingSend = $state(false) + let honeypot = $state('') + let turnstileToken = $state('') + + // Bumped after each submission to remount the widget: Turnstile tokens are + // single-use, so a resubmit with the same token would be rejected. + let turnstileNonce = $state(0) + + // Without a configured site key (e.g. local development) there is no widget + // to wait for, and the server decides whether to accept the submission. + const canSubmit = $derived(!isSubmitting && (!turnstileSiteKey || turnstileToken !== '')) let htmlPreview = $derived(micromark(message)) @@ -178,7 +190,9 @@ ${userPostcode.toUpperCase()}`) senderPostcode: userPostcode, recipient: mp.email, subject: subject.trim(), - message: message.trim() + message: message.trim(), + nickname: honeypot, + turnstileToken }) }) @@ -198,6 +212,10 @@ ${userPostcode.toUpperCase()}`) console.error('Email submission error:', error) } finally { isSubmitting = false + + // The token has now been spent (or rejected) either way — get a fresh one. + turnstileToken = '' + turnstileNonce += 1 } } @@ -214,6 +232,18 @@ ${userPostcode.toUpperCase()}`) onsubmit?.(e) }} > +
+ + +
+

Send this email to {mp.name}?

+ {#key turnstileNonce} + + {/key}