Feature: paid posts slice 1, owner Patreon config (encrypted)
The site owner can connect their OWN Patreon campaign for paid posts
(klonkt-demo-aki), premium-gated in Beheer. Client id/secret, campaign
id and the creator access/refresh token are stored ENCRYPTED at rest
(new CryptoBox AES-256-GCM helper, key from PAID_SECRET), so a database
dump leaks nothing usable; the token auto-refreshes. Separate from
Klonkt Premium's license flow, which is untouched. Degrades gracefully:
without PAID_SECRET the admin page refuses to save rather than storing
plaintext. Nothing patron-facing yet (posts.paid + unlock come in
slices 2 to 4), so no changelog entry.
CryptoBox also carries the cookie-less signed-blob helper (signBlob/
verifyBlob) that slices 3 and 4 reuse for the OAuth state and the
WebAuthn challenge.
Changed files:
src/config/database.js
- paid_patreon table (site_id PK, secrets encrypted)
src/server.js
src/views/pages/admin.ejs
- "Betaalde posts" button in Beheer
New file:
src/services/CryptoBox.js
- aes-256-gcm encrypt/decrypt + HMAC signBlob/verifyBlob
src/services/PaidPatreonService.js
- owner config CRUD (encrypted), token refresh, creatorAccessToken
src/routes/admin-paid.js
- premium-gated config form (GET/POST/disconnect)
src/views/pages/admin-paid.ejs
test/paid-patreon.test.js
- crypto roundtrip, no-plaintext-in-DB, refresh, blob signing
docs/paid-posts-design.md, docs/privacy-betaalde-posts.md
- concurrency property documented
-robo
Co-Authored-By: Claude Opus 4.8 <noreply@…>