sidetree 0.1.0 → 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/.github/workflows/main.yml +1 -1
- data/lib/sidetree/cas/fetch_result.rb +20 -0
- data/lib/sidetree/cas/ipfs.rb +101 -0
- data/lib/sidetree/cas.rb +6 -0
- data/lib/sidetree/did.rb +12 -14
- data/lib/sidetree/key.rb +53 -35
- data/lib/sidetree/model/cas_file_base.rb +40 -0
- data/lib/sidetree/model/chunk.rb +21 -0
- data/lib/sidetree/model/chunk_file.rb +72 -0
- data/lib/sidetree/model/core_index_file.rb +197 -0
- data/lib/sidetree/model/core_proof_file.rb +102 -0
- data/lib/sidetree/model/delta.rb +10 -1
- data/lib/sidetree/model/document.rb +10 -4
- data/lib/sidetree/model/provisional_index_file.rb +129 -0
- data/lib/sidetree/model/provisional_proof_file.rb +80 -0
- data/lib/sidetree/model/service.rb +6 -6
- data/lib/sidetree/model/suffix.rb +2 -2
- data/lib/sidetree/model.rb +11 -4
- data/lib/sidetree/op/create.rb +56 -5
- data/lib/sidetree/op/deactivate.rb +82 -0
- data/lib/sidetree/op/recover.rb +19 -0
- data/lib/sidetree/op/updatable.rb +98 -0
- data/lib/sidetree/op/update.rb +19 -0
- data/lib/sidetree/op.rb +20 -16
- data/lib/sidetree/util/anchored_data_serializer.rb +41 -0
- data/lib/sidetree/util/compressor.rb +38 -0
- data/lib/sidetree/util/jwk.rb +47 -0
- data/lib/sidetree/util/jws.rb +52 -0
- data/lib/sidetree/util.rb +8 -0
- data/lib/sidetree/validator.rb +51 -29
- data/lib/sidetree/version.rb +1 -1
- data/lib/sidetree.rb +36 -19
- data/sidetree.gemspec +3 -3
- metadata +37 -20
- data/exe/ion +0 -34
data/lib/sidetree/op/create.rb
CHANGED
@@ -11,6 +11,57 @@ module Sidetree
|
|
11
11
|
@suffix = suffix
|
12
12
|
end
|
13
13
|
|
14
|
+
# Generate create operation with new generate key.
|
15
|
+
# @param [String] method DID method defined in +Sidetree::Params::METHODS+.
|
16
|
+
# @return [Sidetree::OP::Create]
|
17
|
+
def self.generate(method: Sidetree::Params::METHODS[:ion])
|
18
|
+
recovery_key = Sidetree::Key.generate
|
19
|
+
update_key = Sidetree::Key.generate
|
20
|
+
signing_key = Sidetree::Key.generate(id: "signing-key")
|
21
|
+
document = Sidetree::Model::Document.new(public_keys: [signing_key])
|
22
|
+
did =
|
23
|
+
Sidetree::DID.create(
|
24
|
+
document,
|
25
|
+
update_key,
|
26
|
+
recovery_key,
|
27
|
+
method: method
|
28
|
+
)
|
29
|
+
did.create_op
|
30
|
+
end
|
31
|
+
|
32
|
+
# Parse create operation data from json string
|
33
|
+
# @param [String] create_data create operation data(json string).
|
34
|
+
# @return [Sidetree::OP::Create]
|
35
|
+
# @raise [Sidetree::Error]
|
36
|
+
def self.from_json(create_data)
|
37
|
+
begin
|
38
|
+
json = JSON.parse(create_data, symbolize_names: true)
|
39
|
+
json.each do |k, v|
|
40
|
+
case k
|
41
|
+
when :type, :suffixData, :delta
|
42
|
+
else
|
43
|
+
raise Sidetree::Error,
|
44
|
+
"Create operation missing or unknown property"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
if json[:type] && json[:type] != Sidetree::OP::Type::CREATE
|
48
|
+
raise Sidetree::Error, "Create operation type incorrect"
|
49
|
+
end
|
50
|
+
suffix = Sidetree::Model::Suffix.from_object(json[:suffixData])
|
51
|
+
delta = nil
|
52
|
+
begin
|
53
|
+
# For compatibility with data pruning
|
54
|
+
delta = Sidetree::Model::Delta.from_object(json[:delta]) if json[
|
55
|
+
:delta
|
56
|
+
]
|
57
|
+
rescue Sidetree::Error
|
58
|
+
end
|
59
|
+
Create.new(suffix, delta)
|
60
|
+
rescue JSON::ParserError
|
61
|
+
raise Sidetree::Error, "create_data not json"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
14
65
|
def type
|
15
66
|
Sidetree::OP::Type::CREATE
|
16
67
|
end
|
@@ -31,20 +82,20 @@ module Sidetree
|
|
31
82
|
expected_base64 =
|
32
83
|
Base64.urlsafe_encode64(json.to_json_c14n, padding: false)
|
33
84
|
unless expected_base64 == base64_str
|
34
|
-
raise Error,
|
85
|
+
raise Error, "Initial state object and JCS string mismatch."
|
35
86
|
end
|
36
87
|
|
37
88
|
Create.new(
|
38
|
-
Sidetree::Model::Suffix.
|
39
|
-
Sidetree::Model::Delta.
|
89
|
+
Sidetree::Model::Suffix.from_object(json[:suffixData]),
|
90
|
+
Sidetree::Model::Delta.from_object(json[:delta])
|
40
91
|
)
|
41
92
|
rescue JSON::ParserError
|
42
|
-
raise Error,
|
93
|
+
raise Error, "Long form initial state should be encoded jcs."
|
43
94
|
end
|
44
95
|
end
|
45
96
|
|
46
97
|
def to_h
|
47
|
-
{ suffixData: suffix.to_h, delta: delta
|
98
|
+
{ suffixData: suffix.to_h, delta: delta&.to_h }
|
48
99
|
end
|
49
100
|
|
50
101
|
# Generate long_suffix for DID.
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Sidetree
|
2
|
+
module OP
|
3
|
+
# Deactivate operation class
|
4
|
+
# https://identity.foundation/sidetree/spec/#deactivate
|
5
|
+
class Deactivate < Base
|
6
|
+
attr_reader :did_suffix
|
7
|
+
attr_reader :signed_data
|
8
|
+
attr_reader :revealed_value
|
9
|
+
|
10
|
+
# Initialize
|
11
|
+
# @param [String] did_suffix
|
12
|
+
# @param [JSON::JWS] signed_data
|
13
|
+
# @param [String] revealed_value
|
14
|
+
def initialize(did_suffix, signed_data, revealed_value)
|
15
|
+
Sidetree::Validator.validate_encoded_multi_hash!(
|
16
|
+
did_suffix,
|
17
|
+
"#{type} didSuffix"
|
18
|
+
)
|
19
|
+
Sidetree::Validator.validate_encoded_multi_hash!(
|
20
|
+
revealed_value,
|
21
|
+
"#{type} revealValue"
|
22
|
+
)
|
23
|
+
@did_suffix = did_suffix
|
24
|
+
@signed_data = signed_data
|
25
|
+
@revealed_value = revealed_value
|
26
|
+
end
|
27
|
+
|
28
|
+
# Parse Deactivate operation data from json string
|
29
|
+
# @param [String] deactivate_data deactivate operation data(json string).
|
30
|
+
# @return [Sidetree::OP::Deactivate]
|
31
|
+
# @raise [Sidetree::Error]
|
32
|
+
def self.from_json(deactivate_data)
|
33
|
+
begin
|
34
|
+
json = JSON.parse(deactivate_data, symbolize_names: true)
|
35
|
+
jws, revealed_value, did_suffix = nil, nil, nil
|
36
|
+
json.each do |k, v|
|
37
|
+
case k
|
38
|
+
when :type
|
39
|
+
unless v == Sidetree::OP::Type::DEACTIVATE
|
40
|
+
raise Sidetree::Error, "Deactivate operation type incorrect"
|
41
|
+
end
|
42
|
+
when :didSuffix
|
43
|
+
did_suffix = v
|
44
|
+
when :revealValue
|
45
|
+
revealed_value = v
|
46
|
+
when :signedData
|
47
|
+
jws = Sidetree::Util::JWS.parse(v)
|
48
|
+
unless jws.keys.length == 2
|
49
|
+
raise Sidetree::Error,
|
50
|
+
"Deactivate operation signed data missing or unknown property"
|
51
|
+
end
|
52
|
+
Sidetree::Util::JWK.validate!(
|
53
|
+
Sidetree::Util::JWK.parse(jws["recoveryKey"])
|
54
|
+
)
|
55
|
+
else
|
56
|
+
raise Sidetree::Error,
|
57
|
+
"Unexpected property #{k.to_s} in deactivate operation"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
if jws
|
61
|
+
Validator.validate_canonicalize_object_hash!(
|
62
|
+
jws["recoveryKey"],
|
63
|
+
revealed_value,
|
64
|
+
"Deactivate key"
|
65
|
+
)
|
66
|
+
end
|
67
|
+
unless did_suffix
|
68
|
+
raise Sidetree::Error, "The deactivate didSuffix must be a string"
|
69
|
+
end
|
70
|
+
Deactivate.new(did_suffix, jws, revealed_value)
|
71
|
+
rescue JSON::ParserError
|
72
|
+
raise Sidetree::Error, "deactivate_data not json"
|
73
|
+
rescue JSON::JWS::InvalidFormat
|
74
|
+
raise Sidetree::Error, "Invalid signedData"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
def type
|
78
|
+
Sidetree::OP::Type::DEACTIVATE
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Sidetree
|
2
|
+
module OP
|
3
|
+
# Recover operation class.
|
4
|
+
# https://identity.foundation/sidetree/spec/#recover
|
5
|
+
class Recover < Updatable
|
6
|
+
# Parse Recover operation data from json string
|
7
|
+
# @param [String] recover_data recover operation data(json string).
|
8
|
+
# @return [Sidetree::OP::Recover]
|
9
|
+
# @raise [Sidetree::Error]
|
10
|
+
def self.from_json(recover_data)
|
11
|
+
parse_json(recover_data, Sidetree::OP::Type::RECOVER)
|
12
|
+
end
|
13
|
+
|
14
|
+
def type
|
15
|
+
Sidetree::OP::Type::RECOVER
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module Sidetree
|
2
|
+
module OP
|
3
|
+
class Updatable < Base
|
4
|
+
attr_reader :did_suffix
|
5
|
+
attr_reader :delta
|
6
|
+
attr_reader :signed_data
|
7
|
+
attr_reader :revealed_value
|
8
|
+
|
9
|
+
# Initialize
|
10
|
+
# @param [String] did_suffix
|
11
|
+
# @param [Sidetree::Model::Delta] delta
|
12
|
+
# @param [JSON::JWS] signed_data
|
13
|
+
# @param [String] revealed_value
|
14
|
+
# @raise [Sidetree::Error]
|
15
|
+
def initialize(did_suffix, delta, signed_data, revealed_value)
|
16
|
+
Sidetree::Validator.validate_encoded_multi_hash!(
|
17
|
+
did_suffix,
|
18
|
+
"#{type} didSuffix"
|
19
|
+
)
|
20
|
+
Sidetree::Validator.validate_encoded_multi_hash!(
|
21
|
+
revealed_value,
|
22
|
+
"#{type} revealValue"
|
23
|
+
)
|
24
|
+
if signed_data
|
25
|
+
Validator.validate_canonicalize_object_hash!(
|
26
|
+
signed_data[key_name],
|
27
|
+
revealed_value,
|
28
|
+
type
|
29
|
+
)
|
30
|
+
end
|
31
|
+
@did_suffix = did_suffix
|
32
|
+
@delta = delta
|
33
|
+
@signed_data = signed_data
|
34
|
+
@revealed_value = revealed_value
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.parse_json(data, type)
|
38
|
+
begin
|
39
|
+
json = JSON.parse(data, symbolize_names: true)
|
40
|
+
delta, jws, revealed_value, did_suffix = nil, nil, nil, nil
|
41
|
+
json.each do |k, v|
|
42
|
+
case k
|
43
|
+
when :type
|
44
|
+
unless v == type
|
45
|
+
raise Sidetree::Error,
|
46
|
+
"#{type.capitalize} operation type incorrect"
|
47
|
+
end
|
48
|
+
when :didSuffix
|
49
|
+
did_suffix = v
|
50
|
+
when :revealValue
|
51
|
+
revealed_value = v
|
52
|
+
when :signedData
|
53
|
+
jws = Sidetree::Util::JWS.parse(v)
|
54
|
+
unless jws.keys.length ==
|
55
|
+
(type == Sidetree::OP::Type::RECOVER ? 3 : 2)
|
56
|
+
raise Sidetree::Error,
|
57
|
+
"#{type.capitalize} operation signed data missing or unknown property"
|
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
|
+
)
|
70
|
+
when :delta
|
71
|
+
delta = Sidetree::Model::Delta.from_object(v)
|
72
|
+
else
|
73
|
+
raise Sidetree::Error,
|
74
|
+
"Unexpected property #{k.to_s} in #{type} operation"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
unless did_suffix
|
78
|
+
raise Sidetree::Error, "The #{type} didSuffix must be a string"
|
79
|
+
end
|
80
|
+
Module.const_get("Sidetree::OP::#{type.capitalize}").new(
|
81
|
+
did_suffix,
|
82
|
+
delta,
|
83
|
+
jws,
|
84
|
+
revealed_value
|
85
|
+
)
|
86
|
+
rescue JSON::ParserError
|
87
|
+
raise Sidetree::Error, "data dose not json"
|
88
|
+
rescue JSON::JWS::InvalidFormat
|
89
|
+
raise Sidetree::Error, "Invalid signedData"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def key_name
|
94
|
+
type == Sidetree::OP::Type::UPDATE ? "updateKey" : "recoveryKey"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Sidetree
|
2
|
+
module OP
|
3
|
+
# Update operation class.
|
4
|
+
# https://identity.foundation/sidetree/spec/#update
|
5
|
+
class Update < Updatable
|
6
|
+
# Parse update operation data from json string
|
7
|
+
# @param [String] update_data update operation data(json string).
|
8
|
+
# @return [Sidetree::OP::Update]
|
9
|
+
# @raise [Sidetree::Error]
|
10
|
+
def self.from_json(update_data)
|
11
|
+
parse_json(update_data, Sidetree::OP::Type::UPDATE)
|
12
|
+
end
|
13
|
+
|
14
|
+
def type
|
15
|
+
Sidetree::OP::Type::UPDATE
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/sidetree/op.rb
CHANGED
@@ -1,28 +1,28 @@
|
|
1
1
|
module Sidetree
|
2
2
|
module OP
|
3
3
|
module Type
|
4
|
-
CREATE =
|
5
|
-
UPDATE =
|
6
|
-
RECOVER =
|
7
|
-
DEACTIVATE =
|
4
|
+
CREATE = "create"
|
5
|
+
UPDATE = "update"
|
6
|
+
RECOVER = "recover"
|
7
|
+
DEACTIVATE = "deactivate"
|
8
8
|
end
|
9
9
|
|
10
10
|
# Sidetree patch actions. These are the valid values in the action property of a patch.
|
11
11
|
module PatchAction
|
12
|
-
REPLACE =
|
13
|
-
ADD_PUBLIC_KEYS =
|
14
|
-
REMOVE_PUBLIC_KEYS =
|
15
|
-
ADD_SERVICES =
|
16
|
-
REMOVE_SERVICES =
|
12
|
+
REPLACE = "replace"
|
13
|
+
ADD_PUBLIC_KEYS = "add-public-keys"
|
14
|
+
REMOVE_PUBLIC_KEYS = "remove-public-keys"
|
15
|
+
ADD_SERVICES = "add-services"
|
16
|
+
REMOVE_SERVICES = "remove-services"
|
17
17
|
end
|
18
18
|
|
19
19
|
# DID Document public key purpose.
|
20
20
|
module PublicKeyPurpose
|
21
|
-
AUTHENTICATION =
|
22
|
-
ASSERTION_METHOD =
|
23
|
-
CAPABILITY_INVOCATION =
|
24
|
-
CAPABILITY_DELEGATION =
|
25
|
-
KEY_AGREEMENT =
|
21
|
+
AUTHENTICATION = "authentication"
|
22
|
+
ASSERTION_METHOD = "assertionMethod"
|
23
|
+
CAPABILITY_INVOCATION = "capabilityInvocation"
|
24
|
+
CAPABILITY_DELEGATION = "capabilityDelegation"
|
25
|
+
KEY_AGREEMENT = "keyAgreement"
|
26
26
|
|
27
27
|
module_function
|
28
28
|
|
@@ -31,7 +31,11 @@ module Sidetree
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
autoload :Base,
|
35
|
-
autoload :
|
34
|
+
autoload :Base, "sidetree/op/base"
|
35
|
+
autoload :Updatable, "sidetree/op/updatable"
|
36
|
+
autoload :Create, "sidetree/op/create"
|
37
|
+
autoload :Recover, "sidetree/op/recover"
|
38
|
+
autoload :Update, "sidetree/op/update"
|
39
|
+
autoload :Deactivate, "sidetree/op/deactivate"
|
36
40
|
end
|
37
41
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Sidetree
|
2
|
+
module Util
|
3
|
+
module AnchoredDataSerializer
|
4
|
+
DELIMITER = "."
|
5
|
+
|
6
|
+
module_function
|
7
|
+
|
8
|
+
# Serialize given data as Anchor String.
|
9
|
+
# @param [Integer] op_count Number of operations
|
10
|
+
# @param [String] uri Core Index File uri.
|
11
|
+
# @return [String] Anchor String
|
12
|
+
# @raise [Sidetree::Error]
|
13
|
+
def serialize(op_count, uri)
|
14
|
+
if op_count > Sidetree::Params::MAX_OPERATION_COUNT
|
15
|
+
raise Sidetree::Error, "Number of operations greater than max"
|
16
|
+
end
|
17
|
+
"#{op_count}#{DELIMITER}#{uri}"
|
18
|
+
end
|
19
|
+
|
20
|
+
# Deserializes the given string that is read from the blockchain into data.
|
21
|
+
# @param [String] anchor_str Anchor String
|
22
|
+
# @return [Array[Integer, String]]
|
23
|
+
# @raise [Sidetree::Error]
|
24
|
+
def deserialize(anchor_str)
|
25
|
+
data = anchor_str.split(DELIMITER)
|
26
|
+
raise Sidetree::Error, "Invalid anchor string" unless data.length == 2
|
27
|
+
unless data[0] =~ /^[1-9]\d*$/
|
28
|
+
raise Sidetree::Error,
|
29
|
+
"Number of operations in anchor string is not positive number"
|
30
|
+
end
|
31
|
+
|
32
|
+
count = data[0].to_i
|
33
|
+
if count > Sidetree::Params::MAX_OPERATION_COUNT
|
34
|
+
raise Sidetree::Error,
|
35
|
+
"Number of operations in anchor string greater than max"
|
36
|
+
end
|
37
|
+
[count, data[1]]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "zlib"
|
2
|
+
|
3
|
+
module Sidetree
|
4
|
+
module Util
|
5
|
+
module Compressor
|
6
|
+
# The estimated ratio/multiplier of decompressed Sidetree CAS file size compared against the compressed file size.
|
7
|
+
ESTIMATE_DECOMPRESSION_MULTIPLIER = 3
|
8
|
+
|
9
|
+
module_function
|
10
|
+
|
11
|
+
# Compresses teh data in gzip and return it as buffer.
|
12
|
+
# @param [String] data Data to be compressed.
|
13
|
+
# @return [String] compressed data.
|
14
|
+
def compress(data)
|
15
|
+
io = StringIO.new("w")
|
16
|
+
Zlib::GzipWriter.wrap(io) do |w|
|
17
|
+
w.mtime = 0
|
18
|
+
w.write data
|
19
|
+
end
|
20
|
+
io.string.force_encoding("binary")
|
21
|
+
end
|
22
|
+
|
23
|
+
# Decompresses +compressed+.
|
24
|
+
# @param [String] compressed compressed data.
|
25
|
+
# @return [String] decompressed data.
|
26
|
+
# @raise [Sidetree::Error] raise if data exceeds max_bytes size.
|
27
|
+
def decompress(compressed, max_bytes: nil)
|
28
|
+
if max_bytes && compressed.bytesize > max_bytes
|
29
|
+
raise Sidetree::Error, "Exceed maximum compressed chunk file size."
|
30
|
+
end
|
31
|
+
io = StringIO.new(compressed)
|
32
|
+
result = StringIO.new
|
33
|
+
Zlib::GzipReader.wrap(io) { |gz| result << gz.read }
|
34
|
+
result.string
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
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
|