Consolidate audit-fixes branch: webhooks, integrations, and deploy hardening
Batch commit of the pending working tree on security/audit-fixes-2026-07. Major areas: - Outbound webhooks / Zapier: schema + signed delivery with retries, public v1 API (REST-hook subscribe/unsubscribe), settings UI, cron drain. - Deploy hardening: email via SMTP2GO (Resend fully removed), verified DB TLS (DATABASE_SSL=require + DATABASE_CA), storage fails loud in production when Spaces is unconfigured instead of silently using ephemeral disk. - Integrations & features (concurrent work): accounting (QuickBooks/Xero), e-signature (DocuSign/Dropbox Sign), PayPal, geocoding/maps, onboarding, expanded legal pages. - DB migrations 0006–0009. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
969d5d4c8a
commit
c9968531e4
+6
-6
@@ -3,7 +3,7 @@
|
||||
> **⚠️ TREAT ALL SECRETS IN `.env.local` AS COMPROMISED.**
|
||||
> This project was distributed in a transfer package, which means every secret
|
||||
> that was present in `.env.local` — the `DATABASE_URL` / Postgres password,
|
||||
> `BETTER_AUTH_SECRET`, and any Stripe / OpenAI / Resend API keys — has left a
|
||||
> `BETTER_AUTH_SECRET`, and any Stripe / OpenAI / SMTP credentials — has left a
|
||||
> trusted boundary and **must be treated as leaked**. Rotate **all** of them
|
||||
> before any production deployment or client handoff. Do not assume "it was only
|
||||
> a zip" — assume the file is public.
|
||||
@@ -26,14 +26,14 @@ ever appeared in the distributed `.env.local`.
|
||||
- [ ] **Stripe** — roll the secret key (and restricted keys), and rotate the
|
||||
webhook signing secret in the Stripe Dashboard.
|
||||
- [ ] **OpenAI** — revoke the leaked API key and issue a new one.
|
||||
- [ ] **Resend** — revoke the leaked API key and issue a new one.
|
||||
- [ ] **SMTP (SMTP2GO)** — rotate the SMTP password / credentials.
|
||||
- [ ] **`CRON_SECRET`** — set a strong random value (the cron routes now fail
|
||||
closed if it is unset):
|
||||
```bash
|
||||
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
||||
```
|
||||
Configure the same value in Vercel so Cron sends
|
||||
`Authorization: Bearer <CRON_SECRET>`.
|
||||
Configure the same value in your host's env (e.g. DigitalOcean App Platform)
|
||||
so the scheduled tasks send `Authorization: Bearer <CRON_SECRET>`.
|
||||
- [ ] **Google OAuth** — if the client secret was present in the transfer,
|
||||
rotate it in the Google Cloud Console.
|
||||
|
||||
@@ -42,7 +42,7 @@ ever appeared in the distributed `.env.local`.
|
||||
- [ ] **Never commit `.env.local`** (or any real `.env*` with live values).
|
||||
Confirm it is listed in `.gitignore`.
|
||||
- [ ] Store production secrets in the deployment platform's encrypted env-var
|
||||
store (e.g. Vercel Project Settings → Environment Variables), not in files.
|
||||
store (e.g. DigitalOcean App Platform → Environment Variables), not in files.
|
||||
- [ ] Use distinct secrets per environment (dev / preview / production).
|
||||
|
||||
## 3. Database / TLS
|
||||
@@ -64,7 +64,7 @@ The following hardening has already been applied in this codebase:
|
||||
`require`), with optional `DATABASE_CA`.
|
||||
- **Constant-time cron auth** — `lib/cron-auth.ts` performs a `timingSafeEqual`
|
||||
bearer-token comparison that **fails closed** when `CRON_SECRET` is unset. All
|
||||
cron routes (`daily`, `late-fees`, `lease-expiry`, `rent-reminders`) now use it
|
||||
cron routes (`daily`, `late-fees`, `follow-ups`) now use it
|
||||
and share the standard `Authorization: Bearer` scheme.
|
||||
- **Security headers** — `next.config.ts` sets a strict baseline on all routes:
|
||||
`X-Content-Type-Options`, `X-Frame-Options: DENY`, `Referrer-Policy: no-referrer`
|
||||
|
||||
Reference in New Issue
Block a user