Merge branch 'salmon-refactor'

This commit is contained in:
Raphael 2010-10-05 09:47:10 -07:00
commit bb88a6fb8c
11 changed files with 176 additions and 95 deletions

View file

@ -166,26 +166,28 @@ class User
aspect.save
target_people = target_people | aspect.people
}
push_to_people(post, target_people)
end
def push_to_people(post, people)
salmon = salmon(post)
people.each{|person|
salmon(post, :to => person)
xml = salmon.xml_for person
push_to_person( person, xml)
}
end
def push_to_person( person, xml )
Rails.logger.debug("Adding xml for #{self} to message queue to #{url}")
QUEUE.add_post_request( person.receive_url, person.encrypt(xml) )
QUEUE.add_post_request( person.receive_url, xml )
QUEUE.process
end
def salmon( post, opts = {} )
salmon = Salmon::SalmonSlap.create(self, post.to_diaspora_xml)
push_to_person( opts[:to], salmon.to_xml)
salmon
def salmon( post )
created_salmon = Salmon::SalmonSlap.create(self, post.to_diaspora_xml)
created_salmon
end
######## Commenting ########
@ -217,7 +219,7 @@ class User
push_to_people comment, people_in_aspects(aspects_with_post(comment.post.id))
elsif owns? comment
comment.save
salmon comment, :to => comment.post.person
push_to_people comment, [comment.post.person]
end
end

View file

@ -6,7 +6,7 @@ cross_server:
deploy_to: '/usr/local/app/diaspora'
user: 'root'
repo: 'git://github.com/diaspora/diaspora.git'
branch: 'master'
branch: 'salmon_refactor'
default_env: 'development'
servers:
tom:

View file

@ -22,7 +22,7 @@ module Diaspora
aspect.requests << request
aspect.save
salmon request, :to => desired_friend
push_to_people request, [desired_friend]
end
request
end
@ -80,7 +80,7 @@ module Diaspora
def unfriend(bad_friend)
Rails.logger.info("#{self.real_name} is unfriending #{bad_friend.inspect}")
retraction = Retraction.for(self)
salmon( retraction, :to => bad_friend)
push_to_people retraction, [bad_friend]
remove_friend(bad_friend)
end

View file

@ -1,12 +1,11 @@
module Diaspora
module UserModules
module Receiving
def receive_salmon ciphertext
cleartext = decrypt( ciphertext)
salmon = Salmon::SalmonSlap.parse cleartext
def receive_salmon salmon_xml
salmon = Salmon::SalmonSlap.parse salmon_xml, self
if salmon.verified_for_key?(salmon.author.public_key)
Rails.logger.info("data in salmon: #{salmon.data}")
self.receive(salmon.data)
Rails.logger.info("data in salmon: #{salmon.parsed_data}")
self.receive(salmon.parsed_data)
end
end

View file

@ -41,16 +41,37 @@ end
module Salmon
class SalmonSlap
attr_accessor :magic_sig, :author, :author_email, :data, :data_type, :sig
def self.parse(xml)
attr_accessor :magic_sig, :author, :author_email, :aes_key, :iv, :parsed_data,
:data_type, :sig
def self.create(user, activity)
salmon = self.new
salmon.author = user.person
aes_key_hash = user.person.gen_aes_key
salmon.aes_key = aes_key_hash['key']
salmon.iv = aes_key_hash['iv']
salmon.magic_sig = MagicSigEnvelope.create(user , user.person.aes_encrypt(activity, aes_key_hash))
salmon
end
def self.parse(xml, user)
slap = self.new
doc = Nokogiri::XML(xml)
sig_doc = doc.search('entry')
### Header ##
decrypted_header = user.decrypt(doc.search('encrypted_header').text)
header_doc = Nokogiri::XML(decrypted_header)
slap.aes_key = header_doc.search('aes_key').text
slap.iv = header_doc.search('iv').text
slap.magic_sig = MagicSigEnvelope.parse sig_doc
if 'base64url' == slap.magic_sig.encoding
slap.data = decode64url(slap.magic_sig.data)
key_hash = {'key' => slap.aes_key, 'iv' => slap.iv}
slap.parsed_data = user.aes_decrypt(decode64url(slap.magic_sig.data), key_hash)
slap.sig = slap.magic_sig.sig
else
raise ArgumentError, "Magic Signature data must be encoded with base64url, was #{slap.magic_sig.encoding}"
@ -65,17 +86,11 @@ module Salmon
slap
end
def self.create(user, activity)
salmon = self.new
salmon.author = user.person
salmon.magic_sig = MagicSigEnvelope.create(user , activity)
salmon
end
def to_xml
def xml_for person
xml =<<ENTRY
<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns='http://www.w3.org/2005/Atom'>
<encrypted_header>#{person.encrypt(decrypted_header)}</encrypted_header>
<author>
<name>#{@author.real_name}</name>
<uri>acct:#{@author.diaspora_handle}</uri>
@ -86,6 +101,19 @@ ENTRY
end
def decrypted_header
header =<<HEADER
<decrypted_header>
<iv>#{iv}</iv>
<aes_key>#{aes_key}</aes_key>
<author>
<name>#{@author.real_name}</name>
<uri>acct:#{@author.diaspora_handle}</uri>
</author>
</decrypted_header>
HEADER
end
def author
if @author
@author

