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