oydid 0.4.4 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/oydid/basic.rb +149 -33
  4. data/lib/oydid/didcomm.rb +9 -9
  5. data/lib/oydid/log.rb +14 -7
  6. data/lib/oydid/vc.rb +308 -0
  7. data/lib/oydid.rb +305 -112
  8. data/spec/input/basic/sample_b16_dec.doc +1 -0
  9. data/spec/input/basic/sample_b17_edec.doc +1 -0
  10. data/spec/input/basic/sample_b32_dec.doc +1 -0
  11. data/spec/input/basic/sample_b58_enc.doc +1 -0
  12. data/spec/input/basic/sample_b64_dec.doc +1 -0
  13. data/spec/input/basic/sample_b64_enc.doc +1 -0
  14. data/spec/input/basic/sample_blake2b-16_b16_hash.doc +1 -0
  15. data/spec/input/basic/sample_blake2b-32_b32_hash.doc +1 -0
  16. data/spec/input/basic/sample_blake2b-64_b58_hash.doc +1 -0
  17. data/spec/input/basic/sample_invalid2_readkey.doc +1 -1
  18. data/spec/input/basic/sample_invalid3_readkey.doc +1 -1
  19. data/spec/input/basic/sample_readkey.doc +1 -1
  20. data/spec/input/basic/sample_sha2-256_b58_hash.doc +1 -0
  21. data/spec/input/basic/sample_sha2-512_b58_hash.doc +1 -0
  22. data/spec/input/basic/sample_sha3-224_b64_hash.doc +1 -0
  23. data/spec/output/basic/sample_b16_dec.doc +1 -0
  24. data/spec/output/basic/sample_b16_enc.doc +1 -0
  25. data/spec/output/basic/sample_b17_edec.doc +2 -0
  26. data/spec/output/basic/sample_b17_enc.doc +1 -0
  27. data/spec/output/basic/sample_b32_dec.doc +1 -0
  28. data/spec/output/basic/sample_b32_enc.doc +1 -0
  29. data/spec/output/basic/sample_b58_dec.doc +1 -0
  30. data/spec/output/basic/sample_b64_dec.doc +1 -0
  31. data/spec/output/basic/sample_b64_enc.doc +1 -0
  32. data/spec/output/basic/sample_blake2b-16_b16_hash.doc +1 -0
  33. data/spec/output/basic/sample_blake2b-32_b32_hash.doc +1 -0
  34. data/spec/output/basic/sample_blake2b-64_b58_hash.doc +1 -0
  35. data/spec/output/basic/sample_sha2-512_b58_hash.doc +1 -0
  36. data/spec/output/basic/sample_sha3-224_b64_hash.doc +1 -0
  37. data/spec/oydid_spec.rb +95 -13
  38. metadata +72 -19
  39. /data/spec/input/basic/{sample_enc.doc → sample_b16_enc.doc} +0 -0
  40. /data/spec/input/basic/{sample_hash.doc → sample_b17_enc.doc} +0 -0
  41. /data/spec/{output/basic/sample_dec.doc → input/basic/sample_b32_enc.doc} +0 -0
  42. /data/spec/input/basic/{sample_dec.doc → sample_b58_dec.doc} +0 -0
  43. /data/spec/output/basic/{sample_enc.doc → sample_b58_enc.doc} +0 -0
  44. /data/spec/output/basic/{sample_hash.doc → sample_sha2-256_b58_hash.doc} +0 -0
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,46 @@ 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
204
+ # if a location is provided this is only relevant for writing the DID
205
+ update_location = options[:location]
206
+ update_doc_location = options[:doc_location]
207
+ update_log_location = options[:log_location]
208
+ options[:location] = nil
209
+ options[:doc_location] = nil
210
+ options[:log_location] = nil
191
211
  did_info, msg = read(did, options)
212
+ options[:location] = options[:location]
213
+ options[:doc_location] = options[:doc_location]
214
+ options[:log_location] = options[:log_location]
215
+
192
216
  if did_info.nil?
193
- return [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "cannot resolve DID (on updating DID)"]
217
+ return [nil, nil, nil, "cannot resolve DID (on updating DID)"]
194
218
  end
