diff --git a/lib/diaspora_federation/salmon/encrypted_slap.rb b/lib/diaspora_federation/salmon/encrypted_slap.rb index 4acc4ef..42dba8b 100644 --- a/lib/diaspora_federation/salmon/encrypted_slap.rb +++ b/lib/diaspora_federation/salmon/encrypted_slap.rb @@ -115,7 +115,7 @@ module DiasporaFederation magic_envelope = MagicEnvelope.new(entity) slap.cipher_params = magic_envelope.encrypt! - slap.magic_envelope_xml = magic_envelope.envelop(privkey) + slap.magic_envelope_xml = magic_envelope.envelop(privkey).root end end diff --git a/lib/diaspora_federation/salmon/magic_envelope.rb b/lib/diaspora_federation/salmon/magic_envelope.rb index 8d8544f..1c8acaa 100644 --- a/lib/diaspora_federation/salmon/magic_envelope.rb +++ b/lib/diaspora_federation/salmon/magic_envelope.rb @@ -153,7 +153,7 @@ module DiasporaFederation def build_xml Nokogiri::XML::Builder.new(encoding: "UTF-8") {|xml| yield xml - }.doc.root + }.doc end # Creates the signature for all fields according to specification diff --git a/lib/diaspora_federation/salmon/slap.rb b/lib/diaspora_federation/salmon/slap.rb index 958550a..3e65b54 100644 --- a/lib/diaspora_federation/salmon/slap.rb +++ b/lib/diaspora_federation/salmon/slap.rb @@ -49,27 +49,6 @@ module DiasporaFederation MagicEnvelope.unenvelop(magic_env_from_doc(doc), sender) end - # Creates an unencrypted Salmon Slap and returns the XML string. - # - # @param [String] author_id diaspora* ID of the author - # @param [OpenSSL::PKey::RSA] privkey sender private_key for signing the magic envelope - # @param [Entity] entity payload - # @return [String] Salmon XML string - # @raise [ArgumentError] if any of the arguments is not the correct type - def self.generate_xml(author_id, privkey, entity) - raise ArgumentError unless author_id.instance_of?(String) && - privkey.instance_of?(OpenSSL::PKey::RSA) && - entity.is_a?(Entity) - - build_xml do |xml| - xml.header { - xml.author_id(author_id) - } - - xml.parent << MagicEnvelope.new(entity, author_id).envelop(privkey) - end - end - # Builds the xml for the Salmon Slap. # # @yield [xml] Invokes the block with the diff --git a/spec/lib/diaspora_federation/federation/receiver_spec.rb b/spec/lib/diaspora_federation/federation/receiver_spec.rb index 0c924c8..83d2df1 100644 --- a/spec/lib/diaspora_federation/federation/receiver_spec.rb +++ b/spec/lib/diaspora_federation/federation/receiver_spec.rb @@ -24,7 +24,13 @@ module DiasporaFederation it "parses the entity with legacy slap receiver" do expect_callback(:fetch_public_key, post.author).and_return(sender_key) - data = DiasporaFederation::Salmon::Slap.generate_xml(post.author, sender_key, post) + data = DiasporaFederation::Salmon::Slap.build_xml do |xml| + xml.header { + xml.author_id(post.author) + } + + xml.parent << Salmon::MagicEnvelope.new(post, post.author).envelop(sender_key).root + end expect_callback(:receive_entity, kind_of(Entities::StatusMessage), post.author, nil) do |_, entity| expect(entity.guid).to eq(post.guid) diff --git a/spec/lib/diaspora_federation/salmon/encrypted_magic_envelope_spec.rb b/spec/lib/diaspora_federation/salmon/encrypted_magic_envelope_spec.rb index 2c5bafd..f39fa21 100644 --- a/spec/lib/diaspora_federation/salmon/encrypted_magic_envelope_spec.rb +++ b/spec/lib/diaspora_federation/salmon/encrypted_magic_envelope_spec.rb @@ -32,7 +32,7 @@ module DiasporaFederation xml = Salmon::AES.decrypt(json["encrypted_magic_envelope"], key["key"], key["iv"]) - expect(Nokogiri::XML::Document.parse(xml).root.to_xml).to eq(magic_env.to_xml) + expect(Nokogiri::XML::Document.parse(xml).to_xml).to eq(magic_env.to_xml) 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 47a5955..90c76a4 100644 --- a/spec/lib/diaspora_federation/salmon/magic_envelope_spec.rb +++ b/spec/lib/diaspora_federation/salmon/magic_envelope_spec.rb @@ -6,10 +6,10 @@ module DiasporaFederation let(:envelope) { Salmon::MagicEnvelope.new(payload, sender) } def sig_subj(env) - data = Base64.urlsafe_decode64(env.at_xpath("me:data").content) - type = env.at_xpath("me:data")["type"] - enc = env.at_xpath("me:encoding").content - alg = env.at_xpath("me:alg").content + data = Base64.urlsafe_decode64(env.at_xpath("me:env/me:data").content) + type = env.at_xpath("me:env/me:data")["type"] + enc = env.at_xpath("me:env/me:encoding").content + alg = env.at_xpath("me:env/me:alg").content [data, type, enc, alg].map {|i| Base64.urlsafe_encode64(i) }.join(".") end @@ -41,12 +41,12 @@ module DiasporaFederation end end - it "should be an instance of Nokogiri::XML::Element" do - expect(envelope.envelop(privkey)).to be_an_instance_of Nokogiri::XML::Element + it "should be an instance of Nokogiri::XML::Document" do + expect(envelope.envelop(privkey)).to be_an_instance_of Nokogiri::XML::Document end it "returns a magic envelope of correct structure" do - env_xml = envelope.envelop(privkey) + env_xml = envelope.envelop(privkey).root expect(env_xml.name).to eq("env") control = %w(data encoding alg sig) @@ -59,13 +59,13 @@ module DiasporaFederation end it "adds the sender to the signature" do - key_id = envelope.envelop(privkey).at_xpath("me:sig")["key_id"] + key_id = envelope.envelop(privkey).at_xpath("me:env/me:sig")["key_id"] expect(Base64.urlsafe_decode64(key_id)).to eq(sender) end it "adds the data_type" do - data_type = envelope.envelop(privkey).at_xpath("me:data")["type"] + data_type = envelope.envelop(privkey).at_xpath("me:env/me:data")["type"] expect(data_type).to eq("application/xml") end @@ -74,7 +74,7 @@ module DiasporaFederation env_xml = envelope.envelop(privkey) subj = sig_subj(env_xml) - sig = Base64.urlsafe_decode64(env_xml.at_xpath("me:sig").content) + sig = Base64.urlsafe_decode64(env_xml.at_xpath("me:env/me:sig").content) expect(privkey.public_key.verify(OpenSSL::Digest::SHA256.new, sig, subj)).to be_truthy end @@ -103,6 +103,8 @@ module DiasporaFederation end describe ".unenvelop" do + let(:envelope_root) { envelope.envelop(privkey).root } + context "sanity" do before do allow(DiasporaFederation.callbacks).to receive(:trigger).with( @@ -112,7 +114,7 @@ module DiasporaFederation it "works with sane input" do expect { - Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey), sender) + Salmon::MagicEnvelope.unenvelop(envelope_root, sender) }.not_to raise_error end @@ -131,10 +133,9 @@ module DiasporaFederation end it "raises if missing signature" do - bad_env = envelope.envelop(privkey) - bad_env.at_xpath("me:sig").remove + envelope_root.at_xpath("me:sig").remove expect { - Salmon::MagicEnvelope.unenvelop(bad_env, sender) + Salmon::MagicEnvelope.unenvelop(envelope_root, sender) }.to raise_error Salmon::InvalidEnvelope, "missing me:sig" end @@ -145,70 +146,63 @@ module DiasporaFederation expect_callback(:fetch_public_key, other_sender).and_return(other_key) expect { - Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey), other_sender) + Salmon::MagicEnvelope.unenvelop(envelope_root, other_sender) }.to raise_error Salmon::InvalidSignature end it "raises if missing data" do - bad_env = envelope.envelop(privkey) - bad_env.at_xpath("me:data").remove + envelope_root.at_xpath("me:data").remove expect { - Salmon::MagicEnvelope.unenvelop(bad_env, sender) + Salmon::MagicEnvelope.unenvelop(envelope_root, sender) }.to raise_error Salmon::InvalidEnvelope, "missing me:data" end it "raises if missing encoding" do - bad_env = envelope.envelop(privkey) - bad_env.at_xpath("me:encoding").remove + envelope_root.at_xpath("me:encoding").remove expect { - Salmon::MagicEnvelope.unenvelop(bad_env, sender) + Salmon::MagicEnvelope.unenvelop(envelope_root, sender) }.to raise_error Salmon::InvalidEncoding, "missing encoding" end it "verifies the encoding" do - bad_env = envelope.envelop(privkey) - bad_env.at_xpath("me:encoding").content = "invalid_enc" + envelope_root.at_xpath("me:encoding").content = "invalid_enc" expect { - Salmon::MagicEnvelope.unenvelop(bad_env, sender) + Salmon::MagicEnvelope.unenvelop(envelope_root, sender) }.to raise_error Salmon::InvalidEncoding, "invalid encoding: invalid_enc" end it "raises if missing algorithm" do - bad_env = envelope.envelop(privkey) - bad_env.at_xpath("me:alg").remove + envelope_root.at_xpath("me:alg").remove expect { - Salmon::MagicEnvelope.unenvelop(bad_env, sender) + Salmon::MagicEnvelope.unenvelop(envelope_root, sender) }.to raise_error Salmon::InvalidAlgorithm, "missing algorithm" end it "verifies the algorithm" do - bad_env = envelope.envelop(privkey) - bad_env.at_xpath("me:alg").content = "invalid_alg" + envelope_root.at_xpath("me:alg").content = "invalid_alg" expect { - Salmon::MagicEnvelope.unenvelop(bad_env, sender) + Salmon::MagicEnvelope.unenvelop(envelope_root, sender) }.to raise_error Salmon::InvalidAlgorithm, "invalid algorithm: invalid_alg" end it "raises if missing data type" do - bad_env = envelope.envelop(privkey) - bad_env.at_xpath("me:data").attributes["type"].remove + envelope_root.at_xpath("me:data").attributes["type"].remove expect { - Salmon::MagicEnvelope.unenvelop(bad_env, sender) + Salmon::MagicEnvelope.unenvelop(envelope_root, sender) }.to raise_error Salmon::InvalidDataType, "missing data type" end it "verifies the data type" do - bad_env = envelope.envelop(privkey) - bad_env.at_xpath("me:data")["type"] = "invalid_type" + envelope_root.at_xpath("me:data")["type"] = "invalid_type" expect { - Salmon::MagicEnvelope.unenvelop(bad_env, sender) + Salmon::MagicEnvelope.unenvelop(envelope_root, sender) }.to raise_error Salmon::InvalidDataType, "invalid data type: invalid_type" end end context "generated instance" do it_behaves_like "a MagicEnvelope instance" do - subject { Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey), sender) } + subject { Salmon::MagicEnvelope.unenvelop(envelope_root, sender) } end end @@ -217,7 +211,7 @@ module DiasporaFederation env = Salmon::MagicEnvelope.new(payload) params = env.encrypt! - env_xml = env.envelop(privkey) + env_xml = env.envelop(privkey).root magic_env = Salmon::MagicEnvelope.unenvelop(env_xml, sender, params) expect(magic_env.payload).to be_an_instance_of Entities::TestEntity @@ -227,17 +221,15 @@ module DiasporaFederation context "use key_id from magic envelope" do context "generated instance" do it_behaves_like "a MagicEnvelope instance" do - subject { Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey)) } + subject { Salmon::MagicEnvelope.unenvelop(envelope_root) } end end it "raises if the magic envelope has no key_id" do - bad_env = envelope.envelop(privkey) - - bad_env.at_xpath("me:sig").attributes["key_id"].remove + envelope_root.at_xpath("me:sig").attributes["key_id"].remove expect { - Salmon::MagicEnvelope.unenvelop(bad_env) + Salmon::MagicEnvelope.unenvelop(envelope_root) }.to raise_error Salmon::InvalidEnvelope end @@ -245,7 +237,7 @@ module DiasporaFederation expect_callback(:fetch_public_key, sender).and_return(nil) expect { - Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey)) + Salmon::MagicEnvelope.unenvelop(envelope_root) }.to raise_error Salmon::SenderKeyNotFound end end diff --git a/spec/lib/diaspora_federation/salmon/slap_spec.rb b/spec/lib/diaspora_federation/salmon/slap_spec.rb index 5143e70..efabbf1 100644 --- a/spec/lib/diaspora_federation/salmon/slap_spec.rb +++ b/spec/lib/diaspora_federation/salmon/slap_spec.rb @@ -3,49 +3,15 @@ module DiasporaFederation let(:sender) { "test_user@pod.somedomain.tld" } let(:privkey) { OpenSSL::PKey::RSA.generate(512) } # use small key for speedy specs let(:payload) { Entities::TestEntity.new(test: "qwertzuiop") } - let(:slap_xml) { Salmon::Slap.generate_xml(sender, privkey, payload) } + let(:slap_xml) { + Salmon::Slap.build_xml do |xml| + xml.header { + xml.author_id(sender) + } - describe ".generate_xml" do - context "sanity" do - it "accepts correct params" do - expect { - Salmon::Slap.generate_xml(sender, privkey, payload) - }.not_to raise_error - end - - it "raises an error when the sender is the wrong type" do - [1234, true, :symbol, payload, privkey].each do |val| - expect { - Salmon::Slap.generate_xml(val, privkey, payload) - }.to raise_error ArgumentError - end - end - - it "raises an error when the privkey is the wrong type" do - ["asdf", 1234, true, :symbol, payload].each do |val| - expect { - Salmon::Slap.generate_xml(sender, val, payload) - }.to raise_error ArgumentError - end - end - - it "raises an error when the payload is the wrong type" do - ["asdf", 1234, true, :symbol, privkey].each do |val| - expect { - Salmon::Slap.generate_xml(sender, privkey, val) - }.to raise_error ArgumentError - end - end + xml.parent << Salmon::MagicEnvelope.new(payload, sender).envelop(privkey).root end - - it "generates valid xml" do - ns = {d: Salmon::XMLNS, me: Salmon::MagicEnvelope::XMLNS} - 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(sender) - expect(doc.xpath("d:diaspora/me:env", ns)).to have(1).item - end - end + } describe ".from_xml" do context "sanity" do