heroku_ssl 0.6.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 00f612a6491420af98a63a207d0d1d17a6a20bbf
4
+ data.tar.gz: 327c380d45de0e67ff691fa886bb5abd8d0ccd12
5
+ SHA512:
6
+ metadata.gz: ca5e94d5682c154c1961976f27c47d9a47eb5cb17a1674a6d3c7305e29f32a800d97da5eec682b34a3d58cefb5afa65a4892b9ce666583c63318757260639fa3
7
+ data.tar.gz: 68eff01513b554ef21f7f3af737d19f0dda30666577fb9c74221221adcecb97ed2bd2cfc60696afe1a9c11af9228fa5a965230f989f481902952383700d1b9b1
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2016 Kai Marshland
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.
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # Heroku SSL
2
+ With the advent of free SSL from [Let's Encrypt](https://letsencrypt.org/), SSL should be as easy as clicking a button.
3
+
4
+ ## Usage on Heroku
5
+ Add this gem to your gemfile, then deploy it to heroku.
6
+ Then, you can simply run `rake ssl:update_heroku_certs`
7
+
8
+ This should prompt you for everything you need to update your shiny new SSL certificate!
9
+ The only thing left to do will be to [configure your DNS correctly](https://devcenter.heroku.com/articles/ssl-endpoint#dns-and-domain-configuration).
10
+ You'll also want to make sure that the domain had been added to heroku with `heroku domains:add [your domain]`
11
+
12
+ ## Usage outside of Heroku
13
+ Although designed for Heroku, it can generate certificates on other providers.
14
+ To do so, on your server, run `rake ssl:generate_certs`.
15
+ This will print a JSON encoded set of PEM keys to the console.
16
+ You can download these (you will likely want to use `privkey` and `fullchain` as your public and private keys respectively)
17
+ and add them to your own servers and configure the DNS yourself.
18
+
19
+ ## Installation
20
+ Add this line to your application's Gemfile:
21
+
22
+ ```ruby
23
+ gem 'heroku-ssl'
24
+ ```
25
+
26
+ Or, to test the bleeding edge version:
27
+ ```ruby
28
+ gem 'heroku_ssl', git: 'https://github.com/KMarshland/heroku-ssl.git'
29
+ ```
30
+
31
+ And then execute:
32
+ ```bash
33
+ $ bundle install
34
+ ```
35
+
36
+ It also requires one of the following:
37
+ - The global variable `$redis` is set
38
+ - The environment variable `REDIS_URL` is set
39
+ - The environment variable `HEROKU_REDIS_URL` is set
40
+
41
+ ## Contributing
42
+ Submit a pull request!
43
+
44
+ ## License
45
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'HerokuSsl'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+ require 'bundler/gem_tasks'
25
+
26
+ require 'rake/testtask'
27
+
28
+ Rake::TestTask.new(:test) do |t|
29
+ t.libs << 'lib'
30
+ t.libs << 'test'
31
+ t.pattern = 'test/**/*_test.rb'
32
+ t.verbose = false
33
+ end
34
+
35
+
36
+ task default: :test
@@ -0,0 +1,2 @@
1
+ //= link_directory ../javascripts/heroku_ssl .js
2
+ //= link_directory ../stylesheets/heroku_ssl .css
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,2 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,5 @@
1
+ module HerokuSsl
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+ end
5
+ end
@@ -0,0 +1,12 @@
1
+ require_dependency "heroku_ssl/application_controller"
2
+
3
+ module HerokuSsl
4
+ class HerokuSslController < ApplicationController
5
+
6
+ def challenge
7
+ response = HerokuSsl::redis_instance.get("ssl-challenge-#{params[:challenge]}")
8
+ render text: response
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,4 @@
1
+ module HerokuSsl
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module HerokuSsl
2
+ module HerokuSslHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module HerokuSsl
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module HerokuSsl
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: 'from@example.com'
4
+ layout 'mailer'
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module HerokuSsl
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Heroku ssl</title>
5
+ <%= stylesheet_link_tag "heroku_ssl/application", media: "all" %>
6
+ <%= javascript_include_tag "heroku_ssl/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ Rails.application.routes.draw do
2
+
3
+ get '.well-known/acme-challenge/:challenge' => 'heroku_ssl/heroku_ssl#challenge'
4
+
5
+ end
@@ -0,0 +1,5 @@
1
+ module HerokuSsl
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace HerokuSsl
4
+ end
5
+ end
@@ -0,0 +1,187 @@
1
+ require 'openssl'
2
+ require 'acme-client'
3
+
4
+ module HerokuSsl
5
+
6
+ class << self
7
+ def endpoint
8
+ # Use 'https://acme-staging.api.letsencrypt.org/' for development
9
+
10
+ 'https://acme-v01.api.letsencrypt.org/'
11
+ end
12
+
13
+ def redis_instance
14
+
15
+ return $redis if $redis.present?
16
+ return $heroku_ssl_redis if $heroku_ssl_redis.present?
17
+
18
+ redis_url = ENV['REDIS_URL'] || ENV['HEROKU_REDIS_URL'] || 'redis://127.0.0.1:6379/0'
19
+ $heroku_ssl_redis = Redis.new(:url => redis_url)
20
+
21
+ end
22
+
23
+ # Where the certificates are stored
24
+ def cert_directory
25
+ Rails.root.join('certs')
26
+ end
27
+
28
+ def write(filename, content)
29
+ FileUtils.mkdir_p cert_directory
30
+
31
+ File.write(cert_directory.join(filename), content)
32
+ end
33
+
34
+ def read(filename)
35
+ FileUtils.mkdir_p cert_directory
36
+
37
+ return nil unless File.exists? cert_directory.join(filename)
38
+
39
+ File.read cert_directory.join(filename)
40
+ end
41
+
42
+ def gen_unless_exists(filename)
43
+ existing = read filename
44
+ return existing if existing.present?
45
+
46
+ created = yield filename
47
+ write filename, created
48
+
49
+ created
50
+ end
51
+
52
+ #forcibly regenerates the account private key
53
+ def regenerate_private_key
54
+ @private_key = OpenSSL::PKey::RSA.new(4096)
55
+ write('account.pem', @private_key.export)
56
+
57
+ @private_key
58
+ end
59
+
60
+ #returns any existing account private key; only generates a new one if none exist
61
+ def private_key
62
+ return @private_key if @private_key.present?
63
+
64
+ pem = read "#{Rails.env}/account.pem"
65
+ if pem.present?
66
+ @private_key = OpenSSL::PKey::RSA.new(pem)
67
+ else
68
+ regenerate_private_key
69
+ end
70
+ end
71
+
72
+
73
+ def client
74
+ @client ||= Acme::Client.new(
75
+ private_key: private_key,
76
+ endpoint: endpoint,
77
+ connection_options: {
78
+ request: {
79
+ open_timeout: 5,
80
+ timeout: 5
81
+ }
82
+ }
83
+ )
84
+ end
85
+
86
+ #adds a contact for a domain
87
+ def register(email)
88
+ # If the private key is not known to the server, we need to register it for the first time.
89
+ registration = client.register(contact: "mailto:#{email}")
90
+
91
+ # 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)
92
+ registration.agree_terms
93
+ rescue Acme::Client::Error::Malformed => e
94
+ if e.message == 'Registration key is already in use'
95
+ puts 'Already registered'
96
+ else
97
+ raise e
98
+ end
99
+ end
100
+
101
+ def authorize(domain)
102
+ if domain.is_a? Array
103
+ domain.each do |dom|
104
+ authorize dom
105
+ end
106
+
107
+ return
108
+ end
109
+
110
+ authorization = client.authorize(domain: domain)
111
+
112
+ return if authorization.status == 'valid'
113
+
114
+ # This example is using the http-01 challenge type. Other challenges are dns-01 or tls-sni-01.
115
+ challenge = authorization.http01
116
+
117
+ redis_instance.set("ssl-challenge-#{challenge.filename.split('/').last}", challenge.file_content)
118
+ redis_instance.expire("ssl-challenge-#{challenge.filename.split('/').last}", 5.minutes)
119
+
120
+ challenge.request_verification
121
+
122
+ # Wait a bit for the server to make the request, or just blink. It should be fast.
123
+ sleep(1)
124
+
125
+ status = nil
126
+ begin
127
+ # May sometimes give an error, for mysterious reasons
128
+ status = challenge.authorization.verify_status
129
+ rescue
130
+ end
131
+
132
+ #alternate method to read authorization status
133
+ status = client.authorize(domain: domain).status if status == 'pending' || status.blank?
134
+
135
+ unless status == 'valid'
136
+ puts challenge.error
137
+ raise "Did not verify client. Status is still #{status}"
138
+ end
139
+ end
140
+
141
+ def try_authorize(domain, retries=1)
142
+ begin
143
+ authorize domain
144
+ return true
145
+ rescue RuntimeError => e
146
+ puts e.message
147
+
148
+ if retries > 0
149
+ puts 'Retrying domain authorization...'
150
+ return try_authorize domain, retries-1
151
+ else
152
+ return false
153
+ end
154
+ end
155
+ end
156
+
157
+ def request_certificate(domain)
158
+ unless try_authorize domain
159
+ puts 'Domain authorization failed. Aborting operation'
160
+ return
161
+ end
162
+
163
+ csr = Acme::Client::CertificateRequest.new(names: [*domain])
164
+
165
+ # We can now request a certificate. You can pass anything that returns
166
+ # a valid DER encoded CSR when calling to_der on it. For example an
167
+ # OpenSSL::X509::Request should work too.
168
+ certificate = client.new_certificate(csr)
169
+
170
+ {
171
+ privkey: certificate.request.private_key.to_pem,
172
+ cert: certificate.to_pem,
173
+ chain: certificate.chain_to_pem,
174
+ fullchain: certificate.fullchain_to_pem
175
+ }
176
+
177
+ end
178
+
179
+ def create_dh_params
180
+ gen_unless_exists 'dhparam.pem' do |filename|
181
+ `openssl dhparam -out #{filename} 4096`
182
+ end
183
+ end
184
+
185
+ end
186
+
187
+ end
@@ -0,0 +1,3 @@
1
+ module HerokuSsl
2
+ VERSION = '0.6.0'
3
+ end
data/lib/heroku_ssl.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "heroku_ssl/engine"
2
+ require "heroku_ssl/ssl"
3
+
4
+ module HerokuSsl
5
+
6
+ end
@@ -0,0 +1,162 @@
1
+
2
+ namespace :heroku_ssl do
3
+
4
+ task :update_certs do
5
+ STDOUT.puts 'Once your app has been deployed to Heroku, hit enter.'
6
+
7
+ STDIN.gets
8
+
9
+ email = get_email
10
+ domains = get_domains
11
+ app = get_app
12
+
13
+ puts "Attempting to generate ssl certificates for #{app} (registering #{domains} to #{email})"
14
+
15
+ #generate the certs on the server
16
+ output = `unset RUBYOPT; heroku run rake heroku_ssl:generate_certs #{email} #{domains} --app #{app}`
17
+
18
+ #read out the certs to temporary files
19
+ if output.include? '~~ GENERATED CERTIFICATES START ~~'
20
+ puts 'Successfully generated certificates! Attempting to update Heroku DNS'
21
+
22
+ output = output.split('~~ GENERATED CERTIFICATES START ~~').last
23
+ .split('~~ GENERATED CERTIFICATES END ~~').first
24
+ output = JSON(output)
25
+
26
+ File.open('fullchain.pem', 'wb') do |file|
27
+ file.write output['fullchain']
28
+ end
29
+
30
+ File.open('privkey.pem', 'wb') do |file|
31
+ file.write output['privkey']
32
+ end
33
+
34
+ # update heroku certs
35
+ # RUBYOPT breaks the heroku command for some reason, so you have to unset it
36
+ `unset RUBYOPT; heroku certs:update fullchain.pem privkey.pem --app #{get_app} --confirm #{get_app}`
37
+
38
+ # clean up
39
+ File.delete('fullchain.pem', 'privkey.pem')
40
+
41
+ puts 'Successfully updated Heroku SSL certificates! Now you just need to make sure your DNS is configured to point as follows: '
42
+ puts `unset RUBYOPT; heroku domains`.split("\n")[4..-1].join("\n")
43
+ else
44
+ puts 'Full log: '
45
+ puts output
46
+ puts ''
47
+
48
+ puts 'Could not generate certificates. Please try again later or try running `heroku run rake heroku_ssl:generate_certs` directly'
49
+ end
50
+
51
+ end
52
+
53
+ task :generate_certs do
54
+ email = (ARGV[1] || '').strip
55
+ email = get_email if email.blank?
56
+
57
+ puts "Registering #{email}"
58
+ HerokuSsl::register email
59
+
60
+ domain = ARGV[2..-1]
61
+ domain = get_domains if domain.blank?
62
+
63
+ puts "Authorizing and generating certificates for #{domain}"
64
+
65
+ certs = HerokuSsl::request_certificate domain
66
+
67
+ if certs.present?
68
+ STDOUT.puts '~~ GENERATED CERTIFICATES START ~~'
69
+ STDOUT.puts JSON(certs)
70
+ STDOUT.puts '~~ GENERATED CERTIFICATES END ~~'
71
+ end
72
+ end
73
+
74
+ def get_email
75
+ return @email if @email.present?
76
+
77
+ @email = `git config user.email`
78
+ @email.strip! if @email.present?
79
+
80
+ default_prompt = ''
81
+ default_prompt = " [#{@email}]" if @email.present?
82
+
83
+ new_email = nil
84
+ while new_email.blank?
85
+ STDOUT.puts "Enter your email#{default_prompt}: "
86
+ new_email = STDIN.gets
87
+
88
+ if new_email.blank?
89
+ new_email = @email
90
+ else
91
+ new_email.strip!
92
+ end
93
+ end
94
+
95
+ @email = new_email
96
+ end
97
+
98
+ def get_domains
99
+ return @domain if @domain.present?
100
+
101
+ domains = `unset RUBYOPT; heroku domains`.split("\n").select(&:present?)[5..-1]
102
+ domains.map! do |domain|
103
+ domain.split(/\s+/).first
104
+ end
105
+ @domain = domains.join ' '
106
+
107
+ default_prompt = ''
108
+ default_prompt = " [#{@domain}]" if @domain.present?
109
+
110
+ new_domain = nil
111
+ while new_domain.blank?
112
+ STDOUT.puts "Enter the domain to register#{default_prompt}: "
113
+ new_domain = STDIN.gets
114
+
115
+ if new_domain.blank?
116
+ new_domain = @domain
117
+ else
118
+ new_domain.strip!
119
+ end
120
+ end
121
+
122
+ @domain = new_domain
123
+ end
124
+
125
+ def get_app
126
+ return @app if @app.present?
127
+
128
+ @apps = @apps || `unset RUBYOPT; heroku apps`.split("\n")
129
+ remotes = `git remote -v`.split("\n").map do |r|
130
+ r.split("\t").last
131
+ end
132
+
133
+ @apps.each do |app|
134
+ remotes.each do |remote|
135
+ if remote.include? app
136
+ @app = app
137
+ break
138
+ end
139
+ end
140
+ break if @app.present?
141
+ end
142
+
143
+ default_prompt = ''
144
+ default_prompt = " [#{@app}]" if @app.present?
145
+
146
+ new_app = nil
147
+ while new_app.blank?
148
+ STDOUT.puts "Enter the heroku app#{default_prompt}: "
149
+ new_app = STDIN.gets
150
+
151
+ if new_app.blank?
152
+ new_app = @app
153
+ else
154
+ new_app.strip!
155
+ end
156
+ end
157
+
158
+ @app = new_app
159
+ end
160
+
161
+ end
162
+
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: heroku_ssl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.0
5
+ platform: ruby
6
+ authors:
7
+ - Kai Marshland
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-11-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 4.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 4.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: acme-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.4.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.4.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: redis
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: Designed for Heroku, but can be adapted for other hosts as well
56
+ email:
57
+ - kaimarshland@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - MIT-LICENSE
63
+ - README.md
64
+ - Rakefile
65
+ - app/assets/config/heroku_ssl_manifest.js
66
+ - app/assets/javascripts/heroku_ssl/application.js
67
+ - app/assets/javascripts/heroku_ssl/heroku_ssl.js
68
+ - app/assets/stylesheets/heroku_ssl/application.css
69
+ - app/assets/stylesheets/heroku_ssl/heroku_ssl.css
70
+ - app/controllers/heroku_ssl/application_controller.rb
71
+ - app/controllers/heroku_ssl/heroku_ssl_controller.rb
72
+ - app/helpers/heroku_ssl/application_helper.rb
73
+ - app/helpers/heroku_ssl/heroku_ssl_helper.rb
74
+ - app/jobs/heroku_ssl/application_job.rb
75
+ - app/mailers/heroku_ssl/application_mailer.rb
76
+ - app/models/heroku_ssl/application_record.rb
77
+ - app/views/layouts/heroku_ssl/application.html.erb
78
+ - config/routes.rb
79
+ - lib/heroku_ssl.rb
80
+ - lib/heroku_ssl/engine.rb
81
+ - lib/heroku_ssl/ssl.rb
82
+ - lib/heroku_ssl/version.rb
83
+ - lib/tasks/heroku_ssl_tasks.rake
84
+ homepage: https://github.com/KMarshland/heroku-ssl
85
+ licenses:
86
+ - MIT
87
+ metadata: {}
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 2.5.1
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Quickly and easily add SSL to a Rails App with Let's Encrypt
108
+ test_files: []