use related entity as parent for relayables

This commit is contained in:
Benjamin Neff 2016-03-28 07:10:02 +02:00
parent 3ac21b585b
commit 23fc8dc180
16 changed files with 94 additions and 24 deletions

View file

@ -8,6 +8,9 @@ module DiasporaFederation
# @deprecated # @deprecated
LEGACY_SIGNATURE_ORDER = %i(guid parent_guid text author).freeze LEGACY_SIGNATURE_ORDER = %i(guid parent_guid text author).freeze
# The {Comment} parent is a {Post}
PARENT_TYPE = "Post".freeze
include Relayable include Relayable
# @!attribute [r] text # @!attribute [r] text
@ -22,7 +25,7 @@ module DiasporaFederation
# The {Comment} parent is a Post # The {Comment} parent is a Post
# @return [String] parent type # @return [String] parent type
def parent_type def parent_type
"Post" PARENT_TYPE
end end
end end
end end

View file

@ -8,6 +8,9 @@ module DiasporaFederation
# @deprecated # @deprecated
LEGACY_SIGNATURE_ORDER = %i(guid parent_guid text created_at author conversation_guid).freeze 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 include Relayable
# @!attribute [r] text # @!attribute [r] text
@ -29,7 +32,7 @@ module DiasporaFederation
# The {Message} parent is a {Conversation} # The {Message} parent is a {Conversation}
# @return [String] parent type # @return [String] parent type
def parent_type def parent_type
"Conversation" PARENT_TYPE
end end
end end
end end

View file

@ -8,6 +8,9 @@ module DiasporaFederation
# @deprecated # @deprecated
LEGACY_SIGNATURE_ORDER = %i(guid parent_guid author poll_answer_guid).freeze LEGACY_SIGNATURE_ORDER = %i(guid parent_guid author poll_answer_guid).freeze
# The {PollParticipation} parent is a {Poll}
PARENT_TYPE = "Poll".freeze
include Relayable include Relayable
# @!attribute [r] poll_answer_guid # @!attribute [r] poll_answer_guid
@ -19,7 +22,7 @@ module DiasporaFederation
# The {PollParticipation} parent is a {Poll} # The {PollParticipation} parent is a {Poll}
# @return [String] parent type # @return [String] parent type
def parent_type def parent_type
"Poll" PARENT_TYPE
end end
end end
end end

View file

@ -10,6 +10,10 @@ module DiasporaFederation
# digest instance used for signing # digest instance used for signing
DIGEST = OpenSSL::Digest::SHA256.new DIGEST = OpenSSL::Digest::SHA256.new
# parent entity
# @return [RelatedEntity] parent entity
attr_reader :parent
# order from the parsed xml for signature # order from the parsed xml for signature
# @return [Array] order from xml # @return [Array] order from xml
attr_reader :xml_order attr_reader :xml_order
@ -68,6 +72,7 @@ module DiasporaFederation
# @param [Hash] additional_xml_elements additional xml elements # @param [Hash] additional_xml_elements additional xml elements
# @see DiasporaFederation::Entity#initialize # @see DiasporaFederation::Entity#initialize
def initialize(data, xml_order=nil, additional_xml_elements={}) def initialize(data, xml_order=nil, additional_xml_elements={})
@parent = data[:parent] if data
@xml_order = xml_order @xml_order = xml_order
@additional_xml_elements = additional_xml_elements @additional_xml_elements = additional_xml_elements
@ -197,8 +202,18 @@ module DiasporaFederation
end end
end end
add_parent(entity_data)
new(entity_data, xml_order, additional_xml_elements).tap(&:verify_signatures) new(entity_data, xml_order, additional_xml_elements).tap(&:verify_signatures)
end 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 end
# Raised, if creating the author_signature failes, because the private key was not found # Raised, if creating the author_signature failes, because the private key was not found

View file

