acme-client 2.0.2 → 2.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://travis-ci.org/unixcharles/acme-client.svg?branch=master)](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.
|