oydid 0.4.4 → 0.5.3

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/oydid/basic.rb +149 -33
  4. data/lib/oydid/didcomm.rb +9 -9
  5. data/lib/oydid/log.rb +14 -7
  6. data/lib/oydid/vc.rb +264 -0
  7. data/lib/oydid.rb +283 -113
  8. data/spec/input/basic/sample_b16_dec.doc +1 -0
  9. data/spec/input/basic/{sample_enc.doc → sample_b16_enc.doc} +0 -0
  10. data/spec/input/basic/sample_b17_edec.doc +1 -0
  11. data/spec/input/basic/{sample_hash.doc → sample_b17_enc.doc} +0 -0
  12. data/spec/input/basic/sample_b32_dec.doc +1 -0
  13. data/spec/{output/basic/sample_dec.doc → input/basic/sample_b32_enc.doc} +0 -0
  14. data/spec/input/basic/{sample_dec.doc → sample_b58_dec.doc} +0 -0
  15. data/spec/input/basic/sample_b58_enc.doc +1 -0
  16. data/spec/input/basic/sample_b64_dec.doc +1 -0
  17. data/spec/input/basic/sample_b64_enc.doc +1 -0
  18. data/spec/input/basic/sample_blake2b-16_b16_hash.doc +1 -0
  19. data/spec/input/basic/sample_blake2b-32_b32_hash.doc +1 -0
  20. data/spec/input/basic/sample_blake2b-64_b58_hash.doc +1 -0
  21. data/spec/input/basic/sample_invalid2_readkey.doc +1 -1
  22. data/spec/input/basic/sample_invalid3_readkey.doc +1 -1
  23. data/spec/input/basic/sample_readkey.doc +1 -1
  24. data/spec/input/basic/sample_sha2-256_b58_hash.doc +1 -0
  25. data/spec/input/basic/sample_sha2-512_b58_hash.doc +1 -0
  26. data/spec/input/basic/sample_sha3-224_b64_hash.doc +1 -0
  27. data/spec/output/basic/sample_b16_dec.doc +1 -0
  28. data/spec/output/basic/sample_b16_enc.doc +1 -0
  29. data/spec/output/basic/sample_b17_edec.doc +2 -0
  30. data/spec/output/basic/sample_b17_enc.doc +1 -0
  31. data/spec/output/basic/sample_b32_dec.doc +1 -0
  32. data/spec/output/basic/sample_b32_enc.doc +1 -0
  33. data/spec/output/basic/sample_b58_dec.doc +1 -0
  34. data/spec/output/basic/{sample_enc.doc → sample_b58_enc.doc} +0 -0
  35. data/spec/output/basic/sample_b64_dec.doc +1 -0
  36. data/spec/output/basic/sample_b64_enc.doc +1 -0
  37. data/spec/output/basic/sample_blake2b-16_b16_hash.doc +1 -0
  38. data/spec/output/basic/sample_blake2b-32_b32_hash.doc +1 -0
  39. data/spec/output/basic/sample_blake2b-64_b58_hash.doc +1 -0
  40. data/spec/output/basic/{sample_hash.doc → sample_sha2-256_b58_hash.doc} +0 -0
  41. data/spec/output/basic/sample_sha2-512_b58_hash.doc +1 -0
  42. data/spec/output/basic/sample_sha3-224_b64_hash.doc +1 -0
  43. data/spec/oydid_spec.rb +95 -13
  44. metadata +72 -19
data/lib/oydid.rb CHANGED
@@ -13,12 +13,17 @@ require 'json/canonicalization'
13
13
  require 'oydid/basic'
14
14
  require 'oydid/log'
15
15
  require 'oydid/didcomm'
16
+ require 'oydid/vc'
16
17
 
17
18
  class Oydid
18
19
 
19
20
  LOCATION_PREFIX = "@"
20
21
  DEFAULT_LOCATION = "https://oydid.ownyourdata.eu"
21
-
22
+ DEFAULT_DIGEST = "sha2-256"
23
+ SUPPORTED_DIGESTS = ["sha2-256", "sha2-512", "sha3-224", "sha3-256", "sha3-384", "sha3-512", "blake2b-16", "blake2b-32", "blake2b-64"]
24
+ DEFAULT_ENCODING = "base58btc"
25
+ SUPPORTED_ENCODINGS = ["base16", "base32", "base58btc", "base64"]
26
+ LOG_HASH_OPTIONS = {:digest => "sha2-256", :encode => "base58btc"}
22
27
 
23
28
  # expected DID format: did:oyd:123
24
29
  def self.read(did, options)
@@ -33,8 +38,6 @@ class Oydid
33
38
  "message": "",
34
39
  "verification": ""
35
40
  }.transform_keys(&:to_s)
36
- did_hash = did.delete_prefix("did:oyd:")
37
- did10 = did_hash[0,10]
38
41
 
