oydid 0.4.4 → 0.5.4

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 +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