use RelatedEntity as target for RelayableRetraction
This commit is contained in:
parent
8f2b3e6a14
commit
01d45e225d
7 changed files with 62 additions and 33 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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) }
|
||||||
|
|
|
||||||
|
|
@ -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("")
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue