diff --git a/app/models/account_migration.rb b/app/models/account_migration.rb index f2b78f85f..8a3c42cab 100644 --- a/app/models/account_migration.rb +++ b/app/models/account_migration.rb @@ -128,7 +128,7 @@ class AccountMigration < ApplicationRecord def person_references references = Person.reflections.reject {|key, _| - %w[profile owner notifications pod account_migration].include?(key) + %w[profile owner notifications pod account_deletion account_migration].include?(key) } references.map {|key, value| diff --git a/app/models/person.rb b/app/models/person.rb index 66f731522..5a61a01ca 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -57,6 +57,7 @@ class Person < ApplicationRecord has_many :mentions, :dependent => :destroy + has_one :account_deletion, dependent: :destroy has_one :account_migration, foreign_key: :old_person_id, dependent: :nullify, inverse_of: :old_person validate :owner_xor_pod diff --git a/app/workers/receive_base.rb b/app/workers/receive_base.rb index b8330aa24..48c424291 100644 --- a/app/workers/receive_base.rb +++ b/app/workers/receive_base.rb @@ -26,6 +26,7 @@ module Workers DiasporaFederation::Salmon::InvalidEncoding, Diaspora::Federation::AuthorIgnored, Diaspora::Federation::InvalidAuthor, + Diaspora::Federation::RecipientClosed, # TODO: deprecated DiasporaFederation::Salmon::MissingMagicEnvelope, DiasporaFederation::Salmon::MissingAuthor, diff --git a/config/initializers/diaspora_federation.rb b/config/initializers/diaspora_federation.rb index a634f33a0..b8e037cce 100644 --- a/config/initializers/diaspora_federation.rb +++ b/config/initializers/diaspora_federation.rb @@ -103,18 +103,9 @@ DiasporaFederation.configure do |config| end on :receive_entity do |entity, sender, recipient_id| - Person.by_account_identifier(sender).pod.try(:schedule_check_if_needed) - unless recipient_id.nil? - User.find_by(id: recipient_id).tap do |user| - next unless user.person.account_migration - - Diaspora::Federation::Dispatcher.build( - user, - user.person.account_migration, - subscribers: [Person.by_account_identifier(sender)] - ).dispatch - end - end + sender_person = Person.by_account_identifier(sender) + sender_person.pod&.schedule_check_if_needed + Diaspora::Federation::Receive.handle_closed_recipient(sender_person, User.find(recipient_id)) if recipient_id case entity when DiasporaFederation::Entities::AccountDeletion diff --git a/lib/diaspora/federation.rb b/lib/diaspora/federation.rb index 1a1bd96b9..8a5bd9ac4 100644 --- a/lib/diaspora/federation.rb +++ b/lib/diaspora/federation.rb @@ -9,6 +9,10 @@ module Diaspora # Raised, if the author of the existing object doesn't match the received author class InvalidAuthor < RuntimeError end + + # Raised, if the recipient account is closed already + class RecipientClosed < RuntimeError + end end end diff --git a/lib/diaspora/federation/receive.rb b/lib/diaspora/federation/receive.rb index 7148c2521..80773ac95 100644 --- a/lib/diaspora/federation/receive.rb +++ b/lib/diaspora/federation/receive.rb @@ -9,6 +9,15 @@ module Diaspora public_send(Mappings.receiver_for(entity), entity) end + def self.handle_closed_recipient(sender, recipient) + return unless recipient.closed_account? + + entity = recipient.person.account_migration || recipient.person.account_deletion + Diaspora::Federation::Dispatcher.build(recipient, entity, subscribers: [sender]).dispatch if entity.present? + + raise Diaspora::Federation::RecipientClosed + end + def self.account_deletion(entity) person = author_of(entity) AccountDeletion.create!(person: person) unless AccountDeletion.where(person: person).exists? diff --git a/spec/federation_callbacks_spec.rb b/spec/federation_callbacks_spec.rb index d9dcb4767..e1931c87a 100644 --- a/spec/federation_callbacks_spec.rb +++ b/spec/federation_callbacks_spec.rb @@ -387,12 +387,13 @@ describe "diaspora federation callbacks" do it "receives a entity for a recipient" do received = Fabricate(:status_message_entity, author: remote_person.diaspora_handle) persisted = FactoryGirl.create(:status_message) - recipient_id = FactoryGirl.create(:user).id + recipient = FactoryGirl.create(:user) + expect(Diaspora::Federation::Receive).to receive(:handle_closed_recipient).with(remote_person, recipient) expect(Diaspora::Federation::Receive).to receive(:perform).with(received).and_return(persisted) - expect(Workers::ReceiveLocal).to receive(:perform_async).with(persisted.class.to_s, persisted.id, [recipient_id]) + expect(Workers::ReceiveLocal).to receive(:perform_async).with(persisted.class.to_s, persisted.id, [recipient.id]) - DiasporaFederation.callbacks.trigger(:receive_entity, received, received.author, recipient_id) + DiasporaFederation.callbacks.trigger(:receive_entity, received, received.author, recipient.id) end it "does not trigger a ReceiveLocal job if Receive.perform returned nil" do diff --git a/spec/lib/account_deleter_spec.rb b/spec/lib/account_deleter_spec.rb index 0a91304f0..9732410f9 100644 --- a/spec/lib/account_deleter_spec.rb +++ b/spec/lib/account_deleter_spec.rb @@ -200,7 +200,7 @@ describe AccountDeleter do it "has all person association keys accounted for" do ignored_or_special_ar_person_associations = %i[comments likes poll_participations contacts notification_actors notifications owner profile pod conversations messages - account_migration] + account_deletion account_migration] all_keys = @account_deletion.normal_ar_person_associates_to_delete + ignored_or_special_ar_person_associations expect(all_keys.sort_by(&:to_s)).to eq(Person.reflections.keys.sort_by(&:to_s).map(&:to_sym)) end diff --git a/spec/lib/diaspora/federation/receive_spec.rb b/spec/lib/diaspora/federation/receive_spec.rb index 1b3e087e7..e34c1bb2c 100644 --- a/spec/lib/diaspora/federation/receive_spec.rb +++ b/spec/lib/diaspora/federation/receive_spec.rb @@ -4,6 +4,58 @@ describe Diaspora::Federation::Receive do let(:sender) { FactoryGirl.create(:person) } let(:post) { FactoryGirl.create(:status_message, text: "hello", public: true, author: alice.person) } + describe ".handle_closed_recipient" do + let(:closed_recipient) { FactoryGirl.create(:user).tap {|u| u.person.lock_access! } } + + it "does nothing if the recipient isn't closed" do + recipient = FactoryGirl.create(:user) + expect { Diaspora::Federation::Receive.handle_closed_recipient(sender, recipient) }.not_to raise_error + end + + it "raises if the recipient is closed, but no AccountMigration and/or AccountDeletion exists" do + expect(Diaspora::Federation::Dispatcher).not_to receive(:build) + expect { Diaspora::Federation::Receive.handle_closed_recipient(sender, closed_recipient) } + .to raise_error(Diaspora::Federation::RecipientClosed) + end + + it "resends AccountMigration if the recipient is closed and an AccountMigration exists" do + migration = AccountMigration.create(old_person: closed_recipient.person, new_person: FactoryGirl.create(:person)) + + dispatcher = double + expect(Diaspora::Federation::Dispatcher).to receive(:build) + .with(closed_recipient, migration, subscribers: [sender]).and_return(dispatcher) + expect(dispatcher).to receive(:dispatch) + + expect { Diaspora::Federation::Receive.handle_closed_recipient(sender, closed_recipient) } + .to raise_error(Diaspora::Federation::RecipientClosed) + end + + it "resends AccountDeletion if the recipient is closed and an AccountDeletion exists" do + deletion = AccountDeletion.create(person: closed_recipient.person) + + dispatcher = double + expect(Diaspora::Federation::Dispatcher).to receive(:build) + .with(closed_recipient, deletion, subscribers: [sender]).and_return(dispatcher) + expect(dispatcher).to receive(:dispatch) + + expect { Diaspora::Federation::Receive.handle_closed_recipient(sender, closed_recipient) } + .to raise_error(Diaspora::Federation::RecipientClosed) + end + + it "resends AccountMigration if the recipient is closed and both an AccountMigration and AccountDeletion exists" do + AccountDeletion.create(person: closed_recipient.person) + migration = AccountMigration.create(old_person: closed_recipient.person, new_person: FactoryGirl.create(:person)) + + dispatcher = double + expect(Diaspora::Federation::Dispatcher).to receive(:build) + .with(closed_recipient, migration, subscribers: [sender]).and_return(dispatcher) + expect(dispatcher).to receive(:dispatch) + + expect { Diaspora::Federation::Receive.handle_closed_recipient(sender, closed_recipient) } + .to raise_error(Diaspora::Federation::RecipientClosed) + end + end + describe ".account_deletion" do let(:account_deletion_entity) { Fabricate(:account_deletion_entity, author: sender.diaspora_handle) }