ppldid 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +1 -0
  3. data/LICENSE +201 -0
  4. data/README.md +2 -0
  5. data/VERSION +1 -0
  6. data/lib/oydid/basic.rb +278 -0
  7. data/lib/oydid/didcomm.rb +120 -0
  8. data/lib/oydid/log.rb +394 -0
  9. data/lib/oydid.rb +738 -0
  10. data/spec/input/basic/arrays.json +8 -0
  11. data/spec/input/basic/french.json +6 -0
  12. data/spec/input/basic/sample2_get_location.doc +1 -0
  13. data/spec/input/basic/sample2_retrieve_document.doc +1 -0
  14. data/spec/input/basic/sample3_retrieve_document.doc +1 -0
  15. data/spec/input/basic/sample4_retrieve_document.doc +1 -0
  16. data/spec/input/basic/sample5_retrieve_document.doc +1 -0
  17. data/spec/input/basic/sample_dec.doc +1 -0
  18. data/spec/input/basic/sample_enc.doc +1 -0
  19. data/spec/input/basic/sample_get_location.doc +1 -0
  20. data/spec/input/basic/sample_hash.doc +1 -0
  21. data/spec/input/basic/sample_invalid2_readkey.doc +1 -0
  22. data/spec/input/basic/sample_invalid2_verify.doc +1 -0
  23. data/spec/input/basic/sample_invalid3_readkey.doc +1 -0
  24. data/spec/input/basic/sample_invalid3_verify.doc +1 -0
  25. data/spec/input/basic/sample_invalid_privkey.doc +1 -0
  26. data/spec/input/basic/sample_invalid_readkey.doc +1 -0
  27. data/spec/input/basic/sample_invalid_sign.doc +1 -0
  28. data/spec/input/basic/sample_invalid_verify.doc +1 -0
  29. data/spec/input/basic/sample_key.doc +1 -0
  30. data/spec/input/basic/sample_readkey.doc +1 -0
  31. data/spec/input/basic/sample_retrieve_document.doc +1 -0
  32. data/spec/input/basic/sample_sign.doc +1 -0
  33. data/spec/input/basic/sample_valid_privkey.doc +1 -0
  34. data/spec/input/basic/sample_verify.doc +1 -0
  35. data/spec/input/basic/structures.json +8 -0
  36. data/spec/input/basic/unicode.json +3 -0
  37. data/spec/input/basic/values.json +5 -0
  38. data/spec/input/basic/wierd.json +11 -0
  39. data/spec/input/basic/zQmaBZTghn.doc +1 -0
  40. data/spec/input/log/sample0_dag2array.doc +1 -0
  41. data/spec/input/log/sample0_dag_did.doc +1 -0
  42. data/spec/input/log/sample1_dag_did.doc +1 -0
  43. data/spec/input/log/sample1_dag_update.doc +1 -0
  44. data/spec/input/log/sample2_dag_did.doc +1 -0
  45. data/spec/input/log/sample2_dag_update.doc +1 -0
  46. data/spec/input/log/sample2_retrieve_log.doc +1 -0
  47. data/spec/input/log/sample3_dag_did.doc +1 -0
  48. data/spec/input/log/sample3_dag_update.doc +1 -0
  49. data/spec/input/log/sample3_retrieve_log.doc +1 -0
  50. data/spec/input/log/sample4_dag_did.doc +1 -0
  51. data/spec/input/log/sample4_dag_update.doc +1 -0
  52. data/spec/input/log/sample4_retrieve_log.doc +1 -0
  53. data/spec/input/log/sample5_dag_update.doc +1 -0
  54. data/spec/input/log/sample5_retrieve_log.doc +1 -0
  55. data/spec/input/log/sample6_dag_update.doc +1 -0
  56. data/spec/input/log/sample6_retrieve_log.doc +1 -0
  57. data/spec/input/log/sample7_dag_update.doc +1 -0
  58. data/spec/input/log/sample7_retrieve_log.doc +1 -0
  59. data/spec/input/log/sample8_dag_update.doc +1 -0
  60. data/spec/input/log/sample_addhash.doc +1 -0
  61. data/spec/input/log/sample_dag_update.doc +1 -0
  62. data/spec/input/log/sample_match_log.doc +1 -0
  63. data/spec/input/log/sample_op1_addhash.doc +1 -0
  64. data/spec/input/log/sample_retrieve_log.doc +1 -0
  65. data/spec/input/main/sample0_read.doc +1 -0
  66. data/spec/output/basic/arrays.json +1 -0
  67. data/spec/output/basic/french.json +1 -0
  68. data/spec/output/basic/sample2_get_location.doc +1 -0
  69. data/spec/output/basic/sample2_retrieve_document.doc +1 -0
  70. data/spec/output/basic/sample3_retrieve_document.doc +1 -0
  71. data/spec/output/basic/sample4_retrieve_document.doc +1 -0
  72. data/spec/output/basic/sample5_retrieve_document.doc +1 -0
  73. data/spec/output/basic/sample_dec.doc +1 -0
  74. data/spec/output/basic/sample_enc.doc +1 -0
  75. data/spec/output/basic/sample_get_location.doc +1 -0
  76. data/spec/output/basic/sample_hash.doc +1 -0
  77. data/spec/output/basic/sample_invalid2_readkey.doc +1 -0
  78. data/spec/output/basic/sample_invalid2_verify.doc +1 -0
  79. data/spec/output/basic/sample_invalid3_readkey.doc +1 -0
  80. data/spec/output/basic/sample_invalid3_verify.doc +1 -0
  81. data/spec/output/basic/sample_invalid_privkey.doc +1 -0
  82. data/spec/output/basic/sample_invalid_readkey.doc +1 -0
  83. data/spec/output/basic/sample_invalid_sign.doc +1 -0
  84. data/spec/output/basic/sample_invalid_verify.doc +1 -0
  85. data/spec/output/basic/sample_key.doc +1 -0
  86. data/spec/output/basic/sample_readkey.doc +1 -0
  87. data/spec/output/basic/sample_retrieve_document.doc +1 -0
  88. data/spec/output/basic/sample_sign.doc +1 -0
  89. data/spec/output/basic/sample_valid_privkey.doc +1 -0
  90. data/spec/output/basic/sample_verify.doc +1 -0
  91. data/spec/output/basic/structures.json +1 -0
  92. data/spec/output/basic/unicode.json +1 -0
  93. data/spec/output/basic/values.json +1 -0
  94. data/spec/output/basic/wierd.json +1 -0
  95. data/spec/output/log/sample0_dag2array.doc +1 -0
  96. data/spec/output/log/sample0_dag_did.doc +1 -0
  97. data/spec/output/log/sample1_dag_did.doc +1 -0
  98. data/spec/output/log/sample1_dag_update.doc +1 -0
  99. data/spec/output/log/sample2_dag_did.doc +1 -0
  100. data/spec/output/log/sample2_dag_update.doc +1 -0
  101. data/spec/output/log/sample2_retrieve_log.doc +1 -0
  102. data/spec/output/log/sample3_dag_did.doc +1 -0
  103. data/spec/output/log/sample3_dag_update.doc +1 -0
  104. data/spec/output/log/sample3_retrieve_log.doc +1 -0
  105. data/spec/output/log/sample4_dag_did.doc +1 -0
  106. data/spec/output/log/sample4_dag_update.doc +1 -0
  107. data/spec/output/log/sample4_retrieve_log.doc +1 -0
  108. data/spec/output/log/sample5_dag_update.doc +1 -0
  109. data/spec/output/log/sample5_retrieve_log.doc +1 -0
  110. data/spec/output/log/sample6_dag_update.doc +1 -0
  111. data/spec/output/log/sample6_retrieve_log.doc +1 -0
  112. data/spec/output/log/sample7_dag_update.doc +1 -0
  113. data/spec/output/log/sample7_retrieve_log.doc +1 -0
  114. data/spec/output/log/sample8_dag_update.doc +1 -0
  115. data/spec/output/log/sample_addhash.doc +1 -0
  116. data/spec/output/log/sample_dag_update.doc +1 -0
  117. data/spec/output/log/sample_match_log.doc +1 -0
  118. data/spec/output/log/sample_op1_addhash.doc +1 -0
  119. data/spec/output/log/sample_retrieve_log.doc +1 -0
  120. data/spec/output/main/sample0_read.doc +1 -0
  121. data/spec/oydid_spec.rb +170 -0
  122. data/spec/spec_helper.rb +31 -0
  123. metadata +420 -0
data/lib/oydid/log.rb ADDED
@@ -0,0 +1,394 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+ class Oydid
5
+ # log functions -----------------------------
6
+ def self.add_hash(log)
7
+ log.map do |item|
8
+ i = item.dup
9
+ i.delete("previous")
10
+ item["entry-hash"] = hash(canonical(item))
11
+ if item.transform_keys(&:to_s)["op"] == 1
12
+ item["sub-entry-hash"] = hash(canonical(i))
13
+ end
14
+ item
15
+ end
16
+ end
17
+
18
+ # check if signature matches current document
19
+ # check if signature in log is correct
20
+ def self.match_log_did?(log, doc)
21
+ message = log["doc"].to_s
22
+ signature = log["sig"].to_s
23
+ public_keys = doc["key"].to_s
24
+ public_key = public_keys.split(":")[0] rescue ""
25
+ return verify(message, signature, public_key).first
26
+ end
27
+
28
+ def self.retrieve_log(did_hash, log_file, log_location, options)
29
+ if log_location == ""
30
+ log_location = DEFAULT_LOCATION
31
+ end
32
+ if !(log_location == "" || log_location == "local")
33
+ if !log_location.start_with?("http")
34
+ log_location = "https://" + log_location
35
+ end
36
+ end
37
+
38
+ case log_location
39
+ when /^http/
40
+ log_location = log_location.sub("%3A%2F%2F","://")
41
+ retVal = HTTParty.get(log_location + "/log/" + did_hash)
42
+ if retVal.code != 200
43
+ msg = retVal.parsed_response("error").to_s rescue
44
+ "invalid response from " + log_location.to_s + "/log/" + did_hash.to_s
45
+
46
+ return [nil, msg]
47
+ end
48
+ if options.transform_keys(&:to_s)["trace"]
49
+ if options[:silent].nil? || !options[:silent]
50
+ puts "GET log for " + did_hash + " from " + log_location
51
+ end
52
+ end
53
+ retVal = JSON.parse(retVal.to_s) rescue nil
54
+ return [retVal, ""]
55
+ when "", "local"
56
+ doc = JSON.parse(read_private_storage(log_file)) rescue {}
57
+ if doc == {}
58
+ return [nil, "cannot read file '" + log_file + "'"]
59
+ end
60
+ return [doc, ""]
61
+ end
62
+ end
63
+
64
+ def self.dag_did(logs, options)
65
+ dag = DAG.new
66
+ dag_log = []
67
+ log_hash = []
68
+
69
+ # calculate hash values for each entry and build vertices
70
+ i = 0
71
+ create_entries = 0
72
+ create_index = nil
73
+ terminate_indices = []
74
+ logs.each do |el|
75
+ if el["op"].to_i == 2
76
+ create_entries += 1
77
+ create_index = i
78
+ end
79
+ if el["op"].to_i == 0
80
+ terminate_indices << i
81
+ end
82
+ log_hash << Oydid.hash(Oydid.canonical(el))
83
+ dag_log << dag.add_vertex(id: i)
84
+ i += 1
85
+ end unless logs.nil?
86
+
87
+ if create_entries != 1
88
+ return [nil, nil, nil, "wrong number of CREATE entries (" + create_entries.to_s + ") in log" ]
89
+ end
90
+ if terminate_indices.length == 0
91
+ return [nil, nil, nil, "missing TERMINATE entries" ]
92
+ end
93
+
94
+ # create edges between vertices
95
+ i = 0
96
+ logs.each do |el|
97
+ el["previous"].each do |p|
98
+ position = log_hash.find_index(p)
99
+ if !position.nil?
100
+ dag.add_edge from: dag_log[position], to: dag_log[i]
101
+ end
102
+ end unless el["previous"] == []
103
+ i += 1
104
+ end unless logs.nil?
105
+
106
+ # identify tangling TERMINATE entry
107
+ i = 0
108
+ terminate_entries = 0
109
+ terminate_overall = 0
110
+ terminate_index = nil
111
+ logs.each do |el|
112
+ if el["op"].to_i == 0
113
+ if dag.vertices[i].successors.length == 0
114
+ terminate_entries += 1
115
+ terminate_index = i
116
+ end
117
+ terminate_overall += 1
118
+ end
119
+ i += 1
120
+ end unless logs.nil?
121
+
122
+ if terminate_entries != 1 && !options[:log_complete]
123
+ if options[:silent].nil? || !options[:silent]
124
+ return [nil, nil, nil, "cannot resolve DID" ]
125
+ end
126
+ end
127
+ return [dag, create_index, terminate_index, ""]
128
+ end
129
+
130
+ def self.dag2array(dag, log_array, index, result, options)
131
+ if options.transform_keys(&:to_s)["trace"]
132
+ if options[:silent].nil? || !options[:silent]
133
+ puts " vertex " + index.to_s + " at " + log_array[index]["ts"].to_s + " op: " + log_array[index]["op"].to_s + " doc: " + log_array[index]["doc"].to_s
134
+ end
135
+ end
136
+ result << log_array[index]
137
+ dag.vertices[index].successors.each do |s|
138
+ # check if successor has predecessor that is not self (i.e. REVOKE with TERMINATE)
139
+ s.predecessors.each do |p|
140
+ if p[:id] != index
141
+ if options.transform_keys(&:to_s)["trace"]
142
+ if options[:silent].nil? || !options[:silent]
143
+ puts " vertex " + p[:id].to_s + " at " + log_array[p[:id]]["ts"].to_s + " op: " + log_array[p[:id]]["op"].to_s + " doc: " + log_array[p[:id]]["doc"].to_s
144
+ end
145
+ end
146
+ result << log_array[p[:id]]
147
+ end
148
+ end unless s.predecessors.length < 2
149
+ dag2array(dag, log_array, s[:id], result, options)
150
+ end unless dag.vertices[index].successors.count == 0
151
+ result
152
+ end
153
+
154
+ def self.dag_update(currentDID, options)
155
+ i = 0
156
+ doc_location = ""
157
+ initial_did = currentDID["did"].to_s.dup
158
+ initial_did = initial_did.delete_prefix("did:ppld:")
159
+ if initial_did.include?(LOCATION_PREFIX)
160
+ tmp = initial_did.split(LOCATION_PREFIX)
161
+ initial_did = tmp[0]
162
+ doc_location = tmp[1]
163
+ end
164
+ current_public_doc_key = ""
165
+ verification_output = false
166
+ currentDID["log"].each do |el|
167
+ case el["op"]
168
+ when 2,3 # CREATE, UPDATE
169
+ currentDID["doc_log_id"] = i
170
+ doc_did = el["doc"]
171
+ did_hash = doc_did.delete_prefix("did:ppld:")
172
+ did_hash = did_hash.split(LOCATION_PREFIX).first
173
+ did10 = did_hash[0,10]
174
+ doc = retrieve_document_raw(doc_did, did10 + ".doc", doc_location, {})
175
+ if doc.first.nil?
176
+ currentDID["error"] = 2
177
+ msg = doc.last.to_s
178
+ if msg == ""
179
+ msg = "cannot retrieve " + doc_did.to_s
180
+ end
181
+ currentDID["message"] = msg
182
+ return currentDID
183
+ end
184
+ doc = doc.first["doc"]
185
+ if el["op"] == 2 # CREATE
186
+ if !match_log_did?(el, doc)
187
+ currentDID["error"] = 1
188
+ currentDID["message"] = "Signatures in log don't match"
189
+ return currentDID
190
+ end
191
+ end
192
+ currentDID["did"] = doc_did
193
+ currentDID["doc"] = doc
194
+ # since hash is guaranteed during retrieve_document this check is not necessary
195
+ # if hash(canonical(doc)) != did_hash
196
+ # currentDID["error"] = 1
197
+ # currentDID["message"] = "DID identifier and DID document don't match"
198
+ # if did_hash == initial_did
199
+ # verification_output = true
200
+ # end
201
+ # if verification_output
202
+ # currentDID["verification"] += "identifier: " + did_hash.to_s + "\n"
203
+ # currentDID["verification"] += "⛔ does not match DID Document:" + "\n"
204
+ # currentDID["verification"] += JSON.pretty_generate(doc) + "\n"
205
+ # currentDID["verification"] += "(Details: https://ownyourdata.github.io/ppldid/#calculate_hash)" + "\n\n"
206
+ # end
207
+ # return currentDID
208
+ # end
209
+ if did_hash == initial_did
210
+ verification_output = true
211
+ end
212
+ if verification_output
213
+ currentDID["verification"] += "identifier: " + did_hash.to_s + "\n"
214
+ currentDID["verification"] += "✅ is hash of DID Document:" + "\n"
215
+ currentDID["verification"] += JSON.pretty_generate(doc) + "\n"
216
+ currentDID["verification"] += "(Details: https://ownyourdata.github.io/ppldid/#calculate_hash)" + "\n\n"
217
+ end
218
+ current_public_doc_key = currentDID["doc"]["key"].split(":").first rescue ""
219
+
220
+ when 0 # TERMINATE
221
+ currentDID["termination_log_id"] = i
222
+
223
+ doc_did = currentDID["did"]
224
+ did_hash = doc_did.delete_prefix("did:ppld:")
225
+ did_hash = did_hash.split(LOCATION_PREFIX).first
226
+ did10 = did_hash[0,10]
227
+ doc = retrieve_document_raw(doc_did, did10 + ".doc", doc_location, {})
228
+ # since it retrieves a DID that previously existed, this test is not necessary
229
+ # if doc.first.nil?
230
+ # currentDID["error"] = 2
231
+ # currentDID["message"] = doc.last.to_s
232
+ # return currentDID
233
+ # end
234
+ doc = doc.first["doc"]
235
+ term = doc["log"]
236
+ log_location = term.split(LOCATION_PREFIX)[1] rescue ""
237
+ if log_location.to_s == ""
238
+ log_location = DEFAULT_LOCATION
239
+ end
240
+ term = term.split(LOCATION_PREFIX).first
241
+ if hash(canonical(el)) != term
242
+ currentDID["error"] = 1
243
+ currentDID["message"] = "Log reference and record don't match"
244
+ if verification_output
245
+ currentDID["verification"] += "'log' reference in DID Document: " + term.to_s + "\n"
246
+ currentDID["verification"] += "⛔ does not match TERMINATE log record:" + "\n"
247
+ currentDID["verification"] += JSON.pretty_generate(el) + "\n"
248
+ currentDID["verification"] += "(Details: https://ownyourdata.github.io/ppldid/#calculate_hash)" + "\n\n"
249
+ end
250
+ return currentDID
251
+ end
252
+ if verification_output
253
+ currentDID["verification"] += "'log' reference in DID Document: " + term.to_s + "\n"
254
+ currentDID["verification"] += "✅ is hash of TERMINATE log record:" + "\n"
255
+ currentDID["verification"] += JSON.pretty_generate(el) + "\n"
256
+ currentDID["verification"] += "(Details: https://ownyourdata.github.io/ppldid/#calculate_hash)" + "\n\n"
257
+ end
258
+
259
+ # check if there is a revocation entry
260
+ revocation_record = {}
261
+ revoc_term = el["doc"]
262
+ revoc_term = revoc_term.split(LOCATION_PREFIX).first
263
+ revoc_term_found = false
264
+ log_array, msg = retrieve_log(did_hash, did10 + ".log", log_location, options)
265
+ log_array.each do |log_el|
266
+ log_el_structure = log_el.dup
267
+ if log_el["op"].to_i == 1 # TERMINATE
268
+ log_el_structure.delete("previous")
269
+ end
270
+ if hash(canonical(log_el_structure)) == revoc_term
271
+ revoc_term_found = true
272
+ revocation_record = log_el.dup
273
+ if verification_output
274
+ currentDID["verification"] += "'doc' reference in TERMINATE log record: " + revoc_term.to_s + "\n"
275
+ currentDID["verification"] += "✅ is hash of REVOCATION log record (without 'previous' attribute):" + "\n"
276
+ currentDID["verification"] += JSON.pretty_generate(log_el) + "\n"
277
+ currentDID["verification"] += "(Details: https://ownyourdata.github.io/ppldid/#calculate_hash)" + "\n\n"
278
+ end
279
+ break
280
+ end
281
+ end unless log_array.nil?
282
+ # this should actually be covered by retrieve_log in the block above
283
+ # (actually I wasn't able to craft a test case covering this part...)
284
+ # if !options.transform_keys(&:to_s)["log_location"].nil?
285
+ # log_array, msg = retrieve_log(revoc_term, did10 + ".log", options.transform_keys(&:to_s)["log_location"], options)
286
+ # log_array.each do |log_el|
287
+ # if log_el["op"] == 1 # TERMINATE
288
+ # log_el_structure = log_el.delete("previous")
289
+ # else
290
+ # log_el_structure = log_el
291
+ # end
292
+ # if hash(canonical(log_el_structure)) == revoc_term
293
+ # revoc_term_found = true
294
+ # revocation_record = log_el.dup
295
+ # if verification_output
296
+ # currentDID["verification"] += "'doc' reference in TERMINATE log record: " + revoc_term.to_s + "\n"
297
+ # currentDID["verification"] += "✅ is hash of REVOCATION log record (without 'previous' attribute):" + "\n"
298
+ # currentDID["verification"] += JSON.pretty_generate(log_el) + "\n"
299
+ # currentDID["verification"] += "(Details: https://ownyourdata.github.io/ppldid/#calculate_hash)" + "\n\n"
300
+ # end
301
+ # break
302
+ # end
303
+ # end
304
+ # end
305
+
306
+ if revoc_term_found
307
+ update_term_found = false
308
+ log_array.each do |log_el|
309
+ if log_el["op"].to_i == 3
310
+ if log_el["previous"].include?(hash(canonical(revocation_record)))
311
+ update_term_found = true
312
+ message = log_el["doc"].to_s
313
+
314
+ signature = log_el["sig"]
315
+ public_key = current_public_doc_key.to_s
316
+ signature_verification = verify(message, signature, public_key).first
317
+ if signature_verification
318
+ if verification_output
319
+ currentDID["verification"] += "found UPDATE log record:" + "\n"
320
+ currentDID["verification"] += JSON.pretty_generate(log_el) + "\n"
321
+ currentDID["verification"] += "✅ public key from last DID Document: " + current_public_doc_key.to_s + "\n"
322
+ currentDID["verification"] += "verifies 'doc' reference of new DID Document: " + log_el["doc"].to_s + "\n"
323
+ currentDID["verification"] += log_el["sig"].to_s + "\n"
324
+ currentDID["verification"] += "of next DID Document (Details: https://ownyourdata.github.io/ppldid/#verify_signature)" + "\n"
325
+
326
+ next_doc_did = log_el["doc"].to_s
327
+ next_doc_location = doc_location
328
+ next_did_hash = next_doc_did.delete_prefix("did:ppld:")
329
+ next_did_hash = next_did_hash.split(LOCATION_PREFIX).first
330
+ next_did10 = next_did_hash[0,10]
331
+ next_doc = retrieve_document_raw(next_doc_did, next_did10 + ".doc", next_doc_location, {})
332
+ if next_doc.first.nil?
333
+ currentDID["error"] = 2
334
+ currentDID["message"] = next_doc.last
335
+ return currentDID
336
+ end
337
+ next_doc = next_doc.first["doc"]
338
+ if public_key == next_doc["key"].split(":").first
339
+ currentDID["verification"] += "⚠️ no key rotation in updated DID Document" + "\n"
340
+ end
341
+ currentDID["verification"] += "\n"
342
+ end
343
+ else
344
+ currentDID["error"] = 1
345
+ currentDID["message"] = "Signature does not match"
346
+ if verification_output
347
+ new_doc_did = log_el["doc"].to_s
348
+ new_doc_location = doc_location
349
+ new_did_hash = new_doc_did.delete_prefix("did:ppld:")
350
+ new_did_hash = new_did_hash.split(LOCATION_PREFIX).first
351
+ new_did10 = new_did_hash[0,10]
352
+ new_doc = retrieve_document(new_doc_did, new_did10 + ".doc", new_doc_location, {}).first
353
+ currentDID["verification"] += "found UPDATE log record:" + "\n"
354
+ currentDID["verification"] += JSON.pretty_generate(log_el) + "\n"
355
+ currentDID["verification"] += "⛔ public key from last DID Document: " + current_public_doc_key.to_s + "\n"
356
+ currentDID["verification"] += "does not verify 'doc' reference of new DID Document: " + log_el["doc"].to_s + "\n"
357
+ currentDID["verification"] += log_el["sig"].to_s + "\n"
358
+ currentDID["verification"] += "next DID Document (Details: https://ownyourdata.github.io/ppldid/#verify_signature)" + "\n"
359
+ currentDID["verification"] += JSON.pretty_generate(new_doc) + "\n\n"
360
+ end
361
+ return currentDID
362
+ end
363
+ break
364
+ end
365
+ end
366
+ end
367
+
368
+ else
369
+ if verification_output
370
+ currentDID["verification"] += "Revocation reference in log record: " + revoc_term.to_s + "\n"
371
+ currentDID["verification"] += "✅ cannot find revocation record searching at" + "\n"
372
+ currentDID["verification"] += "- " + log_location + "\n"
373
+ if !options.transform_keys(&:to_s)["log_location"].nil?
374
+ currentDID["verification"] += "- " + options.transform_keys(&:to_s)["log_location"].to_s + "\n"
375
+ end
376
+ currentDID["verification"] += "(Details: https://ownyourdata.github.io/ppldid/#retrieve_log)" + "\n\n"
377
+ end
378
+ break
379
+ end
380
+ when 1 # revocation log entry
381
+ # do nothing
382
+ else
383
+ currentDID["error"] = 2
384
+ currentDID["message"] = "FATAL ERROR: op code '" + el["op"].to_s + "' not implemented"
385
+ return currentDID
386
+
387
+ end
388
+ i += 1
389
+ end unless currentDID["log"].nil?
390
+
391
+ return currentDID
392
+ end
393
+
394
+ end