You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

75 lines
2.3 KiB

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