sidetree 0.1.2 → 0.1.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/lib/sidetree/did.rb +2 -2
- data/lib/sidetree/key.rb +17 -4
- data/lib/sidetree/model/cas_file_base.rb +40 -0
- data/lib/sidetree/model/chunk_file.rb +7 -15
- data/lib/sidetree/model/core_index_file.rb +6 -13
- data/lib/sidetree/model/core_proof_file.rb +102 -0
- data/lib/sidetree/model/document.rb +6 -0
- data/lib/sidetree/model/provisional_index_file.rb +9 -14
- data/lib/sidetree/model/provisional_proof_file.rb +80 -0
- data/lib/sidetree/model.rb +3 -0
- data/lib/sidetree/op/deactivate.rb +4 -1
- data/lib/sidetree/op/updatable.rb +24 -10
- data/lib/sidetree/util/jwk.rb +47 -0
- data/lib/sidetree/util/jws.rb +52 -0
- data/lib/sidetree/util.rb +2 -0
- data/lib/sidetree/version.rb +1 -1
- data/lib/sidetree.rb +2 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b65f50d961dcfc15f1440ae26225fad38a7b42f43874764005b9d01cc624bb3a
|
4
|
+
data.tar.gz: dbe04b5d7072da5b1cbec36b90089d29cb69e6077cc60a501045d0eddff38d92
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e7aa774c61569b33aa98de41aa6ab265c58107346704aaebf673e45bc464f250f1073ea70994ae1a884cbd92964dc7e84b1841e2cbfc917601157a2eea1a7854
|
7
|
+
data.tar.gz: a68ccd2615046db978b08dcffa585611f2ed44ee59a765e0c53614074892ad83e5f733df493bc8f06a15a4b264c777c52867f486562e13918b5cf4fff236c758
|
data/lib/sidetree/did.rb
CHANGED
@@ -48,8 +48,8 @@ module Sidetree
|
|
48
48
|
raise Error, "recovery_key must be Sidetree::Key instance."
|
49
49
|
end
|
50
50
|
|
51
|
-
|
52
|
-
|
51
|
+
delta =
|
52
|
+
Model::Delta.new([document.to_replace_patch], update_key.to_commitment)
|
53
53
|
suffix =
|
54
54
|
Sidetree::Model::Suffix.new(delta.to_hash, recovery_key.to_commitment)
|
55
55
|
DID.new(
|
data/lib/sidetree/key.rb
CHANGED
@@ -128,10 +128,11 @@ module Sidetree
|
|
128
128
|
end
|
129
129
|
|
130
130
|
# Generate JSON::JWK object.
|
131
|
+
# @param [Boolean] include_privkey whether include private key or not.
|
131
132
|
# @return [JSON::JWK]
|
132
|
-
def to_jwk
|
133
|
+
def to_jwk(include_privkey: false)
|
133
134
|
jwk =
|
134
|
-
|
135
|
+
Sidetree::Util::JWK.parse(
|
135
136
|
kty: "EC",
|
136
137
|
crv: "secp256k1",
|
137
138
|
x:
|
@@ -151,18 +152,30 @@ module Sidetree
|
|
151
152
|
padding: false
|
152
153
|
)
|
153
154
|
)
|
154
|
-
jwk["d"] = encoded_private_key if private_key
|
155
|
+
jwk["d"] = encoded_private_key if include_privkey && private_key
|
155
156
|
jwk
|
156
157
|
end
|
157
158
|
|
159
|
+
# Convert the private key to the format (OpenSSL::PKey::EC) in which it will be signed in JWS.
|
160
|
+
# @return [OpenSSL::PKey::EC]
|
161
|
+
def jws_sign_key
|
162
|
+
return nil unless private_key
|
163
|
+
to_jwk(include_privkey: true).to_key
|
164
|
+
end
|
165
|
+
|
158
166
|
# Generate commitment for this key.
|
159
167
|
# @return [String] Base64 encoded commitment.
|
160
168
|
def to_commitment
|
161
169
|
digest = Digest::SHA256.digest(to_jwk.normalize.to_json_c14n)
|
162
|
-
|
163
170
|
Sidetree.to_hash(digest)
|
164
171
|
end
|
165
172
|
|
173
|
+
# Generate reveal value for this key.
|
174
|
+
# @return [String] Base64 encoded reveal value.
|
175
|
+
def to_reveal_value
|
176
|
+
Sidetree.to_hash(to_jwk.normalize.to_json_c14n)
|
177
|
+
end
|
178
|
+
|
166
179
|
def to_h
|
167
180
|
h = { publicKeyJwk: to_jwk.normalize, purposes: purposes }
|
168
181
|
h[:id] = id if id
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Sidetree
|
2
|
+
module Model
|
3
|
+
class CASFileBase
|
4
|
+
include Sidetree::Util::Compressor
|
5
|
+
|
6
|
+
# Decompress +data+.
|
7
|
+
# @param [String] data compressed data.
|
8
|
+
# @param [Integer] max_size
|
9
|
+
# @return [String] decompressed data.
|
10
|
+
# @raise [Sidetree::Error]
|
11
|
+
def self.decompress(data, max_size)
|
12
|
+
begin
|
13
|
+
Sidetree::Util::Compressor.decompress(
|
14
|
+
data,
|
15
|
+
max_bytes:
|
16
|
+
max_size *
|
17
|
+
Sidetree::Util::Compressor::ESTIMATE_DECOMPRESSION_MULTIPLIER
|
18
|
+
)
|
19
|
+
rescue Zlib::GzipFile::Error
|
20
|
+
raise Sidetree::Error,
|
21
|
+
"#{self.name.split("::").last.split(/(?=[A-Z])/).join(" ")} decompression failure"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Build json string to be stored in CAS.
|
26
|
+
# Child classes must implement this method.
|
27
|
+
# @return [String]
|
28
|
+
def to_json
|
29
|
+
raise NotImplementedError,
|
30
|
+
"You must implement #{self.class}##{__method__}"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Generate compressed data via to_json to be stored in CAS.
|
34
|
+
# @return [String] compressed data.
|
35
|
+
def to_compress
|
36
|
+
compress(to_json)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Sidetree
|
2
2
|
module Model
|
3
3
|
# https://identity.foundation/sidetree/spec/#chunk-files
|
4
|
-
class ChunkFile
|
4
|
+
class ChunkFile < CASFileBase
|
5
5
|
attr_reader :deltas # Array of Sidetree::Model::Delta
|
6
6
|
|
7
7
|
def initialize(deltas = [])
|
@@ -19,8 +19,7 @@ module Sidetree
|
|
19
19
|
# @param [Array[Sidetree::OP::Recover]] recover_ops
|
20
20
|
# @param [Array[Sidetree::OP::Update]] update_ops
|
21
21
|
def self.create_from_ops(create_ops: [], recover_ops: [], update_ops: [])
|
22
|
-
deltas = create_ops.map(&:delta)
|
23
|
-
# TODO add update and recover operation delta
|
22
|
+
deltas = (create_ops + recover_ops + update_ops).map(&:delta)
|
24
23
|
ChunkFile.new(deltas)
|
25
24
|
end
|
26
25
|
|
@@ -30,16 +29,10 @@ module Sidetree
|
|
30
29
|
# @return [Sidetree::Model::ChunkFile]
|
31
30
|
# @raise [Sidetree::Error]
|
32
31
|
def self.parse(chunk_file, compressed: true)
|
33
|
-
max_bytes =
|
34
|
-
Sidetree::Params::MAX_CHUNK_FILE_SIZE *
|
35
|
-
Sidetree::Util::Compressor::ESTIMATE_DECOMPRESSION_MULTIPLIER
|
36
32
|
decompressed =
|
37
33
|
(
|
38
34
|
if compressed
|
39
|
-
Sidetree::
|
40
|
-
chunk_file,
|
41
|
-
max_bytes: max_bytes
|
42
|
-
)
|
35
|
+
decompress(chunk_file, Sidetree::Params::MAX_CHUNK_FILE_SIZE)
|
43
36
|
else
|
44
37
|
chunk_file
|
45
38
|
end
|
@@ -62,11 +55,10 @@ module Sidetree
|
|
62
55
|
)
|
63
56
|
end
|
64
57
|
|
65
|
-
#
|
66
|
-
# @return [String]
|
67
|
-
def
|
68
|
-
|
69
|
-
Sidetree::Util::Compressor.compress(params.to_json)
|
58
|
+
# Build json string to be stored in CAS.
|
59
|
+
# @return [String] json string.
|
60
|
+
def to_json
|
61
|
+
{ deltas: deltas.map(&:to_h) }.to_json
|
70
62
|
end
|
71
63
|
|
72
64
|
# Check if the +other+ object have the same chunk data.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Sidetree
|
2
2
|
module Model
|
3
3
|
# https://identity.foundation/sidetree/spec/#core-index-file
|
4
|
-
class CoreIndexFile
|
4
|
+
class CoreIndexFile < CASFileBase
|
5
5
|
attr_reader :core_proof_file_uri
|
6
6
|
attr_reader :provisional_index_file_uri
|
7
7
|
attr_reader :writer_lock_id
|
@@ -74,14 +74,7 @@ module Sidetree
|
|
74
74
|
decompressed =
|
75
75
|
(
|
76
76
|
if compressed
|
77
|
-
|
78
|
-
Sidetree::Util::Compressor.decompress(
|
79
|
-
index_data,
|
80
|
-
max_bytes: Sidetree::Params::MAX_CORE_INDEX_FILE_SIZE
|
81
|
-
)
|
82
|
-
rescue Zlib::GzipFile::Error
|
83
|
-
raise Sidetree::Error, "Core index file decompression failure"
|
84
|
-
end
|
77
|
+
decompress(index_data, Sidetree::Params::MAX_CORE_INDEX_FILE_SIZE)
|
85
78
|
else
|
86
79
|
index_data
|
87
80
|
end
|
@@ -165,9 +158,9 @@ module Sidetree
|
|
165
158
|
(recover_ops + deactivate_ops).map { |o| o.did_suffix }
|
166
159
|
end
|
167
160
|
|
168
|
-
#
|
169
|
-
# @return [String]
|
170
|
-
def
|
161
|
+
# Build json string to be stored in CAS.
|
162
|
+
# @return [String] json string.
|
163
|
+
def to_json
|
171
164
|
params = {}
|
172
165
|
params[
|
173
166
|
:provisionalIndexFileUri
|
@@ -197,7 +190,7 @@ module Sidetree
|
|
197
190
|
params[:operations] = operations
|
198
191
|
params[:coreProofFileUri] = core_proof_file_uri if core_proof_file_uri
|
199
192
|
params[:writerLockId] = writer_lock_id if writer_lock_id
|
200
|
-
|
193
|
+
params.to_json
|
201
194
|
end
|
202
195
|
end
|
203
196
|
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module Sidetree
|
2
|
+
module Model
|
3
|
+
# https://identity.foundation/sidetree/spec/#core-proof-file
|
4
|
+
class CoreProofFile < CASFileBase
|
5
|
+
attr_reader :recover_proofs
|
6
|
+
attr_reader :deactivate_proofs
|
7
|
+
|
8
|
+
def initialize(recover_proofs, deactivate_proofs)
|
9
|
+
@recover_proofs = recover_proofs
|
10
|
+
@deactivate_proofs = deactivate_proofs
|
11
|
+
end
|
12
|
+
|
13
|
+
# Parse core proof file from compressed data.
|
14
|
+
# @param [String] proof_file compressed core proof file.
|
15
|
+
# @param [Boolean] compressed Whether the proof_file is compressed or not, default: true.
|
16
|
+
# @return [Sidetree::Model::CoreProofFile]
|
17
|
+
# @raise [Sidetree::Error]
|
18
|
+
def self.parse(proof_file, compressed: true)
|
19
|
+
decompressed =
|
20
|
+
(
|
21
|
+
if compressed
|
22
|
+
decompress(proof_file, Sidetree::Params::MAX_PROOF_FILE_SIZE)
|
23
|
+
else
|
24
|
+
proof_file
|
25
|
+
end
|
26
|
+
)
|
27
|
+
begin
|
28
|
+
json = JSON.parse(decompressed, symbolize_names: true)
|
29
|
+
recover_proofs, deactivate_proofs = [], []
|
30
|
+
json.keys.each do |k|
|
31
|
+
unless k == :operations
|
32
|
+
raise Sidetree::Error,
|
33
|
+
"Unexpected property #{k.to_s} in core proof file"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
unless json[:operations]
|
37
|
+
raise Sidetree::Error,
|
38
|
+
"Core proof file does not have any operation proofs"
|
39
|
+
end
|
40
|
+
json[:operations].keys.each do |k|
|
41
|
+
unless k == :recover || k == :deactivate
|
42
|
+
raise Sidetree::Error,
|
43
|
+
"Unexpected property #{k.to_s} in core proof file"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
if json[:operations][:recover]
|
47
|
+
unless json[:operations][:recover].is_a?(Array)
|
48
|
+
raise Sidetree::Error,
|
49
|
+
"Core proof file recover property not array"
|
50
|
+
end
|
51
|
+
recover_proofs =
|
52
|
+
json[:operations][:recover].each.map do |update|
|
53
|
+
update.keys.each do |k|
|
54
|
+
unless k == :signedData
|
55
|
+
raise Sidetree::Error,
|
56
|
+
"Unexpected property #{k.to_s} in core proof file"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
Sidetree::Util::JWS.parse(update[:signedData])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
if json[:operations][:deactivate]
|
63
|
+
unless json[:operations][:deactivate].is_a?(Array)
|
64
|
+
raise Sidetree::Error,
|
65
|
+
"Core proof file deactivate property not array"
|
66
|
+
end
|
67
|
+
deactivate_proofs =
|
68
|
+
json[:operations][:deactivate].each.map do |update|
|
69
|
+
update.keys.each do |k|
|
70
|
+
unless k == :signedData
|
71
|
+
raise Sidetree::Error,
|
72
|
+
"Unexpected property #{k.to_s} in core proof file"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
Sidetree::Util::JWS.parse(update[:signedData])
|
76
|
+
end
|
77
|
+
end
|
78
|
+
if recover_proofs.length + deactivate_proofs.length == 0
|
79
|
+
raise Sidetree::Error, "Core proof file has no proof"
|
80
|
+
end
|
81
|
+
CoreProofFile.new(recover_proofs, deactivate_proofs)
|
82
|
+
rescue JSON::ParserError
|
83
|
+
raise Sidetree::Error, "Core proof file is not json"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Build json string to be stored in CAS.
|
88
|
+
# @return [String] json string.
|
89
|
+
def to_json
|
90
|
+
operations = {}
|
91
|
+
operations[:recover] = recover_proofs.map do |u|
|
92
|
+
{ signedData: u.to_s }
|
93
|
+
end unless recover_proofs.empty?
|
94
|
+
operations[:deactivate] = deactivate_proofs.map do |u|
|
95
|
+
{ signedData: u.to_s }
|
96
|
+
end unless deactivate_proofs.empty?
|
97
|
+
params = { operations: operations }
|
98
|
+
params.to_json
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -35,6 +35,12 @@ module Sidetree
|
|
35
35
|
def to_h
|
36
36
|
{ publicKeys: public_keys.map(&:to_h), services: services.map(&:to_h) }
|
37
37
|
end
|
38
|
+
|
39
|
+
# Generate replace patch.
|
40
|
+
# @return [Hash]
|
41
|
+
def to_replace_patch
|
42
|
+
{ action: OP::PatchAction::REPLACE, document: to_h }
|
43
|
+
end
|
38
44
|
end
|
39
45
|
end
|
40
46
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Sidetree
|
2
2
|
module Model
|
3
3
|
# https://identity.foundation/sidetree/spec/#provisional-index-file
|
4
|
-
class ProvisionalIndexFile
|
4
|
+
class ProvisionalIndexFile < CASFileBase
|
5
5
|
attr_reader :provisional_proof_file_uri
|
6
6
|
attr_reader :chunks
|
7
7
|
attr_reader :operations
|
@@ -44,15 +44,10 @@ module Sidetree
|
|
44
44
|
decompressed =
|
45
45
|
(
|
46
46
|
if compressed
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
)
|
52
|
-
rescue Zlib::GzipFile::Error
|
53
|
-
raise Sidetree::Error,
|
54
|
-
"Provisional Index File decompression failure"
|
55
|
-
end
|
47
|
+
decompress(
|
48
|
+
index_data,
|
49
|
+
Sidetree::Params::MAX_PROVISIONAL_INDEX_FILE_SIZE
|
50
|
+
)
|
56
51
|
else
|
57
52
|
index_data
|
58
53
|
end
|
@@ -111,9 +106,9 @@ module Sidetree
|
|
111
106
|
end
|
112
107
|
end
|
113
108
|
|
114
|
-
#
|
115
|
-
# @return [String]
|
116
|
-
def
|
109
|
+
# Build json string to be stored in CAS.
|
110
|
+
# @return [String] json string.
|
111
|
+
def to_json
|
117
112
|
params = { chunks: chunks.map(&:to_h) }
|
118
113
|
unless operations.empty?
|
119
114
|
params[:operations] = {
|
@@ -127,7 +122,7 @@ module Sidetree
|
|
127
122
|
}
|
128
123
|
params[:provisionalProofFileUri] = provisional_proof_file_uri
|
129
124
|
end
|
130
|
-
|
125
|
+
params.to_json
|
131
126
|
end
|
132
127
|
end
|
133
128
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Sidetree
|
2
|
+
module Model
|
3
|
+
# https://identity.foundation/sidetree/spec/#provisional-proof-file
|
4
|
+
class ProvisionalProofFile < CASFileBase
|
5
|
+
attr_reader :update_proofs
|
6
|
+
|
7
|
+
# Initialize
|
8
|
+
# @param [Array[JSON::JWS]] update_proofs Array of update proof.
|
9
|
+
def initialize(update_proofs)
|
10
|
+
@update_proofs = update_proofs
|
11
|
+
end
|
12
|
+
|
13
|
+
# Parse provisional proof file from compressed data.
|
14
|
+
# @param [String] proof_file compressed provisional proof file.
|
15
|
+
# @param [Boolean] compressed Whether the proof_file is compressed or not, default: true.
|
16
|
+
# @return [Sidetree::Model::ProvisionalProofFile]
|
17
|
+
# @raise [Sidetree::Error]
|
18
|
+
def self.parse(proof_file, compressed: true)
|
19
|
+
decompressed =
|
20
|
+
(
|
21
|
+
if compressed
|
22
|
+
decompress(proof_file, Sidetree::Params::MAX_PROOF_FILE_SIZE)
|
23
|
+
else
|
24
|
+
proof_file
|
25
|
+
end
|
26
|
+
)
|
27
|
+
begin
|
28
|
+
json = JSON.parse(decompressed, symbolize_names: true)
|
29
|
+
json.keys.each do |k|
|
30
|
+
unless k == :operations
|
31
|
+
raise Sidetree::Error,
|
32
|
+
"Unexpected property #{k.to_s} in provisional proof file"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
unless json[:operations]
|
36
|
+
raise Sidetree::Error,
|
37
|
+
"Provisional proof file does not have any operation proofs"
|
38
|
+
end
|
39
|
+
json[:operations].keys.each do |k|
|
40
|
+
unless k == :update
|
41
|
+
raise Sidetree::Error,
|
42
|
+
"Unexpected property #{k.to_s} in provisional proof file"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
unless json[:operations][:update].is_a?(Array)
|
46
|
+
raise Sidetree::Error,
|
47
|
+
"Provisional proof file update property not array"
|
48
|
+
end
|
49
|
+
update_proofs =
|
50
|
+
json[:operations][:update].each.map do |update|
|
51
|
+
update.keys.each do |k|
|
52
|
+
unless k == :signedData
|
53
|
+
raise Sidetree::Error,
|
54
|
+
"Unexpected property #{k.to_s} in provisional proof file"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
Sidetree::Util::JWS.parse(update[:signedData])
|
58
|
+
end
|
59
|
+
if update_proofs.empty?
|
60
|
+
raise Sidetree::Error, "Provisional proof file has no proof"
|
61
|
+
end
|
62
|
+
ProvisionalProofFile.new(update_proofs)
|
63
|
+
rescue JSON::ParserError
|
64
|
+
raise Sidetree::Error, "Provisional proof file is not json"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Build json string to be stored in CAS.
|
69
|
+
# @return [String] json string.
|
70
|
+
def to_json
|
71
|
+
params = {
|
72
|
+
operations: {
|
73
|
+
update: update_proofs.map { |u| { signedData: u.to_s } }
|
74
|
+
}
|
75
|
+
}
|
76
|
+
params.to_json
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/sidetree/model.rb
CHANGED
@@ -4,9 +4,12 @@ module Sidetree
|
|
4
4
|
autoload :Delta, "sidetree/model/delta"
|
5
5
|
autoload :Document, "sidetree/model/document"
|
6
6
|
autoload :Service, "sidetree/model/service"
|
7
|
+
autoload :CASFileBase, "sidetree/model/cas_file_base"
|
7
8
|
autoload :CoreIndexFile, "sidetree/model/core_index_file"
|
8
9
|
autoload :ChunkFile, "sidetree/model/chunk_file"
|
9
10
|
autoload :Chunk, "sidetree/model/chunk"
|
10
11
|
autoload :ProvisionalIndexFile, "sidetree/model/provisional_index_file"
|
12
|
+
autoload :ProvisionalProofFile, "sidetree/model/provisional_proof_file"
|
13
|
+
autoload :CoreProofFile, "sidetree/model/core_proof_file"
|
11
14
|
end
|
12
15
|
end
|
@@ -44,11 +44,14 @@ module Sidetree
|
|
44
44
|
when :revealValue
|
45
45
|
revealed_value = v
|
46
46
|
when :signedData
|
47
|
-
jws =
|
47
|
+
jws = Sidetree::Util::JWS.parse(v)
|
48
48
|
unless jws.keys.length == 2
|
49
49
|
raise Sidetree::Error,
|
50
50
|
"Deactivate operation signed data missing or unknown property"
|
51
51
|
end
|
52
|
+
Sidetree::Util::JWK.validate!(
|
53
|
+
Sidetree::Util::JWK.parse(jws["recoveryKey"])
|
54
|
+
)
|
52
55
|
else
|
53
56
|
raise Sidetree::Error,
|
54
57
|
"Unexpected property #{k.to_s} in deactivate operation"
|
@@ -11,6 +11,7 @@ module Sidetree
|
|
11
11
|
# @param [Sidetree::Model::Delta] delta
|
12
12
|
# @param [JSON::JWS] signed_data
|
13
13
|
# @param [String] revealed_value
|
14
|
+
# @raise [Sidetree::Error]
|
14
15
|
def initialize(did_suffix, delta, signed_data, revealed_value)
|
15
16
|
Sidetree::Validator.validate_encoded_multi_hash!(
|
16
17
|
did_suffix,
|
@@ -20,6 +21,13 @@ module Sidetree
|
|
20
21
|
revealed_value,
|
21
22
|
"#{type} revealValue"
|
22
23
|
)
|
24
|
+
if signed_data
|
25
|
+
Validator.validate_canonicalize_object_hash!(
|
26
|
+
signed_data[key_name],
|
27
|
+
revealed_value,
|
28
|
+
type
|
29
|
+
)
|
30
|
+
end
|
23
31
|
@did_suffix = did_suffix
|
24
32
|
@delta = delta
|
25
33
|
@signed_data = signed_data
|
@@ -42,12 +50,23 @@ module Sidetree
|
|
42
50
|
when :revealValue
|
43
51
|
revealed_value = v
|
44
52
|
when :signedData
|
45
|
-
jws =
|
53
|
+
jws = Sidetree::Util::JWS.parse(v)
|
46
54
|
unless jws.keys.length ==
|
47
55
|
(type == Sidetree::OP::Type::RECOVER ? 3 : 2)
|
48
56
|
raise Sidetree::Error,
|
49
57
|
"#{type.capitalize} operation signed data missing or unknown property"
|
50
58
|
end
|
59
|
+
key_name =
|
60
|
+
(
|
61
|
+
if type == Sidetree::OP::Type::RECOVER
|
62
|
+
"recoveryKey"
|
63
|
+
else
|
64
|
+
"updateKey"
|
65
|
+
end
|
66
|
+
)
|
67
|
+
Sidetree::Util::JWK.validate!(
|
68
|
+
Sidetree::Util::JWK.parse(jws[key_name])
|
69
|
+
)
|
51
70
|
when :delta
|
52
71
|
delta = Sidetree::Model::Delta.from_object(v)
|
53
72
|
else
|
@@ -55,15 +74,6 @@ module Sidetree
|
|
55
74
|
"Unexpected property #{k.to_s} in #{type} operation"
|
56
75
|
end
|
57
76
|
end
|
58
|
-
if jws
|
59
|
-
key =
|
60
|
-
type == Sidetree::OP::Type::UPDATE ? "updateKey" : "recoveryKey"
|
61
|
-
Validator.validate_canonicalize_object_hash!(
|
62
|
-
jws[key],
|
63
|
-
revealed_value,
|
64
|
-
"#{type.capitalize} key"
|
65
|
-
)
|
66
|
-
end
|
67
77
|
unless did_suffix
|
68
78
|
raise Sidetree::Error, "The #{type} didSuffix must be a string"
|
69
79
|
end
|
@@ -79,6 +89,10 @@ module Sidetree
|
|
79
89
|
raise Sidetree::Error, "Invalid signedData"
|
80
90
|
end
|
81
91
|
end
|
92
|
+
|
93
|
+
def key_name
|
94
|
+
type == Sidetree::OP::Type::UPDATE ? "updateKey" : "recoveryKey"
|
95
|
+
end
|
82
96
|
end
|
83
97
|
end
|
84
98
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Sidetree
|
2
|
+
module Util
|
3
|
+
module JWK
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# Parse jwk hash object.
|
7
|
+
# The returned jwk does not include the kid.
|
8
|
+
# @param [Hash] params
|
9
|
+
# @return [JSON::JWK]
|
10
|
+
def parse(params)
|
11
|
+
jwk = JSON::JWK.new(params)
|
12
|
+
jwk.delete("kid")
|
13
|
+
jwk
|
14
|
+
end
|
15
|
+
|
16
|
+
# Validate jwk object as sidetree jwk.
|
17
|
+
# @param [JSON::JWK] jwk
|
18
|
+
# @raise [Sidetree::Error]
|
19
|
+
def validate!(jwk)
|
20
|
+
raise Sidetree::Error unless jwk.is_a?(JSON::JWK)
|
21
|
+
jwk.keys.each do |k|
|
22
|
+
unless %w[kty crv x y].include?(k)
|
23
|
+
raise Sidetree::Error, "JWK Es256k has unknown property"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
unless jwk[:kty] == "EC"
|
27
|
+
raise Sidetree::Error, "JWK Es256k missing or invalid kty"
|
28
|
+
end
|
29
|
+
unless jwk[:crv] == "secp256k1"
|
30
|
+
raise Sidetree::Error, "JWK Es256k missing or invalid crv"
|
31
|
+
end
|
32
|
+
unless jwk[:x].is_a?(String)
|
33
|
+
raise Sidetree::Error, "JWK Es256k missing or invalid type x"
|
34
|
+
end
|
35
|
+
unless jwk[:y].is_a?(String)
|
36
|
+
raise Sidetree::Error, "JWK Es256k missing or invalid type y"
|
37
|
+
end
|
38
|
+
unless jwk[:x].length == 43
|
39
|
+
raise Sidetree::Error, "JWK Es256k has incorrect length of x"
|
40
|
+
end
|
41
|
+
unless jwk[:y].length == 43
|
42
|
+
raise Sidetree::Error, "JWK Es256k has incorrect length of y"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Sidetree
|
2
|
+
module Util
|
3
|
+
module JWS
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# Sign to +claim+ by +private_key+.
|
7
|
+
# @param [Hash] claim
|
8
|
+
# @param [Sidetree::Key] private_key Private key used by sign.
|
9
|
+
# @return [JSON::JWS]
|
10
|
+
def sign(claim, private_key)
|
11
|
+
jwt = JSON::JWT.new(claim)
|
12
|
+
jwt.header.delete(:typ)
|
13
|
+
jwt.sign(private_key.jws_sign_key, :ES256K)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Parse +jws_string+ to JSON::JWS
|
17
|
+
# @param [String] jws_string JWS data string.
|
18
|
+
# @return [JSON::JWS]
|
19
|
+
# @raise [Sidetree::Error]
|
20
|
+
def parse(jws_string)
|
21
|
+
jws =
|
22
|
+
JSON::JWS.decode_compact_serialized(jws_string, :skip_verification)
|
23
|
+
validate!(jws)
|
24
|
+
jws
|
25
|
+
end
|
26
|
+
|
27
|
+
# Check whether valid +jws+ or not as sidetree jws.
|
28
|
+
# @param [JSON::JWS] jws
|
29
|
+
# @return [Boolean]
|
30
|
+
def valid?(jws)
|
31
|
+
begin
|
32
|
+
validate!(jws)
|
33
|
+
true
|
34
|
+
rescue Sidetree::Error
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Validate +jws+ as sidetree jws.
|
40
|
+
# @param [JSON::JWS] jws
|
41
|
+
# @raise [Sidetree::Error]
|
42
|
+
def validate!(jws)
|
43
|
+
unless jws.header.length == 1
|
44
|
+
raise Sidetree::Error, "jws header missing or unknown property"
|
45
|
+
end
|
46
|
+
unless jws.header[:alg] == "ES256K"
|
47
|
+
raise Sidetree::Error, "jws header missing or incorrect alg"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/sidetree/util.rb
CHANGED
data/lib/sidetree/version.rb
CHANGED
data/lib/sidetree.rb
CHANGED
@@ -32,6 +32,8 @@ module Sidetree
|
|
32
32
|
MAX_CHUNK_FILE_SIZE = 10_000_000
|
33
33
|
# Maximum compressed Provisional Index File size. 1 MB (zipped)
|
34
34
|
MAX_PROVISIONAL_INDEX_FILE_SIZE = 1_000_000
|
35
|
+
# Maximum compressed Proof File size. 2.5 MB (zipped)
|
36
|
+
MAX_PROOF_FILE_SIZE = 2_500_000
|
35
37
|
# Maximum compressed Core Index File size. 1 MB (zipped)
|
36
38
|
MAX_CORE_INDEX_FILE_SIZE = 1_000_000
|
37
39
|
# Maximum writer lock ID size
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidetree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- azuchi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-08-
|
11
|
+
date: 2022-08-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ecdsa
|
@@ -136,12 +136,15 @@ files:
|
|
136
136
|
- lib/sidetree/did.rb
|
137
137
|
- lib/sidetree/key.rb
|
138
138
|
- lib/sidetree/model.rb
|
139
|
+
- lib/sidetree/model/cas_file_base.rb
|
139
140
|
- lib/sidetree/model/chunk.rb
|
140
141
|
- lib/sidetree/model/chunk_file.rb
|
141
142
|
- lib/sidetree/model/core_index_file.rb
|
143
|
+
- lib/sidetree/model/core_proof_file.rb
|
142
144
|
- lib/sidetree/model/delta.rb
|
143
145
|
- lib/sidetree/model/document.rb
|
144
146
|
- lib/sidetree/model/provisional_index_file.rb
|
147
|
+
- lib/sidetree/model/provisional_proof_file.rb
|
145
148
|
- lib/sidetree/model/service.rb
|
146
149
|
- lib/sidetree/model/suffix.rb
|
147
150
|
- lib/sidetree/op.rb
|
@@ -154,6 +157,8 @@ files:
|
|
154
157
|
- lib/sidetree/util.rb
|
155
158
|
- lib/sidetree/util/anchored_data_serializer.rb
|
156
159
|
- lib/sidetree/util/compressor.rb
|
160
|
+
- lib/sidetree/util/jwk.rb
|
161
|
+
- lib/sidetree/util/jws.rb
|
157
162
|
- lib/sidetree/validator.rb
|
158
163
|
- lib/sidetree/version.rb
|
159
164
|
- sidetree.gemspec
|