Personas prove what goes to relays; the server says what it reads
FEP-521a and FEP-8b32. Every persona has an Ed25519 key of its own (Avatar.SigningKey; migration 014 gives the earlier ones theirs), named in its actor's assertionMethod as a Multikey, the terms defined in the actor's own context. A persona's activity going to a relay carries an eddsa-jcs-2022 proof (JSON canonicalised by RFC 8785, Jcs), so what Activity-Relay forwards reaches Mastodon, which verifies it with its own code. Nothing else carries one: Mitra takes a proof over the HTTP signature and refuses one by a key it has not read, without reading the actor again. Received: an actor's own Multikeys are kept, and a forwarded activity whose proof one of them verifies is taken as it came instead of being read again from its origin. Discovery: WebFinger for the server's origin links its instance actor (FEP-d556), NodeInfo links it as the application actor (FEP-2677), and actors name RFC 9421 under implements (FEP-844e). Checked live: relay 16 (Activity-Relay's forward of alice's post reaches Mastodon), Mitra, GoToSocial and Mastodon unchanged (165 in all). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
c47b6e5533
commit
9ab87b2779
22 files changed
+702
-30
No files matched your search
+13
-6
@@ -825,7 +825,10 @@ without a port, before it gives out its OAuth client.
|
||||
### Mitra 5.9.1
|
||||
|
||||
- Signs its deliveries with RSA (draft-cavage) and adds an FEP-8b32 proof made with its Ed25519 key (FEP-521a), which
|
||||
PrivaPub does not verify yet; the HTTP signature is enough for what it delivers itself.
|
||||
PrivaPub verifies when the activity comes forwarded; the HTTP signature is enough for what it delivers itself.
|
||||
- **Prefers a proof to the HTTP signature:** an activity delivered with a proof by a key Mitra has not read is refused
|
||||
(401, "key not found in cache"), and Mitra does not read the actor again. So nothing PrivaPub delivers directly carries
|
||||
a proof; only what goes to relays does.
|
||||
- Its Mastodon API resolves an account elsewhere only when the search is not limited to a type
|
||||
(`/api/v2/search?resolve=true`, no `type=accounts`); reactions go through Pleroma's route
|
||||
(`PUT /api/v1/pleroma/statuses/:id/reactions/:emoji`).
|
||||
@@ -840,12 +843,16 @@ without a port, before it gives out its OAuth client.
|
||||
follower whose actor ends in `/relay` (LitePub's way) gets an `Announce` instead.
|
||||
- **aode-relay** takes either kind and announces the post from its own actor.
|
||||
- A forwarded post carries its author's LD signature when Mastodon wrote it; PrivaPub does not verify LD signatures,
|
||||
so it reads every relayed post again from its origin (one signed request each). Verifying them, or FEP-8b32 proofs,
|
||||
would save that request.
|
||||
- **Pasture evidence (2026-10-05, `tools/pasture/scenarios/relay.sh`):** 13 checks pass: PrivaPub's instance actor
|
||||
so it reads such a relayed post again from its origin (one signed request each). One carrying a FEP-8b32 proof by its
|
||||
author's Ed25519 key (Mitra's, Fedify's, PrivaPub's) is taken as it came.
|
||||
- Mastodon 4.7 takes what Activity-Relay forwards only with an LD signature or a FEP-8b32 proof; personas' activities
|
||||
going to a relay carry a proof, so their public posts reach Mastodon through it too. Mastodon reads a known account's keys again at
|
||||
most daily, so a persona's key reaches a server that held its actor before at its next refresh.
|
||||
- **Pasture evidence (2026-10-06, `tools/pasture/scenarios/relay.sh`):** 16 checks pass: PrivaPub's instance actor
|
||||
subscribes to each relay and takes its Accept; Mastodon subscribes; a public post of a Mastodon account nobody here
|
||||
follows reaches the federated timeline, forwarded by Activity-Relay and announced by aode-relay (as its author's,
|
||||
never as the relay's boost), and nobody's home; nothing of a persona's goes to a relay.
|
||||
never as the relay's boost), and nobody's home; a persona's public post goes to the relays, nothing less public, and
|
||||
reaches Mastodon through both (forwarded on its proof, and announced).
|
||||
|
||||
### Smithereen 1.0.3
|
||||
|
||||
@@ -1165,7 +1172,7 @@ snapshots; `/api/privapub/v1/cdns` and `/cdns/:domain` group servers by CDN, wee
|
||||
| 400 vs 401 | A 400 or 401 makes Mastodon 4.7 and WordPress retry with the other scheme | 401 only for signature failures (we do this); 400 only for bodies that are really malformed | P1 (keep) |
|
||||
| Temporary key failure | Mastodon answers 503 | We should answer 503 too, and treat a 503 as a retry in delivery | P2 |
|
||||
| Keys | `publicKey` can be an array (Mastodon 4.6). FEP-521a `assertionMethod` Multikey is FINAL (Ed25519 `z6Mk…`). GoToSocial key ids have no `#` and point at a stub. | Read all of these | P2 |
|
||||
| Integrity proofs | FEP-8b32 `eddsa-jcs-2022`: JCS, no JSON-LD. Sent by Mitra, Streams, Hubzilla, Fedify and others; Mastodon verifies them from 4.7 | Verify, so relayed or forwarded objects need no refetch | P2 |
|
||||
| Integrity proofs | FEP-8b32 `eddsa-jcs-2022`: JCS, no JSON-LD. Sent by Mitra, Streams, Hubzilla, Fedify and others; Mastodon verifies them from 4.7; Mitra prefers a proof to the HTTP signature and refuses one by a key it has not read | Verify, so relayed or forwarded objects need no refetch. **Done 2026-10-06**, both ways: personas' activities to relays carry one, forwarded ones with a valid proof are taken as they came | P2 |
|
||||
| LD signatures | Mastodon still sends `RsaSignature2017` | Ignore, and refetch from origin (we do) | — |
|
||||
| Query string | GoToSocial, Akkoma 3.20 and Misskey 2026.10 sign it; GoToSocial retries without it | Verify both ways | P1 |
|
||||
| `hs2019` | The algorithm comes from the key; some senders hash with SHA-512 | Try rsa-sha256, then sha512 | P2 |
|
||||
|
||||
+9
-5
@@ -686,16 +686,20 @@ it, raw where it doesn't.
|
||||
- RFC 9421 inbound (RSA and Ed25519, Content-Digest): **RSA done 2026-10-05** (PKCS#1 v1.5 and PSS, Content-Digest,
|
||||
deliveries and signed fetches); Ed25519 waits for FEP-521a keys;
|
||||
- outbound double-knock, remembered per host;
|
||||
- `publicKey` arrays and FEP-521a Multikey;
|
||||
- FEP-8b32 proof verification;
|
||||
- `publicKey` arrays and FEP-521a Multikey: Multikeys **done 2026-10-06** (each persona's Ed25519 key published, peers'
|
||||
read);
|
||||
- FEP-8b32 proofs: **done 2026-10-06** (`eddsa-jcs-2022` on a persona's activity going to a relay, and only there:
|
||||
Mitra refuses a proof by a key it has not read and does not read the actor again; a forwarded activity with a
|
||||
proof its actor's key verifies is taken without reading it again; Mastodon accepts PrivaPub's, so Activity-Relay's
|
||||
forwards reach it);
|
||||
- `hs2019` with SHA-512.
|
||||
- **Discovery:**
|
||||
- a relay client for both relay styles: **done 2026-10-05/06** (`Federation:Relays`; forwarded posts read again
|
||||
from their origin, announces unwrapped; personas' public posts sent to them, owner decision; checked live against
|
||||
Activity-Relay and aode-relay). Mastodon drops what Activity-Relay forwards without an LD signature or FEP-8b32
|
||||
proof;
|
||||
- instance actor discovery (FEP-d556, FEP-2677);
|
||||
- `implements` (FEP-844e).
|
||||
proof, which personas' activities now carry;
|
||||
- instance actor discovery (FEP-d556, FEP-2677): **done 2026-10-06**;
|
||||
- `implements` (FEP-844e): **done 2026-10-06** (RFC 9421, on the instance actor and as every actor's `generator`).
|
||||
- **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), grouped notifications.
|
||||
|
||||
Reference in new issue
Block a user