use RelatedEntity as target for RelayableRetraction

This commit is contained in:
Benjamin Neff 2016-03-28 20:14:25 +02:00
parent 8f2b3e6a14
commit 01d45e225d
7 changed files with 62 additions and 33 deletions

View file

@ -25,7 +25,6 @@ module DiasporaFederation
save_person_after_webfinger save_person_after_webfinger
fetch_private_key_by_diaspora_id fetch_private_key_by_diaspora_id
fetch_public_key_by_diaspora_id fetch_public_key_by_diaspora_id
fetch_entity_author_id_by_guid
fetch_related_entity fetch_related_entity
queue_public_receive queue_public_receive
queue_private_receive queue_private_receive
@ -154,12 +153,6 @@ module DiasporaFederation
# @param [String] Diaspora ID of the person # @param [String] Diaspora ID of the person
# @return [OpenSSL::PKey::RSA] key # @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 # fetch_related_entity
# Fetches a related entity by a given guid # Fetches a related entity by a given guid
# @param [String] entity_type (Post, Comment, Like, etc) # @param [String] entity_type (Post, Comment, Like, etc)

View file

@ -53,6 +53,19 @@ module DiasporaFederation
# @return [String] target author signature # @return [String] target author signature
property :target_author_signature, default: nil 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 # use only {Retraction} for receive
# @return [Retraction] instance as normal retraction # @return [Retraction] instance as normal retraction
def to_retraction def to_retraction
@ -64,33 +77,47 @@ module DiasporaFederation
# @param [Nokogiri::XML::Element] root_node xml nodes # @param [Nokogiri::XML::Element] root_node xml nodes
# @return [Retraction] instance # @return [Retraction] instance
def self.populate_entity(root_node) 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 end
private_class_method :populate_entity 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 # 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. # if the signatures are not there yet and if the keys are available.
# #
# @return [Hash] xml elements with updated signatures # @return [Hash] xml elements with updated signatures
def xml_elements 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) privkey = DiasporaFederation.callbacks.trigger(:fetch_private_key_by_diaspora_id, author)
super.tap do |xml_elements| 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
end end
# @param [String] target_author the author of the entity to retract
# @param [OpenSSL::PKey::RSA] privkey private key of sender # @param [OpenSSL::PKey::RSA] privkey private key of sender
# @param [Hash] hash hash given for a signing # @param [Hash] hash hash given for a signing
def fill_required_signature(target_author, privkey, hash) def fill_required_signature(privkey, hash)
if target_author == author && target_author_signature.nil? if target.author == author && target_author_signature.nil?
hash[:target_author_signature] = SignedRetraction.sign_with_key(privkey, self) 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) hash[:parent_author_signature] = SignedRetraction.sign_with_key(privkey, self)
end end
end end
# Raised, if the target of the {Retraction} was not found.
class TargetNotFound < RuntimeError
end
end end
end end
end end

View file

@ -155,6 +155,7 @@ module DiasporaFederation
author { generate(:diaspora_id) } author { generate(:diaspora_id) }
target_guid { generate(:guid) } target_guid { generate(:guid) }
target_type "Comment" target_type "Comment"
target { FactoryGirl.build(:related_entity, author: author) }
end end
factory :reshare_entity, class: DiasporaFederation::Entities::Reshare do factory :reshare_entity, class: DiasporaFederation::Entities::Reshare do

View file

@ -6,8 +6,8 @@ module DiasporaFederation
include Validation include Validation
rule :target_guid, :guid rule :target_guid, :guid
rule :target_type, :not_empty rule :target_type, :not_empty
rule :target, :not_nil
rule :author, %i(not_empty diaspora_id) rule :author, %i(not_empty diaspora_id)
end end

View file

@ -27,6 +27,12 @@ FactoryGirl.define do
after(:create, &:save) after(:create, &:save)
end end
factory :comment, class: Entity do
entity_type "Comment"
author { FactoryGirl.build(:person) }
after(:create, &:save)
end
factory :poll, class: Entity do factory :poll, class: Entity do
entity_type "Poll" entity_type "Poll"
author { FactoryGirl.build(:person) } author { FactoryGirl.build(:person) }

View file

@ -1,8 +1,23 @@
module DiasporaFederation module DiasporaFederation
describe Entities::RelayableRetraction do 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) { 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_author_signature] = nil
data[:target] = target_entity
end end
} }
@ -18,7 +33,7 @@ module DiasporaFederation
XML 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) 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) } let(:hash) { FactoryGirl.attributes_for(:relayable_retraction_entity) }
it "updates author signature when it was nil and key was supplied" do 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( expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:fetch_private_key_by_diaspora_id, hash[:author] :fetch_private_key_by_diaspora_id, hash[:author]
).and_return(author_pkey) ).and_return(author_pkey)
@ -43,10 +54,9 @@ XML
expect(author_pkey.verify(OpenSSL::Digest::SHA256.new, signature, signed_string)).to be_truthy expect(author_pkey.verify(OpenSSL::Digest::SHA256.new, signature, signed_string)).to be_truthy
end end
it "updates parent author signature when it was nil, key was supplied and sender is not author of the target" do it "updates parent author signature when it was nil, key was supplied and sender is author of the parent" do
expect(DiasporaFederation.callbacks).to receive(:trigger).with( parent = FactoryGirl.build(:related_entity, author: hash[:author])
:fetch_entity_author_id_by_guid, hash[:target_type], hash[:target_guid] hash[:target] = FactoryGirl.build(:related_entity, author: bob.diaspora_id, parent: parent)
).and_return(FactoryGirl.generate(:diaspora_id))
expect(DiasporaFederation.callbacks).to receive(:trigger).with( expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:fetch_private_key_by_diaspora_id, hash[:author] :fetch_private_key_by_diaspora_id, hash[:author]
@ -74,10 +84,6 @@ XML
:fetch_private_key_by_diaspora_id, hash[:author] :fetch_private_key_by_diaspora_id, hash[:author]
).and_return(nil) ).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 xml = Entities::RelayableRetraction.new(hash).to_xml
expect(xml.at_xpath("target_author_signature").text).to eq("") expect(xml.at_xpath("target_author_signature").text).to eq("")
expect(xml.at_xpath("parent_author_signature").text).to eq("") expect(xml.at_xpath("parent_author_signature").text).to eq("")

View file

@ -71,10 +71,6 @@ DiasporaFederation.configure do |config|
OpenSSL::PKey::RSA.new(key) unless key.nil? OpenSSL::PKey::RSA.new(key) unless key.nil?
end 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| on :fetch_related_entity do |entity_type, guid|
entity = Entity.find_by(entity_type: entity_type, guid: guid) entity = Entity.find_by(entity_type: entity_type, guid: guid)
if entity if entity