View file

@ -65,4 +65,17 @@ namespace :db do
}
puts "everything should be peachy"
end
task :move_private_key do
User.all.each do |user|
if user.private_key.nil?
user.private_key = user.person.serialized_key
user.save
person = user.person
person.serialized_key = nil
person.serialized_public_key = user.encryption_key.public_key
person.save
end
end
end
end

View file

@ -19,7 +19,6 @@ namespace :generate do
Rails.application.config.secret_token = '#{secret}'
EOF
puts "YAY!!"
end
end

View file

@ -6,30 +6,31 @@ require 'spec_helper'
describe PublicsController do
render_views
let(:user) {Factory.create :user}
let(:user2){Factory.create :user}
before do
@user = Factory.create(:user)
sign_in :user, @user
sign_in :user, user
end
describe 'receive endpoint' do
it 'should have a and endpoint and return a 200 on successful receipt of a request' do
post :receive, :id =>@user.person.id
post :receive, :id =>user.person.id
response.code.should == '200'
end
it 'should accept a post from another node and save the information' do
user2 = Factory.create(:user)
message = user2.build_post(:status_message, :message => "hi")
@user.reload
@user.visible_post_ids.include?(message.id).should be false
xml = @user.person.encrypt(user2.salmon(message, :to => @user.person).to_xml)
user.reload
user.visible_post_ids.include?(message.id).should be false
post :receive, :id => @user.person.id, :xml => xml
xml = user2.salmon(message).xml_for(user.person)
@user.reload
@user.visible_post_ids.include?(message.id).should be true
post :receive, :id => user.person.id, :xml => xml
user.reload
user.visible_post_ids.include?(message.id).should be true
end
end
@ -41,35 +42,29 @@ describe PublicsController do
end
describe 'friend requests' do
let(:aspect2) {user2.aspect(:name => 'disciples')}
let!(:req) {user2.send_friend_request_to(user.person, aspect2)}
let!(:xml) {user2.salmon(req).xml_for(user.person)}
before do
@user2 = Factory.create(:user)
aspect = @user2.aspect(:name => 'disciples')
@user3 = Factory.create(:user)
req = @user2.send_friend_request_to(@user.person, aspect)
@xml = @user.person.encrypt(@user2.salmon(req, :to => @user.person).to_xml)
req.delete
@user2.reload
@user2.pending_requests.count.should be 1
user2.reload
user2.pending_requests.count.should be 1
end
it 'should add the pending request to the right user if the target person exists locally' do
@user2.delete
post :receive, :id => @user.person.id, :xml => @xml
user2.delete
post :receive, :id => user.person.id, :xml => xml
assigns(:user).should eq(@user)
assigns(:user).should eq(user)
end
it 'should add the pending request to the right user if the target person does not exist locally' do
Person.should_receive(:by_webfinger).with(@user2.person.diaspora_handle).and_return(@user2.person)
@user2.person.delete
@user2.delete
post :receive, :id => @user.person.id, :xml => @xml
Person.should_receive(:by_webfinger).with(user2.person.diaspora_handle).and_return(user2.person)
user2.person.delete
user2.delete
post :receive, :id => user.person.id, :xml => xml
assigns(:user).should eq(@user)
assigns(:user).should eq(user)
end
end
end

View file