39
42
  # get did location
40
43
  did_location = ""
@@ -52,13 +55,20 @@ class Oydid
52
55
  did = tmp[0]
53
56
  did_location = tmp[1]
54
57
  end
58
+ if did.include?(CGI.escape LOCATION_PREFIX)
59
+ tmp = did.split(CGI.escape LOCATION_PREFIX)
60
+ did = tmp[0]
61
+ did_location = tmp[1]
62
+ end
55
63
  end
56
64
  if did_location == ""
57
65
  did_location = DEFAULT_LOCATION
58
66
  end
67
+ did_hash = did.delete_prefix("did:oyd:")
68
+ did10 = did_hash[0,10]
59
69
 
60
70
  # retrieve DID document
61
- did_document = retrieve_document(did, did10 + ".doc", did_location, options)
71
+ did_document = retrieve_document(did_hash, did10 + ".doc", did_location, options)
62
72
  if did_document.first.nil?
63
73
  return [nil, did_document.last]
64
74
  end
@@ -140,15 +150,18 @@ class Oydid
140
150
  end
141
151
 
142
152
  def self.simulate_did(content, did, mode, options)
143
- user_did, didDocument, revoc_log, l1, l2, r1, privateKey, revocationKey, did_old, log_old, msg = Oydid.generate_base(content, did, mode, options)
153
+ did_doc, did_key, did_log, msg = Oydid.generate_base(content, did, mode, options)
154
+ user_did = did_doc[:did]
144
155
  return [user_did, msg]
145
156
  end
146
-
157
+
147
158
  def self.generate_base(content, did, mode, options)
148
159
  # input validation
149
160
  did_doc = JSON.parse(content.to_json) rescue nil
150
161
  if did_doc.nil?
151
- return [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "invalid payload"]
162
+ if !content.nil?
163
+ return [nil, nil, nil, "invalid payload"]
164
+ end
152
165
  end
153
166
  did_old = nil
154
167
  log_old = nil
@@ -165,35 +178,35 @@ class Oydid
165
178
  operation_mode = 2 # CREATE
166
179
  if options[:doc_key].nil?
167
180
  if options[:doc_enc].nil?
168
- privateKey, msg = generate_private_key(options[:doc_pwd].to_s, 'ed25519-priv')
181
+ privateKey, msg = generate_private_key(options[:doc_pwd].to_s, 'ed25519-priv', options)
169
182
  else
170
- privateKey, msg = decode_private_key(options[:doc_enc].to_s)
183
+ privateKey, msg = decode_private_key(options[:doc_enc].to_s, options)
171
184
  end
172
185
  else
173
- privateKey, msg = read_private_key(options[:doc_key].to_s)
186
+ privateKey, msg = read_private_key(options[:doc_key].to_s, options)
174
187
  if privateKey.nil?
175
- return [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "private document key not found"]
188
+ return [nil, nil, nil, "private document key not found"]
176
189
  end
177
190
  end
178
191
  if options[:rev_key].nil?
179
192
  if options[:rev_enc].nil?
180
- revocationKey, msg = generate_private_key(options[:rev_pwd].to_s, 'ed25519-priv')
193
+ revocationKey, msg = generate_private_key(options[:rev_pwd].to_s, 'ed25519-priv', options)
181
194
  else
182
- revocationKey, msg = decode_private_key(options[:rev_enc].to_s)
195
+ revocationKey, msg = decode_private_key(options[:rev_enc].to_s, options)
183
196
  end
184
197
  else
185
- revocationKey, msg = read_private_key(options[:rev_key].to_s)
198
+ revocationKey, msg = read_private_key(options[:rev_key].to_s, options)
186
199
  if revocationKey.nil?
187
- return [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "private revocation key not found"]
200
+ return [nil, nil, nil, "private revocation key not found"]
188
201
  end
189
202
  end
190
203
  else # mode == "update" => read information
191
204
  did_info, msg = read(did, options)
192
205
  if did_info.nil?
193
- return [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "cannot resolve DID (on updating DID)"]
206
+ return [nil, nil, nil, "cannot resolve DID (on updating DID)"]
194
207
  end
195
208
  if did_info["error"] != 0
196
- return [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, did_info["message"].to_s]
209
+ return [nil, nil, nil, did_info["message"].to_s]
197
210
  end
198
211
 
199
212
  did = did_info["did"]
@@ -215,75 +228,75 @@ class Oydid
215
228
  if options[:old_doc_key].nil?
216
229
  if options[:old_doc_enc].nil?
217
230
  if options[:old_doc_pwd].nil?
218
- privateKey_old = read_private_storage(did10_old + "_private_key.b58")
231
+ privateKey_old = read_private_storage(did10_old + "_private_key.enc")
219
232
  else
