letsencrypt-rails-heroku 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1a4a463e9fae1296ef19b8fc1213e38fd046e438
4
+ data.tar.gz: 854e97723f2eaf1c7aa3f90ac941ecc8af4a2423
5
+ SHA512:
6
+ metadata.gz: f161f92843c8a7c4af64acea6b2d606b0ce3e62fccbc9bbdbaeda40d7bf92d6f69ce3615e356382519a9c07b0c696231f2fb2007336cd0bf10dc75ed1af709c6
7
+ data.tar.gz: 36a5bd7ee0404c167a649c95b624c5ce518993ad41335e41db878b05e7544487b8f0466bb02f18ed0b00d50dfacebc3a4f5fc555673ace3c35ceb0e88b0396b2
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem 'acme-client', '~> 0.3.7'
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'
7
+
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "rdoc", "~> 3.12"
11
+ gem "bundler", "~> 1.0"
12
+ gem "juwelier", "~> 2.1.0"
13
+ gem "simplecov", ">= 0"
14
+ end
@@ -0,0 +1,117 @@
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
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ acme-client (0.3.7)
13
+ faraday (~> 0.9, >= 0.9.1)
14
+ json-jwt (~> 1.2, >= 1.2.3)
15
+ activesupport (5.0.0)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (~> 0.7)
18
+ minitest (~> 5.1)
19
+ tzinfo (~> 1.1)
20
+ addressable (2.4.0)
21
+ bindata (2.3.1)
22
+ builder (3.2.2)
23
+ concurrent-ruby (1.0.2)
24
+ descendants_tracker (0.0.4)
25
+ thread_safe (~> 0.3, >= 0.3.1)
26
+ docile (1.1.5)
27
+ erubis (2.7.0)
28
+ excon (0.51.0)
29
+ faraday (0.9.2)
30
+ multipart-post (>= 1.2, < 3)
31
+ git (1.3.0)
32
+ github_api (0.14.4)
33
+ addressable (~> 2.4.0)
34
+ descendants_tracker (~> 0.0.4)
35
+ faraday (~> 0.8, < 0.10)
36
+ hashie (>= 3.4)
37
+ oauth2 (~> 1.0.0)
38
+ hashie (3.4.4)
39
+ heroics (0.0.17)
40
+ erubis (~> 2.0)
41
+ excon
42
+ moneta
43
+ multi_json (>= 1.9.2)
44
+ netrc
45
+ highline (1.7.8)
46
+ i18n (0.7.0)
47
+ json (1.8.3)
48
+ json-jwt (1.6.3)
49
+ activesupport
50
+ bindata
51
+ multi_json (>= 1.3)
52
+ securecompare
53
+ url_safe_base64
54
+ juwelier (2.1.2)
55
+ builder
56
+ bundler (>= 1.0)
57
+ git (>= 1.2.5)
58
+ github_api
59
+ highline (>= 1.6.15)
60
+ nokogiri (>= 1.5.10)
61
+ rake
62
+ rdoc
63
+ semver
64
+ jwt (1.5.4)
65
+ mini_portile2 (2.1.0)
66
+ minitest (5.9.0)
67
+ moneta (0.8.0)
68
+ multi_json (1.12.1)
69
+ multi_xml (0.5.5)
70
+ multipart-post (2.0.0)
71
+ netrc (0.11.0)
72
+ nokogiri (1.6.8)
73
+ mini_portile2 (~> 2.1.0)
74
+ pkg-config (~> 1.1.7)
75
+ oauth2 (1.0.0)
76
+ faraday (>= 0.8, < 0.10)
77
+ jwt (~> 1.0)
78
+ multi_json (~> 1.3)
79
+ multi_xml (~> 0.5)
80
+ rack (~> 1.2)
81
+ pkg-config (1.1.7)
82
+ rack (1.6.4)
83
+ rake (11.2.2)
84
+ rdoc (3.12.2)
85
+ json (~> 1.4)
86
+ securecompare (1.0.0)
87
+ semver (1.0.1)
88
+ shoulda (3.5.0)
89
+ shoulda-context (~> 1.0, >= 1.0.1)
90
+ shoulda-matchers (>= 1.4.1, < 3.0)
91
+ shoulda-context (1.2.1)
92
+ shoulda-matchers (2.8.0)
93
+ activesupport (>= 3.0.0)
94
+ simplecov (0.12.0)
95
+ docile (~> 1.1.0)
96
+ json (>= 1.8, < 3)
97
+ simplecov-html (~> 0.10.0)
98
+ simplecov-html (0.10.0)
99
+ thread_safe (0.3.5)
100
+ tzinfo (1.2.2)
101
+ thread_safe (~> 0.1)
102
+ url_safe_base64 (0.2.2)
103
+
104
+ PLATFORMS
105
+ ruby
106
+
107
+ DEPENDENCIES
108
+ acme-client (~> 0.3.7)
109
+ bundler (~> 1.0)
110
+ juwelier (~> 2.1.0)
111
+ platform-api!
112
+ rdoc (~> 3.12)
113
+ shoulda
114
+ simplecov
115
+
116
+ BUNDLED WITH
117
+ 1.12.5
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2016 Pixie Labs
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,174 @@
1
+ # LetsEncrypt & Rails & Heroku
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/letsencrypt-rails-heroku.svg)](https://badge.fury.io/rb/letsencrypt-rails-heroku)
4
+
5
+ This gem is a complete solution for securing your Ruby on Rails application
6
+ on Heroku using their free SNI-based SSL and LetsEncrypt. It will automatically
7
+ handle renewals and keeping your certificate up to date.
8
+
9
+
10
+ ## Pre-requestives
11
+
12
+ - Whilst it is in beta, you must use the labs feature to enable Heroku's free
13
+ SSL offering:
14
+
15
+ ```
16
+ heroku labs:enable http-sni
17
+ ```
18
+
19
+ - You must be using hobby or professional dynos to use free SNI-based SSL.
20
+
21
+ - You should have already configured your app DNS as per [Heroku's
22
+ documentation](https://devcenter.heroku.com/articles/custom-domains).
23
+
24
+ ## Installation
25
+
26
+ Add the gem to your Gemfile:
27
+
28
+ ```
29
+ # Until the API calls are out of beta, you must manually specify my fork
30
+ # of the Heroku API gem:
31
+ gem 'platform-api', github: 'jalada/platform-api', branch: 'master'
32
+
33
+ gem 'letsencrypt-rails-heroku', group: 'production'
34
+ ```
35
+
36
+ And add it as middleware in your `config/environments/production.rb`:
37
+
38
+ ```
39
+ Rails.application.configure do
40
+ <...>
41
+
42
+ config.middleware.use Letsencrypt::Middleware
43
+
44
+ <...>
45
+ end
46
+ ```
47
+
48
+ ## Configuring
49
+
50
+ By default the gem will try to use the following set of configuration variables,
51
+ which you should set.
52
+
53
+ * `ACME_DOMAIN`: Comma separated list of domains for which you want
54
+ certificates, e.g. `example.com,www.example.com`. Your Heroku app should be
55
+ configured to answer to all these domains, because LetsEncrypt will make a
56
+ request to verify ownership.
57
+ * `ACME_EMAIL`: Your email address, should be valid.
58
+ * `HEROKU_TOKEN`: An API token for this app. See below
59
+ * `HEROKU_APP`: Name of Heroku app e.g. bottomless-cavern-7173
60
+
61
+ The gem itself will temporarily create additional environment variables during
62
+ the challenge / validation process:
63
+
64
+ * `ACME_CHALLENGE_FILENAME`: The path of the file LetsEncrypt will request.
65
+ * `ACME_CHALLENGE_FILE_CONTENT`: The content of that challenge file.
66
+
67
+ ## Creating a Heroku token
68
+
69
+ Use the `heroku-oauth` toolbelt plugin to generate an access token suitable
70
+ for accessing the Heroku API to update the certificates. From within your
71
+ project directory:
72
+
73
+ ```
74
+ > heroku plugins:install heroku-cli-oauth
75
+ > heroku authorizations:create -d "LetsEncrypt"
76
+ Created OAuth authorization.
77
+ ID: <heroku-client-id>
78
+ Description: LetsEncrypt
79
+ Scope: global
80
+ Token: <heroku-token>
81
+ ```
82
+
83
+ Use the output of that to set the token (`HEROKU_TOKEN`).
84
+
85
+ ## Using for the first time
86
+
87
+ After deploying, run `heroku run rake letsencrypt:renew`. Ensure that the
88
+ output looks good:
89
+
90
+ ```
91
+ $ heroku run rake letsencrypt-renew
92
+ Running rake letsencrypt:renew on ⬢ yourapp... ⣷ connecting, run.1234
93
+ Creating account key...Done!
94
+ Registering with LetsEncrypt...Done!
95
+ Setting config vars on Heroku...Done!
96
+ Giving config vars time to change...Done!
97
+ Testing filename works (to bring up app)...done!
98
+ Adding new certificate...Done!
99
+ $
100
+ ```
101
+
102
+ If this is the first time you have used an SNI-based SSL certificate on your
103
+ app, you may need to alter your DNS configuration as per
104
+ [Heroku's instructions](https://devcenter.heroku.com/articles/ssl-beta#change-your-dns-for-all-domains-on-your-app).
105
+
106
+ You can see these details by typing `heroku domains`.
107
+
108
+ ## Adding a scheduled task
109
+
110
+ You should add a scheduled task on Heroku to renew the certificate. The
111
+ scheduled task should be configured to run `rake letsencrypt:renew` as often
112
+ as you want to renew your certificate. Letsencrypt certificates are valid for
113
+ 90 days, but there's no harm renewing them more frequently than that.
114
+
115
+ Heroku Scheduler only lets you run a task as infrequently as once a day, but
116
+ you don't want to renew your SSL certificate every day (you will hit
117
+ [the rate limit](https://letsencrypt.org/docs/rate-limits/)). You can make it
118
+ run less frequently using a shell control statement. For example to renew your
119
+ certificate on the 1st day of every month:
120
+
121
+ ```
122
+ if [ "$(date +%d)" = 01 ]; then rake letsencrypt:renew; fi
123
+ ```
124
+
125
+ Source: [blog.dbrgn.ch](https://blog.dbrgn.ch/2013/10/4/heroku-schedule-weekly-monthly-tasks/)
126
+
127
+ ## Security considerations
128
+
129
+ Suggestions and pull requests are welcome in improving the situation with the
130
+ following security considerations:
131
+
132
+ - When configuring this gem you are baking a non-expiring Heroku API token
133
+ into your applications environment. Your collaborators could use this
134
+ token to impersonate the account it was created with when accessing
135
+ the Heroku API. This is important if your account has access to other apps
136
+ that your collaborators don’t. Additionally, if your application’s environment was
137
+ leaked this would give access to the Heroku API as your user account.
138
+ [More information about Heroku’s API and oAuth](https://devcenter.heroku.com/articles/oauth#direct-authorization).
139
+
140
+ You should create the API token from a suitably locked-down account.
141
+
142
+ - This gem uses two environment variables (`ACME_CHALLENGE_FILENAME` and
143
+ `ACME_CHALLENGE_FILE_CONTENT`) to construct routes and responses in your
144
+ app. These environment variables could be manipulated to spoof URLs on your
145
+ application.
146
+
147
+ The gem performs some cursory checks to make sure the filename is roughly
148
+ what is expected to try and mitigate this.
149
+
150
+ ## To-do list
151
+
152
+ - Persist account key, or at least give the option of using an existing one, so
153
+ we don’t register with LetsEncrypt over and over.
154
+
155
+ - Stop using a fork of the `platform-api` gem once it supports the SNI endpoint
156
+ API calls.
157
+
158
+ - Provide instructions for running the gem decoupled from the app it is
159
+ securing, for the paranoid.
160
+
161
+ ## Contributing
162
+
163
+ - Check out the latest master to make sure the feature hasn't been implemented
164
+ or the bug hasn't been fixed yet.
165
+ - Check out the issue tracker to make sure someone already hasn't requested it
166
+ and/or contributed it.
167
+ - Fork the project.
168
+ - Start a feature/bugfix branch.
169
+ - Commit and push until you are happy with your contribution.
170
+ - Make sure to add tests for it. This is important so I don't break it in a
171
+ future version unintentionally.
172
+ - Please try not to mess with the Rakefile, version, or history. If you want to
173
+ have your own version, or is otherwise necessary, that is fine, but please
174
+ isolate to its own commit so I can cherry-pick around it.
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'juwelier'
15
+ Juwelier::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
17
+ gem.name = "letsencrypt-rails-heroku"
18
+ gem.homepage = "http://github.com/jalada/letsencrypt-rails-heroku"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Automatic LetsEncrypt certs in your Rails app on Heroku}
21
+ gem.description = %Q{This gem automatically handles creation, renewal, and applying SSL certificates from LetsEncrypt to your Heroku account.}
22
+ gem.email = "david@jalada.co.uk"
23
+ gem.authors = ["David Somers"]
24
+
25
+ # dependencies defined in Gemfile
26
+ end
27
+ Juwelier::RubygemsDotOrgTasks.new
28
+
29
+ require 'rake/testtask'
30
+ Rake::TestTask.new(:test) do |test|
31
+ test.libs << 'lib' << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+
36
+ desc "Code coverage detail"
37
+ task :simplecov do
38
+ ENV['COVERAGE'] = "true"
39
+ Rake::Task['test'].execute
40
+ end
41
+
42
+ task :default => :test
43
+
44
+ require 'rdoc/task'
45
+ Rake::RDocTask.new do |rdoc|
46
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
47
+
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = "letsencrypt-rails-heroku #{version}"
50
+ rdoc.rdoc_files.include('README*')
51
+ rdoc.rdoc_files.include('lib/**/*.rb')
52
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.3
@@ -0,0 +1,71 @@
1
+ # Generated by juwelier
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+ # stub: letsencrypt-rails-heroku 0.2.3 ruby lib
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "letsencrypt-rails-heroku"
9
+ s.version = "0.2.3"
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 = ["David Somers"]
14
+ s.date = "2016-08-01"
15
+ s.description = "This gem automatically handles creation, renewal, and applying SSL certificates from LetsEncrypt to your Heroku account."
16
+ s.email = "david@jalada.co.uk"
17
+ s.extra_rdoc_files = [
18
+ "LICENSE.txt",
19
+ "README.md"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "LICENSE.txt",
26
+ "README.md",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "letsencrypt-rails-heroku.gemspec",
30
+ "lib/letsencrypt-rails-heroku.rb",
31
+ "lib/letsencrypt-rails-heroku/letsencrypt.rb",
32
+ "lib/letsencrypt-rails-heroku/middleware.rb",
33
+ "lib/letsencrypt-rails-heroku/railtie.rb",
34
+ "lib/tasks/letsencrypt.rake"
35
+ ]
36
+ s.homepage = "http://github.com/jalada/letsencrypt-rails-heroku"
37
+ s.licenses = ["MIT"]
38
+ s.rubygems_version = "2.5.1"
39
+ s.summary = "Automatic LetsEncrypt certs in your Rails app on Heroku"
40
+
41
+ if s.respond_to? :specification_version then
42
+ s.specification_version = 4
43
+
44
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
45
+ s.add_runtime_dependency(%q<acme-client>, ["~> 0.3.7"])
46
+ s.add_runtime_dependency(%q<platform-api>, [">= 0"])
47
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
48
+ s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
49
+ s.add_development_dependency(%q<bundler>, ["~> 1.0"])
50
+ s.add_development_dependency(%q<juwelier>, ["~> 2.1.0"])
51
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
52
+ else
53
+ s.add_dependency(%q<acme-client>, ["~> 0.3.7"])
54
+ s.add_dependency(%q<platform-api>, [">= 0"])
55
+ s.add_dependency(%q<shoulda>, [">= 0"])
56
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
57
+ s.add_dependency(%q<bundler>, ["~> 1.0"])
58
+ s.add_dependency(%q<juwelier>, ["~> 2.1.0"])
59
+ s.add_dependency(%q<simplecov>, [">= 0"])
60
+ end
61
+ else
62
+ s.add_dependency(%q<acme-client>, ["~> 0.3.7"])
63
+ s.add_dependency(%q<platform-api>, [">= 0"])
64
+ s.add_dependency(%q<shoulda>, [">= 0"])
65
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
66
+ s.add_dependency(%q<bundler>, ["~> 1.0"])
67
+ s.add_dependency(%q<juwelier>, ["~> 2.1.0"])
68
+ s.add_dependency(%q<simplecov>, [">= 0"])
69
+ end
70
+ end
71
+
@@ -0,0 +1,6 @@
1
+ require 'letsencrypt-rails-heroku/letsencrypt'
2
+ require 'letsencrypt-rails-heroku/middleware'
3
+
4
+ if defined?(Rails)
5
+ require 'letsencrypt-rails-heroku/railtie'
6
+ end
@@ -0,0 +1,38 @@
1
+ module Letsencrypt
2
+ class << self
3
+ attr_accessor :configuration
4
+ end
5
+
6
+ def self.configure
7
+ self.configuration ||= Configuration.new
8
+ yield(configuration) if block_given?
9
+ end
10
+
11
+ def self.challenge_configured?
12
+ configuration.acme_challenge_filename.present? &&
13
+ configuration.acme_challenge_filename.starts_with?(".well-known/") &&
14
+ configuration.acme_challenge_file_content.present?
15
+ end
16
+
17
+ class Configuration
18
+ attr_accessor :heroku_token, :heroku_app, :acme_email, :acme_domain, :acme_endpoint
19
+
20
+ # Not settable by user; part of the gem's behaviour.
21
+ attr_reader :acme_challenge_filename, :acme_challenge_file_content
22
+
23
+ def initialize
24
+ @heroku_token = ENV["HEROKU_TOKEN"]
25
+ @heroku_app = ENV["HEROKU_APP"]
26
+ @acme_email = ENV["ACME_EMAIL"]
27
+ @acme_domain = ENV["ACME_DOMAIN"]
28
+ @acme_endpoint = ENV["ACME_ENDPOINT"].presence || 'https://acme-v01.api.letsencrypt.org/'
29
+ @acme_challenge_filename = ENV["ACME_CHALLENGE_FILENAME"]
30
+ @acme_challenge_file_content = ENV["ACME_CHALLENGE_FILE_CONTENT"]
31
+ end
32
+
33
+ def valid?
34
+ heroku_token.present? && heroku_app.present? && acme_email.present? &&
35
+ acme_domain.present?
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,17 @@
1
+ module Letsencrypt
2
+ class Middleware
3
+
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ if Letsencrypt.challenge_configured? && env["PATH_INFO"] == "/#{Letsencrypt.configuration.acme_challenge_filename}"
10
+ return [200, {"Content-Type" => "text/plain"}, [Letsencrypt.configuration.acme_challenge_file_content]]
11
+ end
12
+
13
+ @app.call(env)
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ class LetsencryptRailsHerokuRailtie < Rails::Railtie
2
+ config.before_configuration do
3
+ Letsencrypt.configure
4
+ end
5
+
6
+ rake_tasks do
7
+ load 'tasks/letsencrypt.rake'
8
+ end
9
+ end
@@ -0,0 +1,106 @@
1
+ require 'open-uri'
2
+ require 'openssl'
3
+ require 'acme-client'
4
+ require 'platform-api'
5
+
6
+ namespace :letsencrypt do
7
+
8
+ desc 'Renew your LetsEncrypt certificate'
9
+ task :renew => :environment do
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, acmp_email and acme_domain configured either via a `Letsencrypt.configure` block in an initializer or as environment variables." unless Letsencrypt.configuration.valid?
12
+
13
+ # Set up Heroku client
14
+ heroku = PlatformAPI.connect_oauth Letsencrypt.configuration.heroku_token
15
+ heroku_app = Letsencrypt.configuration.heroku_app
16
+
17
+ # Create a private key
18
+ print "Creating account key..."
19
+ private_key = OpenSSL::PKey::RSA.new(4096)
20
+ puts "Done!"
21
+
22
+ client = Acme::Client.new(private_key: private_key, endpoint: Letsencrypt.configuration.acme_endpoint, connection_options: { request: { open_timeout: 5, timeout: 5 } })
23
+
24
+ print "Registering with LetsEncrypt..."
25
+ registration = client.register(contact: "mailto:#{Letsencrypt.configuration.acme_email}")
26
+
27
+ registration.agree_terms
28
+ puts "Done!"
29
+
30
+ authorization = client.authorize(domain: Letsencrypt.configuration.acme_domain)
31
+ challenge = authorization.http01
32
+
33
+ print "Setting config vars on Heroku..."
34
+ heroku.config_var.update(heroku_app, {
35
+ 'ACME_CHALLENGE_FILENAME' => challenge.filename,
36
+ 'ACME_CHALLENGE_FILE_CONTENT' => challenge.file_content
37
+ })
38
+ puts "Done!"
39
+
40
+ # Wait for request to go through
41
+ print "Giving config vars time to change..."
42
+ sleep(5)
43
+ puts "Done!"
44
+
45
+ # Wait for app to come up
46
+ print "Testing filename works (to bring up app)..."
47
+
48
+ # Get the domain name from Heroku
49
+ hostname = heroku.domain.list(heroku_app).first['hostname']
50
+ open("http://#{hostname}/#{challenge.filename}").read
51
+ puts "done!"
52
+
53
+ # Once you are ready to serve the confirmation request you can proceed.
54
+ challenge.request_verification # => true
55
+ challenge.verify_status # => 'pending'
56
+
57
+ # Wait a bit for the server to make the request, or just blink. It should be fast.
58
+ sleep(5)
59
+
60
+ unless challenge.verify_status == 'valid'
61
+ abort "Problem with verifying challenge."
62
+ end
63
+
64
+ # Unset temporary config vars. We don't care about waiting for this to
65
+ # restart
66
+ heroku.config_var.update(heroku_app, {
67
+ 'ACME_CHALLENGE_FILENAME' => nil,
68
+ 'ACME_CHALLENGE_FILE_CONTENT' => nil
69
+ })
70
+
71
+ # Create CSR
72
+ names = Letsencrypt.configuration.acme_domain.split(',').map(&:strip)
73
+ csr = Acme::Client::CertificateRequest.new(names: names)
74
+
75
+ # Get certificate
76
+ certificate = client.new_certificate(csr) # => #<Acme::Client::Certificate ....>
77
+
78
+ # Send certificates to Heroku via API
79
+
80
+ # First check for existing certificates:
81
+ certificates = heroku.sni_endpoint.list(heroku_app)
82
+
83
+ begin
84
+ if certificates.any?
85
+ print "Updating existing certificate #{certificates[0]['name']}..."
86
+ heroku.sni_endpoint.update(heroku_app, certificates[0]['name'], {
87
+ certificate_chain: certificate.fullchain_to_pem,
88
+ private_key: certificate.request.private_key.to_pem
89
+ })
90
+ puts "Done!"
91
+ else
92
+ print "Adding new certificate..."
93
+ heroku.sni_endpoint.create(heroku_app, {
94
+ certificate_chain: certificate.fullchain_to_pem,
95
+ private_key: certificate.request.private_key.to_pem
96
+ })
97
+ puts "Done!"
98
+ end
99
+ rescue Excon::Error::UnprocessableEntity => e
100
+ warn "Error adding certificate to Heroku. Response from Heroku’s API follows:"
101
+ abort e.response.body
102
+ end
103
+
104
+ end
105
+
106
+ end
metadata ADDED
@@ -0,0 +1,157 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: letsencrypt-rails-heroku
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.3
5
+ platform: ruby
6
+ authors:
7
+ - David Somers
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-08-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: acme-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.3.7
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.3.7
27
+ - !ruby/object:Gem::Dependency
28
+ name: platform-api
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: shoulda
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rdoc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.12'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.12'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: juwelier
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 2.1.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 2.1.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: This gem automatically handles creation, renewal, and applying SSL certificates
112
+ from LetsEncrypt to your Heroku account.
113
+ email: david@jalada.co.uk
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files:
117
+ - LICENSE.txt
118
+ - README.md
119
+ files:
120
+ - ".document"
121
+ - Gemfile
122
+ - Gemfile.lock
123
+ - LICENSE.txt
124
+ - README.md
125
+ - Rakefile
126
+ - VERSION
127
+ - letsencrypt-rails-heroku.gemspec
128
+ - lib/letsencrypt-rails-heroku.rb
129
+ - lib/letsencrypt-rails-heroku/letsencrypt.rb
130
+ - lib/letsencrypt-rails-heroku/middleware.rb
131
+ - lib/letsencrypt-rails-heroku/railtie.rb
132
+ - lib/tasks/letsencrypt.rake
133
+ homepage: http://github.com/jalada/letsencrypt-rails-heroku
134
+ licenses:
135
+ - MIT
136
+ metadata: {}
137
+ post_install_message:
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubyforge_project:
153
+ rubygems_version: 2.5.1
154
+ signing_key:
155
+ specification_version: 4
156
+ summary: Automatic LetsEncrypt certs in your Rails app on Heroku
157
+ test_files: []