diff --git a/app/models/comment.rb b/app/models/comment.rb index b1cdc493b9cde69ef6411d14a3d395a231171aa2..67918dd96b2903be046a4565d8a07ab122d4a190 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -2,12 +2,13 @@ class Comment include MongoMapper::Document include ROXML include Diaspora::Webhooks - + include Encryptable xml_accessor :text xml_accessor :person, :as => Person xml_accessor :post_id + key :text, String timestamps! @@ -25,10 +26,42 @@ class Comment (self.message == other.message) && (self.person.email == other.person.email) end + #ENCRYPTION - protected + before_validation :sign_if_mine, :sign_if_my_post + validates_true_for :creator_signature, :logic => lambda {self.verify_creator_signature} - def send_people_comments_on_my_posts + xml_accessor :creator_signature + key :creator_signature, String + key :post_creator_signature, String + + def signable_accessors + accessors = self.class.roxml_attrs.collect{|definition| + definition.accessor} + accessors.delete 'person' + accessors.delete 'creator_signature' + accessors.delete 'post_creator_signature' + accessors + end + + def signable_string + signable_accessors.collect{|accessor| + (self.send accessor.to_sym).to_s}.join ';' + end + + def verify_post_creator_signature + verify_signature(post_creator_signature, post.person) + end + + + protected + def sign_if_my_post + if self.post.person == User.owner + self.post_creator_signature = sign + end + end + + def send_people_comments_on_my_posts if User.owner.mine?(self.post) && !(self.person.is_a? User) self.push_to(self.post.people_with_permissions) end diff --git a/app/models/post.rb b/app/models/post.rb index a4d710f191650d5d63ce5a1e247f5d778c5965e8..9b711d6ce79e18a2101057f3ef7abb5e66e3e1a9 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -4,9 +4,9 @@ class Post include MongoMapper::Document include ROXML include Diaspora::Webhooks + include Encryptable xml_accessor :_id - xml_accessor :owner_signature xml_accessor :person, :as => Person key :person_id, ObjectId @@ -44,45 +44,27 @@ class Post end #ENCRYPTION - before_validation :sign_if_mine - validates_true_for :owner_signature, :logic => lambda {self.verify_signature} - - key :owner_signature, String - - def signable_accessors - accessors = self.class.roxml_attrs.collect{|definition| - definition.accessor} - accessors.delete 'person' - accessors.delete 'owner_signature' - accessors - end - - def signable_string - signable_accessors.collect{|accessor| - (self.send accessor.to_sym).to_s}.join ';' - end + validates_true_for :creator_signature, :logic => lambda {self.verify_creator_signature} + + xml_accessor :creator_signature + key :creator_signature, String + + def signable_accessors + accessors = self.class.roxml_attrs.collect{|definition| + definition.accessor} + accessors.delete 'person' + accessors.delete 'creator_signature' + accessors + end - def verify_signature - return false unless owner_signature && person.key_fingerprint - validity = nil - GPGME::verify(owner_signature, signable_string, - {:armor => true, :always_trust => true}){ |signature| - validity = signature.status == GPGME::GPG_ERR_NO_ERROR && - signature.fpr == person.key_fingerprint - } - return validity - end - - protected - def sign_if_mine - if self.person == User.owner - self.owner_signature = GPGME::sign(signable_string,nil, - {:armor=> true, :mode => GPGME::SIG_MODE_DETACH}) + def signable_string + signable_accessors.collect{|accessor| + (self.send accessor.to_sym).to_s}.join ';' end - end - def destroy_comments +protected + def destroy_comments comments.each{|c| c.destroy} end diff --git a/db/seeds/request.rb b/db/seeds/request.rb new file mode 100644 index 0000000000000000000000000000000000000000..b0c652ca859ad586c2fbfee33dca6175d26a6d2d --- /dev/null +++ b/db/seeds/request.rb @@ -0,0 +1,6 @@ + +require 'config/environment' + +Request.all.each{|r| + User.owner.accept_friend_request(r.id) +} diff --git a/gpg/diaspora-test/pubring.gpg b/gpg/diaspora-test/pubring.gpg index 46e8a37d1e84b145278442b92bfe4314e1562434..6949770abe15219a8dcf14b912cd2644bb33bfae 100644 Binary files a/gpg/diaspora-test/pubring.gpg and b/gpg/diaspora-test/pubring.gpg differ diff --git a/gpg/diaspora-test/secring.gpg b/gpg/diaspora-test/secring.gpg index 81164ee0e2175f201621b3d36808fc614a4e2428..9f945d3f1e68aac39851a98abd25127a806880bd 100644 Binary files a/gpg/diaspora-test/secring.gpg and b/gpg/diaspora-test/secring.gpg differ diff --git a/gpg/diaspora-test/trustdb.gpg b/gpg/diaspora-test/trustdb.gpg index 45e0c76adf3c9bab923cb7a571bcdc1d64ff4598..1fec81fc8c39a371e7de456d93e66eb9dd3172ee 100644 Binary files a/gpg/diaspora-test/trustdb.gpg and b/gpg/diaspora-test/trustdb.gpg differ diff --git a/lib/encryptable.rb b/lib/encryptable.rb new file mode 100644 index 0000000000000000000000000000000000000000..10a9ac39c0301c102819a58c1963aa3b948e127d --- /dev/null +++ b/lib/encryptable.rb @@ -0,0 +1,33 @@ + module Encryptable + def signable_string + "" + end + def verify_creator_signature + verify_signature(creator_signature, person) + end + + def verify_signature(signature, person) + return false unless signature && person.key_fingerprint + validity = nil + GPGME::verify(creator_signature, signable_string, + {:armor => true, :always_trust => true}){ |signature| + puts signature + validity = signature.status == GPGME::GPG_ERR_NO_ERROR && + signature.fpr == person.key_fingerprint + } + return validity + end + + protected + def sign_if_mine + if self.person == User.owner + self.creator_signature = sign + end + end + + def sign + GPGME::sign(signable_string,nil, + {:armor=> true, :mode => GPGME::SIG_MODE_DETACH, :signers => [User.owner.key]}) + end + end + diff --git a/spec/controllers/publics_controller_spec.rb b/spec/controllers/publics_controller_spec.rb index e9539b4641fc42b80f5c0c000d8841b71b9974e7..be297a64fa90298a60771a6a477d236778dc1bb4 100644 --- a/spec/controllers/publics_controller_spec.rb +++ b/spec/controllers/publics_controller_spec.rb @@ -4,7 +4,7 @@ describe PublicsController do render_views before do - @user = Factory.create(:user, :profile => Profile.create( :first_name => "bob", :last_name => "smith")) + @user = Factory.create(:user, :profile => Profile.new( :first_name => "bob", :last_name => "smith")) request.env['warden'] = mock_model(Warden, :authenticate? => @user, :authenticate! => @user, :authenticate => @user) end diff --git a/spec/models/person_spec.rb b/spec/models/person_spec.rb index a882b9849f197fa7445b507416a0a5fbf5a6ebd3..72cad89ace18a6975253a2de9705bfe5b42255a1 100644 --- a/spec/models/person_spec.rb +++ b/spec/models/person_spec.rb @@ -65,6 +65,7 @@ describe Person do Person.friends.all.count.should == 1 u.unfriend(f.id) Person.friends.all.count.should == 0 + Person.all.count.should == 1 end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7273c0d282186a730fe9ec60379d58e04b2d53d6..79412d92d40b8ef861cdaa1dcdd0439b7aa0f2ec 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -42,10 +42,11 @@ end end def stub_signature_verification - Post.any_instance.stubs(:verify_signature).returns(true) - StatusMessage.any_instance.stubs(:verify_signature).returns(true) - Blog.any_instance.stubs(:verify_signature).returns(true) - Bookmark.any_instance.stubs(:verify_signature).returns(true) + Post.any_instance.stubs(:verify_creator_signature).returns(true) + StatusMessage.any_instance.stubs(:verify_creator_signature).returns(true) + Blog.any_instance.stubs(:verify_creator_signature).returns(true) + Bookmark.any_instance.stubs(:verify_creator_signature).returns(true) + Comment.any_instance.stubs(:verify_creator_signature).returns(true) end def unstub_mocha_stubs diff --git a/spec/user_encryption_spec.rb b/spec/user_encryption_spec.rb index af4fcfc4e300de52dc9b9c48ea618b9e73841a22..63f4785c9c085937c5c06f008dbc42091981ef8c 100644 --- a/spec/user_encryption_spec.rb +++ b/spec/user_encryption_spec.rb @@ -10,17 +10,21 @@ describe 'user encryption' do end before do unstub_mocha_stubs - @u = Factory.create(:user) - @u.send(:assign_key) - @u.save + @user = Factory.create(:user) + @user.send(:assign_key) + @user.save @person = Factory.create(:person, :key_fingerprint => GPGME.list_keys("Remote Friend").first.subkeys.first.fpr, :profile => Profile.new(:first_name => 'Remote', :last_name => 'Friend'), :email => 'somewhere@else.com', - :url => 'http://distant-example.com/', - :key_fingerprint => '57F553EE2C230991566B7C60D3638485F3960087') - + :url => 'http://distant-example.com/') + @person2 = Factory.create(:person, + :key_fingerprint => GPGME.list_keys("Second Friend").first.subkeys.first.fpr, + :profile => Profile.new(:first_name => 'Second', + :last_name => 'Friend'), + :email => 'elsewhere@else.com', + :url => 'http://distanter-example.com/') end after do @@ -44,18 +48,18 @@ describe 'user encryption' do end it 'should have a key fingerprint' do - @u.key_fingerprint.should_not be nil + @user.key_fingerprint.should_not be nil end it 'should retrieve a user key' do - @u.key.subkeys[0].fpr.should == @u.key_fingerprint + @user.key.subkeys[0].fpr.should == @user.key_fingerprint end describe 'key exchange on friending' do it 'should send over a public key' do Comment.send(:class_variable_get, :@@queue).stub!(:add_post_request) - request = @u.send_friend_request_to("http://example.com/") - Request.build_xml_for([request]).include?( @u.export_key).should be true + request = @user.send_friend_request_to("http://example.com/") + Request.build_xml_for([request]).include?( @user.export_key).should be true end it 'should receive and marshal a public key from a request' do @@ -70,8 +74,9 @@ describe 'user encryption' do xml = Request.build_xml_for [request] person.destroy + personcount = Person.all.count store_objects_from_xml(xml) - Person.all.count.should == 3 + Person.all.count.should == personcount + 1 new_person = Person.first(:url => "http://test.url/") new_person.key_fingerprint.nil?.should == false new_person.id.should == id @@ -83,54 +88,54 @@ describe 'user encryption' do describe 'signing and verifying' do it 'should sign a message on create' do - message = Factory.create(:status_message, :person => @u) - message.verify_signature.should be true + message = Factory.create(:status_message, :person => @user) + message.verify_creator_signature.should be true end it 'should not be able to verify a message from a person without a key' do person = Factory.create(:person, :key_fingerprint => "123") message = Factory.build(:status_message, :person => person) message.save(:validate => false) - message.verify_signature.should be false + message.verify_creator_signature.should be false end it 'should verify a remote signature' do message = Factory.build(:status_message, :person => @person) - message.owner_signature = GPGME.sign(message.signable_string, nil, + message.creator_signature = GPGME.sign(message.signable_string, nil, {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@person.key]}) message.save(:validate => false) - message.verify_signature.should be true + message.verify_creator_signature.should be true end it 'should know if the signature is from the wrong person' do message = Factory.build(:status_message, :person => @person) message.save(:validate => false) - message.owner_signature = GPGME.sign(message.signable_string, nil, + message.creator_signature = GPGME.sign(message.signable_string, nil, {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@person.key]}) - message.person = @u - message.verify_signature.should be false + message.person = @user + message.verify_creator_signature.should be false end it 'should know if the signature is for the wrong text' do message = Factory.build(:status_message, :person => @person) - message.owner_signature = GPGME.sign(message.signable_string, nil, + message.creator_signature = GPGME.sign(message.signable_string, nil, {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@person.key]}) message.message = 'I love VENISON' message.save(:validate => false) - message.verify_signature.should be false + message.verify_creator_signature.should be false end end describe 'sending and recieving signatures' do it 'should contain the signature in the xml' do - message = Factory.create(:status_message, :person => @u) + message = Factory.create(:status_message, :person => @user) xml = message.to_xml.to_s - xml.include?(message.owner_signature).should be true + xml.include?(message.creator_signature).should be true end - it 'the signature should be verified on marshaling' do + it 'A message with an invalid signature should be rejected' do message = Factory.build(:status_message, :person => @person) - message.owner_signature = GPGME.sign(message.signable_string, nil, - {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@u.key]}) + message.creator_signature = GPGME.sign(message.signable_string, nil, + {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@user.key]}) message.save xml = Post.build_xml_for([message]) message.destroy @@ -140,4 +145,46 @@ describe 'user encryption' do end end + describe 'comments' do + before do + @remote_message = Factory.build(:status_message, :person => @person) + @remote_message.creator_signature = GPGME.sign(@remote_message.signable_string, nil, + {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@person.key]}) + @remote_message.save + + end + it 'should attach the creator signature if the user is commenting' do + @user.comment "Yeah, it was great", :on => @remote_message + @remote_message.comments.first.verify_creator_signature.should be true + end + + it 'should sign the comment if the user is the post creator' do + message = Factory.create(:status_message, :person => @user) + @user.comment "Yeah, it was great", :on => message + StatusMessage.first.comments.first.verify_creator_signature.should be true + StatusMessage.first.comments.first.verify_post_creator_signature.should be true + end + + it 'should verify a comment made on a remote post by a different friend' do + comment = Comment.new(:person => @person2, :text => "balls", :post => @remote_message) + comment.creator_signature = GPGME.sign(@remote_message.signable_string, nil, + {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@person2.key]}) + comment.verify_creator_signature.should be true + + end + + it 'should reject comments on a remote post with only a creator sig' do + comment = Comment.new(:person => @person2, :text => "balls", :post => @remote_message) + comment.creator_signature = GPGME.sign(@remote_message.signable_string, nil, + {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@person2.key]}) + comment.verify_creator_signature.should be true + comment.verify_post_creator_signature.should be false + comment.save.should be false + end + + it 'should receive remote comments on a user post with a creator sig' do + + end + + end end