195
219
  if did_info["error"] != 0
196
- return [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, did_info["message"].to_s]
220
+ return [nil, nil, nil, did_info["message"].to_s]
197
221
  end
198
222
 
199
223
  did = did_info["did"]
@@ -215,75 +239,75 @@ class Oydid
215
239
  if options[:old_doc_key].nil?
216
240
  if options[:old_doc_enc].nil?
217
241
  if options[:old_doc_pwd].nil?
218
- privateKey_old = read_private_storage(did10_old + "_private_key.b58")
242
+ privateKey_old = read_private_storage(did10_old + "_private_key.enc")
219
243
  else
220
- privateKey_old, msg = generate_private_key(options[:old_doc_pwd].to_s, 'ed25519-priv')
244
+ privateKey_old, msg = generate_private_key(options[:old_doc_pwd].to_s, 'ed25519-priv', options)
221
245
  end
222
246
  else
223
- privateKey_old, msg = decode_private_key(options[:old_doc_enc].to_s)
247
+ privateKey_old, msg = decode_private_key(options[:old_doc_enc].to_s, options)
224
248
  end
225
249
  else
226
- privateKey_old, msg = read_private_key(options[:old_doc_key].to_s)
250
+ privateKey_old, msg = read_private_key(options[:old_doc_key].to_s, options)
227
251
  end
252
+
228
253
  if privateKey_old.nil?
229
- return [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "invalid or missing old private document key"]
254
+ return [nil, nil, nil, "invalid or missing old private document key"]
230
255
  end
231
256
  if options[:old_rev_key].nil?
232
257
  if options[:old_rev_enc].nil?
233
258
  if options[:old_rev_pwd].nil?
234
- revocationKey_old = read_private_storage(did10_old + "_revocation_key.b58")
259
+ revocationKey_old = read_private_storage(did10_old + "_revocation_key.enc")
235
260
  else
236
- revocationKey_old, msg = generate_private_key(options[:old_rev_pwd].to_s, 'ed25519-priv')
261
+ revocationKey_old, msg = generate_private_key(options[:old_rev_pwd].to_s, 'ed25519-priv', options)
237
262
  end
238
263
  else
239
- revocationKey_old, msg = decode_private_key(options[:old_rev_enc].to_s)
264
+ revocationKey_old, msg = decode_private_key(options[:old_rev_enc].to_s, options)
240
265
  end
241
266
  else
242
- revocationKey_old, msg = read_private_key(options[:old_rev_key].to_s)
267
+ revocationKey_old, msg = read_private_key(options[:old_rev_key].to_s, options)
243
268
  end
244
269
  if revocationKey_old.nil?
245
- return [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "invalid or missing old private revocation key"]
270
+ return [nil, nil, nil, "invalid or missing old private revocation key"]
246
271
  end
247
-
248
272
  # key management
249
273
  if options[:doc_key].nil?
250
274
  if options[:doc_enc].nil?
251
- privateKey, msg = generate_private_key(options[:doc_pwd].to_s, 'ed25519-priv')
275
+ privateKey, msg = generate_private_key(options[:doc_pwd].to_s, 'ed25519-priv', options)
252
276
  else
253
- privateKey, msg = decode_private_key(options[:doc_enc].to_s)
277
+ privateKey, msg = decode_private_key(options[:doc_enc].to_s, options)
254
278
  end
255
279
  else
256
- privateKey, msg = read_private_key(options[:doc_key].to_s)
280
+ privateKey, msg = read_private_key(options[:doc_key].to_s, options)
257
281
  end
258
282
  # if options[:rev_key].nil? && options[:rev_pwd].nil? && options[:rev_enc].nil?
259
283
  # revocationLog = read_private_storage(did10 + "_revocation.json")
260
284
  # if revocationLog.nil?
261
- # return [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "invalid or missing old revocation log"]
285
+ # return [nil, nil, nil, "invalid or missing old revocation log"]
262
286
  # end
263
287
  # else
264
288
  if options[:rev_key].nil?
265
289
  if options[:rev_enc].nil?
