From 3f9b28ce26ee6ec3b1657da01c9a90ecbcb4427a Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 21 Oct 2021 01:14:04 +0200 Subject: [PATCH] Add support for fetching Create and Announce activities by URI (#16383) * Add support for fetching Create and Announce activities by URI This should improve compatibility with ZAP and offer a way to fetch boosts, which is currently not possible. * Add tests --- .../fetch_remote_status_service.rb | 29 ++++++++----- .../fetch_remote_status_service_spec.rb | 41 +++++++++++++++++++ 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/app/services/activitypub/fetch_remote_status_service.rb b/app/services/activitypub/fetch_remote_status_service.rb index cf4f62899..4f789d50b 100644 --- a/app/services/activitypub/fetch_remote_status_service.rb +++ b/app/services/activitypub/fetch_remote_status_service.rb @@ -13,7 +13,20 @@ class ActivityPub::FetchRemoteStatusService < BaseService end end - return if !(supported_context? && expected_type?) || actor_id.nil? || !trustworthy_attribution?(@json['id'], actor_id) + return unless supported_context? + + actor_id = nil + activity_json = nil + + if expected_object_type? + actor_id = value_or_id(first_of_value(@json['attributedTo'])) + activity_json = { 'type' => 'Create', 'actor' => actor_id, 'object' => @json } + elsif expected_activity_type? + actor_id = value_or_id(first_of_value(@json['actor'])) + activity_json = @json + end + + return if activity_json.nil? || !trustworthy_attribution?(@json['id'], actor_id) actor = ActivityPub::TagManager.instance.uri_to_resource(actor_id, Account) actor = ActivityPub::FetchRemoteAccountService.new.call(actor_id, id: true) if actor.nil? || needs_update?(actor) @@ -25,14 +38,6 @@ class ActivityPub::FetchRemoteStatusService < BaseService private - def activity_json - { 'type' => 'Create', 'actor' => actor_id, 'object' => @json } - end - - def actor_id - value_or_id(first_of_value(@json['attributedTo'])) - end - def trustworthy_attribution?(uri, attributed_to) return false if uri.nil? || attributed_to.nil? Addressable::URI.parse(uri).normalized_host.casecmp(Addressable::URI.parse(attributed_to).normalized_host).zero? @@ -42,7 +47,11 @@ class ActivityPub::FetchRemoteStatusService < BaseService super(@json) end - def expected_type? + def expected_activity_type? + equals_or_includes_any?(@json['type'], %w(Create Announce)) + end + + def expected_object_type? equals_or_includes_any?(@json['type'], ActivityPub::Activity::Create::SUPPORTED_TYPES + ActivityPub::Activity::Create::CONVERTED_TYPES) end diff --git a/spec/services/activitypub/fetch_remote_status_service_spec.rb b/spec/services/activitypub/fetch_remote_status_service_spec.rb index 1ecc46952..ceba5f210 100644 --- a/spec/services/activitypub/fetch_remote_status_service_spec.rb +++ b/spec/services/activitypub/fetch_remote_status_service_spec.rb @@ -145,5 +145,46 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do expect(sender.statuses.first).to be_nil end end + + context 'with a valid Create activity' do + let(:object) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: "https://#{valid_domain}/@foo/1234/create", + type: 'Create', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: note, + } + end + + it 'creates status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.uri).to eq note[:id] + expect(status.text).to eq note[:content] + end + end + + context 'with a Create activity with a mismatching id' do + let(:object) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: "https://#{valid_domain}/@foo/1234/create", + type: 'Create', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: { + id: "https://real.address/@foo/1234", + type: 'Note', + content: 'Lorem ipsum', + attributedTo: ActivityPub::TagManager.instance.uri_for(sender), + }, + } + end + + it 'does not create status' do + expect(sender.statuses.first).to be_nil + end + end end end