oydid 0.4.3 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
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