refactor encrypted slap to reuse it for every recipient

This commit is contained in:
Benjamin Neff 2016-01-14 03:42:36 +01:00
parent c7f33d7cf4
commit a0398430ed
12 changed files with 204 additions and 130 deletions

View file

@ -67,7 +67,7 @@ module DiasporaFederation
# Generates an XML document from the current instance and returns it as string # Generates an XML document from the current instance and returns it as string
# @return [String] XML document # @return [String] XML document
def to_xml def to_xml
builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml| Nokogiri::XML::Builder.new(encoding: "UTF-8") {|xml|
xml.XRD("xmlns" => XMLNS) { xml.XRD("xmlns" => XMLNS) {
xml.Expires(@expires.strftime(DATETIME_FORMAT)) if @expires.instance_of?(DateTime) xml.Expires(@expires.strftime(DATETIME_FORMAT)) if @expires.instance_of?(DateTime)
@ -77,8 +77,7 @@ module DiasporaFederation
add_properties_to(xml) add_properties_to(xml)
add_links_to(xml) add_links_to(xml)
} }
end }.to_xml
builder.to_xml
end end
# Parse the XRD document from the given string and create a hash containing # Parse the XRD document from the given string and create a hash containing

View file

@ -49,7 +49,7 @@ module DiasporaFederation
# resolved on each call # resolved on each call
# @return [Hash] default values # @return [Hash] default values
def default_values def default_values
default_props.each_with_object({}) { |(name, prop), hash| default_props.each_with_object({}) {|(name, prop), hash|
hash[name] = prop.respond_to?(:call) ? prop.call : prop hash[name] = prop.respond_to?(:call) ? prop.call : prop
} }
end end
@ -105,7 +105,7 @@ module DiasporaFederation
# @param [Class] type the type to check # @param [Class] type the type to check
# @return [Boolean] # @return [Boolean]
def type_valid?(type) def type_valid?(type)
[type].flatten.all? { |type| [type].flatten.all? {|type|
type.respond_to?(:ancestors) && type.ancestors.include?(Entity) type.respond_to?(:ancestors) && type.ancestors.include?(Entity)
} }
end end

View file

