improve documentation
This commit is contained in:
parent
eef6ca19d2
commit
dc0f786b2c
8 changed files with 70 additions and 24 deletions
|
|
@ -32,6 +32,8 @@ module DiasporaFederation
|
||||||
end
|
end
|
||||||
|
|
||||||
# Generates XML and updates signatures
|
# Generates XML and updates signatures
|
||||||
|
# @see Entity#to_xml
|
||||||
|
# @return [Nokogiri::XML::Element] root element containing properties as child elements
|
||||||
def to_xml
|
def to_xml
|
||||||
entity_xml.tap do |xml|
|
entity_xml.tap do |xml|
|
||||||
hash = to_h
|
hash = to_h
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ module DiasporaFederation
|
||||||
# {http://www.rubydoc.info/gems/nokogiri/Nokogiri/XML/Element Nokogiri::XML::Element}s
|
# {http://www.rubydoc.info/gems/nokogiri/Nokogiri/XML/Element Nokogiri::XML::Element}s
|
||||||
#
|
#
|
||||||
# @see Nokogiri::XML::Node.to_xml
|
# @see Nokogiri::XML::Node.to_xml
|
||||||
# @see Salmon::XmlPayload.pack
|
# @see XmlPayload#pack
|
||||||
#
|
#
|
||||||
# @return [Nokogiri::XML::Element] root element containing properties as child elements
|
# @return [Nokogiri::XML::Element] root element containing properties as child elements
|
||||||
def to_xml
|
def to_xml
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,11 @@ module DiasporaFederation
|
||||||
# @param [String] key AES key
|
# @param [String] key AES key
|
||||||
# @param [String] iv AES initialization vector
|
# @param [String] iv AES initialization vector
|
||||||
# @return [String] base64 encoded ciphertext
|
# @return [String] base64 encoded ciphertext
|
||||||
|
# @raise [ArgumentError] if any of the arguments is missing or not the correct type
|
||||||
def self.encrypt(data, key, iv)
|
def self.encrypt(data, key, iv)
|
||||||
raise ArgumentError unless data.instance_of?(String)
|
raise ArgumentError unless data.instance_of?(String) &&
|
||||||
|
key.instance_of?(String) &&
|
||||||
|
iv.instance_of?(String)
|
||||||
|
|
||||||
cipher = OpenSSL::Cipher.new(CIPHER)
|
cipher = OpenSSL::Cipher.new(CIPHER)
|
||||||
cipher.encrypt
|
cipher.encrypt
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,8 @@ module DiasporaFederation
|
||||||
|
|
||||||
# Creates a new instance of MagicEnvelope.
|
# Creates a new instance of MagicEnvelope.
|
||||||
#
|
#
|
||||||
# @param rsa_pkey [OpenSSL::PKey::RSA] private key used for signing
|
# @param [OpenSSL::PKey::RSA] rsa_pkey private key used for signing
|
||||||
# @param payload [Entity] Entity instance
|
# @param [Entity] payload Entity instance
|
||||||
# @raise [ArgumentError] if either argument is not of the right type
|
# @raise [ArgumentError] if either argument is not of the right type
|
||||||
def initialize(rsa_pkey, payload)
|
def initialize(rsa_pkey, payload)
|
||||||
raise ArgumentError unless rsa_pkey.instance_of?(OpenSSL::PKey::RSA) &&
|
raise ArgumentError unless rsa_pkey.instance_of?(OpenSSL::PKey::RSA) &&
|
||||||
|
|
@ -55,7 +55,7 @@ module DiasporaFederation
|
||||||
# Builds the XML structure for the magic envelope, inserts the {ENCODING}
|
# Builds the XML structure for the magic envelope, inserts the {ENCODING}
|
||||||
# encoded data and signs the envelope using {DIGEST}.
|
# encoded data and signs the envelope using {DIGEST}.
|
||||||
#
|
#
|
||||||
# @return [Nokogiri::XML::Element] XML root node
|
# @param [Nokogiri::XML::Builder] xml Salmon XML builder
|
||||||
def envelop(xml)
|
def envelop(xml)
|
||||||
xml["me"].env {
|
xml["me"].env {
|
||||||
xml["me"].data(Base64.urlsafe_encode64(@payload), type: DATA_TYPE)
|
xml["me"].data(Base64.urlsafe_encode64(@payload), type: DATA_TYPE)
|
||||||
|
|
@ -71,7 +71,8 @@ module DiasporaFederation
|
||||||
# This must happen after the MagicEnvelope instance was created and before
|
# This must happen after the MagicEnvelope instance was created and before
|
||||||
# {MagicEnvelope#envelop} is called.
|
# {MagicEnvelope#envelop} is called.
|
||||||
#
|
#
|
||||||
# @see Salmon.aes_encrypt
|
# @see AES#generate_key_and_iv
|
||||||
|
# @see AES#encrypt
|
||||||
#
|
#
|
||||||
# @return [Hash] AES key and iv. E.g.: { key: "...", iv: "..." }
|
# @return [Hash] AES key and iv. E.g.: { key: "...", iv: "..." }
|
||||||
def encrypt!
|
def encrypt!
|
||||||
|
|
@ -85,8 +86,8 @@ module DiasporaFederation
|
||||||
#
|
#
|
||||||
# Does some sanity checking to avoid bad surprises...
|
# Does some sanity checking to avoid bad surprises...
|
||||||
#
|
#
|
||||||
# @see XmlPayload.unpack
|
# @see XmlPayload#unpack
|
||||||
# @see Salmon.aes_decrypt
|
# @see AES#decrypt
|
||||||
#
|
#
|
||||||
# @param [Nokogiri::XML::Element] magic_env XML root node of a magic envelope
|
# @param [Nokogiri::XML::Element] magic_env XML root node of a magic envelope
|
||||||
# @param [OpenSSL::PKey::RSA] rsa_pubkey public key to verify the signature
|
# @param [OpenSSL::PKey::RSA] rsa_pubkey public key to verify the signature
|
||||||
|
|
@ -118,6 +119,8 @@ module DiasporaFederation
|
||||||
private
|
private
|
||||||
|
|
||||||
# create the signature for all fields according to specification
|
# create the signature for all fields according to specification
|
||||||
|
#
|
||||||
|
# @return [String] the signature
|
||||||
def signature
|
def signature
|
||||||
subject = self.class.sig_subject([@payload,
|
subject = self.class.sig_subject([@payload,
|
||||||
DATA_TYPE,
|
DATA_TYPE,
|
||||||
|
|
@ -126,7 +129,7 @@ module DiasporaFederation
|
||||||
@rsa_pkey.sign(DIGEST, subject)
|
@rsa_pkey.sign(DIGEST, subject)
|
||||||
end
|
end
|
||||||
|
|
||||||
# @param [Nokogiri::XML::Element] env envelope
|
# @param [Nokogiri::XML::Element] env magic envelope XML
|
||||||
def self.envelope_valid?(env)
|
def self.envelope_valid?(env)
|
||||||
(env.instance_of?(Nokogiri::XML::Element) &&
|
(env.instance_of?(Nokogiri::XML::Element) &&
|
||||||
env.name == "env" &&
|
env.name == "env" &&
|
||||||
|
|
@ -137,8 +140,9 @@ module DiasporaFederation
|
||||||
end
|
end
|
||||||
private_class_method :envelope_valid?
|
private_class_method :envelope_valid?
|
||||||
|
|
||||||
# @param [Nokogiri::XML::Element] env
|
# @param [Nokogiri::XML::Element] env magic envelope XML
|
||||||
# @param [OpenSSL::PKey::RSA] pkey public key
|
# @param [OpenSSL::PKey::RSA] pkey public key
|
||||||
|
# @return [Boolean]
|
||||||
def self.signature_valid?(env, pkey)
|
def self.signature_valid?(env, pkey)
|
||||||
subject = sig_subject([Base64.urlsafe_decode64(env.at_xpath("me:data").content),
|
subject = sig_subject([Base64.urlsafe_decode64(env.at_xpath("me:data").content),
|
||||||
env.at_xpath("me:data")["type"],
|
env.at_xpath("me:data")["type"],
|
||||||
|
|
@ -154,20 +158,28 @@ module DiasporaFederation
|
||||||
# the given array should consist of the data, data_type (mimetype), encoding
|
# the given array should consist of the data, data_type (mimetype), encoding
|
||||||
# and the algorithm
|
# and the algorithm
|
||||||
# @param [Array<String>] data_arr
|
# @param [Array<String>] data_arr
|
||||||
|
# @return [String] signature subject
|
||||||
def self.sig_subject(data_arr)
|
def self.sig_subject(data_arr)
|
||||||
data_arr.map {|i| Base64.urlsafe_encode64(i) }.join(".")
|
data_arr.map {|i| Base64.urlsafe_encode64(i) }.join(".")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @param [Nokogiri::XML::Element] magic_env magic envelope XML
|
||||||
|
# @return [Boolean]
|
||||||
def self.encoding_valid?(magic_env)
|
def self.encoding_valid?(magic_env)
|
||||||
magic_env.at_xpath("me:encoding").content == ENCODING
|
magic_env.at_xpath("me:encoding").content == ENCODING
|
||||||
end
|
end
|
||||||
private_class_method :encoding_valid?
|
private_class_method :encoding_valid?
|
||||||
|
|
||||||
|
# @param [Nokogiri::XML::Element] magic_env magic envelope XML
|
||||||
|
# @return [Boolean]
|
||||||
def self.algorithm_valid?(magic_env)
|
def self.algorithm_valid?(magic_env)
|
||||||
magic_env.at_xpath("me:alg").content == ALGORITHM
|
magic_env.at_xpath("me:alg").content == ALGORITHM
|
||||||
end
|
end
|
||||||
private_class_method :algorithm_valid?
|
private_class_method :algorithm_valid?
|
||||||
|
|
||||||
|
# @param [Nokogiri::XML::Element] magic_env magic envelope XML
|
||||||
|
# @param [Hash] cipher_params hash containing the key and iv
|
||||||
|
# @return [String] data
|
||||||
def self.read_and_decrypt_data(magic_env, cipher_params)
|
def self.read_and_decrypt_data(magic_env, cipher_params)
|
||||||
data = Base64.urlsafe_decode64(magic_env.at_xpath("me:data").content)
|
data = Base64.urlsafe_decode64(magic_env.at_xpath("me:data").content)
|
||||||
data = AES.decrypt(data, cipher_params[:key], cipher_params[:iv]) unless cipher_params.nil?
|
data = AES.decrypt(data, cipher_params[:key], cipher_params[:iv]) unless cipher_params.nil?
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,11 @@ module DiasporaFederation
|
||||||
end
|
end
|
||||||
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
|
def self.build_xml
|
||||||
builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
|
builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
|
||||||
xml.diaspora("xmlns" => Salmon::XMLNS, "xmlns:me" => MagicEnvelope::XMLNS) {
|
xml.diaspora("xmlns" => Salmon::XMLNS, "xmlns:me" => MagicEnvelope::XMLNS) {
|
||||||
|
|
@ -102,6 +107,9 @@ module DiasporaFederation
|
||||||
builder.to_xml
|
builder.to_xml
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Parses the magic envelop from the document.
|
||||||
|
#
|
||||||
|
# @param [Nokogiri::XML::Document] doc Salmon XML Document
|
||||||
def add_magic_env_from_doc(doc)
|
def add_magic_env_from_doc(doc)
|
||||||
@magic_envelope = doc.at_xpath("d:diaspora/me:env", Slap::NS).tap do |env|
|
@magic_envelope = doc.at_xpath("d:diaspora/me:env", Slap::NS).tap do |env|
|
||||||
raise MissingMagicEnvelope if env.nil?
|
raise MissingMagicEnvelope if env.nil?
|
||||||
|
|
|
||||||
|
|
@ -82,18 +82,18 @@ module DiasporaFederation
|
||||||
# Works recursively on nested Entities and Arrays thereof.
|
# Works recursively on nested Entities and Arrays thereof.
|
||||||
#
|
#
|
||||||
# @param [Class] klass entity class
|
# @param [Class] klass entity class
|
||||||
# @param [Nokogiri::XML::Element] node xml nodes
|
# @param [Nokogiri::XML::Element] root_node xml nodes
|
||||||
# @return [Entity] instance
|
# @return [Entity] instance
|
||||||
def self.populate_entity(klass, node)
|
def self.populate_entity(klass, root_node)
|
||||||
# Use all known properties to build the Entity. All other elements are respected
|
# Use all known properties to build the Entity. All other elements are respected
|
||||||
# and attached to resulted hash as string. It is intended to build a hash
|
# and attached to resulted hash as string. It is intended to build a hash
|
||||||
# invariable of an Entity definition, in order to support receiving objects
|
# invariable of an Entity definition, in order to support receiving objects
|
||||||
# from the future versions of Diaspora, where new elements may have been added.
|
# from the future versions of Diaspora, where new elements may have been added.
|
||||||
data = node.element_children.map { |child|
|
data = root_node.element_children.map { |child|
|
||||||
xml_name = child.name
|
xml_name = child.name
|
||||||
property = klass.class_props.find {|prop| prop[:xml_name].to_s == xml_name }
|
property = klass.class_props.find {|prop| prop[:xml_name].to_s == xml_name }
|
||||||
if property
|
if property
|
||||||
parse_element_from_node(property[:name], property[:type], xml_name, node)
|
parse_element_from_node(property[:name], property[:type], xml_name, root_node)
|
||||||
else
|
else
|
||||||
[xml_name, child.text]
|
[xml_name, child.text]
|
||||||
end
|
end
|
||||||
|
|
@ -105,6 +105,11 @@ module DiasporaFederation
|
||||||
end
|
end
|
||||||
private_class_method :populate_entity
|
private_class_method :populate_entity
|
||||||
|
|
||||||
|
# @param [Symbol] name property name
|
||||||
|
# @param [Class] type target type to parse
|
||||||
|
# @param [String] xml_name xml tag to parse
|
||||||
|
# @param [Nokogiri::XML::Element] node XML node to parse
|
||||||
|
# @return [Array<Symbol, Object>] parsed data
|
||||||
def self.parse_element_from_node(name, type, xml_name, node)
|
def self.parse_element_from_node(name, type, xml_name, node)
|
||||||
if type == String
|
if type == String
|
||||||
[name, parse_string_from_node(xml_name, node)]
|
[name, parse_string_from_node(xml_name, node)]
|
||||||
|
|
@ -117,26 +122,35 @@ module DiasporaFederation
|
||||||
private_class_method :parse_element_from_node
|
private_class_method :parse_element_from_node
|
||||||
|
|
||||||
# create simple entry in data hash
|
# create simple entry in data hash
|
||||||
|
#
|
||||||
|
# @param [String] name xml tag to parse
|
||||||
|
# @param [Nokogiri::XML::Element] root_node XML root_node to parse
|
||||||
# @return [String] data
|
# @return [String] data
|
||||||
def self.parse_string_from_node(name, node)
|
def self.parse_string_from_node(name, root_node)
|
||||||
n = node.xpath(name.to_s)
|
node = root_node.xpath(name.to_s)
|
||||||
n.first.text if n.any?
|
node.first.text if node.any?
|
||||||
end
|
end
|
||||||
private_class_method :parse_string_from_node
|
private_class_method :parse_string_from_node
|
||||||
|
|
||||||
# create an entry in the data hash for the nested entity
|
# create an entry in the data hash for the nested entity
|
||||||
|
#
|
||||||
|
# @param [Class] type target type to parse
|
||||||
|
# @param [Nokogiri::XML::Element] root_node XML node to parse
|
||||||
# @return [Entity] parsed child entity
|
# @return [Entity] parsed child entity
|
||||||
def self.parse_entity_from_node(type, node)
|
def self.parse_entity_from_node(type, root_node)
|
||||||
n = node.xpath(type.entity_name)
|
node = root_node.xpath(type.entity_name)
|
||||||
populate_entity(type, n.first) if n.any?
|
populate_entity(type, node.first) if node.any?
|
||||||
end
|
end
|
||||||
private_class_method :parse_entity_from_node
|
private_class_method :parse_entity_from_node
|
||||||
|
|
||||||
# collect all nested children of that type and create an array in the data hash
|
# collect all nested children of that type and create an array in the data hash
|
||||||
|
#
|
||||||
|
# @param [Array<Class>] type target type to parse
|
||||||
|
# @param [Nokogiri::XML::Element] root_node XML node to parse
|
||||||
# @return [Array<Entity>] array with parsed child entities
|
# @return [Array<Entity>] array with parsed child entities
|
||||||
def self.parse_array_from_node(type, node)
|
def self.parse_array_from_node(type, root_node)
|
||||||
n = node.xpath(type.first.entity_name)
|
node = root_node.xpath(type.first.entity_name)
|
||||||
n.map {|child| populate_entity(type.first, child) }
|
node.map {|child| populate_entity(type.first, child) }
|
||||||
end
|
end
|
||||||
private_class_method :parse_array_from_node
|
private_class_method :parse_array_from_node
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,10 @@ module DiasporaFederation
|
||||||
# this module defines operations of signing an arbitrary hash with an arbitrary key
|
# this module defines operations of signing an arbitrary hash with an arbitrary key
|
||||||
module Signing
|
module Signing
|
||||||
extend Logging
|
extend Logging
|
||||||
|
|
||||||
|
# Sign the data with the key
|
||||||
|
#
|
||||||
|
# @param [Hash] hash data to sign
|
||||||
# @param [OpenSSL::PKey::RSA] key An RSA key
|
# @param [OpenSSL::PKey::RSA] key An RSA key
|
||||||
# @return [String] A Base64 encoded signature of #signable_string with key
|
# @return [String] A Base64 encoded signature of #signable_string with key
|
||||||
def self.sign_with_key(hash, key)
|
def self.sign_with_key(hash, key)
|
||||||
|
|
@ -17,6 +21,7 @@ module DiasporaFederation
|
||||||
|
|
||||||
# Check that signature is a correct signature
|
# Check that signature is a correct signature
|
||||||
#
|
#
|
||||||
|
# @param [Hash] hash data to verify
|
||||||
# @param [String] signature The signature to be verified.
|
# @param [String] signature The signature to be verified.
|
||||||
# @param [OpenSSL::PKey::RSA] key An RSA key
|
# @param [OpenSSL::PKey::RSA] key An RSA key
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
|
|
@ -40,6 +45,8 @@ module DiasporaFederation
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
# @param [Hash] hash data to sign
|
||||||
|
# @return [String] signature data string
|
||||||
def self.signable_string(hash)
|
def self.signable_string(hash)
|
||||||
hash.map { |name, value|
|
hash.map { |name, value|
|
||||||
value.to_s unless name.match(/signature/)
|
value.to_s unless name.match(/signature/)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
require "diaspora_federation/test/factories"
|
require "diaspora_federation/test/factories"
|
||||||
|
|
||||||
module DiasporaFederation
|
module DiasporaFederation
|
||||||
# This module incapsulates helper functions maybe wanted by a testsuite of a diaspora_federation gem user application
|
# This module encapsulates helper functions maybe wanted by a testsuite of a diaspora_federation gem user application
|
||||||
module Test
|
module Test
|
||||||
# Sort hash according to an entity class's property sequence.
|
# Sort hash according to an entity class's property sequence.
|
||||||
# This is used for rspec tests in order to generate correct input hash to
|
# This is used for rspec tests in order to generate correct input hash to
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue