oydid 0.6.5 → 0.6.7
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 +76 -6
- data/spec/fixtures/http/did2-data-container-doc.json +1 -0
- data/spec/fixtures/http/manifest.json +56 -0
- data/spec/fixtures/http/oydid-doc-did-zQmaBZ.json +1 -0
- data/spec/fixtures/http/oydid-doc-empty.json +1 -0
- data/spec/fixtures/http/oydid-doc-raw-zQmaBZ.json +1 -0
- data/spec/fixtures/http/oydid-doc-zQmaBZ.json +1 -0
- data/spec/fixtures/http/oydid-log-zQmVwM.json +1 -0
- data/spec/fixtures/http/oydid-log-zQmZEP.json +1 -0
- data/spec/fixtures/http/oydid-log-zQmaBZ.json +1 -0
- data/spec/output/basic/sample3_retrieve_document.doc +1 -1
- data/spec/output/basic/sample_invalid_verify.doc +1 -1
- data/spec/output/basic/sample_valid_privkey.doc +1 -1
- data/spec/output/log/sample_addhash.doc +1 -1
- data/spec/output/log/sample_op1_addhash.doc +1 -1
- data/spec/output/main/sample0_read.doc +1 -1
- data/spec/oydid_spec.rb +79 -1
- data/spec/spec_helper.rb +3 -0
- data/spec/support/http_stubs.rb +43 -0
- metadata +24 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e8b1fc642be72b8b9a92b137f995360b5d4e68742b5a9744b59b3e88649976bb
|
|
4
|
+
data.tar.gz: 291e766737dec1b5756de3408097f5f243b02d3119ab3be2a29444957e82e9af
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 04bf2f70fcfe5200ed15417dbcd57734b3fe33603bb36eb4dc5007821d6c27af135a3b37552fd75c42a9a1feb02453411a47106340b9abb836496df679ec7b99
|
|
7
|
+
data.tar.gz: fd8d594757ecf3119c409b0d6169e607a823b1a575fcb1b5599625c2f305f580e51dee886a3112217272695b69e1da9ca65d1b3b1599a5908f916bce12aaacc1
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.6.
|
|
1
|
+
0.6.7
|
data/lib/oydid/basic.rb
CHANGED
|
@@ -791,9 +791,13 @@ class Oydid
|
|
|
791
791
|
rescue
|
|
792
792
|
return [nil, "cannot read file"]
|
|
793
793
|
end
|
|
794
|
-
|
|
794
|
+
# get_keytype raises for anything that is not a valid key, and the
|
|
795
|
+
# inline rescue below only guards the assignment - so key_type can end up
|
|
796
|
+
# nil when the caller passes no :key_type either. Coerce to a string
|
|
797
|
+
# instead of calling String methods on nil (raised NoMethodError before).
|
|
798
|
+
key_type = (get_keytype(key_encoded) || options[:key_type] rescue options[:key_type]).to_s
|
|
795
799
|
if key_type.include?('-')
|
|
796
|
-
key_type = key_type.split('-').first || options[:key_type]
|
|
800
|
+
key_type = (key_type.split('-').first || options[:key_type]).to_s
|
|
797
801
|
end
|
|
798
802
|
if key_type == 'p256'
|
|
799
803
|
begin
|
|
@@ -1012,14 +1016,23 @@ class Oydid
|
|
|
1012
1016
|
end
|
|
1013
1017
|
end
|
|
1014
1018
|
|
|
1015
|
-
#
|
|
1016
|
-
#
|
|
1017
|
-
#
|
|
1018
|
-
def self.
|
|
1019
|
+
# normalize and validate hex input shared by the hex-based converters below:
|
|
1020
|
+
# strips whitespace and an optional '0x' prefix and rejects anything that is
|
|
1021
|
+
# not an even number of hex digits. Returns [normalized_hex, ""] or [nil, msg].
|
|
1022
|
+
def self.normalize_hex(hex)
|
|
1019
1023
|
hex = hex.to_s.strip.delete_prefix("0x").delete_prefix("0X")
|
|
1020
1024
|
unless hex =~ /\A[0-9a-fA-F]+\z/ && hex.length.even?
|
|
1021
1025
|
return [nil, "invalid hex input"]
|
|
1022
1026
|
end
|
|
1027
|
+
return [hex, ""]
|
|
1028
|
+
end
|
|
1029
|
+
|
|
1030
|
+
# build an OYDID multibase-encoded private key from a raw hex-encoded key
|
|
1031
|
+
# (e.g. an externally generated P-256 or Ed25519 key). The key type is taken
|
|
1032
|
+
# from options[:key_type] (default 'ed25519').
|
|
1033
|
+
def self.private_key_from_hex(hex, options = {})
|
|
1034
|
+
hex, msg = normalize_hex(hex)
|
|
1035
|
+
return [nil, msg] if hex.nil?
|
|
1023
1036
|
raw = [hex].pack("H*")
|
|
1024
1037
|
key_type = options[:key_type].to_s
|
|
1025
1038
|
key_type = "ed25519" if key_type == ""
|
|
@@ -1047,6 +1060,63 @@ class Oydid
|
|
|
1047
1060
|
return multi_encode([code, length, raw].pack("SCa#{length}"), options)
|
|
1048
1061
|
end
|
|
1049
1062
|
|
|
1063
|
+
# counterpart to private_key_from_hex for public keys.
|
|
1064
|
+
#
|
|
1065
|
+
# NOTE on the p256 length check: multicodec 0x1200 ('p256-pub') is specified
|
|
1066
|
+
# for compressed points, but Oydid.public_key() emits uncompressed ones
|
|
1067
|
+
# (OpenSSL's default point_conversion_form), so both forms are accepted here
|
|
1068
|
+
# to stay compatible with keys this library produces itself.
|
|
1069
|
+
def self.public_key_from_hex(hex, options = {})
|
|
1070
|
+
hex, msg = normalize_hex(hex)
|
|
1071
|
+
return [nil, msg] if hex.nil?
|
|
1072
|
+
raw = [hex].pack("H*")
|
|
1073
|
+
key_type = options[:key_type].to_s
|
|
1074
|
+
key_type = "ed25519" if key_type == ""
|
|
1075
|
+
case key_type
|
|
1076
|
+
when "p256"
|
|
1077
|
+
unless [33, 65].include?(raw.bytesize)
|
|
1078
|
+
return [nil, "p256 public key must be 33 (compressed) or 65 (uncompressed) bytes"]
|
|
1079
|
+
end
|
|
1080
|
+
# the length alone says nothing: verify that the input actually
|
|
1081
|
+
# decodes to a point on prime256v1 (this also rejects a wrong
|
|
1082
|
+
# leading byte), otherwise an unusable key would be encoded happily
|
|
1083
|
+
begin
|
|
1084
|
+
OpenSSL::PKey::EC::Point.new(
|
|
1085
|
+
OpenSSL::PKey::EC::Group.new("prime256v1"),
|
|
1086
|
+
OpenSSL::BN.new(hex, 16))
|
|
1087
|
+
rescue StandardError
|
|
1088
|
+
return [nil, "p256 public key is not a valid point on the curve"]
|
|
1089
|
+
end
|
|
1090
|
+
code = Multicodecs["p256-pub"].code
|
|
1091
|
+
when "ed25519"
|
|
1092
|
+
unless raw.bytesize == 32
|
|
1093
|
+
return [nil, "ed25519 public key must be 32 bytes (64 hex characters)"]
|
|
1094
|
+
end
|
|
1095
|
+
# there is no cheap point validation for ed25519 (Ed25519::VerifyKey
|
|
1096
|
+
# accepts any 32 bytes), and a private key has the same length - so
|
|
1097
|
+
# passing a *private* key with --public silently yields a public key
|
|
1098
|
+
# multibase. Callers have to know what they hand in.
|
|
1099
|
+
code = Multicodecs["ed25519-pub"].code
|
|
1100
|
+
else
|
|
1101
|
+
return [nil, "unsupported key type"]
|
|
1102
|
+
end
|
|
1103
|
+
return multi_encode(Multibases::DecodedByteArray.new((to_varint(code) << raw.bytes).flatten).to_s(Encoding::BINARY), options)
|
|
1104
|
+
end
|
|
1105
|
+
|
|
1106
|
+
# convert raw hex data (no multicodec prefix, e.g. a signature) to Multibase
|
|
1107
|
+
def self.hex_to_multibase(hex, options = {})
|
|
1108
|
+
hex, msg = normalize_hex(hex)
|
|
1109
|
+
return [nil, msg] if hex.nil?
|
|
1110
|
+
# the multibases gem cannot represent an all-zero byte string: packing
|
|
1111
|
+
# raises NoMethodError and unpacking the correct base58btc form ("z1111")
|
|
1112
|
+
# raises RangeError. Leading zero bytes in otherwise non-zero input are
|
|
1113
|
+
# handled correctly, so only the all-zero case has to be rejected.
|
|
1114
|
+
if hex.delete("0") == ""
|
|
1115
|
+
return [nil, "all-zero input is not supported by the multibase encoder"]
|
|
1116
|
+
end
|
|
1117
|
+
return multi_encode([hex].pack("H*"), options)
|
|
1118
|
+
end
|
|
1119
|
+
|
|
1050
1120
|
# reverse of private_key_from_hex / public_key encoding:
|
|
1051
1121
|
# decode an OYDID Multibase-encoded key (private or public) back to raw hex.
|
|
1052
1122
|
def self.key_to_hex(key_encoded, options = {})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"doc":{"location":"non-default"},"key":"z6MutdYiDqv5kiJ79KXhcSyD38RZTRRhHYkhBo16891QsVmV:z6Mv8NqXsiUXeHVgJGCeX3JSnGwD17JKxMHep47SfSEy4u8Y","log":"zQmQwzGTZk1Me6GKWe6egJXGtRmoR3dfymVci4yqePqS8SN@https://did2.data-container.net"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"url": "https://did2.data-container.net/doc/did:oyd:zQmNauTUUdkpi5TcrTZ2524SKM8dJAzuuw4xfW13iHrtY1W",
|
|
4
|
+
"status": 200,
|
|
5
|
+
"content_type": "application/json; charset=utf-8",
|
|
6
|
+
"body": "did2-data-container-doc.json"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"url": "https://oydid.ownyourdata.eu/doc/",
|
|
10
|
+
"status": 404,
|
|
11
|
+
"content_type": "application/json; charset=utf-8",
|
|
12
|
+
"body": "oydid-doc-empty.json"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"url": "https://oydid.ownyourdata.eu/doc/did:oyd:zQmaBZTghndXTgxNwfbdpVLWdFf6faYE4oeuN2zzXdQt1kh",
|
|
16
|
+
"status": 200,
|
|
17
|
+
"content_type": "application/json; charset=utf-8",
|
|
18
|
+
"body": "oydid-doc-did-zQmaBZ.json"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"url": "https://oydid.ownyourdata.eu/log/zQmZEP95SPr699GjBeN82cspsZww8RKKHLR9UChbZxKw3H7",
|
|
22
|
+
"status": 200,
|
|
23
|
+
"content_type": "application/json; charset=utf-8",
|
|
24
|
+
"body": "oydid-log-zQmZEP.json"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"url": "https://www.orf.at/log/zQmZEP95SPr699GjBeN82cspsZww8RKKHLR9UChbZxKw3H",
|
|
28
|
+
"status": 404,
|
|
29
|
+
"content_type": "text/html;charset=utf-8",
|
|
30
|
+
"body": "orf-at-log.html"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"url": "https://oydid.ownyourdata.eu/doc/zQmaBZTghndXTgxNwfbdpVLWdFf6faYE4oeuN2zzXdQt1kh",
|
|
34
|
+
"status": 200,
|
|
35
|
+
"content_type": "application/json; charset=utf-8",
|
|
36
|
+
"body": "oydid-doc-zQmaBZ.json"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"url": "https://oydid.ownyourdata.eu/log/zQmVwMvovLy5KNYHHVHQ1wv8J7y9L6UPE8eyU4tzypFWtYe",
|
|
40
|
+
"status": 200,
|
|
41
|
+
"content_type": "application/json; charset=utf-8",
|
|
42
|
+
"body": "oydid-log-zQmVwM.json"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"url": "https://oydid.ownyourdata.eu/doc_raw/zQmaBZTghndXTgxNwfbdpVLWdFf6faYE4oeuN2zzXdQt1kh",
|
|
46
|
+
"status": 200,
|
|
47
|
+
"content_type": "application/json; charset=utf-8",
|
|
48
|
+
"body": "oydid-doc-raw-zQmaBZ.json"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"url": "https://oydid.ownyourdata.eu/log/zQmaBZTghndXTgxNwfbdpVLWdFf6faYE4oeuN2zzXdQt1kh",
|
|
52
|
+
"status": 200,
|
|
53
|
+
"content_type": "application/json; charset=utf-8",
|
|
54
|
+
"body": "oydid-log-zQmaBZ.json"
|
|
55
|
+
}
|
|
56
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"doc":{"simple":"example"},"key":"z6MusYB5iT5krCHYsZ76EzBaTdRwGKsaBhMcSbrXaPJgkuRQ:z6Mv7EYihbAat6Wq7GsjNsjcxt58dZT8fmsRjQGTkYamYrjB","log":"zQmVwMvovLy5KNYHHVHQ1wv8J7y9L6UPE8eyU4tzypFWtYe"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"error":"invalid path"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"doc":{"doc":{"simple":"example"},"key":"z6MusYB5iT5krCHYsZ76EzBaTdRwGKsaBhMcSbrXaPJgkuRQ:z6Mv7EYihbAat6Wq7GsjNsjcxt58dZT8fmsRjQGTkYamYrjB","log":"zQmVwMvovLy5KNYHHVHQ1wv8J7y9L6UPE8eyU4tzypFWtYe"},"log":[{"ts":1641224736,"op":2,"doc":"zQmaBZTghndXTgxNwfbdpVLWdFf6faYE4oeuN2zzXdQt1kh","sig":"z3Kb5qeReCqr3ftxpf2i5UypUwrzrVkyspMtaDcb6e9YdHVSptcAFgvwbgk3qWqspTcGiKDYKXZZh8g6XyM2WPmNp","previous":[]},{"ts":1641224736,"op":0,"doc":"zQmT8SG7a238bF7wdV7LdrEAQpimqhKGor7CQsjtCYdZdTS","sig":"z63hu8LseptBrvB2kEDwhPP35sBj7JDDJsEDW85cjRkrjjac9ZV3HxPW9NVKewHcQYwrVLVsnDCcm1RjbEARE5rJU","previous":[]}]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"doc":{"simple":"example"},"key":"z6MusYB5iT5krCHYsZ76EzBaTdRwGKsaBhMcSbrXaPJgkuRQ:z6Mv7EYihbAat6Wq7GsjNsjcxt58dZT8fmsRjQGTkYamYrjB","log":"zQmVwMvovLy5KNYHHVHQ1wv8J7y9L6UPE8eyU4tzypFWtYe"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[{"ts":1641224736,"op":2,"doc":"zQmaBZTghndXTgxNwfbdpVLWdFf6faYE4oeuN2zzXdQt1kh","sig":"z3Kb5qeReCqr3ftxpf2i5UypUwrzrVkyspMtaDcb6e9YdHVSptcAFgvwbgk3qWqspTcGiKDYKXZZh8g6XyM2WPmNp","previous":[]},{"ts":1641224736,"op":0,"doc":"zQmT8SG7a238bF7wdV7LdrEAQpimqhKGor7CQsjtCYdZdTS","sig":"z63hu8LseptBrvB2kEDwhPP35sBj7JDDJsEDW85cjRkrjjac9ZV3HxPW9NVKewHcQYwrVLVsnDCcm1RjbEARE5rJU","previous":[]}]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[{"ts":0,"op":2,"doc":"zQmZEP95SPr699GjBeN82cspsZww8RKKHLR9UChbZxKw3H7","sig":"z2vESePysjyywnUpVZbftZzh34j4GwPknfvtZms5BqmE4j7v72KHpBPrW5QxK22kWVoVbcxHanL2qwVd32MFRzDfM","previous":[]},{"ts":0,"op":0,"doc":"zQmReRus2QnsapBdVBqhYRddh2PyTRF1hDbUfJS44izyiex","sig":"zsxdDbaakXCj3tWLMf8m9UsYLNuisUD2jErcBdfSgjkLpA4CxZirJQpJahiC2Yxu5oqoTG2G7vvv9EPJhozVF4jE","previous":[]}]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[{"ts":1641224736,"op":2,"doc":"zQmaBZTghndXTgxNwfbdpVLWdFf6faYE4oeuN2zzXdQt1kh","sig":"z3Kb5qeReCqr3ftxpf2i5UypUwrzrVkyspMtaDcb6e9YdHVSptcAFgvwbgk3qWqspTcGiKDYKXZZh8g6XyM2WPmNp","previous":[]},{"ts":1641224736,"op":0,"doc":"zQmT8SG7a238bF7wdV7LdrEAQpimqhKGor7CQsjtCYdZdTS","sig":"z63hu8LseptBrvB2kEDwhPP35sBj7JDDJsEDW85cjRkrjjac9ZV3HxPW9NVKewHcQYwrVLVsnDCcm1RjbEARE5rJU","previous":[]}]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
[null,
|
|
1
|
+
[null,"invalid path"]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
[null,
|
|
1
|
+
[null,"unknown key codec"]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
["
|
|
1
|
+
["z6MkvkE1Gw5shxc8S6wNpfr8YNZWxgiUs6Yp6n45qdgTMoUF",""]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"hello":"world","entry-hash":"
|
|
1
|
+
[{"hello":"world","entry-hash":"zQmSvPd3sHK7iWgZuW47fyLy4CaZQe2DwxvRhrJ39VpBVMK"}]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"
|
|
1
|
+
[{"hello":"world","op":1,"entry-hash":"zQmemaqk7duDBUQZud3FahCPe83kMC5kxqKxkxgSUpzVhq1","sub-entry-hash":"zQmemaqk7duDBUQZud3FahCPe83kMC5kxqKxkxgSUpzVhq1"}]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"did":"zQmaBZTghndXTgxNwfbdpVLWdFf6faYE4oeuN2zzXdQt1kh","doc":{"doc":{"simple":"example"},"key":"z6MusYB5iT5krCHYsZ76EzBaTdRwGKsaBhMcSbrXaPJgkuRQ:z6Mv7EYihbAat6Wq7GsjNsjcxt58dZT8fmsRjQGTkYamYrjB","log":"zQmVwMvovLy5KNYHHVHQ1wv8J7y9L6UPE8eyU4tzypFWtYe"},"log":[{"ts":1641224736,"op":2,"doc":"zQmaBZTghndXTgxNwfbdpVLWdFf6faYE4oeuN2zzXdQt1kh","sig":"z3Kb5qeReCqr3ftxpf2i5UypUwrzrVkyspMtaDcb6e9YdHVSptcAFgvwbgk3qWqspTcGiKDYKXZZh8g6XyM2WPmNp","previous":[]},{"ts":1641224736,"op":0,"doc":"zQmT8SG7a238bF7wdV7LdrEAQpimqhKGor7CQsjtCYdZdTS","sig":"z63hu8LseptBrvB2kEDwhPP35sBj7JDDJsEDW85cjRkrjjac9ZV3HxPW9NVKewHcQYwrVLVsnDCcm1RjbEARE5rJU","previous":[]}],"doc_log_id":0,"termination_log_id":1,"error":0,"message":"","verification":"identifier: zQmaBZTghndXTgxNwfbdpVLWdFf6faYE4oeuN2zzXdQt1kh\n✅ is hash of DID Document:\n{\n \"doc\": {\n \"simple\": \"example\"\n },\n \"key\": \"z6MusYB5iT5krCHYsZ76EzBaTdRwGKsaBhMcSbrXaPJgkuRQ:z6Mv7EYihbAat6Wq7GsjNsjcxt58dZT8fmsRjQGTkYamYrjB\",\n \"log\": \"zQmVwMvovLy5KNYHHVHQ1wv8J7y9L6UPE8eyU4tzypFWtYe\"\n}\n(Details: https://ownyourdata.github.io/oydid/#calculate_hash)\n\n'log' reference in DID Document: zQmVwMvovLy5KNYHHVHQ1wv8J7y9L6UPE8eyU4tzypFWtYe\n✅ is hash of TERMINATE log record:\n{\n \"ts\": 1641224736,\n \"op\": 0,\n \"doc\": \"zQmT8SG7a238bF7wdV7LdrEAQpimqhKGor7CQsjtCYdZdTS\",\n \"sig\": \"z63hu8LseptBrvB2kEDwhPP35sBj7JDDJsEDW85cjRkrjjac9ZV3HxPW9NVKewHcQYwrVLVsnDCcm1RjbEARE5rJU\",\n \"previous\": [
|
|
1
|
+
[{"did":"zQmaBZTghndXTgxNwfbdpVLWdFf6faYE4oeuN2zzXdQt1kh","doc":{"doc":{"simple":"example"},"key":"z6MusYB5iT5krCHYsZ76EzBaTdRwGKsaBhMcSbrXaPJgkuRQ:z6Mv7EYihbAat6Wq7GsjNsjcxt58dZT8fmsRjQGTkYamYrjB","log":"zQmVwMvovLy5KNYHHVHQ1wv8J7y9L6UPE8eyU4tzypFWtYe"},"log":[{"ts":1641224736,"op":2,"doc":"zQmaBZTghndXTgxNwfbdpVLWdFf6faYE4oeuN2zzXdQt1kh","sig":"z3Kb5qeReCqr3ftxpf2i5UypUwrzrVkyspMtaDcb6e9YdHVSptcAFgvwbgk3qWqspTcGiKDYKXZZh8g6XyM2WPmNp","previous":[]},{"ts":1641224736,"op":0,"doc":"zQmT8SG7a238bF7wdV7LdrEAQpimqhKGor7CQsjtCYdZdTS","sig":"z63hu8LseptBrvB2kEDwhPP35sBj7JDDJsEDW85cjRkrjjac9ZV3HxPW9NVKewHcQYwrVLVsnDCcm1RjbEARE5rJU","previous":[]}],"doc_log_id":0,"termination_log_id":1,"error":0,"message":"","verification":"identifier: zQmaBZTghndXTgxNwfbdpVLWdFf6faYE4oeuN2zzXdQt1kh\n✅ is hash of DID Document:\n{\n \"doc\": {\n \"simple\": \"example\"\n },\n \"key\": \"z6MusYB5iT5krCHYsZ76EzBaTdRwGKsaBhMcSbrXaPJgkuRQ:z6Mv7EYihbAat6Wq7GsjNsjcxt58dZT8fmsRjQGTkYamYrjB\",\n \"log\": \"zQmVwMvovLy5KNYHHVHQ1wv8J7y9L6UPE8eyU4tzypFWtYe\"\n}\n(Details: https://ownyourdata.github.io/oydid/#calculate_hash)\n\n'log' reference in DID Document: zQmVwMvovLy5KNYHHVHQ1wv8J7y9L6UPE8eyU4tzypFWtYe\n✅ is hash of TERMINATE log record:\n{\n \"ts\": 1641224736,\n \"op\": 0,\n \"doc\": \"zQmT8SG7a238bF7wdV7LdrEAQpimqhKGor7CQsjtCYdZdTS\",\n \"sig\": \"z63hu8LseptBrvB2kEDwhPP35sBj7JDDJsEDW85cjRkrjjac9ZV3HxPW9NVKewHcQYwrVLVsnDCcm1RjbEARE5rJU\",\n \"previous\": []\n}\n(Details: https://ownyourdata.github.io/oydid/#calculate_hash)\n\nRevocation reference in log record: zQmT8SG7a238bF7wdV7LdrEAQpimqhKGor7CQsjtCYdZdTS\n✅ cannot find revocation record searching at\n- https://oydid.ownyourdata.eu\n(Details: https://ownyourdata.github.io/oydid/#retrieve_log)\n\n","full_log":[{"ts":1641224736,"op":2,"doc":"zQmaBZTghndXTgxNwfbdpVLWdFf6faYE4oeuN2zzXdQt1kh","sig":"z3Kb5qeReCqr3ftxpf2i5UypUwrzrVkyspMtaDcb6e9YdHVSptcAFgvwbgk3qWqspTcGiKDYKXZZh8g6XyM2WPmNp","previous":[]},{"ts":1641224736,"op":0,"doc":"zQmT8SG7a238bF7wdV7LdrEAQpimqhKGor7CQsjtCYdZdTS","sig":"z63hu8LseptBrvB2kEDwhPP35sBj7JDDJsEDW85cjRkrjjac9ZV3HxPW9NVKewHcQYwrVLVsnDCcm1RjbEARE5rJU","previous":[]}]},""]
|
data/spec/oydid_spec.rb
CHANGED
|
@@ -123,7 +123,9 @@ describe "OYDID handling" do
|
|
|
123
123
|
it "generates #{input.split('/').last}" do
|
|
124
124
|
expected = File.read(input.sub('input', 'output'))
|
|
125
125
|
data = File.read(input)
|
|
126
|
-
|
|
126
|
+
# signature is (input, method, options) - passing options as the 2nd
|
|
127
|
+
# argument made this resolve the codec {} and always return nil
|
|
128
|
+
expect(Oydid.generate_private_key(data, "ed25519-priv", {}).first).to eq expected
|
|
127
129
|
end
|
|
128
130
|
end
|
|
129
131
|
it "handles unknown key codec" do
|
|
@@ -238,6 +240,82 @@ describe "OYDID handling" do
|
|
|
238
240
|
expect(Oydid.key_to_hex("not-a-key", {}).first).to be_nil
|
|
239
241
|
end
|
|
240
242
|
|
|
243
|
+
# hex2mb: public keys (--public)
|
|
244
|
+
it "encodes an ed25519 public key from hex identically to public_key()" do
|
|
245
|
+
privkey, _ = Oydid.private_key_from_hex("aa" * 32, {key_type: "ed25519"})
|
|
246
|
+
pub_mb, _ = Oydid.public_key(privkey, {})
|
|
247
|
+
pub_hex, _ = Oydid.key_to_hex(pub_mb, {})
|
|
248
|
+
from_hex, msg = Oydid.public_key_from_hex(pub_hex, {key_type: "ed25519"})
|
|
249
|
+
expect(msg).to eq ""
|
|
250
|
+
expect(from_hex).to eq pub_mb
|
|
251
|
+
expect(Oydid.get_keytype(from_hex)).to eq "ed25519-pub"
|
|
252
|
+
end
|
|
253
|
+
it "encodes a p256 public key from hex identically to public_key()" do
|
|
254
|
+
privkey, _ = Oydid.private_key_from_hex(
|
|
255
|
+
"96fe0f41947d645c7a1858c48c7a0560e7e5bd3d45125b57a611a3a9a103626b",
|
|
256
|
+
{key_type: "p256"})
|
|
257
|
+
pub_mb, _ = Oydid.public_key(privkey, {})
|
|
258
|
+
pub_hex, _ = Oydid.key_to_hex(pub_mb, {})
|
|
259
|
+
from_hex, msg = Oydid.public_key_from_hex(pub_hex, {key_type: "p256"})
|
|
260
|
+
expect(msg).to eq ""
|
|
261
|
+
expect(from_hex).to eq pub_mb
|
|
262
|
+
expect(Oydid.get_keytype(from_hex)).to eq "p256-pub"
|
|
263
|
+
end
|
|
264
|
+
it "round-trips a public key hex -> mb -> hex" do
|
|
265
|
+
hex = "e734ea6c2b6257de72355e472aa05a4c487e6b463c029ed306df2f01b5636b58"
|
|
266
|
+
mb, _ = Oydid.public_key_from_hex(hex, {key_type: "ed25519"})
|
|
267
|
+
back, _ = Oydid.key_to_hex(mb, {})
|
|
268
|
+
expect(back).to eq hex
|
|
269
|
+
end
|
|
270
|
+
it "accepts a compressed p256 public key" do
|
|
271
|
+
hex = "03bcad0c43ac859d0552d95b639156073f9c1c4fb1aa9490f3639a8cf0a2aaadaa"
|
|
272
|
+
mb, msg = Oydid.public_key_from_hex(hex, {key_type: "p256"})
|
|
273
|
+
expect(msg).to eq ""
|
|
274
|
+
expect(Oydid.get_keytype(mb)).to eq "p256-pub"
|
|
275
|
+
end
|
|
276
|
+
it "rejects a p256 public key that is not a point on the curve" do
|
|
277
|
+
mb, msg = Oydid.public_key_from_hex("04" + "11" * 64, {key_type: "p256"})
|
|
278
|
+
expect(mb).to be_nil
|
|
279
|
+
expect(msg).to match(/not a valid point/)
|
|
280
|
+
end
|
|
281
|
+
it "rejects malformed public key hex" do
|
|
282
|
+
expect(Oydid.public_key_from_hex("xyz", {key_type: "ed25519"}).first).to be_nil
|
|
283
|
+
expect(Oydid.public_key_from_hex("aa" * 31, {key_type: "ed25519"}).first).to be_nil
|
|
284
|
+
expect(Oydid.public_key_from_hex("aa" * 32, {key_type: "p256"}).first).to be_nil
|
|
285
|
+
expect(Oydid.public_key_from_hex("aa" * 32, {key_type: "secp256k1"}).first).to be_nil
|
|
286
|
+
end
|
|
287
|
+
it "defaults to ed25519 when no key type is given for a public key" do
|
|
288
|
+
hex = "e734ea6c2b6257de72355e472aa05a4c487e6b463c029ed306df2f01b5636b58"
|
|
289
|
+
expect(Oydid.get_keytype(Oydid.public_key_from_hex(hex, {}).first)).to eq "ed25519-pub"
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# hex2mb: raw data (--raw)
|
|
293
|
+
it "encodes raw hex data to multibase without a multicodec prefix" do
|
|
294
|
+
mb, msg = Oydid.hex_to_multibase("deadbeef", {})
|
|
295
|
+
expect(msg).to eq ""
|
|
296
|
+
expect(Oydid.multi_decode(mb).first.unpack1("H*")).to eq "deadbeef"
|
|
297
|
+
# no multicodec prefix -> deliberately not readable back as a key
|
|
298
|
+
expect(Oydid.key_to_hex(mb, {}).first).to be_nil
|
|
299
|
+
end
|
|
300
|
+
it "preserves leading zero bytes in raw hex data" do
|
|
301
|
+
mb, _ = Oydid.hex_to_multibase("00deadbeef", {})
|
|
302
|
+
expect(Oydid.multi_decode(mb).first.unpack1("H*")).to eq "00deadbeef"
|
|
303
|
+
end
|
|
304
|
+
it "accepts a 0x prefix and surrounding whitespace in raw hex data" do
|
|
305
|
+
expect(Oydid.hex_to_multibase(" 0xdeadbeef\n", {}).first).to \
|
|
306
|
+
eq Oydid.hex_to_multibase("deadbeef", {}).first
|
|
307
|
+
end
|
|
308
|
+
it "rejects all-zero raw hex data with a specific message" do
|
|
309
|
+
mb, msg = Oydid.hex_to_multibase("00" * 4, {})
|
|
310
|
+
expect(mb).to be_nil
|
|
311
|
+
expect(msg).to match(/all-zero/)
|
|
312
|
+
end
|
|
313
|
+
it "rejects malformed raw hex data" do
|
|
314
|
+
expect(Oydid.hex_to_multibase("xyz", {}).first).to be_nil
|
|
315
|
+
expect(Oydid.hex_to_multibase("abc", {}).first).to be_nil
|
|
316
|
+
expect(Oydid.hex_to_multibase("", {}).first).to be_nil
|
|
317
|
+
end
|
|
318
|
+
|
|
241
319
|
# storage functions
|
|
242
320
|
it "should create 'filename' and put/read 'text'" do
|
|
243
321
|
@buffer = StringIO.new()
|
data/spec/spec_helper.rb
CHANGED
|
@@ -25,6 +25,9 @@ end
|
|
|
25
25
|
|
|
26
26
|
require 'oydid'
|
|
27
27
|
|
|
28
|
+
# spec/support/http_stubs.rb keeps the suite off the network
|
|
29
|
+
Dir[File.expand_path("support/**/*.rb", __dir__)].sort.each { |f| require f }
|
|
30
|
+
|
|
28
31
|
::RSpec.configure do |c|
|
|
29
32
|
c.filter_run focus: true
|
|
30
33
|
c.run_all_when_everything_filtered = true
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Keeps the suite off the public internet.
|
|
2
|
+
#
|
|
3
|
+
# Seven examples used to resolve DID documents and logs over HTTP against
|
|
4
|
+
# oydid.ownyourdata.eu and did2.data-container.net. That made the suite depend
|
|
5
|
+
# on production staying reachable and on data from 2022 never changing - a CI
|
|
6
|
+
# failure then said nothing about the code.
|
|
7
|
+
#
|
|
8
|
+
# The recorded responses live in spec/fixtures/http; manifest.json maps each URL
|
|
9
|
+
# to its status, content type and body file. To refresh one, fetch the URL and
|
|
10
|
+
# overwrite the body file - the expectations under spec/output must then be
|
|
11
|
+
# checked, not blindly regenerated.
|
|
12
|
+
#
|
|
13
|
+
# disable_net_connect! makes any unstubbed request fail loudly, so a newly added
|
|
14
|
+
# network call cannot slip in unnoticed.
|
|
15
|
+
|
|
16
|
+
require "json"
|
|
17
|
+
require "webmock/rspec"
|
|
18
|
+
|
|
19
|
+
WebMock.disable_net_connect!(allow_localhost: false)
|
|
20
|
+
|
|
21
|
+
module HttpFixtures
|
|
22
|
+
DIR = File.expand_path("../fixtures/http", __dir__)
|
|
23
|
+
|
|
24
|
+
def self.entries
|
|
25
|
+
@entries ||= JSON.parse(File.read(File.join(DIR, "manifest.json")))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.body(entry)
|
|
29
|
+
File.read(File.join(DIR, entry["body"]))
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
RSpec.configure do |config|
|
|
34
|
+
config.before(:each) do
|
|
35
|
+
HttpFixtures.entries.each do |entry|
|
|
36
|
+
stub_request(:get, entry["url"]).to_return(
|
|
37
|
+
status: entry["status"],
|
|
38
|
+
body: HttpFixtures.body(entry),
|
|
39
|
+
headers: { "Content-Type" => entry["content_type"] },
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
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.6.
|
|
4
|
+
version: 0.6.7
|
|
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-19 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: simple_dag
|
|
@@ -261,6 +261,15 @@ files:
|
|
|
261
261
|
- lib/oydid/didcomm.rb
|
|
262
262
|
- lib/oydid/log.rb
|
|
263
263
|
- lib/oydid/vc.rb
|
|
264
|
+
- spec/fixtures/http/did2-data-container-doc.json
|
|
265
|
+
- spec/fixtures/http/manifest.json
|
|
266
|
+
- spec/fixtures/http/oydid-doc-did-zQmaBZ.json
|
|
267
|
+
- spec/fixtures/http/oydid-doc-empty.json
|
|
268
|
+
- spec/fixtures/http/oydid-doc-raw-zQmaBZ.json
|
|
269
|
+
- spec/fixtures/http/oydid-doc-zQmaBZ.json
|
|
270
|
+
- spec/fixtures/http/oydid-log-zQmVwM.json
|
|
271
|
+
- spec/fixtures/http/oydid-log-zQmZEP.json
|
|
272
|
+
- spec/fixtures/http/oydid-log-zQmaBZ.json
|
|
264
273
|
- spec/input/basic/arrays.json
|
|
265
274
|
- spec/input/basic/french.json
|
|
266
275
|
- spec/input/basic/sample2_get_location.doc
|
|
@@ -400,6 +409,7 @@ files:
|
|
|
400
409
|
- spec/output/main/sample0_read.doc
|
|
401
410
|
- spec/oydid_spec.rb
|
|
402
411
|
- spec/spec_helper.rb
|
|
412
|
+
- spec/support/http_stubs.rb
|
|
403
413
|
homepage: http://github.com/ownyourdata/oydid
|
|
404
414
|
licenses:
|
|
405
415
|
- Apache-2.0
|
|
@@ -415,17 +425,26 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
415
425
|
requirements:
|
|
416
426
|
- - ">="
|
|
417
427
|
- !ruby/object:Gem::Version
|
|
418
|
-
version: 3.
|
|
428
|
+
version: 3.2.0
|
|
419
429
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
420
430
|
requirements:
|
|
421
431
|
- - ">="
|
|
422
432
|
- !ruby/object:Gem::Version
|
|
423
433
|
version: '0'
|
|
424
434
|
requirements: []
|
|
425
|
-
rubygems_version: 4.0.
|
|
435
|
+
rubygems_version: 4.0.12
|
|
426
436
|
specification_version: 4
|
|
427
437
|
summary: Own Your Decentralized Identifier for Ruby.
|
|
428
438
|
test_files:
|
|
439
|
+
- spec/fixtures/http/did2-data-container-doc.json
|
|
440
|
+
- spec/fixtures/http/manifest.json
|
|
441
|
+
- spec/fixtures/http/oydid-doc-did-zQmaBZ.json
|
|
442
|
+
- spec/fixtures/http/oydid-doc-empty.json
|
|
443
|
+
- spec/fixtures/http/oydid-doc-raw-zQmaBZ.json
|
|
444
|
+
- spec/fixtures/http/oydid-doc-zQmaBZ.json
|
|
445
|
+
- spec/fixtures/http/oydid-log-zQmVwM.json
|
|
446
|
+
- spec/fixtures/http/oydid-log-zQmZEP.json
|
|
447
|
+
- spec/fixtures/http/oydid-log-zQmaBZ.json
|
|
429
448
|
- spec/input/basic/arrays.json
|
|
430
449
|
- spec/input/basic/french.json
|
|
431
450
|
- spec/input/basic/sample2_get_location.doc
|
|
@@ -565,3 +584,4 @@ test_files:
|
|
|
565
584
|
- spec/output/main/sample0_read.doc
|
|
566
585
|
- spec/oydid_spec.rb
|
|
567
586
|
- spec/spec_helper.rb
|
|
587
|
+
- spec/support/http_stubs.rb
|