acme-client 1.0.0 → 2.0.0

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.
@@ -15,6 +15,6 @@ class Acme::Client::Resources::Challenges::DNS01 < Acme::Client::Resources::Chal
15
15
  end
16
16
 
17
17
  def record_content
18
- Acme::Client::Util.urlsafe_base64(DIGEST.digest(authorization_key))
18
+ Acme::Client::Util.urlsafe_base64(DIGEST.digest(key_authorization))
19
19
  end
20
20
  end
@@ -9,7 +9,7 @@ class Acme::Client::Resources::Challenges::HTTP01 < Acme::Client::Resources::Cha
9
9
  end
10
10
 
11
11
  def file_content
12
- authorization_key
12
+ key_authorization
13
13
  end
14
14
 
15
15
  def filename
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Acme::Client::Resources::Directory
4
+ DIRECTORY_RESOURCES = {
5
+ new_nonce: 'newNonce',
6
+ new_account: 'newAccount',
7
+ new_order: 'newOrder',
8
+ new_authz: 'newAuthz',
9
+ revoke_certificate: 'revokeCert',
10
+ key_change: 'keyChange'
11
+ }
12
+
13
+ DIRECTORY_META = {
14
+ terms_of_service: 'termsOfService',
15
+ website: 'website',
16
+ caa_identities: 'caaIdentities',
17
+ external_account_required: 'externalAccountRequired'
18
+ }
19
+
20
+ def initialize(url, connection_options)
21
+ @url, @connection_options = url, connection_options
22
+ end
23
+
24
+ def endpoint_for(key)
25
+ directory.fetch(key) do |missing_key|
26
+ raise Acme::Client::Error::UnsupportedOperation,
27
+ "Directory at #{@url} does not include `#{missing_key}`"
28
+ end
29
+ end
30
+
31
+ def terms_of_service
32
+ meta[DIRECTORY_META[:terms_of_service]]
33
+ end
34
+
35
+ def website
36
+ meta[DIRECTORY_META[:website]]
37
+ end
38
+
39
+ def caa_identities
40
+ meta[DIRECTORY_META[:caa_identities]]
41
+ end
42
+
43
+ def external_account_required
44
+ meta[DIRECTORY_META[:external_account_required]]
45
+ end
46
+
47
+ def meta
48
+ directory[:meta]
49
+ end
50
+
51
+ private
52
+
53
+ def directory
54
+ @directory ||= load_directory
55
+ end
56
+
57
+ def load_directory
58
+ body = fetch_directory
59
+ result = {}
60
+ result[:meta] = body.delete('meta')
61
+ DIRECTORY_RESOURCES.each do |key, entry|
62
+ result[key] = URI(body[entry]) if body[entry]
63
+ end
64
+ result
65
+ rescue JSON::ParserError => exception
66
+ raise InvalidDirectory, "Invalid directory url\n#{@directory} did not return a valid directory\n#{exception.inspect}"
67
+ end
68
+
69
+ def fetch_directory
70
+ connection = Faraday.new(url: @directory, **@connection_options)
71
+ connection.headers[:user_agent] = Acme::Client::USER_AGENT
72
+ response = connection.get(@url)
73
+ JSON.parse(response.body)
74
+ end
75
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Acme::Client::Resources::Order
4
+ attr_reader :url, :status, :contact, :finalize_url, :identifiers, :authorization_urls, :expires, :certificate_url
5
+
6
+ def initialize(client, **arguments)
7
+ @client = client
8
+ assign_attributes(arguments)
9
+ end
10
+
11
+ def reload
12
+ assign_attributes **@client.order(url: url).to_h
13
+ true
14
+ end
15
+
16
+ def authorizations
17
+ @authorization_urls.map do |authorization_url|
18
+ @client.authorization(url: authorization_url)
19
+ end
20
+ end
21
+
22
+ def finalize(csr:)
23
+ assign_attributes **@client.finalize(url: finalize_url, csr: csr).to_h
24
+ true
25
+ end
26
+
27
+ def certificate
28
+ if certificate_url
29
+ @client.certificate(url: certificate_url)
30
+ else
31
+ raise Acme::Client::Error::CertificateNotReady, 'No certificate_url to collect the order'
32
+ end
33
+ end
34
+
35
+ def to_h
36
+ {
37
+ url: url,
38
+ status: status,
39
+ expires: expires,
40
+ finalize_url: finalize_url,
41
+ authorization_urls: authorization_urls,
42
+ identifiers: identifiers,
43
+ certificate_url: certificate_url
44
+ }
45
+ end
46
+
47
+ private
48
+
49
+ def assign_attributes(url:, status:, expires:, finalize_url:, authorization_urls:, identifiers:, certificate_url: nil)
50
+ @url = url
51
+ @status = status
52
+ @expires = expires
53
+ @finalize_url = finalize_url
54
+ @authorization_urls = authorization_urls
55
+ @identifiers = identifiers
56
+ @certificate_url = certificate_url
57
+ end
58
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Acme
4
4
  class Client
