create attr_reader for payload entity and sender on magic env instance
This commit is contained in:
parent
930c3051c7
commit
4e0c7e205b
10 changed files with 61 additions and 46 deletions
|
|
@ -30,7 +30,7 @@ module DiasporaFederation
|
|||
|
||||
def create_magic_envelope(entity)
|
||||
privkey = DiasporaFederation.callbacks.trigger(:fetch_private_key_by_diaspora_id, entity.author)
|
||||
Salmon::MagicEnvelope.new(entity).envelop(privkey, entity.author) if privkey
|
||||
Salmon::MagicEnvelope.new(entity, entity.author).envelop(privkey) if privkey
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -114,9 +114,9 @@ module DiasporaFederation
|
|||
EncryptedSlap.new.tap do |slap|
|
||||
slap.author_id = author_id
|
||||
|
||||
magic_envelope = MagicEnvelope.new(entity)
|
||||
magic_envelope = MagicEnvelope.new(entity, author_id)
|
||||
slap.cipher_params = magic_envelope.encrypt!
|
||||
slap.magic_envelope_xml = magic_envelope.envelop(privkey, author_id)
|
||||
slap.magic_envelope_xml = magic_envelope.envelop(privkey)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -36,31 +36,40 @@ module DiasporaFederation
|
|||
# XML namespace url
|
||||
XMLNS = "http://salmon-protocol.org/ns/magic-env".freeze
|
||||
|
||||
# the payload entity of the magic envelope
|
||||
# @return [Entity] payload entity
|
||||
attr_reader :payload
|
||||
|
||||
# the sender of the magic envelope
|
||||
# @return [String] diaspora-ID of the sender
|
||||
attr_reader :sender
|
||||
|
||||
# Creates a new instance of MagicEnvelope.
|
||||
#
|
||||
# @param [Entity] payload Entity instance
|
||||
# @param [String] sender diaspora-ID of the sender
|
||||
# @raise [ArgumentError] if either argument is not of the right type
|
||||
def initialize(payload)
|
||||
raise ArgumentError unless payload.is_a?(Entity)
|
||||
def initialize(payload, sender)
|
||||
raise ArgumentError unless payload.is_a?(Entity) && sender.is_a?(String)
|
||||
|
||||
@payload = XmlPayload.pack(payload).to_xml.strip
|
||||
@payload = payload
|
||||
@sender = sender
|
||||
end
|
||||
|
||||
# Builds the XML structure for the magic envelope, inserts the {ENCODING}
|
||||
# encoded data and signs the envelope using {DIGEST}.
|
||||
#
|
||||
# @param [OpenSSL::PKey::RSA] privkey private key used for signing
|
||||
# @param [String] sender_id diaspora-ID of the sender
|
||||
# @return [Nokogiri::XML::Element] XML root node
|
||||
def envelop(privkey, sender_id)
|
||||
raise ArgumentError unless privkey.instance_of?(OpenSSL::PKey::RSA) && sender_id.is_a?(String)
|
||||
def envelop(privkey)
|
||||
raise ArgumentError unless privkey.instance_of?(OpenSSL::PKey::RSA)
|
||||
|
||||
build_xml {|xml|
|
||||
xml["me"].env("xmlns:me" => XMLNS) {
|
||||
xml["me"].data(Base64.urlsafe_encode64(@payload), type: DATA_TYPE)
|
||||
xml["me"].data(Base64.urlsafe_encode64(payload_data), type: DATA_TYPE)
|
||||
xml["me"].encoding(ENCODING)
|
||||
xml["me"].alg(ALGORITHM)
|
||||
xml["me"].sig(Base64.urlsafe_encode64(sign(privkey)), key_id: Base64.urlsafe_encode64(sender_id))
|
||||
xml["me"].sig(Base64.urlsafe_encode64(sign(privkey)), key_id: Base64.urlsafe_encode64(sender))
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
@ -77,7 +86,7 @@ module DiasporaFederation
|
|||
# @return [Hash] AES key and iv. E.g.: { key: "...", iv: "..." }
|
||||
def encrypt!
|
||||
AES.generate_key_and_iv.tap do |key|
|
||||
@payload = AES.encrypt(@payload, key[:key], key[:iv])
|
||||
@payload_data = AES.encrypt(payload_data, key[:key], key[:iv])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -117,6 +126,12 @@ module DiasporaFederation
|
|||
|
||||
private
|
||||
|
||||
# the payload data as string
|
||||
# @return [String] payload data
|
||||
def payload_data
|
||||
@payload_data ||= XmlPayload.pack(@payload).to_xml.strip
|
||||
end
|
||||
|
||||
# Builds the xml root node of the magic envelope.
|
||||
#
|
||||
# @yield [xml] Invokes the block with the
|
||||
|
|
@ -133,7 +148,7 @@ module DiasporaFederation
|
|||
# @param [OpenSSL::PKey::RSA] privkey private key used for signing
|
||||
# @return [String] the signature
|
||||
def sign(privkey)
|
||||
subject = MagicEnvelope.send(:sig_subject, [@payload, DATA_TYPE, ENCODING, ALGORITHM])
|
||||
subject = MagicEnvelope.send(:sig_subject, [payload_data, DATA_TYPE, ENCODING, ALGORITHM])
|
||||
privkey.sign(DIGEST, subject)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ module DiasporaFederation
|
|||
xml.author_id(author_id)
|
||||
}
|
||||
|
||||
xml.parent << MagicEnvelope.new(entity).envelop(privkey, author_id)
|
||||
xml.parent << MagicEnvelope.new(entity, author_id).envelop(privkey)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
module DiasporaFederation
|
||||
describe Federation::Fetcher do
|
||||
let(:post) { FactoryGirl.build(:status_message_entity, public: true) }
|
||||
let(:post_magic_env) { Salmon::MagicEnvelope.new(post).envelop(alice.private_key, post.author).to_xml }
|
||||
let(:post_magic_env) { Salmon::MagicEnvelope.new(post, post.author).envelop(alice.private_key).to_xml }
|
||||
|
||||
describe ".fetch_public" do
|
||||
it "fetches a public post" do
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ module DiasporaFederation
|
|||
let(:sender_key) { OpenSSL::PKey::RSA.generate(1024) }
|
||||
let(:recipient_key) { OpenSSL::PKey::RSA.generate(1024) }
|
||||
let(:entity) { FactoryGirl.build(:status_message_entity, public: false) }
|
||||
let(:magic_env) { Salmon::MagicEnvelope.new(entity).envelop(sender_key, sender_id) }
|
||||
let(:magic_env) { Salmon::MagicEnvelope.new(entity, sender_id).envelop(sender_key) }
|
||||
let(:data) { Salmon::EncryptedMagicEnvelope.encrypt(magic_env, recipient_key.public_key) }
|
||||
|
||||
it "parses the entity if everything is fine" do
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ module DiasporaFederation
|
|||
let(:sender_id) { FactoryGirl.generate(:diaspora_id) }
|
||||
let(:sender_key) { OpenSSL::PKey::RSA.generate(1024) }
|
||||
let(:entity) { FactoryGirl.build(:status_message_entity) }
|
||||
let(:data) { Salmon::MagicEnvelope.new(entity).envelop(sender_key, sender_id).to_xml }
|
||||
let(:data) { Salmon::MagicEnvelope.new(entity, sender_id).envelop(sender_key).to_xml }
|
||||
|
||||
it "parses the entity if everything is fine" do
|
||||
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ module DiasporaFederation
|
|||
:fetch_public_key_by_diaspora_id, sender_id
|
||||
).and_return(sender_key)
|
||||
|
||||
data = Salmon::MagicEnvelope.new(post).envelop(sender_key, sender_id).to_xml
|
||||
data = Salmon::MagicEnvelope.new(post, sender_id).envelop(sender_key).to_xml
|
||||
|
||||
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
|
||||
:receive_entity, kind_of(Entities::StatusMessage), nil
|
||||
|
|
@ -54,7 +54,7 @@ module DiasporaFederation
|
|||
:fetch_public_key_by_diaspora_id, sender_id
|
||||
).and_return(sender_key)
|
||||
|
||||
magic_env = Salmon::MagicEnvelope.new(post).envelop(sender_key, sender_id)
|
||||
magic_env = Salmon::MagicEnvelope.new(post, sender_id).envelop(sender_key)
|
||||
data = Salmon::EncryptedMagicEnvelope.encrypt(magic_env, recipient_key.public_key)
|
||||
|
||||
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
|
||||
|
|
@ -90,7 +90,7 @@ module DiasporaFederation
|
|||
end
|
||||
|
||||
it "raises when recipient private key is not available" do
|
||||
magic_env = Salmon::MagicEnvelope.new(post).envelop(sender_key, sender_id)
|
||||
magic_env = Salmon::MagicEnvelope.new(post, sender_id).envelop(sender_key)
|
||||
data = Salmon::EncryptedMagicEnvelope.encrypt(magic_env, recipient_key.public_key)
|
||||
|
||||
expect {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ module DiasporaFederation
|
|||
let(:sender_id) { FactoryGirl.generate(:diaspora_id) }
|
||||
let(:sender_key) { OpenSSL::PKey::RSA.generate(512) } # use small key for speedy specs
|
||||
let(:entity) { Entities::TestEntity.new(test: "abcd") }
|
||||
let(:magic_env) { Salmon::MagicEnvelope.new(entity).envelop(sender_key, sender_id) }
|
||||
let(:magic_env) { Salmon::MagicEnvelope.new(entity, sender_id).envelop(sender_key) }
|
||||
|
||||
let(:privkey) { OpenSSL::PKey::RSA.generate(1024) } # use small key for speedy specs
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
module DiasporaFederation
|
||||
describe Salmon::MagicEnvelope do
|
||||
let(:sender_id) { FactoryGirl.generate(:diaspora_id) }
|
||||
let(:sender) { FactoryGirl.generate(:diaspora_id) }
|
||||
let(:privkey) { OpenSSL::PKey::RSA.generate(512) } # use small key for speedy specs
|
||||
let(:payload) { Entities::TestEntity.new(test: "asdf") }
|
||||
let(:envelope) { Salmon::MagicEnvelope.new(payload) }
|
||||
let(:envelope) { Salmon::MagicEnvelope.new(payload, sender) }
|
||||
|
||||
def sig_subj(env)
|
||||
data = Base64.urlsafe_decode64(env.at_xpath("me:data").content)
|
||||
|
|
@ -17,14 +17,14 @@ module DiasporaFederation
|
|||
context "sanity" do
|
||||
it "constructs an instance" do
|
||||
expect {
|
||||
Salmon::MagicEnvelope.new(payload)
|
||||
Salmon::MagicEnvelope.new(payload, sender)
|
||||
}.not_to raise_error
|
||||
end
|
||||
|
||||
it "raises an error if the param types are wrong" do
|
||||
["asdf", 1234, :test, false].each do |val|
|
||||
expect {
|
||||
Salmon::MagicEnvelope.new(val)
|
||||
Salmon::MagicEnvelope.new(val, val)
|
||||
}.to raise_error ArgumentError
|
||||
end
|
||||
end
|
||||
|
|
@ -35,18 +35,18 @@ module DiasporaFederation
|
|||
it "raises an error if the param types are wrong" do
|
||||
["asdf", 1234, :test, false].each do |val|
|
||||
expect {
|
||||
envelope.envelop(val, val)
|
||||
envelope.envelop(val)
|
||||
}.to raise_error ArgumentError
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "should be an instance of Nokogiri::XML::Element" do
|
||||
expect(envelope.envelop(privkey, sender_id)).to be_an_instance_of Nokogiri::XML::Element
|
||||
expect(envelope.envelop(privkey)).to be_an_instance_of Nokogiri::XML::Element
|
||||
end
|
||||
|
||||
it "returns a magic envelope of correct structure" do
|
||||
env_xml = envelope.envelop(privkey, sender_id)
|
||||
env_xml = envelope.envelop(privkey)
|
||||
expect(env_xml.name).to eq("env")
|
||||
|
||||
control = %w(data encoding alg sig)
|
||||
|
|
@ -58,20 +58,20 @@ module DiasporaFederation
|
|||
expect(control).to be_empty
|
||||
end
|
||||
|
||||
it "adds the sender_id to the signature" do
|
||||
key_id = envelope.envelop(privkey, sender_id).at_xpath("me:sig")["key_id"]
|
||||
it "adds the sender to the signature" do
|
||||
key_id = envelope.envelop(privkey).at_xpath("me:sig")["key_id"]
|
||||
|
||||
expect(Base64.urlsafe_decode64(key_id)).to eq(sender_id)
|
||||
expect(Base64.urlsafe_decode64(key_id)).to eq(sender)
|
||||
end
|
||||
|
||||
it "adds the data_type" do
|
||||
data_type = envelope.envelop(privkey, sender_id).at_xpath("me:data")["type"]
|
||||
data_type = envelope.envelop(privkey).at_xpath("me:data")["type"]
|
||||
|
||||
expect(data_type).to eq("application/xml")
|
||||
end
|
||||
|
||||
it "signs the payload correctly" do
|
||||
env_xml = envelope.envelop(privkey, sender_id)
|
||||
env_xml = envelope.envelop(privkey)
|
||||
|
||||
subj = sig_subj(env_xml)
|
||||
sig = Base64.urlsafe_decode64(env_xml.at_xpath("me:sig").content)
|
||||
|
|
@ -87,9 +87,9 @@ module DiasporaFederation
|
|||
end
|
||||
|
||||
it "actually encrypts the payload" do
|
||||
plain_payload = envelope.instance_variable_get(:@payload)
|
||||
plain_payload = envelope.send(:payload_data)
|
||||
params = envelope.encrypt!
|
||||
encrypted_payload = envelope.instance_variable_get(:@payload)
|
||||
encrypted_payload = envelope.send(:payload_data)
|
||||
|
||||
cipher = OpenSSL::Cipher.new(Salmon::AES::CIPHER)
|
||||
cipher.encrypt
|
||||
|
|
@ -111,7 +111,7 @@ module DiasporaFederation
|
|||
|
||||
it "works with sane input" do
|
||||
expect {
|
||||
Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey, sender_id), privkey.public_key)
|
||||
Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey), privkey.public_key)
|
||||
}.not_to raise_error
|
||||
end
|
||||
|
||||
|
|
@ -132,12 +132,12 @@ module DiasporaFederation
|
|||
it "verifies the signature" do
|
||||
other_key = OpenSSL::PKey::RSA.generate(512)
|
||||
expect {
|
||||
Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey, sender_id), other_key.public_key)
|
||||
Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey), other_key.public_key)
|
||||
}.to raise_error Salmon::InvalidSignature
|
||||
end
|
||||
|
||||
it "verifies the encoding" do
|
||||
bad_env = envelope.envelop(privkey, sender_id)
|
||||
bad_env = envelope.envelop(privkey)
|
||||
bad_env.at_xpath("me:encoding").content = "invalid_enc"
|
||||
re_sign(bad_env, privkey)
|
||||
expect {
|
||||
|
|
@ -146,7 +146,7 @@ module DiasporaFederation
|
|||
end
|
||||
|
||||
it "verifies the algorithm" do
|
||||
bad_env = envelope.envelop(privkey, sender_id)
|
||||
bad_env = envelope.envelop(privkey)
|
||||
bad_env.at_xpath("me:alg").content = "invalid_alg"
|
||||
re_sign(bad_env, privkey)
|
||||
expect {
|
||||
|
|
@ -156,7 +156,7 @@ module DiasporaFederation
|
|||
end
|
||||
|
||||
it "returns the original entity" do
|
||||
entity = Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey, sender_id), privkey.public_key)
|
||||
entity = Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey), privkey.public_key)
|
||||
expect(entity).to be_an_instance_of Entities::TestEntity
|
||||
expect(entity.test).to eq("asdf")
|
||||
end
|
||||
|
|
@ -164,7 +164,7 @@ module DiasporaFederation
|
|||
it "decrypts on the fly, when cipher params are present" do
|
||||
params = envelope.encrypt!
|
||||
|
||||
env_xml = envelope.envelop(privkey, sender_id)
|
||||
env_xml = envelope.envelop(privkey)
|
||||
|
||||
entity = Salmon::MagicEnvelope.unenvelop(env_xml, privkey.public_key, params)
|
||||
expect(entity).to be_an_instance_of Entities::TestEntity
|
||||
|
|
@ -174,16 +174,16 @@ module DiasporaFederation
|
|||
context "use key_id from magic envelope" do
|
||||
it "returns the original entity" do
|
||||
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
|
||||
:fetch_public_key_by_diaspora_id, sender_id
|
||||
:fetch_public_key_by_diaspora_id, sender
|
||||
).and_return(privkey.public_key)
|
||||
|
||||
entity = Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey, sender_id))
|
||||
entity = Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey))
|
||||
expect(entity).to be_an_instance_of Entities::TestEntity
|
||||
expect(entity.test).to eq("asdf")
|
||||
end
|
||||
|
||||
it "raises if the magic envelope has no key_id" do
|
||||
bad_env = envelope.envelop(privkey, sender_id)
|
||||
bad_env = envelope.envelop(privkey)
|
||||
|
||||
bad_env.at_xpath("me:sig").attributes["key_id"].remove
|
||||
|
||||
|
|
@ -194,11 +194,11 @@ module DiasporaFederation
|
|||
|
||||
it "raises if the sender key is not found" do
|
||||
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
|
||||
:fetch_public_key_by_diaspora_id, sender_id
|
||||
:fetch_public_key_by_diaspora_id, sender
|
||||
).and_return(nil)
|
||||
|
||||
expect {
|
||||
Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey, sender_id))
|
||||
Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey))
|
||||
}.to raise_error Salmon::SenderKeyNotFound
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue