oydid 0.5.5 → 0.5.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/oydid/basic.rb +175 -8
- data/lib/oydid/log.rb +52 -5
- data/lib/oydid.rb +90 -13
- metadata +99 -99
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
|
@@ -98,7 +104,7 @@ class Oydid
|
|
98
104
|
end
|
99
105
|
|
100
106
|
# key management ----------------------------
|
101
|
-
def self.generate_private_key(input, method = "ed25519-priv", options)
|
107
|
+
def self.generate_private_key(input, method = "ed25519-priv", options = {})
|
102
108
|
begin
|
103
109
|
omc = Multicodecs[method].code
|
104
110
|
rescue
|
@@ -108,15 +114,18 @@ class Oydid
|
|
108
114
|
case Multicodecs[method].name
|
109
115
|
when 'ed25519-priv'
|
110
116
|
if input != ""
|
111
|
-
raw_key = Ed25519::SigningKey.new(RbNaCl::Hash.sha256(input))
|
117
|
+
raw_key = Ed25519::SigningKey.new(RbNaCl::Hash.sha256(input))
|
112
118
|
else
|
113
|
-
raw_key = Ed25519::SigningKey.generate
|
119
|
+
raw_key = Ed25519::SigningKey.generate
|
114
120
|
end
|
121
|
+
raw_key = raw_key.to_bytes
|
122
|
+
length = raw_key.bytesize
|
115
123
|
else
|
116
124
|
return [nil, "unsupported key codec"]
|
117
125
|
end
|
118
|
-
|
126
|
+
|
119
127
|
encoded = multi_encode([omc, length, raw_key].pack("SCa#{length}"), options)
|
128
|
+
# encoded = multi_encode(raw_key.to_bytes, options)
|
120
129
|
if encoded.first.nil?
|
121
130
|
return [nil, encoded.last]
|
122
131
|
else
|
@@ -124,7 +133,7 @@ class Oydid
|
|
124
133
|
end
|
125
134
|
end
|
126
135
|
|
127
|
-
def self.public_key(private_key, options, method = "ed25519-pub")
|
136
|
+
def self.public_key(private_key, options = {}, method = "ed25519-pub")
|
128
137
|
code, length, digest = multi_decode(private_key).first.unpack('SCa*')
|
129
138
|
case Multicodecs[code].name
|
130
139
|
when 'ed25519-priv'
|
@@ -136,6 +145,7 @@ class Oydid
|
|
136
145
|
else
|
137
146
|
return [nil, "unsupported key codec"]
|
138
147
|
end
|
148
|
+
# encoded = multi_encode(public_key.to_bytes, options)
|
139
149
|
length = public_key.to_bytes.bytesize
|
140
150
|
encoded = multi_encode([Multicodecs[method].code, length, public_key].pack("CCa#{length}"), options)
|
141
151
|
if encoded.first.nil?
|
@@ -323,10 +333,160 @@ class Oydid
|
|
323
333
|
end
|
324
334
|
end
|
325
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
|
+
|
326
486
|
def self.read_private_key(filename, options)
|
327
487
|
begin
|
328
488
|
f = File.open(filename)
|
329
|
-
key_encoded = f.read
|
489
|
+
key_encoded = f.read.strip
|
330
490
|
f.close
|
331
491
|
rescue
|
332
492
|
return [nil, "cannot read file"]
|
@@ -357,6 +517,9 @@ class Oydid
|
|
357
517
|
when 'ed25519-pub'
|
358
518
|
verify_key = Ed25519::VerifyKey.new(digest)
|
359
519
|
return [verify_key, ""]
|
520
|
+
when 'x25519-pub'
|
521
|
+
pub_key = RbNaCl::PublicKey.new(digest)
|
522
|
+
return [pub_key, ""]
|
360
523
|
else
|
361
524
|
return [nil, "unsupported key codec"]
|
362
525
|
end
|
@@ -404,7 +567,11 @@ class Oydid
|
|
404
567
|
case doc_location
|
405
568
|
when /^http/
|
406
569
|
doc_location = doc_location.sub("%3A%2F%2F","://").sub("%3A", ":")
|
407
|
-
|
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)
|
408
575
|
if retVal.code != 200
|
409
576
|
msg = retVal.parsed_response["error"].to_s rescue ""
|
410
577
|
if msg.to_s == ""
|
data/lib/oydid/log.rb
CHANGED
@@ -137,17 +137,26 @@ class Oydid
|
|
137
137
|
terminate_overall = 0
|
138
138
|
terminate_index = nil
|
139
139
|
logs.each do |el|
|
140
|
-
if el["op"].to_i == 0
|
140
|
+
if el["op"].to_i == 0 # TERMINATE
|
141
141
|
if dag.vertices[i].successors.length == 0
|
142
142
|
terminate_entries += 1
|
143
143
|
terminate_index = i
|
144
144
|
end
|
145
145
|
terminate_overall += 1
|
146
|
+
elsif el["op"].to_i == 1 # REVOKE
|
147
|
+
# get terminate_index for revoked DIDs
|
148
|
+
if dag.vertices[i].successors.length == 0
|
149
|
+
dag.vertices[i].predecessors.each do |l|
|
150
|
+
if logs[l[:id]]["op"].to_i == 0 # TERMINATE
|
151
|
+
terminate_index = l[:id]
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
146
155
|
end
|
147
156
|
i += 1
|
148
157
|
end unless logs.nil?
|
149
158
|
|
150
|
-
if terminate_entries != 1 && !options[:log_complete]
|
159
|
+
if terminate_entries != 1 && !options[:log_complete] && !options[:followAlsoKnownAs]
|
151
160
|
if options[:silent].nil? || !options[:silent]
|
152
161
|
return [nil, nil, nil, "cannot resolve DID" ]
|
153
162
|
end
|
@@ -217,7 +226,7 @@ class Oydid
|
|
217
226
|
end unless s.predecessors.length < 2
|
218
227
|
dag2array(dag, log_array, s[:id], result, options)
|
219
228
|
end unless dag.vertices[index].successors.count == 0
|
220
|
-
result
|
229
|
+
result.uniq
|
221
230
|
end
|
222
231
|
|
223
232
|
def self.dag2array_terminate(dag, log_array, index, result, options)
|
@@ -237,7 +246,7 @@ class Oydid
|
|
237
246
|
end
|
238
247
|
end unless dag.vertices[index].nil?
|
239
248
|
result << log_array[index]
|
240
|
-
result
|
249
|
+
result.uniq
|
241
250
|
end
|
242
251
|
|
243
252
|
def self.dag_update(currentDID, options)
|
@@ -490,7 +499,45 @@ class Oydid
|
|
490
499
|
break
|
491
500
|
end
|
492
501
|
when 1 # revocation log entry
|
493
|
-
#
|
502
|
+
# handle DID Rotation
|
503
|
+
if (i == (currentDID["log"].length-1))
|
504
|
+
if options[:followAlsoKnownAs]
|
505
|
+
current_doc = currentDID["doc"]
|
506
|
+
if current_doc["doc"].transform_keys(&:to_s).has_key?("alsoKnownAs")
|
507
|
+
rotate_DID = current_doc["doc"].transform_keys(&:to_s)["alsoKnownAs"]
|
508
|
+
if rotate_DID.start_with?("did:")
|
509
|
+
rotate_DID_method = rotate_DID.split(":").take(2).join(":")
|
510
|
+
did_orig = currentDID["did"]
|
511
|
+
if !did_orig.start_with?("did:oyd")
|
512
|
+
did_orig = "did:oyd:" + did_orig
|
513
|
+
end
|
514
|
+
case rotate_DID_method
|
515
|
+
when "did:ebsi"
|
516
|
+
public_resolver = DEFAULT_PUBLIC_RESOLVER
|
517
|
+
rotate_DID_Document = HTTParty.get(public_resolver + rotate_DID)
|
518
|
+
rotate_ddoc = JSON.parse(rotate_DID_Document.parsed_response)
|
519
|
+
rotate_ddoc = rotate_ddoc.except("didDocumentMetadata", "didResolutionMetadata")
|
520
|
+
|
521
|
+
# checks
|
522
|
+
# 1) is original DID revoked -> fulfilled, otherwise we would not be in this branch
|
523
|
+
# 2) das new DID reference back original DID
|
524
|
+
currentDID["did"] = rotate_DID
|
525
|
+
currentDID["doc"]["doc"] = rotate_ddoc
|
526
|
+
if verification_output
|
527
|
+
currentDID["verification"] += "DID rotation to: " + rotate_DID.to_s + "\n"
|
528
|
+
currentDID["verification"] += "✅ original DID (" + did_orig + ") revoked and referenced in alsoKnownAs\n"
|
529
|
+
currentDID["verification"] += "(Details: https://ownyourdata.github.io/oydid/#did_rotation)" + "\n\n"
|
530
|
+
end
|
531
|
+
when "did:oyd"
|
532
|
+
puts "try to resolve did:oyd with our own resolver"
|
533
|
+
puts "add verification text"
|
534
|
+
else
|
535
|
+
# do nothing: DID Rotation is not supported for this DID method yet
|
536
|
+
end
|
537
|
+
end
|
538
|
+
end
|
539
|
+
end
|
540
|
+
end
|
494
541
|
when 5 # DELEGATE
|
495
542
|
# do nothing
|
496
543
|
else
|
data/lib/oydid.rb
CHANGED
@@ -24,10 +24,14 @@ class Oydid
|
|
24
24
|
DEFAULT_ENCODING = "base58btc"
|
25
25
|
SUPPORTED_ENCODINGS = ["base16", "base32", "base58btc", "base64"]
|
26
26
|
LOG_HASH_OPTIONS = {:digest => "sha2-256", :encode => "base58btc"}
|
27
|
+
DEFAULT_PUBLIC_RESOLVER = "https://dev.uniresolver.io/1.0/identifiers/"
|
28
|
+
|
29
|
+
# full Multicodecs table: https://github.com/multiformats/multicodec/blob/master/table.csv
|
30
|
+
# Multicodecs.register(code: 0x1305, name: 'rsa-priv', tag: 'key')
|
31
|
+
# Multicodecs.register(code: 0x1205, name: 'rsa-pub', tag: 'key')
|
27
32
|
|
28
33
|
# expected DID format: did:oyd:123
|
29
34
|
def self.read(did, options)
|
30
|
-
|
31
35
|
if did.to_s == ""
|
32
36
|
return [nil, "missing DID"]
|
33
37
|
end
|
@@ -133,14 +137,24 @@ class Oydid
|
|
133
137
|
end
|
134
138
|
end
|
135
139
|
end
|
136
|
-
|
140
|
+
|
141
|
+
# identify if DID Rotation was performed
|
142
|
+
rotated_DID = (currentDID.transform_keys(&:to_s)["doc"]["doc"].has_key?("@context") &&
|
143
|
+
currentDID.transform_keys(&:to_s)["doc"]["doc"].has_key?("id") &&
|
144
|
+
currentDID.transform_keys(&:to_s)["doc"]["doc"]["id"].split(":").first == "did") rescue false
|
145
|
+
|
146
|
+
if rotated_DID
|
147
|
+
doc = currentDID["doc"].dup
|
148
|
+
currentDID = dag_update(currentDID, options)
|
149
|
+
currentDID["doc"] = doc
|
150
|
+
else
|
151
|
+
currentDID = dag_update(currentDID, options)
|
152
|
+
end
|
137
153
|
if options[:log_complete]
|
138
154
|
currentDID["log"] = log_array
|
139
155
|
end
|
140
|
-
|
141
156
|
return [currentDID, ""]
|
142
157
|
end
|
143
|
-
|
144
158
|
end
|
145
159
|
|
146
160
|
def self.create(content, options)
|
@@ -289,6 +303,27 @@ class Oydid
|
|
289
303
|
pubRevoKey = public_key(revocationKey, options).first
|
290
304
|
did_key = publicKey + ":" + pubRevoKey
|
291
305
|
|
306
|
+
if options[:x25519_keyAgreement]
|
307
|
+
if did_doc.nil?
|
308
|
+
did_doc = {}
|
309
|
+
end
|
310
|
+
did_doc[:keyAgreement] = [{
|
311
|
+
"id": "#key-doc-x25519",
|
312
|
+
"type": "X25519KeyAgreementKey2019",
|
313
|
+
"publicKeyMultibase": public_key(privateKey, options, 'x25519-pub').first
|
314
|
+
}]
|
315
|
+
did_doc = did_doc.transform_keys(&:to_s)
|
316
|
+
end
|
317
|
+
if options[:authentication]
|
318
|
+
if did_doc.nil?
|
319
|
+
did_doc = {}
|
320
|
+
end
|
321
|
+
did_doc[:authentication] = [{
|
322
|
+
"id": "#key-doc"
|
323
|
+
}]
|
324
|
+
did_doc = did_doc.transform_keys(&:to_s)
|
325
|
+
end
|
326
|
+
|
292
327
|
# build new revocation document
|
293
328
|
subDid = {"doc": did_doc, "key": did_key}.to_json
|
294
329
|
retVal = multi_hash(canonical(subDid), LOG_HASH_OPTIONS)
|
@@ -494,14 +529,17 @@ class Oydid
|
|
494
529
|
success, msg = publish(did, didDocument, logs, options)
|
495
530
|
|
496
531
|
if success
|
532
|
+
didDocumentBackup = Marshal.load(Marshal.dump(didDocument))
|
497
533
|
w3c_input = {
|
498
|
-
"did" => did,
|
499
|
-
"doc" => didDocument
|
534
|
+
"did" => did.clone,
|
535
|
+
"doc" => didDocument.clone
|
500
536
|
}
|
537
|
+
doc_w3c = Oydid.w3c(w3c_input, options)
|
538
|
+
didDocument = didDocumentBackup
|
501
539
|
retVal = {
|
502
540
|
"did" => did,
|
503
541
|
"doc" => didDocument,
|
504
|
-
"doc_w3c" =>
|
542
|
+
"doc_w3c" => doc_w3c,
|
505
543
|
"log" => logs
|
506
544
|
}
|
507
545
|
if options[:return_secrets]
|
@@ -927,12 +965,19 @@ class Oydid
|
|
927
965
|
end
|
928
966
|
|
929
967
|
def self.w3c(did_info, options)
|
968
|
+
# check if doc is already W3C DID
|
969
|
+
is_already_w3c_did = (did_info.transform_keys(&:to_s)["doc"]["doc"].has_key?("@context") &&
|
970
|
+
did_info.transform_keys(&:to_s)["doc"]["doc"].has_key?("id") &&
|
971
|
+
did_info.transform_keys(&:to_s)["doc"]["doc"]["id"].split(":").first == "did") rescue false
|
972
|
+
if is_already_w3c_did
|
973
|
+
return did_info.transform_keys(&:to_s)["doc"]["doc"]
|
974
|
+
end
|
930
975
|
did = percent_encode(did_info["did"])
|
931
976
|
if !did.start_with?("did:oyd:")
|
932
977
|
did = "did:oyd:" + did
|
933
978
|
end
|
934
979
|
|
935
|
-
didDoc = did_info.transform_keys(&:to_s)["doc"]
|
980
|
+
didDoc = did_info.dup.transform_keys(&:to_s)["doc"]
|
936
981
|
pubDocKey = didDoc["key"].split(":")[0] rescue ""
|
937
982
|
pubRevKey = didDoc["key"].split(":")[1] rescue ""
|
938
983
|
delegateDocKeys = getDelegatedPubKeysFromDID(did, "doc").first - [pubDocKey] rescue []
|
@@ -1020,7 +1065,7 @@ class Oydid
|
|
1020
1065
|
end
|
1021
1066
|
end unless did_info["log"].nil?
|
1022
1067
|
if equivalentIds.length > 0
|
1023
|
-
wd[
|
1068
|
+
wd["alsoKnownAs"] = equivalentIds
|
1024
1069
|
end
|
1025
1070
|
|
1026
1071
|
if didDoc["doc"].is_a?(Hash) && !didDoc["doc"]["service"].nil?
|
@@ -1046,16 +1091,32 @@ class Oydid
|
|
1046
1091
|
if didDoc["doc"] != {}
|
1047
1092
|
didDoc = didDoc["doc"]
|
1048
1093
|
if didDoc["authentication"].to_s != ""
|
1049
|
-
|
1050
|
-
didDoc
|
1094
|
+
new_authentication = []
|
1095
|
+
didDoc["authentication"].each do |el|
|
1096
|
+
new_el = el.transform_keys(&:to_s)
|
1097
|
+
new_el["id"] = percent_encode(did) + new_el["id"]
|
1098
|
+
new_authentication << new_el
|
1099
|
+
end unless didDoc["authentication"].nil?
|
1100
|
+
if new_authentication.length > 0
|
1101
|
+
wd["authentication"] = new_authentication
|
1102
|
+
didDoc.delete("authentication")
|
1103
|
+
end
|
1051
1104
|
end
|
1052
1105
|
if didDoc["assertionMethod"].to_s != ""
|
1053
1106
|
wd["assertionMethod"] = didDoc["assertionMethod"]
|
1054
1107
|
didDoc.delete("assertionMethod")
|
1055
1108
|
end
|
1056
1109
|
if didDoc["keyAgreement"].to_s != ""
|
1057
|
-
|
1058
|
-
didDoc
|
1110
|
+
new_keyAgreement = []
|
1111
|
+
didDoc["keyAgreement"].each do |el|
|
1112
|
+
new_el = el.transform_keys(&:to_s)
|
1113
|
+
new_el["id"] = percent_encode(did) + new_el["id"]
|
1114
|
+
new_keyAgreement << new_el
|
1115
|
+
end unless didDoc["keyAgreement"].nil?
|
1116
|
+
if new_keyAgreement.length > 0
|
1117
|
+
wd["keyAgreement"] = new_keyAgreement
|
1118
|
+
didDoc.delete("keyAgreement")
|
1119
|
+
end
|
1059
1120
|
end
|
1060
1121
|
if didDoc["capabilityInvocation"].to_s != ""
|
1061
1122
|
wd["capabilityInvocation"] = didDoc["capabilityInvocation"]
|
@@ -1065,7 +1126,23 @@ class Oydid
|
|
1065
1126
|
wd["capabilityDelegation"] = didDoc["capabilityDelegation"]
|
1066
1127
|
didDoc.delete("capabilityDelegation")
|
1067
1128
|
end
|
1129
|
+
if didDoc["alsoKnownAs"].to_s != ""
|
1130
|
+
if didDoc["alsoKnownAs"].is_a?(Array)
|
1131
|
+
dda = didDoc["alsoKnownAs"]
|
1132
|
+
else
|
1133
|
+
dda = [didDoc["alsoKnownAs"]]
|
1134
|
+
end
|
1135
|
+
if wd["alsoKnownAs"].nil?
|
1136
|
+
wd["alsoKnownAs"] = dda
|
1137
|
+
else
|
1138
|
+
wd["alsoKnownAs"] += dda
|
1139
|
+
end
|
1140
|
+
didDoc.delete("alsoKnownAs")
|
1141
|
+
end
|
1068
1142
|
payload = didDoc
|
1143
|
+
if payload == {}
|
1144
|
+
payload = nil
|
1145
|
+
end
|
1069
1146
|
end
|
1070
1147
|
else
|
1071
1148
|
payload = didDoc["doc"]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oydid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christoph Fabianek
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: simple_dag
|
@@ -327,147 +327,147 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
327
327
|
- !ruby/object:Gem::Version
|
328
328
|
version: '0'
|
329
329
|
requirements: []
|
330
|
-
rubygems_version: 3.
|
330
|
+
rubygems_version: 3.5.4
|
331
331
|
signing_key:
|
332
332
|
specification_version: 4
|
333
333
|
summary: Own Your Decentralized Identifier for Ruby.
|
334
334
|
test_files:
|
335
|
-
- spec/spec_helper.rb
|
336
335
|
- spec/oydid_spec.rb
|
337
|
-
- spec/
|
336
|
+
- spec/spec_helper.rb
|
338
337
|
- spec/input/basic/arrays.json
|
338
|
+
- spec/input/basic/french.json
|
339
339
|
- spec/input/basic/structures.json
|
340
340
|
- spec/input/basic/unicode.json
|
341
|
-
- spec/input/basic/wierd.json
|
342
341
|
- spec/input/basic/values.json
|
343
|
-
- spec/
|
342
|
+
- spec/input/basic/wierd.json
|
344
343
|
- spec/output/basic/arrays.json
|
344
|
+
- spec/output/basic/french.json
|
345
345
|
- spec/output/basic/structures.json
|
346
346
|
- spec/output/basic/unicode.json
|
347
|
-
- spec/output/basic/wierd.json
|
348
347
|
- spec/output/basic/values.json
|
349
|
-
- spec/
|
350
|
-
- spec/input/basic/
|
351
|
-
- spec/input/basic/sample_retrieve_document.doc
|
352
|
-
- spec/input/basic/sample_b58_dec.doc
|
353
|
-
- spec/input/basic/sample_sha2-512_b58_hash.doc
|
354
|
-
- spec/input/basic/sample_b32_enc.doc
|
355
|
-
- spec/input/basic/sample_get_location.doc
|
356
|
-
- spec/input/basic/sample_invalid2_verify.doc
|
357
|
-
- spec/input/basic/sample_valid_privkey.doc
|
348
|
+
- spec/output/basic/wierd.json
|
349
|
+
- spec/input/basic/sample2_get_location.doc
|
358
350
|
- spec/input/basic/sample2_retrieve_document.doc
|
359
|
-
- spec/input/basic/
|
360
|
-
- spec/input/basic/sample_blake2b-16_b16_hash.doc
|
351
|
+
- spec/input/basic/sample3_retrieve_document.doc
|
361
352
|
- spec/input/basic/sample4_retrieve_document.doc
|
362
|
-
- spec/input/basic/
|
363
|
-
- spec/input/basic/
|
353
|
+
- spec/input/basic/sample5_retrieve_document.doc
|
354
|
+
- spec/input/basic/sample_b16_dec.doc
|
364
355
|
- spec/input/basic/sample_b16_enc.doc
|
356
|
+
- spec/input/basic/sample_b17_edec.doc
|
365
357
|
- spec/input/basic/sample_b17_enc.doc
|
366
|
-
- spec/input/basic/
|
358
|
+
- spec/input/basic/sample_b32_dec.doc
|
359
|
+
- spec/input/basic/sample_b32_enc.doc
|
360
|
+
- spec/input/basic/sample_b58_dec.doc
|
361
|
+
- spec/input/basic/sample_b58_enc.doc
|
367
362
|
- spec/input/basic/sample_b64_dec.doc
|
368
|
-
- spec/input/basic/
|
369
|
-
- spec/input/basic/
|
363
|
+
- spec/input/basic/sample_b64_enc.doc
|
364
|
+
- spec/input/basic/sample_blake2b-16_b16_hash.doc
|
365
|
+
- spec/input/basic/sample_blake2b-32_b32_hash.doc
|
370
366
|
- spec/input/basic/sample_blake2b-64_b58_hash.doc
|
371
|
-
- spec/input/basic/
|
367
|
+
- spec/input/basic/sample_get_location.doc
|
368
|
+
- spec/input/basic/sample_invalid2_readkey.doc
|
369
|
+
- spec/input/basic/sample_invalid2_verify.doc
|
370
|
+
- spec/input/basic/sample_invalid3_readkey.doc
|
372
371
|
- spec/input/basic/sample_invalid3_verify.doc
|
373
|
-
- spec/input/basic/
|
374
|
-
- spec/input/basic/sample_key.doc
|
375
|
-
- spec/input/basic/sample3_retrieve_document.doc
|
376
|
-
- spec/input/basic/sample_b17_edec.doc
|
377
|
-
- spec/input/basic/sample_verify.doc
|
378
|
-
- spec/input/basic/sample5_retrieve_document.doc
|
379
|
-
- spec/input/basic/sample_sha3-224_b64_hash.doc
|
380
|
-
- spec/input/basic/sample2_get_location.doc
|
372
|
+
- spec/input/basic/sample_invalid_privkey.doc
|
381
373
|
- spec/input/basic/sample_invalid_readkey.doc
|
382
|
-
- spec/input/basic/
|
374
|
+
- spec/input/basic/sample_invalid_sign.doc
|
383
375
|
- spec/input/basic/sample_invalid_verify.doc
|
376
|
+
- spec/input/basic/sample_key.doc
|
377
|
+
- spec/input/basic/sample_readkey.doc
|
378
|
+
- spec/input/basic/sample_retrieve_document.doc
|
384
379
|
- spec/input/basic/sample_sha2-256_b58_hash.doc
|
385
|
-
- spec/input/basic/
|
386
|
-
- spec/input/
|
387
|
-
- spec/input/
|
388
|
-
- spec/input/
|
389
|
-
- spec/input/
|
390
|
-
- spec/input/
|
391
|
-
- spec/input/log/sample3_dag_did.doc
|
380
|
+
- spec/input/basic/sample_sha2-512_b58_hash.doc
|
381
|
+
- spec/input/basic/sample_sha3-224_b64_hash.doc
|
382
|
+
- spec/input/basic/sample_sign.doc
|
383
|
+
- spec/input/basic/sample_valid_privkey.doc
|
384
|
+
- spec/input/basic/sample_verify.doc
|
385
|
+
- spec/input/basic/zQmaBZTghn.doc
|
392
386
|
- spec/input/log/sample0_dag2array.doc
|
393
|
-
- spec/input/log/
|
394
|
-
- spec/input/log/sample_dag_update.doc
|
395
|
-
- spec/input/log/sample1_dag_update.doc
|
396
|
-
- spec/input/log/sample6_retrieve_log.doc
|
387
|
+
- spec/input/log/sample0_dag_did.doc
|
397
388
|
- spec/input/log/sample1_dag_did.doc
|
398
|
-
- spec/input/log/
|
399
|
-
- spec/input/log/
|
389
|
+
- spec/input/log/sample1_dag_update.doc
|
390
|
+
- spec/input/log/sample2_dag_did.doc
|
391
|
+
- spec/input/log/sample2_dag_update.doc
|
400
392
|
- spec/input/log/sample2_retrieve_log.doc
|
393
|
+
- spec/input/log/sample3_dag_did.doc
|
394
|
+
- spec/input/log/sample3_dag_update.doc
|
395
|
+
- spec/input/log/sample3_retrieve_log.doc
|
396
|
+
- spec/input/log/sample4_dag_did.doc
|
397
|
+
- spec/input/log/sample4_dag_update.doc
|
398
|
+
- spec/input/log/sample4_retrieve_log.doc
|
399
|
+
- spec/input/log/sample5_dag_update.doc
|
400
|
+
- spec/input/log/sample5_retrieve_log.doc
|
401
|
+
- spec/input/log/sample6_dag_update.doc
|
402
|
+
- spec/input/log/sample6_retrieve_log.doc
|
401
403
|
- spec/input/log/sample7_dag_update.doc
|
404
|
+
- spec/input/log/sample7_retrieve_log.doc
|
402
405
|
- spec/input/log/sample8_dag_update.doc
|
403
|
-
- spec/input/log/
|
404
|
-
- spec/input/log/
|
406
|
+
- spec/input/log/sample_addhash.doc
|
407
|
+
- spec/input/log/sample_dag_update.doc
|
405
408
|
- spec/input/log/sample_match_log.doc
|
406
|
-
- spec/input/log/
|
407
|
-
- spec/input/log/
|
408
|
-
- spec/input/log/sample3_retrieve_log.doc
|
409
|
-
- spec/input/log/sample2_dag_did.doc
|
410
|
-
- spec/input/log/sample3_dag_update.doc
|
409
|
+
- spec/input/log/sample_op1_addhash.doc
|
410
|
+
- spec/input/log/sample_retrieve_log.doc
|
411
411
|
- spec/input/main/sample0_read.doc
|
412
|
-
- spec/output/basic/
|
413
|
-
- spec/output/basic/sample_b58_enc.doc
|
414
|
-
- spec/output/basic/sample_retrieve_document.doc
|
415
|
-
- spec/output/basic/sample_b58_dec.doc
|
416
|
-
- spec/output/basic/sample_sha2-512_b58_hash.doc
|
417
|
-
- spec/output/basic/sample_b32_enc.doc
|
418
|
-
- spec/output/basic/sample_get_location.doc
|
419
|
-
- spec/output/basic/sample_invalid2_verify.doc
|
420
|
-
- spec/output/basic/sample_valid_privkey.doc
|
412
|
+
- spec/output/basic/sample2_get_location.doc
|
421
413
|
- spec/output/basic/sample2_retrieve_document.doc
|
422
|
-
- spec/output/basic/
|
414
|
+
- spec/output/basic/sample3_retrieve_document.doc
|
423
415
|
- spec/output/basic/sample4_retrieve_document.doc
|
424
|
-
- spec/output/basic/
|
425
|
-
- spec/output/basic/
|
416
|
+
- spec/output/basic/sample5_retrieve_document.doc
|
417
|
+
- spec/output/basic/sample_b16_dec.doc
|
426
418
|
- spec/output/basic/sample_b16_enc.doc
|
419
|
+
- spec/output/basic/sample_b17_edec.doc
|
427
420
|
- spec/output/basic/sample_b17_enc.doc
|
428
|
-
- spec/output/basic/
|
421
|
+
- spec/output/basic/sample_b32_dec.doc
|
422
|
+
- spec/output/basic/sample_b32_enc.doc
|
423
|
+
- spec/output/basic/sample_b58_dec.doc
|
424
|
+
- spec/output/basic/sample_b58_enc.doc
|
429
425
|
- spec/output/basic/sample_b64_dec.doc
|
430
|
-
- spec/output/basic/
|
431
|
-
- spec/output/basic/
|
426
|
+
- spec/output/basic/sample_b64_enc.doc
|
427
|
+
- spec/output/basic/sample_blake2b-16_b16_hash.doc
|
428
|
+
- spec/output/basic/sample_blake2b-32_b32_hash.doc
|
432
429
|
- spec/output/basic/sample_blake2b-64_b58_hash.doc
|
433
|
-
- spec/output/basic/
|
430
|
+
- spec/output/basic/sample_get_location.doc
|
431
|
+
- spec/output/basic/sample_invalid2_readkey.doc
|
432
|
+
- spec/output/basic/sample_invalid2_verify.doc
|
433
|
+
- spec/output/basic/sample_invalid3_readkey.doc
|
434
434
|
- spec/output/basic/sample_invalid3_verify.doc
|
435
|
-
- spec/output/basic/
|
436
|
-
- spec/output/basic/sample_key.doc
|
437
|
-
- spec/output/basic/sample3_retrieve_document.doc
|
438
|
-
- spec/output/basic/sample_b17_edec.doc
|
439
|
-
- spec/output/basic/sample_verify.doc
|
440
|
-
- spec/output/basic/sample5_retrieve_document.doc
|
441
|
-
- spec/output/basic/sample_sha3-224_b64_hash.doc
|
442
|
-
- spec/output/basic/sample2_get_location.doc
|
435
|
+
- spec/output/basic/sample_invalid_privkey.doc
|
443
436
|
- spec/output/basic/sample_invalid_readkey.doc
|
444
|
-
- spec/output/basic/
|
437
|
+
- spec/output/basic/sample_invalid_sign.doc
|
445
438
|
- spec/output/basic/sample_invalid_verify.doc
|
439
|
+
- spec/output/basic/sample_key.doc
|
440
|
+
- spec/output/basic/sample_readkey.doc
|
441
|
+
- spec/output/basic/sample_retrieve_document.doc
|
446
442
|
- spec/output/basic/sample_sha2-256_b58_hash.doc
|
447
|
-
- spec/output/basic/
|
448
|
-
- spec/output/
|
449
|
-
- spec/output/
|
450
|
-
- spec/output/
|
451
|
-
- spec/output/
|
452
|
-
- spec/output/log/sample_addhash.doc
|
453
|
-
- spec/output/log/sample3_dag_did.doc
|
443
|
+
- spec/output/basic/sample_sha2-512_b58_hash.doc
|
444
|
+
- spec/output/basic/sample_sha3-224_b64_hash.doc
|
445
|
+
- spec/output/basic/sample_sign.doc
|
446
|
+
- spec/output/basic/sample_valid_privkey.doc
|
447
|
+
- spec/output/basic/sample_verify.doc
|
454
448
|
- spec/output/log/sample0_dag2array.doc
|
455
|
-
- spec/output/log/
|
456
|
-
- spec/output/log/sample_dag_update.doc
|
457
|
-
- spec/output/log/sample1_dag_update.doc
|
458
|
-
- spec/output/log/sample6_retrieve_log.doc
|
449
|
+
- spec/output/log/sample0_dag_did.doc
|
459
450
|
- spec/output/log/sample1_dag_did.doc
|
460
|
-
- spec/output/log/
|
461
|
-
- spec/output/log/
|
451
|
+
- spec/output/log/sample1_dag_update.doc
|
452
|
+
- spec/output/log/sample2_dag_did.doc
|
453
|
+
- spec/output/log/sample2_dag_update.doc
|
462
454
|
- spec/output/log/sample2_retrieve_log.doc
|
455
|
+
- spec/output/log/sample3_dag_did.doc
|
456
|
+
- spec/output/log/sample3_dag_update.doc
|
457
|
+
- spec/output/log/sample3_retrieve_log.doc
|
458
|
+
- spec/output/log/sample4_dag_did.doc
|
459
|
+
- spec/output/log/sample4_dag_update.doc
|
460
|
+
- spec/output/log/sample4_retrieve_log.doc
|
461
|
+
- spec/output/log/sample5_dag_update.doc
|
462
|
+
- spec/output/log/sample5_retrieve_log.doc
|
463
|
+
- spec/output/log/sample6_dag_update.doc
|
464
|
+
- spec/output/log/sample6_retrieve_log.doc
|
463
465
|
- spec/output/log/sample7_dag_update.doc
|
466
|
+
- spec/output/log/sample7_retrieve_log.doc
|
464
467
|
- spec/output/log/sample8_dag_update.doc
|
465
|
-
- spec/output/log/
|
466
|
-
- spec/output/log/
|
468
|
+
- spec/output/log/sample_addhash.doc
|
469
|
+
- spec/output/log/sample_dag_update.doc
|
467
470
|
- spec/output/log/sample_match_log.doc
|
468
|
-
- spec/output/log/
|
469
|
-
- spec/output/log/
|
470
|
-
- spec/output/log/sample3_retrieve_log.doc
|
471
|
-
- spec/output/log/sample2_dag_did.doc
|
472
|
-
- spec/output/log/sample3_dag_update.doc
|
471
|
+
- spec/output/log/sample_op1_addhash.doc
|
472
|
+
- spec/output/log/sample_retrieve_log.doc
|
473
473
|
- spec/output/main/sample0_read.doc
|