oydid 0.4.4 → 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 +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