Skip to content

fix: obfuscate mailto email addresses to prevent scraping (#106)#108

Merged
edkranz merged 1 commit intomainfrom
claude/keen-chaplygin-a60738
May 5, 2026
Merged

fix: obfuscate mailto email addresses to prevent scraping (#106)#108
edkranz merged 1 commit intomainfrom
claude/keen-chaplygin-a60738

Conversation

@designbyalex
Copy link
Copy Markdown
Member

@designbyalex designbyalex commented May 4, 2026

Closes #106.

Summary

  • Encode contactEmail / contactCc as base64 at the server→client boundary in components/layout/layout.tsx and decode them in a new <MailtoLink /> client component via useEffect, so addresses never appear in SSR HTML or the hydration payload.
  • Remove the plaintext pennywalker@ssw.com.au and +61 2 9953 3000 link entries from the footer per request — the footer's primary CTA mailto button stays.
  • Implements the fallback approach from the SSW rule when a contact form isn't feasible: https://www.ssw.com.au/rules/avoid-using-mailto-on-your-website

Why

Issue #106 flagged that mailto: href attributes were exposing plaintext email addresses to scrapers. Acceptance criteria called for the email contact to remain usable while removing the plaintext exposure across all occurrences.

What changed

New

  • lib/email-obfuscation.ts — isomorphic base64 encode/decode + buildMailtoHref helper.
  • components/ui/mailto-link.tsx'use client' component that renders <a href="#contact"> server-side and swaps to a real mailto: URL via useEffect after hydration. Forwards refs so it composes with <Button asChild>.

Modified

  • components/layout/layout.tsx — encodes contactEmail / contactCc once and strips the plaintext fields before they reach LayoutProvider.
  • components/layout/layout-context.tsx — exposes encodedContactEmail / encodedContactCc via context.
  • components/blocks/fbc-pricing.tsx, components/blocks/fbc-certification.tsx, components/blocks/fbc-cta-banner.tsx — swap <a href={mailtoLink}>…</a> for <MailtoLink> (still wrapped by <Button asChild>).
  • components/layout/nav/footer.tsx — primary CTA now uses <MailtoLink>; deleted the dead link.href.startsWith('mailto:…') branch and the duplicate contactEmailLink constant.
  • components/layout/nav/header.tsx — removed unused mailtoLink dead code.
  • content/global/index.json — removed pennywalker@ssw.com.au and +61 2 9953 3000 link entries.

Editors keep entering plaintext into the TinaCMS Global → Contact Email field. Encoding is internal.

Test plan

  • pnpm install, pnpm dev, open http://localhost:3000
  • View source: confirm zero matches for pennywalker, adamcogan, 9953 3000, and mailto:
  • Click each CTA (Apply now / Commit / Submit) on Pricing, Certification, CTA Banner, and Footer — verify the email client opens with correct To, CC, Subject, and Body
  • Confirm the footer no longer shows the email or phone-number rows
  • DevTools → Network → main document: search payload for pennywalker / adamcogan — zero matches
  • In TinaCMS admin (/admin), edit Global → Contact Email, save, verify a CTA opens mailto: with the new address
  • pnpm lint clean

🤖 Generated with Claude Code

Encode contact email + cc as base64 at the server→client boundary in
layout.tsx and decode them in a new MailtoLink client component via
useEffect, so addresses never appear in SSR HTML or the hydration
payload. Also remove the plaintext email and phone link entries from
the footer per request — the primary CTA mailto button stays.

Implements the fallback approach from the SSW rule when a contact form
isn't feasible: https://www.ssw.com.au/rules/avoid-using-mailto-on-your-website

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@edkranz
Copy link
Copy Markdown
Member

edkranz commented May 4, 2026

@vercel Deploy?

@edkranz edkranz merged commit 7481b44 into main May 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐛 Bug: Mailto links expose plain-text email addresses

2 participants