about summary refs log tree commit diff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/accounts_controller_spec.rb2
-rw-r--r--spec/controllers/activitypub/collections_controller_spec.rb2
-rw-r--r--spec/controllers/activitypub/followers_synchronizations_controller_spec.rb2
-rw-r--r--spec/controllers/activitypub/inboxes_controller_spec.rb2
-rw-r--r--spec/controllers/activitypub/outboxes_controller_spec.rb2
-rw-r--r--spec/controllers/activitypub/replies_controller_spec.rb2
-rw-r--r--spec/controllers/concerns/signature_verification_spec.rb45
-rw-r--r--spec/controllers/statuses_controller_spec.rb2
-rw-r--r--spec/lib/activitypub/activity/announce_spec.rb2
-rw-r--r--spec/lib/activitypub/dereferencer_spec.rb8
-rw-r--r--spec/lib/activitypub/linked_data_signature_spec.rb14
-rw-r--r--spec/services/activitypub/fetch_remote_actor_service_spec.rb180
-rw-r--r--spec/services/activitypub/process_collection_service_spec.rb6
-rw-r--r--spec/services/fetch_resource_service_spec.rb2
14 files changed, 248 insertions, 23 deletions
diff --git a/spec/controllers/accounts_controller_spec.rb b/spec/controllers/accounts_controller_spec.rb
index 662a89927..12266c800 100644
--- a/spec/controllers/accounts_controller_spec.rb
+++ b/spec/controllers/accounts_controller_spec.rb
@@ -420,7 +420,7 @@ RSpec.describe AccountsController, type: :controller do
         let(:remote_account) { Fabricate(:account, domain: 'example.com') }
 
         before do
-          allow(controller).to receive(:signed_request_account).and_return(remote_account)
+          allow(controller).to receive(:signed_request_actor).and_return(remote_account)
           get :show, params: { username: account.username, format: format }
         end
 
diff --git a/spec/controllers/activitypub/collections_controller_spec.rb b/spec/controllers/activitypub/collections_controller_spec.rb
index 4d87f80ce..f78d9abbf 100644
--- a/spec/controllers/activitypub/collections_controller_spec.rb
+++ b/spec/controllers/activitypub/collections_controller_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
   end
 
   before do
-    allow(controller).to receive(:signed_request_account).and_return(remote_account)
+    allow(controller).to receive(:signed_request_actor).and_return(remote_account)
 
     Fabricate(:status_pin, account: account)
     Fabricate(:status_pin, account: account)
diff --git a/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb b/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb
index e233bd560..c19bb8cae 100644
--- a/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb
+++ b/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe ActivityPub::FollowersSynchronizationsController, type: :controll
   end
 
   before do
-    allow(controller).to receive(:signed_request_account).and_return(remote_account)
+    allow(controller).to receive(:signed_request_actor).and_return(remote_account)
   end
 
   describe 'GET #show' do
diff --git a/spec/controllers/activitypub/inboxes_controller_spec.rb b/spec/controllers/activitypub/inboxes_controller_spec.rb
index 973ad83bb..2f023197b 100644
--- a/spec/controllers/activitypub/inboxes_controller_spec.rb
+++ b/spec/controllers/activitypub/inboxes_controller_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe ActivityPub::InboxesController, type: :controller do
   let(:remote_account) { nil }
 
   before do
-    allow(controller).to receive(:signed_request_account).and_return(remote_account)
+    allow(controller).to receive(:signed_request_actor).and_return(remote_account)
   end
 
   describe 'POST #create' do
diff --git a/spec/controllers/activitypub/outboxes_controller_spec.rb b/spec/controllers/activitypub/outboxes_controller_spec.rb
index 04f036447..74bf46a5e 100644
--- a/spec/controllers/activitypub/outboxes_controller_spec.rb
+++ b/spec/controllers/activitypub/outboxes_controller_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
   end
 
   before do
-    allow(controller).to receive(:signed_request_account).and_return(remote_account)
+    allow(controller).to receive(:signed_request_actor).and_return(remote_account)
   end
 
   describe 'GET #show' do
diff --git a/spec/controllers/activitypub/replies_controller_spec.rb b/spec/controllers/activitypub/replies_controller_spec.rb
index a35957f24..aee1a8b1a 100644
--- a/spec/controllers/activitypub/replies_controller_spec.rb
+++ b/spec/controllers/activitypub/replies_controller_spec.rb
@@ -168,7 +168,7 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do
 
   before do
     stub_const 'ActivityPub::RepliesController::DESCENDANTS_LIMIT', 5
-    allow(controller).to receive(:signed_request_account).and_return(remote_querier)
+    allow(controller).to receive(:signed_request_actor).and_return(remote_querier)
 
     Fabricate(:status, thread: status, visibility: :public)
     Fabricate(:status, thread: status, visibility: :public)
diff --git a/spec/controllers/concerns/signature_verification_spec.rb b/spec/controllers/concerns/signature_verification_spec.rb
index 05fb1445b..6e73643b4 100644
--- a/spec/controllers/concerns/signature_verification_spec.rb
+++ b/spec/controllers/concerns/signature_verification_spec.rb
@@ -3,6 +3,16 @@
 require 'rails_helper'
 
 describe ApplicationController, type: :controller do
