Commit Graph

8 Commits

Author SHA1 Message Date
156adeab59 Validate email addresses on both public form endpoints
The ROI calculator accepted the email field with no validation at all and
stored whatever arrived, which is where the spam submissions were putting
shell-command payloads. Nothing was executable — there is no child_process
or eval in the codebase and all writes are parameterized — but the junk was
being persisted, and the field is the obvious place to stop it.

Adds security.validateEmail(), deliberately stricter than RFC 5322: the
local part is limited to the characters real addresses use, which excludes
every shell metacharacter (; | & ` $ ( ) < > \ " ' space) and CSV-injection
lead-ins. Also rejects control characters (including the CR/LF used for
mail-header injection), caps lengths at 254/64/253, rejects non-strings,
and normalizes to trimmed lowercase before storage.

Applied to /api/calculate (optional field — empty is fine, present must be
valid) and to /api/leads, replacing its much weaker regex. The client
mirrors the check for immediate feedback; the server remains authoritative.

Also hardens the /api/leads required-field checks, which called .trim() on
unvalidated input and returned a 500 rather than a 400 when a bot posted a
non-string.

Trade-off: RFC-legal but vanishingly rare addresses (foo!bar$baz@x.com, a
leading + in the local part) are rejected. Those characters are the
injection surface.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 08:25:22 -04:00
04ef642775 Add abuse protection to the ROI calculator form
The calculator endpoint was open to anyone, and it has been collecting
spam submissions. Add a layered guard that runs before anything is
written to the DB or sent to the AI provider:

- Cloudflare Turnstile CAPTCHA, verified server-side (active when
  TURNSTILE_* keys are configured; fails closed if unverifiable)
- Honeypot field that only bots fill in
- Signed, single-use form token enforcing a 4s minimum fill time
- Per-IP rate limiting (5 per 10 min, 25 per 24h)

Layers 2-4 need no configuration and work on their own, so submissions
are throttled immediately; adding Turnstile keys upgrades it to a full
challenge. Blocked submissions now stop the flow client-side instead of
silently showing a result.

Also sets `trust proxy` for correct client IPs behind nginx, caps the
JSON body at 32kb, and fixes a latent ReferenceError in the
"AI not configured" branch that called saveCalcSubmission() before the
variables it closes over were declared.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 07:13:14 -04:00
b26903c4ee Hide AI recommendation from results view; keep DB capture
AI text is still generated and saved to calc_submissions for internal
follow-up, but no longer displayed to the user — keeps the detailed
analysis behind the product sign-up wall.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 11:12:02 -04:00
8a369f6a57 Add calculator UX enhancements and submission tracking
- Button loading spinner + disable on submit to prevent duplicate AI calls
- Email field and opt-in consent checkbox on calculator form (checked by default)
- Privacy assurance blurb below opt-in
- Refinement blurb on results screen explaining live cash-flow optimization
- calc_submissions SQLite table stores form inputs, computed results, AI text, email, opt-in
- GET /api/calc-submissions endpoint (x-admin-key protected) to retrieve submissions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 10:58:19 -04:00
bf70efc0d7 Add OpenAI-compatible AI investment advisor to benefit calculator
- server.js: add /api/calculate endpoint using openai SDK with configurable
  AI_API_URL, AI_API_KEY, AI_MODEL, AI_DEBUG env vars (works with any
  OpenAI-compatible provider: NVIDIA NIM, Together AI, Groq, Ollama, etc.)
- app.js: make calculator submit handler async; call /api/calculate with
  graceful fallback to client-side generated text if AI is unavailable
- package.json: add openai and dotenv dependencies
- AI_SETUP.md: rewrite to document new unified env var config with provider examples

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 10:05:41 -04:00
ba9ddee99d Add interest income benefit calculator widget to hero
- New "✦ Calculate Your Interest Income Potential" button between hero CTAs
  with gradient border styling distinct from primary/ghost buttons
- Modal overlay collects: homesites, property type, annual dues + frequency,
  reserve fund balance, and 2025 actual interest income
- Conservative calculation model: 4.0% HYSA for operating cash, 4.25% CD
  ladder for 65% of investable reserves; operating multiplier varies by
  payment frequency (monthly 10%, quarterly 20%, annual 35%)
- Results screen shows animated dollar counter, operating vs reserve
  breakdown, AI-style narrative recommendation, and direct CTA to signup
- Modal closes on backdrop click or Escape key; CTA closes modal and
  scrolls to early access signup form

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 09:49:18 -04:00
4f99e8c71a Replace hero mockup with auto-rotating screenshot carousel
- Swap static dashboard card for 3-slide image carousel in hero section
- Slides auto-advance every 4.5s, pause on hover, support manual prev/next and dot navigation
- Add carousel CSS with fade transition, dot indicators, and glow border treatment
- Add carousel JS with goTo/prev/next/auto-rotate logic
- Images expected at img/screenshot-dashboard.png, img/screenshot-cashflow.png, img/screenshot-capital.png

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 14:42:05 -04:00
e922e2dbd3 Initial commit of existing project 2026-03-03 08:58:15 -05:00