source: Klonkt/package.json@ 603d246

main
Last change on this file since 603d246 was 9e9e6f9, checked in by Robin <roboburr@…>, 7 weeks ago

Feature: paid posts slice 3, patron link + passkey (cookie-less)

The registration leg of the paid-posts flow (klonkt-demo-aki). A
visitor links once via Patreon and gets a pseudonymous passkey entitlement,
with no session and no patron identity stored.

  • Dependency (approved): @simplewebauthn/server for verification, plus @simplewebauthn/browser vendored (UMD) so the page loads it with no CDN.
  • New paid_entitlements table: {passkey, site, proven cents, expiry}. No name, e-mail or Patreon id, ever.
  • Cookie-less throughout: the OAuth state and the WebAuthn challenge travel in signed blobs (CryptoBox), so nothing is kept between requests.
  • Flow: GET /paid/link -> Patreon authorize; GET /paid/callback verifies the patron (verifyPatron exchanges the code, reads identity?include=memberships.campaign, checks patron_status + currently_entitled_amount_cents against the post's price), then hands out registration options + a signed blob carrying the challenge and proven cents; POST /paid/register verifies the passkey and stores the entitlement. The patron token is used once and discarded.

The gate button and the per-post unlock (assertion) are slice 4; this
leg is what that flow calls to register a passkey on demand.

Changed files:
package.json, package-lock.json

  • @simplewebauthn/server + @simplewebauthn/browser

src/assets/vendor/simplewebauthn-browser.umd.min.js

  • vendored browser UMD (no CDN)

src/config/database.js

  • paid_entitlements table (no patron identity)

src/services/PaidPatreonService.js

  • pickCampaignMembership (pure), verifyPatron (exchange + identity)

src/server.js

  • mount /paid before the /:slug catch-all

New file:
src/services/PasskeyService.js

  • registration options + verify (lib) + entitlement store/prune

src/routes/paid.js

  • link / callback / register (cookie-less)

src/views/pages/paid-passkey.ejs, paid-result.ejs

  • passkey creation + not-a-supporter pages

test/paid-patron.test.js

  • membership parse, patron exchange (mock), options challenge, entitlement store/expiry/prune/delete, no-identity-columns

-robo
Co-Authored-By: Claude Opus 4.8 <noreply@…>

  • Property mode set to 100644
File size: 1.2 KB
Line 
1{
2 "name": "klonkt",
3 "version": "1.6.0-dev",
4 "description": "Klonkt — self-hosted multi-site music & blog platform (solo, hub or circles). Node + SQLite + htmx.",
5 "license": "AGPL-3.0-or-later",
6 "type": "module",
7 "main": "src/server.js",
8 "scripts": {
9 "start": "node src/server.js",
10 "dev": "node --watch src/server.js",
11 "test": "node --test",
12 "migrate": "node src/db/migrate.js",
13 "reset-admin": "node scripts/reset-admin.mjs",
14 "backfill:durations": "node scripts/backfill-durations.mjs"
15 },
16 "dependencies": {
17 "@resvg/resvg-js": "^2.6.2",
18 "@simplewebauthn/browser": "^13.3.0",
19 "@simplewebauthn/server": "^13.3.2",
20 "bcryptjs": "^2.4.3",
21 "better-sqlite3": "^11.3.0",
22 "body-parser": "^1.20.2",
23 "dotenv": "^16.3.1",
24 "ejs": "^3.1.9",
25 "express": "^4.18.2",
26 "express-rate-limit": "^7.4.1",
27 "express-session": "^1.17.3",
28 "ffmpeg-static": "^5.2.0",
29 "fluent-ffmpeg": "^2.1.3",
30 "helmet": "^7.1.0",
31 "htmx.org": "1.9.12",
32 "marked": "^11.1.1",
33 "multer": "^1.4.5-lts.1",
34 "node-webpmux": "^3.2.1",
35 "nodemailer": "^6.9.15",
36 "sanitize-html": "^2.17.3",
37 "uuid": "^9.0.1"
38 },
39 "engines": {
40 "node": ">=20"
41 }
42}
Note: See TracBrowser for help on using the repository browser.