220
- privateKey_old, msg = generate_private_key(options[:old_doc_pwd].to_s, 'ed25519-priv')
233
+ privateKey_old, msg = generate_private_key(options[:old_doc_pwd].to_s, 'ed25519-priv', options)
221
234
  end
222
235
  else
223
- privateKey_old, msg = decode_private_key(options[:old_doc_enc].to_s)
236
+ privateKey_old, msg = decode_private_key(options[:old_doc_enc].to_s, options)
224
237
  end
225
238
  else
226
- privateKey_old, msg = read_private_key(options[:old_doc_key].to_s)
239
+ privateKey_old, msg = read_private_key(options[:old_doc_key].to_s, options)
227
240
  end
241
+
228
242
  if privateKey_old.nil?
229
- return [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "invalid or missing old private document key"]
243
+ return [nil, nil, nil, "invalid or missing old private document key"]
230
244
  end
231
245
  if options[:old_rev_key].nil?
232
246
  if options[:old_rev_enc].nil?
233
247
  if options[:old_rev_pwd].nil?
234
- revocationKey_old = read_private_storage(did10_old + "_revocation_key.b58")
248
+ revocationKey_old = read_private_storage(did10_old + "_revocation_key.enc")
235
249
  else
236
- revocationKey_old, msg = generate_private_key(options[:old_rev_pwd].to_s, 'ed25519-priv')
250
+ revocationKey_old, msg = generate_private_key(options[:old_rev_pwd].to_s, 'ed25519-priv', options)
237
251
  end
238
252
  else
239
- revocationKey_old, msg = decode_private_key(options[:old_rev_enc].to_s)
253
+ revocationKey_old, msg = decode_private_key(options[:old_rev_enc].to_s, options)
240
254
  end
241
255
  else
242
- revocationKey_old, msg = read_private_key(options[:old_rev_key].to_s)
256
+ revocationKey_old, msg = read_private_key(options[:old_rev_key].to_s, options)
243
257
  end
244
258
  if revocationKey_old.nil?
245
- return [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "invalid or missing old private revocation key"]
259
+ return [nil, nil, nil, "invalid or missing old private revocation key"]
246
260
  end
247
-
248
261
  # key management
249
262
  if options[:doc_key].nil?
250
263
  if options[:doc_enc].nil?
251
- privateKey, msg = generate_private_key(options[:doc_pwd].to_s, 'ed25519-priv')
264
+ privateKey, msg = generate_private_key(options[:doc_pwd].to_s, 'ed25519-priv', options)
252
265
  else
253
- privateKey, msg = decode_private_key(options[:doc_enc].to_s)
266
+ privateKey, msg = decode_private_key(options[:doc_enc].to_s, options)
254
267
  end
255
268
  else
256
- privateKey, msg = read_private_key(options[:doc_key].to_s)
269
+ privateKey, msg = read_private_key(options[:doc_key].to_s, options)
257
270
  end
258
271
  # if options[:rev_key].nil? && options[:rev_pwd].nil? && options[:rev_enc].nil?
259
272
  # revocationLog = read_private_storage(did10 + "_revocation.json")
260
273
  # if revocationLog.nil?
261
- # return [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "invalid or missing old revocation log"]
274
+ # return [nil, nil, nil, "invalid or missing old revocation log"]
262
275
  # end
263
276
  # else
264
277
  if options[:rev_key].nil?
265
278
  if options[:rev_enc].nil?
266
279
  if options[:rev_pwd].nil?
267
- revocationKey, msg = generate_private_key("", 'ed25519-priv')
280
+ revocationKey, msg = generate_private_key("", 'ed25519-priv', options)
268
281
  else
269
- revocationKey, msg = generate_private_key(options[:rev_pwd].to_s, 'ed25519-priv')
282
+ revocationKey, msg = generate_private_key(options[:rev_pwd].to_s, 'ed25519-priv', options)
270
283
  end
271
284
  else
272
- revocationKey, msg = decode_private_key(options[:rev_enc].to_s)
285
+ revocationKey, msg = decode_private_key(options[:rev_enc].to_s, options)
273
286
  end
274
287
  else
275
- revocationKey, msg = read_private_key(options[:rev_key].to_s)
288
+ revocationKey, msg = read_private_key(options[:rev_key].to_s, options)
276
289
  end
277
290
 
278
291
  # re-build revocation document
279
292
  did_old_doc = did_info["doc"]["doc"]
280
293
  ts_old = did_info["log"].last["ts"]
281
- publicKey_old = public_key(privateKey_old).first
282
- pubRevoKey_old = public_key(revocationKey_old).first
294
+ publicKey_old = public_key(privateKey_old, options).first
295
+ pubRevoKey_old = public_key(revocationKey_old, options).first
283
296
  did_key_old = publicKey_old + ":" + pubRevoKey_old
284
297
  subDid = {"doc": did_old_doc, "key": did_key_old}.to_json
