From 87c994fa473dd6610c2c50178e00cfc918c197a2 Mon Sep 17 00:00:00 2001 From: Maxwell Salzberg Date: Fri, 9 Sep 2011 13:28:48 -0700 Subject: [PATCH] MS DG cleaned up and fleshed out salmon specs --- app/models/job/http_multi.rb | 2 +- app/models/user.rb | 2 +- lib/salmon/magic_sig_envelope.rb | 3 +- lib/salmon/slap.rb | 22 +++---- spec/lib/salmon/encrypted_slap_spec.rb | 86 ++++++++------------------ spec/lib/salmon/slap_spec.rb | 53 +++++++++++++++- spec/models/jobs/http_multi_spec.rb | 4 +- 7 files changed, 93 insertions(+), 79 deletions(-) diff --git a/app/models/job/http_multi.rb b/app/models/job/http_multi.rb index 3b7b749da..62b763952 100644 --- a/app/models/job/http_multi.rb +++ b/app/models/job/http_multi.rb @@ -19,7 +19,7 @@ module Job people = Person.where(:id => person_ids) - salmon = Salmon::EncryptedSlap.create(user, Base64.decode64(enc_object_xml)) + salmon = Salmon::EncryptedSlap.create_by_user_and_activity(user, Base64.decode64(enc_object_xml)) failed_request_people = [] diff --git a/app/models/user.rb b/app/models/user.rb index fb7342248..3fc69e017 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -215,7 +215,7 @@ class User < ActiveRecord::Base end def salmon(post) - Salmon::EncryptedSlap.create(self, post.to_diaspora_xml) + Salmon::EncryptedSlap.create_by_user_and_activity(self, post.to_diaspora_xml) end def build_relayable(model, options = {}) diff --git a/lib/salmon/magic_sig_envelope.rb b/lib/salmon/magic_sig_envelope.rb index c60802ddc..ae93bdc39 100644 --- a/lib/salmon/magic_sig_envelope.rb +++ b/lib/salmon/magic_sig_envelope.rb @@ -6,12 +6,13 @@ module Salmon class MagicSigEnvelope attr_accessor :data, :data_type, :encoding, :alg, :sig, :author def self.parse(doc) + puts doc.to_s env = self.new ns = {'me'=>'http://salmon-protocol.org/ns/magic-env'} env.encoding = doc.search('//me:env/me:encoding', ns).text.strip if env.encoding != 'base64url' - raise ArgumentError, "Magic Signature data must be encoded with base64url, was #{slap.magic_sig.encoding}" + raise ArgumentError, "Magic Signature data must be encoded with base64url, was #{env.encoding}" end env.data = doc.search('//me:env/me:data', ns).text diff --git a/lib/salmon/slap.rb b/lib/salmon/slap.rb index ad3f7b285..1e98c839d 100644 --- a/lib/salmon/slap.rb +++ b/lib/salmon/slap.rb @@ -7,7 +7,9 @@ module Salmon attr_accessor :magic_sig, :author, :author_email, :parsed_data attr_accessor :aes_key, :iv - def self.create(user, activity) + delegate :sig, :data_type, :to => :magic_sig + + def self.create_by_user_and_activity(user, activity) salmon = self.new salmon.author = user.person aes_key_hash = user.person.gen_aes_key @@ -20,34 +22,30 @@ module Salmon salmon end - def self.parse(xml, user=nil) + def self.from_xml(xml, receiving_user=nil) slap = self.new doc = Nokogiri::XML(xml) + entry_doc = doc.search('entry') + ### Header ## - header_doc = slap.salmon_header(doc, user) + header_doc = slap.salmon_header(doc, receiving_user) slap.author_email= header_doc.search('uri').text.split("acct:").last + slap.aes_key = header_doc.search('aes_key').text slap.iv = header_doc.search('iv').text - slap.magic_sig = MagicSigEnvelope.parse(doc.search('entry')) + slap.magic_sig = MagicSigEnvelope.parse(entry_doc) #should be in encrypted salmon only key_hash = {'key' => slap.aes_key, 'iv' => slap.iv} - slap.parsed_data = slap.parse_data(key_hash, user) + slap.parsed_data = slap.parse_data(key_hash, receiving_user) slap end - def sig - self.magic_sig.sig - end - - def data_type - self.magic_sig.data_type - end # @return [String] def self.payload(activity, user=nil, aes_key_hash=nil) diff --git a/spec/lib/salmon/encrypted_slap_spec.rb b/spec/lib/salmon/encrypted_slap_spec.rb index 99aac03b4..4f6ea88bd 100644 --- a/spec/lib/salmon/encrypted_slap_spec.rb +++ b/spec/lib/salmon/encrypted_slap_spec.rb @@ -5,34 +5,43 @@ require 'spec_helper' describe Salmon::EncryptedSlap do - let(:post){ alice.post :status_message, :text => "hi", :to => alice.aspects.create(:name => "sdg").id } - - let!(:created_salmon) {Salmon::EncryptedSlap.create(alice, post.to_diaspora_xml)} + before do + @post = alice.post(:status_message, :text => "hi", :to => alice.aspects.create(:name => "abcd").id) + @created_salmon = Salmon::EncryptedSlap.create_by_user_and_activity(alice, @post.to_diaspora_xml) + end describe '#create' do - - it 'has data in the magic envelope' do - created_salmon.magic_sig.data.should_not be nil - end - - it 'has no parsed_data' do - created_salmon.parsed_data.should be nil + it 'makes the data in the signature encrypted with that key' do + key_hash = {'key' => @created_salmon.aes_key, 'iv' => @created_salmon.iv} + decoded_string = Salmon::EncryptedSlap.decode64url(@created_salmon.magic_sig.data) + alice.aes_decrypt(decoded_string, key_hash).should == @post.to_diaspora_xml end it 'sets aes and iv key' do - created_salmon.aes_key.should_not be nil - created_salmon.iv.should_not be nil + @created_salmon.aes_key.should_not be_nil + @created_salmon.iv.should_not be_nil + end + end + + context 'marshalling' do + let(:xml) {@created_salmon.xml_for(eve.person)} + let(:parsed_salmon) { Salmon::EncryptedSlap.from_xml(xml, alice)} + + it 'should parse out the aes key' do + parsed_salmon.aes_key.should == @created_salmon.aes_key end - it 'makes the data in the signature encrypted with that key' do - key_hash = {'key' => created_salmon.aes_key, 'iv' => created_salmon.iv} - decoded_string = Salmon::EncryptedSlap.decode64url(created_salmon.magic_sig.data) - alice.aes_decrypt(decoded_string, key_hash).should == post.to_diaspora_xml + it 'should parse out the iv' do + parsed_salmon.iv.should == @created_salmon.iv + end + + it 'contains the original data' do + parsed_salmon.parsed_data.should == @post.to_diaspora_xml end end describe '#xml_for' do - let(:xml) {created_salmon.xml_for eve.person} + let(:xml) {@created_salmon.xml_for eve.person} it 'has a encrypted header field' do xml.include?("encrypted_header").should be true @@ -41,49 +50,8 @@ describe Salmon::EncryptedSlap do it 'the encrypted_header field should contain the aes key' do doc = Nokogiri::XML(xml) decrypted_header = eve.decrypt(doc.search('encrypted_header').text) - decrypted_header.include?(created_salmon.aes_key).should be true + decrypted_header.include?(@created_salmon.aes_key).should be true end end - - context 'marshaling' do - let(:xml) {created_salmon.xml_for eve.person} - let(:parsed_salmon) { Salmon::EncryptedSlap.parse(xml, eve)} - - it 'should parse out the aes key' do - parsed_salmon.aes_key.should == created_salmon.aes_key - end - - it 'should parse out the iv' do - parsed_salmon.iv.should == created_salmon.iv - end - it 'should parse out the authors diaspora_handle' do - parsed_salmon.author_email.should == alice.person.diaspora_handle - - end - - describe '#author' do - it 'should reference a local author' do - parsed_salmon.author.should == alice.person - end - - it 'should fail if no author is found' do - parsed_salmon.author_email = 'tom@tom.joindiaspora.com' - - - proc {parsed_salmon.author.public_key}.should raise_error "did you remember to async webfinger?" - - end - - end - - it 'verifies the signature for the sender' do - parsed_salmon.verified_for_key?(alice.public_key).should be true - end - - it 'contains the original data' do - parsed_salmon.parsed_data.should == post.to_diaspora_xml - end - - end end diff --git a/spec/lib/salmon/slap_spec.rb b/spec/lib/salmon/slap_spec.rb index 7d1d076dc..c1d6cfa85 100644 --- a/spec/lib/salmon/slap_spec.rb +++ b/spec/lib/salmon/slap_spec.rb @@ -1,16 +1,63 @@ require 'spec_helper' describe Salmon::Slap do - before do @post = alice.post(:status_message, :text => "hi", :to => alice.aspects.create(:name => "abcd").id) - @created_salmon = Salmon::Slap.create(alice, @post.to_diaspora_xml) + @created_salmon = Salmon::Slap.create_by_user_and_activity(alice, @post.to_diaspora_xml) + end + + describe '#create' do + it 'has data in the magic envelope' do + @created_salmon.magic_sig.data.should_not be nil + end + + it 'has no parsed_data' do + @created_salmon.parsed_data.should be nil + end + end it 'works' do salmon_string = @created_salmon.xml_for(nil) - salmon = Salmon::Slap.parse(salmon_string) + salmon = Salmon::Slap.from_xml(salmon_string) salmon.author.should == alice.person salmon.parsed_data.should == @post.to_diaspora_xml end + + describe '#author' do + let(:xml) {@created_salmon.xml_for(eve.person)} + let(:parsed_salmon) { Salmon::Slap.from_xml(xml, alice)} + + it 'should reference a local author' do + parsed_salmon.author.should == alice.person + end + + it 'should fail if no author is found' do + parsed_salmon.author_email = 'tom@tom.joindiaspora.com' + expect { + parsed_salmon.author.public_key + }.should raise_error "did you remember to async webfinger?" + end + end + + context 'marshaling' do + let(:xml) {@created_salmon.xml_for(eve.person)} + let(:parsed_salmon) { Salmon::Slap.from_xml(xml)} + + it 'should parse out the authors diaspora_handle' do + parsed_salmon.author_email.should == alice.person.diaspora_handle + end + + it 'verifies the signature for the sender' do + parsed_salmon.verified_for_key?(alice.public_key).should be_true + end + + it 'verifies the signature for the sender' do + parsed_salmon.verified_for_key?(Factory(:person).public_key).should be_false + end + + it 'contains the original data' do + parsed_salmon.parsed_data.should == @post.to_diaspora_xml + end + end end diff --git a/spec/models/jobs/http_multi_spec.rb b/spec/models/jobs/http_multi_spec.rb index 941e4b6d2..1233e0b0c 100644 --- a/spec/models/jobs/http_multi_spec.rb +++ b/spec/models/jobs/http_multi_spec.rb @@ -60,8 +60,8 @@ describe Job::HttpMulti do Typhoeus::Hydra.stub!(:new).and_return(@hydra) - salmon = Salmon::EncryptedSlap.create(bob, Base64.decode64(@post_xml)) - Salmon::EncryptedSlap.stub(:create).and_return(salmon) + salmon = Salmon::EncryptedSlap.create_by_user_and_activity(bob, Base64.decode64(@post_xml)) + Salmon::EncryptedSlap.stub(:create_by_user_and_activity).and_return(salmon) salmon.should_receive(:xml_for).and_return("encrypted things") Job::HttpMulti.perform(bob.id, @post_xml, [person.id])