oydid 0.5.4 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/oydid/basic.rb +255 -12
- data/lib/oydid/didcomm.rb +2 -2
- data/lib/oydid/log.rb +194 -42
- data/lib/oydid/vc.rb +4 -2
- data/lib/oydid.rb +499 -184
- metadata +102 -102
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6e4098a11373a9b648447adbc7f6ec7b89d0efced1bb920080797dfdc5d17de
|
4
|
+
data.tar.gz: bf33e0ddd9abd26a04d92fa945db9183f87000e246f154aa509c55e9b5f4aefd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6175bb5b1d28443b26573754dd92f97094a7c139d032252c541a73dbd5019028466847b9602b380cd1ca814eeb3e7843576f7a86a77808a5268af62fe89dfba7
|
7
|
+
data.tar.gz: a719e0d4c5530340be4ad4a284ffadd46924db95a81c0212fb61e38243cac6a133bf8568ed6407a54d026502048bb06394f5e737f12e0ad588b65c43411bb046
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.6
|
data/lib/oydid/basic.rb
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
class Hash
|
5
|
+
def except(*keys)
|
6
|
+
self.reject { |key, _| keys.include?(key) }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
4
10
|
class Oydid
|
5
11
|
|
6
12
|
# basic functions ---------------------------
|
7
|
-
# %w[multibases multihashes rbnacl json].each { |f| require f }
|
13
|
+
# %w[multibases multihashes rbnacl json multicodecs].each { |f| require f }
|
8
14
|
def self.multi_encode(message, options)
|
9
15
|
method = options[:encode] || DEFAULT_ENCODING rescue DEFAULT_ENCODING
|
10
16
|
case method
|
@@ -54,7 +60,11 @@ class Oydid
|
|
54
60
|
end
|
55
61
|
|
56
62
|
def self.get_digest(message)
|
57
|
-
|
63
|
+
decoded_message, error = Oydid.multi_decode(message)
|
64
|
+
if decoded_message.nil?
|
65
|
+
return [nil, error]
|
66
|
+
end
|
67
|
+
retVal = Multihashes.decode decoded_message
|
58
68
|
if retVal[:hash_function].to_s != ""
|
59
69
|
return [retVal[:hash_function].to_s, ""]
|
60
70
|
end
|
@@ -94,7 +104,7 @@ class Oydid
|
|
94
104
|
end
|
95
105
|
|
96
106
|
# key management ----------------------------
|
97
|
-
def self.generate_private_key(input, method = "ed25519-priv", options)
|
107
|
+
def self.generate_private_key(input, method = "ed25519-priv", options = {})
|
98
108
|
begin
|
99
109
|
omc = Multicodecs[method].code
|
100
110
|
rescue
|
@@ -104,15 +114,18 @@ class Oydid
|
|
104
114
|
case Multicodecs[method].name
|
105
115
|
when 'ed25519-priv'
|
106
116
|
if input != ""
|
107
|
-
raw_key = Ed25519::SigningKey.new(RbNaCl::Hash.sha256(input))
|
117
|
+
raw_key = Ed25519::SigningKey.new(RbNaCl::Hash.sha256(input))
|
108
118
|
else
|
109
|
-
raw_key = Ed25519::SigningKey.generate
|
119
|
+
raw_key = Ed25519::SigningKey.generate
|
110
120
|
end
|
121
|
+
raw_key = raw_key.to_bytes
|
122
|
+
length = raw_key.bytesize
|
111
123
|
else
|
112
124
|
return [nil, "unsupported key codec"]
|
113
125
|
end
|
114
|
-
|
126
|
+
|
115
127
|
encoded = multi_encode([omc, length, raw_key].pack("SCa#{length}"), options)
|
128
|
+
# encoded = multi_encode(raw_key.to_bytes, options)
|
116
129
|
if encoded.first.nil?
|
117
130
|
return [nil, encoded.last]
|
118
131
|
else
|
@@ -120,7 +133,7 @@ class Oydid
|
|
120
133
|
end
|
121
134
|
end
|
122
135
|
|
123
|
-
def self.public_key(private_key, options, method = "ed25519-pub")
|
136
|
+
def self.public_key(private_key, options = {}, method = "ed25519-pub")
|
124
137
|
code, length, digest = multi_decode(private_key).first.unpack('SCa*')
|
125
138
|
case Multicodecs[code].name
|
126
139
|
when 'ed25519-priv'
|
@@ -132,6 +145,7 @@ class Oydid
|
|
132
145
|
else
|
133
146
|
return [nil, "unsupported key codec"]
|
134
147
|
end
|
148
|
+
# encoded = multi_encode(public_key.to_bytes, options)
|
135
149
|
length = public_key.to_bytes.bytesize
|
136
150
|
encoded = multi_encode([Multicodecs[method].code, length, public_key].pack("CCa#{length}"), options)
|
137
151
|
if encoded.first.nil?
|
@@ -144,6 +158,29 @@ class Oydid
|
|
144
158
|
end
|
145
159
|
end
|
146
160
|
|
161
|
+
def self.getPrivateKey(enc, pwd, dsk, dfl, options)
|
162
|
+
if enc.to_s == "" # usually read from options[:doc_enc]
|
163
|
+
if pwd.to_s == "" # usually read from options[:doc_pwd]
|
164
|
+
if dsk.to_s == "" # usually read from options[:doc_key]
|
165
|
+
if dfl.to_s == "" # default file name for key
|
166
|
+
return [nil, "no reference"]
|
167
|
+
else
|
168
|
+
privateKey, msg = read_private_key(dfl.to_s, options)
|
169
|
+
end
|
170
|
+
else
|
171
|
+
privateKey, msg = read_private_key(dsk.to_s, options)
|
172
|
+
end
|
173
|
+
else
|
174
|
+
privateKey, msg = generate_private_key(pwd, 'ed25519-priv', options)
|
175
|
+
end
|
176
|
+
else
|
177
|
+
privateKey, msg = decode_private_key(enc.to_s, options)
|
178
|
+
end
|
179
|
+
return [privateKey, msg]
|
180
|
+
end
|
181
|
+
|
182
|
+
# if the identifier is already the public key there is no validation if it is a valid key
|
183
|
+
# (this is a privacy-preserving feature)
|
147
184
|
def self.getPubKeyFromDID(did)
|
148
185
|
identifier = did.split(LOCATION_PREFIX).first.split(CGI.escape LOCATION_PREFIX).first rescue did
|
149
186
|
identifier = identifier.delete_prefix("did:oyd:")
|
@@ -166,6 +203,52 @@ class Oydid
|
|
166
203
|
end
|
167
204
|
end
|
168
205
|
|
206
|
+
# available key_types
|
207
|
+
# * doc - document key
|
208
|
+
# * rev - revocation key
|
209
|
+
def self.getDelegatedPubKeysFromDID(did, key_type = "doc")
|
210
|
+
# retrieve DID
|
211
|
+
did_document, msg = read(did, {})
|
212
|
+
keys, msg = getDelegatedPubKeysFromFullDidDocument(did_document, key_type)
|
213
|
+
if keys.nil?
|
214
|
+
return [nil, msg]
|
215
|
+
else
|
216
|
+
return [keys, ""]
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def self.getDelegatedPubKeysFromFullDidDocument(did_document, key_type = "doc")
|
221
|
+
# get current public key
|
222
|
+
case key_type
|
223
|
+
when "doc"
|
224
|
+
keys = [did_document["doc"]["key"].split(":").first] rescue nil
|
225
|
+
when "rev"
|
226
|
+
keys = [did_document["doc"]["key"].split(":").last] rescue nil
|
227
|
+
else
|
228
|
+
return [nil, "invalid key type: " + key_type]
|
229
|
+
end
|
230
|
+
if keys.nil?
|
231
|
+
return [nil, "cannot retrieve current key"]
|
232
|
+
end
|
233
|
+
|
234
|
+
# travers through log and get active delegation public keys
|
235
|
+
log = did_document["log"]
|
236
|
+
log.each do |item|
|
237
|
+
if item["op"] == 5 # DELEGATE
|
238
|
+
# !!!OPEN: check if log entry is confirmed / referenced in a termination entry
|
239
|
+
item_keys = item["doc"]
|
240
|
+
if key_type == "doc" && item_keys[0..3] == "doc:"
|
241
|
+
keys << item_keys[4-item_keys.length..]
|
242
|
+
elsif key_type == "rev" && item_keys[0..3] == "rev:"
|
243
|
+
keys << item_keys[4-item_keys.length..]
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end unless log.nil?
|
247
|
+
|
248
|
+
# return array
|
249
|
+
return [keys.uniq, ""]
|
250
|
+
end
|
251
|
+
|
169
252
|
def self.sign(message, private_key, options)
|
170
253
|
code, length, digest = multi_decode(private_key).first.unpack('SCa*')
|
171
254
|
case Multicodecs[code].name
|
@@ -203,7 +286,7 @@ class Oydid
|
|
203
286
|
end
|
204
287
|
end
|
205
288
|
|
206
|
-
def self.encrypt(message, public_key, options)
|
289
|
+
def self.encrypt(message, public_key, options = {})
|
207
290
|
begin
|
208
291
|
code, length, digest = multi_decode(public_key).first.unpack('CCa*')
|
209
292
|
case Multicodecs[code].name
|
@@ -229,7 +312,7 @@ class Oydid
|
|
229
312
|
end
|
230
313
|
end
|
231
314
|
|
232
|
-
def self.decrypt(message, private_key, options)
|
315
|
+
def self.decrypt(message, private_key, options = {})
|
233
316
|
begin
|
234
317
|
cipher = [JSON.parse(message)["value"]].pack('H*')
|
235
318
|
nonce = [JSON.parse(message)["nonce"]].pack('H*')
|
@@ -250,10 +333,160 @@ class Oydid
|
|
250
333
|
end
|
251
334
|
end
|
252
335
|
|
336
|
+
# key="812b578d2e357270cbbd26a9dd44f93e5c8a3b44462e271348ce8f742dfe08144d06fd1f64d5a15c5b21564695d0dca9d65af322e8f96ef394400fe255d288cf"
|
337
|
+
def jweh(key)
|
338
|
+
pub_key=key[-64..-1]
|
339
|
+
prv_key=key[0..-65]
|
340
|
+
|
341
|
+
hex_pub=pub_key
|
342
|
+
bin_pub=[hex_pub].pack('H*')
|
343
|
+
int_pub=RbNaCl::PublicKey.new(bin_pub)
|
344
|
+
len_pub=int_pub.to_bytes.bytesize
|
345
|
+
enc_pub=Oydid.multi_encode([Multicodecs["x25519-pub"].code,len_pub,int_pub].pack("CCa#{len_pub}"),{}).first
|
346
|
+
|
347
|
+
hex_prv=prv_key
|
348
|
+
bin_prv=[hex_prv].pack('H*')
|
349
|
+
int_prv=RbNaCl::PrivateKey.new(bin_prv)
|
350
|
+
len_prv=int_prv.to_bytes.bytesize
|
351
|
+
enc_prv=Oydid.multi_encode([Multicodecs["ed25519-priv"].code,len_prv,int_prv].pack("SCa#{len_prv}"),{}).first
|
352
|
+
return [enc_pub, enc_prv]
|
353
|
+
end
|
354
|
+
|
355
|
+
# public_key=jweh(key).first
|
356
|
+
# require 'oydid'
|
357
|
+
# message="hallo"
|
358
|
+
# public_key="z6Mv4uEoFYJ369NoE9xUzxG5sm8KpPnvHX6YH6GsYFGSQ32J"
|
359
|
+
# jwe=Oydid.encryptJWE(message, public_key).first
|
360
|
+
def self.encryptJWE(message, public_key, options = {})
|
361
|
+
|
362
|
+
jwe_header = {"enc":"XC20P"}
|
363
|
+
recipient_alg = 'ECDH-ES+XC20PKW'
|
364
|
+
|
365
|
+
# Content Encryption ---
|
366
|
+
# random nonce for XChaCha20-Poly1305: uses a 192-bit nonce (24 bytes)
|
367
|
+
cnt_nnc = RbNaCl::Random.random_bytes(RbNaCl::AEAD::XChaCha20Poly1305IETF.nonce_bytes)
|
368
|
+
# random key for XChaCha20-Poly1305: uses a 256-bit key (32 bytes)
|
369
|
+
cnt_key = RbNaCl::Random.random_bytes(RbNaCl::AEAD::XChaCha20Poly1305IETF.key_bytes)
|
370
|
+
# addtional data
|
371
|
+
cnt_aad = jwe_header.to_json
|
372
|
+
# setup XChaCha20-Poly1305 for Authenticated Encryption with Associated Data (AEAD)
|
373
|
+
cnt_aead = RbNaCl::AEAD::XChaCha20Poly1305IETF.new(cnt_key)
|
374
|
+
# encrypt
|
375
|
+
msg_enc = cnt_aead.encrypt(cnt_nnc, message, cnt_aad)
|
376
|
+
cnt_enc = msg_enc[0...-cnt_aead.tag_bytes]
|
377
|
+
cnt_tag = msg_enc[-cnt_aead.tag_bytes .. -1]
|
378
|
+
|
379
|
+
# Key Encryption ---
|
380
|
+
snd_prv = RbNaCl::PrivateKey.generate
|
381
|
+
code, length, digest = Oydid.multi_decode(public_key).first.unpack('CCa*')
|
382
|
+
buffer = RbNaCl::Util.zeros(RbNaCl::Boxes::Curve25519XSalsa20Poly1305::PublicKey::BYTES)
|
383
|
+
RbNaCl::Signatures::Ed25519::VerifyKey.crypto_sign_ed25519_pk_to_curve25519(buffer, digest)
|
384
|
+
shared_secret = RbNaCl::GroupElement.new(buffer).mult(snd_prv.to_bytes)
|
385
|
+
jwe_const = [0, 0, 0, 1] +
|
386
|
+
shared_secret.to_bytes.unpack('C*') +
|
387
|
+
[0,0,0,15] +
|
388
|
+
recipient_alg.bytes +
|
389
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
|
390
|
+
kek = RbNaCl::Hash.sha256(jwe_const.pack('C*'))
|
391
|
+
snd_nnc = RbNaCl::Random.random_bytes(RbNaCl::AEAD::XChaCha20Poly1305IETF.nonce_bytes)
|
392
|
+
snd_aead = RbNaCl::AEAD::XChaCha20Poly1305IETF.new(kek)
|
393
|
+
snd_enc = snd_aead.encrypt(snd_nnc, cnt_key, nil)
|
394
|
+
snd_key = snd_enc[0...-snd_aead.tag_bytes]
|
395
|
+
snd_aut = snd_enc[-snd_aead.tag_bytes .. -1]
|
396
|
+
|
397
|
+
# create JWE ---
|
398
|
+
jwe_protected = Base64.urlsafe_encode64(jwe_header.to_json).delete("=")
|
399
|
+
jwe_encrypted_key = Base64.urlsafe_encode64(snd_key).delete("=")
|
400
|
+
jwe_init_vector = Base64.urlsafe_encode64(cnt_nnc).delete("=")
|
401
|
+
jwe_cipher_text = Base64.urlsafe_encode64(cnt_enc).delete("=")
|
402
|
+
jwe_auth_tag = Base64.urlsafe_encode64(cnt_tag).delete("=")
|
403
|
+
rcp_nnc_enc = Base64.urlsafe_encode64(snd_nnc).delete("=")
|
404
|
+
rcp_tag_enc = Base64.urlsafe_encode64(snd_aut).delete("=")
|
405
|
+
|
406
|
+
jwe_full = {
|
407
|
+
protected: jwe_protected,
|
408
|
+
iv: jwe_init_vector,
|
409
|
+
ciphertext: jwe_cipher_text,
|
410
|
+
tag: jwe_auth_tag,
|
411
|
+
recipients: [
|
412
|
+
{
|
413
|
+
encrypted_key: jwe_encrypted_key,
|
414
|
+
header: {
|
415
|
+
alg: recipient_alg,
|
416
|
+
iv: rcp_nnc_enc,
|
417
|
+
tag: rcp_tag_enc,
|
418
|
+
epk: {
|
419
|
+
kty: "OKP",
|
420
|
+
crv: "X25519",
|
421
|
+
x: Base64.urlsafe_encode64(snd_prv.public_key.to_bytes).delete("=")
|
422
|
+
}
|
423
|
+
}
|
424
|
+
}
|
425
|
+
]
|
426
|
+
}
|
427
|
+
|
428
|
+
jwe = jwe_protected
|
429
|
+
jwe += "." + jwe_encrypted_key
|
430
|
+
jwe += "." + jwe_init_vector
|
431
|
+
jwe += "." + jwe_cipher_text
|
432
|
+
jwe += "." + jwe_auth_tag
|
433
|
+
|
434
|
+
return [jwe_full, ""]
|
435
|
+
end
|
436
|
+
|
437
|
+
# require 'oydid'
|
438
|
+
# message = '{"protected":"eyJlbmMiOiJYQzIwUCJ9","iv":"G24pK06HSbL0vTlRZMIEBLfa074tJ1tq","ciphertext":"N5bgUr8","tag":"CJeq8cuaercgoBZmrYoGUA","recipients":[{"encrypted_key":"chR8HQh1CRYRU4TdlfBbvon4fcb5PKfWPSo0SgkMC_8","header":{"alg":"ECDH-ES+XC20PKW","iv":"K7lUo8shyJhxC7Nl45VlXes4tbDeZyBL","tag":"2sLCGRv70ESqEAqos3ZhSg","epk":{"kty":"OKP","crv":"X25519","x":"ZpnKcI7Kac6HPwVAGwM0PBweTFKM6wHHVljTHMRWpD4"}}}]}'
|
439
|
+
# message = jwe.to_json
|
440
|
+
# private_key = "z1S5USmDosHvi2giCLHCCgcq3Cd31mrhMcUy2fcfszxxLkD7"
|
441
|
+
# Oydid.decryptJWE(jwe.to_json, private_key)
|
442
|
+
def self.decryptJWE(message, private_key, options = {})
|
443
|
+
|
444
|
+
# JWE parsing
|
445
|
+
jwe_full = JSON.parse(message)
|
446
|
+
snd_pub_enc = jwe_full["recipients"].first["header"]["epk"]["x"]
|
447
|
+
snd_key_enc = jwe_full["recipients"].first["encrypted_key"]
|
448
|
+
snd_nnc_enc = jwe_full["recipients"].first["header"]["iv"]
|
449
|
+
snd_tag_enc = jwe_full["recipients"].first["header"]["tag"]
|
450
|
+
cnt_cip_enc = jwe_full["ciphertext"]
|
451
|
+
cnt_tag_enc = jwe_full["tag"]
|
452
|
+
cnt_nnc_enc = jwe_full["iv"]
|
453
|
+
cnt_aad_enc = jwe_full["protected"]
|
454
|
+
recipient_alg = jwe_full["recipients"].first["header"]["alg"]
|
455
|
+
|
456
|
+
snd_pub = Base64.urlsafe_decode64(snd_pub_enc)
|
457
|
+
snd_nnc = Base64.urlsafe_decode64(snd_nnc_enc)
|
458
|
+
snd_key = Base64.urlsafe_decode64(snd_key_enc)
|
459
|
+
snd_tag = Base64.urlsafe_decode64(snd_tag_enc)
|
460
|
+
cnt_nnc = Base64.urlsafe_decode64(cnt_nnc_enc)
|
461
|
+
cnt_cip = Base64.urlsafe_decode64(cnt_cip_enc)
|
462
|
+
cnt_tag = Base64.urlsafe_decode64(cnt_tag_enc)
|
463
|
+
cnt_aad = Base64.urlsafe_decode64(cnt_aad_enc)
|
464
|
+
|
465
|
+
# Key Decryption
|
466
|
+
code, length, digest = Oydid.multi_decode(private_key).first.unpack('SCa*')
|
467
|
+
buffer = RbNaCl::Util.zeros(RbNaCl::Boxes::Curve25519XSalsa20Poly1305::PublicKey::BYTES)
|
468
|
+
RbNaCl::Signatures::Ed25519::SigningKey.crypto_sign_ed25519_sk_to_curve25519(buffer, digest)
|
469
|
+
shared_secret = RbNaCl::GroupElement.new(snd_pub).mult(buffer)
|
470
|
+
jwe_const = [0, 0, 0, 1] +
|
471
|
+
shared_secret.to_bytes.unpack('C*') +
|
472
|
+
[0,0,0,15] +
|
473
|
+
recipient_alg.bytes +
|
474
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
|
475
|
+
kek = RbNaCl::Hash.sha256(jwe_const.pack('C*'))
|
476
|
+
snd_aead = RbNaCl::AEAD::XChaCha20Poly1305IETF.new(kek)
|
477
|
+
cnt_key = snd_aead.decrypt(snd_nnc, snd_key+snd_tag, nil)
|
478
|
+
|
479
|
+
# Content Decryption
|
480
|
+
cnt_aead = RbNaCl::AEAD::XChaCha20Poly1305IETF.new(cnt_key)
|
481
|
+
cnt_dec = cnt_aead.decrypt(cnt_nnc, cnt_cip+cnt_tag, cnt_aad)
|
482
|
+
|
483
|
+
return [cnt_dec, ""]
|
484
|
+
end
|
485
|
+
|
253
486
|
def self.read_private_key(filename, options)
|
254
487
|
begin
|
255
488
|
f = File.open(filename)
|
256
|
-
key_encoded = f.read
|
489
|
+
key_encoded = f.read.strip
|
257
490
|
f.close
|
258
491
|
rescue
|
259
492
|
return [nil, "cannot read file"]
|
@@ -284,6 +517,9 @@ class Oydid
|
|
284
517
|
when 'ed25519-pub'
|
285
518
|
verify_key = Ed25519::VerifyKey.new(digest)
|
286
519
|
return [verify_key, ""]
|
520
|
+
when 'x25519-pub'
|
521
|
+
pub_key = RbNaCl::PublicKey.new(digest)
|
522
|
+
return [pub_key, ""]
|
287
523
|
else
|
288
524
|
return [nil, "unsupported key codec"]
|
289
525
|
end
|
@@ -331,9 +567,16 @@ class Oydid
|
|
331
567
|
case doc_location
|
332
568
|
when /^http/
|
333
569
|
doc_location = doc_location.sub("%3A%2F%2F","://").sub("%3A", ":")
|
334
|
-
|
570
|
+
option_str = ""
|
571
|
+
if options[:followAlsoKnownAs]
|
572
|
+
option_str = "?followAlsoKnownAs=true"
|
573
|
+
end
|
574
|
+
retVal = HTTParty.get(doc_location + "/doc/" + doc_identifier + option_str)
|
335
575
|
if retVal.code != 200
|
336
|
-
msg = retVal.parsed_response
|
576
|
+
msg = retVal.parsed_response["error"].to_s rescue ""
|
577
|
+
if msg.to_s == ""
|
578
|
+
msg = "invalid response from " + doc_location.to_s + "/doc/" + doc_identifier.to_s
|
579
|
+
end
|
337
580
|
return [nil, msg]
|
338
581
|
end
|
339
582
|
if options.transform_keys(&:to_s)["trace"]
|
data/lib/oydid/didcomm.rb
CHANGED
@@ -102,12 +102,12 @@ class Oydid
|
|
102
102
|
# DID Auth for data container with challenge ---
|
103
103
|
def self.token_from_challenge(host, pwd, options = {})
|
104
104
|
sid = SecureRandom.hex(20).to_s
|
105
|
+
public_key = public_key(generate_private_key(pwd, options).first, options).first
|
105
106
|
retVal = HTTParty.post(host + "/oydid/init",
|
106
107
|
headers: { 'Content-Type' => 'application/json' },
|
107
|
-
body: { "session_id": sid }.to_json )
|
108
|
+
body: { "session_id": sid, "public_key": public_key }.to_json )
|
108
109
|
challenge = retVal.parsed_response["challenge"]
|
109
110
|
signed_challenge = sign(challenge, Oydid.generate_private_key(pwd, options).first, options).first
|
110
|
-
public_key = public_key(generate_private_key(pwd, options).first, options).first
|
111
111
|
retVal = HTTParty.post(host + "/oydid/token",
|
112
112
|
headers: { 'Content-Type' => 'application/json' },
|
113
113
|
body: {
|