@ -87,6 +87,7 @@ module DiasporaFederation
factory :relayable_entity, class: DiasporaFederation::Entities::Relayable do factory :relayable_entity, class: DiasporaFederation::Entities::Relayable do
parent_guid { generate(:guid) } parent_guid { generate(:guid) }
parent { FactoryGirl.build(:related_entity) }
end end
factory :participation_entity, factory :participation_entity,

View file

@ -9,6 +9,7 @@ module DiasporaFederation
rule :author, %i(not_empty diaspora_id) rule :author, %i(not_empty diaspora_id)
rule :guid, :guid rule :guid, :guid
rule :parent_guid, :guid rule :parent_guid, :guid
rule :parent, :not_nil
end end
end end
end end

View file

@ -60,8 +60,11 @@ KEY
let(:new_data) { "foobar" } let(:new_data) { "foobar" }
let(:text) { "this is a very informative comment" } let(:text) { "this is a very informative comment" }
let(:parent) { FactoryGirl.build(:related_entity, author: bob.diaspora_id) }
let(:comment) { 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) { let(:legacy_comment_xml_alice) {
@ -204,6 +207,9 @@ XML
expect(DiasporaFederation.callbacks).to receive(:trigger).with( expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:fetch_author_private_key_by_entity_guid, "Post", parent_guid :fetch_author_private_key_by_entity_guid, "Post", parent_guid
).and_return(parent_key) ).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 xml = Nokogiri::XML::Document.parse(new_data_comment_xml_alice).root
Salmon::XmlPayload.unpack(xml).to_xml Salmon::XmlPayload.unpack(xml).to_xml
@ -221,6 +227,9 @@ XML
expect(DiasporaFederation.callbacks).to receive(:trigger).with( expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:fetch_author_private_key_by_entity_guid, "Post", parent_guid :fetch_author_private_key_by_entity_guid, "Post", parent_guid
).and_return(parent_key) ).and_return(parent_key)
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:fetch_related_entity, "Post", parent_guid
).and_return(parent)
end end
it "relays legacy signatures and xml" do it "relays legacy signatures and xml" do
@ -253,6 +262,9 @@ XML
expect(DiasporaFederation.callbacks).to receive(:trigger).with( expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:fetch_author_public_key_by_entity_guid, "Post", parent_guid :fetch_author_public_key_by_entity_guid, "Post", parent_guid
).and_return(parent_key.public_key) ).and_return(parent_key.public_key)
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:fetch_related_entity, "Post", parent_guid
).and_return(parent)
end end
it "parses legacy signatures and xml" do it "parses legacy signatures and xml" do

View file

@ -1,9 +1,10 @@
module DiasporaFederation module DiasporaFederation
describe Entities::Comment do describe Entities::Comment do
let(:parent) { FactoryGirl.create(:post, author: bob) } let(:parent) { FactoryGirl.create(:post, author: bob) }
let(:parent_entity) { FactoryGirl.build(:related_entity, author: bob.diaspora_id) }
let(:data) { let(:data) {
FactoryGirl.build(:comment_entity, author: alice.diaspora_id, parent_guid: parent.guid).send(:xml_elements) FactoryGirl.build(:comment_entity, author: alice.diaspora_id, parent_guid: parent.guid, parent: parent_entity)
.merge(created_at: Time.now.utc) .send(:xml_elements).merge(created_at: Time.now.utc, parent: parent_entity)
} }
let(:xml) { let(:xml) {
@ -19,7 +20,7 @@ module DiasporaFederation
XML XML
} }
it_behaves_like "an Entity subclass" it_behaves_like "an Entity subclass", [:parent]
it_behaves_like "an XML Entity", [:created_at] it_behaves_like "an XML Entity", [:created_at]
@ -35,6 +36,7 @@ XML
created_at = Time.now.utc - 1.minute 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 = FactoryGirl.build(:comment_entity, author: alice.diaspora_id, parent_guid: parent.guid).to_h
comment_data[:created_at] = created_at 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)) comment = described_class.new(comment_data, %i(author guid parent_guid text created_at))
parsed_comment = described_class.from_xml(comment.to_xml) parsed_comment = described_class.from_xml(comment.to_xml)