266
290
  if options[:rev_pwd].nil?
267
- revocationKey, msg = generate_private_key("", 'ed25519-priv')
291
+ revocationKey, msg = generate_private_key("", 'ed25519-priv', options)
268
292
  else
269
- revocationKey, msg = generate_private_key(options[:rev_pwd].to_s, 'ed25519-priv')
293
+ revocationKey, msg = generate_private_key(options[:rev_pwd].to_s, 'ed25519-priv', options)
270
294
  end
271
295
  else
272
- revocationKey, msg = decode_private_key(options[:rev_enc].to_s)
296
+ revocationKey, msg = decode_private_key(options[:rev_enc].to_s, options)
273
297
  end
274
298
  else
275
- revocationKey, msg = read_private_key(options[:rev_key].to_s)
299
+ revocationKey, msg = read_private_key(options[:rev_key].to_s, options)
276
300
  end
277
301
 
278
302
  # re-build revocation document
279
303
  did_old_doc = did_info["doc"]["doc"]
280
304
  ts_old = did_info["log"].last["ts"]
281
- publicKey_old = public_key(privateKey_old).first
282
- pubRevoKey_old = public_key(revocationKey_old).first
305
+ publicKey_old = public_key(privateKey_old, options).first
306
+ pubRevoKey_old = public_key(revocationKey_old, options).first
283
307
  did_key_old = publicKey_old + ":" + pubRevoKey_old
284
308
  subDid = {"doc": did_old_doc, "key": did_key_old}.to_json
285
- subDidHash = hash(canonical(subDid))
286
- signedSubDidHash = sign(subDidHash, revocationKey_old).first
309
+ subDidHash = multi_hash(canonical(subDid), LOG_HASH_OPTIONS).first
310
+ signedSubDidHash = sign(subDidHash, revocationKey_old, options).first
287
311
  revocationLog = {
288
312
  "ts": ts_old,
289
313
  "op": 1, # REVOKE
@@ -292,38 +316,48 @@ class Oydid
292
316
  # end
293
317
  revoc_log = JSON.parse(revocationLog)
294
318
  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]))
319
+ multi_hash(canonical(log_old[did_info["doc_log_id"].to_i]), LOG_HASH_OPTIONS).first,
320
+ multi_hash(canonical(log_old[did_info["termination_log_id"].to_i]), LOG_HASH_OPTIONS).first
297
321
  ]
298
- prev_hash = [hash(canonical(revoc_log))]
322
+ prev_hash = [multi_hash(canonical(revoc_log), LOG_HASH_OPTIONS).first]
299
323
  end
300
-
301
- publicKey = public_key(privateKey).first
302
- pubRevoKey = public_key(revocationKey).first
324
+ publicKey = public_key(privateKey, options).first
325
+ pubRevoKey = public_key(revocationKey, options).first
303
326
  did_key = publicKey + ":" + pubRevoKey
304
327
 
328
+ # check if pubKeys matches with existing DID Document
329
+ if mode == "update"
330
+ if did_key_old.to_s != did_info["doc"]["key"].to_s
331
+ return [nil, nil, nil, "keys from original DID don't match"]
332
+ end
333
+ end
334
+
305
335
  # build new revocation document
306
336
  subDid = {"doc": did_doc, "key": did_key}.to_json
307
- subDidHash = hash(canonical(subDid))
308
- signedSubDidHash = sign(subDidHash, revocationKey).first
337
+ retVal = multi_hash(canonical(subDid), LOG_HASH_OPTIONS)
338
+ if retVal.first.nil?
339
+ return [nil, nil, nil, retVal.last]
340
+ end
341
+ subDidHash = retVal.first
342
+ signedSubDidHash = sign(subDidHash, revocationKey, options).first
309
343
  r1 = { "ts": ts,
310
344
  "op": 1, # REVOKE
311
345
  "doc": subDidHash,
312
346
  "sig": signedSubDidHash }.transform_keys(&:to_s)
313
347
 
314
348
  # build termination log entry
315
- l2_doc = hash(canonical(r1))
349
+ l2_doc = multi_hash(canonical(r1), LOG_HASH_OPTIONS).first
316
350
  if !doc_location.nil?