285
- subDidHash = hash(canonical(subDid))
286
- signedSubDidHash = sign(subDidHash, revocationKey_old).first
298
+ subDidHash = multi_hash(canonical(subDid), LOG_HASH_OPTIONS).first
299
+ signedSubDidHash = sign(subDidHash, revocationKey_old, options).first
287
300
  revocationLog = {
288
301
  "ts": ts_old,
289
302
  "op": 1, # REVOKE
@@ -292,38 +305,41 @@ class Oydid
292
305
  # end
293
306
  revoc_log = JSON.parse(revocationLog)
294
307
  revoc_log["previous"] = [
295
- hash(canonical(log_old[did_info["doc_log_id"].to_i])),
296
- hash(canonical(log_old[did_info["termination_log_id"].to_i]))
308
+ multi_hash(canonical(log_old[did_info["doc_log_id"].to_i]), LOG_HASH_OPTIONS).first,
309
+ multi_hash(canonical(log_old[did_info["termination_log_id"].to_i]), LOG_HASH_OPTIONS).first
297
310
  ]
298
- prev_hash = [hash(canonical(revoc_log))]
311
+ prev_hash = [multi_hash(canonical(revoc_log), LOG_HASH_OPTIONS).first]
299
312
  end
300
-
301
- publicKey = public_key(privateKey).first
302
- pubRevoKey = public_key(revocationKey).first
313
+ publicKey = public_key(privateKey, options).first
314
+ pubRevoKey = public_key(revocationKey, options).first
303
315
  did_key = publicKey + ":" + pubRevoKey
304
316
 
305
317
  # build new revocation document
306
318
  subDid = {"doc": did_doc, "key": did_key}.to_json
307
- subDidHash = hash(canonical(subDid))
308
- signedSubDidHash = sign(subDidHash, revocationKey).first
319
+ retVal = multi_hash(canonical(subDid), LOG_HASH_OPTIONS)
320
+ if retVal.first.nil?
321
+ return [nil, nil, nil, retVal.last]
322
+ end
323
+ subDidHash = retVal.first
324
+ signedSubDidHash = sign(subDidHash, revocationKey, options).first
309
325
  r1 = { "ts": ts,
310
326
  "op": 1, # REVOKE
311
327
  "doc": subDidHash,
312
328
  "sig": signedSubDidHash }.transform_keys(&:to_s)
313
329
 
314
330
  # build termination log entry
315
- l2_doc = hash(canonical(r1))
331
+ l2_doc = multi_hash(canonical(r1), LOG_HASH_OPTIONS).first
316
332
  if !doc_location.nil?
317
333
  l2_doc += LOCATION_PREFIX + doc_location.to_s
318
334
  end
319
335
  l2 = { "ts": ts,
320
336
  "op": 0, # TERMINATE
321
337
  "doc": l2_doc,
322
- "sig": sign(l2_doc, privateKey).first,
338
+ "sig": sign(l2_doc, privateKey, options).first,
323
339
  "previous": [] }.transform_keys(&:to_s)
324
340
 
325
341
  # build actual DID document
326
- log_str = hash(canonical(l2))
342
+ log_str = multi_hash(canonical(l2), LOG_HASH_OPTIONS).first
327
343
  if !doc_location.nil?
328
344
  log_str += LOCATION_PREFIX + doc_location.to_s
329
345
  end
@@ -332,7 +348,7 @@ class Oydid
332
348
  "log": log_str }.transform_keys(&:to_s)
333
349
 
334
350
  # create DID
335
- l1_doc = hash(canonical(didDocument))
351
+ l1_doc = multi_hash(canonical(didDocument), options).first
336
352
  if !doc_location.nil?
337
353
  l1_doc += LOCATION_PREFIX + doc_location.to_s
338
354
  end
@@ -345,13 +361,13 @@ class Oydid
345
361
  "ts": ts,
346
362
  "op": 4, # CLONE
347
363
  "doc": l1_doc,
348
- "sig": sign(l1_doc, privateKey).first,
364
+ "sig": sign(l1_doc, privateKey, options).first,
349
365
  "previous": [options[:previous_clone].to_s]
350
366
  }
351
367
  retVal = HTTParty.post(options[:source_location] + "/log/" + options[:source_did],
352
368
  headers: { 'Content-Type' => 'application/json' },
353
369
  body: {"log": new_log}.to_json )
354
- prev_hash = [hash(canonical(new_log))]
370
+ prev_hash = [multi_hash(canonical(new_log), LOG_HASH_OPTIONS).first]
355
371
  end
356
372
 
357
373
  # build creation log entry