@ -63,14 +63,22 @@ module DiasporaFederation
# #
# entity = slap.entity(author_pubkey) # entity = slap.entity(author_pubkey)
# #
class EncryptedSlap class EncryptedSlap < Slap
# the key and iv if it is an encrypted slap
# @param [Hash] value hash containing the key and iv
attr_writer :cipher_params
# the prepared encrypted magic envelope xml
# @param [Nokogiri::XML::Element] value magic envelope xml
attr_writer :magic_envelope_xml
# Creates a Slap instance from the data within the given XML string # Creates a Slap instance from the data within the given XML string
# containing an encrypted payload. # containing an encrypted payload.
# #
# @param [String] slap_xml encrypted Salmon xml # @param [String] slap_xml encrypted Salmon xml
# @param [OpenSSL::PKey::RSA] privkey recipient private_key for decryption # @param [OpenSSL::PKey::RSA] privkey recipient private_key for decryption
# #
# @return [Slap] new Slap instance # @return [EncryptedSlap] new Slap instance
# #
# @raise [ArgumentError] if any of the arguments is of the wrong type # @raise [ArgumentError] if any of the arguments is of the wrong type
# @raise [MissingHeader] if the +encrypted_header+ element is missing in the XML # @raise [MissingHeader] if the +encrypted_header+ element is missing in the XML
@ -79,7 +87,7 @@ module DiasporaFederation
raise ArgumentError unless slap_xml.instance_of?(String) && privkey.instance_of?(OpenSSL::PKey::RSA) raise ArgumentError unless slap_xml.instance_of?(String) && privkey.instance_of?(OpenSSL::PKey::RSA)
doc = Nokogiri::XML::Document.parse(slap_xml) doc = Nokogiri::XML::Document.parse(slap_xml)
Slap.new.tap do |slap| EncryptedSlap.new.tap do |slap|
header_elem = doc.at_xpath("d:diaspora/d:encrypted_header", Slap::NS) header_elem = doc.at_xpath("d:diaspora/d:encrypted_header", Slap::NS)
raise MissingHeader if header_elem.nil? raise MissingHeader if header_elem.nil?
header = header_data(header_elem.content, privkey) header = header_data(header_elem.content, privkey)
@ -90,29 +98,44 @@ module DiasporaFederation
end end
end end
# Creates an encrypted Salmon Slap and returns the XML string. # Creates an encrypted Salmon Slap.
# #
# @param [String] author_id Diaspora* handle of the author # @param [String] author_id Diaspora* handle of the author
# @param [OpenSSL::PKey::RSA] privkey sender private key for signing the magic envelope # @param [OpenSSL::PKey::RSA] privkey sender private key for signing the magic envelope
# @param [Entity] entity payload # @param [Entity] entity payload
# @return [EncryptedSlap] encrypted Slap instance
# @raise [ArgumentError] if any of the arguments is of the wrong type
def self.prepare(author_id, privkey, entity)
raise ArgumentError unless author_id.instance_of?(String) &&
privkey.instance_of?(OpenSSL::PKey::RSA) &&
entity.is_a?(Entity)
EncryptedSlap.new.tap do |slap|
slap.author_id = author_id
magic_envelope = MagicEnvelope.new(privkey, entity)
slap.cipher_params = magic_envelope.encrypt!
slap.magic_envelope_xml = magic_envelope.envelop
end
end
# Creates an encrypted Salmon Slap XML string.
#
# @param [OpenSSL::PKey::RSA] pubkey recipient public key for encrypting the AES key # @param [OpenSSL::PKey::RSA] pubkey recipient public key for encrypting the AES key
# @return [String] Salmon XML string # @return [String] Salmon XML string
# @raise [ArgumentError] if any of the arguments is of the wrong type # @raise [ArgumentError] if any of the arguments is of the wrong type
def self.generate_xml(author_id, privkey, entity, pubkey) def generate_xml(pubkey)
raise ArgumentError unless author_id.instance_of?(String) && raise ArgumentError unless pubkey.instance_of?(OpenSSL::PKey::RSA)
privkey.instance_of?(OpenSSL::PKey::RSA) &&
entity.is_a?(Entity) &&
pubkey.instance_of?(OpenSSL::PKey::RSA)
Slap.build_xml do |xml| Slap.build_xml do |xml|
magic_envelope = MagicEnvelope.new(privkey, entity) xml.encrypted_header(encrypted_header(author_id, @cipher_params, pubkey))
envelope_key = magic_envelope.encrypt!
encrypted_header(author_id, envelope_key, pubkey, xml) xml.parent << @magic_envelope_xml
magic_envelope.envelop(xml)
end end
end end
private
# decrypts and reads the data from the encrypted XML header # decrypts and reads the data from the encrypted XML header
# @param [String] data base64 encoded, encrypted header data # @param [String] data base64 encoded, encrypted header data
# @param [OpenSSL::PKey::RSA] privkey private key for decryption # @param [OpenSSL::PKey::RSA] privkey private key for decryption
@ -147,43 +170,33 @@ module DiasporaFederation
# @param [String] author_id diaspora_handle # @param [String] author_id diaspora_handle
# @param [Hash] envelope_key envelope cipher params # @param [Hash] envelope_key envelope cipher params
# @param [OpenSSL::PKey::RSA] pubkey recipient public_key # @param [OpenSSL::PKey::RSA] pubkey recipient public_key
# @param [Nokogiri::XML::Element] xml parent element for inserting in XML document # @return [String] encrypted base64 encoded header
def self.encrypted_header(author_id, envelope_key, pubkey, xml) def encrypted_header(author_id, envelope_key, pubkey)
data = header_xml(author_id, strict_base64_encode(envelope_key)) encoded_key = Hash[envelope_key.map {|k, v| [k, Base64.strict_encode64(v)] }]
key = AES.generate_key_and_iv data = header_xml(author_id, encoded_key)
ciphertext = AES.encrypt(data, key[:key], key[:iv]) ciphertext = AES.encrypt(data, envelope_key[:key], envelope_key[:iv])
json_key = JSON.generate(strict_base64_encode(key)) json_key = JSON.generate(encoded_key)
encrypted_key = Base64.strict_encode64(pubkey.public_encrypt(json_key)) encrypted_key = Base64.strict_encode64(pubkey.public_encrypt(json_key))
json_header = JSON.generate(aes_key: encrypted_key, ciphertext: ciphertext) json_header = JSON.generate(aes_key: encrypted_key, ciphertext: ciphertext)
xml.encrypted_header(Base64.strict_encode64(json_header)) Base64.strict_encode64(json_header)
end end
private_class_method :encrypted_header
# generate the header xml string, including the author, aes_key and iv # generate the header xml string, including the author, aes_key and iv
# @param [String] author_id diaspora_handle of the author # @param [String] author_id diaspora_handle of the author
# @param [Hash] envelope_key { key: "...", iv: "..." } (values in base64) # @param [Hash] envelope_key { key: "...", iv: "..." } (values in base64)
# @return [String] header XML string # @return [String] header XML string
def self.header_xml(author_id, envelope_key) def header_xml(author_id, envelope_key)
builder = Nokogiri::XML::Builder.new do |xml| @header_xml ||= Nokogiri::XML::Builder.new(encoding: "UTF-8") {|xml|
xml.decrypted_header { xml.decrypted_header {
xml.iv(envelope_key[:iv]) xml.iv(envelope_key[:iv])
xml.aes_key(envelope_key[:key]) xml.aes_key(envelope_key[:key])
xml.author_id(author_id) xml.author_id(author_id)
} }
end }.to_xml.strip
builder.to_xml.strip
end end
private_class_method :header_xml
# @param [Hash] hash { key: "...", iv: "..." }
# @return [Hash] encoded hash: { key: "...", iv: "..." }
def self.strict_base64_encode(hash)
Hash[hash.map {|k, v| [k, Base64.strict_encode64(v)] }]
end
private_class_method :strict_base64_encode
end end
end end
end end