317
351
  l2_doc += LOCATION_PREFIX + doc_location.to_s
318
352
  end
319
353
  l2 = { "ts": ts,
320
354
  "op": 0, # TERMINATE
321
355
  "doc": l2_doc,
322
- "sig": sign(l2_doc, privateKey).first,
356
+ "sig": sign(l2_doc, privateKey, options).first,
323
357
  "previous": [] }.transform_keys(&:to_s)
324
358
 
325
359
  # build actual DID document
326
- log_str = hash(canonical(l2))
360
+ log_str = multi_hash(canonical(l2), LOG_HASH_OPTIONS).first
327
361
  if !doc_location.nil?
328
362
  log_str += LOCATION_PREFIX + doc_location.to_s
329
363
  end
@@ -332,7 +366,7 @@ class Oydid
332
366
  "log": log_str }.transform_keys(&:to_s)
333
367
 
334
368
  # create DID
335
- l1_doc = hash(canonical(didDocument))
369
+ l1_doc = multi_hash(canonical(didDocument), options).first
336
370
  if !doc_location.nil?
337
371
  l1_doc += LOCATION_PREFIX + doc_location.to_s
338
372
  end
@@ -345,13 +379,13 @@ class Oydid
345
379
  "ts": ts,
346
380
  "op": 4, # CLONE
347
381
  "doc": l1_doc,
348
- "sig": sign(l1_doc, privateKey).first,
382
+ "sig": sign(l1_doc, privateKey, options).first,
349
383
  "previous": [options[:previous_clone].to_s]
350
384
  }
351
385
  retVal = HTTParty.post(options[:source_location] + "/log/" + options[:source_did],
352
386
  headers: { 'Content-Type' => 'application/json' },
353
387
  body: {"log": new_log}.to_json )
354
- prev_hash = [hash(canonical(new_log))]
388
+ prev_hash = [multi_hash(canonical(new_log), LOG_HASH_OPTIONS).first]
355
389
  end
356
390
 
357
391
  # build creation log entry
@@ -359,17 +393,39 @@ class Oydid
359
393
  l1 = { "ts": ts,
360
394
  "op": operation_mode, # UPDATE
361
395
  "doc": l1_doc,
362
- "sig": sign(l1_doc, privateKey_old).first,
396
+ "sig": sign(l1_doc, privateKey_old, options).first,
363
397
  "previous": prev_hash }.transform_keys(&:to_s)
364
398
  else
365
399
  l1 = { "ts": ts,
366
400
  "op": operation_mode, # CREATE
367
401
  "doc": l1_doc,
368
- "sig": sign(l1_doc, privateKey).first,
402
+ "sig": sign(l1_doc, privateKey, options).first,
369
403
  "previous": prev_hash }.transform_keys(&:to_s)
370
404
  end
371
405
 
372
- return [did, didDocument, revoc_log, l1, l2, r1, privateKey, revocationKey, did_old, log_old, ""]
406
+ # did, didDocument, revoc_log, l1, l2, r1, privateKey, revocationKey, did_old, log_old, msg = Oydid.generate_base(content, "", "create", options)
407
+ # did_doc = [did, didDocument, did_old]
408
+ # did_log = [revoc_log, l1, l2, r1, log_old]
409
+ # did_key = [privateKey, revocationKey]
410
+
411
+ did_doc = {
412
+ :did => did,
413
+ :didDocument => didDocument,
414
+ :did_old => did_old
415
+ }
416
+ did_log = {
417
+ :revoc_log => revoc_log,
418
+ :l1 => l1,
419
+ :l2 => l2,
420
+ :r1 => r1,
421
+ :log_old => log_old
422
+ }
423
+ did_key = {
424
+ :privateKey => privateKey,
425
+ :revocationKey => revocationKey
426
+ }
427
+ return [did_doc, did_key, did_log, ""]
428
+ # return [did, didDocument, revoc_log, l1, l2, r1, privateKey, revocationKey, did_old, log_old, ""]
373
429
  end
374
430
 
375
431
  def self.publish(did, didDocument, logs, options)
