diff --git a/lib/diaspora_federation/entities/comment.rb b/lib/diaspora_federation/entities/comment.rb index a047560..dfd91b6 100644 --- a/lib/diaspora_federation/entities/comment.rb +++ b/lib/diaspora_federation/entities/comment.rb @@ -8,6 +8,9 @@ module DiasporaFederation # @deprecated LEGACY_SIGNATURE_ORDER = %i(guid parent_guid text author).freeze + # The {Comment} parent is a {Post} + PARENT_TYPE = "Post".freeze + include Relayable # @!attribute [r] text @@ -22,7 +25,7 @@ module DiasporaFederation # The {Comment} parent is a Post # @return [String] parent type def parent_type - "Post" + PARENT_TYPE end end end diff --git a/lib/diaspora_federation/entities/message.rb b/lib/diaspora_federation/entities/message.rb index 3854463..892e37e 100644 --- a/lib/diaspora_federation/entities/message.rb +++ b/lib/diaspora_federation/entities/message.rb @@ -8,6 +8,9 @@ module DiasporaFederation # @deprecated LEGACY_SIGNATURE_ORDER = %i(guid parent_guid text created_at author conversation_guid).freeze + # The {Message} parent is a {Conversation} + PARENT_TYPE = "Conversation".freeze + include Relayable # @!attribute [r] text @@ -29,7 +32,7 @@ module DiasporaFederation # The {Message} parent is a {Conversation} # @return [String] parent type def parent_type - "Conversation" + PARENT_TYPE end end end diff --git a/lib/diaspora_federation/entities/poll_participation.rb b/lib/diaspora_federation/entities/poll_participation.rb index 3f2534a..408181f 100644 --- a/lib/diaspora_federation/entities/poll_participation.rb +++ b/lib/diaspora_federation/entities/poll_participation.rb @@ -8,6 +8,9 @@ module DiasporaFederation # @deprecated LEGACY_SIGNATURE_ORDER = %i(guid parent_guid author poll_answer_guid).freeze + # The {PollParticipation} parent is a {Poll} + PARENT_TYPE = "Poll".freeze + include Relayable # @!attribute [r] poll_answer_guid @@ -19,7 +22,7 @@ module DiasporaFederation # The {PollParticipation} parent is a {Poll} # @return [String] parent type def parent_type - "Poll" + PARENT_TYPE end end end diff --git a/lib/diaspora_federation/entities/relayable.rb b/lib/diaspora_federation/entities/relayable.rb index 948d638..abb8376 100644 --- a/lib/diaspora_federation/entities/relayable.rb +++ b/lib/diaspora_federation/entities/relayable.rb @@ -10,6 +10,10 @@ module DiasporaFederation # digest instance used for signing DIGEST = OpenSSL::Digest::SHA256.new + # parent entity + # @return [RelatedEntity] parent entity + attr_reader :parent + # order from the parsed xml for signature # @return [Array] order from xml attr_reader :xml_order @@ -68,6 +72,7 @@ module DiasporaFederation # @param [Hash] additional_xml_elements additional xml elements # @see DiasporaFederation::Entity#initialize def initialize(data, xml_order=nil, additional_xml_elements={}) + @parent = data[:parent] if data @xml_order = xml_order @additional_xml_elements = additional_xml_elements @@ -197,8 +202,18 @@ module DiasporaFederation end end + add_parent(entity_data) new(entity_data, xml_order, additional_xml_elements).tap(&:verify_signatures) end + + def add_parent(data) + data[:parent] = fetch_parent(data) + end + + def fetch_parent(data) + type = data[:parent_type] || self::PARENT_TYPE + DiasporaFederation.callbacks.trigger(:fetch_related_entity, type, data[:parent_guid]) + end end # Raised, if creating the author_signature failes, because the private key was not found diff --git a/lib/diaspora_federation/test/factories.rb b/lib/diaspora_federation/test/factories.rb index c14946e..1f61cd7 100644 --- a/lib/diaspora_federation/test/factories.rb +++ b/lib/diaspora_federation/test/factories.rb @@ -87,6 +87,7 @@ module DiasporaFederation factory :relayable_entity, class: DiasporaFederation::Entities::Relayable do parent_guid { generate(:guid) } + parent { FactoryGirl.build(:related_entity) } end factory :participation_entity, diff --git a/lib/diaspora_federation/validators/relayable_validator.rb b/lib/diaspora_federation/validators/relayable_validator.rb index 7fc3557..3f14195 100644 --- a/lib/diaspora_federation/validators/relayable_validator.rb +++ b/lib/diaspora_federation/validators/relayable_validator.rb @@ -9,6 +9,7 @@ module DiasporaFederation rule :author, %i(not_empty diaspora_id) rule :guid, :guid rule :parent_guid, :guid + rule :parent, :not_nil end end end diff --git a/spec/integration/comment_integration_spec.rb b/spec/integration/comment_integration_spec.rb index a42930f..b48698a 100644 --- a/spec/integration/comment_integration_spec.rb +++ b/spec/integration/comment_integration_spec.rb @@ -60,8 +60,11 @@ KEY let(:new_data) { "foobar" } let(:text) { "this is a very informative comment" } + let(:parent) { FactoryGirl.build(:related_entity, author: bob.diaspora_id) } let(:comment) { - Entities::Comment.new(author: author, guid: guid, parent_guid: parent_guid, text: text, new_data: new_data) + Entities::Comment.new( + author: author, guid: guid, parent_guid: parent_guid, text: text, parent: parent, new_data: new_data + ) } let(:legacy_comment_xml_alice) { @@ -204,6 +207,9 @@ XML expect(DiasporaFederation.callbacks).to receive(:trigger).with( :fetch_author_private_key_by_entity_guid, "Post", parent_guid ).and_return(parent_key) + expect(DiasporaFederation.callbacks).to receive(:trigger).with( + :fetch_related_entity, "Post", parent_guid + ).and_return(parent) xml = Nokogiri::XML::Document.parse(new_data_comment_xml_alice).root Salmon::XmlPayload.unpack(xml).to_xml @@ -221,6 +227,9 @@ XML expect(DiasporaFederation.callbacks).to receive(:trigger).with( :fetch_author_private_key_by_entity_guid, "Post", parent_guid ).and_return(parent_key) + expect(DiasporaFederation.callbacks).to receive(:trigger).with( + :fetch_related_entity, "Post", parent_guid + ).and_return(parent) end it "relays legacy signatures and xml" do @@ -253,6 +262,9 @@ XML expect(DiasporaFederation.callbacks).to receive(:trigger).with( :fetch_author_public_key_by_entity_guid, "Post", parent_guid ).and_return(parent_key.public_key) + expect(DiasporaFederation.callbacks).to receive(:trigger).with( + :fetch_related_entity, "Post", parent_guid + ).and_return(parent) end it "parses legacy signatures and xml" do diff --git a/spec/lib/diaspora_federation/entities/comment_spec.rb b/spec/lib/diaspora_federation/entities/comment_spec.rb index c270ab3..37806cb 100644 --- a/spec/lib/diaspora_federation/entities/comment_spec.rb +++ b/spec/lib/diaspora_federation/entities/comment_spec.rb @@ -1,9 +1,10 @@ module DiasporaFederation describe Entities::Comment do let(:parent) { FactoryGirl.create(:post, author: bob) } + let(:parent_entity) { FactoryGirl.build(:related_entity, author: bob.diaspora_id) } let(:data) { - FactoryGirl.build(:comment_entity, author: alice.diaspora_id, parent_guid: parent.guid).send(:xml_elements) - .merge(created_at: Time.now.utc) + FactoryGirl.build(:comment_entity, author: alice.diaspora_id, parent_guid: parent.guid, parent: parent_entity) + .send(:xml_elements).merge(created_at: Time.now.utc, parent: parent_entity) } let(:xml) { @@ -19,7 +20,7 @@ module DiasporaFederation XML } - it_behaves_like "an Entity subclass" + it_behaves_like "an Entity subclass", [:parent] it_behaves_like "an XML Entity", [:created_at] @@ -35,6 +36,7 @@ XML created_at = Time.now.utc - 1.minute comment_data = FactoryGirl.build(:comment_entity, author: alice.diaspora_id, parent_guid: parent.guid).to_h comment_data[:created_at] = created_at + comment_data[:parent] = parent_entity comment = described_class.new(comment_data, %i(author guid parent_guid text created_at)) parsed_comment = described_class.from_xml(comment.to_xml) diff --git a/spec/lib/diaspora_federation/entities/conversation_spec.rb b/spec/lib/diaspora_federation/entities/conversation_spec.rb index 8022170..0bf4425 100644 --- a/spec/lib/diaspora_federation/entities/conversation_spec.rb +++ b/spec/lib/diaspora_federation/entities/conversation_spec.rb @@ -1,13 +1,14 @@ module DiasporaFederation describe Entities::Conversation do let(:parent) { FactoryGirl.create(:conversation, author: bob) } + let(:parent_entity) { FactoryGirl.build(:related_entity, author: bob.diaspora_id) } let(:signed_msg1) { msg = FactoryGirl.build(:message_entity, author: alice.diaspora_id, parent_guid: parent.guid).send(:xml_elements) - Entities::Message.new(msg) + Entities::Message.new(msg.merge(parent: parent_entity)) } let(:signed_msg2) { msg = FactoryGirl.build(:message_entity, author: alice.diaspora_id, parent_guid: parent.guid).send(:xml_elements) - Entities::Message.new(msg) + Entities::Message.new(msg.merge(parent: parent_entity)) } let(:data) { FactoryGirl.attributes_for(:conversation_entity).merge!( diff --git a/spec/lib/diaspora_federation/entities/like_spec.rb b/spec/lib/diaspora_federation/entities/like_spec.rb index daf1af8..bbce006 100644 --- a/spec/lib/diaspora_federation/entities/like_spec.rb +++ b/spec/lib/diaspora_federation/entities/like_spec.rb @@ -1,13 +1,15 @@ module DiasporaFederation describe Entities::Like do let(:parent) { FactoryGirl.create(:post, author: bob) } + let(:parent_entity) { FactoryGirl.build(:related_entity, author: bob.diaspora_id) } let(:data) { FactoryGirl.build( :like_entity, author: alice.diaspora_id, parent_guid: parent.guid, - parent_type: parent.entity_type - ).send(:xml_elements) + parent_type: parent.entity_type, + parent: parent_entity + ).send(:xml_elements).merge(parent: parent_entity) } let(:xml) { @@ -24,7 +26,7 @@ module DiasporaFederation XML } - it_behaves_like "an Entity subclass" + it_behaves_like "an Entity subclass", [:parent] it_behaves_like "an XML Entity" diff --git a/spec/lib/diaspora_federation/entities/message_spec.rb b/spec/lib/diaspora_federation/entities/message_spec.rb index e203314..48b710c 100644 --- a/spec/lib/diaspora_federation/entities/message_spec.rb +++ b/spec/lib/diaspora_federation/entities/message_spec.rb @@ -1,8 +1,10 @@ module DiasporaFederation describe Entities::Message do let(:parent) { FactoryGirl.create(:conversation, author: bob) } + let(:parent_entity) { FactoryGirl.build(:related_entity, author: bob.diaspora_id) } let(:data) { - FactoryGirl.build(:message_entity, author: alice.diaspora_id, parent_guid: parent.guid).send(:xml_elements) + FactoryGirl.build(:message_entity, author: alice.diaspora_id, parent_guid: parent.guid, parent: parent_entity) + .send(:xml_elements).merge(parent: parent_entity) } let(:xml) { @@ -20,7 +22,7 @@ module DiasporaFederation XML } - it_behaves_like "an Entity subclass" + it_behaves_like "an Entity subclass", [:parent] it_behaves_like "an XML Entity" diff --git a/spec/lib/diaspora_federation/entities/participation_spec.rb b/spec/lib/diaspora_federation/entities/participation_spec.rb index 4e0e5ba..a47cf67 100644 --- a/spec/lib/diaspora_federation/entities/participation_spec.rb +++ b/spec/lib/diaspora_federation/entities/participation_spec.rb @@ -1,13 +1,15 @@ module DiasporaFederation describe Entities::Participation do let(:parent) { FactoryGirl.create(:post, author: bob) } + let(:parent_entity) { FactoryGirl.build(:related_entity, author: bob.diaspora_id) } let(:data) { FactoryGirl.build( :participation_entity, author: alice.diaspora_id, parent_guid: parent.guid, - parent_type: parent.entity_type - ).send(:xml_elements) + parent_type: parent.entity_type, + parent: parent_entity + ).send(:xml_elements).merge(parent: parent_entity) } let(:xml) { @@ -23,7 +25,7 @@ module DiasporaFederation XML } - it_behaves_like "an Entity subclass" + it_behaves_like "an Entity subclass", [:parent] it_behaves_like "an XML Entity" diff --git a/spec/lib/diaspora_federation/entities/poll_participation_spec.rb b/spec/lib/diaspora_federation/entities/poll_participation_spec.rb index 9b61744..e886475 100644 --- a/spec/lib/diaspora_federation/entities/poll_participation_spec.rb +++ b/spec/lib/diaspora_federation/entities/poll_participation_spec.rb @@ -1,12 +1,14 @@ module DiasporaFederation describe Entities::PollParticipation do let(:parent) { FactoryGirl.create(:poll, author: bob) } + let(:parent_entity) { FactoryGirl.build(:related_entity, author: bob.diaspora_id) } let(:data) { FactoryGirl.build( :poll_participation_entity, author: alice.diaspora_id, - parent_guid: parent.guid - ).send(:xml_elements) + parent_guid: parent.guid, + parent: parent_entity + ).send(:xml_elements).merge(parent: parent_entity) } let(:xml) { @@ -22,7 +24,7 @@ module DiasporaFederation XML } - it_behaves_like "an Entity subclass" + it_behaves_like "an Entity subclass", [:parent] it_behaves_like "an XML Entity" diff --git a/spec/lib/diaspora_federation/entities/relayable_spec.rb b/spec/lib/diaspora_federation/entities/relayable_spec.rb index 99747b5..0161bdf 100644 --- a/spec/lib/diaspora_federation/entities/relayable_spec.rb +++ b/spec/lib/diaspora_federation/entities/relayable_spec.rb @@ -8,6 +8,7 @@ module DiasporaFederation let(:author) { FactoryGirl.generate(:diaspora_id) } let(:property) { "hello" } let(:new_property) { "some text" } + let(:parent) { FactoryGirl.build(:related_entity, author: bob.diaspora_id) } let(:hash) { {guid: guid, author: author, parent_guid: parent_guid, property: property} } let(:legacy_signature_data) { "#{guid};#{author};#{property};#{parent_guid}" } @@ -15,12 +16,14 @@ module DiasporaFederation class SomeRelayable < Entity LEGACY_SIGNATURE_ORDER = %i(guid author property parent_guid).freeze + PARENT_TYPE = "Parent".freeze + include Entities::Relayable property :property def parent_type - "Parent" + PARENT_TYPE end end @@ -300,6 +303,10 @@ XML expect(DiasporaFederation.callbacks).to receive(:trigger).with( :entity_author_is_local?, "Parent", parent_guid ).and_return(false) + + expect(DiasporaFederation.callbacks).to receive(:trigger).with( + :fetch_related_entity, "Parent", parent_guid + ).and_return(parent) end let(:new_signature_data) { "#{author};#{guid};#{parent_guid};#{new_property};#{property}" } @@ -359,6 +366,10 @@ XML :fetch_public_key_by_diaspora_id, author ).and_return(author_pkey.public_key) + expect(DiasporaFederation.callbacks).to receive(:trigger).with( + :fetch_related_entity, "Parent", parent_guid + ).and_return(parent) + expect { SomeRelayable.from_xml(xml) }.to raise_error DiasporaFederation::Entities::Relayable::SignatureVerificationFailed diff --git a/spec/support/shared_entity_specs.rb b/spec/support/shared_entity_specs.rb index 8890a20..c70cbfc 100644 --- a/spec/support/shared_entity_specs.rb +++ b/spec/support/shared_entity_specs.rb @@ -1,10 +1,10 @@ -shared_examples "an Entity subclass" do +shared_examples "an Entity subclass" do |ignored_props=[]| it "should be an Entity" do expect(described_class).to be < DiasporaFederation::Entity end it "has its properties set" do - expect(described_class.class_props.keys).to include(*data.keys) + expect(described_class.class_props.keys).to include(*(data.keys - ignored_props)) end context "behaviour" do @@ -26,7 +26,9 @@ shared_examples "an Entity subclass" do describe "#to_h" do it "should resemble the input data" do - expect(instance.to_h).to eq(data) + hash = instance.to_h + ignored_props.each {|key| data.delete(key) } + expect(hash).to eq(data) end end end diff --git a/spec/support/shared_validator_specs.rb b/spec/support/shared_validator_specs.rb index 4f424fc..a78c93c 100644 --- a/spec/support/shared_validator_specs.rb +++ b/spec/support/shared_validator_specs.rb @@ -33,6 +33,14 @@ shared_examples "a relayable validator" do let(:property) { :parent_guid } end end + + describe "#parent" do + it_behaves_like "a property with a value validation/restriction" do + let(:property) { :parent } + let(:wrong_values) { [nil] } + let(:correct_values) { [FactoryGirl.build(:related_entity)] } + end + end end shared_examples "a property with a value validation/restriction" do