Fetch boosted statuses on behalf of a follower (fixes #7426) (#7459)

When an ActivityPub Announce is processed and the boosted toot is not known,
fetch it on behalf of one of the booster's followers. This is to allow
fetching self-boosts of previously-unknown private toots.

If fetching on behalf of a user fails, try fetching it anonymously: the
selected follower of a boosting user may be banned by the boosted toot's
author.
This commit is contained in:
ThibG 2018-05-12 16:48:32 +02:00 committed by Eugen Rochko
parent f9afd06221
commit 7467361d70
3 changed files with 13 additions and 8 deletions

View File

@ -52,18 +52,22 @@ module JsonLdHelper
graph.dump(:normalize) graph.dump(:normalize)
end end
def fetch_resource(uri, id) def fetch_resource(uri, id, on_behalf_of = nil)
unless id unless id
json = fetch_resource_without_id_validation(uri) json = fetch_resource_without_id_validation(uri, on_behalf_of)
return unless json return unless json
uri = json['id'] uri = json['id']
end end
json = fetch_resource_without_id_validation(uri) json = fetch_resource_without_id_validation(uri, on_behalf_of)
json.present? && json['id'] == uri ? json : nil json.present? && json['id'] == uri ? json : nil
end end
def fetch_resource_without_id_validation(uri) def fetch_resource_without_id_validation(uri, on_behalf_of = nil)
build_request(uri, on_behalf_of).perform do |response|
return body_to_json(response.body_with_limit) if response.code == 200
end
# If request failed, retry without doing it on behalf of a user
build_request(uri).perform do |response| build_request(uri).perform do |response|
response.code == 200 ? body_to_json(response.body_with_limit) : nil response.code == 200 ? body_to_json(response.body_with_limit) : nil
end end
@ -85,8 +89,9 @@ module JsonLdHelper
private private
def build_request(uri) def build_request(uri, on_behalf_of = nil)
request = Request.new(:get, uri) request = Request.new(:get, uri)
request.on_behalf_of(on_behalf_of) if on_behalf_of
request.add_headers('Accept' => 'application/activity+json, application/ld+json') request.add_headers('Accept' => 'application/activity+json, application/ld+json')
request request
end end

View File

@ -30,7 +30,7 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
if object_uri.start_with?('http') if object_uri.start_with?('http')
return if ActivityPub::TagManager.instance.local_uri?(object_uri) return if ActivityPub::TagManager.instance.local_uri?(object_uri)
ActivityPub::FetchRemoteStatusService.new.call(object_uri, id: true) ActivityPub::FetchRemoteStatusService.new.call(object_uri, id: true, on_behalf_of: @account.followers.local.first)
elsif @object['url'].present? elsif @object['url'].present?
::FetchRemoteStatusService.new.call(@object['url']) ::FetchRemoteStatusService.new.call(@object['url'])
end end

View File

@ -4,9 +4,9 @@ class ActivityPub::FetchRemoteStatusService < BaseService
include JsonLdHelper include JsonLdHelper
# Should be called when uri has already been checked for locality # Should be called when uri has already been checked for locality
def call(uri, id: true, prefetched_body: nil) def call(uri, id: true, prefetched_body: nil, on_behalf_of: nil)
@json = if prefetched_body.nil? @json = if prefetched_body.nil?
fetch_resource(uri, id) fetch_resource(uri, id, on_behalf_of)
else else
body_to_json(prefetched_body) body_to_json(prefetched_body)
end end