@@ -415,10 +471,21 @@ class Oydid
415
471
  end
416
472
 
417
473
  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)
474
+ did_doc, did_key, did_log, msg = generate_base(content, did, mode, options)
419
475
  if msg != ""
420
476
  return [nil, msg]
421
477
  end
478
+ did = did_doc[:did]
479
+ didDocument = did_doc[:didDocument]
480
+ did_old = did_doc[:did_old]
481
+ revoc_log = did_log[:revoc_log]
482
+ l1 = did_log[:l1]
483
+ l2 = did_log[:l2]
484
+ r1 = did_log[:r1]
485
+ log_old = did_log[:log_old]
486
+ privateKey = did_key[:privateKey]
487
+ revocationKey = did_key[:revocationKey]
488
+ # did, didDocument, revoc_log, l1, l2, r1, privateKey, revocationKey, did_old, log_old, msg = generate_base(content, did, mode, options)
422
489
 
423
490
  did_hash = did.delete_prefix("did:oyd:")
424
491
  did10 = did_hash[0,10]
@@ -435,7 +502,6 @@ class Oydid
435
502
  doc_location = DEFAULT_LOCATION
436
503
  end
437
504
  end
438
-
439
505
  case doc_location.to_s
440
506
  when /^http/
441
507
  logs = [revoc_log, l1, l2].flatten.compact
@@ -463,8 +529,8 @@ class Oydid
463
529
  retVal["revocation_key"] = revocationKey
464
530
  retVal["revocation_log"] = r1
465
531
  else
466
- write_private_storage(privateKey, did10 + "_private_key.b58")
467
- write_private_storage(revocationKey, did10 + "_revocation_key.b58")
532
+ write_private_storage(privateKey, did10 + "_private_key.enc")
533
+ write_private_storage(revocationKey, did10 + "_revocation_key.enc")
468
534
  write_private_storage(r1.to_json, did10 + "_revocation.json")
469
535
  end
470
536
 
@@ -509,15 +575,15 @@ class Oydid
509
575
  if options[:old_doc_key].nil?
510
576
  if options[:old_doc_enc].nil?
511
577
  if options[:old_doc_pwd].nil?
512
- privateKey_old = read_private_storage(did10_old + "_private_key.b58")
578
+ privateKey_old = read_private_storage(did10_old + "_private_key.enc")
513
579
  else
514
- privateKey_old, msg = generate_private_key(options[:old_doc_pwd].to_s, 'ed25519-priv')
580
+ privateKey_old, msg = generate_private_key(options[:old_doc_pwd].to_s, 'ed25519-priv', options)
515
581
  end
516
582
  else
517
- privateKey_old, msg = decode_private_key(options[:old_doc_enc].to_s)
583
+ privateKey_old, msg = decode_private_key(options[:old_doc_enc].to_s, options)
518
584
  end
519
585
  else
520
- privateKey_old, msg = read_private_key(options[:old_doc_key].to_s)
586
+ privateKey_old, msg = read_private_key(options[:old_doc_key].to_s, options)
521
587
  end
522
588
  if privateKey_old.nil?
523
589
  return [nil, "invalid or missing old private document key"]
@@ -525,42 +591,42 @@ class Oydid
525
591
  if options[:old_rev_key].nil?
526
592
  if options[:old_rev_enc].nil?
527
593
  if options[:old_rev_pwd].nil?
528
- revocationKey_old = read_private_storage(did10_old + "_revocation_key.b58")
594
+ revocationKey_old = read_private_storage(did10_old + "_revocation_key.enc")
529
595
  else
530
- revocationKey_old, msg = generate_private_key(options[:old_rev_pwd].to_s, 'ed25519-priv')
596
+ revocationKey_old, msg = generate_private_key(options[:old_rev_pwd].to_s, 'ed25519-priv', options)
531
597
  end
532
598
  else
533
- revocationKey_old, msg = decode_private_key(options[:old_rev_enc].to_s)
599
+ revocationKey_old, msg = decode_private_key(options[:old_rev_enc].to_s, options)
534
600
  end
535
601
  else