@@ -359,17 +375,40 @@ class Oydid
359
375
  l1 = { "ts": ts,
360
376
  "op": operation_mode, # UPDATE
361
377
  "doc": l1_doc,
362
- "sig": sign(l1_doc, privateKey_old).first,
378
+ "sig": sign(l1_doc, privateKey_old, options).first,
363
379
  "previous": prev_hash }.transform_keys(&:to_s)
364
380
  else
365
381
  l1 = { "ts": ts,
366
382
  "op": operation_mode, # CREATE
367
383
  "doc": l1_doc,
368
- "sig": sign(l1_doc, privateKey).first,
384
+ "sig": sign(l1_doc, privateKey, options).first,
369
385
  "previous": prev_hash }.transform_keys(&:to_s)
370
386
  end
371
387
 
372
- return [did, didDocument, revoc_log, l1, l2, r1, privateKey, revocationKey, did_old, log_old, ""]
388
+ # did, didDocument, revoc_log, l1, l2, r1, privateKey, revocationKey, did_old, log_old, msg = Oydid.generate_base(content, "", "create", options)
389
+ # did_doc = [did, didDocument, did_old]
390
+ # did_log = [revoc_log, l1, l2, r1, log_old]
391
+ # did_key = [privateKey, revocationKey]
392
+
393
+ did_doc = {
394
+ :did => did,
395
+ :didDocument => didDocument,
396
+ :did_old => did_old
397
+ }
398
+ did_log = {
399
+ :revoc_log => revoc_log,
400
+ :l1 => l1,
401
+ :l2 => l2,
402
+ :r1 => r1,
403
+ :log_old => log_old
404
+ }
405
+ did_key = {
406
+ :privateKey => privateKey,
407
+ :revocationKey => revocationKey
408
+ }
409
+
410
+ return [did_doc, did_key, did_log, ""]
411
+ # return [did, didDocument, revoc_log, l1, l2, r1, privateKey, revocationKey, did_old, log_old, ""]
373
412
  end
374
413
 
375
414
  def self.publish(did, didDocument, logs, options)
@@ -415,11 +454,22 @@ class Oydid
415
454
  end
416
455
 
417
456
  def self.write(content, did, mode, options)
418
- did, didDocument, revoc_log, l1, l2, r1, privateKey, revocationKey, did_old, log_old, msg = generate_base(content, did, mode, options)
457
+ did_doc, did_key, did_log, msg = generate_base(content, did, mode, options)
458
+ did = did_doc[:did]
459
+ didDocument = did_doc[:didDocument]
460
+ did_old = did_doc[:did_old]
461
+ revoc_log = did_log[:revoc_log]
462
+ l1 = did_log[:l1]
463
+ l2 = did_log[:l2]
464
+ r1 = did_log[:r1]
465
+ log_old = did_log[:log_old]
466
+ privateKey = did_key[:privateKey]
467
+ revocationKey = did_key[:revocationKey]
468
+ # did, didDocument, revoc_log, l1, l2, r1, privateKey, revocationKey, did_old, log_old, msg = generate_base(content, did, mode, options)
469
+
419
470
  if msg != ""
420
471
  return [nil, msg]
421
472
  end
422
-
423
473
  did_hash = did.delete_prefix("did:oyd:")
424
474
  did10 = did_hash[0,10]
425
475
  did_old_hash = did_old.delete_prefix("did:oyd:") rescue nil
@@ -435,7 +485,6 @@ class Oydid
435
485
  doc_location = DEFAULT_LOCATION
436
486
  end
437
487
  end
438
-
439
488
  case doc_location.to_s
440
489
  when /^http/
441
490
  logs = [revoc_log, l1, l2].flatten.compact
@@ -463,8 +512,8 @@ class Oydid
463
512
  retVal["revocation_key"] = revocationKey
464
513
  retVal["revocation_log"] = r1
465
514
  else
466
- write_private_storage(privateKey, did10 + "_private_key.b58")
467
- write_private_storage(revocationKey, did10 + "_revocation_key.b58")
515
+ write_private_storage(privateKey, did10 + "_private_key.enc")
516
+ write_private_storage(revocationKey, did10 + "_revocation_key.enc")
468
517
  write_private_storage(r1.to_json, did10 + "_revocation.json")
469
518
  end
470
519
 
@@ -509,15 +558,15 @@ class Oydid
509
558
  if options[:old_doc_key].nil?
510
559
  if options[:old_doc_enc].nil?
511
560
  if options[:old_doc_pwd].nil?
512
- privateKey_old = read_private_storage(did10_old + "_private_key.b58")
561
+ privateKey_old = read_private_storage(did10_old + "_private_key.enc")
513
562
  else
514
- privateKey_old, msg = generate_private_key(options[:old_doc_pwd].to_s, 'ed25519-priv')
563
+ privateKey_old, msg = generate_private_key(options[:old_doc_pwd].to_s, 'ed25519-priv', options)
515
564
  end
516
565
  else
