letsencrypt-rails-heroku 1.2.0 → 2.0.3

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
- SHA1:
3
- metadata.gz: c3f97585c884a70e519fdc84a79276ab7abb845e
4
- data.tar.gz: 04ecb09cedcc720fbfb2eb87175f68165eab842f
2
+ SHA256:
3
+ metadata.gz: 5f589e4dde9bc04d66b094ae2d1fd43a34b87c3224c616e98bd3a7c08facfbca
4
+ data.tar.gz: 0b28b8ce30bee194a6df29900c84c086338fd70eb40fa8e2680f6ebbe1f63616
5
5
  SHA512:
6
- metadata.gz: 9b52c79ddaf3970f102d6c24b4baa210fb78ec162a83e44ee1cf858dbdfd5acef0498d5a0e2f8050d83442b6abecc1d34f39753bd8ef8643083138ecd4729208
7
- data.tar.gz: c9d16e37682bfd2649b9e5a42aa587e574e31fc9aff5f6e4454bcf41092931998ebe3bd2362c7f6c37ffc2b7690483035a2b12fba462a641e04f549b6a6edade
6
+ metadata.gz: af35ed069d85e13ffebc88a94fa341056658050bf542812492735b48b49654d0f21c0d28820c3875f2af658d68db2e0495a8ef8b93579d1be75aa503ba6e72df
7
+ data.tar.gz: 1fd670635000f7dd4585a2b87155cd7799169f4a72aa6dc3b4ac20c9ed266ea43d25750283f49a43d6d1eaec32dccd100b42ab461bb2130751bffdd3bbf15b85
@@ -1,3 +1,54 @@
1
+ # 2.0.3
2
+
3
+ - Raise an error when the HTTP challenge is nil (#71). Thanks
4
+ [@mashedkeyboard](https://github.com/mashedkeyboard)!
5
+ - Return the response body on a 403 Forbidden from Heroku, not that it's
6
+ that useful.
7
+ - Relax `platform-api` version requirements, as it works OK with v3 too.
8
+
9
+ # 2.0.2
10
+
11
+ - Include OpenSSL::SSL::SSLError as a valid error we retry for when waiting
12
+ for the app to come back up.
13
+
14
+ # 2.0.1
15
+
16
+ - Fixed a typo that broke renewals with existing certificates.
17
+
18
+ # 2.0.0
19
+
20
+ Thanks to [@mashedkeyboard](https://github.com/mashedkeyboard) for their
21
+ work on ACME v2, saving registration, and DNS-based validation.
22
+
23
+ - *BREAKING* You must indicate your acceptance of Let's Encrypt's terms
24
+ and conditions by setting the `ACME_TERMS_AGREED` configuration variable.
25
+ - *BREAKING* Removed `ACME_ENDPOINT` environment variable reference. We never
26
+ documented that we support alternative endpoints, and we never tested it,
27
+ and the gem is called *letsencrypt*-rails-heroku, so let's not pretend.
28
+ Please get in touch if you were using this configuration variable, we'd
29
+ like to hear from you! Psst; you can still set `acme_directory` when
30
+ configuring the gem in an initializer.
31
+ - Use version 2 of the ACME API, paving the way for DNS validation.
32
+ - Save private key & key ID variables after registering with Let's Encrypt.
33
+ This will create two new permanent environment variables, `ACME_PRIVATE_KEY`
34
+ and `ACME_KEY_ID`.
35
+
36
+ # 1.2.1
37
+
38
+ - Update `rack` and `nokogiri` dependencies due to reported vulnerabilities
39
+ in those libraries. Note that these don't affect letsencrypt-rails-heroku
40
+ directly.
41
+ [CVE-2018-16471](https://nvd.nist.gov/vuln/detail/CVE-2018-16471),
42
+ [CVE-2016-4658](https://nvd.nist.gov/vuln/detail/CVE-2016-4658),
43
+ [CVE-2017-5029](https://nvd.nist.gov/vuln/detail/CVE-2017-5029),
44
+ [CVE-2018-14404](https://nvd.nist.gov/vuln/detail/CVE-2018-14404),
45
+ [CVE-2017-18258](https://nvd.nist.gov/vuln/detail/CVE-2017-18258),
46
+ [CVE-2017-9050](https://nvd.nist.gov/vuln/detail/CVE-2017-9050).
47
+
48
+ - Stop using [jalada/platform-api](https://github.com/jalada/platform-api)
49
+ because the newer version of the official version supports the API endpoints
50
+ we need now.
51
+
1
52
  # 1.2.0
2
53
 
3
54
  - Support SSL Endpoint configuration, as well as the default SNI.
data/Gemfile CHANGED
@@ -1,9 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- gem 'acme-client', '~> 0.4.0'
4
- # SNI endpoints not supported yet:
5
- # <https://github.com/heroku/platform-api/issues/49>
6
- gem 'platform-api', github: 'jalada/platform-api', branch: 'master'
3
+ gem 'acme-client', '~> 2.0'
4
+ gem 'platform-api', '>= 2.2', '< 4'
7
5
 
8
6
  group :development do
9
7
  gem "shoulda", ">= 0"
@@ -1,48 +1,43 @@
1
- GIT
2
- remote: git://github.com/jalada/platform-api.git
3
- revision: 45ddb3c1a7e2c7f85d979c0791db18e99affb237
4
- branch: master
5
- specs:
6
- platform-api (0.8.0)
7
- heroics (~> 0.0.17)
8
-
9
1
  GEM
10
2
  remote: https://rubygems.org/
11
3
  specs:
12
- acme-client (0.4.1)
13
- faraday (~> 0.9, >= 0.9.1)
14
- activesupport (5.0.0)
4
+ acme-client (2.0.7)
5
+ faraday (>= 0.17, < 2.0.0)
6
+ activesupport (6.0.3.3)
15
7
  concurrent-ruby (~> 1.0, >= 1.0.2)
16
- i18n (~> 0.7)
8
+ i18n (>= 0.7, < 2)
17
9
  minitest (~> 5.1)
18
10
  tzinfo (~> 1.1)
19
- addressable (2.4.0)
20
- builder (3.2.2)
21
- concurrent-ruby (1.0.2)
11
+ zeitwerk (~> 2.2, >= 2.2.2)
12
+ addressable (2.7.0)
13
+ public_suffix (>= 2.0.2, < 5.0)
14
+ builder (3.2.4)
15
+ concurrent-ruby (1.1.7)
22
16
  descendants_tracker (0.0.4)
23
17
  thread_safe (~> 0.3, >= 0.3.1)
24
- docile (1.1.5)
18
+ docile (1.3.2)
25
19
  erubis (2.7.0)
26
- excon (0.51.0)
27
- faraday (0.9.2)
20
+ excon (0.76.0)
21
+ faraday (1.0.1)
28
22
  multipart-post (>= 1.2, < 3)
29
- git (1.3.0)
30
- github_api (0.14.5)
31
- addressable (~> 2.4.0)
23
+ git (1.7.0)
24
+ rchardet (~> 1.8)
25
+ github_api (0.19.0)
26
+ addressable (~> 2.4)
32
27
  descendants_tracker (~> 0.0.4)
33
- faraday (~> 0.8, < 0.10)
34
- hashie (>= 3.4)
28
+ faraday (>= 0.8, < 2)
29
+ hashie (~> 3.5, >= 3.5.2)
35
30
  oauth2 (~> 1.0)
36
- hashie (3.4.6)
37
- heroics (0.0.17)
31
+ hashie (3.6.0)
32
+ heroics (0.1.1)
38
33
  erubis (~> 2.0)
39
34
  excon
40
35
  moneta
41
36
  multi_json (>= 1.9.2)
42
- netrc
43
- highline (1.7.8)
44
- i18n (0.7.0)
45
- json (1.8.3)
37
+ highline (2.0.3)
38
+ i18n (1.8.5)
39
+ concurrent-ruby (~> 1.0)
40
+ json (1.8.6)
46
41
  juwelier (2.1.3)
47
42
  builder
48
43
  bundler (>= 1.13)
@@ -53,53 +48,59 @@ GEM
53
48
  rake
54
49
  rdoc
55
50
  semver
56
- jwt (1.5.6)
57
- mini_portile2 (2.1.0)
58
- minitest (5.9.0)
59
- moneta (0.8.0)
60
- multi_json (1.12.1)
51
+ jwt (2.2.2)
52
+ mini_portile2 (2.4.0)
53
+ minitest (5.14.2)
54
+ moneta (1.0.0)
55
+ multi_json (1.15.0)
61
56
  multi_xml (0.6.0)
62
- multipart-post (2.0.0)
63
- netrc (0.11.0)
64
- nokogiri (1.6.8.1)
65
- mini_portile2 (~> 2.1.0)
66
- oauth2 (1.2.0)
67
- faraday (>= 0.8, < 0.10)
68
- jwt (~> 1.0)
57
+ multipart-post (2.1.1)
58
+ nokogiri (1.10.10)
59
+ mini_portile2 (~> 2.4.0)
60
+ oauth2 (1.4.4)
61
+ faraday (>= 0.8, < 2.0)
62
+ jwt (>= 1.0, < 3.0)
69
63
  multi_json (~> 1.3)
70
64
  multi_xml (~> 0.5)
71
65
  rack (>= 1.2, < 3)
72
- rack (2.0.1)
73
- rake (12.0.0)
66
+ platform-api (3.0.0)
67
+ heroics (~> 0.1.1)
68
+ moneta (~> 1.0.0)
69
+ rate_throttle_client (~> 0.1.0)
70
+ public_suffix (4.0.6)
71
+ rack (2.2.3)
72
+ rake (13.0.1)
73
+ rate_throttle_client (0.1.2)
74
+ rchardet (1.8.0)
74
75
  rdoc (3.12.2)
75
76
  json (~> 1.4)
76
77
  semver (1.0.1)
77
- shoulda (3.5.0)
78
- shoulda-context (~> 1.0, >= 1.0.1)
79
- shoulda-matchers (>= 1.4.1, < 3.0)
80
- shoulda-context (1.2.1)
81
- shoulda-matchers (2.8.0)
82
- activesupport (>= 3.0.0)
83
- simplecov (0.12.0)
84
- docile (~> 1.1.0)
85
- json (>= 1.8, < 3)
86
- simplecov-html (~> 0.10.0)
87
- simplecov-html (0.10.0)
88
- thread_safe (0.3.5)
89
- tzinfo (1.2.2)
78
+ shoulda (4.0.0)
79
+ shoulda-context (~> 2.0)
80
+ shoulda-matchers (~> 4.0)
81
+ shoulda-context (2.0.0)
82
+ shoulda-matchers (4.4.1)
83
+ activesupport (>= 4.2.0)
84
+ simplecov (0.19.0)
85
+ docile (~> 1.1)
86
+ simplecov-html (~> 0.11)
87
+ simplecov-html (0.12.3)
88
+ thread_safe (0.3.6)
89
+ tzinfo (1.2.7)
90
90
  thread_safe (~> 0.1)
91
+ zeitwerk (2.4.0)
91
92
 
92
93
  PLATFORMS
93
94
  ruby
94
95
 
95
96
  DEPENDENCIES
96
- acme-client (~> 0.4.0)
97
+ acme-client (~> 2.0)
97
98
  bundler (~> 1.0)
98
99
  juwelier (~> 2.1.0)
99
- platform-api!
100
+ platform-api (>= 2.2, < 4)
100
101
  rdoc (~> 3.12)
101
102
  shoulda
102
103
  simplecov
103
104
 
104
105
  BUNDLED WITH
105
- 1.13.6
106
+ 1.17.3
@@ -1,4 +1,4 @@
1
- Copyright (c) 2016 Pixie Labs
1
+ Copyright (c) 2020 Pixie Labs
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # LetsEncrypt & Rails & Heroku
2
2
 
3
+ ### Deprecated: Heroku now support [free automated SSL certificates for paid dynos](https://devcenter.heroku.com/articles/automated-certificate-management), you should use that instead of this gem unless your situation is covered by the [known limitations](https://devcenter.heroku.com/articles/automated-certificate-management#known-limitations) of ACM, e.g. your app runs in Heroku Private Spaces.
4
+
5
+
3
6
  [![Gem Version](https://badge.fury.io/rb/letsencrypt-rails-heroku.svg)](https://badge.fury.io/rb/letsencrypt-rails-heroku)
4
7
 
5
8
  This gem is a complete solution for securing your Ruby on Rails application
@@ -14,7 +17,9 @@ repository.
14
17
 
15
18
  ## Requirements
16
19
 
17
- - You must be using hobby or professional dynos to use free SNI-based SSL. Find out more on [Heroku's documentation page about SSL](https://devcenter.heroku.com/articles/ssl).
20
+ - You must be using hobby or professional dynos to use free SNI-based SSL.
21
+ Find out more on [Heroku's documentation page about
22
+ SSL](https://devcenter.heroku.com/articles/ssl).
18
23
 
19
24
  - You should have already configured your app DNS as per [Heroku's
20
25
  documentation](https://devcenter.heroku.com/articles/custom-domains).
@@ -24,10 +29,6 @@ repository.
24
29
  Add the gem to your Gemfile:
25
30
 
26
31
  ```
27
- # Until the new API calls are generally available, you must manually specify my fork
28
- # of the Heroku API gem:
29
- gem 'platform-api', git: 'https://github.com/jalada/platform-api', branch: 'master'
30
-
31
32
  gem 'letsencrypt-rails-heroku', group: 'production'
32
33
  ```
33
34
 
@@ -60,19 +61,24 @@ end
60
61
 
61
62
  ## Configuring
62
63
 
63
- By default the gem will try to use the following set of configuration variables,
64
- which you should set.
64
+ By default the gem will try to use the following set of configuration
65
+ variables. You must set:
66
+
67
+ * `ACME_EMAIL`: Your email address, should be valid.
68
+ * `ACME_TERMS_AGREED`: Existence of this environment variable represents your
69
+ agreement to [Let's Encrypt's terms of service](https://letsencrypt.org/repository/).
70
+ * `HEROKU_TOKEN`: An API token for this app. See below
71
+ * `HEROKU_APP`: Name of Heroku app e.g. bottomless-cavern-7173
72
+
73
+ You can also set:
65
74
 
66
75
  * `ACME_DOMAIN`: Comma separated list of domains for which you want
67
76
  certificates, e.g. `example.com,www.example.com`. Your Heroku app should be
68
- configured to answer to all these domains, because LetsEncrypt will make a
77
+ configured to answer to all these domains, because Let's Encrypt will make a
69
78
  request to verify ownership.
70
79
 
71
80
  If you leave this blank, the gem will try and use the Heroku API to get a
72
81
  list of configured domains for your app, and verify all of them.
73
- * `ACME_EMAIL`: Your email address, should be valid.
74
- * `HEROKU_TOKEN`: An API token for this app. See below
75
- * `HEROKU_APP`: Name of Heroku app e.g. bottomless-cavern-7173
76
82
  * `SSL_TYPE`: Optional: One of `sni` or `endpoint`, defaults to `sni`.
77
83
  `endpoint` requires your app to have an
78
84
  [SSL endpoint addon](https://elements.heroku.com/addons/ssl) configured.
@@ -83,6 +89,14 @@ the challenge / validation process:
83
89
  * `ACME_CHALLENGE_FILENAME`: The path of the file LetsEncrypt will request.
84
90
  * `ACME_CHALLENGE_FILE_CONTENT`: The content of that challenge file.
85
91
 
92
+ It will also create two permanent environment variables after the first run:
93
+
94
+ * `ACME_PRIVATE_KEY`: Private key used to create requests for certificates.
95
+ * `ACME_KEY_ID`: Key ID assigned to your private key by Let's Encrypt.
96
+
97
+ If you remove these, a new account will be created and new environment
98
+ variables will be set.
99
+
86
100
  ## Creating a Heroku token
87
101
 
88
102
  Use the `heroku-oauth` toolbelt plugin to generate an access token suitable
@@ -126,10 +140,13 @@ You can see these details by typing `heroku domains`.
126
140
 
127
141
  ## Adding a scheduled task
128
142
 
129
- You should add a scheduled task on Heroku to renew the certificate. The
130
- scheduled task should be configured to run `rake letsencrypt:renew` as often
131
- as you want to renew your certificate. Letsencrypt certificates are valid for
132
- 90 days, but there's no harm renewing them more frequently than that.
143
+ You should add a scheduled task on Heroku to renew the certificate. If you
144
+ are unfamiliar with how to do this, take a look at [Heroku's documentation
145
+ on their scheduler addon](https://devcenter.heroku.com/articles/scheduler).
146
+
147
+ The scheduled task should be configured to run `rake letsencrypt:renew` as
148
+ often as you want to renew your certificate. Letsencrypt certificates are valid
149
+ for 90 days, but there's no harm renewing them more frequently than that.
133
150
 
134
151
  Heroku Scheduler only lets you run a task as infrequently as once a day, but
135
152
  you don't want to renew your SSL certificate every day (you will hit
@@ -138,7 +155,7 @@ run less frequently using a shell control statement. For example to renew your
138
155
  certificate on the 1st day of every month:
139
156
 
140
157
  ```
141
- if [ "$(date +%d)" = 01 ]; then rake letsencrypt:renew; fi
158
+ if [ "$(date +%d)" = 01 ]; then bundle exec rake letsencrypt:renew; fi
142
159
  ```
143
160
 
144
161
  Source: [blog.dbrgn.ch](https://blog.dbrgn.ch/2013/10/4/heroku-schedule-weekly-monthly-tasks/)
@@ -148,12 +165,13 @@ Source: [blog.dbrgn.ch](https://blog.dbrgn.ch/2013/10/4/heroku-schedule-weekly-m
148
165
  Suggestions and pull requests are welcome in improving the situation with the
149
166
  following security considerations:
150
167
 
151
- - When configuring this gem you must add a non-expiring Heroku API token
152
- into your application environment. Your collaborators could use this
153
- token to impersonate the account it was created with when accessing
154
- the Heroku API. This is important if your account has access to other apps
155
- that your collaborators don’t. Additionally, if your application environment was
156
- leaked this would give the attacker access to the Heroku API as your user account.
168
+ - When configuring this gem you must add a non-expiring Heroku API token into
169
+ your application environment. Your collaborators could use this token to
170
+ impersonate the account it was created with when accessing the Heroku API.
171
+ This is important if your account has access to other apps that your
172
+ collaborators don’t. Additionally, if your application environment was
173
+ leaked this would give the attacker access to the Heroku API as your user
174
+ account.
157
175
  [More information about Heroku’s API and oAuth](https://devcenter.heroku.com/articles/oauth#direct-authorization).
158
176
 
159
177
  You should create the API token from a suitably locked-down account.
@@ -170,17 +188,17 @@ following security considerations:
170
188
 
171
189
  ### Common name invalid errors (security certificate is from *.herokuapp.com)
172
190
 
173
- Your domain is still configured as a CNAME or ALIAS to `your-app.herokuapp.com`. Check the output of `heroku domains` matches your DNS configuration. When you add an SNI cert to an app for the first time [the DNS target changes](https://devcenter.heroku.com/articles/custom-domains#view-existing-domains).
191
+ Your domain is still configured as a CNAME or ALIAS to
192
+ `your-app.herokuapp.com`. Check the output of `heroku domains` matches your DNS
193
+ configuration. When you add an SNI cert to an app for the first time
194
+ [the DNS target changes](https://devcenter.heroku.com/articles/custom-domains#view-existing-domains).
174
195
 
175
196
  ## To-do list
176
197
 
177
198
  - Persist account key, or at least give the option of using an existing one, so
178
199
  we don’t register with LetsEncrypt over and over.
179
200
 
180
- - Stop using a fork of the `platform-api` gem once it supports the SNI endpoint
181
- API calls. [See issue #49 of the platform-api gem](https://github.com/heroku/platform-api/issues/49).
182
-
183
- - Provide instructions for running the gem decoupled from the app it is
201
+ - Provide instructions for running the gem decoupled from the app it is
184
202
  securing, for the paranoid.
185
203
 
186
204
  ## Contributing
@@ -202,4 +220,5 @@ Your domain is still configured as a CNAME or ALIAS to `your-app.herokuapp.com`.
202
220
 
203
221
  1. Bump the version: `rake version:bump:{major,minor,patch}`.
204
222
  2. Update `CHANGELOG.md` & commit.
205
- 3. Use `rake release` to regenerate gemspec, push a tag to git, and push a new `.gem` to rubygems.org
223
+ 3. Use `rake release` to regenerate gemspec, push a tag to git, and push a new
224
+ `.gem` to rubygems.org.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.0
1
+ 2.0.3
@@ -2,19 +2,20 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: letsencrypt-rails-heroku 1.2.0 ruby lib
5
+ # stub: letsencrypt-rails-heroku 2.0.3 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
- s.name = "letsencrypt-rails-heroku"
9
- s.version = "1.2.0"
8
+ s.name = "letsencrypt-rails-heroku".freeze
9
+ s.version = "2.0.3"
10
10
 
11
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
- s.require_paths = ["lib"]
13
- s.authors = ["Pixie Labs", "David Somers", "Abigail McPhillips"]
14
- s.date = "2017-03-03"
15
- s.description = "This gem automatically handles creation, renewal, and applying SSL certificates from LetsEncrypt to your Heroku account."
16
- s.email = "team@pixielabs.io"
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib".freeze]
13
+ s.authors = ["Pixie Labs".freeze, "David Somers".freeze, "Abigail McPhillips".freeze]
14
+ s.date = "2020-10-07"
15
+ s.description = "This gem automatically handles creation, renewal, and applying SSL certificates from LetsEncrypt to your Heroku account.".freeze
16
+ s.email = "team@pixielabs.io".freeze
17
17
  s.extra_rdoc_files = [
18
+ "CHANGELOG.md",
18
19
  "LICENSE.txt",
19
20
  "README.md"
20
21
  ]
@@ -35,39 +36,39 @@ Gem::Specification.new do |s|
35
36
  "lib/letsencrypt-rails-heroku/railtie.rb",
36
37
  "lib/tasks/letsencrypt.rake"
37
38
  ]
38
- s.homepage = "https://github.com/pixielabs/letsencrypt-rails-heroku"
39
- s.licenses = ["MIT"]
40
- s.rubygems_version = "2.5.1"
41
- s.summary = "Automatic LetsEncrypt certificates in your Rails app on Heroku"
39
+ s.homepage = "https://github.com/pixielabs/letsencrypt-rails-heroku".freeze
40
+ s.licenses = ["MIT".freeze]
41
+ s.rubygems_version = "3.0.6".freeze
42
+ s.summary = "Automatic LetsEncrypt certificates in your Rails app on Heroku".freeze
42
43
 
43
44
  if s.respond_to? :specification_version then
44
45
  s.specification_version = 4
45
46
 
46
47
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
47
- s.add_runtime_dependency(%q<acme-client>, ["~> 0.4.0"])
48
- s.add_runtime_dependency(%q<platform-api>, [">= 0"])
49
- s.add_development_dependency(%q<shoulda>, [">= 0"])
50
- s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
51
- s.add_development_dependency(%q<bundler>, ["~> 1.0"])
52
- s.add_development_dependency(%q<juwelier>, ["~> 2.1.0"])
53
- s.add_development_dependency(%q<simplecov>, [">= 0"])
48
+ s.add_runtime_dependency(%q<acme-client>.freeze, ["~> 2.0"])
49
+ s.add_runtime_dependency(%q<platform-api>.freeze, [">= 2.2", "< 4"])
50
+ s.add_development_dependency(%q<shoulda>.freeze, [">= 0"])
51
+ s.add_development_dependency(%q<rdoc>.freeze, ["~> 3.12"])
52
+ s.add_development_dependency(%q<bundler>.freeze, ["~> 1.0"])
53
+ s.add_development_dependency(%q<juwelier>.freeze, ["~> 2.1.0"])
54
+ s.add_development_dependency(%q<simplecov>.freeze, [">= 0"])
54
55
  else
55
- s.add_dependency(%q<acme-client>, ["~> 0.4.0"])
56
- s.add_dependency(%q<platform-api>, [">= 0"])
57
- s.add_dependency(%q<shoulda>, [">= 0"])
58
- s.add_dependency(%q<rdoc>, ["~> 3.12"])
59
- s.add_dependency(%q<bundler>, ["~> 1.0"])
60
- s.add_dependency(%q<juwelier>, ["~> 2.1.0"])
61
- s.add_dependency(%q<simplecov>, [">= 0"])
56
+ s.add_dependency(%q<acme-client>.freeze, ["~> 2.0"])
57
+ s.add_dependency(%q<platform-api>.freeze, [">= 2.2", "< 4"])
58
+ s.add_dependency(%q<shoulda>.freeze, [">= 0"])
59
+ s.add_dependency(%q<rdoc>.freeze, ["~> 3.12"])
60
+ s.add_dependency(%q<bundler>.freeze, ["~> 1.0"])
61
+ s.add_dependency(%q<juwelier>.freeze, ["~> 2.1.0"])
62
+ s.add_dependency(%q<simplecov>.freeze, [">= 0"])
62
63
  end
63
64
  else
64
- s.add_dependency(%q<acme-client>, ["~> 0.4.0"])
65
- s.add_dependency(%q<platform-api>, [">= 0"])
66
- s.add_dependency(%q<shoulda>, [">= 0"])
67
- s.add_dependency(%q<rdoc>, ["~> 3.12"])
68
- s.add_dependency(%q<bundler>, ["~> 1.0"])
69
- s.add_dependency(%q<juwelier>, ["~> 2.1.0"])
70
- s.add_dependency(%q<simplecov>, [">= 0"])
65
+ s.add_dependency(%q<acme-client>.freeze, ["~> 2.0"])
66
+ s.add_dependency(%q<platform-api>.freeze, [">= 2.2", "< 4"])
67
+ s.add_dependency(%q<shoulda>.freeze, [">= 0"])
68
+ s.add_dependency(%q<rdoc>.freeze, ["~> 3.12"])
69
+ s.add_dependency(%q<bundler>.freeze, ["~> 1.0"])
70
+ s.add_dependency(%q<juwelier>.freeze, ["~> 2.1.0"])
71
+ s.add_dependency(%q<simplecov>.freeze, [">= 0"])
71
72
  end
72
73
  end
73
74
 
@@ -1,12 +1,18 @@
1
1
  module Letsencrypt
2
2
  module Error
3
- # Exception raised when LetsEncrypt encounters an issue verifying the challenge.
3
+ # LetsEncrypt encountered an issue verifying the challenge.
4
4
  class VerificationError < StandardError; end
5
- # Exception raised when challenge URL is not available.
5
+ # LetsEncrypt encountered an issue finalizing the order.
6
+ class FinalizationError < StandardError; end
7
+ # Challenge URL is not available.
6
8
  class ChallengeUrlError < StandardError; end
7
- # Exception raised on timeout of challenge verification.
9
+ # Domain verification took longer than we'd like.
8
10
  class VerificationTimeoutError < StandardError; end
9
- # Exception raised when an error occurs adding the certificate to Heroku.
11
+ # Order finalization took longer than we'd like.
12
+ class FinalizationTimeoutError < StandardError; end
13
+ # Error adding the certificate to Heroku.
10
14
  class HerokuCertificateError < StandardError; end
15
+ # No HTTP challenge available from certificate provider.
16
+ class NoHTTPChallengeError < StandardError; end
11
17
  end
12
18
  end
@@ -14,26 +14,36 @@ module Letsencrypt
14
14
  configuration.acme_challenge_file_content
15
15
  end
16
16
 
17
+ def self.registered?
18
+ configuration.acme_private_key && configuration.acme_key_id
19
+ end
20
+
17
21
  class Configuration
18
22
  attr_accessor :heroku_token, :heroku_app, :acme_email, :acme_domain,
19
- :acme_endpoint, :ssl_type
23
+ :acme_directory, :ssl_type, :acme_terms_agreed
20
24
 
21
25
  # Not settable by user; part of the gem's behaviour.
22
- attr_reader :acme_challenge_filename, :acme_challenge_file_content
26
+ attr_reader :acme_challenge_filename, :acme_challenge_file_content,
27
+ :acme_private_key, :acme_key_id
23
28
 
24
29
  def initialize
25
30
  @heroku_token = ENV["HEROKU_TOKEN"]
26
31
  @heroku_app = ENV["HEROKU_APP"]
27
32
  @acme_email = ENV["ACME_EMAIL"]
28
33
  @acme_domain = ENV["ACME_DOMAIN"]
29
- @acme_endpoint = ENV["ACME_ENDPOINT"] || 'https://acme-v01.api.letsencrypt.org/'
34
+ @acme_directory = 'https://acme-v02.api.letsencrypt.org/directory'
35
+ @acme_terms_agreed = ENV["ACME_TERMS_AGREED"]
30
36
  @ssl_type = ENV["SSL_TYPE"] || 'sni'
37
+
31
38
  @acme_challenge_filename = ENV["ACME_CHALLENGE_FILENAME"]
32
39
  @acme_challenge_file_content = ENV["ACME_CHALLENGE_FILE_CONTENT"]
40
+
41
+ @acme_private_key = ENV["ACME_PRIVATE_KEY"]
42
+ @acme_key_id = ENV["ACME_KEY_ID"]
33
43
  end
34
44
 
35
45
  def valid?
36
- heroku_token && heroku_app && acme_email
46
+ heroku_token && heroku_app && acme_email && acme_terms_agreed
37
47
  end
38
48
  end
39
49
  end
@@ -8,24 +8,48 @@ namespace :letsencrypt do
8
8
  desc 'Renew your LetsEncrypt certificate'
9
9
  task :renew do
10
10
  # Check configuration looks OK
11
- abort "letsencrypt-rails-heroku is configured incorrectly. Are you missing an environment variable or other configuration? You should have a heroku_token, heroku_app and acme_email configured either via a `Letsencrypt.configure` block in an initializer or as environment variables." unless Letsencrypt.configuration.valid?
11
+ abort "letsencrypt-rails-heroku is configured incorrectly. Are you missing an environment variable or other configuration? You should have heroku_token, heroku_app, acme_email and acme_terms_agreed configured either via a `Letsencrypt.configure` block in an initializer or as environment variables." unless Letsencrypt.configuration.valid?
12
12
 
13
13
  # Set up Heroku client
14
14
  heroku = PlatformAPI.connect_oauth Letsencrypt.configuration.heroku_token
15
15
  heroku_app = Letsencrypt.configuration.heroku_app
16
16
 
17
- # Create a private key
18
- print "Creating account key..."
19
- private_key = OpenSSL::PKey::RSA.new(4096)
20
- puts "Done!"
17
+ if Letsencrypt.registered?
18
+ puts "Using existing registration details"
19
+ private_key = OpenSSL::PKey::RSA.new(Letsencrypt.configuration.acme_private_key)
20
+ key_id = Letsencrypt.configuration.acme_key_id
21
+ else
22
+ # Create a private key
23
+ print "Creating account key..."
24
+ private_key = OpenSSL::PKey::RSA.new(4096)
25
+ puts "Done!"
21
26
 
22
- client = Acme::Client.new(private_key: private_key, endpoint: Letsencrypt.configuration.acme_endpoint, connection_options: { request: { open_timeout: 5, timeout: 5 } })
27
+ client = Acme::Client.new(private_key: private_key,
28
+ directory: Letsencrypt.configuration.acme_directory,
29
+ connection_options: {
30
+ request: {
31
+ open_timeout: 5,
32
+ timeout: 5
33
+ }
34
+ })
23
35
 
24
- print "Registering with LetsEncrypt..."
25
- registration = client.register(contact: "mailto:#{Letsencrypt.configuration.acme_email}")
36
+ print "Registering with LetsEncrypt..."
37
+ account = client.new_account(contact: "mailto:#{Letsencrypt.configuration.acme_email}",
38
+ terms_of_service_agreed: true)
26
39
 
27
- registration.agree_terms
28
- puts "Done!"
40
+ key_id = account.kid
41
+ puts "Done!"
42
+ print "Saving account details as configuration variables..."
43
+ heroku.config_var.update(heroku_app,
44
+ 'ACME_PRIVATE_KEY' => private_key.to_pem,
45
+ 'ACME_KEY_ID' => account.kid)
46
+ puts "Done!"
47
+ end
48
+
49
+ # Make a new Acme::Client with whichever private_key & key_id we ended up with.
50
+ client = Acme::Client.new(private_key: private_key,
51
+ directory: Letsencrypt.configuration.acme_directory,
52
+ kid: key_id)
29
53
 
30
54
  domains = []
31
55
  if Letsencrypt.configuration.acme_domain
@@ -36,11 +60,14 @@ namespace :letsencrypt do
36
60
  puts "Using #{domains.length} configured Heroku domain(s) for this app..."
37
61
  end
38
62
 
39
- domains.each do |domain|
40
- puts "Performing verification for #{domain}:"
63
+ order = client.new_order(identifiers: domains)
41
64
 
42
- authorization = client.authorize(domain: domain)
43
- challenge = authorization.http01
65
+ order.authorizations.each do |authorization|
66
+ puts "Performing verification for #{authorization.domain}:"
67
+
68
+ challenge = authorization.http
69
+
70
+ raise Letsencrypt::Error::NoHTTPChallengeError, "No HTTP challenge was given by Let's Encrypt for #{authorization.domain}, and letsencrypt-rails-heroku does not currently support other challenge types." unless challenge
44
71
 
45
72
  print "Setting config vars on Heroku..."
46
73
  heroku.config_var.update(heroku_app, {
@@ -62,7 +89,7 @@ namespace :letsencrypt do
62
89
 
63
90
  begin
64
91
  open("http://#{hostname}/#{challenge.filename}").read
65
- rescue OpenURI::HTTPError, RuntimeError => e
92
+ rescue OpenSSL::SSL::SSLError, OpenURI::HTTPError, RuntimeError => e
66
93
  raise e if e.is_a?(RuntimeError) && !e.message.include?("redirection forbidden")
67
94
  if Time.now - start_time <= 60
68
95
  puts "Error fetching challenge, retrying... #{e.message}"
@@ -78,24 +105,23 @@ namespace :letsencrypt do
78
105
 
79
106
  print "Giving LetsEncrypt some time to verify..."
80
107
  # Once you are ready to serve the confirmation request you can proceed.
81
- challenge.request_verification # => true
82
- challenge.verify_status # => 'pending'
108
+ challenge.request_validation
83
109
 
84
110
  start_time = Time.now
85
-
86
- while challenge.verify_status == 'pending'
111
+ while challenge.status == 'pending'
87
112
  if Time.now - start_time >= 30
88
113
  failure_message = "Failed - timed out waiting for challenge verification."
89
114
  raise Letsencrypt::Error::VerificationTimeoutError, failure_message
90
115
  end
91
- sleep(3)
116
+ sleep(2)
117
+ challenge.reload
92
118
  end
93
119
 
94
120
  puts "Done!"
95
121
 
96
- unless challenge.verify_status == 'valid'
122
+ unless challenge.status == 'valid'
97
123
  puts "Problem verifying challenge."
98
- failure_message = "Status: #{challenge.verify_status}, Error: #{challenge.error}"
124
+ failure_message = "Status: #{challenge.status}, Error: #{challenge.error}"
99
125
  raise Letsencrypt::Error::VerificationError, failure_message
100
126
  end
101
127
 
@@ -110,10 +136,33 @@ namespace :letsencrypt do
110
136
  })
111
137
 
112
138
  # Create CSR
113
- csr = Acme::Client::CertificateRequest.new(names: domains)
139
+ csr_private_key = OpenSSL::PKey::RSA.new 4096
140
+ csr = Acme::Client::CertificateRequest.new(names: domains,
141
+ private_key: csr_private_key)
114
142
 
143
+ print "Asking LetsEncrypt to finalize our certificate order..."
115
144
  # Get certificate
116
- certificate = client.new_certificate(csr) # => #<Acme::Client::Certificate ....>
145
+ order.finalize(csr: csr)
146
+
147
+ # Wait for order to process
148
+ start_time = Time.now
149
+ while order.status == 'processing'
150
+ if Time.now - start_time >= 30
151
+ failure_message = "Failed - timed out waiting for order finalization"
152
+ raise Letsencrypt::Error::FinalizationTimeoutError, failure_message
153
+ end
154
+ sleep(2)
155
+ order.reload
156
+ end
157
+
158
+ puts "Done!"
159
+
160
+ unless order.status == 'valid'
161
+ failure_message = "Problem finalizing order - status: #{order.status}"
162
+ raise Letsencrypt::Error::FinalizationError, failure_message
163
+ end
164
+
165
+ certificate = order.certificate # => PEM-formatted certificate
117
166
 
118
167
  # Send certificates to Heroku via API
119
168
 
@@ -124,28 +173,34 @@ namespace :letsencrypt do
124
173
  heroku.ssl_endpoint
125
174
  end
126
175
 
127
- # First check for existing certificates:
128
- certificates = endpoint.list(heroku_app)
176
+ certificate_info = {
177
+ certificate_chain: certificate,
178
+ private_key: csr_private_key.to_pem
179
+ }
180
+
181
+ # Fetch existing certificate from Heroku (if any). We just use the first
182
+ # one; if someone has more than one, they're probably not actually using
183
+ # this gem. Could also be an error?
184
+ existing_certificate = endpoint.list(heroku_app)[0]
129
185
 
130
186
  begin
131
- if certificates.any?
132
- print "Updating existing certificate #{certificates[0]['name']}..."
133
- endpoint.update(heroku_app, certificates[0]['name'], {
134
- certificate_chain: certificate.fullchain_to_pem,
135
- private_key: certificate.request.private_key.to_pem
136
- })
187
+ if existing_certificate
188
+ print "Updating existing certificate #{existing_certificate['name']}..."
189
+ endpoint.update(heroku_app, existing_certificate['name'], certificate_info)
137
190
  puts "Done!"
138
191
  else
139
192
  print "Adding new certificate..."
140
- endpoint.create(heroku_app, {
141
- certificate_chain: certificate.fullchain_to_pem,
142
- private_key: certificate.request.private_key.to_pem
143
- })
193
+ endpoint.create(heroku_app, certificate_info)
144
194
  puts "Done!"
145
195
  end
146
196
  rescue Excon::Error::UnprocessableEntity => e
147
197
  warn "Error adding certificate to Heroku. Response from Heroku’s API follows:"
148
198
  raise Letsencrypt::Error::HerokuCertificateError, e.response.body
199
+ rescue Excon::Error::Forbidden => e
200
+ warn "Error adding certificate to Heroku, expected an OK response status, got a '403 Forbidden'. Response follows:"
201
+ puts e.response.body
202
+ # Re-raise for now.
203
+ raise e
149
204
  end
150
205
 
151
206
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: letsencrypt-rails-heroku
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pixie Labs
8
8
  - David Somers
9
9
  - Abigail McPhillips
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2017-03-03 00:00:00.000000000 Z
13
+ date: 2020-10-07 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: acme-client
@@ -18,28 +18,34 @@ dependencies:
18
18
  requirements:
19
19
  - - "~>"
20
20
  - !ruby/object:Gem::Version
21
- version: 0.4.0
21
+ version: '2.0'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - "~>"
27
27
  - !ruby/object:Gem::Version
28
- version: 0.4.0
28
+ version: '2.0'
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: platform-api
31
31
  requirement: !ruby/object:Gem::Requirement
32
32
  requirements:
33
33
  - - ">="
34
34
  - !ruby/object:Gem::Version
35
- version: '0'
35
+ version: '2.2'
36
+ - - "<"
37
+ - !ruby/object:Gem::Version
38
+ version: '4'
36
39
  type: :runtime
37
40
  prerelease: false
38
41
  version_requirements: !ruby/object:Gem::Requirement
39
42
  requirements:
40
43
  - - ">="
41
44
  - !ruby/object:Gem::Version
42
- version: '0'
45
+ version: '2.2'
46
+ - - "<"
47
+ - !ruby/object:Gem::Version
48
+ version: '4'
43
49
  - !ruby/object:Gem::Dependency
44
50
  name: shoulda
45
51
  requirement: !ruby/object:Gem::Requirement
@@ -116,6 +122,7 @@ email: team@pixielabs.io
116
122
  executables: []
117
123
  extensions: []
118
124
  extra_rdoc_files:
125
+ - CHANGELOG.md
119
126
  - LICENSE.txt
120
127
  - README.md
121
128
  files:
@@ -138,7 +145,7 @@ homepage: https://github.com/pixielabs/letsencrypt-rails-heroku
138
145
  licenses:
139
146
  - MIT
140
147
  metadata: {}
141
- post_install_message:
148
+ post_install_message:
142
149
  rdoc_options: []
143
150
  require_paths:
144
151
  - lib
@@ -153,9 +160,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
160
  - !ruby/object:Gem::Version
154
161
  version: '0'
155
162
  requirements: []
156
- rubyforge_project:
157
- rubygems_version: 2.5.1
158
- signing_key:
163
+ rubygems_version: 3.0.6
164
+ signing_key:
159
165
  specification_version: 4
160
166
  summary: Automatic LetsEncrypt certificates in your Rails app on Heroku
161
167
  test_files: []