acme-client 0.3.0 → 0.3.1

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