process_collection_service.rb 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. # frozen_string_literal: true
  2. class ActivityPub::ProcessCollectionService < BaseService
  3. include JsonLdHelper
  4. def call(body, actor, **options)
  5. @account = actor
  6. @json = original_json = Oj.load(body, mode: :strict)
  7. @options = options
  8. begin
  9. @json = compact(@json) if @json['signature'].is_a?(Hash)
  10. rescue JSON::LD::JsonLdError => e
  11. Rails.logger.debug "Error when compacting JSON-LD document for #{value_or_id(@json['actor'])}: #{e.message}"
  12. @json = original_json.without('signature')
  13. end
  14. return if !supported_context? || (different_actor? && verify_account!.nil?) || suspended_actor? || @account.local?
  15. return unless @account.is_a?(Account)
  16. if @json['signature'].present?
  17. # We have verified the signature, but in the compaction step above, might
  18. # have introduced incompatibilities with other servers that do not
  19. # normalize the JSON-LD documents (for instance, previous Mastodon
  20. # versions), so skip redistribution if we can't get a safe document.
  21. patch_for_forwarding!(original_json, @json)
  22. @json.delete('signature') unless safe_for_forwarding?(original_json, @json)
  23. end
  24. case @json['type']
  25. when 'Collection', 'CollectionPage'
  26. process_items @json['items']
  27. when 'OrderedCollection', 'OrderedCollectionPage'
  28. process_items @json['orderedItems']
  29. else
  30. process_items [@json]
  31. end
  32. rescue Oj::ParseError
  33. nil
  34. end
  35. private
  36. def different_actor?
  37. @json['actor'].present? && value_or_id(@json['actor']) != @account.uri
  38. end
  39. def suspended_actor?
  40. @account.suspended? && !activity_allowed_while_suspended?
  41. end
  42. def activity_allowed_while_suspended?
  43. %w(Delete Reject Undo Update).include?(@json['type'])
  44. end
  45. def process_items(items)
  46. items.reverse_each.filter_map { |item| process_item(item) }
  47. end
  48. def supported_context?
  49. super(@json)
  50. end
  51. def process_item(item)
  52. activity = ActivityPub::Activity.factory(item, @account, **@options)
  53. activity&.perform
  54. end
  55. def verify_account!
  56. @options[:relayed_through_actor] = @account
  57. @account = ActivityPub::LinkedDataSignature.new(@json).verify_actor!
  58. @account = nil unless @account.is_a?(Account)
  59. @account
  60. rescue JSON::LD::JsonLdError => e
  61. Rails.logger.debug "Could not verify LD-Signature for #{value_or_id(@json['actor'])}: #{e.message}"
  62. nil
  63. end
  64. end