536
- revocationKey_old, msg = read_private_key(options[:old_rev_key].to_s)
602
+ revocationKey_old, msg = read_private_key(options[:old_rev_key].to_s, options)
537
603
  end
538
604
  if revocationKey_old.nil?
539
605
  return [nil, "invalid or missing old private revocation key"]
540
606
  end
541
607
 
542
608
  if options[:rev_key].nil? && options[:rev_pwd].nil? && options[:rev_enc].nil?
543
- revocationKey, msg = read_private_key(did10 + "_revocation_key.b58")
609
+ revocationKey, msg = read_private_key(did10 + "_revocation_key.enc", options)
544
610
  revocationLog = read_private_storage(did10 + "_revocation.json")
545
611
  else
546
612
  if options[:rev_pwd].nil?
547
613
  if options[:rev_enc].nil?
548
- revocationKey, msg = read_private_key(options[:rev_key].to_s)
614
+ revocationKey, msg = read_private_key(options[:rev_key].to_s, options)
549
615
  else
550
- revocationKey, msg = decode_private_key(options[:rev_enc].to_s)
616
+ revocationKey, msg = decode_private_key(options[:rev_enc].to_s, options)
551
617
  end
552
618
  else
553
- revocationKey, msg = generate_private_key(options[:rev_pwd].to_s, 'ed25519-priv')
619
+ revocationKey, msg = generate_private_key(options[:rev_pwd].to_s, 'ed25519-priv', options)
554
620
  end
555
621
  # re-build revocation document
556
622
  did_old_doc = did_info["doc"]["doc"]
557
623
  ts_old = did_info["log"].last["ts"]
558
- publicKey_old = public_key(privateKey_old).first
559
- pubRevoKey_old = public_key(revocationKey_old).first
624
+ publicKey_old = public_key(privateKey_old, options).first
625
+ pubRevoKey_old = public_key(revocationKey_old, options).first
560
626
  did_key_old = publicKey_old + ":" + pubRevoKey_old
561
627
  subDid = {"doc": did_old_doc, "key": did_key_old}.to_json
562
- subDidHash = hash(canonical(subDid))
563
- signedSubDidHash = sign(subDidHash, revocationKey_old).first
628
+ subDidHash = multi_hash(canonical(subDid), LOG_HASH_OPTIONS).first
629
+ signedSubDidHash = sign(subDidHash, revocationKey_old, options).first
564
630
  revocationLog = {
565
631
  "ts": ts_old,
566
632
  "op": 1, # REVOKE
@@ -574,8 +640,8 @@ class Oydid
574
640
 
575
641
  revoc_log = JSON.parse(revocationLog)
576
642
  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]))
643
+ multi_hash(canonical(log_old[did_info["doc_log_id"].to_i]), LOG_HASH_OPTIONS).first,
644
+ multi_hash(canonical(log_old[did_info["termination_log_id"].to_i]), LOG_HASH_OPTIONS).first,
579
645
  ]
580
646
  return [revoc_log, ""]
581
647
  end
@@ -628,10 +694,16 @@ class Oydid
628
694
  target_location = DEFAULT_LOCATION
629
695
  end
630
696
  if did.include?(LOCATION_PREFIX)
631
- hash_split = did.split(LOCATION_PREFIX)
632
- did = hash_split[0]
633
- source_location = hash_split[1]
697
+ tmp = did.split(LOCATION_PREFIX)
698
+ did = tmp[0]
699
+ source_location = tmp[1]
700
+ end
701
+ if did.include?(CGI.escape LOCATION_PREFIX)
702
+ tmp = did.split(CGI.escape LOCATION_PREFIX)
703
+ did = tmp[0]
704
+ source_location = tmp[1]
634
705
  end
706
+
635
707
  if source_location.to_s == ""
636
708
  source_location = DEFAULT_LOCATION
637
709
  end
@@ -657,7 +729,7 @@ class Oydid
657
729
  # write did to new location
658
730
  options[:doc_location] = target_location
659
731
  options[:log_location] = target_location
