oydid 0.5.5 → 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.
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