RFC 0017 — Fediverse: auto-résolution du PEM public dans HttpSigVerifier
- Auteur : EBO (rustwarden)
- Date : 2026-05-10
- Statut : Accepted (auto-revue mainteneur unique 2026-05-10, score 27/35)
- Apps consommatrices concernées : toute app fediverse en production qui veut une vérification HTTP-Sig sans avoir à pré-résoudre la clé publique côté handler.
- Plan associé : Phase 5 — production polish.
- Dépendances : RFC 0003 (
RemoteIdentityService), RFC 0010 (SignatureVerifier), RFC 0015 / 0016 (HTTP-Sig).
Summary
Brancher HttpSigVerifier (RFC 0016) sur RemoteIdentityService (RFC 0003) pour qu'il résolve lui-même la clé publique de l'acteur signataire à partir de ctx.actor_ap_id quand ctx.public_key_pem est vide. Élimine le contrat « le caller doit pré-résoudre la clé », réduit le boilerplate côté inbox handlers et ferme le dernier TODO documenté de RFC 0016.
Motivation
Aujourd'hui HttpSigVerifier::verify retourne Err(Validation("public key not resolved")) quand ctx.public_key_pem est vide — ce qui est toujours le cas depuis inbox::handle et auth_routes::auth_inbox car ceux-ci ne touchent pas à RemoteIdentityService. La vérification réelle est donc en pratique désactivée sans configuration manuelle des apps consommatrices.
Cette RFC rend le wiring transparent : par défaut le verifier résout via le service de cache.
Non-goals
- Pas de cache supplémentaire —
RemoteIdentityServicea déjà son TTL. - Pas de fallback
WebFingerici — si l'acteur n'est pas dans le cache, le verifier échoue avecErr. Une RFC suivante ajoutera la résolution paresseuse viaRemoteFetchersi nécessaire. - Pas de modification de l'API publique de
HttpSigVerifier—new()reste sans argument ; on ajoute un constructeurwith_resolver(db).
API proposée
pub struct HttpSigVerifier { db: Option<sea_orm::DatabaseConnection>, } impl HttpSigVerifier { /// Verifier non-resolving. Si `ctx.public_key_pem` est vide, le /// verifier rejette la requête (comportement RFC 0016 inchangé). pub fn new() -> Self; /// Verifier auto-resolving. Si `ctx.public_key_pem` est vide, /// le verifier appelle `RemoteIdentityService::find_by_ap_id` sur /// la connection fournie pour récupérer le PEM avant la vérif. pub fn with_resolver(db: sea_orm::DatabaseConnection) -> Self; }
L'impl verify :
- Si
ctx.public_key_pemnon-vide → comportement RFC 0016. - Sinon, si
self.db.is_some()→ lookupremote_identitiesparap_id = ctx.actor_ap_id. PEM trouvé → vérification. Pas trouvé →Err(Validation("actor not in cache")). - Sinon →
Err(Validation("public key not resolved"))(comportement RFC 0016).
Analyse de compatibilité
-
Non-breaking : nouveau constructeur, ancien
new()inchangé. - Pas de schéma DB.
-
Pas de modif de la signature
verify.
Alternatives considérées
Alternative A (recommandée) — Constructeur séparé with_resolver(db)
Pros : explicite, test-friendly, pas d'effet de bord sur les callers existants.
Alternative B — Toujours résoudre, paramètre db: Option<…> dans new
Cons : casse l'API minimaliste actuelle ; aucun test ne s'exécute sans DB.
Rejeté.
Alternative C — Trait PublicKeyResolver injectable
Pros : flexibilité maximale.
Cons : sur-engineered pour un cas d'usage à 1 impl ; complexité immédiate sans bénéfice tangible.
Rejeté pour cette RFC — pourra être revisitée si plusieurs impls émergent.
Alternative D — Ne rien faire (caller pré-résout)
Cons : tous les inbox handlers doivent porter le boilerplate. Une faute de wiring = vérif désactivée silencieusement.
Rejeté.
Testing plan
5 tests :
with_resolver_constructor_stores_db.verify_uses_provided_pem_when_present(régression du chemin RFC 0016).verify_resolves_pem_from_remote_identities_when_empty— DB-mocked, PEM stockée → succès round-trip.verify_rejects_when_actor_not_in_cache— DB-mocked, lookup retourneNone→Err(Validation).verify_without_resolver_rejects_empty_pem(régression du chemin RFC 0016).
Migration guide
### Added - `HttpSigVerifier::with_resolver(db)` — verifier qui résout automatiquement le PEM via `RemoteIdentityService`. ### Migration steps Avant : ```rust builder.with_signature_verifier(Arc::new(HttpSigVerifier::new())) // + caller-side resolution
Après (recommandé) :
builder.with_signature_verifier(Arc::new(HttpSigVerifier::with_resolver(db.clone())))
HttpSigVerifier::new() reste disponible pour les apps qui veulent
gérer la résolution elles-mêmes.
## Open questions Toutes résolues à l'auto-revue : - [x] **Cache miss** : `Err(Validation)` — pas de fetch paresseux dans cette RFC. - [x] **Service vs trait** : on appelle `RemoteIdentityService` directement (pas un trait) car c'est le seul backend prévu et le service est déjà gated `experimental-fediverse`. ## 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 résolution lazy à venir. | | Stabilité API | 5 | Additif pur. | | Performance | 4 | Une lookup DB par requête entrante ; cache RFC 0003 limite. | | Sécurité | 5 | Ferme le trou « verifier accepte tout silencieusement ». | | Complexité d'implémentation | 4 | ~80 lignes (constructeur + branch + 5 tests). | | Maintenance | 3 | Une dépendance directe `RemoteIdentityService`. | | Documentation | 2 | Rustdoc EN, doctest. | | **Total** | **27/35** | ≥ 25 → Accepted |
GitRust