R9 Web Push, then the honest version: VAPID key, push subscriptions, encrypted pushes, 4.5.0 advertised

The server's VAPID key (PushKeys, made on first need, in Mongo) is the instance API's vapid.public_key and every app's
vapid_key. /api/v1/push/subscription (POST, GET, PUT, DELETE) keeps one subscription per access token, so per persona;
every notification kept (never a filtered one) is queued as a SendPush job for the subscriptions whose alert and policy
admit it, and sent through the `push` client (the safe handler, https only) encrypted as RFC 8291 aes128gcm or the
aesgcm draft with an ES256 VAPID JWT. 404/410 delete the subscription, 429/5xx/timeouts retry, other answers drop the
push. Subscriptions end with their tokens (revocation, sessions ended, suspension, deletion, a restore); backups hold
neither keys nor subscriptions. The walk of every Mastodon 4.3-4.5 client route (docs/MASTODON-API.md) added
conversations/:id/unread, domain_blocks/preview, v2 notifications clear and PUT policy, /oauth/userinfo and stubs, so both
instance APIs now say 4.5.0 (compatible; PrivaPub <release>). The pasture gets a push sink (pushsink.test) and
scenarios/push.sh in batch A.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WpVCoDeM1qUTRp4fXQdfof
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-10-18 09:18:26 +02:00
1 parent 87529bca49
commit 9b792042e6
43 files changed
+2079 -49

No files matched your search

+22 -2
View File
@@ -154,6 +154,24 @@ Written 2026-10-01 from the original 2023 code, the decePubClient UI, a federati
settings form; a `Move` carries the persona's endorsement and note to the new account; featured tags, notes and
endorsements are left out of the persona archive (Mastodon's layout has none), its `following_accounts.csv` now
carries notify and languages.
- R9 Web Push, then the honest version (built 2026-10-18, not yet deployed; `tools/pasture/scenarios/push.sh` with the
pasture's own push service, `tools/pasture/pushsink`): the server's VAPID key (`PushKeys`, made on first need, in
Mongo, never in a backup), Mastodon's `/api/v1/push/subscription` (create, show, update, delete; one subscription
per access token, so per persona), every notification kept (never a filtered one) pushed to the subscriptions whose
alert and policy admit it, as `SendPush` jobs through the `push` client, encrypted as RFC 8291 `aes128gcm` or the
`aesgcm` draft, signed with an ES256 VAPID JWT; subscriptions end with their tokens (revocation, sessions ended,
suspension, deletion, a restore). Then the walk of every Mastodon 4.3, 4.4 and 4.5 client route
(`docs/MASTODON-API.md`), with what it found missing built (`conversations/:id/unread`, `domain_blocks/preview`, v2
`notifications/clear` and `PUT` policy, `/oauth/userinfo` and the `profile` scope on `verify_credentials`) or answered
as stubs (annual reports by year, API registration 403, e-mail confirmation, peer search, async refreshes), and both
instance APIs advertising `4.5.0 (compatible; PrivaPub <release>)`. Chosen while building it, for the owner to
confirm: the payload carries the subscription's own access token, as Mastodon's does (encrypted to that client
alone); what a persona tells itself (its poll ended, the staff's warning) passes the `followed` and `follower` policies
(Mastodon would hold it back); a push service's 4xx other than 404, 410, 408 and 429 drops that push and keeps the
subscription (Mastodon deletes it); the JWT lasts twelve hours (Mastodon's a day); titles are Mastodon's English
subjects and `preferred_locale` is the persona's posting language (no persona has an interface language); six
attempts on the jobs' backoff (Mastodon retries five times); `alerts` answers every alert true or false (Mastodon
echoes those sent); the key lives in Mongo, not in the configuration; `/oauth/userinfo` is served (Mastodon 4.4's).
## Intent
@@ -600,7 +618,8 @@ The first refactor commit is a pure move with namespaces only. Logic changes fol
- `Link` paging on `max_id`, `since_id` and `min_id`; CORS exposes `Link`.
- `Idempotency-Key` honoured on posting statuses.
- **Endpoints:**
- **Instance:** v1 and v2, advertising version `4.2.0 (compatible; PrivaPub)`.
- **Instance:** v1 and v2, advertising version `4.2.0 (compatible; PrivaPub)`. *`4.5.0 (compatible; PrivaPub
<release>)` since R9 (2026-10-18), after the walk in `docs/MASTODON-API.md`.*
- **Accounts:** `verify_credentials`, `update_credentials`, `:id`, `:id/statuses`, `lookup`, `relationships`,
`search`, followers and following, follow and unfollow, `follow_requests`.
- **Statuses:** CRUD, edit, `context`, `history`, `source`, favourite and reblog plus their undos (outbound Like and
@@ -829,7 +848,8 @@ it, raw where it doesn't.
- **Mastodon API:** ~~streaming WebSocket~~ (done 2026-10-05: `/api/v1/streaming` as a WebSocket and as server-sent
events, user, notification, public, hashtag and list streams, each event mapped for its persona; a deletion reaches
only the streams that showed the post), Web Push (gated: outbound traffic to push services; approved 2026-10-17, C R9), grouped
notifications. Then advertise an honest version.
notifications. Then advertise an honest version. *Done in R9 (2026-10-18): Web Push, then `4.5.0 (compatible; PrivaPub
<release>)` once every 4.3, 4.4 and 4.5 client route was served or a named stub (`docs/MASTODON-API.md`).*
- **Backfill:** an author's outbox after following them: **done 2026-10-05** (`OutboxBackfill`, the first page's
public posts, twenty at most, once a day; checked live against Mastodon).
- **Long tail:**