Class: Salmon::Slap

Inherits:
Object
  • Object
show all
Defined in:
lib/salmon/slap.rb

Direct Known Subclasses

EncryptedSlap

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#aes_keyObject

Returns the value of attribute aes_key


8
9
10
# File 'lib/salmon/slap.rb', line 8

def aes_key
  @aes_key
end

#authorPerson


95
96
97
# File 'lib/salmon/slap.rb', line 95

def author
  @author
end

#author_idObject

Returns the value of attribute author_id


7
8
9
# File 'lib/salmon/slap.rb', line 7

def author_id
  @author_id
end

#ivObject

Returns the value of attribute iv


8
9
10
# File 'lib/salmon/slap.rb', line 8

def iv
  @iv
end

#magic_sigObject

Returns the value of attribute magic_sig


7
8
9
# File 'lib/salmon/slap.rb', line 7

def magic_sig
  @magic_sig
end

#parsed_dataObject

Returns the value of attribute parsed_data


7
8
9
# File 'lib/salmon/slap.rb', line 7

def parsed_data
  @parsed_data
end

Class Method Details

.b64_to_n(str) ⇒ Object

Decode a string containing URL safe Base64 into an integer Example:

MagicSig.b64_to_n('AQAB')
# -> 645537

134
135
136
137
# File 'lib/salmon/slap.rb', line 134

def self.b64_to_n(str)
  packed = decode64url(str)
  packed.unpack('B*')[0].to_i(2)
end

.build_key(n, e) ⇒ Object

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

161
162
163
164
165
166
# File 'lib/salmon/slap.rb', line 161

def self.build_key(n,e)
  key = OpenSSL::PKey::RSA.new
  key.n = n
  key.e = e
  key
end

.create_by_user_and_activity(user, activity) ⇒ Slap


15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/salmon/slap.rb', line 15

def self.create_by_user_and_activity(user, activity)
  salmon = self.new
  salmon.author   = user.person
  aes_key_hash    = user.person.gen_aes_key

  #additional headers
  salmon.aes_key  = aes_key_hash['key']
  salmon.iv       = aes_key_hash['iv']

  salmon.magic_sig = MagicSigEnvelope.create(user, self.payload(activity, user, aes_key_hash))
  salmon
end

.decode64url(str) ⇒ Object

Decode URL-safe-Base64. This implements


104
105
106
107
108
109
110
111
112
113
114
# File 'lib/salmon/slap.rb', line 104

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

.from_xml(xml, receiving_user = nil) ⇒ Object


28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/salmon/slap.rb', line 28

def self.from_xml(xml, receiving_user=nil)
  slap = self.new
  doc = Nokogiri::XML(xml)

  root_doc = doc.search('diaspora')

  ### Header ##
  header_doc       = slap.salmon_header(doc, receiving_user) 
  slap.process_header(header_doc)

  ### Envelope ##
  slap.magic_sig = MagicSigEnvelope.parse(root_doc)

  slap.parsed_data = slap.parse_data(receiving_user)

  slap
end

.parse_key(str) ⇒ Object

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

147
148
149
150
# File 'lib/salmon/slap.rb', line 147

def self.parse_key(str)
  n,e = str.match(/^RSA.([^.]*).([^.]*)$/)[1..2]
  build_key(b64_to_n(n),b64_to_n(e))
end

.payload(activity, user = nil, aes_key_hash = nil) ⇒ String


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

def self.payload(activity, user=nil, aes_key_hash=nil)
  activity
end

Instance Method Details

#header(person) ⇒ String

Wraps plaintext header in <header></header> tags


82
83
84
# File 'lib/salmon/slap.rb', line 82

def header(person)
  "<header>#{plaintext_header}</header>"
end

#parse_data(user = nil) ⇒ String


59
60
61
# File 'lib/salmon/slap.rb', line 59

def parse_data(user=nil)
  Slap.decode64url(self.magic_sig.data)
end

#plaintext_headerString

Generate a plaintext salmon header (unencrypted), sans <header></header> tags


88
89
90
91
92
# File 'lib/salmon/slap.rb', line 88

def plaintext_header
  header ="<author_id>\#{@author.diaspora_handle}</author_id>\n"
end

#process_header(doc) ⇒ String

Takes in a doc of the header and sets the author id returns an empty hash


54
55
56
# File 'lib/salmon/slap.rb', line 54

def process_header(doc)
  self.author_id   = doc.search('author_id').text
end

#salmon_header(doc, user = nil) ⇒ Nokogiri::Doc


64
65
66
# File 'lib/salmon/slap.rb', line 64

def salmon_header(doc, user=nil)
  doc.search('header')
end

#verified_for_key?(public_key) ⇒ Boolean

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

122
123
124
125
126
127
# File 'lib/salmon/slap.rb', line 122

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

#xml_for(person) ⇒ String

note this memoizes the xml, as for every user for unsigned salmon will be the same


70
71
72
73
74
75
76
77
78
# File 'lib/salmon/slap.rb', line 70

def xml_for(person)
  @xml ="<?xml version='1.0' encoding='UTF-8'?>\n<diaspora xmlns=\"https://joindiaspora.com/protocol\" xmlns:me=\"http://salmon-protocol.org/ns/magic-env\">\n  \#{header(person)}\n  \#{@magic_sig.to_xml}\n</diaspora>\n"
end