acme-client 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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