refactor: newsletter signup posts no credential (SEC-14-R1 option a)
Rework PR #15 per security review SEC-14-R1: the client no longer carries an API token. js/newsletter-config.js ships only the non-secret endpoint, enforced https-only at config load time via validateEndpoint() (mirroring the protocol allowlist in js/reading-list.js); js/newsletter.js POSTs email-only with no Authorization header. Failure paths keep the single user-safe message that never leaks token, endpoint, status, or raw body; success still shows the confirmation. CI gains a gitleaks step that fails on any secret hit; README documents the server-side token, the residual signup-abuse risk, and the authoritative server-side validation follow-up.
This commit is contained in:
@@ -17,19 +17,34 @@ vanilla JavaScript.
|
||||
## Newsletter signup
|
||||
|
||||
The signup form on `newsletter.html` POSTs the visitor's email to a serverless
|
||||
endpoint. Everything is configured in one file — `js/newsletter-config.js`:
|
||||
endpoint. The client ships only the endpoint URL — no credential is ever sent
|
||||
in the request:
|
||||
|
||||
- `NEWSLETTER_ENDPOINT` — the serverless endpoint the form POSTs to.
|
||||
- `NEWSLETTER_API_TOKEN` — the API token sent in the `Authorization` header.
|
||||
- `NEWSLETTER_ENDPOINT` — the serverless endpoint the form POSTs to. This is
|
||||
the **only** thing configured in `js/newsletter-config.js`, and it is
|
||||
enforced `https://`-only at config load time and by tests (mirroring the
|
||||
protocol allowlist in `js/reading-list.js`).
|
||||
|
||||
**Security:** a real API token must never be committed to the repository. The
|
||||
committed default is an empty placeholder; the deployer sets the real token in
|
||||
`js/newsletter-config.js` at deploy time, and only then. The page logic reads
|
||||
the token from this config module and never hardcodes one.
|
||||
**Authentication is server-side only.** The serverless function reads its API
|
||||
token from platform env/secrets at deploy time — never from this repository and
|
||||
never from any client-served asset. Do not add a token to `js/newsletter-config.js`
|
||||
or anywhere else in the tree; anything committed here is public.
|
||||
|
||||
When the token is missing or the endpoint rejects it, the visitor sees a fixed,
|
||||
user-safe error message — the token or endpoint internals are never surfaced.
|
||||
After a successful signup a confirmation message is shown.
|
||||
When the endpoint is unavailable or rejects the submission, the visitor sees a
|
||||
fixed, user-safe error message — the server-held token, the endpoint, the status
|
||||
code, and any raw response body are never surfaced. After a successful signup a
|
||||
confirmation message is shown.
|
||||
|
||||
**Server-side validation (required follow-up on the function, not this diff):**
|
||||
the serverless function must authoritatively validate submissions before
|
||||
processing — email syntax, length caps, pinned `Content-Type`, and rejection of
|
||||
unknown fields. Client-side checks here are UX only and are bypassable by
|
||||
direct API calls.
|
||||
|
||||
**Residual signup-abuse risk (accepted, out of scope):** this pass adds no spam
|
||||
filtering or captcha. Scripted signups remain possible, so the serverless
|
||||
function must mitigate abuse server-side with rate limiting and an origin
|
||||
allowlist.
|
||||
|
||||
## Reading list
|
||||
|
||||
@@ -79,11 +94,11 @@ contact.html Contact page
|
||||
newsletter.html Newsletter signup page
|
||||
css/style.css Global + responsive styles
|
||||
data/reading-list.js Curated reading list data (edit to add links)
|
||||
js/newsletter-config.js Newsletter endpoint + API token (edit at deploy time)
|
||||
js/newsletter.js Newsletter signup wiring: POST + user-safe errors (tested)
|
||||
js/newsletter-config.js Newsletter endpoint (non-secret, https-only) — edit at deploy time
|
||||
js/newsletter.js Newsletter signup wiring: credential-free POST + user-safe errors (tested)
|
||||
js/mailto.js Pure mailto: URL builder (unit tested)
|
||||
js/contact.js Contact form wiring (browser + tests)
|
||||
js/reading-list.js Reading list renderer: data file -> grouped HTML (tested)
|
||||
tests/ Node built-in test suite
|
||||
.gitea/workflows/ ci.yml runs `npm test` on PRs and pushes to main
|
||||
.gitea/workflows/ ci.yml runs `npm test` plus a gitleaks secret scan (fails on any hit) on PRs and pushes to main
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user