diff --git a/lib/diaspora_federation.rb b/lib/diaspora_federation.rb index adb7e83..5120099 100644 --- a/lib/diaspora_federation.rb +++ b/lib/diaspora_federation.rb @@ -25,7 +25,6 @@ module DiasporaFederation save_person_after_webfinger fetch_private_key_by_diaspora_id fetch_public_key_by_diaspora_id - fetch_entity_author_id_by_guid fetch_related_entity queue_public_receive queue_private_receive @@ -154,12 +153,6 @@ module DiasporaFederation # @param [String] Diaspora ID of the person # @return [OpenSSL::PKey::RSA] key # - # fetch_entity_author_id_by_guid - # Fetches Diaspora ID of the person who authored the entity identified by a given guid - # @param [String] entity_type (Post, Comment, Like, etc) - # @param [String] guid of the entity - # @return [String] Diaspora ID of the person - # # fetch_related_entity # Fetches a related entity by a given guid # @param [String] entity_type (Post, Comment, Like, etc) diff --git a/lib/diaspora_federation/entities/relayable_retraction.rb b/lib/diaspora_federation/entities/relayable_retraction.rb index e6596b1..5de0dcd 100644 --- a/lib/diaspora_federation/entities/relayable_retraction.rb +++ b/lib/diaspora_federation/entities/relayable_retraction.rb @@ -53,6 +53,19 @@ module DiasporaFederation # @return [String] target author signature property :target_author_signature, default: nil + # target entity + # @return [RelatedEntity] target entity + attr_reader :target + + # Initializes a new relayable retraction entity + # + # @param [Hash] data entity data + # @see DiasporaFederation::Entity#initialize + def initialize(data) + @target = data[:target] if data + super(data) + end + # use only {Retraction} for receive # @return [Retraction] instance as normal retraction def to_retraction @@ -64,33 +77,47 @@ module DiasporaFederation # @param [Nokogiri::XML::Element] root_node xml nodes # @return [Retraction] instance def self.populate_entity(root_node) - super(root_node).to_retraction + entity_data = Hash[class_props.map {|name, type| + [name, parse_element_from_node(name, type, root_node)] + }] + + entity_data[:target] = fetch_target(entity_data[:target_type], entity_data[:target_guid]) + new(entity_data).to_retraction end private_class_method :populate_entity + def self.fetch_target(target_type, target_guid) + DiasporaFederation.callbacks.trigger(:fetch_related_entity, target_type, target_guid).tap do |target| + raise TargetNotFound unless target + end + end + private_class_method :fetch_target + # It updates also the signatures with the keys of the author and the parent # if the signatures are not there yet and if the keys are available. # # @return [Hash] xml elements with updated signatures def xml_elements - target_author = DiasporaFederation.callbacks.trigger(:fetch_entity_author_id_by_guid, target_type, target_guid) privkey = DiasporaFederation.callbacks.trigger(:fetch_private_key_by_diaspora_id, author) super.tap do |xml_elements| - fill_required_signature(target_author, privkey, xml_elements) unless privkey.nil? + fill_required_signature(privkey, xml_elements) unless privkey.nil? end end - # @param [String] target_author the author of the entity to retract # @param [OpenSSL::PKey::RSA] privkey private key of sender # @param [Hash] hash hash given for a signing - def fill_required_signature(target_author, privkey, hash) - if target_author == author && target_author_signature.nil? + def fill_required_signature(privkey, hash) + if target.author == author && target_author_signature.nil? hash[:target_author_signature] = SignedRetraction.sign_with_key(privkey, self) - elsif target_author != author && parent_author_signature.nil? + elsif target.parent.author == author && parent_author_signature.nil? hash[:parent_author_signature] = SignedRetraction.sign_with_key(privkey, self) end end + + # Raised, if the target of the {Retraction} was not found. + class TargetNotFound < RuntimeError + end end end end diff --git a/lib/diaspora_federation/test/factories.rb b/lib/diaspora_federation/test/factories.rb index 1f61cd7..5512f05 100644 --- a/lib/diaspora_federation/test/factories.rb +++ b/lib/diaspora_federation/test/factories.rb @@ -155,6 +155,7 @@ module DiasporaFederation author { generate(:diaspora_id) } target_guid { generate(:guid) } target_type "Comment" + target { FactoryGirl.build(:related_entity, author: author) } end factory :reshare_entity, class: DiasporaFederation::Entities::Reshare do diff --git a/lib/diaspora_federation/validators/relayable_retraction_validator.rb b/lib/diaspora_federation/validators/relayable_retraction_validator.rb index 7fa2245..c062f15 100644 --- a/lib/diaspora_federation/validators/relayable_retraction_validator.rb +++ b/lib/diaspora_federation/validators/relayable_retraction_validator.rb @@ -6,8 +6,8 @@ module DiasporaFederation include Validation rule :target_guid, :guid - rule :target_type, :not_empty + rule :target, :not_nil rule :author, %i(not_empty diaspora_id) end diff --git a/spec/factories.rb b/spec/factories.rb index 61ed6fd..3dc7213 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -27,6 +27,12 @@ FactoryGirl.define do after(:create, &:save) end + factory :comment, class: Entity do + entity_type "Comment" + author { FactoryGirl.build(:person) } + after(:create, &:save) + end + factory :poll, class: Entity do entity_type "Poll" author { FactoryGirl.build(:person) } diff --git a/spec/lib/diaspora_federation/entities/relayable_retraction_spec.rb b/spec/lib/diaspora_federation/entities/relayable_retraction_spec.rb index 721577f..d786d35 100644 --- a/spec/lib/diaspora_federation/entities/relayable_retraction_spec.rb +++ b/spec/lib/diaspora_federation/entities/relayable_retraction_spec.rb @@ -1,8 +1,23 @@ module DiasporaFederation describe Entities::RelayableRetraction do + let(:target) { FactoryGirl.create(:comment, author: bob) } + let(:target_entity) { + FactoryGirl.build( + :related_entity, + author: bob.diaspora_id, + parent: FactoryGirl.build(:related_entity, author: alice.diaspora_id) + ) + } let(:data) { - FactoryGirl.build(:relayable_retraction_entity, author: alice.diaspora_id).send(:xml_elements).tap do |data| + FactoryGirl.build( + :relayable_retraction_entity, + author: alice.diaspora_id, + target_guid: target.guid, + target_type: target.entity_type, + target: target_entity + ).send(:xml_elements).tap do |data| data[:target_author_signature] = nil + data[:target] = target_entity end } @@ -18,7 +33,7 @@ module DiasporaFederation XML } - it_behaves_like "an Entity subclass" + it_behaves_like "an Entity subclass", [:target] it_behaves_like "an XML Entity", %i(parent_author_signature target_author_signature) @@ -27,10 +42,6 @@ XML let(:hash) { FactoryGirl.attributes_for(:relayable_retraction_entity) } it "updates author signature when it was nil and key was supplied" do - expect(DiasporaFederation.callbacks).to receive(:trigger).with( - :fetch_entity_author_id_by_guid, hash[:target_type], hash[:target_guid] - ).and_return(hash[:author]) - expect(DiasporaFederation.callbacks).to receive(:trigger).with( :fetch_private_key_by_diaspora_id, hash[:author] ).and_return(author_pkey) @@ -43,10 +54,9 @@ XML expect(author_pkey.verify(OpenSSL::Digest::SHA256.new, signature, signed_string)).to be_truthy end - it "updates parent author signature when it was nil, key was supplied and sender is not author of the target" do - expect(DiasporaFederation.callbacks).to receive(:trigger).with( - :fetch_entity_author_id_by_guid, hash[:target_type], hash[:target_guid] - ).and_return(FactoryGirl.generate(:diaspora_id)) + it "updates parent author signature when it was nil, key was supplied and sender is author of the parent" do + parent = FactoryGirl.build(:related_entity, author: hash[:author]) + hash[:target] = FactoryGirl.build(:related_entity, author: bob.diaspora_id, parent: parent) expect(DiasporaFederation.callbacks).to receive(:trigger).with( :fetch_private_key_by_diaspora_id, hash[:author] @@ -74,10 +84,6 @@ XML :fetch_private_key_by_diaspora_id, hash[:author] ).and_return(nil) - expect(DiasporaFederation.callbacks).to receive(:trigger).with( - :fetch_entity_author_id_by_guid, "Comment", hash[:target_guid] - ).and_return(hash[:author]) - xml = Entities::RelayableRetraction.new(hash).to_xml expect(xml.at_xpath("target_author_signature").text).to eq("") expect(xml.at_xpath("parent_author_signature").text).to eq("") diff --git a/test/dummy/config/initializers/diaspora_federation.rb b/test/dummy/config/initializers/diaspora_federation.rb index acd5b41..fdd8339 100644 --- a/test/dummy/config/initializers/diaspora_federation.rb +++ b/test/dummy/config/initializers/diaspora_federation.rb @@ -71,10 +71,6 @@ DiasporaFederation.configure do |config| OpenSSL::PKey::RSA.new(key) unless key.nil? end - on :fetch_entity_author_id_by_guid do |entity_type, guid| - Entity.where(entity_type: entity_type, guid: guid).joins(:author).pluck(:diaspora_id).first - end - on :fetch_related_entity do |entity_type, guid| entity = Entity.find_by(entity_type: entity_type, guid: guid) if entity