oydid 0.4.4 → 0.5.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/oydid/basic.rb +149 -33
- data/lib/oydid/didcomm.rb +9 -9
- data/lib/oydid/log.rb +14 -7
- data/lib/oydid/vc.rb +308 -0
- data/lib/oydid.rb +305 -112
- data/spec/input/basic/sample_b16_dec.doc +1 -0
- data/spec/input/basic/sample_b17_edec.doc +1 -0
- data/spec/input/basic/sample_b32_dec.doc +1 -0
- data/spec/input/basic/sample_b58_enc.doc +1 -0
- data/spec/input/basic/sample_b64_dec.doc +1 -0
- data/spec/input/basic/sample_b64_enc.doc +1 -0
- data/spec/input/basic/sample_blake2b-16_b16_hash.doc +1 -0
- data/spec/input/basic/sample_blake2b-32_b32_hash.doc +1 -0
- data/spec/input/basic/sample_blake2b-64_b58_hash.doc +1 -0
- data/spec/input/basic/sample_invalid2_readkey.doc +1 -1
- data/spec/input/basic/sample_invalid3_readkey.doc +1 -1
- data/spec/input/basic/sample_readkey.doc +1 -1
- data/spec/input/basic/sample_sha2-256_b58_hash.doc +1 -0
- data/spec/input/basic/sample_sha2-512_b58_hash.doc +1 -0
- data/spec/input/basic/sample_sha3-224_b64_hash.doc +1 -0
- data/spec/output/basic/sample_b16_dec.doc +1 -0
- data/spec/output/basic/sample_b16_enc.doc +1 -0
- data/spec/output/basic/sample_b17_edec.doc +2 -0
- data/spec/output/basic/sample_b17_enc.doc +1 -0
- data/spec/output/basic/sample_b32_dec.doc +1 -0
- data/spec/output/basic/sample_b32_enc.doc +1 -0
- data/spec/output/basic/sample_b58_dec.doc +1 -0
- data/spec/output/basic/sample_b64_dec.doc +1 -0
- data/spec/output/basic/sample_b64_enc.doc +1 -0
- data/spec/output/basic/sample_blake2b-16_b16_hash.doc +1 -0
- data/spec/output/basic/sample_blake2b-32_b32_hash.doc +1 -0
- data/spec/output/basic/sample_blake2b-64_b58_hash.doc +1 -0
- data/spec/output/basic/sample_sha2-512_b58_hash.doc +1 -0
- data/spec/output/basic/sample_sha3-224_b64_hash.doc +1 -0
- data/spec/oydid_spec.rb +95 -13
- metadata +72 -19
- /data/spec/input/basic/{sample_enc.doc → sample_b16_enc.doc} +0 -0
- /data/spec/input/basic/{sample_hash.doc → sample_b17_enc.doc} +0 -0
- /data/spec/{output/basic/sample_dec.doc → input/basic/sample_b32_enc.doc} +0 -0
- /data/spec/input/basic/{sample_dec.doc → sample_b58_dec.doc} +0 -0
- /data/spec/output/basic/{sample_enc.doc → sample_b58_enc.doc} +0 -0
- /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(
|
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
|
-
|
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
|
-
|
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,
|
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,
|
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,
|
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,
|
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.
|
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,
|
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.
|
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,
|
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,
|
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 =
|
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
|
-
|
296
|
-
|
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 = [
|
322
|
+
prev_hash = [multi_hash(canonical(revoc_log), LOG_HASH_OPTIONS).first]
|
299
323
|
end
|
300
|
-
|
301
|
-
|
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
|
-
|
308
|
-
|
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 =
|
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 =
|
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 =
|
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 = [
|
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
|
-
|
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
|
-
|
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.
|
467
|
-
write_private_storage(revocationKey, did10 + "_revocation_key.
|
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.
|
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.
|
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.
|
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 =
|
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
|
-
|
578
|
-
|
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
|
-
|
632
|
-
did =
|
633
|
-
source_location =
|
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] =
|
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"]
|
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"].
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
didDoc.
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
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["
|
913
|
+
newDidDoc = didDoc["doc"]
|
719
914
|
end
|
720
915
|
else
|
721
|
-
newDidDoc = didDoc
|
916
|
+
newDidDoc = didDoc["doc"]
|
722
917
|
end
|
723
|
-
|
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"]
|
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
|