diff --git a/lib/diaspora_federation/entities/participation.rb b/lib/diaspora_federation/entities/participation.rb index cfa0299..d7e23e2 100644 --- a/lib/diaspora_federation/entities/participation.rb +++ b/lib/diaspora_federation/entities/participation.rb @@ -22,13 +22,22 @@ module DiasporaFederation sender == author end - # Default implementation, don't verify signatures for a {Participation}. + # validates that the parent exists and the parent author is local + def validate_parent + parent = DiasporaFederation.callbacks.trigger(:fetch_related_entity, parent_type, parent_guid) + raise ParentNotLocal, "parent: #{parent_type}:#{parent_guid}" unless parent && parent.local + end + + # Don't verify signatures for a {Participation}. Validate that the parent is local. # @see Entity.populate_entity - # @deprecated remove after {Participation} doesn't include {Relayable} anymore # @param [Nokogiri::XML::Element] root_node xml nodes # @return [Entity] instance private_class_method def self.populate_entity(root_node) - new(entity_data(root_node).merge(parent: nil)) + new(entity_data(root_node).merge(parent: nil)).tap(&:validate_parent) + end + + # Raised, if the parent is not owned by the receiving pod. + class ParentNotLocal < RuntimeError end end end diff --git a/spec/lib/diaspora_federation/entities/participation_spec.rb b/spec/lib/diaspora_federation/entities/participation_spec.rb index fd091ae..cc62b02 100644 --- a/spec/lib/diaspora_federation/entities/participation_spec.rb +++ b/spec/lib/diaspora_federation/entities/participation_spec.rb @@ -44,7 +44,7 @@ XML end end - context "relayable signature verification" do + context "parse xml" do it "does not verify the signature" do data.merge!(author_signature: "aa", parent_author_signature: "bb") xml = Entities::Participation.new(data).to_xml @@ -53,6 +53,39 @@ XML Entities::Participation.from_xml(xml) }.not_to raise_error end + + describe "#validate_parent" do + let(:xml) { + allow(DiasporaFederation.callbacks).to receive(:trigger).and_call_original + Entities::Participation.new(data).to_xml + } + + it "succeeds when the parent is local" do + local_parent = FactoryGirl.build(:related_entity, local: true) + expect_callback(:fetch_related_entity, parent.entity_type, parent.guid).and_return(local_parent) + + expect { + Entities::Participation.from_xml(xml) + }.not_to raise_error + end + + it "raises ParentNotLocal when the parent is not found" do + expect_callback(:fetch_related_entity, parent.entity_type, parent.guid).and_return(nil) + + expect { + Entities::Participation.from_xml(xml) + }.to raise_error Entities::Participation::ParentNotLocal, "parent: #{parent.entity_type}:#{parent.guid}" + end + + it "raises ParentNotLocal when the parent is not local" do + remote_parent = FactoryGirl.build(:related_entity, local: false) + expect_callback(:fetch_related_entity, parent.entity_type, parent.guid).and_return(remote_parent) + + expect { + Entities::Participation.from_xml(xml) + }.to raise_error Entities::Participation::ParentNotLocal, "parent: #{parent.entity_type}:#{parent.guid}" + end + end end end end