mastodon/app/lib/activitypub/dereferencer.rb
Oneric 3059884c90 Fix Accept headers when fetching AP objects to match spec
ActivityPub spec section 3.2 reads
> The client MUST specify an Accept header with the
> `application/ld+json; profile="https://www.w3.org/ns/activitystreams"`
> media type in order to retrieve the activity.

Currently Mastodon omits the profile in its dereferences (but not the
fetch service) and only lists application/ld+json as one of several
possible types. This breaks spec and allows spec-compliant
implementations to refuse any such fetch requests.

Resolve this by adding the required profile and while at it,
make the only spec-compliant type the first listed choice in all
relevant places and drop profile-less JSON-LD.

Section 7 also specifies the same media type MUST be used
in the Content-Type header of for POST requests, but here
we can't specify alternatives, so for now keep the current type.

Fixes a part of https://github.com/mastodon/mastodon/issues/22720
2024-11-22 17:00:14 +01:00

61 lines
1.4 KiB
Ruby

# frozen_string_literal: true
class ActivityPub::Dereferencer
include JsonLdHelper
def initialize(uri, permitted_origin: nil, signature_actor: nil)
@uri = uri
@permitted_origin = permitted_origin
@signature_actor = signature_actor
end
def object
@object ||= fetch_object!
end
private
def bear_cap?
@uri.start_with?('bear:')
end
def fetch_object!
if bear_cap?
fetch_with_token!
else
fetch_with_signature!
end
end
def fetch_with_token!
perform_request(bear_cap['u'], headers: { 'Authorization' => "Bearer #{bear_cap['t']}" })
end
def fetch_with_signature!
perform_request(@uri)
end
def bear_cap
@bear_cap ||= Addressable::URI.parse(@uri).query_values
end
def perform_request(uri, headers: nil)
return if non_matching_uri_hosts?(@permitted_origin, uri)
req = Request.new(:get, uri)
req.add_headers('Accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/activity+json')
req.add_headers(headers) if headers
req.on_behalf_of(@signature_actor) if @signature_actor
req.perform do |res|
if res.code == 200
json = body_to_json(res.body_with_limit)
json if json.present? && json['id'] == uri
else
raise Mastodon::UnexpectedResponseError, res unless response_successful?(res) || response_error_unsalvageable?(res)
end
end
end
end