process_collection_service.rb 2.4 KB

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