acme-client 0.3.0 → 0.3.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b4f8844db80f42dfbebde13f4834adff81b31a6c
4
- data.tar.gz: aac066e3a86278081ad327072318cf659065760d
3
+ metadata.gz: 056d35b4c628c93ad60a134ab46044cdbc5f9e38
4
+ data.tar.gz: d90a2d072631c7f68e9ea783e1a8878bc844314f
5
5
  SHA512:
6
- metadata.gz: 0d8ae92a14464b33d91f07e127c35016987c4b912cb65edfa2d416f1471127f3a6ea8df093ca349778a45cf745d5caeae734d8c2f2f93b6a029deb04d7841ff0
7
- data.tar.gz: 7e16c99dfedf9620fb9f1879ce89fba8bbc6f547f4c589b2177e9ee96966074f35bb85ff4c0afa9edd94ec9d3203dc05f8fb5568c57754300e7ed2ea1a9b7752
6
+ metadata.gz: e8b93b207b8016d1464f9e9f4fa20e7e303554eee08ac01eed069de34db084318dfb440e78d1ef07978bbd91ae385c8eaae3350b18b5f806c8a170d6bb776a0a
7
+ data.tar.gz: a23f0b2e33d7434abfe4e77bcb51e4d4d867cff629781f820704a484c89c0a6abfab028099542936c539b81c0e11d0abd9a05da4a96485425a91cb1034847ba0
data/README.md CHANGED
@@ -3,18 +3,37 @@
3
3
 