660
- options[:previous_clone] = hash(canonical(source_log)) + LOCATION_PREFIX + source_location
732
+ options[:previous_clone] = multi_hash(canonical(source_log), LOG_HASH_OPTIONS).first + LOCATION_PREFIX + source_location
661
733
  options[:source_location] = source_location
662
734
  options[:source_did] = source_did["did"]
663
735
  retVal, msg = write(source_did["doc"]["doc"], nil, "clone", options)
@@ -665,6 +737,128 @@ class Oydid
665
737
  end
666
738
 
667
739
  def self.w3c(did_info, options)
740
+ did = percent_encode(did_info["did"])
741
+ if !did.start_with?("did:oyd:")
742
+ did = "did:oyd:" + did
743
+ end
744
+
745
+ didDoc = did_info.transform_keys(&:to_s)["doc"]
746
+ pubDocKey = didDoc["key"].split(":")[0] rescue ""
747
+ pubRevKey = didDoc["key"].split(":")[1] rescue ""
748
+
749
+ wd = {}
750
+ if didDoc["doc"].is_a?(Hash)
751
+ if didDoc["doc"]["@context"].nil?
752
+ wd["@context"] = ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1"]
753
+ else
754
+ if didDoc["doc"]["@context"].is_a?(Array)
755
+ wd["@context"] = ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1"] + didDoc["doc"]["@context"]
756
+ else
757
+ wd["@context"] = ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1", didDoc["doc"]["@context"]]
758
+ end
759
+ didDoc["doc"].delete("@context")
760
+ end
761
+ else
762
+ wd["@context"] = ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1"]
763
+ end
764
+ wd["id"] = percent_encode(did)
765
+ wd["verificationMethod"] = [{
766
+ "id": did + "#key-doc",
767
+ "type": "Ed25519VerificationKey2020",
768
+ "controller": did,
769
+ "publicKeyMultibase": pubDocKey
770
+ },{
771
+ "id": did + "#key-rev",
772
+ "type": "Ed25519VerificationKey2020",
773
+ "controller": did,
774
+ "publicKeyMultibase": pubRevKey
775
+ }]
776
+
777
+ equivalentIds = []
778
+ did_info["log"].each do |log|
779
+ if log["op"] == 2 || log["op"] == 3
780
+ eid = percent_encode("did:oyd:" + log["doc"])
781
+ if eid != did
782
+ equivalentIds << eid
783
+ end
784
+ end
785
+ end unless did_info["log"].nil?
786
+ if equivalentIds.length > 0
787
+ wd[:alsoKnownAs] = equivalentIds
788
+ end
789
+
790
+ if didDoc["doc"].is_a?(Hash) && !didDoc["doc"]["service"].nil?
791
+ location = options[:location]
792
+ if location.nil?
793
+ location = get_location(did_info["did"].to_s)
794
+ end
795
+ wd = wd.merge(didDoc["doc"])
796
+ if wd["service"] != []
797
+ if wd["service"].is_a?(Array)
798
+ wdf = wd["service"].first
799
+ else
800
+ wdf = wd["service"]
801
+ end
802
+ wdf = { "id": did + "#payload",
803
+ "type": "Custom",
804
+ "serviceEndpoint": location }.merge(wdf)
805
+ wd["service"] = [wdf] + wd["service"].drop(1)
806
+ end
807
+ else
808
+ payload = nil
809
+ if didDoc["doc"].is_a?(Hash)
810
+ didDoc = didDoc["doc"]
811
+ if didDoc["authentication"].to_s != ""
812
+ wd["authentication"] = didDoc["authentication"]
813
+ didDoc.delete("authentication")
814
+ end
815
+ if didDoc["assertionMethod"].to_s != ""
816
+ wd["assertionMethod"] = didDoc["assertionMethod"]
817
+ didDoc.delete("assertionMethod")
818
+ end
819
+ if didDoc["keyAgreement"].to_s != ""
820
+ wd["keyAgreement"] = didDoc["keyAgreement"]
821
+ didDoc.delete("keyAgreement")
822
+ end
823
+ if didDoc["capabilityInvocation"].to_s != ""
824
+ wd["capabilityInvocation"] = didDoc["capabilityInvocation"]
825
+ didDoc.delete("capabilityInvocation")
826
+ end
827
+ if didDoc["capabilityDelegation"].to_s != ""
828
+ wd["capabilityDelegation"] = didDoc["capabilityDelegation"]
829
+ didDoc.delete("capabilityDelegation")
830
+ end
831
+ payload = didDoc
832
+ else
833
+ payload = didDoc["doc"]
834
+ end
835
+ if !payload.nil?
836
+ location = options[:location]
837
+ if location.nil?
838
+ location = get_location(did_info["did"].to_s)
839
+ end
840
+ if payload.is_a?(Array) &&
841
+ payload.length == 1 &&
842
+ payload.first.is_a?(Hash) &&
843
+ !payload.first["id"].nil? &&
844
+ !payload.first["type"].nil? &&
845
+ !payload.first["serviceEndpoint"].nil?
846
+ wd["service"] = payload
847
+ else
848
+ wd["service"] = [{
849
+ "id": did + "#payload",
850
+ "type": "Custom",
851
+ "serviceEndpoint": location,
852
+ "payload": payload
853
+ }]
854
+ end
855
+ end
856
+ end
857
+ return wd
858
+ end
859
+
860
+
861
+ def self.w3c_legacy(did_info, options)
668
862
  did = did_info["did"]
