Skip to content

Commit 45d333e

Browse files
committed
refactor(contact): TSDoc over inline comments
Move the captcha-design rationale into the route handler's TSDoc and drop the inline body/JSX comments, per the project's TSDoc-only comment convention.
1 parent 2d44d47 commit 45d333e

2 files changed

Lines changed: 14 additions & 23 deletions

File tree

apps/sim/app/(landing)/contact/components/contact-form/contact-form.tsx

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,6 @@ export function ContactForm() {
144144
return
145145
}
146146

147-
// Best-effort Turnstile execution: re-run the (invisible) widget on every
148-
// submit, including after an expiry, since reset + execute yields a fresh
149-
// token. If the widget never loaded or execution fails, the token is omitted
150-
// and the server applies its stricter no-captcha rate limit.
151147
let captchaToken: string | undefined
152148
const widget = turnstileRef.current
153149

@@ -172,9 +168,6 @@ export function ContactForm() {
172168
onError: () => {
173169
turnstileRef.current?.reset()
174170
},
175-
// Reset the pre-submit gate only once the mutation settles, so `isBusy`
176-
// stays true continuously (the captcha window then `isPending`) and a
177-
// second click can never slip through to fire a duplicate request.
178171
onSettled: () => {
179172
setIsSubmitting(false)
180173
},
@@ -224,7 +217,6 @@ export function ContactForm() {
224217
className='relative mt-5 flex flex-col gap-4'
225218
noValidate
226219
>
227-
{/* Honeypot */}
228220
<div
229221
aria-hidden='true'
230222
className='pointer-events-none absolute left-[-9999px] h-px w-px overflow-hidden opacity-0'
@@ -333,10 +325,6 @@ export function ContactForm() {
333325
</p>
334326
) : null}
335327

336-
{/*
337-
`Chip` gives its label span `flex-1`; under `fullWidth` that left-aligns the
338-
label, so center it with `justify-center` + a `flex-none` span override.
339-
*/}
340328
<Chip
341329
type='submit'
342330
variant='primary'

apps/sim/app/api/contact/route.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,20 @@ const CAPTCHA_UNAVAILABLE_RATE_LIMIT: TokenBucketConfig = {
3535
const SUCCESS_RESPONSE = { success: true, message: "Thanks — we'll be in touch soon." }
3636
const TOO_MANY_REQUESTS_RESPONSE = { error: 'Too many requests. Please try again later.' }
3737

38+
/**
39+
* Public contact-form endpoint: per-IP rate limit, honeypot drop, captcha, then a
40+
* help-inbox notification plus a best-effort visitor confirmation.
41+
*
42+
* Captcha is server-authoritative — a valid Turnstile token is the only way past
43+
* the stricter fallback bucket, so a caller cannot opt out of the challenge. A
44+
* missing token (widget could not load) or a Cloudflare transport error falls
45+
* back to the tighter no-captcha bucket rather than a free pass; an outright
46+
* invalid token is rejected. That backstop is enforced `failClosed`, so an
47+
* unavailable limiter rejects token-less submits instead of admitting them. No
48+
* `expectedHostname` is pinned: the site key is already domain-bound in
49+
* Cloudflare, and a single-host pin would reject valid self-hosted/preview/apex
50+
* tokens.
51+
*/
3852
export const POST = withRouteHandler(async (req: NextRequest) => {
3953
const requestId = generateRequestId()
4054

@@ -69,20 +83,12 @@ export const POST = withRouteHandler(async (req: NextRequest) => {
6983
return NextResponse.json(SUCCESS_RESPONSE, { status: 201 })
7084
}
7185

72-
// Captcha is server-authoritative: a valid Turnstile token is the only way to
73-
// skip the stricter fallback bucket. A missing token (widget could not load) or
74-
// a Cloudflare transport error falls back to the tighter no-captcha rate limit
75-
// rather than a free pass, so callers cannot opt out of the challenge. An
76-
// outright invalid token is rejected.
7786
if (isTurnstileConfigured()) {
7887
let captchaVerified = false
7988
const token =
8089
typeof captchaToken === 'string' && captchaToken.length > 0 ? captchaToken : null
8190

8291
if (token) {
83-
// No expectedHostname: the Turnstile site key is already domain-bound in
84-
// Cloudflare, and pinning a single hostname here would reject valid tokens
85-
// from self-hosted, preview, and apex-vs-www deployments.
8692
const verification = await verifyTurnstileToken({ token, remoteIp: ip })
8793
if (verification.success) {
8894
captchaVerified = true
@@ -104,9 +110,6 @@ export const POST = withRouteHandler(async (req: NextRequest) => {
104110
}
105111

106112
if (!captchaVerified) {
107-
// Fail closed: this bucket is the only throttle on token-less submits, so
108-
// if the limiter storage is unavailable we reject rather than admit an
109-
// uncaptcha'd request to the email path.
110113
const nocaptchaKey = `public:contact:nocaptcha:${ip}`
111114
const { allowed: nocaptchaAllowed } = await rateLimiter.checkRateLimitDirect(
112115
nocaptchaKey,

0 commit comments

Comments
 (0)