4
4
  `acme-client` is a client implementation of the [ACME](https://letsencrypt.github.io/acme-spec) protocol in Ruby.
5
5
 
6
- You can find the server reference implementation for ACME server [here](https://github.com/letsencrypt/boulder) and also the a reference [client](https://github.com/letsencrypt/letsencrypt) in python.
6
+ You can find the ACME reference implementations of the [server](https://github.com/letsencrypt/boulder) in Go and the [client](https://github.com/letsencrypt/letsencrypt) in Python.
7
7
 
8
- ACME is part of the [Letsencrypt](https://letsencrypt.org/) project, that are working hard at encrypting all the things.
8
+ ACME is part of the [Letsencrypt](https://letsencrypt.org/) project, which goal is to provide free SSL/TLS certificates with automation of the acquiring and renewal process.
9
+
10
+ ## Installation
11
+
12
+ Via Rubygems:
13
+
14
+ $ gem install acme-client
15
+
16
+ Or add it to a Gemfile:
17
+
18
+ ```ruby
19
+ gem 'acme-client'
20
+ ```
9
21
 
10
22
  ## Usage
11
23
 
24
+ ### Register client
25
+
26
+ In order to authenticate our client, we have to create an account for it.
27
+
12
28
  ```ruby
13
29
  # We're going to need a private key.
14
30
  require 'openssl'
15
- private_key = OpenSSL::PKey::RSA.new(2048)
31
+ private_key = OpenSSL::PKey::RSA.new(4096)
16
32
 
17
33
  # We need an ACME server to talk to, see github.com/letsencrypt/boulder
34
+ # WARNING: This endpoint is the production endpoint, which is rate limited and will produce valid certificates.
35
+ # You should probably use the staging endpoint for all your experimentation:
36
+ # endpoint = 'https://acme-staging.api.letsencrypt.org/'
18
37
  endpoint = 'https://acme-v01.api.letsencrypt.org/'
19
38
 
20
39
  # Initialize the client
@@ -24,18 +43,24 @@ client = Acme::Client.new(private_key: private_key, endpoint: endpoint)
24
43
  # If the private key is not known to the server, we need to register it for the first time.
25
44
  registration = client.register(contact: 'mailto:contact@example.com')
26
45
 
27
- # You'll may need to agree to the term (that's up the to the server to require it or not but boulder does by default)
46
+ # You may need to agree to the terms of service (that's up the to the server to require it or not but boulder does by default)
28
47
  registration.agree_terms
48
+ ```
49
+
50
+ ### Authorize for domain
29
51
 
30
- # Let's try to optain a certificate for example.org
52
+ Before you are able to obtain certificates for your domain, you have to prove that you are in control of it.
31
53
 
32
- # We need to prove that we control the domain using one of the challenges method.
54
+ ```ruby
33
55
  authorization = client.authorize(domain: 'example.org')
34
56
 
35
- # For now the only challenge method supprted by the client is http-01.
57
+ # This example is using the http-01 challenge type. Other challenges are dns-01 or tls-sni-01.
36
58
  challenge = authorization.http01
37
59
 
38
- # The http-01 method will require you to response to an HTTP request.
60
+ # The http-01 method will require you to respond to a HTTP request.
61
+
62
+ # You can retrieve the challenge token
63
+ challenge.token # => "some_token"
39
64
 
40
65
  # You can retrieve the expected path for the file.
41
66
  challenge.filename # => ".well-known/acme-challenge/:some_token"
@@ -43,38 +68,51 @@ challenge.filename # => ".well-known/acme-challenge/:some_token"
43
68
  # You can generate the body of the expected response.
44
69
  challenge.file_content # => 'string token and JWK thumbprint'
45
70
 
46
- # You can send no Content-Type at all but if you send one it has to be 'text/plain'.
71
+ # You are not required to send a Content-Type. This method will return the right Content-Type should you decide to include one.
47
72
  challenge.content_type
48
73
 
49
- # Save the file. We'll create a public directory to serve it from, and we'll creating the challenge directory.
74
+ # Save the file. We'll create a public directory to serve it from, and inside it we'll create the challenge file.
50
75
  FileUtils.mkdir_p( File.join( 'public', File.dirname( challenge.filename ) ) )
51
76
 
52
- # Then writing the file
77
+ # We'll write the content of the file
53
78
  File.write( File.join( 'public', challenge.filename), challenge.file_content )
54
79
 
55
- # The challenge file can be server with a Ruby webserver such as run a webserver in another console. You may need to forward ports on your router
56
- #ruby -run -e httpd public -p 8080 --bind-address 0.0.0.0
80
+ # Optionally save the challenge for use at another time (eg: by a background job processor)
81
+ File.write('challenge', challenge.to_h.to_json)
82
+
83
+ # The challenge file can be served with a Ruby webserver.
84
+ # You can run a webserver in another console for that purpose. You may need to forward ports on your router.
85
+ #
86
+ # $ ruby -run -e httpd public -p 8080 --bind-address 0.0.0.0
57
87
 
88
+ # Load a saved challenge. This is only required if you need to reuse a saved challenge as outlined above.
89
+ challenge = client.challenge_from_hash(JSON.parse(File.read('challenge')))
58
90
 
59
91
  # Once you are ready to serve the confirmation request you can proceed.
60
92
  challenge.request_verification # => true
61
93
  challenge.verify_status # => 'pending'
62
94
 
63
- # Wait a bit for the server to make the request, or really just blink, it should be fast.
95
+ # Wait a bit for the server to make the request, or just blink. It should be fast.
64
96
  sleep(1)
65
97
 
66
98
  challenge.verify_status # => 'valid'
99
+ ```
100
+
101
+ ### Obtain a certificate
67
102
 
103
+ Now that your account is authorized for the domain, you should be able to obtain a certificate for it.
104
+
105
+ ```ruby
68
106
  # We're going to need a certificate signing request. If not explicitly
69
107
  # specified, the first name listed becomes the common name.
70
108
  csr = Acme::Client::CertificateRequest.new(names: %w[example.org www.example.org])
71
109
 
72
- # We can now request a certificate, you can pass anything that returns
73
- # a valid DER encoded CSR when calling to_der on it, for example a
74
- # OpenSSL::X509::Request too.
110
+ # We can now request a certificate. You can pass anything that returns
111
+ # a valid DER encoded CSR when calling to_der on it. For example an
112
+ # OpenSSL::X509::Request should work too.
75
113
  certificate = client.new_certificate(csr) # => #<Acme::Client::Certificate ....>
76
114
 
77
- # Save the certificate and key
115
+ # Save the certificate and the private key to files
78
116
  File.write("privkey.pem", certificate.request.private_key.to_pem)
79
117
  File.write("cert.pem", certificate.to_pem)
80
118
  File.write("chain.pem", certificate.chain_to_pem)
data/acme-client.gemspec CHANGED
@@ -15,6 +15,8 @@ Gem::Specification.new do |spec|
15
15
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
16
  spec.require_paths = ['lib']
17
17
 
18
+ spec.required_ruby_version = '>= 2.1.0'
19
+
18
20
  spec.add_development_dependency 'bundler', '~> 1.6', '>= 1.6.9'
19
21
  spec.add_development_dependency 'rake', '~> 10.0'
20
22
  spec.add_development_dependency 'rspec', '~> 3.3', '>= 3.3.0'
data/lib/acme/client.rb CHANGED
@@ -68,6 +68,17 @@ class Acme::Client
68
68
  end
69
69
  end
70
70
 
71
+ def challenge_from_hash(attributes)
72
+ case attributes.fetch('type')
73
+ when 'http-01'
74
+ Acme::Client::Resources::Challenges::HTTP01.new(self, attributes)
75
+ when 'dns-01'
76
+ Acme::Client::Resources::Challenges::DNS01.new(self, attributes)
77
+ when 'tls-sni-01'
78
+ Acme::Client::Resources::Challenges::TLSSNI01.new(self, attributes)
79
+ end
80
+ end
81
+
71
82
  private
72
83
 
73
84
  def fetch_chain(response, limit = 10)
@@ -19,6 +19,10 @@ class Acme::Client::Resources::Challenges::Base
19
19
  response.success?
20
20
  end
21
21
 
22
+ def to_h
23
+ { 'token' => token, 'uri' => uri, 'type' => challenge_type }
24
+ end
25
+
22
26
  private
23
27
 
24
28
  def challenge_type
@@ -1,5 +1,5 @@
1
1
  module Acme
2
2
  class Client
3
- VERSION = '0.3.0'.freeze
3
+ VERSION = '0.3.1'.freeze
4
4
  end
5
5
  end
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: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charles Barbier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-29 00:00:00.000000000 Z
11
+ date: 2016-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -191,7 +191,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
191
191
  requirements:
192
192
  - - ">="
193
193
  - !ruby/object:Gem::Version
194
- version: '0'
194
+ version: 2.1.0
195
195
  required_rubygems_version: !ruby/object:Gem::Requirement
196
196
  requirements:
197
197
  - - ">="