message not relayable anymore
receive only from author and ignore signature checking, or from parent author with valid signature. see #36
This commit is contained in:
parent
7f869a5cdf
commit
c62bede41c
6 changed files with 130 additions and 14 deletions
|
|
@ -8,9 +8,6 @@ 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
|
||||
|
|
@ -28,6 +25,40 @@ module DiasporaFederation
|
|||
# @see Conversation#guid
|
||||
# @return [String] conversation guid
|
||||
property :conversation_guid
|
||||
|
||||
# It is only valid to receive a {Message} from the author itself,
|
||||
# or from the author of the parent {Conversation} if the author signature is valid.
|
||||
# @deprecated remove after {Message} doesn't include {Relayable} anymore
|
||||
def sender_valid?(sender)
|
||||
sender == author || (sender == parent_author && verify_author_signature)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# @deprecated remove after {Message} doesn't include {Relayable} anymore
|
||||
def verify_author_signature
|
||||
pubkey = DiasporaFederation.callbacks.trigger(:fetch_public_key, author)
|
||||
raise PublicKeyNotFound, "author_signature author=#{author} guid=#{guid}" if pubkey.nil?
|
||||
raise SignatureVerificationFailed, "wrong author_signature" unless verify_signature(pubkey, author_signature)
|
||||
true
|
||||
end
|
||||
|
||||
# @deprecated remove after {Message} doesn't include {Relayable} anymore
|
||||
def parent_author
|
||||
parent = DiasporaFederation.callbacks.trigger(:fetch_related_entity, "Conversation", conversation_guid)
|
||||
raise Federation::Fetcher::NotFetchable, "Conversation:#{conversation_guid} not found" unless parent
|
||||
parent.author
|
||||
end
|
||||
|
||||
# Default implementation, don't verify signatures for a {Message}.
|
||||
# @see Entity.populate_entity
|
||||
# @deprecated remove after {Message} doesn't include {Relayable} anymore
|
||||
# @param [Nokogiri::XML::Element] root_node xml nodes
|
||||
# @return [Entity] instance
|
||||
def self.populate_entity(root_node)
|
||||
new({parent_guid: nil, parent: nil}.merge(entity_data(root_node)))
|
||||
end
|
||||
private_class_method :populate_entity
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ module DiasporaFederation
|
|||
class MessageValidator < Validation::Validator
|
||||
include Validation
|
||||
|
||||
include RelayableValidator
|
||||
|
||||
rule :author, %i(not_empty diaspora_id)
|
||||
rule :guid, :guid
|
||||
rule :conversation_guid, :guid
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ XML
|
|||
|
||||
it_behaves_like "an Entity subclass"
|
||||
|
||||
it_behaves_like "an XML Entity"
|
||||
it_behaves_like "an XML Entity", %i(parent parent_guid)
|
||||
|
||||
context "default values" do
|
||||
let(:minimal_xml) {
|
||||
|
|
|
|||
|
|
@ -25,8 +25,84 @@ XML
|
|||
|
||||
it_behaves_like "an Entity subclass"
|
||||
|
||||
it_behaves_like "an XML Entity"
|
||||
it_behaves_like "an XML Entity", %i(parent parent_guid)
|
||||
|
||||
it_behaves_like "a relayable Entity"
|
||||
|
||||
describe "#sender_valid?" do
|
||||
let(:entity) { Entities::Message.new(data) }
|
||||
|
||||
it "allows the author" do
|
||||
expect(entity.sender_valid?(alice.diaspora_id)).to be_truthy
|
||||
end
|
||||
|
||||
it "allows parent author if the signature is valid" do
|
||||
expect_callback(:fetch_related_entity, "Conversation", entity.conversation_guid).and_return(data[:parent])
|
||||
expect_callback(:fetch_public_key, alice.diaspora_id).and_return(alice.private_key)
|
||||
expect(entity.sender_valid?(bob.diaspora_id)).to be_truthy
|
||||
end
|
||||
|
||||
it "does not allow any other person" do
|
||||
expect_callback(:fetch_related_entity, "Conversation", entity.conversation_guid).and_return(data[:parent])
|
||||
invalid_sender = FactoryGirl.generate(:diaspora_id)
|
||||
expect(entity.sender_valid?(invalid_sender)).to be_falsey
|
||||
end
|
||||
|
||||
it "does not allow the parent author if the signature is invalid" do
|
||||
expect_callback(:fetch_related_entity, "Conversation", entity.conversation_guid).and_return(data[:parent])
|
||||
expect_callback(:fetch_public_key, alice.diaspora_id).and_return(alice.private_key)
|
||||
invalid_entity = Entities::Message.new(data.merge(author_signature: "aa"))
|
||||
expect {
|
||||
invalid_entity.sender_valid?(bob.diaspora_id)
|
||||
}.to raise_error Entities::Relayable::SignatureVerificationFailed, "wrong author_signature"
|
||||
end
|
||||
|
||||
it "raises NotFetchable if the parent Conversation can not be found" do
|
||||
expect_callback(:fetch_related_entity, "Conversation", entity.conversation_guid).and_return(nil)
|
||||
expect {
|
||||
entity.sender_valid?(bob.diaspora_id)
|
||||
}.to raise_error Federation::Fetcher::NotFetchable
|
||||
end
|
||||
end
|
||||
|
||||
context "relayable signature verification" do
|
||||
it "does not verify the signature" do
|
||||
data.merge!(author_signature: "aa", parent_author_signature: "bb")
|
||||
xml = Entities::Message.new(data).to_xml
|
||||
|
||||
expect {
|
||||
Entities::Message.from_xml(xml)
|
||||
}.not_to raise_error
|
||||
end
|
||||
end
|
||||
|
||||
describe ".populate_entity" do
|
||||
it "adds a nil parent" do
|
||||
xml = Entities::Message.new(data).to_xml
|
||||
parsed = Entities::Message.from_xml(xml)
|
||||
expect(parsed.parent).to be_nil
|
||||
end
|
||||
|
||||
it "uses the parent_guid from the parsed xml" do
|
||||
xml = Entities::Message.new(data).to_xml
|
||||
parsed = Entities::Message.from_xml(xml)
|
||||
expect(parsed.parent_guid).to eq(data[:parent_guid])
|
||||
end
|
||||
|
||||
it "uses nil for parent_guid if not in the xml" do
|
||||
xml = <<-XML
|
||||
<message>
|
||||
<author>#{data[:author]}</author>
|
||||
<guid>#{data[:guid]}</guid>
|
||||
<text>#{data[:text]}</text>
|
||||
<created_at>#{data[:created_at]}</created_at>
|
||||
<conversation_guid>#{data[:conversation_guid]}</conversation_guid>
|
||||
</message>
|
||||
XML
|
||||
|
||||
parsed = Entities::Message.from_xml(Nokogiri::XML::Document.parse(xml).root)
|
||||
expect(parsed.parent_guid).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,16 @@ module DiasporaFederation
|
|||
let(:entity) { :message_entity }
|
||||
it_behaves_like "a common validator"
|
||||
|
||||
it_behaves_like "a relayable validator"
|
||||
it_behaves_like "a diaspora id validator" do
|
||||
let(:property) { :author }
|
||||
let(:mandatory) { true }
|
||||
end
|
||||
|
||||
describe "#guid" do
|
||||
it_behaves_like "a guid validator" do
|
||||
let(:property) { :guid }
|
||||
end
|
||||
end
|
||||
|
||||
describe "#conversation_guid" do
|
||||
it_behaves_like "a guid validator" do
|
||||
|
|
|
|||
|
|
@ -66,21 +66,21 @@ shared_examples "an XML Entity" do |ignored_props=[]|
|
|||
end
|
||||
end
|
||||
|
||||
def check_entity(entity, parsed_entity, ignored_props=[])
|
||||
entity.class.class_props.each do |name, type|
|
||||
validate_values(entity.send(name), parsed_entity.send(name), type) unless ignored_props.include?(name)
|
||||
def check_entity(entity, parsed_entity, ignored_props)
|
||||
entity.class.class_props.reject {|name| ignored_props.include?(name) }.each do |name, type|
|
||||
validate_values(entity.send(name), parsed_entity.send(name), type, ignored_props)
|
||||
end
|
||||
end
|
||||
|
||||
def validate_values(value, parsed_value, type)
|
||||
def validate_values(value, parsed_value, type, ignored_props)
|
||||
if value.nil?
|
||||
expect(parsed_value).to be_nil
|
||||
elsif type == String
|
||||
expect(parsed_value.to_s).to eq(value.to_s)
|
||||
elsif type.instance_of?(Array)
|
||||
value.each_with_index {|entity, index| check_entity(entity, parsed_value[index]) }
|
||||
value.each_with_index {|entity, index| check_entity(entity, parsed_value[index], ignored_props) }
|
||||
elsif type.ancestors.include?(DiasporaFederation::Entity)
|
||||
check_entity(value, parsed_value)
|
||||
check_entity(value, parsed_value, ignored_props)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue