oydid 0.9.2 → 0.9.3
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 +26 -7
- data/lib/oydid/log.rb +25 -11
- data/spec/oydid_spec.rb +59 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b941c83aec6492dfb37d272fd83a77f1b036902b70aab64634fed657d1ccaf6a
|
|
4
|
+
data.tar.gz: 0ba0f288c5c30e2cd7d7d831bd072ef0c4924082d70fba44634e1412578a8dc7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ddc6020c44371fee58f2e527513e4d94974ee5d4a3ebabd22a01b5cc039f5c91cfe1a0ab0f4046c50a356ab0784db6a626c971c5ee18e10b076e03625250605e
|
|
7
|
+
data.tar.gz: eaba43282881c1239cde7af7733707d5beff7670b27388327926b4e7a5c739e9c221c1f9b70565a629adb3e7b4ee43dd3ebb3cb977bf6b2dd885ff6f55a34e93
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.9.
|
|
1
|
+
0.9.3
|
data/lib/oydid/basic.rb
CHANGED
|
@@ -1248,6 +1248,30 @@ class Oydid
|
|
|
1248
1248
|
end
|
|
1249
1249
|
end
|
|
1250
1250
|
|
|
1251
|
+
# Marks a failure of the queried repository itself (HTTP 5xx) as opposed to
|
|
1252
|
+
# a DID that is simply not stored there. Without the distinction a caller
|
|
1253
|
+
# turns a broken upstream into "not found", which claims the identifier
|
|
1254
|
+
# never existed - see upstream_error?.
|
|
1255
|
+
UPSTREAM_ERROR_PREFIX = "upstream error"
|
|
1256
|
+
|
|
1257
|
+
def self.upstream_error?(message)
|
|
1258
|
+
message.to_s.start_with?(UPSTREAM_ERROR_PREFIX)
|
|
1259
|
+
end
|
|
1260
|
+
|
|
1261
|
+
# Failure message for a non-200 response: the repository's own error field
|
|
1262
|
+
# when it sent one, otherwise a message naming status and URL. A 5xx gets
|
|
1263
|
+
# the prefix above so callers can tell it apart from a missing DID.
|
|
1264
|
+
def self.http_error_message(response, url)
|
|
1265
|
+
msg = (response.parsed_response["error"].to_s rescue "")
|
|
1266
|
+
return msg unless msg.to_s == ""
|
|
1267
|
+
code = response.code.to_i rescue 0
|
|
1268
|
+
if code >= 500
|
|
1269
|
+
UPSTREAM_ERROR_PREFIX + " " + code.to_s + " from " + url.to_s
|
|
1270
|
+
else
|
|
1271
|
+
"invalid response from " + url.to_s
|
|
1272
|
+
end
|
|
1273
|
+
end
|
|
1274
|
+
|
|
1251
1275
|
def self.retrieve_document(doc_identifier, doc_file, doc_location, options)
|
|
1252
1276
|
# in-process callers can supply the DID document directly (e.g. read from
|
|
1253
1277
|
# a local database) to avoid any HTTP/file lookup
|
|
@@ -1271,11 +1295,7 @@ class Oydid
|
|
|
1271
1295
|
end
|
|
1272
1296
|
retVal = HTTParty.get(doc_location + "/doc/" + doc_identifier + option_str)
|
|
1273
1297
|
if retVal.code != 200
|
|
1274
|
-
|
|
1275
|
-
if msg.to_s == ""
|
|
1276
|
-
msg = "invalid response from " + doc_location.to_s + "/doc/" + doc_identifier.to_s
|
|
1277
|
-
end
|
|
1278
|
-
return [nil, msg]
|
|
1298
|
+
return [nil, http_error_message(retVal, doc_location.to_s + "/doc/" + doc_identifier.to_s)]
|
|
1279
1299
|
end
|
|
1280
1300
|
if options.transform_keys(&:to_s)["trace"]
|
|
1281
1301
|
if options[:silent].nil? || !options[:silent]
|
|
@@ -1324,8 +1344,7 @@ class Oydid
|
|
|
1324
1344
|
doc_location = doc_location.sub("%3A%2F%2F","://").sub("%3A", ":")
|
|
1325
1345
|
retVal = HTTParty.get(doc_location + "/doc_raw/" + doc_hash)
|
|
1326
1346
|
if retVal.code != 200
|
|
1327
|
-
|
|
1328
|
-
return [nil, msg]
|
|
1347
|
+
return [nil, http_error_message(retVal, doc_location.to_s + "/doc_raw/" + doc_hash.to_s)]
|
|
1329
1348
|
end
|
|
1330
1349
|
if options.transform_keys(&:to_s)["trace"]
|
|
1331
1350
|
if options[:silent].nil? || !options[:silent]
|
data/lib/oydid/log.rb
CHANGED
|
@@ -44,10 +44,7 @@ class Oydid
|
|
|
44
44
|
log_location = log_location.gsub("%2F%2F","//")
|
|
45
45
|
retVal = HTTParty.get(log_location + "/log/" + did_hash)
|
|
46
46
|
if retVal.code != 200
|
|
47
|
-
|
|
48
|
-
"invalid response from " + log_location.to_s + "/log/" + did_hash.to_s
|
|
49
|
-
|
|
50
|
-
return [nil, msg]
|
|
47
|
+
return [nil, http_error_message(retVal, log_location.to_s + "/log/" + did_hash.to_s)]
|
|
51
48
|
end
|
|
52
49
|
if options.transform_keys(&:to_s)["trace"]
|
|
53
50
|
if options[:silent].nil? || !options[:silent]
|
|
@@ -79,9 +76,7 @@ class Oydid
|
|
|
79
76
|
log_location = log_location.gsub("%2F%2F","//")
|
|
80
77
|
retVal = HTTParty.get(log_location + "/log/" + log_hash + "/item")
|
|
81
78
|
if retVal.code != 200
|
|
82
|
-
|
|
83
|
-
"invalid response from " + log_location.to_s + "/log/" + log_hash.to_s + "/item"
|
|
84
|
-
return [nil, msg]
|
|
79
|
+
return [nil, http_error_message(retVal, log_location.to_s + "/log/" + log_hash.to_s + "/item")]
|
|
85
80
|
end
|
|
86
81
|
if options.transform_keys(&:to_s)["trace"]
|
|
87
82
|
if options[:silent].nil? || !options[:silent]
|
|
@@ -558,9 +553,22 @@ class Oydid
|
|
|
558
553
|
# handle DID Rotation
|
|
559
554
|
if (i == (currentDID["log"].length-1))
|
|
560
555
|
if options[:followAlsoKnownAs]
|
|
556
|
+
# the payload of a DID Document is arbitrary JSON: an
|
|
557
|
+
# Array or a scalar is valid and simply carries no
|
|
558
|
+
# alsoKnownAs, so only a Hash can be inspected for it.
|
|
559
|
+
# Without this guard a revoked DID whose document holds
|
|
560
|
+
# e.g. [5] raised NoMethodError here, the repository
|
|
561
|
+
# answered 500 with an empty body, and the resolver
|
|
562
|
+
# degraded that to "not found" instead of "deactivated".
|
|
561
563
|
current_doc = currentDID["doc"]
|
|
562
|
-
|
|
563
|
-
|
|
564
|
+
doc_payload = current_doc.is_a?(Hash) ? current_doc["doc"] : nil
|
|
565
|
+
doc_payload = doc_payload.transform_keys(&:to_s) if doc_payload.is_a?(Hash)
|
|
566
|
+
if doc_payload.is_a?(Hash) && doc_payload.has_key?("alsoKnownAs")
|
|
567
|
+
# DID Core defines alsoKnownAs as a set; older
|
|
568
|
+
# documents wrote a bare String
|
|
569
|
+
rotate_DID = doc_payload["alsoKnownAs"]
|
|
570
|
+
rotate_DID = rotate_DID.first if rotate_DID.is_a?(Array)
|
|
571
|
+
rotate_DID = rotate_DID.to_s
|
|
564
572
|
if rotate_DID.start_with?("did:")
|
|
565
573
|
rotate_DID_method = rotate_DID.split(":").take(2).join(":")
|
|
566
574
|
did_orig = currentDID["did"]
|
|
@@ -586,8 +594,14 @@ class Oydid
|
|
|
586
594
|
currentDID["verification"] += "(Details: https://ownyourdata.github.io/oydid/#did_rotation)" + "\n\n"
|
|
587
595
|
end
|
|
588
596
|
when "did:oyd"
|
|
589
|
-
|
|
590
|
-
|
|
597
|
+
# DID Rotation to another did:oyd identifier
|
|
598
|
+
# is not implemented yet: resolving it needs
|
|
599
|
+
# a second pass through this resolver.
|
|
600
|
+
if verification_output
|
|
601
|
+
currentDID["verification"] += "DID rotation to: " + rotate_DID.to_s + "\n"
|
|
602
|
+
currentDID["verification"] += "⚠️ rotation to another did:oyd identifier is not supported yet\n"
|
|
603
|
+
currentDID["verification"] += "(Details: https://ownyourdata.github.io/oydid/#did_rotation)" + "\n\n"
|
|
604
|
+
end
|
|
591
605
|
else
|
|
592
606
|
# do nothing: DID Rotation is not supported for this DID method yet
|
|
593
607
|
end
|
data/spec/oydid_spec.rb
CHANGED
|
@@ -519,6 +519,65 @@ describe "OYDID handling" do
|
|
|
519
519
|
# end
|
|
520
520
|
# end
|
|
521
521
|
|
|
522
|
+
# regression: the payload of a DID Document is arbitrary JSON, not
|
|
523
|
+
# necessarily an object. A revoked DID whose payload is an Array used to
|
|
524
|
+
# raise NoMethodError in the alsoKnownAs lookup - the repository then
|
|
525
|
+
# answered 500 with an empty body and the resolver reported "not found"
|
|
526
|
+
# instead of "deactivated".
|
|
527
|
+
describe "dag_update with a non-object DID Document payload" do
|
|
528
|
+
def revoked_state(payload)
|
|
529
|
+
{ "did" => "did:oyd:zQmPyjnkL52gQxBBhPuCFkf167MzpCKquqbu5Qt5ia2JGTr",
|
|
530
|
+
"doc" => { "doc" => payload, "key" => "", "log" => "" },
|
|
531
|
+
"log" => [{ "ts" => 1647732475, "op" => 1, "doc" => "zQmcVLwEtzU8By7TTeRFGvVUKm7HhZS6GgRTDFt51QNnans",
|
|
532
|
+
"sig" => "", "previous" => [] }] }
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
it "does not raise for an Array payload" do
|
|
536
|
+
expect {
|
|
537
|
+
Oydid.dag_update(revoked_state([5]), { followAlsoKnownAs: true })
|
|
538
|
+
}.not_to raise_error
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
it "does not raise for a scalar payload" do
|
|
542
|
+
expect {
|
|
543
|
+
Oydid.dag_update(revoked_state("plain"), { followAlsoKnownAs: true })
|
|
544
|
+
}.not_to raise_error
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
it "accepts alsoKnownAs written as a set" do
|
|
548
|
+
state = revoked_state({ "alsoKnownAs" => ["did:oyd:zQmaBZTghndXTgxNwfbdpVLWdFf6faYE4oeuN2zzXdQt1kh"] })
|
|
549
|
+
expect {
|
|
550
|
+
Oydid.dag_update(state, { followAlsoKnownAs: true })
|
|
551
|
+
}.not_to raise_error
|
|
552
|
+
end
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
# a broken repository (5xx) has to stay distinguishable from a DID that is
|
|
556
|
+
# not stored there - otherwise the caller reports "not found" and thereby
|
|
557
|
+
# claims the identifier never existed
|
|
558
|
+
describe "failure messages for non-200 responses" do
|
|
559
|
+
it "marks a 5xx as an upstream error" do
|
|
560
|
+
reply = double(code: 500, parsed_response: "")
|
|
561
|
+
msg = Oydid.http_error_message(reply, "https://oydid.ownyourdata.eu/doc/zQmXY")
|
|
562
|
+
expect(Oydid.upstream_error?(msg)).to be true
|
|
563
|
+
expect(msg).to include("500")
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
it "passes the repository's own error through" do
|
|
567
|
+
reply = double(code: 410, parsed_response: { "error" => "revoked" })
|
|
568
|
+
msg = Oydid.http_error_message(reply, "https://oydid.ownyourdata.eu/doc/zQmXY")
|
|
569
|
+
expect(msg).to eq "revoked"
|
|
570
|
+
expect(Oydid.upstream_error?(msg)).to be false
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
it "does not mark a 4xx without an error field as upstream error" do
|
|
574
|
+
reply = double(code: 404, parsed_response: nil)
|
|
575
|
+
msg = Oydid.http_error_message(reply, "https://oydid.ownyourdata.eu/doc/zQmXY")
|
|
576
|
+
expect(msg).to start_with("invalid response from")
|
|
577
|
+
expect(Oydid.upstream_error?(msg)).to be false
|
|
578
|
+
end
|
|
579
|
+
end
|
|
580
|
+
|
|
522
581
|
# main functionds
|
|
523
582
|
Dir.glob(File.expand_path("../input/main/*_read.doc", __FILE__)).each do |input|
|
|
524
583
|
it "execute read for #{input.split('/').last}" do
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: oydid
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.9.
|
|
4
|
+
version: 0.9.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Christoph Fabianek
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-08-
|
|
10
|
+
date: 2026-08-29 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: simple_dag
|