feat: phase 5 contact form — hCaptcha, honeypot, rate limit, notify
Working /contact POST flow: honeypot → hCaptcha server-verify → field validation → SlowAPI 3/hr IP rate limit → contact_submissions row → best-effort Resend notification (Reply-To = submitter) → generic success page. Spam paths don't persist and render the same success page (anti-enumeration). Send failures don't break the request path — the row is already durable. New services: HCaptchaService (async httpx + dev fallback), ContactService. EmailService gains send_contact_notification. Production config validator now requires ADMIN_CONTACT_EMAIL, HCAPTCHA_SECRET, HCAPTCHA_SITE_KEY. 23 new tests, all green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
31
app/templates/public/contact_sent.html
Normal file
31
app/templates/public/contact_sent.html
Normal file
@@ -0,0 +1,31 @@
|
||||
{#
|
||||
Contact success page — rendered after a successful POST /contact
|
||||
OR after a silent spam rejection (honeypot tripped / hCaptcha
|
||||
failed). Copy MUST stay identical across those branches so a bot
|
||||
operator can't use the response body to distinguish "we accepted
|
||||
your message" from "we filed your message under spam".
|
||||
|
||||
Context:
|
||||
- active_nav : "contact"
|
||||
#}
|
||||
{% extends "public/base.html" %}
|
||||
|
||||
{% block title %}Message sent — Chicken Babies R Us{% endblock %}
|
||||
{% block meta_description %}Thanks for reaching out to Chicken Babies R Us.{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<article class="page-article">
|
||||
<header class="page-article__header">
|
||||
<h1 class="page-article__title">Thanks for reaching out</h1>
|
||||
</header>
|
||||
|
||||
<p>
|
||||
Your message is on its way to Head Hen. We'll get back to you as
|
||||
soon as the chickens let us.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a class="btn btn--primary" href="/">Back to the home page</a>
|
||||
</p>
|
||||
</article>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user