517
- privateKey_old, msg = decode_private_key(options[:old_doc_enc].to_s)
566
+ privateKey_old, msg = decode_private_key(options[:old_doc_enc].to_s, options)
518
567
  end
519
568
  else
520
- privateKey_old, msg = read_private_key(options[:old_doc_key].to_s)
569
+ privateKey_old, msg = read_private_key(options[:old_doc_key].to_s, options)
521
570
  end
522
571
  if privateKey_old.nil?
523
572
  return [nil, "invalid or missing old private document key"]
@@ -525,42 +574,42 @@ class Oydid
525
574
  if options[:old_rev_key].nil?
526
575
  if options[:old_rev_enc].nil?
527
576
  if options[:old_rev_pwd].nil?
528
- revocationKey_old = read_private_storage(did10_old + "_revocation_key.b58")
577
+ revocationKey_old = read_private_storage(did10_old + "_revocation_key.enc")
529
578
  else
530
- revocationKey_old, msg = generate_private_key(options[:old_rev_pwd].to_s, 'ed25519-priv')
579
+ revocationKey_old, msg = generate_private_key(options[:old_rev_pwd].to_s, 'ed25519-priv', options)
531
580
  end
532
581
  else
533
- revocationKey_old, msg = decode_private_key(options[:old_rev_enc].to_s)
582
+ revocationKey_old, msg = decode_private_key(options[:old_rev_enc].to_s, options)
534
583
  end
535
584
  else
536
- revocationKey_old, msg = read_private_key(options[:old_rev_key].to_s)
585
+ revocationKey_old, msg = read_private_key(options[:old_rev_key].to_s, options)
537
586
  end
538
587
  if revocationKey_old.nil?
539
588
  return [nil, "invalid or missing old private revocation key"]
540
589
  end
541
590
 
542
591
  if options[:rev_key].nil? && options[:rev_pwd].nil? && options[:rev_enc].nil?
543
- revocationKey, msg = read_private_key(did10 + "_revocation_key.b58")
592
+ revocationKey, msg = read_private_key(did10 + "_revocation_key.enc", options)
544
593
  revocationLog = read_private_storage(did10 + "_revocation.json")
545
594
  else
546
595
  if options[:rev_pwd].nil?
547
596
  if options[:rev_enc].nil?
548
- revocationKey, msg = read_private_key(options[:rev_key].to_s)
597
+ revocationKey, msg = read_private_key(options[:rev_key].to_s, options)
549
598
  else
550
- revocationKey, msg = decode_private_key(options[:rev_enc].to_s)
599
+ revocationKey, msg = decode_private_key(options[:rev_enc].to_s, options)
551
600
  end
552
601
  else
553
- revocationKey, msg = generate_private_key(options[:rev_pwd].to_s, 'ed25519-priv')
602
+ revocationKey, msg = generate_private_key(options[:rev_pwd].to_s, 'ed25519-priv', options)
554
603
  end
555
604
  # re-build revocation document
556
605
  did_old_doc = did_info["doc"]["doc"]
557
606
  ts_old = did_info["log"].last["ts"]
558
- publicKey_old = public_key(privateKey_old).first
559
- pubRevoKey_old = public_key(revocationKey_old).first
607
+ publicKey_old = public_key(privateKey_old, options).first
608
+ pubRevoKey_old = public_key(revocationKey_old, options).first
560
609
  did_key_old = publicKey_old + ":" + pubRevoKey_old
561
610
  subDid = {"doc": did_old_doc, "key": did_key_old}.to_json
