oydid 0.4.3 → 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 +204 -26
  4. data/lib/oydid/didcomm.rb +25 -6
  5. data/lib/oydid/log.rb +15 -7
  6. data/lib/oydid/vc.rb +264 -0
  7. data/lib/oydid.rb +286 -111
  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
@@ -139,11 +149,19 @@ class Oydid
139
149
  return write(content, did, "update", options)
140
150
  end
141
151
 
152
+ def self.simulate_did(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]
155
+ return [user_did, msg]
156
+ end
157
+
142
158
  def self.generate_base(content, did, mode, options)
143
159
  # input validation
144
160
  did_doc = JSON.parse(content.to_json) rescue nil
145
161
  if did_doc.nil?
146
- 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
147
165
  end
148
166
  did_old = nil
149
167
  log_old = nil
@@ -160,35 +178,35 @@ class Oydid
160
178
  operation_mode = 2 # CREATE
161
179
  if options[:doc_key].nil?
162
180
  if options[:doc_enc].nil?
163
- 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)
164
182
  else
165
- privateKey, msg = decode_private_key(options[:doc_enc].to_s)
183
+ privateKey, msg = decode_private_key(options[:doc_enc].to_s, options)
166
184
  end
167
185
  else
168
- privateKey, msg = read_private_key(options[:doc_key].to_s)
186
+ privateKey, msg = read_private_key(options[:doc_key].to_s, options)
169
187
  if privateKey.nil?
170
- 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"]
171
189
  end
172
190
  end
173
191
  if options[:rev_key].nil?
174
192
  if options[:rev_enc].nil?
175
- 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)
176
194
  else
177
- revocationKey, msg = decode_private_key(options[:rev_enc].to_s)
195
+ revocationKey, msg = decode_private_key(options[:rev_enc].to_s, options)
178
196
  end
179
197
  else
180
- revocationKey, msg = read_private_key(options[:rev_key].to_s)
198
+ revocationKey, msg = read_private_key(options[:rev_key].to_s, options)
181
199
  if revocationKey.nil?
182
- 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"]
183
201
  end
184
202
  end
185
203
  else # mode == "update" => read information
186
204
  did_info, msg = read(did, options)
187
205
  if did_info.nil?
188
- 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)"]
189
207
  end
190
208
  if did_info["error"] != 0
191
- 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]
192
210
  end
193
211
 
194
212
  did = did_info["did"]
@@ -210,75 +228,75 @@ class Oydid
210
228
  if options[:old_doc_key].nil?
211
229
  if options[:old_doc_enc].nil?
212
230
  if options[:old_doc_pwd].nil?
213
- privateKey_old = read_private_storage(did10_old + "_private_key.b58")
231
+ privateKey_old = read_private_storage(did10_old + "_private_key.enc")
214
232
  else
215
- 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)
216
234
  end
217
235
  else
218
- 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)
219
237
  end
220
238
  else
221
- 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)
222
240
  end
241
+
223
242
  if privateKey_old.nil?
224
- 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"]
225
244
  end
226
245
  if options[:old_rev_key].nil?
227
246
  if options[:old_rev_enc].nil?
228
247
  if options[:old_rev_pwd].nil?
229
- revocationKey_old = read_private_storage(did10_old + "_revocation_key.b58")
248
+ revocationKey_old = read_private_storage(did10_old + "_revocation_key.enc")
230
249
  else
231
- 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)
232
251
  end
233
252
  else
234
- 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)
235
254
  end
236
255
  else
237
- 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)
238
257
  end
239
258
  if revocationKey_old.nil?
240
- 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"]
241
260
  end
242
-
243
261
  # key management
244
262
  if options[:doc_key].nil?
245
263
  if options[:doc_enc].nil?
246
- 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)
247
265
  else
248
- privateKey, msg = decode_private_key(options[:doc_enc].to_s)
266
+ privateKey, msg = decode_private_key(options[:doc_enc].to_s, options)
249
267
  end
250
268
  else
251
- privateKey, msg = read_private_key(options[:doc_key].to_s)
269
+ privateKey, msg = read_private_key(options[:doc_key].to_s, options)
252
270
  end
253
271
  # if options[:rev_key].nil? && options[:rev_pwd].nil? && options[:rev_enc].nil?
254
272
  # revocationLog = read_private_storage(did10 + "_revocation.json")
255
273
  # if revocationLog.nil?
256
- # 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"]
257
275
  # end
258
276
  # else
259
277
  if options[:rev_key].nil?
260
278
  if options[:rev_enc].nil?
261
279
  if options[:rev_pwd].nil?
