From a0398430ede0c50f41a317807f15a1ec30370bce Mon Sep 17 00:00:00 2001 From: Benjamin Neff Date: Thu, 14 Jan 2016 03:42:36 +0100 Subject: [PATCH] refactor encrypted slap to reuse it for every recipient --- .../discovery/xrd_document.rb | 5 +- lib/diaspora_federation/properties_dsl.rb | 4 +- .../salmon/encrypted_slap.rb | 79 +++++---- .../salmon/magic_envelope.rb | 26 +-- lib/diaspora_federation/salmon/slap.rb | 11 +- lib/diaspora_federation/salmon/xml_payload.rb | 2 +- lib/diaspora_federation/signing.rb | 2 +- lib/diaspora_federation/test.rb | 2 +- .../federation/receiver/private_spec.rb | 8 +- .../salmon/encrypted_slap_spec.rb | 158 ++++++++++++------ .../salmon/magic_envelope_spec.rb | 7 +- .../diaspora_federation/salmon/slap_spec.rb | 30 +++- 12 files changed, 204 insertions(+), 130 deletions(-) diff --git a/lib/diaspora_federation/discovery/xrd_document.rb b/lib/diaspora_federation/discovery/xrd_document.rb index 7e1a22a..57039e9 100644 --- a/lib/diaspora_federation/discovery/xrd_document.rb +++ b/lib/diaspora_federation/discovery/xrd_document.rb @@ -67,7 +67,7 @@ module DiasporaFederation # Generates an XML document from the current instance and returns it as string # @return [String] XML document 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.Expires(@expires.strftime(DATETIME_FORMAT)) if @expires.instance_of?(DateTime) @@ -77,8 +77,7 @@ module DiasporaFederation add_properties_to(xml) add_links_to(xml) } - end - builder.to_xml + }.to_xml end # Parse the XRD document from the given string and create a hash containing diff --git a/lib/diaspora_federation/properties_dsl.rb b/lib/diaspora_federation/properties_dsl.rb index 1013226..98dc074 100644 --- a/lib/diaspora_federation/properties_dsl.rb +++ b/lib/diaspora_federation/properties_dsl.rb @@ -49,7 +49,7 @@ module DiasporaFederation # resolved on each call # @return [Hash] 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 } end @@ -105,7 +105,7 @@ module DiasporaFederation # @param [Class] type the type to check # @return [Boolean] def type_valid?(type) - [type].flatten.all? { |type| + [type].flatten.all? {|type| type.respond_to?(:ancestors) && type.ancestors.include?(Entity) } end diff --git a/lib/diaspora_federation/salmon/encrypted_slap.rb b/lib/diaspora_federation/salmon/encrypted_slap.rb index 410bf6c..74ee725 100644 --- a/lib/diaspora_federation/salmon/encrypted_slap.rb +++ b/lib/diaspora_federation/salmon/encrypted_slap.rb @@ -63,14 +63,22 @@ module DiasporaFederation # # 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 # containing an encrypted payload. # # @param [String] slap_xml encrypted Salmon xml # @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 [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) 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) raise MissingHeader if header_elem.nil? header = header_data(header_elem.content, privkey) @@ -90,29 +98,44 @@ module DiasporaFederation 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 [OpenSSL::PKey::RSA] privkey sender private key for signing the magic envelope # @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 # @return [String] Salmon XML string # @raise [ArgumentError] if any of the arguments is of the wrong type - def self.generate_xml(author_id, privkey, entity, pubkey) - raise ArgumentError unless author_id.instance_of?(String) && - privkey.instance_of?(OpenSSL::PKey::RSA) && - entity.is_a?(Entity) && - pubkey.instance_of?(OpenSSL::PKey::RSA) + def generate_xml(pubkey) + raise ArgumentError unless pubkey.instance_of?(OpenSSL::PKey::RSA) Slap.build_xml do |xml| - magic_envelope = MagicEnvelope.new(privkey, entity) - envelope_key = magic_envelope.encrypt! + xml.encrypted_header(encrypted_header(author_id, @cipher_params, pubkey)) - encrypted_header(author_id, envelope_key, pubkey, xml) - magic_envelope.envelop(xml) + xml.parent << @magic_envelope_xml end end + private + # decrypts and reads the data from the encrypted XML header # @param [String] data base64 encoded, encrypted header data # @param [OpenSSL::PKey::RSA] privkey private key for decryption @@ -147,43 +170,33 @@ module DiasporaFederation # @param [String] author_id diaspora_handle # @param [Hash] envelope_key envelope cipher params # @param [OpenSSL::PKey::RSA] pubkey recipient public_key - # @param [Nokogiri::XML::Element] xml parent element for inserting in XML document - def self.encrypted_header(author_id, envelope_key, pubkey, xml) - data = header_xml(author_id, strict_base64_encode(envelope_key)) - key = AES.generate_key_and_iv - ciphertext = AES.encrypt(data, key[:key], key[:iv]) + # @return [String] encrypted base64 encoded header + def encrypted_header(author_id, envelope_key, pubkey) + encoded_key = Hash[envelope_key.map {|k, v| [k, Base64.strict_encode64(v)] }] + data = header_xml(author_id, encoded_key) + 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)) json_header = JSON.generate(aes_key: encrypted_key, ciphertext: ciphertext) - xml.encrypted_header(Base64.strict_encode64(json_header)) + Base64.strict_encode64(json_header) end - private_class_method :encrypted_header # generate the header xml string, including the author, aes_key and iv # @param [String] author_id diaspora_handle of the author # @param [Hash] envelope_key { key: "...", iv: "..." } (values in base64) # @return [String] header XML string - def self.header_xml(author_id, envelope_key) - builder = Nokogiri::XML::Builder.new do |xml| + def header_xml(author_id, envelope_key) + @header_xml ||= Nokogiri::XML::Builder.new(encoding: "UTF-8") {|xml| xml.decrypted_header { xml.iv(envelope_key[:iv]) xml.aes_key(envelope_key[:key]) xml.author_id(author_id) } - end - builder.to_xml.strip + }.to_xml.strip 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 diff --git a/lib/diaspora_federation/salmon/magic_envelope.rb b/lib/diaspora_federation/salmon/magic_envelope.rb index 374376e..ad386ac 100644 --- a/lib/diaspora_federation/salmon/magic_envelope.rb +++ b/lib/diaspora_federation/salmon/magic_envelope.rb @@ -55,14 +55,20 @@ module DiasporaFederation # Builds the XML structure for the magic envelope, inserts the {ENCODING} # encoded data and signs the envelope using {DIGEST}. # - # @param [Nokogiri::XML::Builder] xml Salmon XML builder - def envelop(xml) - xml["me"].env { - xml["me"].data(Base64.urlsafe_encode64(@payload), type: DATA_TYPE) - xml["me"].encoding(ENCODING) - xml["me"].alg(ALGORITHM) - xml["me"].sig(Base64.urlsafe_encode64(signature)) - } + # @return [Nokogiri::XML::Element] XML root node + def envelop + env_doc = Nokogiri::XML::DocumentFragment.new(Nokogiri::XML::Document.new) + Nokogiri::XML::Element.new("me:env", env_doc).tap do |env| + env << Nokogiri::XML::Element.new("me:data", env_doc).tap {|node| + node.content = Base64.urlsafe_encode64(@payload) + 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 # 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 [InvalidAlgorithm] if the algorithm used doesn't match def self.unenvelop(magic_env, rsa_pubkey, cipher_params=nil) - raise ArgumentError unless rsa_pubkey.instance_of?(OpenSSL::PKey::RSA) && - magic_env.instance_of?(Nokogiri::XML::Element) + raise ArgumentError unless magic_env.instance_of?(Nokogiri::XML::Element) && + rsa_pubkey.instance_of?(OpenSSL::PKey::RSA) raise InvalidEnvelope unless envelope_valid?(magic_env) raise InvalidSignature unless signature_valid?(magic_env, rsa_pubkey) diff --git a/lib/diaspora_federation/salmon/slap.rb b/lib/diaspora_federation/salmon/slap.rb index 3f923b1..d4b6474 100644 --- a/lib/diaspora_federation/salmon/slap.rb +++ b/lib/diaspora_federation/salmon/slap.rb @@ -33,10 +33,6 @@ module DiasporaFederation # @param [String] the author diaspora 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 NS = {d: Salmon::XMLNS, me: MagicEnvelope::XMLNS} @@ -94,7 +90,7 @@ module DiasporaFederation xml.author_id(author_id) } - MagicEnvelope.new(privkey, entity).envelop(xml) + xml.parent << MagicEnvelope.new(privkey, entity).envelop end end @@ -104,12 +100,11 @@ module DiasporaFederation # {http://www.rubydoc.info/gems/nokogiri/Nokogiri/XML/Builder Nokogiri::XML::Builder} # @return [String] Slap 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) { yield xml } - end - builder.to_xml + }.to_xml end # Parses the magic envelop from the document. diff --git a/lib/diaspora_federation/salmon/xml_payload.rb b/lib/diaspora_federation/salmon/xml_payload.rb index e7bd490..e69a8bf 100644 --- a/lib/diaspora_federation/salmon/xml_payload.rb +++ b/lib/diaspora_federation/salmon/xml_payload.rb @@ -89,7 +89,7 @@ module DiasporaFederation # 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 # 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 property = klass.class_props.find {|prop| prop[:xml_name].to_s == xml_name } if property diff --git a/lib/diaspora_federation/signing.rb b/lib/diaspora_federation/signing.rb index 5cb2ed1..1992fa8 100644 --- a/lib/diaspora_federation/signing.rb +++ b/lib/diaspora_federation/signing.rb @@ -48,7 +48,7 @@ module DiasporaFederation # @param [Hash] hash data to sign # @return [String] signature data string def self.signable_string(hash) - hash.map { |name, value| + hash.map {|name, value| value.to_s unless name.match(/signature/) }.compact.join(";") end diff --git a/lib/diaspora_federation/test.rb b/lib/diaspora_federation/test.rb index 2282e2c..6fee3a8 100644 --- a/lib/diaspora_federation/test.rb +++ b/lib/diaspora_federation/test.rb @@ -11,7 +11,7 @@ module DiasporaFederation # @param [Entity.Class] klass entity type to sort according to # @return [Hash] sorted hash 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? }.compact] end diff --git a/spec/lib/diaspora_federation/federation/receiver/private_spec.rb b/spec/lib/diaspora_federation/federation/receiver/private_spec.rb index 0ca7ddb..3bd1dc3 100644 --- a/spec/lib/diaspora_federation/federation/receiver/private_spec.rb +++ b/spec/lib/diaspora_federation/federation/receiver/private_spec.rb @@ -4,12 +4,8 @@ module DiasporaFederation let(:sender_key) { OpenSSL::PKey::RSA.generate(1024) } let(:recipient_key) { OpenSSL::PKey::RSA.generate(1024) } let(:xml) { - DiasporaFederation::Salmon::EncryptedSlap.generate_xml( - sender_id, - sender_key, - FactoryGirl.build(:request_entity), - recipient_key - ) + DiasporaFederation::Salmon::EncryptedSlap.prepare(sender_id, sender_key, FactoryGirl.build(:request_entity)) + .generate_xml(recipient_key) } it "calls save_entity_after_receive if everything is fine" do diff --git a/spec/lib/diaspora_federation/salmon/encrypted_slap_spec.rb b/spec/lib/diaspora_federation/salmon/encrypted_slap_spec.rb index 2e36751..40ec4f0 100644 --- a/spec/lib/diaspora_federation/salmon/encrypted_slap_spec.rb +++ b/spec/lib/diaspora_federation/salmon/encrypted_slap_spec.rb @@ -4,72 +4,122 @@ module DiasporaFederation 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(:entity) { Entities::TestEntity.new(test: "qwertzuiop") } - let(:slap_xml) { Salmon::EncryptedSlap.generate_xml(author_id, privkey, entity, recipient_key.public_key) } - let(:ns) { {d: Salmon::XMLNS, me: Salmon::MagicEnvelope::XMLNS} } + let(:slap_xml) { Salmon::EncryptedSlap.prepare(author_id, privkey, entity).generate_xml(recipient_key.public_key) } - describe ".generate_xml" do - context "sanity" do - it "accepts correct params" do - expect { - Salmon::EncryptedSlap.generate_xml(author_id, privkey, entity, recipient_key.public_key) - }.not_to raise_error - end + context "generate" do + describe ".prepare" do + context "sanity" do + it "raises an error when the author_id is the wrong type" do + [1234, true, :symbol, entity, privkey].each do |val| + expect { + Salmon::EncryptedSlap.prepare(val, privkey, entity) + }.to raise_error ArgumentError + end + end - it "raises an error when the params are the wrong type" do - ["asdf", 1234, true, :symbol, entity, privkey].each do |val| - expect { - Salmon::EncryptedSlap.generate_xml(val, val, val, val) - }.to raise_error ArgumentError + it "raises an error when the privkey is the wrong type" do + ["asdf", 1234, true, :symbol, entity].each do |val| + expect { + Salmon::EncryptedSlap.prepare(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::EncryptedSlap.prepare(author_id, privkey, val) + }.to raise_error ArgumentError + end end end end - it "generates valid xml" do - doc = Nokogiri::XML::Document.parse(slap_xml) - 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 + describe ".generate_xml" do + let(:ns) { {d: Salmon::XMLNS, me: Salmon::MagicEnvelope::XMLNS} } - context "header" do - subject { + context "sanity" do + 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.at_xpath("d:diaspora/d:encrypted_header", ns).content - } - let(:cipher_header) { JSON.parse(Base64.decode64(subject)) } - 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") + 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 - 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") + it "can generate xml for two people" do + slap = Salmon::EncryptedSlap.prepare(author_id, privkey, entity) + + doc1 = Nokogiri::XML::Document.parse(slap.generate_xml(recipient_key.public_key)) + enc_header1 = doc1.at_xpath("d:diaspora/d:encrypted_header", ns).content + 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 - 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) + context "header" do + subject { + doc = Nokogiri::XML::Document.parse(slap_xml) + doc.at_xpath("d:diaspora/d:encrypted_header", ns).content + } + let(:cipher_header) { JSON.parse(Base64.decode64(subject)) } + 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 + + 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 diff --git a/spec/lib/diaspora_federation/salmon/magic_envelope_spec.rb b/spec/lib/diaspora_federation/salmon/magic_envelope_spec.rb index e2dc62c..b23a3f9 100644 --- a/spec/lib/diaspora_federation/salmon/magic_envelope_spec.rb +++ b/spec/lib/diaspora_federation/salmon/magic_envelope_spec.rb @@ -5,12 +5,11 @@ module DiasporaFederation let(:envelope) { envelop_xml(Salmon::MagicEnvelope.new(privkey, payload)) } 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) { - magic_env.envelop(xml) + xml.parent << magic_env.envelop } - end - builder.doc.at_xpath("//me:env") + }.doc.at_xpath("//me:env") end def sig_subj(env) diff --git a/spec/lib/diaspora_federation/salmon/slap_spec.rb b/spec/lib/diaspora_federation/salmon/slap_spec.rb index 608dd42..4d3b3c6 100644 --- a/spec/lib/diaspora_federation/salmon/slap_spec.rb +++ b/spec/lib/diaspora_federation/salmon/slap_spec.rb @@ -3,7 +3,7 @@ module DiasporaFederation let(:author_id) { "test_user@pod.somedomain.tld" } let(:privkey) { OpenSSL::PKey::RSA.generate(512) } # use small key for speedy specs 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 context "sanity" do @@ -13,10 +13,26 @@ module DiasporaFederation }.not_to raise_error end - it "raises an error when the params are the wrong type" do - ["asdf", 1234, true, :symbol, entity, privkey].each do |val| + it "raises an error when the author_id is the wrong type" do + [1234, true, :symbol, entity, privkey].each do |val| 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 end end @@ -24,7 +40,7 @@ module DiasporaFederation it "generates valid xml" do 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.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 @@ -35,7 +51,7 @@ module DiasporaFederation context "sanity" do it "accepts salmon xml as param" do expect { - Salmon::Slap.from_xml(slap) + Salmon::Slap.from_xml(slap_xml) }.not_to raise_error end @@ -75,7 +91,7 @@ XML context "generated 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