669
863
  if !did.start_with?("did:oyd:")
670
864
  did = "did:oyd:" + did
@@ -675,8 +869,8 @@ class Oydid
675
869
  pubRevKey = didDoc["key"].split(":")[1] rescue ""
676
870
 
677
871
  wd = {}
678
- wd["@context"] = "https://www.w3.org/ns/did/v1"
679
- wd["id"] = did
872
+ wd["@context"] = ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1"]
873
+ wd["id"] = percent_encode(did)
680
874
  wd["verificationMethod"] = [{
681
875
  "id": did + "#key-doc",
682
876
  "type": "Ed25519VerificationKey2020",
@@ -689,47 +883,46 @@ class Oydid
689
883
  "publicKeyMultibase": pubRevKey
690
884
  }]
691
885
 
692
- if didDoc["@context"].to_s == "https://www.w3.org/ns/did/v1"
886
+ if didDoc["@context"] == ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1"]
693
887
  didDoc.delete("@context")
694
888
  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]
889
+ if !didDoc["doc"].nil?
890
+ newDidDoc = []
891
+ if didDoc.is_a?(Hash)
892
+ if didDoc["authentication"].to_s != ""
893
+ wd["authentication"] = didDoc["authentication"]
894
+ didDoc.delete("authentication")
895
+ end
896
+ if didDoc["service"].to_s != ""
897
+ if didDoc["service"].is_a?(Array)
898
+ newDidDoc = didDoc.dup
899
+ newDidDoc.delete("service")
900
+ if newDidDoc == {}
901
+ newDidDoc = []
902
+ else
903
+ if !newDidDoc.is_a?(Array)
904
+ newDidDoc=[newDidDoc]
905
+ end
713
906
  end
907
+ newDidDoc << didDoc["service"]
908
+ newDidDoc = newDidDoc.flatten
909
+ else
910
+ newDidDoc = didDoc["service"]
714
911
  end
715
- newDidDoc << didDoc["service"]
716
- newDidDoc = newDidDoc.flatten
717
912
  else
718
- newDidDoc = didDoc["service"]
913
+ newDidDoc = didDoc["doc"]
719
914
  end
720
915
  else
721
- newDidDoc = didDoc
916
+ newDidDoc = didDoc["doc"]
722
917
  end
723
- else
724
- newDidDoc = didDoc
918
+ wd["service"] = newDidDoc
725
919
  end
726
- wd["service"] = newDidDoc
727
920
  return wd
728
921
  end
729
922
 
730
923
  def self.fromW3C(didDocument, options)
731
924
  didDocument = didDocument.transform_keys(&:to_s)
732
- if didDocument["@context"].to_s == "https://www.w3.org/ns/did/v1"
925
+ if didDocument["@context"] == ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1"]
733
926
  didDocument.delete("@context")
734
927
  end
735
928
  didDocument