RFC 0012 — Fediverse: route HTTP /inbox lifecycle (slice routes 1/N)
- Auteur : EBO (rustwarden)
- Date : 2026-05-10
- Statut : Accepted (auto-revue mainteneur unique 2026-05-10, score 26/35)
- Apps consommatrices concernées : toute app utilisant
rustwarden-corequi veut recevoir les signaux APUpdate{Actor}/Delete{Actor}/Revoke{Membership}envoyés par les serveurs distants. - Plan associé :
docs/plans/2026-05-09-fediverse-identity-federation.md, Phase 4 — clôture HTTP. - Dépendances : RFC 0010 (
FediverseSignalService+SignatureVerifier).
Summary
Exposer la route HTTP POST /inbox (montée par with_fediverse() côté RustwardenBuilder) qui :
- Lit le
Signatureheader HTTP. - Délègue la vérification au
SignatureVerifierinjecté côté config (par défautAlwaysAcceptVerifierpour test/dev — production attend la RFC crypto à venir). - Désérialise le body JSON-LD, dispatch sur le
typede l'activité (Update,Delete,Revoke) vers la méthode correspondante deFediverseSignalService. - Retourne
202 Accepted(livraison asynchrone) ou un code d'erreur explicite (401/400/501).
Les routes auth-flow (5 endpoints) et team-invite (3 endpoints) sont explicitement reportées à des RFCs séparées (0013, 0014) pour rester reviewable.
Motivation
Sans cette RFC, FediverseSignalService (livré par RFC 0010) n'a aucun chemin d'entrée HTTP. Mastodon et compagnie ne peuvent pas notifier l'instance qu'un actor distant a été supprimé / mis à jour, et la promesse « Delete{Actor} → sessions invalidées en moins de 30 s » du master plan reste théorique.
Non-goals
- Pas d'autres routes dans cette RFC (auth-flow et invite restent reportées).
- Pas d'implémentation HTTP-Sig RFC 9421 réelle — seul le trait
SignatureVerifier(RFC 0010) est consommé. La route refuse toute requête si leSignatureheader est absent ; en modeAlwaysAcceptVerifier, la signature elle-même n'est pas vérifiée — le warningtracing::warndeAlwaysAcceptVerifierest suffisant pour signaler la non-prod. - Pas de UI ni de page admin pour visualiser les signaux reçus.
- Pas de support
AuthorizationBearer (les inbox AP ne s'authentifient pas via Bearer mais via HTTP-Sig). - Pas de gestion des activités inconnues au-delà du
501 Not Implementeddocumenté.
API proposée
Handler
#[derive(Debug, Deserialize)] pub struct InboxActivity { #[serde(rename = "type")] pub kind: String, pub actor: Option<String>, pub object: Option<serde_json::Value>, pub id: Option<String>, } /// `POST /inbox` handler. /// /// Reads `Signature` header, delegates verification to the configured /// `SignatureVerifier`, then dispatches based on `kind`. pub async fn handle_inbox( Extension(state): Extension<Arc<InboxState>>, Extension(db): Extension<DatabaseConnection>, headers: axum::http::HeaderMap, body: axum::body::Bytes, ) -> Result<axum::http::StatusCode, FediverseError>;
InboxState
pub struct InboxState { pub verifier: Arc<dyn SignatureVerifier>, pub config: FediverseConfig, }
Dispatch table
type du body | Action | Méthode service |
|---|---|---|
Update (object.type = Person) | upsert remote_identities | apply_update_actor |
Delete (object = ap_id de l'actor) | flip disabled_at | apply_delete_actor |
Revoke (object.type = TeamMembership) | drop team_members row | apply_revoke_membership |
| autre | log + 501 Not Implemented | — |
Réponses HTTP
202 Acceptedsur dispatch réussi.400 Bad Requestsi JSON invalide ou champs requis manquants.401 Unauthorizedsi leSignatureheader est absent ou siSignatureVerifier::verifyretourneErr.501 Not Implementedsikindn'est pas dans la table de dispatch.
Wiring RustwardenBuilder::with_fediverse
Le builder stocke un nouveau champ signature_verifier: Option<Arc<dyn SignatureVerifier>> (par défaut Arc::new(AlwaysAcceptVerifier)). La méthode chaînable .with_signature_verifier(verifier) permet aux apps consommatrices de plugger leur impl HTTP-Sig réelle dès qu'elle existe.
Analyse de compatibilité
-
Non-breaking : nouvelle route + champ optionnel dans
RustwardenBuilder. - Aucun changement de schéma DB (RFC 0010 a déjà tout fait).
- Aucune API publique existante n'est modifiée.
Alternatives considérées
Alternative A (recommandée) — /inbox unique avec dispatch par type
Pros : conforme à AP/Mastodon (single inbox per actor + shared inbox). Simple.
Cons : un changement de format AP futur (e.g. Tombstone au lieu de Delete) demande de modifier le dispatch.
Alternative B — /inbox/{type} (route par activité)
Cons : non-conforme AP, casse Mastodon.
Rejeté.
Alternative C — Pas de route, exposer le service en lib seulement
Cons : annule l'intérêt de RFC 0010 pour les apps qui veulent un drop-in.
Rejeté.
Alternative D — Inclure auth-flow + team-invite dans la même RFC
Cons : ~1500 lignes, surface de revue énorme.
Rejeté.
Testing plan
8 tests :
inbox_returns_202_for_valid_update_actor— body bien formé, dispatch réussi.inbox_returns_202_for_valid_delete_actor.inbox_returns_202_for_valid_revoke_membership.inbox_returns_401_when_signature_header_missing.inbox_returns_401_when_verifier_rejects— fake verifier qui retourne Err.inbox_returns_400_for_invalid_json.inbox_returns_501_for_unknown_activity_type.inbox_smoke_test_with_always_accept_verifier.
Tests via axum::Router + tower::ServiceExt::oneshot.
Migration guide
### Added (rustwarden-core, feature `experimental-fediverse`) - Route HTTP `POST /inbox` (montée par `with_fediverse()`). - Type public `InboxState`. - Méthode chaînable `RustwardenBuilder::with_signature_verifier(verifier)`. ### Migration steps 1. Aucun changement requis pour les apps qui n'activent pas la feature. 2. Les apps fediverse existantes : par défaut `AlwaysAcceptVerifier` est utilisé (warning loggé). Quand la RFC HTTP-Sig réelle sera livrée, appeler `.with_signature_verifier(Arc::new(HttpSigVerifier::new(…)))` avant `.build()` pour activer la vérification réelle.
Open questions
Toutes résolues à l'auto-revue :
-
Path :
/inbox(no-prefix, conforme Mastodon discovery par défaut). Les actors locaux pointent vers ce path viaPersonJson::inbox. - Body limit : Axum body limit par défaut. Pas de limite custom dans cette RFC.
-
Status code 202 vs 200 :
202 Acceptedcar certains traitements (e.g. blacklist JWT) sont asynchrones.
Tracking issue
À ouvrir au moment de la PR.
Score d'évaluation
| Critère | Note (1-5) | Commentaire |
|---|---|---|
| Généralité | 4 | Pattern réutilisable pour toute future activité AP entrante. |
| Stabilité API | 5 | Additif, gated, aucun impact sur APIs existantes. |
| Performance | 4 | Dispatch inline, pas de DB lookup avant la signature. |
| Sécurité | 3 | AlwaysAcceptVerifier par défaut — explicite mais à substituer en prod. |
| Complexité d'implémentation | 4 | ~300 lignes (handler + state + 8 tests). |
| Maintenance | 3 | Dispatch table à étendre quand de nouveaux types arrivent. |
| Documentation | 3 | Rustdoc EN, doctest, CHANGELOG. |
| Total | 26/35 | ≥ 25 → Accepted |
GitRust