262
- revocationKey, msg = generate_private_key("", 'ed25519-priv')
280
+ revocationKey, msg = generate_private_key("", 'ed25519-priv', options)
263
281
  else
264
- 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)
265
283
  end
266
284
  else
267
- revocationKey, msg = decode_private_key(options[:rev_enc].to_s)
285
+ revocationKey, msg = decode_private_key(options[:rev_enc].to_s, options)
268
286
  end
269
287
  else
270
- revocationKey, msg = read_private_key(options[:rev_key].to_s)
288
+ revocationKey, msg = read_private_key(options[:rev_key].to_s, options)
271
289
  end
272
290
 
273
291
  # re-build revocation document
274
292
  did_old_doc = did_info["doc"]["doc"]
275
293
  ts_old = did_info["log"].last["ts"]
276
- publicKey_old = public_key(privateKey_old).first
277
- 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
278
296
  did_key_old = publicKey_old + ":" + pubRevoKey_old
279
297
  subDid = {"doc": did_old_doc, "key": did_key_old}.to_json
280
- subDidHash = hash(canonical(subDid))
281
- signedSubDidHash = sign(subDidHash, revocationKey_old).first
298
+ subDidHash = multi_hash(canonical(subDid), LOG_HASH_OPTIONS).first
299
+ signedSubDidHash = sign(subDidHash, revocationKey_old, options).first
282
300
  revocationLog = {
283
301
  "ts": ts_old,
284
302
  "op": 1, # REVOKE
@@ -287,38 +305,41 @@ class Oydid
287
305
  # end
288
306
  revoc_log = JSON.parse(revocationLog)
289
307
  revoc_log["previous"] = [
290
- hash(canonical(log_old[did_info["doc_log_id"].to_i])),
291
- 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
292
310
  ]
293
- prev_hash = [hash(canonical(revoc_log))]
311
+ prev_hash = [multi_hash(canonical(revoc_log), LOG_HASH_OPTIONS).first]
294
312
  end
295
-
296
- publicKey = public_key(privateKey).first
297
- pubRevoKey = public_key(revocationKey).first
313
+ publicKey = public_key(privateKey, options).first
314
+ pubRevoKey = public_key(revocationKey, options).first
298
315
  did_key = publicKey + ":" + pubRevoKey
299
316
 
300
317
  # build new revocation document
301
318
  subDid = {"doc": did_doc, "key": did_key}.to_json
302
- subDidHash = hash(canonical(subDid))
303
- 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
304
325
  r1 = { "ts": ts,
305
326
  "op": 1, # REVOKE
306
327
  "doc": subDidHash,
307
328
  "sig": signedSubDidHash }.transform_keys(&:to_s)
308
329
 
309
330
  # build termination log entry
310
- l2_doc = hash(canonical(r1))
331
+ l2_doc = multi_hash(canonical(r1), LOG_HASH_OPTIONS).first
311
332
  if !doc_location.nil?
312
333
  l2_doc += LOCATION_PREFIX + doc_location.to_s
313
334
  end
314
335
  l2 = { "ts": ts,
315
336
  "op": 0, # TERMINATE
316
337
  "doc": l2_doc,
317
- "sig": sign(l2_doc, privateKey).first,
338
+ "sig": sign(l2_doc, privateKey, options).first,
318
339
  "previous": [] }.transform_keys(&:to_s)
319
340
 
320
341
  # build actual DID document
321
- log_str = hash(canonical(l2))
342
+ log_str = multi_hash(canonical(l2), LOG_HASH_OPTIONS).first
322
343
  if !doc_location.nil?
323
344
  log_str += LOCATION_PREFIX + doc_location.to_s
324
345
  end
@@ -327,7 +348,7 @@ class Oydid
327
348
  "log": log_str }.transform_keys(&:to_s)
328
349
 
329
350
  # create DID
330
- l1_doc = hash(canonical(didDocument))
351
+ l1_doc = multi_hash(canonical(didDocument), options).first
331
352
  if !doc_location.nil?
332
353
  l1_doc += LOCATION_PREFIX + doc_location.to_s
333
354
  end
@@ -340,13 +361,13 @@ class Oydid
340
361
  "ts": ts,
341
362
  "op": 4, # CLONE
342
363
  "doc": l1_doc,
343
- "sig": sign(l1_doc, privateKey).first,
364
+ "sig": sign(l1_doc, privateKey, options).first,
344
365
  "previous": [options[:previous_clone].to_s]
345
366
  }
346
367
  retVal = HTTParty.post(options[:source_location] + "/log/" + options[:source_did],
347
368
  headers: { 'Content-Type' => 'application/json' },
348
369
  body: {"log": new_log}.to_json )
