commit more often

This commit is contained in:
Raphael 2010-07-15 13:29:21 -07:00
parent fd18ac6c4b
commit 2d5d3a2f2d
11 changed files with 174 additions and 71 deletions

View file

@ -2,12 +2,13 @@ class Comment
include MongoMapper::Document include MongoMapper::Document
include ROXML include ROXML
include Diaspora::Webhooks include Diaspora::Webhooks
include Encryptable
xml_accessor :text xml_accessor :text
xml_accessor :person, :as => Person xml_accessor :person, :as => Person
xml_accessor :post_id xml_accessor :post_id
key :text, String key :text, String
timestamps! timestamps!
@ -25,10 +26,42 @@ class Comment
(self.message == other.message) && (self.person.email == other.person.email) (self.message == other.message) && (self.person.email == other.person.email)
end end
#ENCRYPTION
before_validation :sign_if_mine, :sign_if_my_post
validates_true_for :creator_signature, :logic => lambda {self.verify_creator_signature}
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 protected
def sign_if_my_post
def send_people_comments_on_my_posts 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) if User.owner.mine?(self.post) && !(self.person.is_a? User)
self.push_to(self.post.people_with_permissions) self.push_to(self.post.people_with_permissions)
end end

View file

@ -4,9 +4,9 @@ class Post
include MongoMapper::Document include MongoMapper::Document
include ROXML include ROXML
include Diaspora::Webhooks include Diaspora::Webhooks
include Encryptable
xml_accessor :_id xml_accessor :_id
xml_accessor :owner_signature
xml_accessor :person, :as => Person xml_accessor :person, :as => Person
key :person_id, ObjectId key :person_id, ObjectId
@ -44,45 +44,27 @@ class Post
end end
#ENCRYPTION #ENCRYPTION
before_validation :sign_if_mine before_validation :sign_if_mine
validates_true_for :owner_signature, :logic => lambda {self.verify_signature} validates_true_for :creator_signature, :logic => lambda {self.verify_creator_signature}
key :owner_signature, String xml_accessor :creator_signature
key :creator_signature, String
def signable_accessors
accessors = self.class.roxml_attrs.collect{|definition| def signable_accessors
definition.accessor} accessors = self.class.roxml_attrs.collect{|definition|
accessors.delete 'person' definition.accessor}
accessors.delete 'owner_signature' accessors.delete 'person'
accessors accessors.delete 'creator_signature'
end accessors
def signable_string
signable_accessors.collect{|accessor|
(self.send accessor.to_sym).to_s}.join ';'
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})
end end
end
def destroy_comments def signable_string
signable_accessors.collect{|accessor|
(self.send accessor.to_sym).to_s}.join ';'
end
protected
def destroy_comments
comments.each{|c| c.destroy} comments.each{|c| c.destroy}
end end

6
db/seeds/request.rb Normal file
View file

@ -0,0 +1,6 @@
require 'config/environment'
Request.all.each{|r|
User.owner.accept_friend_request(r.id)
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

33
lib/encryptable.rb Normal file
View file

@ -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

View file

@ -4,7 +4,7 @@ describe PublicsController do
render_views render_views
before do 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) request.env['warden'] = mock_model(Warden, :authenticate? => @user, :authenticate! => @user, :authenticate => @user)
end end

View file

@ -65,6 +65,7 @@ describe Person do
Person.friends.all.count.should == 1 Person.friends.all.count.should == 1
u.unfriend(f.id) u.unfriend(f.id)
Person.friends.all.count.should == 0 Person.friends.all.count.should == 0
Person.all.count.should == 1
end end
end end

View file

@ -42,10 +42,11 @@ end
end end
def stub_signature_verification def stub_signature_verification
Post.any_instance.stubs(:verify_signature).returns(true) Post.any_instance.stubs(:verify_creator_signature).returns(true)
StatusMessage.any_instance.stubs(:verify_signature).returns(true) StatusMessage.any_instance.stubs(:verify_creator_signature).returns(true)
Blog.any_instance.stubs(:verify_signature).returns(true) Blog.any_instance.stubs(:verify_creator_signature).returns(true)
Bookmark.any_instance.stubs(:verify_signature).returns(true) Bookmark.any_instance.stubs(:verify_creator_signature).returns(true)
Comment.any_instance.stubs(:verify_creator_signature).returns(true)
end end
def unstub_mocha_stubs def unstub_mocha_stubs

View file