5
- VERSION = '1.0.0'.freeze
5
+ VERSION = '2.0.0'.freeze
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acme-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charles Barbier
@@ -146,7 +146,6 @@ files:
146
146
  - bin/setup
147
147
  - lib/acme-client.rb
148
148
  - lib/acme/client.rb
149
- - lib/acme/client/certificate.rb
150
149
  - lib/acme/client/certificate_request.rb
151
150
  - lib/acme/client/certificate_request/ec_key_patch.rb
152
151
  - lib/acme/client/error.rb
@@ -156,13 +155,14 @@ files:
156
155
  - lib/acme/client/jwk/ecdsa.rb
157
156
  - lib/acme/client/jwk/rsa.rb
158
157
  - lib/acme/client/resources.rb
158
+ - lib/acme/client/resources/account.rb
159
159
  - lib/acme/client/resources/authorization.rb
160
160
  - lib/acme/client/resources/challenges.rb
161
161
  - lib/acme/client/resources/challenges/base.rb
162
162
  - lib/acme/client/resources/challenges/dns01.rb
163
163
  - lib/acme/client/resources/challenges/http01.rb
164
- - lib/acme/client/resources/challenges/tls_sni01.rb
165
- - lib/acme/client/resources/registration.rb
164
+ - lib/acme/client/resources/directory.rb
165
+ - lib/acme/client/resources/order.rb
166
166
  - lib/acme/client/self_sign_certificate.rb
167
167
  - lib/acme/client/util.rb
168
168
  - lib/acme/client/version.rb
@@ -186,7 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
186
186
  version: '0'
187
187
  requirements: []
188
188
  rubyforge_project:
189
- rubygems_version: 2.5.2
189
+ rubygems_version: 2.7.6
190
190
  signing_key:
191
191
  specification_version: 4
192
192
  summary: Client for the ACME protocol.
@@ -1,30 +0,0 @@
1
- class Acme::Client::Certificate
2
- extend Forwardable
3
-
4
- attr_reader :x509, :x509_chain, :request, :private_key, :url
5
-
6
- def_delegators :x509, :to_pem, :to_der
7
-
8
- def initialize(certificate, url, chain, request)
9
- @x509 = certificate
10
- @url = url
11
- @x509_chain = chain
12
- @request = request
13
- end
14
-
15
- def chain_to_pem
16
- x509_chain.map(&:to_pem).join
17
- end
18
-
19
- def x509_fullchain
20
- [x509, *x509_chain]
21
- end
22
-
23
- def fullchain_to_pem
24
- x509_fullchain.map(&:to_pem).join
25
- end
26
-
27
- def common_name
28
- x509.subject.to_a.find { |name, _, _| name == 'CN' }[1]
29
- end
30
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Acme::Client::Resources::Challenges::TLSSNI01 < Acme::Client::Resources::Challenges::Base
4
- CHALLENGE_TYPE = 'tls-sni-01'.freeze
5
- DIGEST = OpenSSL::Digest::SHA256
6
-
7
- def hostname
8
- digest = DIGEST.hexdigest(authorization_key)
9
- "#{digest[0..31]}.#{digest[32..64]}.acme.invalid"
10
- end
11
-
12
- def certificate
13
- self_sign_certificate.certificate
14
- end
15
-
16
- def private_key
17
- self_sign_certificate.private_key
18
- end
19
-
20
- private
21
-
22
- def self_sign_certificate
23
- @self_sign_certificate ||= Acme::Client::SelfSignCertificate.new(subject_alt_names: [hostname])
24
- end
25
- end
@@ -1,37 +0,0 @@
1
- class Acme::Client::Resources::Registration
2
- attr_reader :id, :key, :contact, :uri, :next_uri, :recover_uri, :term_of_service_uri
3
-
4
- def initialize(client, response)
5
- @client = client
6
- @uri = response.headers['location']
7
- assign_links(response.headers['Link'])
8
- assign_attributes(response.body)
9
- end
10
-
11
- def get_terms
12
- return unless @term_of_service_uri
13
-
14
- @client.connection.get(@term_of_service_uri).body
15
- end
16
-
17
- def agree_terms
18
- return true unless @term_of_service_uri
19
-
20
- response = @client.connection.post(@uri, resource: 'reg', agreement: @term_of_service_uri)
21
- response.success?
22
- end
23
-
24
- private
25
-
26
- def assign_links(links)
27
- @next_uri = links['next']
28
- @recover_uri = links['recover']
29
- @term_of_service_uri = links['terms-of-service']
30
- end
31
-
32
- def assign_attributes(body)
33
- @id = body['id']
34
- @key = body['key']
35
- @contact = body['contact']
36
- end
37
- end