+  class WrappedActor
+    attr_reader :wrapped_account
+
+    def initialize(wrapped_account)
+      @wrapped_account = wrapped_account
+    end
+
+    delegate :uri, :keypair, to: :wrapped_account
+  end
+
   controller do
     include SignatureVerification
 
@@ -73,6 +83,41 @@ describe ApplicationController, type: :controller do
       end
     end
 
+    context 'with a valid actor that is not an Account' do
+      let(:actor) { WrappedActor.new(author) }
+
+      before do
+        get :success
+
+        fake_request = Request.new(:get, request.url)
+        fake_request.on_behalf_of(author)
+
+        request.headers.merge!(fake_request.headers)
+
+        allow(ActivityPub::TagManager.instance).to receive(:uri_to_actor).with(anything) do
+          actor
+        end
+      end
+
+      describe '#signed_request?' do
+        it 'returns true' do
+          expect(controller.signed_request?).to be true
+        end
+      end
+
+      describe '#signed_request_account' do
+        it 'returns nil' do
+          expect(controller.signed_request_account).to be_nil
+        end
+      end
+
+      describe '#signed_request_actor' do
+        it 'returns the expected actor' do
+          expect(controller.signed_request_actor).to eq actor
+        end
+      end
+    end
+
     context 'with request older than a day' do
       before do
         get :success
diff --git a/spec/controllers/statuses_controller_spec.rb b/spec/controllers/statuses_controller_spec.rb
index 05fae67fa..6ed5d4bbb 100644
--- a/spec/controllers/statuses_controller_spec.rb
+++ b/spec/controllers/statuses_controller_spec.rb
@@ -426,7 +426,7 @@ describe StatusesController do
       let(:remote_account) { Fabricate(:account, domain: 'example.com') }
 
       before do
-        allow(controller).to receive(:signed_request_account).and_return(remote_account)
+        allow(controller).to receive(:signed_request_actor).and_return(remote_account)
       end
 
       context 'when account blocks account' do
diff --git a/spec/lib/activitypub/activity/announce_spec.rb b/spec/lib/activitypub/activity/announce_spec.rb
index 41806b258..e9cd6c68c 100644
--- a/spec/lib/activitypub/activity/announce_spec.rb
+++ b/spec/lib/activitypub/activity/announce_spec.rb
@@ -115,7 +115,7 @@ RSpec.describe ActivityPub::Activity::Announce do
 
       let(:object_json) { 'https://example.com/actor/hello-world' }
 
-      subject { described_class.new(json, sender, relayed_through_account: relay_account) }
+      subject { described_class.new(json, sender, relayed_through_actor: relay_account) }
 
       before do
         stub_request(:get, 'https://example.com/actor/hello-world').to_return(body: Oj.dump(unknown_object_json))
diff --git a/spec/lib/activitypub/dereferencer_spec.rb b/spec/lib/activitypub/dereferencer_spec.rb
index ce30513d7..e50b497c7 100644
--- a/spec/lib/activitypub/dereferencer_spec.rb
+++ b/spec/lib/activitypub/dereferencer_spec.rb
@@ -4,10 +4,10 @@ RSpec.describe ActivityPub::Dereferencer do
   describe '#object' do
     let(:object) { { '@context': 'https://www.w3.org/ns/activitystreams', id: 'https://example.com/foo', type: 'Note', content: 'Hoge' } }
     let(:permitted_origin) { 'https://example.com' }
-    let(:signature_account) { nil }
+    let(:signature_actor) { nil }
     let(:uri) { nil }
 
-    subject { described_class.new(uri, permitted_origin: permitted_origin, signature_account: signature_account).object }
+    subject { described_class.new(uri, permitted_origin: permitted_origin, signature_actor: signature_actor).object }
 
     before do
       stub_request(:get, 'https://example.com/foo').to_return(body: Oj.dump(object), headers: { 'Content-Type' => 'application/activity+json' })
@@ -21,7 +21,7 @@ RSpec.describe ActivityPub::Dereferencer do
       end
 
       context 'with signature account' do
-        let(:signature_account) { Fabricate(:account) }
+        let(:signature_actor) { Fabricate(:account) }
 
         it 'makes signed request' do
           subject
@@ -52,7 +52,7 @@ RSpec.describe ActivityPub::Dereferencer do
       end
 
       context 'with signature account' do
-        let(:signature_account) { Fabricate(:account) }
+        let(:signature_actor) { Fabricate(:account) }
 
         it 'makes signed request' do
           subject
diff --git a/spec/lib/activitypub/linked_data_signature_spec.rb b/spec/lib/activitypub/linked_data_signature_spec.rb
index 2222c46fb..d55a7c7fa 100644
--- a/spec/lib/activitypub/linked_data_signature_spec.rb
+++ b/spec/lib/activitypub/linked_data_signature_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe ActivityPub::LinkedDataSignature do
     stub_jsonld_contexts!
   end
 