@ -10,17 +10,21 @@ describe 'user encryption' do
end end
before do before do
unstub_mocha_stubs unstub_mocha_stubs
@u = Factory.create(:user) @user = Factory.create(:user)
@u.send(:assign_key) @user.send(:assign_key)
@u.save @user.save
@person = Factory.create(:person, @person = Factory.create(:person,
:key_fingerprint => GPGME.list_keys("Remote Friend").first.subkeys.first.fpr, :key_fingerprint => GPGME.list_keys("Remote Friend").first.subkeys.first.fpr,
:profile => Profile.new(:first_name => 'Remote', :profile => Profile.new(:first_name => 'Remote',
:last_name => 'Friend'), :last_name => 'Friend'),
:email => 'somewhere@else.com', :email => 'somewhere@else.com',
:url => 'http://distant-example.com/', :url => 'http://distant-example.com/')
:key_fingerprint => '57F553EE2C230991566B7C60D3638485F3960087') @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 end
after do after do
@ -44,18 +48,18 @@ describe 'user encryption' do
end end
it 'should have a key fingerprint' do it 'should have a key fingerprint' do
@u.key_fingerprint.should_not be nil @user.key_fingerprint.should_not be nil
end end
it 'should retrieve a user key' do 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 end
describe 'key exchange on friending' do describe 'key exchange on friending' do
it 'should send over a public key' do it 'should send over a public key' do
Comment.send(:class_variable_get, :@@queue).stub!(:add_post_request) Comment.send(:class_variable_get, :@@queue).stub!(:add_post_request)
request = @u.send_friend_request_to("http://example.com/") request = @user.send_friend_request_to("http://example.com/")
Request.build_xml_for([request]).include?( @u.export_key).should be true Request.build_xml_for([request]).include?( @user.export_key).should be true
end end
it 'should receive and marshal a public key from a request' do 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] xml = Request.build_xml_for [request]
person.destroy person.destroy
personcount = Person.all.count
store_objects_from_xml(xml) 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 = Person.first(:url => "http://test.url/")
new_person.key_fingerprint.nil?.should == false new_person.key_fingerprint.nil?.should == false
new_person.id.should == id new_person.id.should == id
@ -83,54 +88,54 @@ describe 'user encryption' do
describe 'signing and verifying' do describe 'signing and verifying' do
it 'should sign a message on create' do it 'should sign a message on create' do
message = Factory.create(:status_message, :person => @u) message = Factory.create(:status_message, :person => @user)
message.verify_signature.should be true message.verify_creator_signature.should be true
end end
it 'should not be able to verify a message from a person without a key' do it 'should not be able to verify a message from a person without a key' do
person = Factory.create(:person, :key_fingerprint => "123") person = Factory.create(:person, :key_fingerprint => "123")
message = Factory.build(:status_message, :person => person) message = Factory.build(:status_message, :person => person)
message.save(:validate => false) message.save(:validate => false)
message.verify_signature.should be false message.verify_creator_signature.should be false
end end
it 'should verify a remote signature' do it 'should verify a remote signature' do
message = Factory.build(:status_message, :person => @person) 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]}) {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@person.key]})
message.save(:validate => false) message.save(:validate => false)
message.verify_signature.should be true message.verify_creator_signature.should be true
end end
it 'should know if the signature is from the wrong person' do it 'should know if the signature is from the wrong person' do
message = Factory.build(:status_message, :person => @person) message = Factory.build(:status_message, :person => @person)
message.save(:validate => false) 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]}) {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@person.key]})
message.person = @u message.person = @user
message.verify_signature.should be false message.verify_creator_signature.should be false
end end
it 'should know if the signature is for the wrong text' do it 'should know if the signature is for the wrong text' do
message = Factory.build(:status_message, :person => @person) 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]}) {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@person.key]})
message.message = 'I love VENISON' message.message = 'I love VENISON'
message.save(:validate => false) message.save(:validate => false)
message.verify_signature.should be false message.verify_creator_signature.should be false
end end
end end
describe 'sending and recieving signatures' do describe 'sending and recieving signatures' do
it 'should contain the signature in the xml' 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 = message.to_xml.to_s
xml.include?(message.owner_signature).should be true xml.include?(message.creator_signature).should be true
end 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 = 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 => [@u.key]}) {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@user.key]})
message.save message.save
xml = Post.build_xml_for([message]) xml = Post.build_xml_for([message])
message.destroy message.destroy
@ -140,4 +145,46 @@ describe 'user encryption' do
end end
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 end