updated salmon to let us not always encrypt the header

This commit is contained in:
Maxwell Salzberg 2011-09-08 16:19:50 -07:00
parent 5ae96efdf6
commit 6b0507949c
7 changed files with 73 additions and 115 deletions

View file

@ -4,12 +4,14 @@
class PublicsController < ApplicationController
require File.join(Rails.root, '/lib/diaspora/parser')
require File.join(Rails.root, '/lib/postzord/receiver/public')
include Diaspora::Parser
skip_before_filter :set_header_data
skip_before_filter :which_action_and_user
skip_before_filter :set_grammatical_gender
before_filter :allow_cross_origin, :only => [:hcard, :host_meta, :webfinger]
before_filter :check_for_xml, :only => [:receive, :receive_public]
respond_to :html
respond_to :xml, :only => :post
@ -47,12 +49,12 @@ class PublicsController < ApplicationController
render :text => params['hub.challenge'], :status => 202, :layout => false
end
def receive
if params[:xml].nil?
render :nothing => true, :status => 422
return
end
def receive_public
Postzord::Receiver::Public.new(params[:xml])
render :nothing => true, :status => :ok
end
def receive
person = Person.where(:guid => params[:guid]).first
if person.nil? || person.owner_id.nil?
@ -66,4 +68,15 @@ class PublicsController < ApplicationController
render :nothing => true, :status => 202
end
private
def check_for_xml
if params[:xml].nil?
render :nothing => true, :status => 422
return
end
end
end

View file

@ -102,7 +102,7 @@ class Post < ActiveRecord::Base
return local_post
end
elsif !local_post
if self.save
if self.save
user.contact_for(person).receive_post(self)
user.notify_if_mentioned(self)
Rails.logger.info("event=receive payload_type=#{self.class} update=false status=complete sender=#{self.diaspora_handle}")

View file

@ -122,6 +122,7 @@ Diaspora::Application.routes.draw do
get 'hcard/users/:guid' => :hcard
get '.well-known/host-meta' => :host_meta
post 'receive/users/:guid' => :receive
post 'receive/public' => :receive_public
get 'hub' => :hub
end

View file

@ -83,7 +83,7 @@ ActiveRecord::Schema.define(:version => 20110911213207) do
t.datetime "updated_at"
end
add_index "conversation_visibilities", ["conversation_id", "person_id"], :name => "index_conversation_visibilities_usefully", :unique => true
add_index "conversation_visibilities", ["conversation_id", "person_id"], :name => "index_conversation_visibilities_on_conversation_id_and_person_id", :unique => true
add_index "conversation_visibilities", ["conversation_id"], :name => "index_conversation_visibilities_on_conversation_id"
add_index "conversation_visibilities", ["person_id"], :name => "index_conversation_visibilities_on_person_id"

View file

@ -54,37 +54,47 @@ module Salmon
salmon
end
def self.parse(xml, user)
def self.parse(xml, user=nil)
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)
header_doc = slap.salmon_header(doc, 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 sig_doc
if 'base64url' == slap.magic_sig.encoding
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}"
end
key_hash = {'key' => slap.aes_key, 'iv' => slap.iv}
slap.parsed_data = slap.parse_data(key_hash, user)
slap.sig = slap.magic_sig.sig
slap.data_type = slap.magic_sig.data_type
raise ArgumentError, "Magic Signature data must be signed with RSA-SHA256, was #{slap.magic_sig.alg}" unless 'RSA-SHA256' == slap.magic_sig.alg
slap
end
def parse_data(key_hash, user)
data = SalmonSlap.decode64url(self.magic_sig.data)
if user.present?
user.aes_decrypt(data, key_hash)
else
data
end
end
# @return [Nokogiri::Doc]
def salmon_header(doc, user)
if user.present?
decrypted_header = user.decrypt(doc.search('encrypted_header').text)
Nokogiri::XML(decrypted_header)
else
doc.search('header')
end
end
def xml_for person
xml =<<ENTRY
<?xml version='1.0' encoding='UTF-8'?>
@ -190,10 +200,20 @@ HEADER
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}"
end
env.data = doc.search('//me:env/me:data', ns).text
env.alg = doc.search('//me:env/me:alg', ns).text.strip
env.sig = doc.search('//me:env/me:sig', ns).text
env.data_type = doc.search('//me:env/me:data', ns).first['type'].strip
unless 'RSA-SHA256' == env.alg
raise ArgumentError, "Magic Signature data must be signed with RSA-SHA256, was #{env.alg}"
end
env
end

View file

@ -20,6 +20,24 @@ describe PublicsController do
end
end
describe '#receive_public' do
it 'succeeds' do
post :receive_public, :xml => "<stuff/>"
response.should be_success
end
it 'returns a 422 if no xml is passed' do
post :receive_public
response.code.should == '422'
end
it 'calls Postzord::Receiver:Public' do
xml = "stuff"
Postzord::Receiver::Public.should_receive(:new).with(xml)
post :receive_public, :xml => xml
end
end
describe '#receive' do
let(:xml) { "<walruses></walruses>" }

View file

@ -1,94 +0,0 @@
# Copyright (c) 2010, Diaspora Inc. This file is
# licensed under the Affero General Public License version 3 or later. See
# the COPYRIGHT file.
require 'spec_helper'
describe Salmon do
let(:user){alice}
let(:user2) {eve}
let(:user3) {Factory.create(:user)}
let(:post){ user.post :status_message, :text => "hi", :to => user.aspects.create(:name => "sdg").id }
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
it 'should reference a local author' do
parsed_salmon.author.should == user.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?(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