349
- prev_hash = [hash(canonical(new_log))]
370
+ prev_hash = [multi_hash(canonical(new_log), LOG_HASH_OPTIONS).first]
350
371
  end
351
372
 
352
373
  # build creation log entry
@@ -354,17 +375,40 @@ class Oydid
354
375
  l1 = { "ts": ts,
355
376
  "op": operation_mode, # UPDATE
356
377
  "doc": l1_doc,
357
- "sig": sign(l1_doc, privateKey_old).first,
378
+ "sig": sign(l1_doc, privateKey_old, options).first,
358
379
  "previous": prev_hash }.transform_keys(&:to_s)
359
380
  else
360
381
  l1 = { "ts": ts,
361
382
  "op": operation_mode, # CREATE
362
383
  "doc": l1_doc,
363
- "sig": sign(l1_doc, privateKey).first,
384
+ "sig": sign(l1_doc, privateKey, options).first,
364
385
  "previous": prev_hash }.transform_keys(&:to_s)
365
386
  end
366
387
 
367
- 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, ""]
368
412
  end
369
413
 
370
414
  def self.publish(did, didDocument, logs, options)
@@ -410,11 +454,22 @@ class Oydid
410
454
  end
411
455
 
412
456
  def self.write(content, did, mode, options)
413
- 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
+
414
470
  if msg != ""
415
471
  return [nil, msg]
416
472
  end
417
-
418
473
  did_hash = did.delete_prefix("did:oyd:")
419
474
  did10 = did_hash[0,10]
420
475
  did_old_hash = did_old.delete_prefix("did:oyd:") rescue nil
@@ -430,7 +485,6 @@ class Oydid
430
485
  doc_location = DEFAULT_LOCATION
431
486
  end
432
487
  end
433
-
434
488
  case doc_location.to_s
435
489
  when /^http/
436
490
  logs = [revoc_log, l1, l2].flatten.compact
@@ -458,8 +512,8 @@ class Oydid
458
512
  retVal["revocation_key"] = revocationKey
459
513
  retVal["revocation_log"] = r1
460
514
  else
461
- write_private_storage(privateKey, did10 + "_private_key.b58")
462
- 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")
463
517
  write_private_storage(r1.to_json, did10 + "_revocation.json")
464
518
  end
465
519
 
@@ -504,15 +558,15 @@ class Oydid
504
558
  if options[:old_doc_key].nil?
505
559
  if options[:old_doc_enc].nil?
506
560
  if options[:old_doc_pwd].nil?
507
- privateKey_old = read_private_storage(did10_old + "_private_key.b58")
561
+ privateKey_old = read_private_storage(did10_old + "_private_key.enc")
508
562
  else
509
- 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)
510
564
  end
511
565
  else
512
- 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)
513
567
  end
514
568
  else
515
- 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)
516
570
  end
517
571
  if privateKey_old.nil?
518
572
  return [nil, "invalid or missing old private document key"]
@@ -520,42 +574,42 @@ class Oydid
520
574
  if options[:old_rev_key].nil?
521
575
  if options[:old_rev_enc].nil?
522
576
  if options[:old_rev_pwd].nil?
523
- revocationKey_old = read_private_storage(did10_old + "_revocation_key.b58")
577
+ revocationKey_old = read_private_storage(did10_old + "_revocation_key.enc")
524
578
  else
525
- 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)
526
580
  end
527
581
  else
528
- 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)
529
583
  end
530
584
  else
531
- 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)
532
586
  end
533
587
  if revocationKey_old.nil?
534
588
  return [nil, "invalid or missing old private revocation key"]
535
589
  end
536
590
 
537
591
  if options[:rev_key].nil? && options[:rev_pwd].nil? && options[:rev_enc].nil?
538
- revocationKey, msg = read_private_key(did10 + "_revocation_key.b58")
592
+ revocationKey, msg = read_private_key(did10 + "_revocation_key.enc", options)
539
593
  revocationLog = read_private_storage(did10 + "_revocation.json")
540
594
  else
541
595
  if options[:rev_pwd].nil?
542
596
  if options[:rev_enc].nil?
543
- revocationKey, msg = read_private_key(options[:rev_key].to_s)
597
+ revocationKey, msg = read_private_key(options[:rev_key].to_s, options)
544
598
  else
545
- revocationKey, msg = decode_private_key(options[:rev_enc].to_s)
599
+ revocationKey, msg = decode_private_key(options[:rev_enc].to_s, options)
546
600
  end
547
601
  else
548
- 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)
549
603
  end
550
604
  # re-build revocation document
551
605
  did_old_doc = did_info["doc"]["doc"]
