Verify FEP-044f quotes with Fedify interaction controls - #641
Merged
Merged
Conversation
Refactor the FEP-044f quote authorization flow to use quoteInteraction
from the new @fedify/interaction-controls dependency. Hollo still owns
the database state, counters, notifications, and delivery.
- Add src/federation/quote.ts with shared helpers to build quote
requests and authorizations, build the policy subject from Hollo's
stored settings, and verify authorizations by dereferencing their
IRIs. A failed verification is marked retryable only when the
document loader failed transiently.
- Incoming QuoteRequest activities go through verifyRequest() against
a locally built target. Their instrument is resolved on an
independent copy, so the request echoed back keeps its original
form. The local canQuote policy is evaluated with evaluatePolicy()
and an approved-follower collection check; visibility, block, and
self-quote checks stay in Hollo. Accept and Reject responses are
built with the helper.
- Accept<QuoteRequest> now verifies the result authorization before
approving. The pending-state transition is a conditional update,
so concurrent responses cannot double-count or overwrite a
rejection.
- Remote quote posts verify quoteAuthorization by its IRI, and the
object dispatcher and the outgoing request and revocation use the
shared constructors. The existing request IDs, authorization URLs,
ordering keys, revocation wire format, and legacy no-policy path are
preserved.
The stricter verification cases are listed in CHANGES.md and covered by
regression tests.
Closes fedify-dev#635
Assisted-by: Claude Code:claude-opus-5-5
Assisted-by: Codex:gpt-6-astra
Assisted-by: Codex:gpt-6.1-sol
Member
Author
|
@coderabbitai full review |
This was referenced Oct 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #635.
quoteInteractionfrom @fedify/interaction-controls replaces Hollo's own requester, target, and authorization checks, so fixes to them arrive with Fedify updates. Hollo still owns quote state, counters, notifications, and delivery. The integration is in src/federation/quote.ts.Incoming quote requests
The target is loaded from the database and swapped into the request as a local
Notecarrying thecanQuoterule built from stored settings. Hollo doesn't fetch its own post over HTTP, and the same object serves as theevaluatePolicy()subject.Hollo resolves the instrument before calling the helper and lets fetch errors propagate, so transient failures trigger an inbox retry instead of dropping the request. Resolution runs on a copy re-parsed from JSON-LD, because
clone()shares the instrument storage and would otherwise rewrite the request echoed back in theAccept.Visibility and block checks still run before policy evaluation. The approved-follower check is a database lookup in
matchesApprovalCollection; the helper swallows errors from that callback, so Hollo rethrows them rather than sending a permanentRejectover a database hiccup.Authorizations
Authorizations from an
Acceptor a remote quote post are always verified by dereferencing their IRI. Embedded bodies are never trusted. Hollo omitsverifyAuthenticitybecause matching fields don't establish authenticity.Retry decisions look at what the document loader threw, not at the helper's failure type, since the helper reports a failed JSON-LD context fetch as
invalidJsonLd. Network, DNS, 5xx, 408, and 429 errors are retried; other 4xx responses and URLs rejected by SSRF protection are not.Verifying an
Acceptnow waits on the network, so the pending-to-accepted transition is a conditional update: concurrentAccepts count once, and aRejectreceived during the fetch wins.What stays local
The revocation
Deletekeeps its embedded authorization, sincecreateRevocation()emits only the IRI. Mapping remote policies to Mastodon's enum is untouched, and so is the legacy path for remote posts without a policy, which the helper would deny.getRevocationisn't wired because Hollo doesn't keep revoked authorization IDs.Behavior changes
Tests cover the stricter rules listed in CHANGES.md: requests need an
idand anactor,quoteandquoteUrlmust agree, cross-origin embedded instruments are refetched, and authorizations must be fetchable from the quoted author's origin. Invalid requests no longer leave the instrument persisted.AcceptandRejectresponses now carry explicit IDs in Fedify's auto-ID shape and address the requester into.Not tested yet: live interop with Mastodon and GoToSocial. The peer fixtures are modeled on Mastodon's serializers, not captured traffic. Accepting impolite quotes from Misskey and similar software is tracked in #640.