-  describe '#verify_account!' do
+  describe '#verify_actor!' do
     context 'when signature matches' do
       let(:raw_signature) do
         {
@@ -32,7 +32,7 @@ RSpec.describe ActivityPub::LinkedDataSignature do
       let(:signature) { raw_signature.merge('type' => 'RsaSignature2017', 'signatureValue' => sign(sender, raw_signature, raw_json)) }
 
       it 'returns creator' do
-        expect(subject.verify_account!).to eq sender
+        expect(subject.verify_actor!).to eq sender
       end
     end
 
@@ -40,7 +40,7 @@ RSpec.describe ActivityPub::LinkedDataSignature do
       let(:signature) { nil }
 
       it 'returns nil' do
-        expect(subject.verify_account!).to be_nil
+        expect(subject.verify_actor!).to be_nil
       end
     end
 
@@ -55,7 +55,7 @@ RSpec.describe ActivityPub::LinkedDataSignature do
       let(:signature) { raw_signature.merge('type' => 'RsaSignature2017', 'signatureValue' => 's69F3mfddd99dGjmvjdjjs81e12jn121Gkm1') }
 
       it 'returns nil' do
-        expect(subject.verify_account!).to be_nil
+        expect(subject.verify_actor!).to be_nil
       end
     end
   end
@@ -73,14 +73,14 @@ RSpec.describe ActivityPub::LinkedDataSignature do
     end
 
     it 'can be verified again' do
-      expect(described_class.new(subject).verify_account!).to eq sender
+      expect(described_class.new(subject).verify_actor!).to eq sender
     end
   end
 
-  def sign(from_account, options, document)
+  def sign(from_actor, options, document)
     options_hash   = Digest::SHA256.hexdigest(canonicalize(options.merge('@context' => ActivityPub::LinkedDataSignature::CONTEXT)))
     document_hash  = Digest::SHA256.hexdigest(canonicalize(document))
     to_be_verified = options_hash + document_hash
-    Base64.strict_encode64(from_account.keypair.sign(OpenSSL::Digest.new('SHA256'), to_be_verified))
+    Base64.strict_encode64(from_actor.keypair.sign(OpenSSL::Digest.new('SHA256'), to_be_verified))
   end
 end
diff --git a/spec/services/activitypub/fetch_remote_actor_service_spec.rb b/spec/services/activitypub/fetch_remote_actor_service_spec.rb
new file mode 100644
index 000000000..20117c66d
--- /dev/null
+++ b/spec/services/activitypub/fetch_remote_actor_service_spec.rb
@@ -0,0 +1,180 @@
+require 'rails_helper'
+
+RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do
+  subject { ActivityPub::FetchRemoteActorService.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', id: true) }
+
+    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
+
+    context 'when WebFinger returns a different URI' do
+      let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/bob' }] } }
+
+      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 'does not create account' do
+        expect(account).to be_nil
+      end
+    end
+
+    context 'when WebFinger returns a different URI after a redirection' do
+      let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/bob' }] } }
+
+      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 'does not create account' do
+        expect(account).to be_nil
+      end
+    end
+
+    context 'with wrong id' do
+      it 'does not create account' do
+        expect(subject.call('https://fake.address/@foo', prefetched_body: Oj.dump(actor))).to be_nil
+      end
+    end
+  end
+end
diff --git a/spec/services/activitypub/process_collection_service_spec.rb b/spec/services/activitypub/process_collection_service_spec.rb
index 3eccaab5b..093a188a2 100644
--- a/spec/services/activitypub/process_collection_service_spec.rb
+++ b/spec/services/activitypub/process_collection_service_spec.rb
@@ -68,7 +68,7 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
       let(:forwarder) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/other_account') }
 
       it 'does not process payload if no signature exists' do
-        expect_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_account!).and_return(nil)
+        expect_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(nil)
         expect(ActivityPub::Activity).not_to receive(:factory)
 
         subject.call(json, forwarder)
@@ -77,7 +77,7 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
       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_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(actor)
         expect(ActivityPub::Activity).to receive(:factory).with(instance_of(Hash), actor, instance_of(Hash))
 
         subject.call(json, forwarder)
@@ -86,7 +86,7 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
       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_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(nil)
         expect(ActivityPub::Activity).not_to receive(:factory)
 
         subject.call(json, forwarder)
diff --git a/spec/services/fetch_resource_service_spec.rb b/spec/services/fetch_resource_service_spec.rb
index ded05ffbc..c0c96ab69 100644
--- a/spec/services/fetch_resource_service_spec.rb
+++ b/spec/services/fetch_resource_service_spec.rb
@@ -66,7 +66,7 @@ RSpec.describe FetchResourceService, type: :service do
 
       it 'signs request' do
         subject
-        expect(a_request(:get, url).with(headers: { 'Signature' => /keyId="#{Regexp.escape(ActivityPub::TagManager.instance.uri_for(Account.representative) + '#main-key')}"/ })).to have_been_made
+        expect(a_request(:get, url).with(headers: { 'Signature' => /keyId="#{Regexp.escape(ActivityPub::TagManager.instance.key_uri_for(Account.representative))}"/ })).to have_been_made
       end
 
       context 'when content type is application/atom+xml' do