View file

@ -1,13 +1,14 @@
module DiasporaFederation module DiasporaFederation
describe Entities::Conversation do describe Entities::Conversation do
let(:parent) { FactoryGirl.create(:conversation, author: bob) } let(:parent) { FactoryGirl.create(:conversation, author: bob) }
let(:parent_entity) { FactoryGirl.build(:related_entity, author: bob.diaspora_id) }
let(:signed_msg1) { let(:signed_msg1) {
msg = FactoryGirl.build(:message_entity, author: alice.diaspora_id, parent_guid: parent.guid).send(:xml_elements) 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) { let(:signed_msg2) {
msg = FactoryGirl.build(:message_entity, author: alice.diaspora_id, parent_guid: parent.guid).send(:xml_elements) 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) { let(:data) {
FactoryGirl.attributes_for(:conversation_entity).merge!( FactoryGirl.attributes_for(:conversation_entity).merge!(

View file

@ -1,13 +1,15 @@
module DiasporaFederation module DiasporaFederation
describe Entities::Like do describe Entities::Like do
let(:parent) { FactoryGirl.create(:post, author: bob) } let(:parent) { FactoryGirl.create(:post, author: bob) }
let(:parent_entity) { FactoryGirl.build(:related_entity, author: bob.diaspora_id) }
let(:data) { let(:data) {
FactoryGirl.build( FactoryGirl.build(
:like_entity, :like_entity,
author: alice.diaspora_id, author: alice.diaspora_id,
parent_guid: parent.guid, parent_guid: parent.guid,
parent_type: parent.entity_type parent_type: parent.entity_type,
).send(:xml_elements) parent: parent_entity
).send(:xml_elements).merge(parent: parent_entity)
} }
let(:xml) { let(:xml) {
@ -24,7 +26,7 @@ module DiasporaFederation
XML XML
} }
it_behaves_like "an Entity subclass" it_behaves_like "an Entity subclass", [:parent]
it_behaves_like "an XML Entity" it_behaves_like "an XML Entity"

View file

@ -1,8 +1,10 @@
module DiasporaFederation module DiasporaFederation
describe Entities::Message do describe Entities::Message do
let(:parent) { FactoryGirl.create(:conversation, author: bob) } let(:parent) { FactoryGirl.create(:conversation, author: bob) }
let(:parent_entity) { FactoryGirl.build(:related_entity, author: bob.diaspora_id) }
let(:data) { 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) { let(:xml) {
@ -20,7 +22,7 @@ module DiasporaFederation
XML XML
} }
it_behaves_like "an Entity subclass" it_behaves_like "an Entity subclass", [:parent]
it_behaves_like "an XML Entity" it_behaves_like "an XML Entity"

View file

@ -1,13 +1,15 @@
module DiasporaFederation module DiasporaFederation
describe Entities::Participation do describe Entities::Participation do
let(:parent) { FactoryGirl.create(:post, author: bob) } let(:parent) { FactoryGirl.create(:post, author: bob) }
let(:parent_entity) { FactoryGirl.build(:related_entity, author: bob.diaspora_id) }
let(:data) { let(:data) {
FactoryGirl.build( FactoryGirl.build(
:participation_entity, :participation_entity,
author: alice.diaspora_id, author: alice.diaspora_id,
parent_guid: parent.guid, parent_guid: parent.guid,
parent_type: parent.entity_type parent_type: parent.entity_type,
).send(:xml_elements) parent: parent_entity
).send(:xml_elements).merge(parent: parent_entity)
} }
let(:xml) { let(:xml) {
@ -23,7 +25,7 @@ module DiasporaFederation
XML XML
} }
it_behaves_like "an Entity subclass" it_behaves_like "an Entity subclass", [:parent]
it_behaves_like "an XML Entity" it_behaves_like "an XML Entity"

View file

@ -1,12 +1,14 @@
module DiasporaFederation module DiasporaFederation
describe Entities::PollParticipation do describe Entities::PollParticipation do
let(:parent) { FactoryGirl.create(:poll, author: bob) } let(:parent) { FactoryGirl.create(:poll, author: bob) }
let(:parent_entity) { FactoryGirl.build(:related_entity, author: bob.diaspora_id) }
let(:data) { let(:data) {
FactoryGirl.build( FactoryGirl.build(
:poll_participation_entity, :poll_participation_entity,
author: alice.diaspora_id, author: alice.diaspora_id,
parent_guid: parent.guid parent_guid: parent.guid,
).send(:xml_elements) parent: parent_entity
).send(:xml_elements).merge(parent: parent_entity)
} }
let(:xml) { let(:xml) {
@ -22,7 +24,7 @@ module DiasporaFederation
XML XML
} }
it_behaves_like "an Entity subclass" it_behaves_like "an Entity subclass", [:parent]
it_behaves_like "an XML Entity" it_behaves_like "an XML Entity"

View file

@ -8,6 +8,7 @@ module DiasporaFederation
let(:author) { FactoryGirl.generate(:diaspora_id) } let(:author) { FactoryGirl.generate(:diaspora_id) }
let(:property) { "hello" } let(:property) { "hello" }
let(:new_property) { "some text" } 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(:hash) { {guid: guid, author: author, parent_guid: parent_guid, property: property} }
let(:legacy_signature_data) { "#{guid};#{author};#{property};#{parent_guid}" } let(:legacy_signature_data) { "#{guid};#{author};#{property};#{parent_guid}" }
@ -15,12 +16,14 @@ module DiasporaFederation
class SomeRelayable < Entity class SomeRelayable < Entity
LEGACY_SIGNATURE_ORDER = %i(guid author property parent_guid).freeze LEGACY_SIGNATURE_ORDER = %i(guid author property parent_guid).freeze
PARENT_TYPE = "Parent".freeze
include Entities::Relayable include Entities::Relayable
property :property property :property
def parent_type def parent_type
"Parent" PARENT_TYPE
end end
end end
@ -300,6 +303,10 @@ XML
expect(DiasporaFederation.callbacks).to receive(:trigger).with( expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:entity_author_is_local?, "Parent", parent_guid :entity_author_is_local?, "Parent", parent_guid
).and_return(false) ).and_return(false)
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:fetch_related_entity, "Parent", parent_guid
).and_return(parent)
end end
let(:new_signature_data) { "#{author};#{guid};#{parent_guid};#{new_property};#{property}" } let(:new_signature_data) { "#{author};#{guid};#{parent_guid};#{new_property};#{property}" }
@ -359,6 +366,10 @@ XML
:fetch_public_key_by_diaspora_id, author :fetch_public_key_by_diaspora_id, author
).and_return(author_pkey.public_key) ).and_return(author_pkey.public_key)
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:fetch_related_entity, "Parent", parent_guid
).and_return(parent)
expect { expect {
SomeRelayable.from_xml(xml) SomeRelayable.from_xml(xml)
}.to raise_error DiasporaFederation::Entities::Relayable::SignatureVerificationFailed }.to raise_error DiasporaFederation::Entities::Relayable::SignatureVerificationFailed

View file

@ -1,10 +1,10 @@
shared_examples "an Entity subclass" do shared_examples "an Entity subclass" do |ignored_props=[]|
it "should be an Entity" do it "should be an Entity" do
expect(described_class).to be < DiasporaFederation::Entity expect(described_class).to be < DiasporaFederation::Entity
end end
it "has its properties set" do 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 end
context "behaviour" do context "behaviour" do
@ -26,7 +26,9 @@ shared_examples "an Entity subclass" do
describe "#to_h" do describe "#to_h" do
it "should resemble the input data" 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 end
end end

View file

@ -33,6 +33,14 @@ shared_examples "a relayable validator" do
let(:property) { :parent_guid } let(:property) { :parent_guid }
end end
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 end
shared_examples "a property with a value validation/restriction" do shared_examples "a property with a value validation/restriction" do