552
606
  ts_old = did_info["log"].last["ts"]
553
- publicKey_old = public_key(privateKey_old).first
554
- 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
555
609
  did_key_old = publicKey_old + ":" + pubRevoKey_old
556
610
  subDid = {"doc": did_old_doc, "key": did_key_old}.to_json
557
- subDidHash = hash(canonical(subDid))
558
- signedSubDidHash = sign(subDidHash, revocationKey_old).first
611
+ subDidHash = multi_hash(canonical(subDid), LOG_HASH_OPTIONS).first
612
+ signedSubDidHash = sign(subDidHash, revocationKey_old, options).first
559
613
  revocationLog = {
560
614
  "ts": ts_old,
561
615
  "op": 1, # REVOKE
@@ -569,8 +623,8 @@ class Oydid
569
623
 
570
624
  revoc_log = JSON.parse(revocationLog)
571
625
  revoc_log["previous"] = [
572
- hash(canonical(log_old[did_info["doc_log_id"].to_i])),
573
- 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,
574
628
  ]
575
629
  return [revoc_log, ""]
576
630
  end
@@ -623,10 +677,16 @@ class Oydid
623
677
  target_location = DEFAULT_LOCATION
624
678
  end
625
679
  if did.include?(LOCATION_PREFIX)
626
- hash_split = did.split(LOCATION_PREFIX)
627
- did = hash_split[0]
628
- source_location = hash_split[1]
680
+ tmp = did.split(LOCATION_PREFIX)
681
+ did = tmp[0]
682
+ source_location = tmp[1]
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]
629
688
  end
689
+
630
690
  if source_location.to_s == ""
631
691
  source_location = DEFAULT_LOCATION
632
692
  end
@@ -652,7 +712,7 @@ class Oydid
652
712
  # write did to new location
653
713
  options[:doc_location] = target_location
654
714
  options[:log_location] = target_location
655
- 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
656
716
  options[:source_location] = source_location
657
717
  options[:source_did] = source_did["did"]
658
718
  retVal, msg = write(source_did["doc"]["doc"], nil, "clone", options)
@@ -660,6 +720,122 @@ class Oydid
660
720
  end
661
721
 
662
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)
663
839
  did = did_info["did"]
664
840
  if !did.start_with?("did:oyd:")
665
841
  did = "did:oyd:" + did
@@ -670,8 +846,8 @@ class Oydid
670
846
  pubRevKey = didDoc["key"].split(":")[1] rescue ""
671
847
 
672
848
  wd = {}
673
- wd["@context"] = "https://www.w3.org/ns/did/v1"
674
- 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)
675
851
  wd["verificationMethod"] = [{
676
852
  "id": did + "#key-doc",
677
853
  "type": "Ed25519VerificationKey2020",
@@ -684,47 +860,46 @@ class Oydid
684
860
  "publicKeyMultibase": pubRevKey
685
861
  }]
686
862
 
687
- 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"]
688
864
  didDoc.delete("@context")
689
865
  end
690
- if didDoc["doc"].to_s != ""
691
- didDoc = didDoc["doc"]
692
- end
693
- newDidDoc = []
694
- if didDoc.is_a?(Hash)
695
- if didDoc["authentication"].to_s != ""
696
- wd["authentication"] = didDoc["authentication"]
697
- didDoc.delete("authentication")
698
- end
699
- if didDoc["service"].to_s != ""
700
- if didDoc["service"].is_a?(Array)
701
- newDidDoc = didDoc.dup
702
- newDidDoc.delete("service")
703
- if newDidDoc == {}
704
- newDidDoc = []
705
- else
706
- if !newDidDoc.is_a?(Array)
707
- 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
708
883
  end
884
+ newDidDoc << didDoc["service"]
885
+ newDidDoc = newDidDoc.flatten
886
+ else
887
+ newDidDoc = didDoc["service"]
709
888
  end
710
- newDidDoc << didDoc["service"]
711
- newDidDoc = newDidDoc.flatten
712
889
  else
713
- newDidDoc = didDoc["service"]
890
+ newDidDoc = didDoc["doc"]
714
891
  end
715
892
  else
716
- newDidDoc = didDoc
893
+ newDidDoc = didDoc["doc"]
717
894
  end
718
- else
719
- newDidDoc = didDoc
895
+ wd["service"] = newDidDoc
720
896
  end
721
- wd["service"] = newDidDoc
722
897
  return wd
723
898
  end
724
899
 
725
900
  def self.fromW3C(didDocument, options)
726
901
  didDocument = didDocument.transform_keys(&:to_s)
727
- 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"]
728
903
  didDocument.delete("@context")
729
904
  end
730
905
  didDocument