Remove generation code for legacy salmon slap from library
Create legacy_helper.rb to still generate old XMLs for the tests. Related to #30
This commit is contained in:
parent
18a23df8d5
commit
ba01882cb2
8 changed files with 71 additions and 305 deletions
|
|
@ -48,32 +48,12 @@ module DiasporaFederation
|
||||||
# Finally, before decrypting the magic envelope payload, the signature should
|
# Finally, before decrypting the magic envelope payload, the signature should
|
||||||
# first be verified.
|
# first be verified.
|
||||||
#
|
#
|
||||||
# @example Generating an encrypted Salmon Slap
|
|
||||||
# author_id = "author@pod.example.tld"
|
|
||||||
# author_privkey = however_you_retrieve_the_authors_private_key(author_id)
|
|
||||||
# recipient_pubkey = however_you_retrieve_the_recipients_public_key()
|
|
||||||
# entity = YourEntity.new(attr: "val")
|
|
||||||
#
|
|
||||||
# slap_xml = EncryptedSlap.prepare(author_id, author_privkey, entity).generate_xml(recipient_pubkey)
|
|
||||||
#
|
|
||||||
# @example Parsing a Salmon Slap
|
# @example Parsing a Salmon Slap
|
||||||
# recipient_privkey = however_you_retrieve_the_recipients_private_key()
|
# recipient_privkey = however_you_retrieve_the_recipients_private_key()
|
||||||
# entity = EncryptedSlap.from_xml(slap_xml, recipient_privkey).payload
|
# entity = EncryptedSlap.from_xml(slap_xml, recipient_privkey).payload
|
||||||
#
|
#
|
||||||
# @deprecated
|
# @deprecated
|
||||||
class EncryptedSlap < Slap
|
class EncryptedSlap < Slap
|
||||||
# the author of the slap
|
|
||||||
# @param [String] value the author diaspora* ID
|
|
||||||
attr_writer :author_id
|
|
||||||
|
|
||||||
# the key and iv if it is an encrypted slap
|
|
||||||
# @param [Hash] value hash containing the key and iv
|
|
||||||
attr_writer :cipher_params
|
|
||||||
|
|
||||||
# the prepared encrypted magic envelope xml
|
|
||||||
# @param [Nokogiri::XML::Element] value magic envelope xml
|
|
||||||
attr_writer :magic_envelope_xml
|
|
||||||
|
|
||||||
# Creates a {MagicEnvelope} instance from the data within the given XML string
|
# Creates a {MagicEnvelope} instance from the data within the given XML string
|
||||||
# containing an encrypted payload.
|
# containing an encrypted payload.
|
||||||
#
|
#
|
||||||
|
|
@ -98,44 +78,6 @@ module DiasporaFederation
|
||||||
MagicEnvelope.unenvelop(magic_env_from_doc(doc), sender, cipher_params)
|
MagicEnvelope.unenvelop(magic_env_from_doc(doc), sender, cipher_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates an encrypted Salmon Slap.
|
|
||||||
#
|
|
||||||
# @param [String] author_id diaspora* ID of the author
|
|
||||||
# @param [OpenSSL::PKey::RSA] privkey sender private key for signing the magic envelope
|
|
||||||
# @param [Entity] entity payload
|
|
||||||
# @return [EncryptedSlap] encrypted Slap instance
|
|
||||||
# @raise [ArgumentError] if any of the arguments is of the wrong type
|
|
||||||
def self.prepare(author_id, privkey, entity)
|
|
||||||
raise ArgumentError unless author_id.instance_of?(String) &&
|
|
||||||
privkey.instance_of?(OpenSSL::PKey::RSA) &&
|
|
||||||
entity.is_a?(Entity)
|
|
||||||
|
|
||||||
EncryptedSlap.new.tap do |slap|
|
|
||||||
slap.author_id = author_id
|
|
||||||
|
|
||||||
magic_envelope = MagicEnvelope.new(entity)
|
|
||||||
slap.cipher_params = magic_envelope.encrypt!
|
|
||||||
slap.magic_envelope_xml = magic_envelope.envelop(privkey).root
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Creates an encrypted Salmon Slap XML string.
|
|
||||||
#
|
|
||||||
# @param [OpenSSL::PKey::RSA] pubkey recipient public key for encrypting the AES key
|
|
||||||
# @return [String] Salmon XML string
|
|
||||||
# @raise [ArgumentError] if any of the arguments is of the wrong type
|
|
||||||
def generate_xml(pubkey)
|
|
||||||
raise ArgumentError unless pubkey.instance_of?(OpenSSL::PKey::RSA)
|
|
||||||
|
|
||||||
Slap.build_xml do |xml|
|
|
||||||
xml.encrypted_header(encrypted_header(@author_id, @cipher_params, pubkey))
|
|
||||||
|
|
||||||
xml.parent << @magic_envelope_xml
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
# Decrypts and reads the data from the encrypted XML header
|
# Decrypts and reads the data from the encrypted XML header
|
||||||
# @param [String] data base64 encoded, encrypted header data
|
# @param [String] data base64 encoded, encrypted header data
|
||||||
# @param [OpenSSL::PKey::RSA] privkey private key for decryption
|
# @param [OpenSSL::PKey::RSA] privkey private key for decryption
|
||||||
|
|
@ -162,45 +104,6 @@ module DiasporaFederation
|
||||||
xml = AES.decrypt(cipher_header["ciphertext"], Base64.decode64(key["key"]), Base64.decode64(key["iv"]))
|
xml = AES.decrypt(cipher_header["ciphertext"], Base64.decode64(key["key"]), Base64.decode64(key["iv"]))
|
||||||
Nokogiri::XML(xml).root
|
Nokogiri::XML(xml).root
|
||||||
end
|
end
|
||||||
|
|
||||||
# Encrypt the header xml with an AES cipher and encrypt the cipher params
|
|
||||||
# with the recipients public_key.
|
|
||||||
# @param [String] author_id diaspora_handle
|
|
||||||
# @param [Hash] envelope_key envelope cipher params
|
|
||||||
# @param [OpenSSL::PKey::RSA] pubkey recipient public_key
|
|
||||||
# @return [String] encrypted base64 encoded header
|
|
||||||
def encrypted_header(author_id, envelope_key, pubkey)
|
|
||||||
data = header_xml(author_id, strict_base64_encode(envelope_key))
|
|
||||||
header_key = AES.generate_key_and_iv
|
|
||||||
ciphertext = AES.encrypt(data, header_key[:key], header_key[:iv])
|
|
||||||
|
|
||||||
json_key = JSON.generate(strict_base64_encode(header_key))
|
|
||||||
encrypted_key = Base64.strict_encode64(pubkey.public_encrypt(json_key))
|
|
||||||
|
|
||||||
json_header = JSON.generate(aes_key: encrypted_key, ciphertext: ciphertext)
|
|
||||||
|
|
||||||
Base64.strict_encode64(json_header)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Generate the header xml string, including the author, aes_key and iv
|
|
||||||
# @param [String] author_id diaspora_handle of the author
|
|
||||||
# @param [Hash] envelope_key { key: "...", iv: "..." } (values in base64)
|
|
||||||
# @return [String] header XML string
|
|
||||||
def header_xml(author_id, envelope_key)
|
|
||||||
@header_xml ||= Nokogiri::XML::Builder.new(encoding: "UTF-8") {|xml|
|
|
||||||
xml.decrypted_header {
|
|
||||||
xml.iv(envelope_key[:iv])
|
|
||||||
xml.aes_key(envelope_key[:key])
|
|
||||||
xml.author_id(author_id)
|
|
||||||
}
|
|
||||||
}.to_xml.strip
|
|
||||||
end
|
|
||||||
|
|
||||||
# @param [Hash] hash { key: "...", iv: "..." }
|
|
||||||
# @return [Hash] encoded hash: { key: "...", iv: "..." }
|
|
||||||
def strict_base64_encode(hash)
|
|
||||||
hash.map {|k, v| [k, Base64.strict_encode64(v)] }.to_h
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -76,22 +76,6 @@ module DiasporaFederation
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Encrypts the payload with a new, random AES cipher and returns the cipher
|
|
||||||
# params that were used.
|
|
||||||
#
|
|
||||||
# This must happen after the MagicEnvelope instance was created and before
|
|
||||||
# {MagicEnvelope#envelop} is called.
|
|
||||||
#
|
|
||||||
# @see AES#generate_key_and_iv
|
|
||||||
# @see AES#encrypt
|
|
||||||
#
|
|
||||||
# @return [Hash] AES key and iv. E.g.: { key: "...", iv: "..." }
|
|
||||||
def encrypt!
|
|
||||||
AES.generate_key_and_iv.tap do |key|
|
|
||||||
@payload_data = AES.encrypt(payload_data, key[:key], key[:iv])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Extracts the entity encoded in the magic envelope data, if the signature
|
# Extracts the entity encoded in the magic envelope data, if the signature
|
||||||
# is valid. If +cipher_params+ is given, also attempts to decrypt the payload first.
|
# is valid. If +cipher_params+ is given, also attempts to decrypt the payload first.
|
||||||
#
|
#
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,6 @@ module DiasporaFederation
|
||||||
# {magic_envelope}
|
# {magic_envelope}
|
||||||
# </diaspora>
|
# </diaspora>
|
||||||
#
|
#
|
||||||
# @example Generating a Salmon Slap
|
|
||||||
# author_id = "author@pod.example.tld"
|
|
||||||
# author_privkey = however_you_retrieve_the_authors_private_key(author_id)
|
|
||||||
# entity = YourEntity.new(attr: "val")
|
|
||||||
#
|
|
||||||
# slap_xml = Slap.generate_xml(author_id, author_privkey, entity)
|
|
||||||
#
|
|
||||||
# @example Parsing a Salmon Slap
|
# @example Parsing a Salmon Slap
|
||||||
# entity = Slap.from_xml(slap_xml).payload
|
# entity = Slap.from_xml(slap_xml).payload
|
||||||
#
|
#
|
||||||
|
|
@ -49,19 +42,6 @@ module DiasporaFederation
|
||||||
MagicEnvelope.unenvelop(magic_env_from_doc(doc), sender)
|
MagicEnvelope.unenvelop(magic_env_from_doc(doc), sender)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Builds the xml for the Salmon Slap.
|
|
||||||
#
|
|
||||||
# @yield [xml] Invokes the block with the
|
|
||||||
# {http://www.rubydoc.info/gems/nokogiri/Nokogiri/XML/Builder Nokogiri::XML::Builder}
|
|
||||||
# @return [String] Slap XML
|
|
||||||
def self.build_xml
|
|
||||||
Nokogiri::XML::Builder.new(encoding: "UTF-8") {|xml|
|
|
||||||
xml.diaspora("xmlns" => Salmon::XMLNS, "xmlns:me" => MagicEnvelope::XMLNS) {
|
|
||||||
yield xml
|
|
||||||
}
|
|
||||||
}.to_xml
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parses the magic envelop from the document.
|
# Parses the magic envelop from the document.
|
||||||
#
|
#
|
||||||
# @param [Nokogiri::XML::Document] doc Salmon XML Document
|
# @param [Nokogiri::XML::Document] doc Salmon XML Document
|
||||||
|
|
|
||||||
|
|
@ -24,13 +24,7 @@ module DiasporaFederation
|
||||||
it "parses the entity with legacy slap receiver" do
|
it "parses the entity with legacy slap receiver" do
|
||||||
expect_callback(:fetch_public_key, post.author).and_return(sender_key)
|
expect_callback(:fetch_public_key, post.author).and_return(sender_key)
|
||||||
|
|
||||||
data = DiasporaFederation::Salmon::Slap.build_xml do |xml|
|
data = generate_legacy_salmon_slap(post, post.author, sender_key)
|
||||||
xml.header {
|
|
||||||
xml.author_id(post.author)
|
|
||||||
}
|
|
||||||
|
|
||||||
xml.parent << Salmon::MagicEnvelope.new(post, post.author).envelop(sender_key).root
|
|
||||||
end
|
|
||||||
|
|
||||||
expect_callback(:receive_entity, kind_of(Entities::StatusMessage), post.author, nil) do |_, entity|
|
expect_callback(:receive_entity, kind_of(Entities::StatusMessage), post.author, nil) do |_, entity|
|
||||||
expect(entity.guid).to eq(post.guid)
|
expect(entity.guid).to eq(post.guid)
|
||||||
|
|
@ -71,8 +65,7 @@ module DiasporaFederation
|
||||||
it "parses the entity with legacy slap receiver" do
|
it "parses the entity with legacy slap receiver" do
|
||||||
expect_callback(:fetch_public_key, post.author).and_return(sender_key)
|
expect_callback(:fetch_public_key, post.author).and_return(sender_key)
|
||||||
|
|
||||||
data = DiasporaFederation::Salmon::EncryptedSlap.prepare(post.author, sender_key, post)
|
data = generate_legacy_encrypted_salmon_slap(post, post.author, sender_key, recipient_key)
|
||||||
.generate_xml(recipient_key)
|
|
||||||
|
|
||||||
expect_callback(:receive_entity, kind_of(Entities::StatusMessage), post.author, 1234) do |_, entity|
|
expect_callback(:receive_entity, kind_of(Entities::StatusMessage), post.author, 1234) do |_, entity|
|
||||||
expect(entity.guid).to eq(post.guid)
|
expect(entity.guid).to eq(post.guid)
|
||||||
|
|
|
||||||
|
|
@ -4,137 +4,7 @@ module DiasporaFederation
|
||||||
let(:privkey) { OpenSSL::PKey::RSA.generate(512) } # use small key for speedy specs
|
let(:privkey) { OpenSSL::PKey::RSA.generate(512) } # use small key for speedy specs
|
||||||
let(:recipient_key) { OpenSSL::PKey::RSA.generate(1024) } # use small key for speedy specs
|
let(:recipient_key) { OpenSSL::PKey::RSA.generate(1024) } # use small key for speedy specs
|
||||||
let(:payload) { Entities::TestEntity.new(test: "qwertzuiop") }
|
let(:payload) { Entities::TestEntity.new(test: "qwertzuiop") }
|
||||||
let(:slap_xml) { Salmon::EncryptedSlap.prepare(sender, privkey, payload).generate_xml(recipient_key.public_key) }
|
let(:slap_xml) { generate_legacy_encrypted_salmon_slap(payload, sender, privkey, recipient_key.public_key) }
|
||||||
|
|
||||||
context "generate" do
|
|
||||||
describe ".prepare" do
|
|
||||||
context "sanity" do
|
|
||||||
it "raises an error when the sender is the wrong type" do
|
|
||||||
[1234, true, :symbol, payload, privkey].each do |val|
|
|
||||||
expect {
|
|
||||||
Salmon::EncryptedSlap.prepare(val, privkey, payload)
|
|
||||||
}.to raise_error ArgumentError
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "raises an error when the privkey is the wrong type" do
|
|
||||||
["asdf", 1234, true, :symbol, payload].each do |val|
|
|
||||||
expect {
|
|
||||||
Salmon::EncryptedSlap.prepare(sender, val, payload)
|
|
||||||
}.to raise_error ArgumentError
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "raises an error when the entity is the wrong type" do
|
|
||||||
["asdf", 1234, true, :symbol, privkey].each do |val|
|
|
||||||
expect {
|
|
||||||
Salmon::EncryptedSlap.prepare(sender, privkey, val)
|
|
||||||
}.to raise_error ArgumentError
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ".generate_xml" do
|
|
||||||
let(:ns) { {d: Salmon::XMLNS, me: Salmon::MagicEnvelope::XMLNS} }
|
|
||||||
|
|
||||||
context "sanity" do
|
|
||||||
it "accepts correct params" do
|
|
||||||
expect {
|
|
||||||
Salmon::EncryptedSlap.prepare(sender, privkey, payload).generate_xml(recipient_key.public_key)
|
|
||||||
}.not_to raise_error
|
|
||||||
end
|
|
||||||
|
|
||||||
it "raises an error when the params are the wrong type" do
|
|
||||||
["asdf", 1234, true, :symbol, payload].each do |val|
|
|
||||||
expect {
|
|
||||||
Salmon::EncryptedSlap.prepare(sender, privkey, payload).generate_xml(val)
|
|
||||||
}.to raise_error ArgumentError
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "generates valid xml" do
|
|
||||||
doc = Nokogiri::XML(slap_xml)
|
|
||||||
expect(doc.root.name).to eq("diaspora")
|
|
||||||
expect(doc.at_xpath("d:diaspora/d:encrypted_header", ns).content).to_not be_empty
|
|
||||||
expect(doc.xpath("d:diaspora/me:env", ns)).to have(1).item
|
|
||||||
end
|
|
||||||
|
|
||||||
it "can generate xml for two people" do
|
|
||||||
slap = Salmon::EncryptedSlap.prepare(sender, privkey, payload)
|
|
||||||
|
|
||||||
doc1 = Nokogiri::XML(slap.generate_xml(recipient_key.public_key))
|
|
||||||
enc_header1 = doc1.at_xpath("d:diaspora/d:encrypted_header", ns).content
|
|
||||||
cipher_header1 = JSON.parse(Base64.decode64(enc_header1))
|
|
||||||
header_key1 = JSON.parse(recipient_key.private_decrypt(Base64.decode64(cipher_header1["aes_key"])))
|
|
||||||
decrypted_header1 = Salmon::AES.decrypt(cipher_header1["ciphertext"],
|
|
||||||
Base64.decode64(header_key1["key"]),
|
|
||||||
Base64.decode64(header_key1["iv"]))
|
|
||||||
|
|
||||||
recipient2_key = OpenSSL::PKey::RSA.generate(1024)
|
|
||||||
doc2 = Nokogiri::XML(slap.generate_xml(recipient2_key.public_key))
|
|
||||||
enc_header2 = doc2.at_xpath("d:diaspora/d:encrypted_header", ns).content
|
|
||||||
cipher_header2 = JSON.parse(Base64.decode64(enc_header2))
|
|
||||||
header_key2 = JSON.parse(recipient2_key.private_decrypt(Base64.decode64(cipher_header2["aes_key"])))
|
|
||||||
decrypted_header2 = Salmon::AES.decrypt(cipher_header2["ciphertext"],
|
|
||||||
Base64.decode64(header_key2["key"]),
|
|
||||||
Base64.decode64(header_key2["iv"]))
|
|
||||||
|
|
||||||
expect(enc_header1).not_to eq(enc_header2)
|
|
||||||
expect(header_key1).not_to eq(header_key2)
|
|
||||||
expect(decrypted_header1).to eq(decrypted_header2)
|
|
||||||
expect(doc1.xpath("d:diaspora/me:env", ns).to_xml).to eq(doc2.xpath("d:diaspora/me:env", ns).to_xml)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not add the sender to the magic envelope" do
|
|
||||||
doc = Nokogiri::XML(slap_xml)
|
|
||||||
expect(doc.at_xpath("d:diaspora/me:env/me:sig", ns)["key_id"]).to be_nil
|
|
||||||
end
|
|
||||||
|
|
||||||
context "header" do
|
|
||||||
subject {
|
|
||||||
doc = Nokogiri::XML(slap_xml)
|
|
||||||
doc.at_xpath("d:diaspora/d:encrypted_header", ns).content
|
|
||||||
}
|
|
||||||
let(:cipher_header) { JSON.parse(Base64.decode64(subject)) }
|
|
||||||
let(:header_key) {
|
|
||||||
JSON.parse(recipient_key.private_decrypt(Base64.decode64(cipher_header["aes_key"])))
|
|
||||||
}
|
|
||||||
|
|
||||||
it "encodes the header correctly" do
|
|
||||||
json_header = {}
|
|
||||||
expect {
|
|
||||||
json_header = JSON.parse(Base64.decode64(subject))
|
|
||||||
}.not_to raise_error
|
|
||||||
expect(json_header).to include("aes_key", "ciphertext")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "encrypts the public_key encrypted header correctly" do
|
|
||||||
key = {}
|
|
||||||
expect {
|
|
||||||
key = JSON.parse(recipient_key.private_decrypt(Base64.decode64(cipher_header["aes_key"])))
|
|
||||||
}.not_to raise_error
|
|
||||||
expect(key).to include("key", "iv")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "encrypts the aes encrypted header correctly" do
|
|
||||||
header = ""
|
|
||||||
expect {
|
|
||||||
header = Salmon::AES.decrypt(cipher_header["ciphertext"],
|
|
||||||
Base64.decode64(header_key["key"]),
|
|
||||||
Base64.decode64(header_key["iv"]))
|
|
||||||
}.not_to raise_error
|
|
||||||
header_doc = Nokogiri::XML(header)
|
|
||||||
expect(header_doc.root.name).to eq("decrypted_header")
|
|
||||||
expect(header_doc.xpath("//iv")).to have(1).item
|
|
||||||
expect(header_doc.xpath("//aes_key")).to have(1).item
|
|
||||||
expect(header_doc.xpath("//author_id")).to have(1).item
|
|
||||||
expect(header_doc.at_xpath("//author_id").content).to eq(sender)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ".from_xml" do
|
describe ".from_xml" do
|
||||||
context "sanity" do
|
context "sanity" do
|
||||||
|
|
|
||||||
|
|
@ -80,28 +80,6 @@ module DiasporaFederation
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#encrypt!" do
|
|
||||||
it "encrypts the payload, returning cipher params" do
|
|
||||||
params = envelope.encrypt!
|
|
||||||
expect(params).to include(:key, :iv)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "actually encrypts the payload" do
|
|
||||||
plain_payload = envelope.send(:payload_data)
|
|
||||||
params = envelope.encrypt!
|
|
||||||
encrypted_payload = envelope.send(:payload_data)
|
|
||||||
|
|
||||||
cipher = OpenSSL::Cipher.new(Salmon::AES::CIPHER)
|
|
||||||
cipher.encrypt
|
|
||||||
cipher.iv = params[:iv]
|
|
||||||
cipher.key = params[:key]
|
|
||||||
|
|
||||||
ciphertext = cipher.update(plain_payload) + cipher.final
|
|
||||||
|
|
||||||
expect(Base64.strict_encode64(ciphertext)).to eq(encrypted_payload)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ".unenvelop" do
|
describe ".unenvelop" do
|
||||||
let(:envelope_root) { envelope.envelop(privkey).root }
|
let(:envelope_root) { envelope.envelop(privkey).root }
|
||||||
|
|
||||||
|
|
@ -210,7 +188,7 @@ module DiasporaFederation
|
||||||
expect_callback(:fetch_public_key, sender).and_return(privkey.public_key)
|
expect_callback(:fetch_public_key, sender).and_return(privkey.public_key)
|
||||||
|
|
||||||
env = Salmon::MagicEnvelope.new(payload)
|
env = Salmon::MagicEnvelope.new(payload)
|
||||||
params = env.encrypt!
|
params = encrypt_magic_env(env)
|
||||||
env_xml = env.envelop(privkey).root
|
env_xml = env.envelop(privkey).root
|
||||||
|
|
||||||
magic_env = Salmon::MagicEnvelope.unenvelop(env_xml, sender, params)
|
magic_env = Salmon::MagicEnvelope.unenvelop(env_xml, sender, params)
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,7 @@ module DiasporaFederation
|
||||||
let(:sender) { "test_user@pod.somedomain.tld" }
|
let(:sender) { "test_user@pod.somedomain.tld" }
|
||||||
let(:privkey) { OpenSSL::PKey::RSA.generate(512) } # use small key for speedy specs
|
let(:privkey) { OpenSSL::PKey::RSA.generate(512) } # use small key for speedy specs
|
||||||
let(:payload) { Entities::TestEntity.new(test: "qwertzuiop") }
|
let(:payload) { Entities::TestEntity.new(test: "qwertzuiop") }
|
||||||
let(:slap_xml) {
|
let(:slap_xml) { generate_legacy_salmon_slap(payload, sender, privkey) }
|
||||||
Salmon::Slap.build_xml do |xml|
|
|
||||||
xml.header {
|
|
||||||
xml.author_id(sender)
|
|
||||||
}
|
|
||||||
|
|
||||||
xml.parent << Salmon::MagicEnvelope.new(payload, sender).envelop(privkey).root
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
describe ".from_xml" do
|
describe ".from_xml" do
|
||||||
context "sanity" do
|
context "sanity" do
|
||||||
|
|
|
||||||
66
spec/support/legacy_helper.rb
Normal file
66
spec/support/legacy_helper.rb
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
# This file only exists to generate legacy XMLs to test that we can still parse it.
|
||||||
|
|
||||||
|
def generate_legacy_salmon_slap(entity, sender, sender_privkey)
|
||||||
|
build_salmon_slap_xml do |xml|
|
||||||
|
xml.header {
|
||||||
|
xml.author_id(sender)
|
||||||
|
}
|
||||||
|
|
||||||
|
xml.parent << DiasporaFederation::Salmon::MagicEnvelope.new(entity, sender).envelop(sender_privkey).root
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_legacy_encrypted_salmon_slap(entity, sender, sender_privkey, recipient_pubkey)
|
||||||
|
magic_envelope = DiasporaFederation::Salmon::MagicEnvelope.new(entity)
|
||||||
|
cipher_params = encrypt_magic_env(magic_envelope)
|
||||||
|
|
||||||
|
build_salmon_slap_xml do |xml|
|
||||||
|
xml.encrypted_header(encrypted_header(sender, cipher_params, recipient_pubkey))
|
||||||
|
|
||||||
|
xml.parent << magic_envelope.envelop(sender_privkey).root
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_salmon_slap_xml
|
||||||
|
Nokogiri::XML::Builder.new(encoding: "UTF-8") {|xml|
|
||||||
|
xml.diaspora("xmlns" => DiasporaFederation::Salmon::XMLNS,
|
||||||
|
"xmlns:me" => DiasporaFederation::Salmon::MagicEnvelope::XMLNS) {
|
||||||
|
yield xml
|
||||||
|
}
|
||||||
|
}.to_xml
|
||||||
|
end
|
||||||
|
|
||||||
|
def encrypt_magic_env(magic_env)
|
||||||
|
DiasporaFederation::Salmon::AES.generate_key_and_iv.tap do |key|
|
||||||
|
magic_env.instance_variable_set(
|
||||||
|
"@payload_data", DiasporaFederation::Salmon::AES.encrypt(magic_env.send(:payload_data), key[:key], key[:iv])
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def encrypted_header(author_id, envelope_key, pubkey)
|
||||||
|
data = decrypted_header_xml(author_id, strict_base64_encode(envelope_key))
|
||||||
|
header_key = DiasporaFederation::Salmon::AES.generate_key_and_iv
|
||||||
|
ciphertext = DiasporaFederation::Salmon::AES.encrypt(data, header_key[:key], header_key[:iv])
|
||||||
|
|
||||||
|
json_key = JSON.generate(strict_base64_encode(header_key))
|
||||||
|
encrypted_key = Base64.strict_encode64(pubkey.public_encrypt(json_key))
|
||||||
|
|
||||||
|
json_header = JSON.generate(aes_key: encrypted_key, ciphertext: ciphertext)
|
||||||
|
|
||||||
|
Base64.strict_encode64(json_header)
|
||||||
|
end
|
||||||
|
|
||||||
|
def decrypted_header_xml(author_id, envelope_key)
|
||||||
|
Nokogiri::XML::Builder.new(encoding: "UTF-8") {|xml|
|
||||||
|
xml.decrypted_header {
|
||||||
|
xml.iv(envelope_key[:iv])
|
||||||
|
xml.aes_key(envelope_key[:key])
|
||||||
|
xml.author_id(author_id)
|
||||||
|
}
|
||||||
|
}.to_xml.strip
|
||||||
|
end
|
||||||
|
|
||||||
|
def strict_base64_encode(hash)
|
||||||
|
hash.map {|k, v| [k, Base64.strict_encode64(v)] }.to_h
|
||||||
|
end
|
||||||
Loading…
Reference in a new issue