about summary refs log tree commit diff
path: root/spec
diff options
context:
space:
mode:
authorThibaut Girka <thib@sitedethib.com>2020-06-09 10:39:20 +0200
committerThibaut Girka <thib@sitedethib.com>2020-06-09 10:39:20 +0200
commit12c8ac9e1443d352eca3538ed1558de8ccdd9434 (patch)
treeed480d77b29f0d571ad219190288bde3b0c09b32 /spec
parentf328f2faa3fbdb182921366c6a20e745c069b840 (diff)
parent89f40b6c3ec525b09d02f21e9b45276084167d8d (diff)
Merge branch 'master' into glitch-soc/merge-upstream
Conflicts:
- `app/controllers/activitypub/collections_controller.rb`:
  Conflict due to glitch-soc having to take care of local-only
  pinned toots in that controller.
  Took upstream's changes and restored the local-only special
  handling.
- `app/controllers/auth/sessions_controller.rb`:
  Minor conflicts due to the theming system, applied upstream
  changes, adapted the following two files for glitch-soc's
  theming system:
  - `app/controllers/concerns/sign_in_token_authentication_concern.rb`
  - `app/controllers/concerns/two_factor_authentication_concern.rb`
- `app/services/backup_service.rb`:
  Minor conflict due to glitch-soc having to handle local-only
  toots specially. Applied upstream changes and restored
  the local-only special handling.
- `app/views/admin/custom_emojis/index.html.haml`:
  Minor conflict due to the theming system.
- `package.json`:
  Upstream dependency updated, too close to a glitch-soc-only
  dependency in the file.
- `yarn.lock`:
  Upstream dependency updated, too close to a glitch-soc-only
  dependency in the file.
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/activitypub/replies_controller_spec.rb17
-rw-r--r--spec/controllers/auth/sessions_controller_spec.rb66
-rw-r--r--spec/fabricators/device_fabricator.rb8
-rw-r--r--spec/fabricators/encrypted_message_fabricator.rb8
-rw-r--r--spec/fabricators/one_time_key_fabricator.rb11
-rw-r--r--spec/fabricators/system_key_fabricator.rb3
-rw-r--r--spec/lib/activitypub/activity/create_spec.rb56
-rw-r--r--spec/mailers/previews/user_mailer_preview.rb5
-rw-r--r--spec/models/device_spec.rb5
-rw-r--r--spec/models/encrypted_message_spec.rb5
-rw-r--r--spec/models/one_time_key_spec.rb5
-rw-r--r--spec/models/system_key_spec.rb5
-rw-r--r--spec/services/clear_domain_media_service_spec.rb23
-rw-r--r--spec/workers/domain_block_worker_spec.rb4
-rw-r--r--spec/workers/domain_clear_media_worker_spec.rb26
15 files changed, 241 insertions, 6 deletions
diff --git a/spec/controllers/activitypub/replies_controller_spec.rb b/spec/controllers/activitypub/replies_controller_spec.rb
index a5ed14180..d956e1b35 100644
--- a/spec/controllers/activitypub/replies_controller_spec.rb
+++ b/spec/controllers/activitypub/replies_controller_spec.rb
@@ -4,6 +4,7 @@ require 'rails_helper'
 
 RSpec.describe ActivityPub::RepliesController, type: :controller do
   let(:status) { Fabricate(:status, visibility: parent_visibility) }
+  let(:remote_reply_id) { nil }
   let(:remote_account) { nil }
 
   before do
@@ -14,6 +15,8 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do
     Fabricate(:status, thread: status, visibility: :private)
     Fabricate(:status, account: status.account, thread: status, visibility: :public)
     Fabricate(:status, account: status.account, thread: status, visibility: :private)
+
+    Fabricate(:status, account: remote_account, thread: status, visibility: :public, uri: remote_reply_id) if remote_reply_id
   end
 
   describe 'GET #index' do
