acme-client 2.0.2 → 2.0.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/.gitignore +1 -0
- data/.rubocop.yml +51 -56
- data/.travis.yml +7 -4
- data/CHANGELOG.md +22 -1
- data/Gemfile +1 -0
- data/README.md +6 -3
- data/acme-client.gemspec +10 -6
- data/bin/release +1 -0
- data/lib/acme/client.rb +54 -18
- data/lib/acme/client/chain_identifier.rb +27 -0
- data/lib/acme/client/error.rb +1 -0
- data/lib/acme/client/faraday_middleware.rb +5 -10
- data/lib/acme/client/jwk/base.rb +2 -2
- data/lib/acme/client/resources/account.rb +1 -1
- data/lib/acme/client/resources/authorization.rb +1 -1
- data/lib/acme/client/resources/challenges.rb +2 -6
- data/lib/acme/client/resources/challenges/base.rb +9 -11
- data/lib/acme/client/resources/challenges/unsupported_challenge.rb +2 -0
- data/lib/acme/client/resources/order.rb +3 -3
- data/lib/acme/client/util.rb +11 -0
- data/lib/acme/client/version.rb +1 -1
- metadata +21 -43
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 718dac85c8139621711a030272097498d04414ca52c9d84544b8bac32179e8a1
|
4
|
+
data.tar.gz: 9e929450733261f291a62b96f5056ed89e8c235cae010805ddccfc3efb17188c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6e77c41a67b3f2fe9d6e373d58e928bfc0ee2523ac7b0ce2beb93167179a0950045cbb0ec4f5d8616527108814001acd0da7909a8bb0df8dac9b6ddde8bfbba
|
7
|
+
data.tar.gz: 9eba181b543cfe437e2043970b2e74cd691944457d43d3c3ea052cf10d3134e59b51aa8ee3522c36f27b25c212797e44e0e29b86f96b13361e98ca07d054ccac
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -7,133 +7,128 @@ AllCops:
|
|
7
7
|
Rails:
|
8
8
|
Enabled: false
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
- 'lib/acme-client.rb'
|
10
|
+
Layout/AlignParameters:
|
11
|
+
EnforcedStyle: with_fixed_indentation
|
13
12
|
|
14
|
-
|
13
|
+
Layout/ElseAlignment:
|
15
14
|
Enabled: false
|
16
15
|
|
17
|
-
|
18
|
-
|
16
|
+
Layout/FirstParameterIndentation:
|
17
|
+
EnforcedStyle: consistent
|
19
18
|
|
20
|
-
|
19
|
+
Layout/IndentationWidth:
|
21
20
|
Enabled: false
|
22
21
|
|
23
22
|
Layout/MultilineOperationIndentation:
|
24
23
|
Enabled: false
|
25
24
|
|
26
|
-
|
27
|
-
EnforcedStyle: only_raise
|
28
|
-
|
29
|
-
Layout/AlignParameters:
|
30
|
-
EnforcedStyle: with_fixed_indentation
|
31
|
-
|
32
|
-
Layout/ElseAlignment:
|
25
|
+
Layout/SpaceInsideBlockBraces:
|
33
26
|
Enabled: false
|
34
27
|
|
35
|
-
|
28
|
+
Lint/AmbiguousOperator:
|
36
29
|
Enabled: false
|
37
30
|
|
38
|
-
|
31
|
+
Lint/AssignmentInCondition:
|
39
32
|
Enabled: false
|
40
33
|
|
41
|
-
|
34
|
+
Lint/EndAlignment:
|
42
35
|
Enabled: false
|
43
36
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
Style/TrailingCommaInArguments:
|
48
|
-
Enabled: false
|
37
|
+
Lint/UnusedMethodArgument:
|
38
|
+
AllowUnusedKeywordArguments: true
|
49
39
|
|
50
|
-
|
40
|
+
Metrics/AbcSize:
|
51
41
|
Enabled: false
|
52
42
|
|
53
43
|
Metrics/BlockLength:
|
54
44
|
Enabled: false
|
55
45
|
|
56
|
-
|
46
|
+
Metrics/ClassLength:
|
57
47
|
Enabled: false
|
58
48
|
|
59
|
-
|
60
|
-
Enabled:
|
49
|
+
Metrics/CyclomaticComplexity:
|
50
|
+
Enabled: false
|
61
51
|
|
62
52
|
Metrics/LineLength:
|
63
53
|
Max: 140
|
64
54
|
|
55
|
+
Metrics/MethodLength:
|
56
|
+
Max: 15
|
57
|
+
Enabled: false
|
58
|
+
|
65
59
|
Metrics/ParameterLists:
|
66
60
|
Max: 5
|
67
61
|
CountKeywordArgs: false
|
68
62
|
|
69
|
-
|
63
|
+
Metrics/PerceivedComplexity:
|
70
64
|
Enabled: false
|
71
65
|
|
72
|
-
|
66
|
+
Security/JSONLoad:
|
73
67
|
Enabled: false
|
74
68
|
|
75
|
-
Style/
|
69
|
+
Style/AccessorMethodName:
|
76
70
|
Enabled: false
|
77
71
|
|
78
|
-
Style/
|
79
|
-
|
80
|
-
|
81
|
-
Lint/UnusedMethodArgument:
|
82
|
-
AllowUnusedKeywordArguments: true
|
72
|
+
Style/Alias:
|
73
|
+
Enabled: false
|
83
74
|
|
84
|
-
|
85
|
-
|
75
|
+
Style/BlockDelimiters:
|
76
|
+
EnforcedStyle: semantic
|
86
77
|
|
87
|
-
Style/
|
78
|
+
Style/ClassAndModuleChildren:
|
88
79
|
Enabled: false
|
89
80
|
|
90
|
-
Style/
|
81
|
+
Style/Documentation:
|
91
82
|
Enabled: false
|
92
83
|
|
93
|
-
Style/
|
84
|
+
Style/DoubleNegation:
|
94
85
|
Enabled: false
|
95
86
|
|
96
|
-
Style/
|
97
|
-
|
87
|
+
Style/FileName:
|
88
|
+
Exclude:
|
89
|
+
- 'lib/acme-client.rb'
|
98
90
|
|
99
|
-
Style/
|
91
|
+
Style/GlobalVars:
|
100
92
|
Enabled: false
|
101
93
|
|
102
94
|
Style/GuardClause:
|
103
95
|
Enabled: false
|
104
96
|
|
105
|
-
Style/
|
97
|
+
Style/IfUnlessModifier:
|
106
98
|
Enabled: false
|
107
99
|
|
108
|
-
|
100
|
+
Style/Lambda:
|
109
101
|
Enabled: false
|
110
102
|
|
111
|
-
|
103
|
+
Style/ModuleFunction:
|
112
104
|
Enabled: false
|
113
105
|
|
114
|
-
|
106
|
+
Style/MultilineBlockChain:
|
115
107
|
Enabled: false
|
116
108
|
|
117
|
-
|
109
|
+
Style/MultipleComparison:
|
118
110
|
Enabled: false
|
119
111
|
|
120
|
-
|
112
|
+
Style/MutableConstant:
|
121
113
|
Enabled: false
|
122
114
|
|
123
|
-
|
115
|
+
Style/ParallelAssignment:
|
124
116
|
Enabled: false
|
125
117
|
|
126
|
-
Style/
|
118
|
+
Style/PercentLiteralDelimiters:
|
127
119
|
Enabled: false
|
128
120
|
|
129
|
-
Style/
|
130
|
-
|
121
|
+
Style/SignalException:
|
122
|
+
EnforcedStyle: only_raise
|
131
123
|
|
132
|
-
Style/
|
124
|
+
Style/SymbolArray:
|
133
125
|
Enabled: false
|
134
126
|
|
135
|
-
|
136
|
-
Enabled:
|
127
|
+
Style/StringLiterals:
|
128
|
+
Enabled: single_quotes
|
137
129
|
|
138
|
-
Style/
|
130
|
+
Style/TrailingCommaInArguments:
|
139
131
|
Enabled: false
|
132
|
+
|
133
|
+
Style/TrivialAccessors:
|
134
|
+
AllowPredicates: true
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,31 @@
|
|
1
|
+
## `2.0.7`
|
2
|
+
|
3
|
+
* Add support for alternate certificate chain
|
4
|
+
* Change `Link` headers parsing to return array of value. This add support multiple entries at the same `rel`
|
5
|
+
|
6
|
+
## `2.0.6`
|
7
|
+
|
8
|
+
* Allow Faraday up to `< 2.0`
|
9
|
+
|
10
|
+
## `2.0.5`
|
11
|
+
|
12
|
+
* Use post-as-get
|
13
|
+
* Remove deprecated keyAuthorization
|
14
|
+
|
15
|
+
## `2.0.4`
|
16
|
+
|
17
|
+
* Add an option to retry bad nonce errors
|
18
|
+
|
19
|
+
## `2.0.3`
|
20
|
+
|
21
|
+
* Do not try to set the body on GET request
|
22
|
+
|
1
23
|
## `2.0.2`
|
2
24
|
|
3
25
|
* Fix constant lookup on InvalidDirectory
|
4
26
|
* Forward connection options when fetching nonce
|
5
27
|
* Fix splats without parenthesis warning
|
6
28
|
|
7
|
-
|
8
29
|
## `2.0.1`
|
9
30
|
|
10
31
|
* Properly require URI
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[](https://travis-ci.org/unixcharles/acme-client)
|
4
4
|
|
5
|
-
`acme-client` is a client implementation of the [
|
5
|
+
`acme-client` is a client implementation of the ACMEv2 / [RFC 8555](https://tools.ietf.org/html/rfc8555) protocol in Ruby.
|
6
6
|
|
7
7
|
You can find the ACME reference implementations of the [server](https://github.com/letsencrypt/boulder) in Go and the [client](https://github.com/certbot/certbot) in Python.
|
8
8
|
|
@@ -182,7 +182,10 @@ Certificate generation happens asynchronously. You may need to poll.
|
|
182
182
|
```ruby
|
183
183
|
csr = Acme::Client::CertificateRequest.new(private_key: a_different_private_key, subject: { common_name: 'example.com' })
|
184
184
|
order.finalize(csr: csr)
|
185
|
-
|
185
|
+
while order.status == 'processing'
|
186
|
+
sleep(1)
|
187
|
+
order.reload
|
188
|
+
end
|
186
189
|
order.certificate # => PEM-formatted certificate
|
187
190
|
```
|
188
191
|
|
@@ -198,7 +201,7 @@ client.revoke(certificate: certificate)
|
|
198
201
|
|
199
202
|
### Certificate renewal
|
200
203
|
|
201
|
-
|
204
|
+
There is no renewal process, just create a new order.
|
202
205
|
|
203
206
|
|
204
207
|
## Not implemented
|
data/acme-client.gemspec
CHANGED
@@ -16,11 +16,15 @@ Gem::Specification.new do |spec|
|
|
16
16
|
|
17
17
|
spec.required_ruby_version = '>= 2.1.0'
|
18
18
|
|
19
|
-
spec.add_development_dependency 'bundler', '
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
spec.add_development_dependency 'bundler', '>= 1.17.3'
|
20
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2')
|
21
|
+
spec.add_development_dependency 'rake', '>= 12.0'
|
22
|
+
else
|
23
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
24
|
+
end
|
25
|
+
spec.add_development_dependency 'rspec', '~> 3.9'
|
26
|
+
spec.add_development_dependency 'vcr', '~> 2.9'
|
27
|
+
spec.add_development_dependency 'webmock', '~> 3.8'
|
24
28
|
|
25
|
-
spec.add_runtime_dependency 'faraday', '
|
29
|
+
spec.add_runtime_dependency 'faraday', '>= 0.17', '< 2.0.0'
|
26
30
|
end
|
data/bin/release
CHANGED
data/lib/acme/client.rb
CHANGED
@@ -20,6 +20,7 @@ require 'acme/client/faraday_middleware'
|
|
20
20
|
require 'acme/client/jwk'
|
21
21
|
require 'acme/client/error'
|
22
22
|
require 'acme/client/util'
|
23
|
+
require 'acme/client/chain_identifier'
|
23
24
|
|
24
25
|
class Acme::Client
|
25
26
|
DEFAULT_DIRECTORY = 'http://127.0.0.1:4000/directory'.freeze
|
@@ -29,7 +30,7 @@ class Acme::Client
|
|
29
30
|
pem: 'application/pem-certificate-chain'
|
30
31
|
}
|
31
32
|
|
32
|
-
def initialize(jwk: nil, kid: nil, private_key: nil, directory: DEFAULT_DIRECTORY, connection_options: {})
|
33
|
+
def initialize(jwk: nil, kid: nil, private_key: nil, directory: DEFAULT_DIRECTORY, connection_options: {}, bad_nonce_retry: 0)
|
33
34
|
if jwk.nil? && private_key.nil?
|
34
35
|
raise ArgumentError, 'must specify jwk or private_key'
|
35
36
|
end
|
@@ -41,6 +42,7 @@ class Acme::Client
|
|
41
42
|
end
|
42
43
|
|
43
44
|
@kid, @connection_options = kid, connection_options
|
45
|
+
@bad_nonce_retry = bad_nonce_retry
|
44
46
|
@directory = Acme::Client::Resources::Directory.new(URI(directory), @connection_options)
|
45
47
|
@nonces ||= []
|
46
48
|
end
|
@@ -89,7 +91,7 @@ class Acme::Client
|
|
89
91
|
response.headers.fetch(:location)
|
90
92
|
end
|
91
93
|
|
92
|
-
response =
|
94
|
+
response = post_as_get(@kid)
|
93
95
|
arguments = attributes_from_account_response(response)
|
94
96
|
Acme::Client::Resources::Account.new(self, url: @kid, **arguments)
|
95
97
|
end
|
@@ -100,13 +102,7 @@ class Acme::Client
|
|
100
102
|
|
101
103
|
def new_order(identifiers:, not_before: nil, not_after: nil)
|
102
104
|
payload = {}
|
103
|
-
payload['identifiers'] =
|
104
|
-
identifiers
|
105
|
-
else
|
106
|
-
Array(identifiers).map do |identifier|
|
107
|
-
{ type: 'dns', value: identifier }
|
108
|
-
end
|
109
|
-
end
|
105
|
+
payload['identifiers'] = prepare_order_identifiers(identifiers)
|
110
106
|
payload['notBefore'] = not_before if not_before
|
111
107
|
payload['notAfter'] = not_after if not_after
|
112
108
|
|
@@ -116,7 +112,7 @@ class Acme::Client
|
|
116
112
|
end
|
117
113
|
|
118
114
|
def order(url:)
|
119
|
-
response =
|
115
|
+
response = post_as_get(url)
|
120
116
|
arguments = attributes_from_order_response(response)
|
121
117
|
Acme::Client::Resources::Order.new(self, **arguments.merge(url: url))
|
122
118
|
end
|
@@ -132,13 +128,28 @@ class Acme::Client
|
|
132
128
|
Acme::Client::Resources::Order.new(self, **arguments)
|
133
129
|
end
|
134
130
|
|
135
|
-
def certificate(url:)
|
131
|
+
def certificate(url:, force_chain: nil)
|
136
132
|
response = download(url, format: :pem)
|
137
|
-
response.body
|
133
|
+
pem = response.body
|
134
|
+
|
135
|
+
return pem if force_chain.nil?
|
136
|
+
|
137
|
+
return pem if ChainIdentifier.new(pem).match_name?(force_chain)
|
138
|
+
|
139
|
+
alternative_urls = Array(response.headers.dig('link', 'alternate'))
|
140
|
+
alternative_urls.each do |alternate_url|
|
141
|
+
response = download(alternate_url, format: :pem)
|
142
|
+
pem = response.body
|
143
|
+
if ChainIdentifier.new(pem).match_name?(force_chain)
|
144
|
+
return pem
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
raise Acme::Client::Error::ForcedChainNotFound, "Could not find any matching chain for `#{force_chain}`"
|
138
149
|
end
|
139
150
|
|
140
151
|
def authorization(url:)
|
141
|
-
response =
|
152
|
+
response = post_as_get(url)
|
142
153
|
arguments = attributes_from_authorization_response(response)
|
143
154
|
Acme::Client::Resources::Authorization.new(self, url: url, **arguments)
|
144
155
|
end
|
@@ -150,13 +161,13 @@ class Acme::Client
|
|
150
161
|
end
|
151
162
|
|
152
163
|
def challenge(url:)
|
153
|
-
response =
|
164
|
+
response = post_as_get(url)
|
154
165
|
arguments = attributes_from_challenge_response(response)
|
155
166
|
Acme::Client::Resources::Challenges.new(self, **arguments)
|
156
167
|
end
|
157
168
|
|
158
|
-
def request_challenge_validation(url:, key_authorization:)
|
159
|
-
response = post(url, payload: {
|
169
|
+
def request_challenge_validation(url:, key_authorization: nil)
|
170
|
+
response = post(url, payload: {})
|
160
171
|
arguments = attributes_from_challenge_response(response)
|
161
172
|
Acme::Client::Resources::Challenges.new(self, **arguments)
|
162
173
|
end
|
@@ -205,6 +216,20 @@ class Acme::Client
|
|
205
216
|
|
206
217
|
private
|
207
218
|
|
219
|
+
def prepare_order_identifiers(identifiers)
|
220
|
+
if identifiers.is_a?(Hash)
|
221
|
+
[identifiers]
|
222
|
+
else
|
223
|
+
Array(identifiers).map do |identifier|
|
224
|
+
if identifier.is_a?(String)
|
225
|
+
{ type: 'dns', value: identifier }
|
226
|
+
else
|
227
|
+
identifier
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
208
233
|
def attributes_from_account_response(response)
|
209
234
|
extract_attributes(
|
210
235
|
response.body,
|
@@ -251,14 +276,19 @@ class Acme::Client
|
|
251
276
|
connection.post(url, payload)
|
252
277
|
end
|
253
278
|
|
279
|
+
def post_as_get(url, mode: :kid)
|
280
|
+
connection = connection_for(url: url, mode: mode)
|
281
|
+
connection.post(url, nil)
|
282
|
+
end
|
283
|
+
|
254
284
|
def get(url, mode: :kid)
|
255
285
|
connection = connection_for(url: url, mode: mode)
|
256
286
|
connection.get(url)
|
257
287
|
end
|
258
288
|
|
259
289
|
def download(url, format:)
|
260
|
-
connection = connection_for(url: url, mode: :
|
261
|
-
connection.
|
290
|
+
connection = connection_for(url: url, mode: :kid)
|
291
|
+
connection.post do |request|
|
262
292
|
request.url(url)
|
263
293
|
request.headers['Accept'] = CONTENT_TYPES.fetch(format)
|
264
294
|
end
|
@@ -280,6 +310,12 @@ class Acme::Client
|
|
280
310
|
|
281
311
|
def new_connection(endpoint:)
|
282
312
|
Faraday.new(endpoint, **@connection_options) do |configuration|
|
313
|
+
if @bad_nonce_retry > 0
|
314
|
+
configuration.request(:retry,
|
315
|
+
max: @bad_nonce_retry,
|
316
|
+
methods: Faraday::Connection::METHODS,
|
317
|
+
exceptions: [Acme::Client::Error::BadNonce])
|
318
|
+
end
|
283
319
|
yield(configuration) if block_given?
|
284
320
|
configuration.adapter Faraday.default_adapter
|
285
321
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Acme::Client
|
2
|
+
class ChainIdentifier
|
3
|
+
def initialize(pem_certificate_chain)
|
4
|
+
@pem_certificate_chain = pem_certificate_chain
|
5
|
+
end
|
6
|
+
|
7
|
+
def match_name?(name)
|
8
|
+
issuers.any? do |issuer|
|
9
|
+
issuer.include?(name)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def issuers
|
16
|
+
x509_certificates.map(&:issuer).map(&:to_s)
|
17
|
+
end
|
18
|
+
|
19
|
+
def x509_certificates
|
20
|
+
@x509_certificates ||= splitted_pem_certificates.map { |pem| OpenSSL::X509::Certificate.new(pem) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def splitted_pem_certificates
|
24
|
+
@pem_certificate_chain.each_line.slice_after(/END CERTIFICATE/).map(&:join)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/acme/client/error.rb
CHANGED
@@ -7,6 +7,7 @@ class Acme::Client::Error < StandardError
|
|
7
7
|
class UnsupportedChallengeType < ClientError; end
|
8
8
|
class NotFound < ClientError; end
|
9
9
|
class CertificateNotReady < ClientError; end
|
10
|
+
class ForcedChainNotFound < ClientError; end
|
10
11
|
|
11
12
|
class ServerError < Acme::Client::Error; end
|
12
13
|
class BadCSR < ServerError; end
|
@@ -16,7 +16,10 @@ class Acme::Client::FaradayMiddleware < Faraday::Middleware
|
|
16
16
|
@env[:request_headers]['User-Agent'] = Acme::Client::USER_AGENT
|
17
17
|
@env[:request_headers]['Content-Type'] = CONTENT_TYPE
|
18
18
|
|
19
|
-
@env.
|
19
|
+
if @env.method != :get
|
20
|
+
@env.body = client.jwk.jws(header: jws_header, payload: env.body)
|
21
|
+
end
|
22
|
+
|
20
23
|
@app.call(env).on_complete { |response_env| on_complete(response_env) }
|
21
24
|
rescue Faraday::TimeoutError, Faraday::ConnectionFailed
|
22
25
|
raise Acme::Client::Error::Timeout
|
@@ -79,18 +82,10 @@ class Acme::Client::FaradayMiddleware < Faraday::Middleware
|
|
79
82
|
end
|
80
83
|
end
|
81
84
|
|
82
|
-
LINK_MATCH = /<(.*?)>;rel="([\w-]+)"/
|
83
|
-
|
84
85
|
def decode_link_headers
|
85
86
|
return unless env.response_headers.key?('Link')
|
86
87
|
link_header = env.response_headers['Link']
|
87
|
-
|
88
|
-
links = link_header.split(', ').map { |entry|
|
89
|
-
_, link, name = *entry.match(LINK_MATCH)
|
90
|
-
[name, link]
|
91
|
-
}
|
92
|
-
|
93
|
-
Hash[*links.flatten]
|
88
|
+
Acme::Client::Util.decode_link_headers(link_header)
|
94
89
|
end
|
95
90
|
|
96
91
|
def store_nonce
|
data/lib/acme/client/jwk/base.rb
CHANGED
@@ -14,10 +14,10 @@ class Acme::Client::JWK::Base
|
|
14
14
|
# payload - A Hash of payload data.
|
15
15
|
#
|
16
16
|
# Returns a JSON String.
|
17
|
-
def jws(header: {}, payload:
|
17
|
+
def jws(header: {}, payload:)
|
18
18
|
header = jws_header(header)
|
19
19
|
encoded_header = Acme::Client::Util.urlsafe_base64(header.to_json)
|
20
|
-
encoded_payload = Acme::Client::Util.urlsafe_base64(payload.to_json)
|
20
|
+
encoded_payload = Acme::Client::Util.urlsafe_base64(payload.nil? ? '' : payload.to_json)
|
21
21
|
|
22
22
|
signature_data = "#{encoded_header}.#{encoded_payload}"
|
23
23
|
signature = sign(signature_data)
|
@@ -4,6 +4,7 @@ module Acme::Client::Resources::Challenges
|
|
4
4
|
require 'acme/client/resources/challenges/base'
|
5
5
|
require 'acme/client/resources/challenges/http01'
|
6
6
|
require 'acme/client/resources/challenges/dns01'
|
7
|
+
require 'acme/client/resources/challenges/unsupported_challenge'
|
7
8
|
|
8
9
|
CHALLENGE_TYPES = {
|
9
10
|
'http-01' => Acme::Client::Resources::Challenges::HTTP01,
|
@@ -11,11 +12,6 @@ module Acme::Client::Resources::Challenges
|
|
11
12
|
}
|
12
13
|
|
13
14
|
def self.new(client, type:, **arguments)
|
14
|
-
|
15
|
-
if klass
|
16
|
-
klass.new(client, **arguments)
|
17
|
-
else
|
18
|
-
{ type: type }.merge(arguments)
|
19
|
-
end
|
15
|
+
CHALLENGE_TYPES.fetch(type, Unsupported).new(client, **arguments)
|
20
16
|
end
|
21
17
|
end
|
@@ -5,7 +5,7 @@ class Acme::Client::Resources::Challenges::Base
|
|
5
5
|
|
6
6
|
def initialize(client, **arguments)
|
7
7
|
@client = client
|
8
|
-
assign_attributes(arguments)
|
8
|
+
assign_attributes(**arguments)
|
9
9
|
end
|
10
10
|
|
11
11
|
def challenge_type
|
@@ -21,17 +21,9 @@ class Acme::Client::Resources::Challenges::Base
|
|
21
21
|
true
|
22
22
|
end
|
23
23
|
|
24
|
-
def send_challenge_vallidation(url:, key_authorization:)
|
25
|
-
@client.request_challenge_validation(
|
26
|
-
url: url,
|
27
|
-
key_authorization: key_authorization
|
28
|
-
).to_h
|
29
|
-
end
|
30
|
-
|
31
24
|
def request_validation
|
32
|
-
assign_attributes(**
|
33
|
-
url: url
|
34
|
-
key_authorization: key_authorization
|
25
|
+
assign_attributes(**send_challenge_validation(
|
26
|
+
url: url
|
35
27
|
))
|
36
28
|
true
|
37
29
|
end
|
@@ -42,6 +34,12 @@ class Acme::Client::Resources::Challenges::Base
|
|
42
34
|
|
43
35
|
private
|
44
36
|
|
37
|
+
def send_challenge_validation(url:)
|
38
|
+
@client.request_challenge_validation(
|
39
|
+
url: url
|
40
|
+
).to_h
|
41
|
+
end
|
42
|
+
|
45
43
|
def assign_attributes(status:, url:, token:, error: nil)
|
46
44
|
@status = status
|
47
45
|
@url = url
|
@@ -5,7 +5,7 @@ class Acme::Client::Resources::Order
|
|
5
5
|
|
6
6
|
def initialize(client, **arguments)
|
7
7
|
@client = client
|
8
|
-
assign_attributes(arguments)
|
8
|
+
assign_attributes(**arguments)
|
9
9
|
end
|
10
10
|
|
11
11
|
def reload
|
@@ -24,9 +24,9 @@ class Acme::Client::Resources::Order
|
|
24
24
|
true
|
25
25
|
end
|
26
26
|
|
27
|
-
def certificate
|
27
|
+
def certificate(force_chain: nil)
|
28
28
|
if certificate_url
|
29
|
-
@client.certificate(url: certificate_url)
|
29
|
+
@client.certificate(url: certificate_url, force_chain: force_chain)
|
30
30
|
else
|
31
31
|
raise Acme::Client::Error::CertificateNotReady, 'No certificate_url to collect the order'
|
32
32
|
end
|
data/lib/acme/client/util.rb
CHANGED
@@ -3,6 +3,17 @@ module Acme::Client::Util
|
|
3
3
|
Base64.urlsafe_encode64(data).sub(/[\s=]*\z/, '')
|
4
4
|
end
|
5
5
|
|
6
|
+
LINK_MATCH = /<(.*?)>\s?;\s?rel="([\w-]+)"/
|
7
|
+
|
8
|
+
# See RFC 8288 - https://tools.ietf.org/html/rfc8288#section-3
|
9
|
+
def decode_link_headers(link_header)
|
10
|
+
link_header.split(',').each_with_object({}) { |entry, hash|
|
11
|
+
_, link, name = *entry.match(LINK_MATCH)
|
12
|
+
hash[name] ||= []
|
13
|
+
hash[name].push(link)
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
6
17
|
# Sets public key on CSR or cert.
|
7
18
|
#
|
8
19
|
# obj - An OpenSSL::X509::Certificate or OpenSSL::X509::Request instance.
|
data/lib/acme/client/version.rb
CHANGED
metadata
CHANGED
@@ -1,69 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acme-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charles Barbier
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-09-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.6'
|
20
17
|
- - ">="
|
21
18
|
- !ruby/object:Gem::Version
|
22
|
-
version: 1.
|
19
|
+
version: 1.17.3
|
23
20
|
type: :development
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
|
-
- - "~>"
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '1.6'
|
30
24
|
- - ">="
|
31
25
|
- !ruby/object:Gem::Version
|
32
|
-
version: 1.
|
26
|
+
version: 1.17.3
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
28
|
name: rake
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
36
30
|
requirements:
|
37
31
|
- - "~>"
|
38
32
|
- !ruby/object:Gem::Version
|
39
|
-
version: '
|
33
|
+
version: '13.0'
|
40
34
|
type: :development
|
41
35
|
prerelease: false
|
42
36
|
version_requirements: !ruby/object:Gem::Requirement
|
43
37
|
requirements:
|
44
38
|
- - "~>"
|
45
39
|
- !ruby/object:Gem::Version
|
46
|
-
version: '
|
40
|
+
version: '13.0'
|
47
41
|
- !ruby/object:Gem::Dependency
|
48
42
|
name: rspec
|
49
43
|
requirement: !ruby/object:Gem::Requirement
|
50
44
|
requirements:
|
51
|
-
- - ">="
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: 3.3.0
|
54
45
|
- - "~>"
|
55
46
|
- !ruby/object:Gem::Version
|
56
|
-
version: '3.
|
47
|
+
version: '3.9'
|
57
48
|
type: :development
|
58
49
|
prerelease: false
|
59
50
|
version_requirements: !ruby/object:Gem::Requirement
|
60
51
|
requirements:
|
61
|
-
- - ">="
|
62
|
-
- !ruby/object:Gem::Version
|
63
|
-
version: 3.3.0
|
64
52
|
- - "~>"
|
65
53
|
- !ruby/object:Gem::Version
|
66
|
-
version: '3.
|
54
|
+
version: '3.9'
|
67
55
|
- !ruby/object:Gem::Dependency
|
68
56
|
name: vcr
|
69
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -71,9 +59,6 @@ dependencies:
|
|
71
59
|
- - "~>"
|
72
60
|
- !ruby/object:Gem::Version
|
73
61
|
version: '2.9'
|
74
|
-
- - ">="
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
version: 2.9.3
|
77
62
|
type: :development
|
78
63
|
prerelease: false
|
79
64
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -81,49 +66,40 @@ dependencies:
|
|
81
66
|
- - "~>"
|
82
67
|
- !ruby/object:Gem::Version
|
83
68
|
version: '2.9'
|
84
|
-
- - ">="
|
85
|
-
- !ruby/object:Gem::Version
|
86
|
-
version: 2.9.3
|
87
69
|
- !ruby/object:Gem::Dependency
|
88
70
|
name: webmock
|
89
71
|
requirement: !ruby/object:Gem::Requirement
|
90
72
|
requirements:
|
91
|
-
- - ">="
|
92
|
-
- !ruby/object:Gem::Version
|
93
|
-
version: 1.21.0
|
94
73
|
- - "~>"
|
95
74
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
75
|
+
version: '3.8'
|
97
76
|
type: :development
|
98
77
|
prerelease: false
|
99
78
|
version_requirements: !ruby/object:Gem::Requirement
|
100
79
|
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: 1.21.0
|
104
80
|
- - "~>"
|
105
81
|
- !ruby/object:Gem::Version
|
106
|
-
version: '
|
82
|
+
version: '3.8'
|
107
83
|
- !ruby/object:Gem::Dependency
|
108
84
|
name: faraday
|
109
85
|
requirement: !ruby/object:Gem::Requirement
|
110
86
|
requirements:
|
111
|
-
- - "~>"
|
112
|
-
- !ruby/object:Gem::Version
|
113
|
-
version: '0.9'
|
114
87
|
- - ">="
|
115
88
|
- !ruby/object:Gem::Version
|
116
|
-
version: 0.
|
89
|
+
version: '0.17'
|
90
|
+
- - "<"
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 2.0.0
|
117
93
|
type: :runtime
|
118
94
|
prerelease: false
|
119
95
|
version_requirements: !ruby/object:Gem::Requirement
|
120
96
|
requirements:
|
121
|
-
- - "~>"
|
122
|
-
- !ruby/object:Gem::Version
|
123
|
-
version: '0.9'
|
124
97
|
- - ">="
|
125
98
|
- !ruby/object:Gem::Version
|
126
|
-
version: 0.
|
99
|
+
version: '0.17'
|
100
|
+
- - "<"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 2.0.0
|
127
103
|
description:
|
128
104
|
email:
|
129
105
|
- unixcharles@gmail.com
|
@@ -148,6 +124,7 @@ files:
|
|
148
124
|
- lib/acme/client.rb
|
149
125
|
- lib/acme/client/certificate_request.rb
|
150
126
|
- lib/acme/client/certificate_request/ec_key_patch.rb
|
127
|
+
- lib/acme/client/chain_identifier.rb
|
151
128
|
- lib/acme/client/error.rb
|
152
129
|
- lib/acme/client/faraday_middleware.rb
|
153
130
|
- lib/acme/client/jwk.rb
|
@@ -161,6 +138,7 @@ files:
|
|
161
138
|
- lib/acme/client/resources/challenges/base.rb
|
162
139
|
- lib/acme/client/resources/challenges/dns01.rb
|
163
140
|
- lib/acme/client/resources/challenges/http01.rb
|
141
|
+
- lib/acme/client/resources/challenges/unsupported_challenge.rb
|
164
142
|
- lib/acme/client/resources/directory.rb
|
165
143
|
- lib/acme/client/resources/order.rb
|
166
144
|
- lib/acme/client/self_sign_certificate.rb
|
@@ -185,7 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
185
163
|
- !ruby/object:Gem::Version
|
186
164
|
version: '0'
|
187
165
|
requirements: []
|
188
|
-
rubygems_version: 3.
|
166
|
+
rubygems_version: 3.1.2
|
189
167
|
signing_key:
|
190
168
|
specification_version: 4
|
191
169
|
summary: Client for the ACME protocol.
|