View file

@ -55,14 +55,20 @@ module DiasporaFederation
# Builds the XML structure for the magic envelope, inserts the {ENCODING} # Builds the XML structure for the magic envelope, inserts the {ENCODING}
# encoded data and signs the envelope using {DIGEST}. # encoded data and signs the envelope using {DIGEST}.
# #
# @param [Nokogiri::XML::Builder] xml Salmon XML builder # @return [Nokogiri::XML::Element] XML root node
def envelop(xml) def envelop
xml["me"].env { env_doc = Nokogiri::XML::DocumentFragment.new(Nokogiri::XML::Document.new)
xml["me"].data(Base64.urlsafe_encode64(@payload), type: DATA_TYPE) Nokogiri::XML::Element.new("me:env", env_doc).tap do |env|
xml["me"].encoding(ENCODING) env << Nokogiri::XML::Element.new("me:data", env_doc).tap {|node|
xml["me"].alg(ALGORITHM) node.content = Base64.urlsafe_encode64(@payload)
xml["me"].sig(Base64.urlsafe_encode64(signature)) node["type"] = DATA_TYPE
} }
env << Nokogiri::XML::Element.new("me:encoding", env_doc).tap {|node| node.content = ENCODING }
env << Nokogiri::XML::Element.new("me:alg", env_doc).tap {|node| node.content = ALGORITHM }
env << Nokogiri::XML::Element.new("me:sig", env_doc).tap {|node|
node.content = Base64.urlsafe_encode64(signature)
}
end
end end
# Encrypts the payload with a new, random AES cipher and returns the cipher # Encrypts the payload with a new, random AES cipher and returns the cipher
@ -102,8 +108,8 @@ module DiasporaFederation
# @raise [InvalidEncoding] if the data is wrongly encoded # @raise [InvalidEncoding] if the data is wrongly encoded
# @raise [InvalidAlgorithm] if the algorithm used doesn't match # @raise [InvalidAlgorithm] if the algorithm used doesn't match
def self.unenvelop(magic_env, rsa_pubkey, cipher_params=nil) def self.unenvelop(magic_env, rsa_pubkey, cipher_params=nil)
raise ArgumentError unless rsa_pubkey.instance_of?(OpenSSL::PKey::RSA) && raise ArgumentError unless magic_env.instance_of?(Nokogiri::XML::Element) &&
magic_env.instance_of?(Nokogiri::XML::Element) rsa_pubkey.instance_of?(OpenSSL::PKey::RSA)
raise InvalidEnvelope unless envelope_valid?(magic_env) raise InvalidEnvelope unless envelope_valid?(magic_env)
raise InvalidSignature unless signature_valid?(magic_env, rsa_pubkey) raise InvalidSignature unless signature_valid?(magic_env, rsa_pubkey)