@@ -110,6 +113,20 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do
               expect(json[:first][:items].size).to eq 2
               expect(json[:first][:items].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true
             end
+
+            context 'with remote responses' do
+              let(:remote_reply_id) { 'foo' }
+
+              it 'returned items are all inlined local toots or are ids' do
+                json = body_as_json
+
+                expect(json[:first]).to be_a Hash
+                expect(json[:first][:items]).to be_an Array
+                expect(json[:first][:items].size).to eq 3
+                expect(json[:first][:items].all? { |item| item.is_a?(Hash) ? ActivityPub::TagManager.instance.local_uri?(item[:id]) : item.is_a?(String) }).to be true
+                expect(json[:first][:items]).to include remote_reply_id
+              end
+            end
           end
         end
 
diff --git a/spec/controllers/auth/sessions_controller_spec.rb b/spec/controllers/auth/sessions_controller_spec.rb
index 1950c173a..c387842cd 100644
--- a/spec/controllers/auth/sessions_controller_spec.rb
+++ b/spec/controllers/auth/sessions_controller_spec.rb
@@ -215,7 +215,7 @@ RSpec.describe Auth::SessionsController, type: :controller do
 
       context 'using a valid OTP' do
         before do
-          post :create, params: { user: { otp_attempt: user.current_otp } }, session: { otp_user_id: user.id }
+          post :create, params: { user: { otp_attempt: user.current_otp } }, session: { attempt_user_id: user.id }
         end
 
         it 'redirects to home' do
@@ -230,7 +230,7 @@ RSpec.describe Auth::SessionsController, type: :controller do
       context 'when the server has an decryption error' do
         before do
           allow_any_instance_of(User).to receive(:validate_and_consume_otp!).and_raise(OpenSSL::Cipher::CipherError)
-          post :create, params: { user: { otp_attempt: user.current_otp } }, session: { otp_user_id: user.id }
+          post :create, params: { user: { otp_attempt: user.current_otp } }, session: { attempt_user_id: user.id }
         end
 
         it 'shows a login error' do
@@ -244,7 +244,7 @@ RSpec.describe Auth::SessionsController, type: :controller do
 
       context 'using a valid recovery code' do
         before do
-          post :create, params: { user: { otp_attempt: recovery_codes.first } }, session: { otp_user_id: user.id }
+          post :create, params: { user: { otp_attempt: recovery_codes.first } }, session: { attempt_user_id: user.id }
         end
 
         it 'redirects to home' do
@@ -258,7 +258,7 @@ RSpec.describe Auth::SessionsController, type: :controller do
 
       context 'using an invalid OTP' do
         before do
-          post :create, params: { user: { otp_attempt: 'wrongotp' } }, session: { otp_user_id: user.id }
+          post :create, params: { user: { otp_attempt: 'wrongotp' } }, session: { attempt_user_id: user.id }
         end
 
         it 'shows a login error' do
@@ -270,5 +270,63 @@ RSpec.describe Auth::SessionsController, type: :controller do
         end
       end
     end
+
+    context 'when 2FA is disabled and IP is unfamiliar' do
+      let!(:user) { Fabricate(:user, email: 'x@y.com', password: 'abcdefgh', current_sign_in_at: 3.weeks.ago, current_sign_in_ip: '0.0.0.0') }
+
+      before do
+        request.remote_ip  = '10.10.10.10'
+        request.user_agent = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0'
+
+        allow(UserMailer).to receive(:sign_in_token).and_return(double('email', deliver_later!: nil))
+      end
+
+      context 'using email and password' do
+        before do
+          post :create, params: { user: { email: user.email, password: user.password } }
+        end
+
+        it 'renders sign in token authentication page' do
+          expect(controller).to render_template("sign_in_token")
+        end
+
+        it 'generates sign in token' do
+          expect(user.reload.sign_in_token).to_not be_nil
+        end
+
+        it 'sends sign in token e-mail' do
+          expect(UserMailer).to have_received(:sign_in_token)
+        end
+      end
+
+      context 'using a valid sign in token' do
+        before do
+          user.generate_sign_in_token && user.save
+          post :create, params: { user: { sign_in_token_attempt: user.sign_in_token } }, session: { attempt_user_id: user.id }
+        end
+
+        it 'redirects to home' do
+          expect(response).to redirect_to(root_path)
+        end
+
+        it 'logs the user in' do
+          expect(controller.current_user).to eq user
+        end
+      end
+
+      context 'using an invalid sign in token' do
+        before do
+          post :create, params: { user: { sign_in_token_attempt: 'wrongotp' } }, session: { attempt_user_id: user.id }
+        end
+
+        it 'shows a login error' do
+          expect(flash[:alert]).to match I18n.t('users.invalid_sign_in_token')
+        end
+
+        it "doesn't log the user in" do
+          expect(controller.current_user).to be_nil
+        end
+      end
+    end
   end
 end
diff --git a/spec/fabricators/device_fabricator.rb b/spec/fabricators/device_fabricator.rb
new file mode 100644
index 000000000..b15d8248f
--- /dev/null
+++ b/spec/fabricators/device_fabricator.rb
@@ -0,0 +1,8 @@
+Fabricator(:device) do
+  access_token
+  account
+  device_id        { Faker::Number.number(digits: 5) }
+  name             { Faker::App.name }
+  fingerprint_key  { Base64.strict_encode64(Ed25519::SigningKey.generate.verify_key.to_bytes) }
+  identity_key     { Base64.strict_encode64(Ed25519::SigningKey.generate.verify_key.to_bytes) }
+end
diff --git a/spec/fabricators/encrypted_message_fabricator.rb b/spec/fabricators/encrypted_message_fabricator.rb
new file mode 100644
index 000000000..e65f66302
--- /dev/null
+++ b/spec/fabricators/encrypted_message_fabricator.rb
@@ -0,0 +1,8 @@
+Fabricator(:encrypted_message) do
+  device
+  from_account
+  from_device_id   { Faker::Number.number(digits: 5) }
+  type             0
+  body             ""
+  message_franking ""
+end
diff --git a/spec/fabricators/one_time_key_fabricator.rb b/spec/fabricators/one_time_key_fabricator.rb
new file mode 100644
index 000000000..8794baeb5
--- /dev/null
+++ b/spec/fabricators/one_time_key_fabricator.rb
@@ -0,0 +1,11 @@
+Fabricator(:one_time_key) do
+  device
+  key_id { Faker::Alphanumeric.alphanumeric(number: 10) }
+  key    { Base64.strict_encode64(Ed25519::SigningKey.generate.verify_key.to_bytes) }
+
+  signature do |attrs|
+    signing_key = Ed25519::SigningKey.generate
+    attrs[:device].update(fingerprint_key: Base64.strict_encode64(signing_key.verify_key.to_bytes))
+    Base64.strict_encode64(signing_key.sign(attrs[:key]))
+  end
+end
diff --git a/spec/fabricators/system_key_fabricator.rb b/spec/fabricators/system_key_fabricator.rb
new file mode 100644
index 000000000..f808495e0
--- /dev/null
+++ b/spec/fabricators/system_key_fabricator.rb
@@ -0,0 +1,3 @@
+Fabricator(:system_key) do
+
+end
diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb
index 5220deabb..2ac4acc12 100644
--- a/spec/lib/activitypub/activity/create_spec.rb
+++ b/spec/lib/activitypub/activity/create_spec.rb
@@ -579,6 +579,62 @@ RSpec.describe ActivityPub::Activity::Create do
       end
     end
 
+    context 'with an encrypted message' do
+      let(:recipient) { Fabricate(:account) }
+      let(:target_device) { Fabricate(:device, account: recipient) }
+
+      subject { described_class.new(json, sender, delivery: true, delivered_to_account_id: recipient.id) }
+
+      let(:object_json) do
+        {
+          id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
+          type: 'EncryptedMessage',
+          attributedTo: {
+            type: 'Device',
+            deviceId: '1234',
+          },
+          to: {
+            type: 'Device',
+            deviceId: target_device.device_id,
+          },
+          messageType: 1,
+          cipherText: 'Foo',
+          messageFranking: 'Baz678',
+          digest: {
+            digestAlgorithm: 'Bar456',
+            digestValue: 'Foo123',
+          },
+        }
+      end
+
+      before do
+        subject.perform
+      end
+
+      it 'creates an encrypted message' do
+        encrypted_message = target_device.encrypted_messages.reload.first
+
+        expect(encrypted_message).to_not be_nil
+        expect(encrypted_message.from_device_id).to eq '1234'
+        expect(encrypted_message.from_account).to eq sender
+        expect(encrypted_message.type).to eq 1
+        expect(encrypted_message.body).to eq 'Foo'
+        expect(encrypted_message.digest).to eq 'Foo123'
+      end
+
+      it 'creates a message franking' do
+        encrypted_message = target_device.encrypted_messages.reload.first
+        message_franking  = encrypted_message.message_franking
+
+        crypt = ActiveSupport::MessageEncryptor.new(SystemKey.current_key, serializer: Oj)
+        json  = crypt.decrypt_and_verify(message_franking)
+
+        expect(json['source_account_id']).to eq sender.id
+        expect(json['target_account_id']).to eq recipient.id
+        expect(json['original_franking']).to eq 'Baz678'
+      end
+    end
+
     context 'when sender is followed by local users' do
       subject { described_class.new(json, sender, delivery: true) }
 
diff --git a/spec/mailers/previews/user_mailer_preview.rb b/spec/mailers/previews/user_mailer_preview.rb
index 464f177d0..313666412 100644
--- a/spec/mailers/previews/user_mailer_preview.rb
+++ b/spec/mailers/previews/user_mailer_preview.rb
@@ -59,4 +59,9 @@ class UserMailerPreview < ActionMailer::Preview
   def warning
     UserMailer.warning(User.first, AccountWarning.new(text: '', action: :silence), [Status.first.id])
   end
+
+  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/sign_in_token
+  def sign_in_token
+    UserMailer.sign_in_token(User.first.tap { |user| user.generate_sign_in_token }, '127.0.0.1', 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0', Time.now.utc)
+  end
 end
diff --git a/spec/models/device_spec.rb b/spec/models/device_spec.rb
new file mode 100644
index 000000000..f56fbf978
--- /dev/null
+++ b/spec/models/device_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe Device, type: :model do
+
+end
diff --git a/spec/models/encrypted_message_spec.rb b/spec/models/encrypted_message_spec.rb
new file mode 100644
index 000000000..1238d57b6
--- /dev/null
+++ b/spec/models/encrypted_message_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe EncryptedMessage, type: :model do
+
+end
diff --git a/spec/models/one_time_key_spec.rb b/spec/models/one_time_key_spec.rb
new file mode 100644
index 000000000..34598334c
--- /dev/null
+++ b/spec/models/one_time_key_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe OneTimeKey, type: :model do
+
+end
diff --git a/spec/models/system_key_spec.rb b/spec/models/system_key_spec.rb
new file mode 100644
index 000000000..a138bc131
--- /dev/null
+++ b/spec/models/system_key_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe SystemKey, type: :model do
+
+end
diff --git a/spec/services/clear_domain_media_service_spec.rb b/spec/services/clear_domain_media_service_spec.rb
new file mode 100644
index 000000000..8e58c6039
--- /dev/null
+++ b/spec/services/clear_domain_media_service_spec.rb
@@ -0,0 +1,23 @@
+require 'rails_helper'
+
+RSpec.describe ClearDomainMediaService, type: :service do
+  let!(:bad_account) { Fabricate(:account, username: 'badguy666', domain: 'evil.org') }
+  let!(:bad_status1) { Fabricate(:status, account: bad_account, text: 'You suck') }
+  let!(:bad_status2) { Fabricate(:status, account: bad_account, text: 'Hahaha') }
+  let!(:bad_attachment) { Fabricate(:media_attachment, account: bad_account, status: bad_status2, file: attachment_fixture('attachment.jpg')) }
+
+  subject { ClearDomainMediaService.new }
+
+  describe 'for a silence with reject media' do
+    before do
+      subject.call(DomainBlock.create!(domain: 'evil.org', severity: :silence, reject_media: true))
+    end
+
+    it 'leaves the domains status and attachements, but clears media' do
+      expect { bad_status1.reload }.not_to raise_error
+      expect { bad_status2.reload }.not_to raise_error
+      expect { bad_attachment.reload }.not_to raise_error
+      expect(bad_attachment.file.exists?).to be false
+    end
+  end
+end
diff --git a/spec/workers/domain_block_worker_spec.rb b/spec/workers/domain_block_worker_spec.rb
index 48b3e38c4..bd8fc4a62 100644
--- a/spec/workers/domain_block_worker_spec.rb
+++ b/spec/workers/domain_block_worker_spec.rb
@@ -8,7 +8,7 @@ describe DomainBlockWorker do
   describe 'perform' do
     let(:domain_block) { Fabricate(:domain_block) }
 
-    it 'returns true for non-existent domain block' do
+    it 'calls domain block service for relevant domain block' do
       service = double(call: nil)
       allow(BlockDomainService).to receive(:new).and_return(service)
       result = subject.perform(domain_block.id)
@@ -17,7 +17,7 @@ describe DomainBlockWorker do
       expect(service).to have_received(:call).with(domain_block, false)
     end
 
-    it 'calls domain block service for relevant domain block' do
+    it 'returns true for non-existent domain block' do
       result = subject.perform('aaa')
 
       expect(result).to eq(true)
diff --git a/spec/workers/domain_clear_media_worker_spec.rb b/spec/workers/domain_clear_media_worker_spec.rb
new file mode 100644
index 000000000..36251b1ec
--- /dev/null
+++ b/spec/workers/domain_clear_media_worker_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe DomainClearMediaWorker do
+  subject { described_class.new }
+
+  describe 'perform' do
+    let(:domain_block) { Fabricate(:domain_block, severity: :silence, reject_media: true) }
+
+    it 'calls domain clear media service for relevant domain block' do
+      service = double(call: nil)
+      allow(ClearDomainMediaService).to receive(:new).and_return(service)
+      result = subject.perform(domain_block.id)
+
+      expect(result).to be_nil
+      expect(service).to have_received(:call).with(domain_block)
+    end
+
+    it 'returns true for non-existent domain block' do
+      result = subject.perform('aaa')
+
+      expect(result).to eq(true)
+    end
+  end
+end