MS DG pulling apart salmon and making our custom hacks more obvious
This commit is contained in:
parent
6b0507949c
commit
e0429ee823
14 changed files with 458 additions and 225 deletions
|
|
@ -19,7 +19,7 @@ module Job
|
|||
|
||||
people = Person.where(:id => person_ids)
|
||||
|
||||
salmon = Salmon::SalmonSlap.create(user, Base64.decode64(enc_object_xml))
|
||||
salmon = Salmon::EncryptedSalmonSlap.create(user, Base64.decode64(enc_object_xml))
|
||||
|
||||
failed_request_people = []
|
||||
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ class User < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def salmon(post)
|
||||
Salmon::SalmonSlap.create(self, post.to_diaspora_xml)
|
||||
Salmon::EncryptedSalmonSlap.create(self, post.to_diaspora_xml)
|
||||
end
|
||||
|
||||
def build_relayable(model, options = {})
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class Postzord::Dispatch
|
|||
end
|
||||
|
||||
def salmon
|
||||
@salmon_factory ||= Salmon::SalmonSlap.create(@sender, @xml)
|
||||
@salmon_factory ||= Salmon::EncryptedSalmonSlap.create(@sender, @xml)
|
||||
end
|
||||
|
||||
def post(opts = {})
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ module Postzord
|
|||
|
||||
protected
|
||||
def salmon
|
||||
@salmon ||= Salmon::SalmonSlap.parse(@salmon_xml, @user)
|
||||
@salmon ||= Salmon::EncryptedSalmonSlap.parse(@salmon_xml, @user)
|
||||
end
|
||||
|
||||
def xml_author
|
||||
|
|
|
|||
16
lib/postzord/receiver/public.rb
Normal file
16
lib/postzord/receiver/public.rb
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Copyright (c) 2010, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
#
|
||||
module Postzord
|
||||
class Receiver
|
||||
class Public
|
||||
attr_accessor :xml
|
||||
|
||||
def initialize(xml)
|
||||
@xml = xml
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
25
lib/salmon/encrypted_salmon_slap.rb
Normal file
25
lib/salmon/encrypted_salmon_slap.rb
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# Copyright (c) 2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
module Salmon
|
||||
class EncryptedSalmonSlap < SalmonSlap
|
||||
def header(person)
|
||||
<<XML
|
||||
<encrypted_header>
|
||||
#{person.encrypt("<decrypted_header>#{plaintext_header}</decrypted_header>")}
|
||||
</encrypted_header>
|
||||
XML
|
||||
end
|
||||
|
||||
def parse_data(key_hash, user)
|
||||
user.aes_decrypt(super, key_hash)
|
||||
end
|
||||
|
||||
# @return [Nokogiri::Doc]
|
||||
def salmon_header(doc, user)
|
||||
header = user.decrypt(doc.search('encrypted_header').text)
|
||||
Nokogiri::XML(header)
|
||||
end
|
||||
end
|
||||
end
|
||||
70
lib/salmon/magic_sig_envelope.rb
Normal file
70
lib/salmon/magic_sig_envelope.rb
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# Copyright (c) 2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
module Salmon
|
||||
class MagicSigEnvelope
|
||||
attr_accessor :data, :data_type, :encoding, :alg, :sig, :author
|
||||
def self.parse(doc)
|
||||
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
|
||||
|
||||
def self.create(user, activity)
|
||||
env = MagicSigEnvelope.new
|
||||
env.author = user.person
|
||||
env.data = Base64.urlsafe_encode64(activity)
|
||||
env.data_type = env.get_data_type
|
||||
env.encoding = env.get_encoding
|
||||
env.alg = env.get_alg
|
||||
|
||||
env.sig = Base64.urlsafe_encode64(
|
||||
user.encryption_key.sign OpenSSL::Digest::SHA256.new, env.signable_string )
|
||||
|
||||
env
|
||||
end
|
||||
|
||||
def signable_string
|
||||
[@data, Base64.urlsafe_encode64(@data_type),Base64.urlsafe_encode64(@encoding), Base64.urlsafe_encode64(@alg)].join(".")
|
||||
end
|
||||
|
||||
def to_xml
|
||||
<<ENTRY
|
||||
<me:env xmlns:me="http://salmon-protocol.org/ns/magic-env">
|
||||
<me:data type='#{@data_type}'>#{@data}</me:data>
|
||||
<me:encoding>#{@encoding}</me:encoding>
|
||||
<me:alg>#{@alg}</me:alg>
|
||||
<me:sig>#{@sig}</me:sig>
|
||||
</me:env>
|
||||
ENTRY
|
||||
end
|
||||
|
||||
def get_encoding
|
||||
'base64url'
|
||||
end
|
||||
|
||||
def get_data_type
|
||||
'application/atom+xml'
|
||||
end
|
||||
|
||||
def get_alg
|
||||
'RSA-SHA256'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -39,225 +39,7 @@ end
|
|||
|
||||
# Verify documents secured with Magic Signatures
|
||||
module Salmon
|
||||
|
||||
class SalmonSlap
|
||||
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=nil)
|
||||
slap = self.new
|
||||
doc = Nokogiri::XML(xml)
|
||||
|
||||
sig_doc = doc.search('entry')
|
||||
|
||||
### 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
|
||||
|
||||
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
|
||||
|
||||
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'?>
|
||||
<entry xmlns='http://www.w3.org/2005/Atom'>
|
||||
<encrypted_header>#{person.encrypt(decrypted_header)}</encrypted_header>
|
||||
#{@magic_sig.to_xml}
|
||||
</entry>
|
||||
ENTRY
|
||||
|
||||
end
|
||||
|
||||
def decrypted_header
|
||||
header =<<HEADER
|
||||
<decrypted_header>
|
||||
<iv>#{iv}</iv>
|
||||
<aes_key>#{aes_key}</aes_key>
|
||||
<author>
|
||||
<name>#{@author.name}</name>
|
||||
<uri>acct:#{@author.diaspora_handle}</uri>
|
||||
</author>
|
||||
</decrypted_header>
|
||||
HEADER
|
||||
end
|
||||
|
||||
def author
|
||||
if @author.nil?
|
||||
@author ||= Person.by_account_identifier @author_email
|
||||
raise "did you remember to async webfinger?" if @author.nil?
|
||||
end
|
||||
@author
|
||||
end
|
||||
|
||||
# Decode URL-safe-Base64. This implements
|
||||
def self.decode64url(str)
|
||||
# remove whitespace
|
||||
sans_whitespace = str.gsub(/\s/, '')
|
||||
# pad to a multiple of 4
|
||||
string = sans_whitespace + '=' * ((4 - sans_whitespace.size) % 4)
|
||||
# convert to standard Base64
|
||||
# string = padded.tr('-','+').tr('_','/')
|
||||
|
||||
# Base64.decode64(string)
|
||||
Base64.urlsafe_decode64 string
|
||||
end
|
||||
|
||||
# Check whether this envelope's signature can be verified with the
|
||||
# provided OpenSSL::PKey::RSA public_key.
|
||||
# Example:
|
||||
#
|
||||
# env.verified_for_key? OpenSSL::PKey::RSA.new(File.open('public_key.pem'))
|
||||
# # -> true
|
||||
def verified_for_key?(public_key)
|
||||
signature = Base64.urlsafe_decode64(self.magic_sig.sig)
|
||||
signed_data = self.magic_sig.signable_string# Base64.urlsafe_decode64(self.magic_sig.signable_string)
|
||||
|
||||
public_key.verify(OpenSSL::Digest::SHA256.new, signature, signed_data )
|
||||
end
|
||||
|
||||
# Decode a string containing URL safe Base64 into an integer
|
||||
# Example:
|
||||
#
|
||||
# MagicSig.b64_to_n('AQAB')
|
||||
# # -> 645537
|
||||
def self.b64_to_n(str)
|
||||
packed = decode64url(str)
|
||||
packed.unpack('B*')[0].to_i(2)
|
||||
end
|
||||
|
||||
# Parse a string containing a magic-public-key into an OpenSSL::PKey::RSA key.
|
||||
# Example:
|
||||
#
|
||||
# key = MagicSig.parse_key('RSA.mVgY8RN6URBTstndvmUUPb4UZTdwvwmddSKE5z_jvKUEK6yk1u3rrC9yN8k6FilGj9K0eeUPe2hf4Pj-5CmHww.AQAB')
|
||||
# key.n
|
||||
# # -> 8031283789075196565022891546563591368344944062154100509645398892293433370859891943306439907454883747534493461257620351548796452092307094036643522661681091
|
||||
# key.e
|
||||
# # -> 65537
|
||||
def self.parse_key(str)
|
||||
n,e = str.match(/^RSA.([^.]*).([^.]*)$/)[1..2]
|
||||
build_key(b64_to_n(n),b64_to_n(e))
|
||||
end
|
||||
|
||||
# Take two integers e, n and create a new OpenSSL::PKey::RSA key with them
|
||||
# Example:
|
||||
#
|
||||
# n = 9487834027867356975347184933768917275269369900665861930617802608089634337052392076689226301419587057117740995382286148368168197915234368486155306558161867
|
||||
# e = 65537
|
||||
# key = MagicSig.build_key(n,e)
|
||||
# key.public_encrypt(...) # for sending to strangers
|
||||
# key.public_decrypt(...) # very rarely used
|
||||
# key.verify(...) # for verifying signatures
|
||||
def self.build_key(n,e)
|
||||
key = OpenSSL::PKey::RSA.new
|
||||
key.n = n
|
||||
key.e = e
|
||||
key
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class MagicSigEnvelope
|
||||
attr_accessor :data, :data_type, :encoding, :alg, :sig, :author
|
||||
def self.parse(doc)
|
||||
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
|
||||
|
||||
def self.create(user, activity)
|
||||
env = MagicSigEnvelope.new
|
||||
env.author = user.person
|
||||
env.data = Base64.urlsafe_encode64(activity)
|
||||
env.data_type = env.get_data_type
|
||||
env.encoding = env.get_encoding
|
||||
env.alg = env.get_alg
|
||||
|
||||
env.sig = Base64.urlsafe_encode64(
|
||||
user.encryption_key.sign OpenSSL::Digest::SHA256.new, env.signable_string )
|
||||
|
||||
env
|
||||
end
|
||||
|
||||
def signable_string
|
||||
[@data, Base64.urlsafe_encode64(@data_type),Base64.urlsafe_encode64(@encoding), Base64.urlsafe_encode64(@alg)].join(".")
|
||||
end
|
||||
|
||||
def to_xml
|
||||
xml= <<ENTRY
|
||||
<me:env xmlns:me="http://salmon-protocol.org/ns/magic-env">
|
||||
<me:data type='#{@data_type}'>#{@data}</me:data>
|
||||
<me:encoding>#{@encoding}</me:encoding>
|
||||
<me:alg>#{@alg}</me:alg>
|
||||
<me:sig>#{@sig}</me:sig>
|
||||
</me:env>
|
||||
ENTRY
|
||||
xml
|
||||
end
|
||||
|
||||
def get_encoding
|
||||
'base64url'
|
||||
end
|
||||
|
||||
def get_data_type
|
||||
'application/atom+xml'
|
||||
end
|
||||
|
||||
def get_alg
|
||||
'RSA-SHA256'
|
||||
end
|
||||
|
||||
end
|
||||
autoload :SalmonSlap, File.join(Rails.root, "lib", "salmon", "salmon_slap")
|
||||
autoload :EncryptedSalmonSlap, File.join(Rails.root, "lib", "salmon", "encrypted_salmon_slap")
|
||||
autoload :MagicSigEnvelope, File.join(Rails.root, "lib", "salmon", "magic_sig_envelope")
|
||||
end
|
||||
|
|
|
|||
150
lib/salmon/salmon_slap.rb
Normal file
150
lib/salmon/salmon_slap.rb
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
# Copyright (c) 2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
module Salmon
|
||||
class SalmonSlap
|
||||
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=nil)
|
||||
slap = self.new
|
||||
doc = Nokogiri::XML(xml)
|
||||
|
||||
sig_doc = doc.search('entry')
|
||||
|
||||
### 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
|
||||
|
||||
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
|
||||
|
||||
slap
|
||||
end
|
||||
|
||||
# @return [String]
|
||||
def parse_data(key_hash, user=nil)
|
||||
SalmonSlap.decode64url(self.magic_sig.data)
|
||||
end
|
||||
|
||||
# @return [Nokogiri::Doc]
|
||||
def salmon_header(doc, user=nil)
|
||||
doc.search('header')
|
||||
end
|
||||
|
||||
def xml_for(person)
|
||||
xml =<<ENTRY
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<entry xmlns='http://www.w3.org/2005/Atom'>
|
||||
#{header(person)}
|
||||
#{@magic_sig.to_xml}
|
||||
</entry>
|
||||
ENTRY
|
||||
end
|
||||
|
||||
def header(person)
|
||||
"<header>#{plaintext_header}</header>"
|
||||
end
|
||||
|
||||
def plaintext_header
|
||||
header =<<HEADER
|
||||
<iv>#{iv}</iv>
|
||||
<aes_key>#{aes_key}</aes_key>
|
||||
<author>
|
||||
<name>#{@author.name}</name>
|
||||
<uri>acct:#{@author.diaspora_handle}</uri>
|
||||
</author>
|
||||
HEADER
|
||||
end
|
||||
|
||||
def author
|
||||
if @author.nil?
|
||||
@author ||= Person.by_account_identifier @author_email
|
||||
raise "did you remember to async webfinger?" if @author.nil?
|
||||
end
|
||||
@author
|
||||
end
|
||||
|
||||
# Decode URL-safe-Base64. This implements
|
||||
def self.decode64url(str)
|
||||
# remove whitespace
|
||||
sans_whitespace = str.gsub(/\s/, '')
|
||||
# pad to a multiple of 4
|
||||
string = sans_whitespace + '=' * ((4 - sans_whitespace.size) % 4)
|
||||
# convert to standard Base64
|
||||
# string = padded.tr('-','+').tr('_','/')
|
||||
|
||||
# Base64.decode64(string)
|
||||
Base64.urlsafe_decode64 string
|
||||
end
|
||||
|
||||
# Check whether this envelope's signature can be verified with the
|
||||
# provided OpenSSL::PKey::RSA public_key.
|
||||
# Example:
|
||||
#
|
||||
# env.verified_for_key? OpenSSL::PKey::RSA.new(File.open('public_key.pem'))
|
||||
# # -> true
|
||||
def verified_for_key?(public_key)
|
||||
signature = Base64.urlsafe_decode64(self.magic_sig.sig)
|
||||
signed_data = self.magic_sig.signable_string# Base64.urlsafe_decode64(self.magic_sig.signable_string)
|
||||
|
||||
public_key.verify(OpenSSL::Digest::SHA256.new, signature, signed_data )
|
||||
end
|
||||
|
||||
# Decode a string containing URL safe Base64 into an integer
|
||||
# Example:
|
||||
#
|
||||
# MagicSig.b64_to_n('AQAB')
|
||||
# # -> 645537
|
||||
def self.b64_to_n(str)
|
||||
packed = decode64url(str)
|
||||
packed.unpack('B*')[0].to_i(2)
|
||||
end
|
||||
|
||||
# Parse a string containing a magic-public-key into an OpenSSL::PKey::RSA key.
|
||||
# Example:
|
||||
#
|
||||
# key = MagicSig.parse_key('RSA.mVgY8RN6URBTstndvmUUPb4UZTdwvwmddSKE5z_jvKUEK6yk1u3rrC9yN8k6FilGj9K0eeUPe2hf4Pj-5CmHww.AQAB')
|
||||
# key.n
|
||||
# # -> 8031283789075196565022891546563591368344944062154100509645398892293433370859891943306439907454883747534493461257620351548796452092307094036643522661681091
|
||||
# key.e
|
||||
# # -> 65537
|
||||
def self.parse_key(str)
|
||||
n,e = str.match(/^RSA.([^.]*).([^.]*)$/)[1..2]
|
||||
build_key(b64_to_n(n),b64_to_n(e))
|
||||
end
|
||||
|
||||
# Take two integers e, n and create a new OpenSSL::PKey::RSA key with them
|
||||
# Example:
|
||||
#
|
||||
# n = 9487834027867356975347184933768917275269369900665861930617802608089634337052392076689226301419587057117740995382286148368168197915234368486155306558161867
|
||||
# e = 65537
|
||||
# key = MagicSig.build_key(n,e)
|
||||
# key.public_encrypt(...) # for sending to strangers
|
||||
# key.public_decrypt(...) # very rarely used
|
||||
# key.verify(...) # for verifying signatures
|
||||
def self.build_key(n,e)
|
||||
key = OpenSSL::PKey::RSA.new
|
||||
key.n = n
|
||||
key.e = e
|
||||
key
|
||||
end
|
||||
end
|
||||
end
|
||||
32
spec/lib/postzord/receiver/public.rb
Normal file
32
spec/lib/postzord/receiver/public.rb
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# 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'
|
||||
|
||||
require File.join(Rails.root, 'lib/postzord')
|
||||
require File.join(Rails.root, 'lib/postzord/receiver/public')
|
||||
|
||||
describe Postzord::Receiver::Public do
|
||||
|
||||
describe '#initialize' do
|
||||
|
||||
end
|
||||
|
||||
describe '#verify_signature' do
|
||||
|
||||
end
|
||||
|
||||
describe '#collect_recipients' do
|
||||
|
||||
end
|
||||
|
||||
describe '#batch_insert_visibilities' do
|
||||
|
||||
end
|
||||
|
||||
describe '#batch_notify' do
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
59
spec/lib/postzord/receiver/public_spec.rb
Normal file
59
spec/lib/postzord/receiver/public_spec.rb
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
# Copyright (c) 2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
require File.join(Rails.root, 'lib/postzord')
|
||||
require File.join(Rails.root, 'lib/postzord/receiver/public')
|
||||
|
||||
describe Postzord::Receiver::Public do
|
||||
|
||||
describe '#initialize' do
|
||||
it 'sets xml as instance variable' do
|
||||
receiver = Postzord::Receiver::Public.new("blah")
|
||||
receiver.xml.should == 'blah'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
it 'calls verify_signature' do
|
||||
|
||||
end
|
||||
|
||||
context 'if signature is valid' do
|
||||
it 'calls collect_recipients' do
|
||||
|
||||
end
|
||||
|
||||
it 'saves the parsed object' do
|
||||
|
||||
end
|
||||
|
||||
it 'calls batch_insert_visibilities' do
|
||||
|
||||
end
|
||||
|
||||
it 'calls batch_notify' do
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#verify_signature' do
|
||||
|
||||
end
|
||||
|
||||
describe '#collect_recipients' do
|
||||
|
||||
end
|
||||
|
||||
describe '#batch_insert_visibilities' do
|
||||
|
||||
end
|
||||
|
||||
describe '#batch_notify' do
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
89
spec/lib/salmon/encrypted_salmon_slap_spec.rb
Normal file
89
spec/lib/salmon/encrypted_salmon_slap_spec.rb
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# 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::EncryptedSalmonSlap do
|
||||
let(:post){ alice.post :status_message, :text => "hi", :to => alice.aspects.create(:name => "sdg").id }
|
||||
|
||||
let!(:created_salmon) {Salmon::EncryptedSalmonSlap.create(alice, 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::EncryptedSalmonSlap.decode64url(created_salmon.magic_sig.data)
|
||||
alice.aes_decrypt(decoded_string, key_hash).should == post.to_diaspora_xml
|
||||
end
|
||||
end
|
||||
|
||||
describe '#xml_for' do
|
||||
let(:xml) {created_salmon.xml_for eve.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 = eve.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 eve.person}
|
||||
let(:parsed_salmon) { Salmon::EncryptedSalmonSlap.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
|
||||
|
||||
5
spec/lib/salmon/magic_sig_envelope_spec.rb
Normal file
5
spec/lib/salmon/magic_sig_envelope_spec.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Salmon::MagicSigEnvelope do
|
||||
|
||||
end
|
||||
5
spec/lib/salmon/salmon_slap_spec.rb
Normal file
5
spec/lib/salmon/salmon_slap_spec.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Salmon::SalmonSlap do
|
||||
|
||||
end
|
||||
Loading…
Reference in a new issue