mirror of
https://github.com/mastodon/mastodon.git
synced 2025-09-06 01:41:08 +00:00
Fix synchronous recursive fetching of deeply-nested quoted posts (#35600)
This commit is contained in:
parent
31ba52a57b
commit
efc0d237af
|
@ -206,8 +206,8 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
||||||
@quote.save
|
@quote.save
|
||||||
|
|
||||||
embedded_quote = safe_prefetched_embed(@account, @status_parser.quoted_object, @json['context'])
|
embedded_quote = safe_prefetched_embed(@account, @status_parser.quoted_object, @json['context'])
|
||||||
ActivityPub::VerifyQuoteService.new.call(@quote, fetchable_quoted_uri: @quote_uri, prefetched_quoted_object: embedded_quote, request_id: @options[:request_id])
|
ActivityPub::VerifyQuoteService.new.call(@quote, fetchable_quoted_uri: @quote_uri, prefetched_quoted_object: embedded_quote, request_id: @options[:request_id], depth: @options[:depth])
|
||||||
rescue Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS
|
rescue Mastodon::RecursionLimitExceededError, Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS
|
||||||
ActivityPub::RefetchAndVerifyQuoteWorker.perform_in(rand(30..600).seconds, @quote.id, @quote_uri, { 'request_id' => @options[:request_id] })
|
ActivityPub::RefetchAndVerifyQuoteWorker.perform_in(rand(30..600).seconds, @quote.id, @quote_uri, { 'request_id' => @options[:request_id] })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,10 @@ class ActivityPub::FetchRemoteStatusService < BaseService
|
||||||
DISCOVERIES_PER_REQUEST = 1000
|
DISCOVERIES_PER_REQUEST = 1000
|
||||||
|
|
||||||
# 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, prefetched_body: nil, on_behalf_of: nil, expected_actor_uri: nil, request_id: nil)
|
def call(uri, prefetched_body: nil, on_behalf_of: nil, expected_actor_uri: nil, request_id: nil, depth: nil)
|
||||||
return if domain_not_allowed?(uri)
|
return if domain_not_allowed?(uri)
|
||||||
|
|
||||||
|
@depth = depth || 0
|
||||||
@request_id = request_id || "#{Time.now.utc.to_i}-status-#{uri}"
|
@request_id = request_id || "#{Time.now.utc.to_i}-status-#{uri}"
|
||||||
@json = if prefetched_body.nil?
|
@json = if prefetched_body.nil?
|
||||||
fetch_status(uri, true, on_behalf_of)
|
fetch_status(uri, true, on_behalf_of)
|
||||||
|
@ -52,7 +53,7 @@ class ActivityPub::FetchRemoteStatusService < BaseService
|
||||||
return nil if discoveries > DISCOVERIES_PER_REQUEST
|
return nil if discoveries > DISCOVERIES_PER_REQUEST
|
||||||
end
|
end
|
||||||
|
|
||||||
ActivityPub::Activity.factory(activity_json, actor, request_id: @request_id).perform
|
ActivityPub::Activity.factory(activity_json, actor, request_id: @request_id, depth: @depth).perform
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -3,9 +3,12 @@
|
||||||
class ActivityPub::VerifyQuoteService < BaseService
|
class ActivityPub::VerifyQuoteService < BaseService
|
||||||
include JsonLdHelper
|
include JsonLdHelper
|
||||||
|
|
||||||
|
MAX_SYNCHRONOUS_DEPTH = 2
|
||||||
|
|
||||||
# Optionally fetch quoted post, and verify the quote is authorized
|
# Optionally fetch quoted post, and verify the quote is authorized
|
||||||
def call(quote, fetchable_quoted_uri: nil, prefetched_quoted_object: nil, prefetched_approval: nil, request_id: nil)
|
def call(quote, fetchable_quoted_uri: nil, prefetched_quoted_object: nil, prefetched_approval: nil, request_id: nil, depth: nil)
|
||||||
@request_id = request_id
|
@request_id = request_id
|
||||||
|
@depth = depth || 0
|
||||||
@quote = quote
|
@quote = quote
|
||||||
@fetching_error = nil
|
@fetching_error = nil
|
||||||
|
|
||||||
|
@ -72,10 +75,12 @@ class ActivityPub::VerifyQuoteService < BaseService
|
||||||
return if uri.nil? || @quote.quoted_status.present?
|
return if uri.nil? || @quote.quoted_status.present?
|
||||||
|
|
||||||
status = ActivityPub::TagManager.instance.uri_to_resource(uri, Status)
|
status = ActivityPub::TagManager.instance.uri_to_resource(uri, Status)
|
||||||
status ||= ActivityPub::FetchRemoteStatusService.new.call(uri, on_behalf_of: @quote.account.followers.local.first, prefetched_body:, request_id: @request_id)
|
raise Mastodon::RecursionLimitExceededError if @depth > MAX_SYNCHRONOUS_DEPTH && status.nil?
|
||||||
|
|
||||||
|
status ||= ActivityPub::FetchRemoteStatusService.new.call(uri, on_behalf_of: @quote.account.followers.local.first, prefetched_body:, request_id: @request_id, depth: @depth + 1)
|
||||||
|
|
||||||
@quote.update(quoted_status: status) if status.present?
|
@quote.update(quoted_status: status) if status.present?
|
||||||
rescue Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS => e
|
rescue Mastodon::RecursionLimitExceededError, Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS => e
|
||||||
@fetching_error = e
|
@fetching_error = e
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -90,7 +95,7 @@ class ActivityPub::VerifyQuoteService < BaseService
|
||||||
# It's not safe to fetch if the inlined object is cross-origin or doesn't match expectations
|
# It's not safe to fetch if the inlined object is cross-origin or doesn't match expectations
|
||||||
return if object['id'] != uri || non_matching_uri_hosts?(@quote.approval_uri, object['id'])
|
return if object['id'] != uri || non_matching_uri_hosts?(@quote.approval_uri, object['id'])
|
||||||
|
|
||||||
status = ActivityPub::FetchRemoteStatusService.new.call(object['id'], prefetched_body: object, on_behalf_of: @quote.account.followers.local.first, request_id: @request_id)
|
status = ActivityPub::FetchRemoteStatusService.new.call(object['id'], prefetched_body: object, on_behalf_of: @quote.account.followers.local.first, request_id: @request_id, depth: @depth)
|
||||||
|
|
||||||
if status.present?
|
if status.present?
|
||||||
@quote.update(quoted_status: status)
|
@quote.update(quoted_status: status)
|
||||||
|
|
|
@ -14,6 +14,7 @@ module Mastodon
|
||||||
class InvalidParameterError < Error; end
|
class InvalidParameterError < Error; end
|
||||||
class SignatureVerificationError < Error; end
|
class SignatureVerificationError < Error; end
|
||||||
class MalformedHeaderError < Error; end
|
class MalformedHeaderError < Error; end
|
||||||
|
class RecursionLimitExceededError < Error; end
|
||||||
|
|
||||||
class UnexpectedResponseError < Error
|
class UnexpectedResponseError < Error
|
||||||
attr_reader :response
|
attr_reader :response
|
||||||
|
|
Loading…
Reference in New Issue
Block a user