562
- subDidHash = hash(canonical(subDid))
563
- signedSubDidHash = sign(subDidHash, revocationKey_old).first
611
+ subDidHash = multi_hash(canonical(subDid), LOG_HASH_OPTIONS).first
612
+ signedSubDidHash = sign(subDidHash, revocationKey_old, options).first
564
613
  revocationLog = {
565
614
  "ts": ts_old,
566
615
  "op": 1, # REVOKE
@@ -574,8 +623,8 @@ class Oydid
574
623
 
575
624
  revoc_log = JSON.parse(revocationLog)
576
625
  revoc_log["previous"] = [
577
- hash(canonical(log_old[did_info["doc_log_id"].to_i])),
578
- hash(canonical(log_old[did_info["termination_log_id"].to_i]))
626
+ multi_hash(canonical(log_old[did_info["doc_log_id"].to_i]), LOG_HASH_OPTIONS).first,
627
+ multi_hash(canonical(log_old[did_info["termination_log_id"].to_i]), LOG_HASH_OPTIONS).first,
579
628
  ]
580
629
  return [revoc_log, ""]
581
630
  end
@@ -628,10 +677,16 @@ class Oydid
628
677
  target_location = DEFAULT_LOCATION
629
678
  end
630
679
  if did.include?(LOCATION_PREFIX)
631
- hash_split = did.split(LOCATION_PREFIX)
632
- did = hash_split[0]
633
- source_location = hash_split[1]
680
+ tmp = did.split(LOCATION_PREFIX)
681
+ did = tmp[0]
682
+ source_location = tmp[1]
634
683
  end
684
+ if did.include?(CGI.escape LOCATION_PREFIX)
685
+ tmp = did.split(CGI.escape LOCATION_PREFIX)
686
+ did = tmp[0]
687
+ source_location = tmp[1]
688
+ end
689
+
635
690
  if source_location.to_s == ""
636
691
  source_location = DEFAULT_LOCATION
637
692
  end
@@ -657,7 +712,7 @@ class Oydid
657
712
  # write did to new location
658
713
  options[:doc_location] = target_location
659
714
  options[:log_location] = target_location
660
- options[:previous_clone] = hash(canonical(source_log)) + LOCATION_PREFIX + source_location
715
+ options[:previous_clone] = multi_hash(canonical(source_log), LOG_HASH_OPTIONS).first + LOCATION_PREFIX + source_location
661
716
  options[:source_location] = source_location
662
717
  options[:source_did] = source_did["did"]
663
718
  retVal, msg = write(source_did["doc"]["doc"], nil, "clone", options)
@@ -665,6 +720,122 @@ class Oydid
665
720
  end
666
721
 
667
722
  def self.w3c(did_info, options)
723
+ did = percent_encode(did_info["did"])
724
+ if !did.start_with?("did:oyd:")
725
+ did = "did:oyd:" + did
726
+ end
727
+
728
+ didDoc = did_info.transform_keys(&:to_s)["doc"]
729
+ pubDocKey = didDoc["key"].split(":")[0] rescue ""
730
+ pubRevKey = didDoc["key"].split(":")[1] rescue ""
731
+
732
+ wd = {}
733
+ if didDoc["doc"].is_a?(Hash)
734
+ if didDoc["doc"]["@context"].nil?
735
+ wd["@context"] = ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1"]
736
+ else
737
+ if didDoc["doc"]["@context"].is_a?(Array)
738
+ wd["@context"] = ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1"] + didDoc["doc"]["@context"]
739
+ else
740
+ wd["@context"] = ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1", didDoc["doc"]["@context"]]
741
+ end
742
+ didDoc["doc"].delete("@context")
743
+ end
744
+ else
745
+ wd["@context"] = ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1"]
746
+ end
747
+ wd["id"] = percent_encode(did)
748
+ wd["verificationMethod"] = [{
749
+ "id": did + "#key-doc",
750
+ "type": "Ed25519VerificationKey2020",
751
+ "controller": did,
752
+ "publicKeyMultibase": pubDocKey
753
+ },{
754
+ "id": did + "#key-rev",
755
+ "type": "Ed25519VerificationKey2020",
756
+ "controller": did,
757
+ "publicKeyMultibase": pubRevKey
758
+ }]
759
+
760
+ equivalentIds = []
761
+ did_info["log"].each do |log|
762
+ if log["op"] == 2 || log["op"] == 3
763
+ eid = percent_encode("did:oyd:" + log["doc"])
764
+ if eid != did
765
+ equivalentIds << eid
766
+ end
767
+ end
768
+ end unless did_info["log"].nil?
769
+ if equivalentIds.length > 0
770
+ wd[:alsoKnownAs] = equivalentIds
771
+ end
772
+
773
+ if didDoc["doc"].is_a?(Hash) && !didDoc["doc"]["service"].nil?
774
+ location = options[:location]
775
+ if location.nil?
776
+ location = get_location(did_info["did"].to_s)
777
+ end
778
+ wd = wd.merge(didDoc["doc"])
779
+ wdf = wd["service"].first
780
+ wdf = { "id": did + "#payload",
781
+ "type": "Custom",
782
+ "serviceEndpoint": location }.merge(wdf)
783
+ wd["service"] = [wdf] + wd["service"].drop(1)
784
+ else
785
+ payload = nil
786
+ if didDoc["doc"].is_a?(Hash)
787
+ didDoc = didDoc["doc"]
788
+ if didDoc["authentication"].to_s != ""
789
+ wd["authentication"] = didDoc["authentication"]
790
+ didDoc.delete("authentication")
791
+ end
792
+ if didDoc["assertionMethod"].to_s != ""
793
+ wd["assertionMethod"] = didDoc["assertionMethod"]
794
+ didDoc.delete("assertionMethod")
795
+ end
796
+ if didDoc["keyAgreement"].to_s != ""
797
+ wd["keyAgreement"] = didDoc["keyAgreement"]
798
+ didDoc.delete("keyAgreement")
799
+ end
800
+ if didDoc["capabilityInvocation"].to_s != ""
801
+ wd["capabilityInvocation"] = didDoc["capabilityInvocation"]
802
+ didDoc.delete("capabilityInvocation")
803
+ end
804
+ if didDoc["capabilityDelegation"].to_s != ""
805
+ wd["capabilityDelegation"] = didDoc["capabilityDelegation"]
806
+ didDoc.delete("capabilityDelegation")
807
+ end
808
+ payload = didDoc
809
+ else
810
+ payload = didDoc["doc"]
811
+ end
812
+ if !payload.nil?
813
+ location = options[:location]
814
+ if location.nil?
815
+ location = get_location(did_info["did"].to_s)
816
+ end
817
+ if payload.is_a?(Array) &&
818
+ payload.length == 1 &&
819
+ payload.first.is_a?(Hash) &&
820
+ !payload.first["id"].nil? &&
821
+ !payload.first["type"].nil? &&
822
+ !payload.first["serviceEndpoint"].nil?
823
+ wd["service"] = payload
824
+ else
825
+ wd["service"] = [{
826
+ "id": did + "#payload",
827
+ "type": "Custom",
828
+ "serviceEndpoint": location,
829
+ "payload": payload
830
+ }]
831
+ end
832
+ end
833
+ end
834
+ return wd
835
+ end
836
+
837
+
838
+ def self.w3c_legacy(did_info, options)
668
839
  did = did_info["did"]
669
840
  if !did.start_with?("did:oyd:")
670
841
  did = "did:oyd:" + did
@@ -675,8 +846,8 @@ class Oydid
675
846
  pubRevKey = didDoc["key"].split(":")[1] rescue ""
676
847
 
677
848
  wd = {}
678
- wd["@context"] = "https://www.w3.org/ns/did/v1"
679
- wd["id"] = did
849
+ wd["@context"] = ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1"]
850
+ wd["id"] = percent_encode(did)
680
851
  wd["verificationMethod"] = [{
681
852
  "id": did + "#key-doc",
682
853
  "type": "Ed25519VerificationKey2020",
@@ -689,47 +860,46 @@ class Oydid
689
860
  "publicKeyMultibase": pubRevKey
690
861
  }]
691
862
 
692
- if didDoc["@context"].to_s == "https://www.w3.org/ns/did/v1"
863
+ if didDoc["@context"] == ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1"]
693
864
  didDoc.delete("@context")
694
865
  end
695
- if didDoc["doc"].to_s != ""
696
- didDoc = didDoc["doc"]
697
- end
698
- newDidDoc = []
699
- if didDoc.is_a?(Hash)
700
- if didDoc["authentication"].to_s != ""
701
- wd["authentication"] = didDoc["authentication"]
702
- didDoc.delete("authentication")
703
- end
704
- if didDoc["service"].to_s != ""
705
- if didDoc["service"].is_a?(Array)
706
- newDidDoc = didDoc.dup
707
- newDidDoc.delete("service")
708
- if newDidDoc == {}
709
- newDidDoc = []
710
- else
711
- if !newDidDoc.is_a?(Array)
712
- newDidDoc=[newDidDoc]
866
+ if !didDoc["doc"].nil?
867
+ newDidDoc = []
868
+ if didDoc.is_a?(Hash)
869
+ if didDoc["authentication"].to_s != ""
870
+ wd["authentication"] = didDoc["authentication"]
871
+ didDoc.delete("authentication")
872
+ end
873
+ if didDoc["service"].to_s != ""
874
+ if didDoc["service"].is_a?(Array)
875
+ newDidDoc = didDoc.dup
876
+ newDidDoc.delete("service")
877
+ if newDidDoc == {}
878
+ newDidDoc = []
879
+ else
880
+ if !newDidDoc.is_a?(Array)
881
+ newDidDoc=[newDidDoc]
882
+ end
713
883
  end
884
+ newDidDoc << didDoc["service"]
885
+ newDidDoc = newDidDoc.flatten
886
+ else
887
+ newDidDoc = didDoc["service"]
714
888
  end
715
- newDidDoc << didDoc["service"]
716
- newDidDoc = newDidDoc.flatten
717
889
  else
718
- newDidDoc = didDoc["service"]
890
+ newDidDoc = didDoc["doc"]
719
891
  end
720
892
  else
721
- newDidDoc = didDoc
893
+ newDidDoc = didDoc["doc"]
722
894
  end
723
- else
724
- newDidDoc = didDoc
895
+ wd["service"] = newDidDoc
725
896
  end
726
- wd["service"] = newDidDoc
727
897
  return wd
728
898
  end
729
899
 
730
900
  def self.fromW3C(didDocument, options)
731
901
  didDocument = didDocument.transform_keys(&:to_s)
732
- if didDocument["@context"].to_s == "https://www.w3.org/ns/did/v1"
902
+ if didDocument["@context"] == ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1"]
733
903
  didDocument.delete("@context")
734
904
  end
735
905
  didDocument