diff --git a/app/lib/activitypub/forwarder.rb b/app/lib/activitypub/forwarder.rb index 3a94f9669..c5ff59fa5 100644 --- a/app/lib/activitypub/forwarder.rb +++ b/app/lib/activitypub/forwarder.rb @@ -27,17 +27,25 @@ class ActivityPub::Forwarder @reblogged_by_account_ids ||= @status.reblogs.includes(:account).references(:account).merge(Account.local).pluck(:account_id) end + def quoted_by_account_ids + @quoted_by_account_ids ||= @status.quotes.includes(:account).references(:account).merge(Account.local).pluck(:account_id) + end + + def shared_by_account_ids + reblogged_by_account_ids.concat(quoted_by_account_ids) + end + def signature_account_id @signature_account_id ||= if in_reply_to_local? in_reply_to.account_id else - reblogged_by_account_ids.first + shared_by_account_ids.first end end def inboxes @inboxes ||= begin - arr = inboxes_for_followers_of_reblogged_by_accounts + arr = inboxes_for_followers_of_shared_by_accounts arr += inboxes_for_followers_of_replied_to_account if in_reply_to_local? arr -= [@account.preferred_inbox_url] arr.uniq! @@ -45,8 +53,8 @@ class ActivityPub::Forwarder end end - def inboxes_for_followers_of_reblogged_by_accounts - Account.where(id: ::Follow.where(target_account_id: reblogged_by_account_ids).select(:account_id)).inboxes + def inboxes_for_followers_of_shared_by_accounts + Account.where(id: ::Follow.where(target_account_id: shared_by_account_ids).select(:account_id)).inboxes end def inboxes_for_followers_of_replied_to_account diff --git a/spec/lib/activitypub/forwarder_spec.rb b/spec/lib/activitypub/forwarder_spec.rb new file mode 100644 index 000000000..f72e33421 --- /dev/null +++ b/spec/lib/activitypub/forwarder_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe ActivityPub::Forwarder do + subject { described_class.new(account, payload, status) } + + let(:account) { Fabricate(:account) } + let(:remote_account) { Fabricate(:account, domain: 'example.com') } + let(:status) { Fabricate(:status, account: remote_account) } + + let(:signature) { { type: 'RsaSignature2017', signatureValue: 'foo' } } + let(:payload) do + { + '@context': [ + 'https://www.w3.org/ns/activitystreams', + 'https://w3id.org/security/v1', + ], + signature: signature, + type: 'Delete', + object: ActivityPub::TagManager.instance.uri_for(status), + }.deep_stringify_keys + end + + describe '#forwardable?' do + context 'when payload has an inlined signature' do + it 'returns true' do + expect(subject.forwardable?).to be true + end + end + + context 'when payload has an no inlined signature' do + let(:signature) { nil } + + it 'returns true' do + expect(subject.forwardable?).to be false + end + end + end + + describe '#forward!' do + let(:alice) { Fabricate(:account) } + let(:bob) { Fabricate(:account) } + let(:eve) { Fabricate(:account, domain: 'remote1.example.com', inbox_url: 'https://remote1.example.com/users/eve/inbox', protocol: :activitypub) } + let(:mallory) { Fabricate(:account, domain: 'remote2.example.com', inbox_url: 'https://remote2.example.com/users/mallory/inbox', protocol: :activitypub) } + + before do + alice.statuses.create!(reblog: status) + Fabricate(:quote, status: Fabricate(:status, account: bob), quoted_status: status, state: :accepted) + + eve.follow!(alice) + mallory.follow!(bob) + end + + it 'correctly forwards to expected remote followers' do + expect { subject.forward! } + .to enqueue_sidekiq_job(ActivityPub::LowPriorityDeliveryWorker).with(Oj.dump(payload), anything, eve.preferred_inbox_url) + .and enqueue_sidekiq_job(ActivityPub::LowPriorityDeliveryWorker).with(Oj.dump(payload), anything, mallory.preferred_inbox_url) + end + end +end