oydid 0.5.5 → 0.5.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/oydid/basic.rb +175 -8
  4. data/lib/oydid/log.rb +52 -5
  5. data/lib/oydid.rb +90 -13
  6. metadata +99 -99
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4a02a41e3567cca1fb47d9f5577892707d4a3841d9505138d1164aa5e84ced98
4
- data.tar.gz: 519f74a4640ebe9b8936ab1b9bc60fcd84601c6b9ee750538f28c8e1fd2b3990
3
+ metadata.gz: e6e4098a11373a9b648447adbc7f6ec7b89d0efced1bb920080797dfdc5d17de
4
+ data.tar.gz: bf33e0ddd9abd26a04d92fa945db9183f87000e246f154aa509c55e9b5f4aefd
5
5
  SHA512:
6
- metadata.gz: 54a1637fd933c8f077eead73351ebca631a8d33992d72870e8e08d6776d034b54ca9bf0350c630b85b0b69afcb6e3840ce01096f4806beabc7a3019897c193d3
7
- data.tar.gz: 2b4d266c2bd558aea5be65c8579567e135ce05ff4277c3ae0ef0727ee65214c86149f7e2a3ec31288b783543327416817764ccda6364f42f270470482f5c6aad
6
+ metadata.gz: 6175bb5b1d28443b26573754dd92f97094a7c139d032252c541a73dbd5019028466847b9602b380cd1ca814eeb3e7843576f7a86a77808a5268af62fe89dfba7
7
+ data.tar.gz: a719e0d4c5530340be4ad4a284ffadd46924db95a81c0212fb61e38243cac6a133bf8568ed6407a54d026502048bb06394f5e737f12e0ad588b65c43411bb046
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.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)).to_bytes
117
+ raw_key = Ed25519::SigningKey.new(RbNaCl::Hash.sha256(input))
112
118
  else
113
- raw_key = Ed25519::SigningKey.generate.to_bytes
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
- length = raw_key.bytesize
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
- retVal = HTTParty.get(doc_location + "/doc/" + doc_identifier)
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
- # do nothing
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
- currentDID = dag_update(currentDID, options)
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" => w3c(w3c_input, options),
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[:alsoKnownAs] = equivalentIds
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
- wd["authentication"] = didDoc["authentication"]
1050
- didDoc.delete("authentication")
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
- wd["keyAgreement"] = didDoc["keyAgreement"]
1058
- didDoc.delete("keyAgreement")
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.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: 2023-05-02 00:00:00.000000000 Z
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.0.9
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/input/basic/french.json
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/output/basic/french.json
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/input/basic/sample_b32_dec.doc
350
- - spec/input/basic/sample_b58_enc.doc
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/zQmaBZTghn.doc
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/sample_b64_enc.doc
363
- - spec/input/basic/sample_invalid3_readkey.doc
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/sample_blake2b-32_b32_hash.doc
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/sample_b16_dec.doc
369
- - spec/input/basic/sample_sign.doc
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/sample_invalid_privkey.doc
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/sample_readkey.doc
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/sample_invalid2_readkey.doc
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/sample_invalid_sign.doc
386
- - spec/input/log/sample4_retrieve_log.doc
387
- - spec/input/log/sample_op1_addhash.doc
388
- - spec/input/log/sample0_dag_did.doc
389
- - spec/input/log/sample5_retrieve_log.doc
390
- - spec/input/log/sample_addhash.doc
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/sample_retrieve_log.doc
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/sample6_dag_update.doc
399
- - spec/input/log/sample4_dag_did.doc
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/sample2_dag_update.doc
404
- - spec/input/log/sample5_dag_update.doc
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/sample7_retrieve_log.doc
407
- - spec/input/log/sample4_dag_update.doc
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/sample_b32_dec.doc
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/sample_blake2b-16_b16_hash.doc
414
+ - spec/output/basic/sample3_retrieve_document.doc
423
415
  - spec/output/basic/sample4_retrieve_document.doc
424
- - spec/output/basic/sample_b64_enc.doc
425
- - spec/output/basic/sample_invalid3_readkey.doc
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/sample_blake2b-32_b32_hash.doc
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/sample_b16_dec.doc
431
- - spec/output/basic/sample_sign.doc
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/sample_invalid_privkey.doc
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/sample_readkey.doc
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/sample_invalid2_readkey.doc
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/sample_invalid_sign.doc
448
- - spec/output/log/sample4_retrieve_log.doc
449
- - spec/output/log/sample_op1_addhash.doc
450
- - spec/output/log/sample0_dag_did.doc
451
- - spec/output/log/sample5_retrieve_log.doc
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/sample_retrieve_log.doc
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/sample6_dag_update.doc
461
- - spec/output/log/sample4_dag_did.doc
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/sample2_dag_update.doc
466
- - spec/output/log/sample5_dag_update.doc
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/sample7_retrieve_log.doc
469
- - spec/output/log/sample4_dag_update.doc
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