acme-client 2.0.6 → 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/.travis.yml +0 -4
- data/CHANGELOG.md +5 -0
- data/README.md +1 -1
- data/lib/acme/client.rb +18 -2
- data/lib/acme/client/chain_identifier.rb +27 -0
- data/lib/acme/client/error.rb +1 -0
- data/lib/acme/client/faraday_middleware.rb +1 -9
- data/lib/acme/client/resources/account.rb +1 -1
- data/lib/acme/client/resources/authorization.rb +1 -1
- data/lib/acme/client/resources/challenges/base.rb +1 -1
- 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 +4 -3
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/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -184,7 +184,7 @@ csr = Acme::Client::CertificateRequest.new(private_key: a_different_private_key,
|
|
184
184
|
order.finalize(csr: csr)
|
185
185
|
while order.status == 'processing'
|
186
186
|
sleep(1)
|
187
|
-
|
187
|
+
order.reload
|
188
188
|
end
|
189
189
|
order.certificate # => PEM-formatted certificate
|
190
190
|
```
|
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
|
@@ -127,9 +128,24 @@ class Acme::Client
|
|
127
128
|
Acme::Client::Resources::Order.new(self, **arguments)
|
128
129
|
end
|
129
130
|
|
130
|
-
def certificate(url:)
|
131
|
+
def certificate(url:, force_chain: nil)
|
131
132
|
response = download(url, format: :pem)
|
132
|
-
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}`"
|
133
149
|
end
|
134
150
|
|
135
151
|
def authorization(url:)
|
@@ -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
|
@@ -82,18 +82,10 @@ class Acme::Client::FaradayMiddleware < Faraday::Middleware
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
-
LINK_MATCH = /<(.*?)>;rel="([\w-]+)"/
|
86
|
-
|
87
85
|
def decode_link_headers
|
88
86
|
return unless env.response_headers.key?('Link')
|
89
87
|
link_header = env.response_headers['Link']
|
90
|
-
|
91
|
-
links = link_header.split(', ').map { |entry|
|
92
|
-
_, link, name = *entry.match(LINK_MATCH)
|
93
|
-
[name, link]
|
94
|
-
}
|
95
|
-
|
96
|
-
Hash[*links.flatten]
|
88
|
+
Acme::Client::Util.decode_link_headers(link_header)
|
97
89
|
end
|
98
90
|
|
99
91
|
def store_nonce
|
@@ -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,14 +1,14 @@
|
|
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: 2020-
|
11
|
+
date: 2020-09-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -124,6 +124,7 @@ files:
|
|
124
124
|
- lib/acme/client.rb
|
125
125
|
- lib/acme/client/certificate_request.rb
|
126
126
|
- lib/acme/client/certificate_request/ec_key_patch.rb
|
127
|
+
- lib/acme/client/chain_identifier.rb
|
127
128
|
- lib/acme/client/error.rb
|
128
129
|
- lib/acme/client/faraday_middleware.rb
|
129
130
|
- lib/acme/client/jwk.rb
|
@@ -162,7 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
162
163
|
- !ruby/object:Gem::Version
|
163
164
|
version: '0'
|
164
165
|
requirements: []
|
165
|
-
rubygems_version: 3.
|
166
|
+
rubygems_version: 3.1.2
|
166
167
|
signing_key:
|
167
168
|
specification_version: 4
|
168
169
|
summary: Client for the ACME protocol.
|