From 4e0c7e205b157f5b07b69e08c4d46aab9b414730 Mon Sep 17 00:00:00 2001 From: Benjamin Neff Date: Sun, 20 Mar 2016 15:51:36 +0100 Subject: [PATCH] create attr_reader for payload entity and sender on magic env instance --- .../diaspora_federation/fetch_controller.rb | 2 +- .../salmon/encrypted_slap.rb | 4 +- .../salmon/magic_envelope.rb | 35 +++++++++---- lib/diaspora_federation/salmon/slap.rb | 2 +- .../federation/fetcher_spec.rb | 2 +- .../encrypted_magic_envelope_receiver_spec.rb | 2 +- .../receiver/magic_envelope_receiver_spec.rb | 2 +- .../federation/receiver_spec.rb | 6 +-- .../salmon/encrypted_magic_envelope_spec.rb | 2 +- .../salmon/magic_envelope_spec.rb | 50 +++++++++---------- 10 files changed, 61 insertions(+), 46 deletions(-) diff --git a/app/controllers/diaspora_federation/fetch_controller.rb b/app/controllers/diaspora_federation/fetch_controller.rb index ae1fc50..95f8d3c 100644 --- a/app/controllers/diaspora_federation/fetch_controller.rb +++ b/app/controllers/diaspora_federation/fetch_controller.rb @@ -30,7 +30,7 @@ module DiasporaFederation def create_magic_envelope(entity) privkey = DiasporaFederation.callbacks.trigger(:fetch_private_key_by_diaspora_id, entity.author) - Salmon::MagicEnvelope.new(entity).envelop(privkey, entity.author) if privkey + Salmon::MagicEnvelope.new(entity, entity.author).envelop(privkey) if privkey end end end diff --git a/lib/diaspora_federation/salmon/encrypted_slap.rb b/lib/diaspora_federation/salmon/encrypted_slap.rb index 0c8e1ff..ce7ca6e 100644 --- a/lib/diaspora_federation/salmon/encrypted_slap.rb +++ b/lib/diaspora_federation/salmon/encrypted_slap.rb @@ -114,9 +114,9 @@ module DiasporaFederation EncryptedSlap.new.tap do |slap| slap.author_id = author_id - magic_envelope = MagicEnvelope.new(entity) + magic_envelope = MagicEnvelope.new(entity, author_id) slap.cipher_params = magic_envelope.encrypt! - slap.magic_envelope_xml = magic_envelope.envelop(privkey, author_id) + slap.magic_envelope_xml = magic_envelope.envelop(privkey) end end diff --git a/lib/diaspora_federation/salmon/magic_envelope.rb b/lib/diaspora_federation/salmon/magic_envelope.rb index 94509cc..8dfcbb5 100644 --- a/lib/diaspora_federation/salmon/magic_envelope.rb +++ b/lib/diaspora_federation/salmon/magic_envelope.rb @@ -36,31 +36,40 @@ module DiasporaFederation # XML namespace url XMLNS = "http://salmon-protocol.org/ns/magic-env".freeze + # the payload entity of the magic envelope + # @return [Entity] payload entity + attr_reader :payload + + # the sender of the magic envelope + # @return [String] diaspora-ID of the sender + attr_reader :sender + # Creates a new instance of MagicEnvelope. # # @param [Entity] payload Entity instance + # @param [String] sender diaspora-ID of the sender # @raise [ArgumentError] if either argument is not of the right type - def initialize(payload) - raise ArgumentError unless payload.is_a?(Entity) + def initialize(payload, sender) + raise ArgumentError unless payload.is_a?(Entity) && sender.is_a?(String) - @payload = XmlPayload.pack(payload).to_xml.strip + @payload = payload + @sender = sender end # Builds the XML structure for the magic envelope, inserts the {ENCODING} # encoded data and signs the envelope using {DIGEST}. # # @param [OpenSSL::PKey::RSA] privkey private key used for signing - # @param [String] sender_id diaspora-ID of the sender # @return [Nokogiri::XML::Element] XML root node - def envelop(privkey, sender_id) - raise ArgumentError unless privkey.instance_of?(OpenSSL::PKey::RSA) && sender_id.is_a?(String) + def envelop(privkey) + raise ArgumentError unless privkey.instance_of?(OpenSSL::PKey::RSA) build_xml {|xml| xml["me"].env("xmlns:me" => XMLNS) { - xml["me"].data(Base64.urlsafe_encode64(@payload), type: DATA_TYPE) + xml["me"].data(Base64.urlsafe_encode64(payload_data), type: DATA_TYPE) xml["me"].encoding(ENCODING) xml["me"].alg(ALGORITHM) - xml["me"].sig(Base64.urlsafe_encode64(sign(privkey)), key_id: Base64.urlsafe_encode64(sender_id)) + xml["me"].sig(Base64.urlsafe_encode64(sign(privkey)), key_id: Base64.urlsafe_encode64(sender)) } } end @@ -77,7 +86,7 @@ module DiasporaFederation # @return [Hash] AES key and iv. E.g.: { key: "...", iv: "..." } def encrypt! AES.generate_key_and_iv.tap do |key| - @payload = AES.encrypt(@payload, key[:key], key[:iv]) + @payload_data = AES.encrypt(payload_data, key[:key], key[:iv]) end end @@ -117,6 +126,12 @@ module DiasporaFederation private + # the payload data as string + # @return [String] payload data + def payload_data + @payload_data ||= XmlPayload.pack(@payload).to_xml.strip + end + # Builds the xml root node of the magic envelope. # # @yield [xml] Invokes the block with the @@ -133,7 +148,7 @@ module DiasporaFederation # @param [OpenSSL::PKey::RSA] privkey private key used for signing # @return [String] the signature def sign(privkey) - subject = MagicEnvelope.send(:sig_subject, [@payload, DATA_TYPE, ENCODING, ALGORITHM]) + subject = MagicEnvelope.send(:sig_subject, [payload_data, DATA_TYPE, ENCODING, ALGORITHM]) privkey.sign(DIGEST, subject) end diff --git a/lib/diaspora_federation/salmon/slap.rb b/lib/diaspora_federation/salmon/slap.rb index 57d4630..f6c0b65 100644 --- a/lib/diaspora_federation/salmon/slap.rb +++ b/lib/diaspora_federation/salmon/slap.rb @@ -92,7 +92,7 @@ module DiasporaFederation xml.author_id(author_id) } - xml.parent << MagicEnvelope.new(entity).envelop(privkey, author_id) + xml.parent << MagicEnvelope.new(entity, author_id).envelop(privkey) end end diff --git a/spec/lib/diaspora_federation/federation/fetcher_spec.rb b/spec/lib/diaspora_federation/federation/fetcher_spec.rb index 1070107..45251f1 100644 --- a/spec/lib/diaspora_federation/federation/fetcher_spec.rb +++ b/spec/lib/diaspora_federation/federation/fetcher_spec.rb @@ -1,7 +1,7 @@ module DiasporaFederation describe Federation::Fetcher do let(:post) { FactoryGirl.build(:status_message_entity, public: true) } - let(:post_magic_env) { Salmon::MagicEnvelope.new(post).envelop(alice.private_key, post.author).to_xml } + let(:post_magic_env) { Salmon::MagicEnvelope.new(post, post.author).envelop(alice.private_key).to_xml } describe ".fetch_public" do it "fetches a public post" do diff --git a/spec/lib/diaspora_federation/federation/receiver/encrypted_magic_envelope_receiver_spec.rb b/spec/lib/diaspora_federation/federation/receiver/encrypted_magic_envelope_receiver_spec.rb index 01fc7fc..817ad61 100644 --- a/spec/lib/diaspora_federation/federation/receiver/encrypted_magic_envelope_receiver_spec.rb +++ b/spec/lib/diaspora_federation/federation/receiver/encrypted_magic_envelope_receiver_spec.rb @@ -4,7 +4,7 @@ module DiasporaFederation let(:sender_key) { OpenSSL::PKey::RSA.generate(1024) } let(:recipient_key) { OpenSSL::PKey::RSA.generate(1024) } let(:entity) { FactoryGirl.build(:status_message_entity, public: false) } - let(:magic_env) { Salmon::MagicEnvelope.new(entity).envelop(sender_key, sender_id) } + let(:magic_env) { Salmon::MagicEnvelope.new(entity, sender_id).envelop(sender_key) } let(:data) { Salmon::EncryptedMagicEnvelope.encrypt(magic_env, recipient_key.public_key) } it "parses the entity if everything is fine" do diff --git a/spec/lib/diaspora_federation/federation/receiver/magic_envelope_receiver_spec.rb b/spec/lib/diaspora_federation/federation/receiver/magic_envelope_receiver_spec.rb index bf98b1f..f72f58d 100644 --- a/spec/lib/diaspora_federation/federation/receiver/magic_envelope_receiver_spec.rb +++ b/spec/lib/diaspora_federation/federation/receiver/magic_envelope_receiver_spec.rb @@ -3,7 +3,7 @@ module DiasporaFederation let(:sender_id) { FactoryGirl.generate(:diaspora_id) } let(:sender_key) { OpenSSL::PKey::RSA.generate(1024) } let(:entity) { FactoryGirl.build(:status_message_entity) } - let(:data) { Salmon::MagicEnvelope.new(entity).envelop(sender_key, sender_id).to_xml } + let(:data) { Salmon::MagicEnvelope.new(entity, sender_id).envelop(sender_key).to_xml } it "parses the entity if everything is fine" do expect(DiasporaFederation.callbacks).to receive(:trigger).with( diff --git a/spec/lib/diaspora_federation/federation/receiver_spec.rb b/spec/lib/diaspora_federation/federation/receiver_spec.rb index 9a999fd..d43993e 100644 --- a/spec/lib/diaspora_federation/federation/receiver_spec.rb +++ b/spec/lib/diaspora_federation/federation/receiver_spec.rb @@ -12,7 +12,7 @@ module DiasporaFederation :fetch_public_key_by_diaspora_id, sender_id ).and_return(sender_key) - data = Salmon::MagicEnvelope.new(post).envelop(sender_key, sender_id).to_xml + data = Salmon::MagicEnvelope.new(post, sender_id).envelop(sender_key).to_xml expect(DiasporaFederation.callbacks).to receive(:trigger).with( :receive_entity, kind_of(Entities::StatusMessage), nil @@ -54,7 +54,7 @@ module DiasporaFederation :fetch_public_key_by_diaspora_id, sender_id ).and_return(sender_key) - magic_env = Salmon::MagicEnvelope.new(post).envelop(sender_key, sender_id) + magic_env = Salmon::MagicEnvelope.new(post, sender_id).envelop(sender_key) data = Salmon::EncryptedMagicEnvelope.encrypt(magic_env, recipient_key.public_key) expect(DiasporaFederation.callbacks).to receive(:trigger).with( @@ -90,7 +90,7 @@ module DiasporaFederation end it "raises when recipient private key is not available" do - magic_env = Salmon::MagicEnvelope.new(post).envelop(sender_key, sender_id) + magic_env = Salmon::MagicEnvelope.new(post, sender_id).envelop(sender_key) data = Salmon::EncryptedMagicEnvelope.encrypt(magic_env, recipient_key.public_key) expect { 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 6c39196..db0963d 100644 --- a/spec/lib/diaspora_federation/salmon/encrypted_magic_envelope_spec.rb +++ b/spec/lib/diaspora_federation/salmon/encrypted_magic_envelope_spec.rb @@ -3,7 +3,7 @@ module DiasporaFederation let(:sender_id) { FactoryGirl.generate(:diaspora_id) } let(:sender_key) { OpenSSL::PKey::RSA.generate(512) } # use small key for speedy specs let(:entity) { Entities::TestEntity.new(test: "abcd") } - let(:magic_env) { Salmon::MagicEnvelope.new(entity).envelop(sender_key, sender_id) } + let(:magic_env) { Salmon::MagicEnvelope.new(entity, sender_id).envelop(sender_key) } let(:privkey) { OpenSSL::PKey::RSA.generate(1024) } # use small key for speedy specs diff --git a/spec/lib/diaspora_federation/salmon/magic_envelope_spec.rb b/spec/lib/diaspora_federation/salmon/magic_envelope_spec.rb index 75484db..c967ce7 100644 --- a/spec/lib/diaspora_federation/salmon/magic_envelope_spec.rb +++ b/spec/lib/diaspora_federation/salmon/magic_envelope_spec.rb @@ -1,9 +1,9 @@ module DiasporaFederation describe Salmon::MagicEnvelope do - let(:sender_id) { FactoryGirl.generate(:diaspora_id) } + let(:sender) { FactoryGirl.generate(:diaspora_id) } let(:privkey) { OpenSSL::PKey::RSA.generate(512) } # use small key for speedy specs let(:payload) { Entities::TestEntity.new(test: "asdf") } - let(:envelope) { Salmon::MagicEnvelope.new(payload) } + let(:envelope) { Salmon::MagicEnvelope.new(payload, sender) } def sig_subj(env) data = Base64.urlsafe_decode64(env.at_xpath("me:data").content) @@ -17,14 +17,14 @@ module DiasporaFederation context "sanity" do it "constructs an instance" do expect { - Salmon::MagicEnvelope.new(payload) + Salmon::MagicEnvelope.new(payload, sender) }.not_to raise_error end it "raises an error if the param types are wrong" do ["asdf", 1234, :test, false].each do |val| expect { - Salmon::MagicEnvelope.new(val) + Salmon::MagicEnvelope.new(val, val) }.to raise_error ArgumentError end end @@ -35,18 +35,18 @@ module DiasporaFederation it "raises an error if the param types are wrong" do ["asdf", 1234, :test, false].each do |val| expect { - envelope.envelop(val, val) + envelope.envelop(val) }.to raise_error ArgumentError end end end it "should be an instance of Nokogiri::XML::Element" do - expect(envelope.envelop(privkey, sender_id)).to be_an_instance_of Nokogiri::XML::Element + expect(envelope.envelop(privkey)).to be_an_instance_of Nokogiri::XML::Element end it "returns a magic envelope of correct structure" do - env_xml = envelope.envelop(privkey, sender_id) + env_xml = envelope.envelop(privkey) expect(env_xml.name).to eq("env") control = %w(data encoding alg sig) @@ -58,20 +58,20 @@ module DiasporaFederation expect(control).to be_empty end - it "adds the sender_id to the signature" do - key_id = envelope.envelop(privkey, sender_id).at_xpath("me:sig")["key_id"] + it "adds the sender to the signature" do + key_id = envelope.envelop(privkey).at_xpath("me:sig")["key_id"] - expect(Base64.urlsafe_decode64(key_id)).to eq(sender_id) + expect(Base64.urlsafe_decode64(key_id)).to eq(sender) end it "adds the data_type" do - data_type = envelope.envelop(privkey, sender_id).at_xpath("me:data")["type"] + data_type = envelope.envelop(privkey).at_xpath("me:data")["type"] expect(data_type).to eq("application/xml") end it "signs the payload correctly" do - env_xml = envelope.envelop(privkey, sender_id) + env_xml = envelope.envelop(privkey) subj = sig_subj(env_xml) sig = Base64.urlsafe_decode64(env_xml.at_xpath("me:sig").content) @@ -87,9 +87,9 @@ module DiasporaFederation end it "actually encrypts the payload" do - plain_payload = envelope.instance_variable_get(:@payload) + plain_payload = envelope.send(:payload_data) params = envelope.encrypt! - encrypted_payload = envelope.instance_variable_get(:@payload) + encrypted_payload = envelope.send(:payload_data) cipher = OpenSSL::Cipher.new(Salmon::AES::CIPHER) cipher.encrypt @@ -111,7 +111,7 @@ module DiasporaFederation it "works with sane input" do expect { - Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey, sender_id), privkey.public_key) + Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey), privkey.public_key) }.not_to raise_error end @@ -132,12 +132,12 @@ module DiasporaFederation it "verifies the signature" do other_key = OpenSSL::PKey::RSA.generate(512) expect { - Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey, sender_id), other_key.public_key) + Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey), other_key.public_key) }.to raise_error Salmon::InvalidSignature end it "verifies the encoding" do - bad_env = envelope.envelop(privkey, sender_id) + bad_env = envelope.envelop(privkey) bad_env.at_xpath("me:encoding").content = "invalid_enc" re_sign(bad_env, privkey) expect { @@ -146,7 +146,7 @@ module DiasporaFederation end it "verifies the algorithm" do - bad_env = envelope.envelop(privkey, sender_id) + bad_env = envelope.envelop(privkey) bad_env.at_xpath("me:alg").content = "invalid_alg" re_sign(bad_env, privkey) expect { @@ -156,7 +156,7 @@ module DiasporaFederation end it "returns the original entity" do - entity = Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey, sender_id), privkey.public_key) + entity = Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey), privkey.public_key) expect(entity).to be_an_instance_of Entities::TestEntity expect(entity.test).to eq("asdf") end @@ -164,7 +164,7 @@ module DiasporaFederation it "decrypts on the fly, when cipher params are present" do params = envelope.encrypt! - env_xml = envelope.envelop(privkey, sender_id) + env_xml = envelope.envelop(privkey) entity = Salmon::MagicEnvelope.unenvelop(env_xml, privkey.public_key, params) expect(entity).to be_an_instance_of Entities::TestEntity @@ -174,16 +174,16 @@ module DiasporaFederation context "use key_id from magic envelope" do it "returns the original entity" do expect(DiasporaFederation.callbacks).to receive(:trigger).with( - :fetch_public_key_by_diaspora_id, sender_id + :fetch_public_key_by_diaspora_id, sender ).and_return(privkey.public_key) - entity = Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey, sender_id)) + entity = Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey)) expect(entity).to be_an_instance_of Entities::TestEntity expect(entity.test).to eq("asdf") end it "raises if the magic envelope has no key_id" do - bad_env = envelope.envelop(privkey, sender_id) + bad_env = envelope.envelop(privkey) bad_env.at_xpath("me:sig").attributes["key_id"].remove @@ -194,11 +194,11 @@ module DiasporaFederation it "raises if the sender key is not found" do expect(DiasporaFederation.callbacks).to receive(:trigger).with( - :fetch_public_key_by_diaspora_id, sender_id + :fetch_public_key_by_diaspora_id, sender ).and_return(nil) expect { - Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey, sender_id)) + Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey)) }.to raise_error Salmon::SenderKeyNotFound end end