Class: DiasporaFederation::Salmon::MagicEnvelope

Inherits:
Object
  • Object
show all
Includes:
Logging
Defined in:
lib/diaspora_federation/salmon/magic_envelope.rb

Overview

Represents a Magic Envelope for diaspora* federation messages

When generating a Magic Envelope, an instance of this class is created and the contents are specified on initialization. Optionally, the payload can be encrypted (MagicEnvelope#encrypt!), before the XML is returned (#envelop).

The generated XML appears like so:

<me:env>
  <me:data type="application/xml">{data}</me:data>
  <me:encoding>base64url</me:encoding>
  <me:alg>RSA-SHA256</me:alg>
  <me:sig key_id="{sender}">{signature}</me:sig>
</me:env>

When parsing the XML of an incoming Magic Envelope MagicEnvelope.unenvelop is used.

Constant Summary collapse

ENCODING =

Encoding used for the payload data

"base64url".freeze
ALGORITHM =

Algorithm used for signing the payload data

"RSA-SHA256".freeze
DATA_TYPE =

Mime type describing the payload data

"application/xml".freeze
DIGEST =

Digest instance used for signing

OpenSSL::Digest::SHA256.new
XMLNS =

XML namespace url

"http://salmon-protocol.org/ns/magic-env".freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Logging

included

Constructor Details

#initialize(payload, sender = nil) ⇒ MagicEnvelope

Creates a new instance of MagicEnvelope.

Raises:

  • (ArgumentError)

    if either argument is not of the right type


54
55
56
57
58
59
# File 'lib/diaspora_federation/salmon/magic_envelope.rb', line 54

def initialize(payload, sender=nil)
  raise ArgumentError unless payload.is_a?(Entity)

  @payload = payload
  @sender = sender
end

Instance Attribute Details

#payloadEntity (readonly)

The payload entity of the magic envelope


43
44
45
# File 'lib/diaspora_federation/salmon/magic_envelope.rb', line 43

def payload
  @payload
end

#senderString (readonly)

The sender of the magic envelope


47
48
49
# File 'lib/diaspora_federation/salmon/magic_envelope.rb', line 47

def sender
  @sender
end

Class Method Details

.unenvelop(magic_env, sender = nil, cipher_params = nil) ⇒ Entity

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.

Does some sanity checking to avoid bad surprises…

Raises:

  • (ArgumentError)

    if any of the arguments is of invalid type

  • (InvalidEnvelope)

    if the envelope XML structure is malformed

  • (InvalidSignature)

    if the signature can't be verified

  • (InvalidDataType)

    if the data is missing or unsupported

  • (InvalidEncoding)

    if the data is wrongly encoded or encoding is missing

  • (InvalidAlgorithm)

    if the algorithm is missing or doesn't match

See Also:


100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/diaspora_federation/salmon/magic_envelope.rb', line 100

def self.unenvelop(magic_env, sender=nil, cipher_params=nil)
  raise ArgumentError unless magic_env.instance_of?(Nokogiri::XML::Element)

  validate_envelope(magic_env)
  validate_type(magic_env)
  validate_encoding(magic_env)
  validate_algorithm(magic_env)

  sender ||= sender(magic_env)
  raise InvalidSignature unless signature_valid?(magic_env, sender)

  data = read_and_decrypt_data(magic_env, cipher_params)

  logger.debug "unenvelop message from #{sender}:\n#{data}"

  new(XmlPayload.unpack(Nokogiri::XML(data).root), sender)
end

Instance Method Details

#envelop(privkey) ⇒ Nokogiri::XML::Element

Builds the XML structure for the magic envelope, inserts the ENCODING encoded data and signs the envelope using DIGEST.

Raises:

  • (ArgumentError)

66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/diaspora_federation/salmon/magic_envelope.rb', line 66

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_data), type: DATA_TYPE)
      xml["me"].encoding(ENCODING)
      xml["me"].alg(ALGORITHM)
      xml["me"].sig(Base64.urlsafe_encode64(sign(privkey)), key_id)
    }
  }
end