View file

@ -33,10 +33,6 @@ module DiasporaFederation
# @param [String] the author diaspora id # @param [String] the author diaspora id
attr_accessor :author_id attr_accessor :author_id
# the key and iv if it is an encrypted slap
# @param [Hash] value hash containing the key and iv
attr_writer :cipher_params
# Namespaces # Namespaces
NS = {d: Salmon::XMLNS, me: MagicEnvelope::XMLNS} NS = {d: Salmon::XMLNS, me: MagicEnvelope::XMLNS}
@ -94,7 +90,7 @@ module DiasporaFederation
xml.author_id(author_id) xml.author_id(author_id)
} }
MagicEnvelope.new(privkey, entity).envelop(xml) xml.parent << MagicEnvelope.new(privkey, entity).envelop
end end
end end
@ -104,12 +100,11 @@ module DiasporaFederation
# {http://www.rubydoc.info/gems/nokogiri/Nokogiri/XML/Builder Nokogiri::XML::Builder} # {http://www.rubydoc.info/gems/nokogiri/Nokogiri/XML/Builder Nokogiri::XML::Builder}
# @return [String] Slap XML # @return [String] Slap XML
def self.build_xml def self.build_xml
builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml| Nokogiri::XML::Builder.new(encoding: "UTF-8") {|xml|
xml.diaspora("xmlns" => Salmon::XMLNS, "xmlns:me" => MagicEnvelope::XMLNS) { xml.diaspora("xmlns" => Salmon::XMLNS, "xmlns:me" => MagicEnvelope::XMLNS) {
yield xml yield xml
} }
end }.to_xml
builder.to_xml
end end
# Parses the magic envelop from the document. # Parses the magic envelop from the document.

View file

@ -89,7 +89,7 @@ module DiasporaFederation
# and attached to resulted hash as string. It is intended to build a hash # and attached to resulted hash as string. It is intended to build a hash
# invariable of an Entity definition, in order to support receiving objects # invariable of an Entity definition, in order to support receiving objects
# from the future versions of Diaspora, where new elements may have been added. # from the future versions of Diaspora, where new elements may have been added.
data = Hash[root_node.element_children.map { |child| data = Hash[root_node.element_children.map {|child|
xml_name = child.name xml_name = child.name
property = klass.class_props.find {|prop| prop[:xml_name].to_s == xml_name } property = klass.class_props.find {|prop| prop[:xml_name].to_s == xml_name }
if property if property

View file

@ -48,7 +48,7 @@ module DiasporaFederation
# @param [Hash] hash data to sign # @param [Hash] hash data to sign
# @return [String] signature data string # @return [String] signature data string
def self.signable_string(hash) def self.signable_string(hash)
hash.map { |name, value| hash.map {|name, value|
value.to_s unless name.match(/signature/) value.to_s unless name.match(/signature/)
}.compact.join(";") }.compact.join(";")
end end

View file

@ -11,7 +11,7 @@ module DiasporaFederation
# @param [Entity.Class] klass entity type to sort according to # @param [Entity.Class] klass entity type to sort according to
# @return [Hash] sorted hash # @return [Hash] sorted hash
def self.sort_hash(data, klass) def self.sort_hash(data, klass)
Hash[klass.class_props.map { |prop| Hash[klass.class_props.map {|prop|
[prop[:name], data[prop[:name]]] unless data[prop[:name]].nil? [prop[:name], data[prop[:name]]] unless data[prop[:name]].nil?
}.compact] }.compact]
end end

View file

@ -4,12 +4,8 @@ module DiasporaFederation
let(:sender_key) { OpenSSL::PKey::RSA.generate(1024) } let(:sender_key) { OpenSSL::PKey::RSA.generate(1024) }
let(:recipient_key) { OpenSSL::PKey::RSA.generate(1024) } let(:recipient_key) { OpenSSL::PKey::RSA.generate(1024) }
let(:xml) { let(:xml) {
DiasporaFederation::Salmon::EncryptedSlap.generate_xml( DiasporaFederation::Salmon::EncryptedSlap.prepare(sender_id, sender_key, FactoryGirl.build(:request_entity))
sender_id, .generate_xml(recipient_key)
sender_key,
FactoryGirl.build(:request_entity),
recipient_key
)
} }
it "calls save_entity_after_receive if everything is fine" do it "calls save_entity_after_receive if everything is fine" do

View file

@ -4,72 +4,122 @@ module DiasporaFederation
let(:privkey) { OpenSSL::PKey::RSA.generate(512) } # use small key for speedy specs let(:privkey) { OpenSSL::PKey::RSA.generate(512) } # use small key for speedy specs
let(:recipient_key) { OpenSSL::PKey::RSA.generate(1024) } # use small key for speedy specs let(:recipient_key) { OpenSSL::PKey::RSA.generate(1024) } # use small key for speedy specs
let(:entity) { Entities::TestEntity.new(test: "qwertzuiop") } let(:entity) { Entities::TestEntity.new(test: "qwertzuiop") }
let(:slap_xml) { Salmon::EncryptedSlap.generate_xml(author_id, privkey, entity, recipient_key.public_key) } let(:slap_xml) { Salmon::EncryptedSlap.prepare(author_id, privkey, entity).generate_xml(recipient_key.public_key) }
let(:ns) { {d: Salmon::XMLNS, me: Salmon::MagicEnvelope::XMLNS} }
describe ".generate_xml" do context "generate" do
context "sanity" do describe ".prepare" do
it "accepts correct params" do context "sanity" do
expect { it "raises an error when the author_id is the wrong type" do
Salmon::EncryptedSlap.generate_xml(author_id, privkey, entity, recipient_key.public_key) [1234, true, :symbol, entity, privkey].each do |val|
}.not_to raise_error expect {
end Salmon::EncryptedSlap.prepare(val, privkey, entity)
}.to raise_error ArgumentError
end
end
it "raises an error when the params are the wrong type" do it "raises an error when the privkey is the wrong type" do
["asdf", 1234, true, :symbol, entity, privkey].each do |val| ["asdf", 1234, true, :symbol, entity].each do |val|
expect { expect {
Salmon::EncryptedSlap.generate_xml(val, val, val, val) Salmon::EncryptedSlap.prepare(author_id, val, entity)
}.to raise_error ArgumentError }.to raise_error ArgumentError
end
end
it "raises an error when the entity is the wrong type" do
["asdf", 1234, true, :symbol, privkey].each do |val|
expect {
Salmon::EncryptedSlap.prepare(author_id, privkey, val)
}.to raise_error ArgumentError
end
end end
end end
end end
it "generates valid xml" do describe ".generate_xml" do
doc = Nokogiri::XML::Document.parse(slap_xml) let(:ns) { {d: Salmon::XMLNS, me: Salmon::MagicEnvelope::XMLNS} }
expect(doc.root.name).to eq("diaspora")
expect(doc.at_xpath("d:diaspora/d:encrypted_header", ns).content).to_not be_empty
expect(doc.xpath("d:diaspora/me:env", ns)).to have(1).item
end
context "header" do context "sanity" do
subject { it "accepts correct params" do
expect {
Salmon::EncryptedSlap.prepare(author_id, privkey, entity).generate_xml(recipient_key.public_key)
}.not_to raise_error
end
it "raises an error when the params are the wrong type" do
["asdf", 1234, true, :symbol, entity].each do |val|
expect {
Salmon::EncryptedSlap.prepare(author_id, privkey, entity).generate_xml(val)
}.to raise_error ArgumentError
end
end
end
it "generates valid xml" do
doc = Nokogiri::XML::Document.parse(slap_xml) doc = Nokogiri::XML::Document.parse(slap_xml)
doc.at_xpath("d:diaspora/d:encrypted_header", ns).content expect(doc.root.name).to eq("diaspora")
} expect(doc.at_xpath("d:diaspora/d:encrypted_header", ns).content).to_not be_empty
let(:cipher_header) { JSON.parse(Base64.decode64(subject)) } expect(doc.xpath("d:diaspora/me:env", ns)).to have(1).item
let(:header_key) {
JSON.parse(recipient_key.private_decrypt(Base64.decode64(cipher_header["aes_key"])))
}
it "encodes the header correctly" do
json_header = {}
expect {
json_header = JSON.parse(Base64.decode64(subject))
}.not_to raise_error
expect(json_header).to include("aes_key", "ciphertext")
end end
it "encrypts the public_key encrypted header correctly" do it "can generate xml for two people" do
key = {} slap = Salmon::EncryptedSlap.prepare(author_id, privkey, entity)
expect {
key = JSON.parse(recipient_key.private_decrypt(Base64.decode64(cipher_header["aes_key"]))) doc1 = Nokogiri::XML::Document.parse(slap.generate_xml(recipient_key.public_key))
}.not_to raise_error enc_header1 = doc1.at_xpath("d:diaspora/d:encrypted_header", ns).content
expect(key).to include("key", "iv") cipher_header1 = JSON.parse(Base64.decode64(enc_header1))
key_json1 = recipient_key.private_decrypt(Base64.decode64(cipher_header1["aes_key"]))
recipient2_key = OpenSSL::PKey::RSA.generate(1024)
doc2 = Nokogiri::XML::Document.parse(slap.generate_xml(recipient2_key.public_key))
enc_header2 = doc2.at_xpath("d:diaspora/d:encrypted_header", ns).content
cipher_header2 = JSON.parse(Base64.decode64(enc_header2))
key_json2 = recipient2_key.private_decrypt(Base64.decode64(cipher_header2["aes_key"]))
expect(enc_header1).not_to eq(enc_header2)
expect(key_json1).to eq(key_json2)
expect(doc1.xpath("d:diaspora/me:env", ns).to_xml).to eq(doc2.xpath("d:diaspora/me:env", ns).to_xml)
end end
it "encrypts the aes encrypted header correctly" do context "header" do
header = "" subject {
expect { doc = Nokogiri::XML::Document.parse(slap_xml)
header = Salmon::AES.decrypt(cipher_header["ciphertext"], doc.at_xpath("d:diaspora/d:encrypted_header", ns).content
Base64.decode64(header_key["key"]), }
Base64.decode64(header_key["iv"])) let(:cipher_header) { JSON.parse(Base64.decode64(subject)) }
}.not_to raise_error let(:header_key) {
header_doc = Nokogiri::XML::Document.parse(header) JSON.parse(recipient_key.private_decrypt(Base64.decode64(cipher_header["aes_key"])))
expect(header_doc.root.name).to eq("decrypted_header") }
expect(header_doc.xpath("//iv")).to have(1).item
expect(header_doc.xpath("//aes_key")).to have(1).item it "encodes the header correctly" do
expect(header_doc.xpath("//author_id")).to have(1).item json_header = {}
expect(header_doc.at_xpath("//author_id").content).to eq(author_id) expect {
json_header = JSON.parse(Base64.decode64(subject))
}.not_to raise_error
expect(json_header).to include("aes_key", "ciphertext")
end
it "encrypts the public_key encrypted header correctly" do
key = {}
expect {
key = JSON.parse(recipient_key.private_decrypt(Base64.decode64(cipher_header["aes_key"])))
}.not_to raise_error
expect(key).to include("key", "iv")
end
it "encrypts the aes encrypted header correctly" do
header = ""
expect {
header = Salmon::AES.decrypt(cipher_header["ciphertext"],
Base64.decode64(header_key["key"]),
Base64.decode64(header_key["iv"]))
}.not_to raise_error
header_doc = Nokogiri::XML::Document.parse(header)
expect(header_doc.root.name).to eq("decrypted_header")
expect(header_doc.xpath("//iv")).to have(1).item
expect(header_doc.xpath("//aes_key")).to have(1).item
expect(header_doc.xpath("//author_id")).to have(1).item
expect(header_doc.at_xpath("//author_id").content).to eq(author_id)
end
end end
end end
end end

View file

@ -5,12 +5,11 @@ module DiasporaFederation
let(:envelope) { envelop_xml(Salmon::MagicEnvelope.new(privkey, payload)) } let(:envelope) { envelop_xml(Salmon::MagicEnvelope.new(privkey, payload)) }
def envelop_xml(magic_env) def envelop_xml(magic_env)
builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml| Nokogiri::XML::Builder.new(encoding: "UTF-8") {|xml|
xml.root("xmlns:me" => Salmon::MagicEnvelope::XMLNS) { xml.root("xmlns:me" => Salmon::MagicEnvelope::XMLNS) {
magic_env.envelop(xml) xml.parent << magic_env.envelop
} }
end }.doc.at_xpath("//me:env")
builder.doc.at_xpath("//me:env")
end end
def sig_subj(env) def sig_subj(env)

View file

@ -3,7 +3,7 @@ module DiasporaFederation
let(:author_id) { "test_user@pod.somedomain.tld" } let(:author_id) { "test_user@pod.somedomain.tld" }
let(:privkey) { OpenSSL::PKey::RSA.generate(512) } # use small key for speedy specs let(:privkey) { OpenSSL::PKey::RSA.generate(512) } # use small key for speedy specs
let(:entity) { Entities::TestEntity.new(test: "qwertzuiop") } let(:entity) { Entities::TestEntity.new(test: "qwertzuiop") }
let(:slap) { Salmon::Slap.generate_xml(author_id, privkey, entity) } let(:slap_xml) { Salmon::Slap.generate_xml(author_id, privkey, entity) }
describe ".generate_xml" do describe ".generate_xml" do
context "sanity" do context "sanity" do
@ -13,10 +13,26 @@ module DiasporaFederation
}.not_to raise_error }.not_to raise_error
end end
it "raises an error when the params are the wrong type" do it "raises an error when the author_id is the wrong type" do
["asdf", 1234, true, :symbol, entity, privkey].each do |val| [1234, true, :symbol, entity, privkey].each do |val|
expect { expect {
Salmon::Slap.generate_xml(val, val, val) Salmon::Slap.generate_xml(val, privkey, entity)
}.to raise_error ArgumentError
end
end
it "raises an error when the privkey is the wrong type" do
["asdf", 1234, true, :symbol, entity].each do |val|
expect {
Salmon::Slap.generate_xml(author_id, val, entity)
}.to raise_error ArgumentError
end
end
it "raises an error when the entity is the wrong type" do
["asdf", 1234, true, :symbol, privkey].each do |val|
expect {
Salmon::Slap.generate_xml(author_id, privkey, val)
}.to raise_error ArgumentError }.to raise_error ArgumentError
end end
end end
@ -24,7 +40,7 @@ module DiasporaFederation
it "generates valid xml" do it "generates valid xml" do
ns = {d: Salmon::XMLNS, me: Salmon::MagicEnvelope::XMLNS} ns = {d: Salmon::XMLNS, me: Salmon::MagicEnvelope::XMLNS}
doc = Nokogiri::XML::Document.parse(slap) doc = Nokogiri::XML::Document.parse(slap_xml)
expect(doc.root.name).to eq("diaspora") expect(doc.root.name).to eq("diaspora")
expect(doc.at_xpath("d:diaspora/d:header/d:author_id", ns).content).to eq(author_id) expect(doc.at_xpath("d:diaspora/d:header/d:author_id", ns).content).to eq(author_id)
expect(doc.xpath("d:diaspora/me:env", ns)).to have(1).item expect(doc.xpath("d:diaspora/me:env", ns)).to have(1).item
@ -35,7 +51,7 @@ module DiasporaFederation
context "sanity" do context "sanity" do
it "accepts salmon xml as param" do it "accepts salmon xml as param" do
expect { expect {
Salmon::Slap.from_xml(slap) Salmon::Slap.from_xml(slap_xml)
}.not_to raise_error }.not_to raise_error
end end
@ -75,7 +91,7 @@ XML
context "generated instance" do context "generated instance" do
it_behaves_like "a Slap instance" do it_behaves_like "a Slap instance" do
subject { Salmon::Slap.from_xml(slap) } subject { Salmon::Slap.from_xml(slap_xml) }
end end
end end
end end