Background
DrFed logs, for every inbox request, the mechanism that verified it, the key it used, and why the request was refused (fedify-dev/drfed#12). Fedify reports these unevenly:
- HTTP Signatures:
verifyRequestDetailed() returns the key or a reason, and the handler later counts an owner mismatch as actorKeyMismatch.
- Linked Data Signatures: a key the actor does not own is measured as
rejected, the same as a bad signature or a failed key fetch.
- Object Integrity Proofs: a valid proof that does not cover the actor is measured as
verified, then verifyObject() returns null.
No mechanism hands its key to inbox listeners. DrFed gets it by watching the KvStore entries under kvPrefixes.publicKey, which depends on KvKeyCache's private serialization. #1122 does not cover this: getSignedKey() verifies again.
Proposed work
- Add detailed variants of
verifyJsonLd() and verifyObject(), like verifyRequestDetailed(): the key or a reason that distinguishes an invalid signature, a key fetch failure, and an owner mismatch.
- Record that reason, as a bounded set, on the
*.verify spans and on activitypub.signature.verification.duration, leaving the HTTP owner mismatch on the inbox span.
- Hand the outcome of inbox verification (mechanism, key, reason) to the application for every request, accepted or refused.
onVerification(): A new hook, called once per inbox request before the response: only that reaches refused, duplicate, and unlistened requests, as well as enqueued ones, without queuing the key.
AI disclosure
Claude Code (claude-opus-5-5) drafted this issue from the analysis it did for fedify-dev/drfed#12. The user decided the direction and edited out the verbose parts.
Background
DrFed logs, for every inbox request, the mechanism that verified it, the key it used, and why the request was refused (fedify-dev/drfed#12). Fedify reports these unevenly:
verifyRequestDetailed()returns the key or a reason, and the handler later counts an owner mismatch asactorKeyMismatch.rejected, the same as a bad signature or a failed key fetch.verified, thenverifyObject()returnsnull.No mechanism hands its key to inbox listeners. DrFed gets it by watching the
KvStoreentries underkvPrefixes.publicKey, which depends onKvKeyCache's private serialization. #1122 does not cover this:getSignedKey()verifies again.Proposed work
verifyJsonLd()andverifyObject(), likeverifyRequestDetailed(): the key or a reason that distinguishes an invalid signature, a key fetch failure, and an owner mismatch.*.verifyspans and onactivitypub.signature.verification.duration, leaving the HTTP owner mismatch on the inbox span.onVerification(): A new hook, called once per inbox request before the response: only that reaches refused, duplicate, and unlistened requests, as well as enqueued ones, without queuing the key.AI disclosure
Claude Code (claude-opus-5-5) drafted this issue from the analysis it did for fedify-dev/drfed#12. The user decided the direction and edited out the verbose parts.