about summary refs log tree commit diff
path: root/spec/services/activitypub
diff options
context:
space:
mode:
Diffstat (limited to 'spec/services/activitypub')
-rw-r--r--spec/services/activitypub/fetch_remote_account_service_spec.rb123
-rw-r--r--spec/services/activitypub/fetch_remote_status_service_spec.rb75
-rw-r--r--spec/services/activitypub/process_account_service_spec.rb5
-rw-r--r--spec/services/activitypub/process_collection_service_spec.rb55
4 files changed, 258 insertions, 0 deletions
diff --git a/spec/services/activitypub/fetch_remote_account_service_spec.rb b/spec/services/activitypub/fetch_remote_account_service_spec.rb
new file mode 100644
index 000000000..391d051c1
--- /dev/null
+++ b/spec/services/activitypub/fetch_remote_account_service_spec.rb
@@ -0,0 +1,123 @@
+require 'rails_helper'
+
+RSpec.describe ActivityPub::FetchRemoteAccountService do
+  subject { ActivityPub::FetchRemoteAccountService.new }
+
+  let!(:actor) do
+    {
+      '@context': 'https://www.w3.org/ns/activitystreams',
+      id: 'https://example.com/alice',
+      type: 'Person',
+      preferredUsername: 'alice',
+      name: 'Alice',
+      summary: 'Foo bar',
+      inbox: 'http://example.com/alice/inbox',
+    }
+  end
+
+  describe '#call' do
+    let(:account) { subject.call('https://example.com/alice') }
+
+    shared_examples 'sets profile data' do
+      it 'returns an account' do
+        expect(account).to be_an Account
+      end
+
+      it 'sets display name' do
+        expect(account.display_name).to eq 'Alice'
+      end
+
+      it 'sets note' do
+        expect(account.note).to eq 'Foo bar'
+      end
+
+      it 'sets URL' do
+        expect(account.url).to eq 'https://example.com/alice'
+      end
+    end
+
+    context 'when the account does not have a inbox' do
+      let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
+
+      before do
+        actor[:inbox] = nil
+        
+        stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
+        stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
+      end
+
+      it 'fetches resource' do
+        account
+        expect(a_request(:get, 'https://example.com/alice')).to have_been_made.once
+      end
+
+      it 'looks up webfinger' do
+        account
+        expect(a_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com')).to have_been_made.once
+      end
+
+      it 'returns nil' do
+        expect(account).to be_nil
+      end
+
+    end
+
+    context 'when URI and WebFinger share the same host' do
+      let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
+
+      before do
+        stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
+        stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
+      end
+
+      it 'fetches resource' do
+        account
+        expect(a_request(:get, 'https://example.com/alice')).to have_been_made.once
+      end
+
+      it 'looks up webfinger' do
+        account
+        expect(a_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com')).to have_been_made.once
+      end
+
+      it 'sets username and domain from webfinger' do
+        expect(account.username).to eq 'alice'
+        expect(account.domain).to eq 'example.com'
+      end
+
+      include_examples 'sets profile data'
+    end
+
+    context 'when WebFinger presents different domain than URI' do
+      let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
+
+      before do
+        stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
+        stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
+        stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
+      end
+
+      it 'fetches resource' do
+        account
+        expect(a_request(:get, 'https://example.com/alice')).to have_been_made.once
+      end
+
+      it 'looks up webfinger' do
+        account
+        expect(a_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com')).to have_been_made.once
+      end
+
+      it 'looks up "redirected" webfinger' do
+        account
+        expect(a_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af')).to have_been_made.once
+      end
+
+      it 'sets username and domain from final webfinger' do
+        expect(account.username).to eq 'alice'
+        expect(account.domain).to eq 'iscool.af'
+      end
+
+      include_examples 'sets profile data'
+    end
+  end
+end
diff --git a/spec/services/activitypub/fetch_remote_status_service_spec.rb b/spec/services/activitypub/fetch_remote_status_service_spec.rb
new file mode 100644
index 000000000..3b22257ed
--- /dev/null
+++ b/spec/services/activitypub/fetch_remote_status_service_spec.rb
@@ -0,0 +1,75 @@
+require 'rails_helper'
+
+RSpec.describe ActivityPub::FetchRemoteStatusService do
+  let(:sender) { Fabricate(:account) }
+  let(:recipient) { Fabricate(:account) }
+  let(:valid_domain) { Rails.configuration.x.local_domain }
+
+  let(:note) do
+    {
+      '@context': 'https://www.w3.org/ns/activitystreams',
+      id: "https://#{valid_domain}/@foo/1234",
+      type: 'Note',
+      content: 'Lorem ipsum',
+      attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
+    }
+  end
+
+  let(:create) do
+    {
+      '@context': 'https://www.w3.org/ns/activitystreams',
+      id: "https://#{valid_domain}/@foo/1234/activity",
+      type: 'Create',
+      actor: ActivityPub::TagManager.instance.uri_for(sender),
+      object: note,
+    }
+  end
+
+  subject { described_class.new }
+
+  describe '#call' do
+    before do
+      subject.call(object[:id], Oj.dump(object))
+    end
+
+    context 'with Note object' do
+      let(:object) { note }
+
+      it 'creates status' do
+        status = sender.statuses.first
+        
+        expect(status).to_not be_nil
+        expect(status.text).to eq 'Lorem ipsum'
+      end
+    end
+
+    context 'with Create activity' do
+      let(:object) { create }
+
+      it 'creates status' do
+        status = sender.statuses.first
+        
+        expect(status).to_not be_nil
+        expect(status.text).to eq 'Lorem ipsum'
+      end
+    end
+
+    context 'with Announce activity' do
+      let(:status) { Fabricate(:status, account: recipient) }
+
+      let(:object) do
+        {
+          '@context': 'https://www.w3.org/ns/activitystreams',
+          id: "https://#{valid_domain}/@foo/1234/activity",
+          type: 'Announce',
+          actor: ActivityPub::TagManager.instance.uri_for(sender),
+          object: ActivityPub::TagManager.instance.uri_for(status),
+        }
+      end
+
+      it 'creates a reblog by sender of status' do
+        expect(sender.reblogged?(status)).to be true
+      end
+    end
+  end
+end
diff --git a/spec/services/activitypub/process_account_service_spec.rb b/spec/services/activitypub/process_account_service_spec.rb
new file mode 100644
index 000000000..84a74c231
--- /dev/null
+++ b/spec/services/activitypub/process_account_service_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe ActivityPub::ProcessAccountService do
+  pending
+end
diff --git a/spec/services/activitypub/process_collection_service_spec.rb b/spec/services/activitypub/process_collection_service_spec.rb
new file mode 100644
index 000000000..249b12470
--- /dev/null
+++ b/spec/services/activitypub/process_collection_service_spec.rb
@@ -0,0 +1,55 @@
+require 'rails_helper'
+
+RSpec.describe ActivityPub::ProcessCollectionService do
+  let(:actor) { Fabricate(:account) }
+
+  let(:payload) do
+    {
+      '@context': 'https://www.w3.org/ns/activitystreams',
+      id: 'foo',
+      type: 'Create',
+      actor: ActivityPub::TagManager.instance.uri_for(actor),
+      object: {
+        id: 'bar',
+        type: 'Note',
+        content: 'Lorem ipsum',
+      },
+    }
+  end
+
+  let(:json) { Oj.dump(payload) }
+
+  subject { described_class.new }
+
+  describe '#call' do
+    context 'when actor is the sender'
+    context 'when actor differs from sender' do
+      let(:forwarder) { Fabricate(:account) }
+
+      it 'processes payload with sender if no signature exists' do
+        expect_any_instance_of(ActivityPub::LinkedDataSignature).not_to receive(:verify_account!)
+        expect(ActivityPub::Activity).to receive(:factory).with(instance_of(Hash), forwarder)
+
+        subject.call(json, forwarder)
+      end
+
+      it 'processes payload with actor if valid signature exists' do
+        payload['signature'] = {'type' => 'RsaSignature2017'}
+
+        expect_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_account!).and_return(actor)
+        expect(ActivityPub::Activity).to receive(:factory).with(instance_of(Hash), actor)
+
+        subject.call(json, forwarder)
+      end
+
+      it 'does not process payload if invalid signature exists' do
+        payload['signature'] = {'type' => 'RsaSignature2017'}
+
+        expect_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_account!).and_return(nil)
+        expect(ActivityPub::Activity).not_to receive(:factory)
+
+        subject.call(json, forwarder)
+      end
+    end
+  end
+end