@ -5,52 +5,97 @@
require 'spec_helper'
describe Salmon do
before do
let(:user){Factory.create :user}
let(:user2) {Factory.create :user}
let(:user3) {Factory.create :user}
let(:post){ user.post :status_message, :message => "hi", :to => user.aspect(:name => "sdg").id }
@user = Factory.create :user
@post = @user.post :status_message, :message => "hi", :to => @user.aspect(:name => "sdg").id
@sent_salmon = Salmon::SalmonSlap.create(@user, @post.to_diaspora_xml)
@parsed_salmon = Salmon::SalmonSlap.parse @sent_salmon.to_xml
let!(:created_salmon) {Salmon::SalmonSlap.create(user, post.to_diaspora_xml)}
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
it 'sets aes and iv key' do
created_salmon.aes_key.should_not be nil
created_salmon.iv.should_not be nil
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::SalmonSlap.decode64url(created_salmon.magic_sig.data)
user.aes_decrypt(decoded_string, key_hash).should == post.to_diaspora_xml
end
end
describe '#xml_for' do
let(:xml) {created_salmon.xml_for user2.person}
it 'has a encrypted header field' do
xml.include?("encrypted_header").should be true
end
it 'the encrypted_header field should contain the aes key' do
doc = Nokogiri::XML(xml)
decrypted_header = user2.decrypt(doc.search('encrypted_header').text)
decrypted_header.include?(created_salmon.aes_key).should be true
end
end
context 'marshaling' do
let(:xml) {created_salmon.xml_for user2.person}
let(:parsed_salmon) { Salmon::SalmonSlap.parse(xml, user2)}
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 == user.person.diaspora_handle
end
describe '#author' do
before do
stub_success("tom@tom.joindiaspora.com")
end
it 'should verify the signature on a roundtrip' do
@sent_salmon.magic_sig.data.should == @parsed_salmon.magic_sig.data
@sent_salmon.magic_sig.sig.should == @parsed_salmon.magic_sig.sig
@sent_salmon.magic_sig.signable_string.should == @parsed_salmon.magic_sig.signable_string
@parsed_salmon.verified_for_key?(OpenSSL::PKey::RSA.new(@user.exported_key)).should be true
@sent_salmon.verified_for_key?(OpenSSL::PKey::RSA.new(@user.exported_key)).should be true
end
it 'should return the data so it can be "received"' do
xml = @post.to_diaspora_xml
@parsed_salmon.data.should == xml
end
it 'should parse out the authors diaspora_handle' do
@parsed_salmon.author_email.should == @user.person.diaspora_handle
end
it 'should reference a local author' do
@parsed_salmon.author.should == @user.person
parsed_salmon.author.should == user.person
end
it 'should reference a remote author' do
@parsed_salmon.author_email = 'tom@tom.joindiaspora.com'
@parsed_salmon.author.public_key.should_not be_nil
parsed_salmon.author_email = 'tom@tom.joindiaspora.com'
parsed_salmon.author.public_key.should_not be_nil
end
it 'should fail to reference a nonexistent remote author' do
@parsed_salmon.author_email = 'idsfug@difgubhpsduh.rgd'
parsed_salmon.author_email = 'idsfug@difgubhpsduh.rgd'
proc {
Redfinger.stub(:finger).and_return(nil) #Redfinger returns nil when there is no profile
@parsed_salmon.author.real_name}.should raise_error /No webfinger profile found/
parsed_salmon.author.real_name}.should raise_error /No webfinger profile found/
end
end
it 'verifies the signature for the sender' do
parsed_salmon.verified_for_key?(user.public_key).should be true
end
it 'contains the original data' do
parsed_salmon.parsed_data.should == post.to_diaspora_xml
end
end
end

View file

@ -71,19 +71,19 @@ describe User do
describe '#push_to_aspects' do
it 'should push a post to a aspect' do
user.should_receive(:salmon).twice
user.should_receive(:push_to_person).twice
user.push_to_aspects(post, aspect.id)
end
it 'should push a post to all aspects' do
user.should_receive(:salmon).exactly(3).times
user.should_receive(:push_to_person).exactly(3).times
user.push_to_aspects(post, :all)
end
end
describe '#push_to_people' do
it 'should push to people' do
user.should_receive(:salmon).twice
user.should_receive(:push_to_person).twice
user.push_to_people(post, [user2.person, user3.person])
end
end

View file

@ -173,11 +173,11 @@ describe User do
describe 'salmon' do
before do
@post = @user.post :status_message, :message => "hello", :to => @aspect.id
@salmon = @user.salmon( @post, :to => @user2.person )
@salmon = @user.salmon( @post )
end
it 'should receive a salmon for a post' do
@user2.receive_salmon( @user2.person.encrypt(@salmon.to_xml) )
@user2.receive_salmon( @salmon.xml_for @user2.person )
@user2.visible_post_ids.include?(@post.id).should be true
end
end