acme-client 2.0.7 → 2.0.10
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/rubocop.yml +23 -0
- data/.github/workflows/test.yml +26 -0
- data/CHANGELOG.md +16 -0
- data/Gemfile +4 -4
- data/README.md +46 -15
- data/acme-client.gemspec +5 -7
- data/lib/acme/client/faraday_middleware.rb +3 -3
- data/lib/acme/client/jwk/ecdsa.rb +3 -1
- data/lib/acme/client/resources/directory.rb +6 -2
- data/lib/acme/client/version.rb +1 -1
- data/lib/acme/client.rb +23 -0
- metadata +42 -13
- data/.travis.yml +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f780d5789f4ea62c093b7b1df25b8a9efeb8b7c3c94fce26205eb79edb8fefa5
|
4
|
+
data.tar.gz: 95118697ef1fcd9a090e822bcc6bb1455c38ebaf392b2b2a7e90928e68cb328a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c10643d9a50b74e142bd8748ab77001d292bc789884410cfeac79e10c01911335f5ffd6adb95a2c359d3582fe7cfac4dc02a686a02fbe90154a6644301736d37
|
7
|
+
data.tar.gz: a8ffa05157b5a3ce8cc606dc74592924b13918fefe0f55717ff8018ef13a219eebe1f614c2bdda6b7f097190e3173f8ecdf5a8de48f8462d462b5bcc09a67161
|
@@ -0,0 +1,23 @@
|
|
1
|
+
name: Lint
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ master ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
rubocop:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
strategy:
|
13
|
+
matrix:
|
14
|
+
ruby-version: ['3.0']
|
15
|
+
steps:
|
16
|
+
- uses: actions/checkout@v2
|
17
|
+
- name: Set up Ruby
|
18
|
+
uses: ruby/setup-ruby@v1
|
19
|
+
with:
|
20
|
+
ruby-version: ${{ matrix.ruby-version }}
|
21
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
22
|
+
- name: Run tests
|
23
|
+
run: bundle exec rake rubocop
|
@@ -0,0 +1,26 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ master ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
strategy:
|
13
|
+
matrix:
|
14
|
+
ruby-version: ['2.6', '2.7', '3.0', truffleruby-head]
|
15
|
+
faraday-version: ['~> 1.7', '~> 2.0']
|
16
|
+
env:
|
17
|
+
FARADAY_VERSION: ${{ matrix.faraday-version }}
|
18
|
+
steps:
|
19
|
+
- uses: actions/checkout@v2
|
20
|
+
- name: Set up Ruby
|
21
|
+
uses: ruby/setup-ruby@v1
|
22
|
+
with:
|
23
|
+
ruby-version: ${{ matrix.ruby-version }}
|
24
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
25
|
+
- name: Run tests
|
26
|
+
run: bundle exec rake spec
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
## `2.0.10`
|
2
|
+
|
3
|
+
* Support for Faraday 1.0 / 2.0
|
4
|
+
|
5
|
+
## `2.0.9`
|
6
|
+
|
7
|
+
* Support for Ruby 3.0 and Faraday 0.17.x
|
8
|
+
* Raise when directory is rate limited
|
9
|
+
|
10
|
+
## `2.0.8`
|
11
|
+
|
12
|
+
* Add support for the keyChange endpoint
|
13
|
+
|
14
|
+
https://tools.ietf.org/html/rfc8555#section-7.3.5
|
15
|
+
|
16
|
+
|
1
17
|
## `2.0.7`
|
2
18
|
|
3
19
|
* Add support for alternate certificate chain
|
data/Gemfile
CHANGED
@@ -2,12 +2,12 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
+
if faraday_version = ENV['FARADAY_VERSION']
|
6
|
+
gem 'faraday', faraday_version
|
7
|
+
end
|
8
|
+
|
5
9
|
group :development, :test do
|
6
10
|
gem 'pry'
|
7
11
|
gem 'rubocop', '~> 0.49.0'
|
8
12
|
gem 'ruby-prof', require: false
|
9
|
-
|
10
|
-
if Gem::Version.new(RUBY_VERSION) <= Gem::Version.new('2.2.2')
|
11
|
-
gem 'activesupport', '~> 4.2.6'
|
12
|
-
end
|
13
13
|
end
|
data/README.md
CHANGED
@@ -23,17 +23,26 @@ gem 'acme-client'
|
|
23
23
|
```
|
24
24
|
|
25
25
|
## Usage
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
26
|
+
- [Acme::Client](#acmeclient)
|
27
|
+
- [Installation](#installation)
|
28
|
+
- [Usage](#usage)
|
29
|
+
- [Setting up a client](#setting-up-a-client)
|
30
|
+
- [Account management](#account-management)
|
31
|
+
- [Obtaining a certificate](#obtaining-a-certificate)
|
32
|
+
- [Ordering a certificate](#ordering-a-certificate)
|
33
|
+
- [Preparing for HTTP challenge](#preparing-for-http-challenge)
|
34
|
+
- [Preparing for DNS challenge](#preparing-for-dns-challenge)
|
35
|
+
- [Requesting a challenge verification](#requesting-a-challenge-verification)
|
36
|
+
- [Downloading a certificate](#downloading-a-certificate)
|
37
|
+
- [Ordering an alternative certificate](#ordering-an-alternative-certificate)
|
38
|
+
- [Extra](#extra)
|
39
|
+
- [Certificate revokation](#certificate-revokation)
|
40
|
+
- [Certificate renewal](#certificate-renewal)
|
41
|
+
- [Not implemented](#not-implemented)
|
42
|
+
- [Requirements](#requirements)
|
43
|
+
- [Development](#development)
|
44
|
+
- [Pull request?](#pull-request)
|
45
|
+
- [License](#license)
|
37
46
|
|
38
47
|
## Setting up a client
|
39
48
|
|
@@ -91,7 +100,7 @@ account.kid # => <kid string>
|
|
91
100
|
|
92
101
|
If you already have an existing account (for example one created in ACME v1) please note that unless the `kid` is provided at initialization, the client will lazy load the `kid` by doing a `POST` to `newAccount` whenever the `kid` is required. Therefore, you can easily get your `kid` for an existing account and (if needed) store it for reuse:
|
93
102
|
|
94
|
-
```
|
103
|
+
```ruby
|
95
104
|
client = Acme::Client.new(private_key: private_key, directory: 'https://acme-staging-v02.api.letsencrypt.org/directory')
|
96
105
|
|
97
106
|
# kid is not set, therefore a call to newAccount is made to lazy-initialize the kid
|
@@ -189,6 +198,23 @@ end
|
|
189
198
|
order.certificate # => PEM-formatted certificate
|
190
199
|
```
|
191
200
|
|
201
|
+
### Ordering an alternative certificate
|
202
|
+
|
203
|
+
Let's Encrypt is [transitioning](https://letsencrypt.org/2019/04/15/transitioning-to-isrg-root.html) to use a new intermediate certificate. Starting January 11, 2021 new certificates will be signed by their own intermediate. To ease the transition on clients Let's Encrypt will continue signing an alternative version of the certificate using the old, cross-signed intermediate until September 29, 2021. In order to utilize an alternative certificate the `Order#certificate` method accepts a `force_chain` keyword argument, which takes the issuer name of the intermediate certificate.
|
204
|
+
For example, to download the cross-signed certificate after January 11, 2021, call `Order#certificate` as follows:
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
begin
|
208
|
+
order.certificate(force_chain: 'DST Root CA X3')
|
209
|
+
rescue Acme::Client::Error::ForcedChainNotFound
|
210
|
+
order.certificate
|
211
|
+
end
|
212
|
+
```
|
213
|
+
|
214
|
+
Note: if the specified forced chain doesn't match an existing alternative certificate the method will raise an `Acme::Client::Error::ForcedChainNotFound` error.
|
215
|
+
|
216
|
+
Learn more about the original Github issue for this client [here](https://github.com/unixcharles/acme-client/issues/186), information from Let's Encrypt [here](https://letsencrypt.org/2019/04/15/transitioning-to-isrg-root.html), and cross-signing [here](https://letsencrypt.org/certificates/#cross-signing).
|
217
|
+
|
192
218
|
## Extra
|
193
219
|
|
194
220
|
### Certificate revokation
|
@@ -204,9 +230,15 @@ client.revoke(certificate: certificate)
|
|
204
230
|
There is no renewal process, just create a new order.
|
205
231
|
|
206
232
|
|
207
|
-
|
233
|
+
### Account Key Roll-over
|
208
234
|
|
209
|
-
|
235
|
+
To change the key used for an account you can call `#account_key_change` with the new private key or jwk.
|
236
|
+
|
237
|
+
```ruby
|
238
|
+
require 'openssl'
|
239
|
+
new_private_key = OpenSSL::PKey::RSA.new(4096)
|
240
|
+
client.account_key_change(private_key: new_private_key)
|
241
|
+
```
|
210
242
|
|
211
243
|
## Requirements
|
212
244
|
|
@@ -227,4 +259,3 @@ Yes.
|
|
227
259
|
## License
|
228
260
|
|
229
261
|
[MIT License](http://opensource.org/licenses/MIT)
|
230
|
-
|
data/acme-client.gemspec
CHANGED
@@ -14,17 +14,15 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
15
15
|
spec.require_paths = ['lib']
|
16
16
|
|
17
|
-
spec.required_ruby_version = '>= 2.
|
17
|
+
spec.required_ruby_version = '>= 2.3.0'
|
18
18
|
|
19
19
|
spec.add_development_dependency 'bundler', '>= 1.17.3'
|
20
|
-
|
21
|
-
spec.add_development_dependency 'rake', '>= 12.0'
|
22
|
-
else
|
23
|
-
spec.add_development_dependency 'rake', '~> 13.0'
|
24
|
-
end
|
20
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
25
21
|
spec.add_development_dependency 'rspec', '~> 3.9'
|
26
22
|
spec.add_development_dependency 'vcr', '~> 2.9'
|
27
23
|
spec.add_development_dependency 'webmock', '~> 3.8'
|
24
|
+
spec.add_development_dependency 'webrick'
|
28
25
|
|
29
|
-
spec.add_runtime_dependency 'faraday', '>= 0
|
26
|
+
spec.add_runtime_dependency 'faraday', '>= 1.0', '< 3.0.0'
|
27
|
+
spec.add_runtime_dependency 'faraday-retry', '~> 1.0'
|
30
28
|
end
|
@@ -5,10 +5,10 @@ class Acme::Client::FaradayMiddleware < Faraday::Middleware
|
|
5
5
|
|
6
6
|
CONTENT_TYPE = 'application/jose+json'
|
7
7
|
|
8
|
-
def initialize(app,
|
8
|
+
def initialize(app, options)
|
9
9
|
super(app)
|
10
|
-
@client = client
|
11
|
-
@mode = mode
|
10
|
+
@client = options.fetch(:client)
|
11
|
+
@mode = options.fetch(:mode)
|
12
12
|
end
|
13
13
|
|
14
14
|
def call(env)
|
@@ -73,8 +73,10 @@ class Acme::Client::JWK::ECDSA < Acme::Client::JWK::Base
|
|
73
73
|
# BigNumbers
|
74
74
|
bns = ints.map(&:value)
|
75
75
|
|
76
|
+
byte_size = (@private_key.group.degree + 7) / 8
|
77
|
+
|
76
78
|
# Binary R/S values
|
77
|
-
r, s = bns.map { |bn|
|
79
|
+
r, s = bns.map { |bn| bn.to_s(2).rjust(byte_size, "\x00") }
|
78
80
|
|
79
81
|
# JWS wants raw R/S concatenated.
|
80
82
|
[r, s].join
|
@@ -68,9 +68,13 @@ class Acme::Client::Resources::Directory
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def fetch_directory
|
71
|
-
connection = Faraday.new(url: @directory, **@connection_options)
|
71
|
+
connection = Faraday.new(url: @directory, **@connection_options) do |configuration|
|
72
|
+
configuration.use Acme::Client::FaradayMiddleware, client: nil, mode: nil
|
73
|
+
|
74
|
+
configuration.adapter Faraday.default_adapter
|
75
|
+
end
|
72
76
|
connection.headers[:user_agent] = Acme::Client::USER_AGENT
|
73
77
|
response = connection.get(@url)
|
74
|
-
|
78
|
+
response.body
|
75
79
|
end
|
76
80
|
end
|
data/lib/acme/client/version.rb
CHANGED
data/lib/acme/client.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'faraday'
|
4
|
+
require 'faraday/retry'
|
4
5
|
require 'json'
|
5
6
|
require 'openssl'
|
6
7
|
require 'digest'
|
@@ -85,6 +86,28 @@ class Acme::Client
|
|
85
86
|
Acme::Client::Resources::Account.new(self, url: kid, **arguments)
|
86
87
|
end
|
87
88
|
|
89
|
+
def account_key_change(new_private_key: nil, new_jwk: nil)
|
90
|
+
if new_private_key.nil? && new_jwk.nil?
|
91
|
+
raise ArgumentError, 'must specify new_jwk or new_private_key'
|
92
|
+
end
|
93
|
+
old_jwk = jwk
|
94
|
+
new_jwk ||= Acme::Client::JWK.from_private_key(new_private_key)
|
95
|
+
|
96
|
+
inner_payload_header = {
|
97
|
+
url: endpoint_for(:key_change)
|
98
|
+
}
|
99
|
+
inner_payload = {
|
100
|
+
account: kid,
|
101
|
+
oldKey: old_jwk.to_h
|
102
|
+
}
|
103
|
+
payload = JSON.parse(new_jwk.jws(header: inner_payload_header, payload: inner_payload))
|
104
|
+
|
105
|
+
response = post(endpoint_for(:key_change), payload: payload, mode: :kid)
|
106
|
+
arguments = attributes_from_account_response(response)
|
107
|
+
@jwk = new_jwk
|
108
|
+
Acme::Client::Resources::Account.new(self, url: kid, **arguments)
|
109
|
+
end
|
110
|
+
|
88
111
|
def account
|
89
112
|
@kid ||= begin
|
90
113
|
response = post(endpoint_for(:new_account), payload: { onlyReturnExisting: true }, mode: :jwk)
|
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.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charles Barbier
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,37 +80,66 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '3.8'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: webrick
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: faraday
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
101
|
- - ">="
|
88
102
|
- !ruby/object:Gem::Version
|
89
|
-
version: '0
|
103
|
+
version: '1.0'
|
90
104
|
- - "<"
|
91
105
|
- !ruby/object:Gem::Version
|
92
|
-
version:
|
106
|
+
version: 3.0.0
|
93
107
|
type: :runtime
|
94
108
|
prerelease: false
|
95
109
|
version_requirements: !ruby/object:Gem::Requirement
|
96
110
|
requirements:
|
97
111
|
- - ">="
|
98
112
|
- !ruby/object:Gem::Version
|
99
|
-
version: '0
|
113
|
+
version: '1.0'
|
100
114
|
- - "<"
|
101
115
|
- !ruby/object:Gem::Version
|
102
|
-
version:
|
103
|
-
|
116
|
+
version: 3.0.0
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: faraday-retry
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '1.0'
|
124
|
+
type: :runtime
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - "~>"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '1.0'
|
131
|
+
description:
|
104
132
|
email:
|
105
133
|
- unixcharles@gmail.com
|
106
134
|
executables: []
|
107
135
|
extensions: []
|
108
136
|
extra_rdoc_files: []
|
109
137
|
files:
|
138
|
+
- ".github/workflows/rubocop.yml"
|
139
|
+
- ".github/workflows/test.yml"
|
110
140
|
- ".gitignore"
|
111
141
|
- ".rspec"
|
112
142
|
- ".rubocop.yml"
|
113
|
-
- ".travis.yml"
|
114
143
|
- CHANGELOG.md
|
115
144
|
- Gemfile
|
116
145
|
- LICENSE.txt
|
@@ -148,7 +177,7 @@ homepage: http://github.com/unixcharles/acme-client
|
|
148
177
|
licenses:
|
149
178
|
- MIT
|
150
179
|
metadata: {}
|
151
|
-
post_install_message:
|
180
|
+
post_install_message:
|
152
181
|
rdoc_options: []
|
153
182
|
require_paths:
|
154
183
|
- lib
|
@@ -156,15 +185,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
156
185
|
requirements:
|
157
186
|
- - ">="
|
158
187
|
- !ruby/object:Gem::Version
|
159
|
-
version: 2.
|
188
|
+
version: 2.3.0
|
160
189
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
190
|
requirements:
|
162
191
|
- - ">="
|
163
192
|
- !ruby/object:Gem::Version
|
164
193
|
version: '0'
|
165
194
|
requirements: []
|
166
|
-
rubygems_version: 3.
|
167
|
-
signing_key:
|
195
|
+
rubygems_version: 3.3.3
|
196
|
+
signing_key:
|
168
197
|
specification_version: 4
|
169
198
|
summary: Client for the ACME protocol.
|
170
199
|
test_files: []
|