rails-letsencrypt 0.5.5 → 0.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a5aeeebd0dd776f4fcc05752ea8b438878398d79
4
- data.tar.gz: fdff5b40a3526cbff50a83c7811b5a9970ccdf19
2
+ SHA256:
3
+ metadata.gz: 803822003496186ae2408760697b9ee88f136051e1cfed2ec6364ac6cfd1d90e
4
+ data.tar.gz: 8132cddcd9d2c6ceb6b039aec68a517873994041ef798a74d396fa92f59240f5
5
5
  SHA512:
6
- metadata.gz: d8759789aae5935de7951c65bb1281de060485ed0ff0d5532f825cd1bb6a0087a2fab3e659c94d42dc76a81f5bf3da7a974eda33e8214d6d94d8f8666a86903f
7
- data.tar.gz: d092e84fd25d14dd4e22546f922d9e74cce4a9357f5f0d1948f43c444fa1c8453170fbf313d51817648fcabefccf75e9c6b7ca9529a9bf3a45ef1d7d8d88f2d9
6
+ metadata.gz: 36ef4db53e0d1652115908850deb8a229f5566964b01415fd6ad4399f47401bd493fa556a4de6c21d7406cf17b2b7f009aef44ec98d4753ebaa24508ab63b8ab
7
+ data.tar.gz: 6fe213a8aaa548b1cead27f95aa56771aa5924b182d52902d5b584e17fe526674ba945ebb2b834c374be73f0ef335f42afa9b6d4a280806b6dd65c1106a1e924
data/README.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  Provide manageable Let's Encrypt Certificate for Rails.
4
4
 
5
+ ## Requirement
6
+
7
+ * Rails 5+
8
+ * Ruby 2.5+
9
+
5
10
  ## Installation
6
11
 
7
12
  Puts this in your Gemfile:
@@ -56,6 +61,10 @@ LetsEncrypt.config do |config|
56
61
  # The redis server url
57
62
  # Default is nil
58
63
  config.redis_url = 'redis://localhost:6379/1'
64
+
65
+ # Enable it if you want to customize the model
66
+ # Default is LetsEncrypt::Certificate
67
+ #config.certificate_model = 'MyCertificate'
59
68
  end
60
69
  ```
61
70
 
@@ -17,7 +17,7 @@ module LetsEncrypt
17
17
  end
18
18
 
19
19
  def certificate
20
- LetsEncrypt::Certificate.find_by(verification_path: filename)
20
+ LetsEncrypt.certificate_model.find_by(verification_path: filename)
21
21
  end
22
22
 
23
23
  def filename
@@ -6,7 +6,7 @@ module LetsEncrypt
6
6
  queue_as :default
7
7
 
8
8
  def perform
9
- LetsEncrypt::Certificate.renewable.each do |certificate|
9
+ LetsEncrypt.certificate_model.renewable.each do |certificate|
10
10
  next if certificate.renew
11
11
  certificate.update(renew_after: 1.day.from_now)
12
12
  end
@@ -10,7 +10,7 @@ module LetsEncrypt
10
10
  logger.info "Getting certificate for #{domain}"
11
11
  create_certificate
12
12
  # rubocop:disable Metrics/LineLength
13
- logger.info "Certificate issued (expires on #{expires_at}, will renew after #{renew_after})"
13
+ logger.info "Certificate issued for #{domain} (expires on #{expires_at}, will renew after #{renew_after})"
14
14
  # rubocop:enable Metrics/LineLength
15
15
  true
16
16
  end
@@ -18,21 +18,22 @@ module LetsEncrypt
18
18
  private
19
19
 
20
20
  def csr
21
- csr = OpenSSL::X509::Request.new
22
- csr.subject = OpenSSL::X509::Name.new(
23
- [['CN', domain, OpenSSL::ASN1::UTF8STRING]]
21
+ Acme::Client::CertificateRequest.new(
22
+ private_key: OpenSSL::PKey::RSA.new(key),
23
+ subject: {
24
+ common_name: domain
25
+ }
24
26
  )
25
- private_key = OpenSSL::PKey::RSA.new(key)
26
- csr.public_key = private_key.public_key
27
- csr.sign(private_key, OpenSSL::Digest::SHA256.new)
28
- csr
29
27
  end
30
28
 
31
29
  def create_certificate
32
- https_cert = LetsEncrypt.client.new_certificate(csr)
33
- self.certificate = https_cert.to_pem
34
- self.intermediaries = https_cert.chain_to_pem
35
- self.expires_at = https_cert.x509.not_after
30
+ order.finalize(csr: csr)
31
+ sleep 1 while order.status == 'processing'
32
+ fullchain = order.certificate.split("\n\n")
33
+ cert = OpenSSL::X509::Certificate.new(fullchain.shift)
34
+ self.certificate = cert.to_pem
35
+ self.intermediaries = fullchain.join("\n\n")
36
+ self.expires_at = cert.not_after
36
37
  self.renew_after = (expires_at - 1.month) + rand(10).days
37
38
  save!
38
39
  end
@@ -7,7 +7,7 @@ module LetsEncrypt
7
7
 
8
8
  # Returns true if verify domain is succeed.
9
9
  def verify
10
- start_authorize
10
+ create_order
11
11
  start_challenge
12
12
  wait_verify_status
13
13
  check_verify_status
@@ -17,9 +17,9 @@ module LetsEncrypt
17
17
 
18
18
  private
19
19
 
20
- def start_authorize
21
- authorization = LetsEncrypt.client.authorize(domain: domain)
22
- @challenge = authorization.http01
20
+ def create_order
21
+ # TODO: Support multiple domain
22
+ @challenge = order.authorizations.first.http
23
23
  self.verification_path = @challenge.filename
24
24
  self.verification_string = @challenge.file_content
25
25
  save!
@@ -27,24 +27,25 @@ module LetsEncrypt
27
27
 
28
28
  def start_challenge
29
29
  logger.info "Attempting verification of #{domain}"
30
- @challenge.request_verification
30
+ @challenge.request_validation
31
31
  end
32
32
 
33
33
  def wait_verify_status
34
34
  checks = 0
35
- until @challenge.verify_status != 'pending'
35
+ until @challenge.status != 'pending'
36
36
  checks += 1
37
37
  if checks > 30
38
- logger.info 'Status remained at pending for 30 checks'
38
+ logger.info "#{domain}: Status remained at pending for 30 checks"
39
39
  return false
40
40
  end
41
41
  sleep 1
42
+ @challenge.reload
42
43
  end
43
44
  end
44
45
 
45
46
  def check_verify_status
46
- unless @challenge.verify_status == 'valid'
47
- logger.info "Status was not valid (was: #{@challenge.verify_status})"
47
+ unless @challenge.status == 'valid'
48
+ logger.info "#{domain}: Status was not valid (was: #{@challenge.status})"
48
49
  return false
49
50
  end
50
51
 
@@ -55,11 +56,11 @@ module LetsEncrypt
55
56
  @retries ||= 0
56
57
  if e.is_a?(Acme::Client::Error::BadNonce) && @retries < 5
57
58
  @retries += 1
58
- logger.info "Bad nounce encountered. Retrying (#{@retries} of 5 attempts)"
59
+ logger.info "#{domain}: Bad nounce encountered. Retrying (#{@retries} of 5 attempts)"
59
60
  sleep 1
60
61
  verify
61
62
  else
62
- logger.info "Error: #{e.class} (#{e.message})"
63
+ logger.info "#{domain}: Error: #{e.class} (#{e.message})"
63
64
  return false
64
65
  end
65
66
  end
@@ -34,6 +34,7 @@ module LetsEncrypt
34
34
 
35
35
  before_create -> { self.key = OpenSSL::PKey::RSA.new(4096).to_s }
36
36
  after_save -> { save_to_redis }, if: -> { LetsEncrypt.config.use_redis? && active? }
37
+ after_destroy -> { delete_from_redis }, if: -> { LetsEncrypt.config.use_redis? && active? }
37
38
 
38
39
  # Returns false if certificate is not issued.
39
40
  #
@@ -57,7 +58,7 @@ module LetsEncrypt
57
58
 
58
59
  # Returns full-chain bundled certificates
59
60
  def bundle
60
- certificate + intermediaries
61
+ (certificate || '') + (intermediaries || '')
61
62
  end
62
63
 
63
64
  def certificate_object
@@ -73,10 +74,19 @@ module LetsEncrypt
73
74
  LetsEncrypt::Redis.save(self)
74
75
  end
75
76
 
77
+ # Delete certificate from redis
78
+ def delete_from_redis
79
+ LetsEncrypt::Redis.delete(self)
80
+ end
81
+
76
82
  protected
77
83
 
78
84
  def logger
79
85
  LetsEncrypt.logger
80
86
  end
87
+
88
+ def order
89
+ @order ||= LetsEncrypt.client.new_order(identifiers: [domain])
90
+ end
81
91
  end
82
92
  end
@@ -12,18 +12,18 @@ require 'letsencrypt/redis'
12
12
  # :nodoc:
13
13
  module LetsEncrypt
14
14
  # Production mode API Endpoint
15
- ENDPOINT = 'https://acme-v01.api.letsencrypt.org/'
15
+ ENDPOINT = 'https://acme-v02.api.letsencrypt.org/directory'
16
16
 
17
17
  # Staging mode API Endpoint, the rate limit is higher
18
18
  # but got invalid certificate for testing
19
- ENDPOINT_STAGING = 'https://acme-staging.api.letsencrypt.org'
19
+ ENDPOINT_STAGING = 'https://acme-staging-v02.api.letsencrypt.org/directory'
20
20
 
21
21
  class << self
22
22
  # Create the ACME Client to Let's Encrypt
23
23
  def client
24
24
  @client ||= ::Acme::Client.new(
25
25
  private_key: private_key,
26
- endpoint: endpoint
26
+ directory: directory
27
27
  )
28
28
  end
29
29
 
@@ -38,7 +38,7 @@ module LetsEncrypt
38
38
  end
39
39
 
40
40
  # Get current using Let's Encrypt endpoint
41
- def endpoint
41
+ def directory
42
42
  @endpoint ||= config.use_staging? ? ENDPOINT_STAGING : ENDPOINT
43
43
  end
44
44
 
@@ -49,10 +49,9 @@ module LetsEncrypt
49
49
  # connect with domain and assign the owner who can
50
50
  # renew and revoked.
51
51
  def register(email)
52
- registration = client.register(contact: "mailto:#{email}")
52
+ account = client.new_account(contact: "mailto:#{email}", terms_of_service_agreed: true)
53
53
  logger.info "Successfully registered private key with address #{email}"
54
- registration.agree_terms
55
- logger.info 'Terms have been accepted'
54
+ account.kid # TODO: Save KID
56
55
  true
57
56
  end
58
57
 
@@ -87,5 +86,9 @@ module LetsEncrypt
87
86
  def table_name_prefix
88
87
  'letsencrypt_'
89
88
  end
89
+
90
+ def certificate_model
91
+ @certificate_model ||= config.certificate_model.constantize
92
+ end
90
93
  end
91
94
  end
@@ -16,6 +16,10 @@ module LetsEncrypt
16
16
  config_accessor :save_to_redis
17
17
  config_accessor :redis_url
18
18
 
19
+ config_accessor :certificate_model do
20
+ 'LetsEncrypt::Certificate'
21
+ end
22
+
19
23
  # Returns true if enabled `save_to_redis` feature
20
24
  def use_redis?
21
25
  save_to_redis == true
@@ -10,10 +10,18 @@ module LetsEncrypt
10
10
 
11
11
  # Save certificate into redis.
12
12
  def save(cert)
13
- return unless cert.key.present? && cert.certificate.present?
14
- LetsEncrypt.logger.info "Save #{cert.domain}'s certificate to redis"
13
+ return unless cert.key.present? && cert.bundle.present?
14
+ LetsEncrypt.logger.info "Save #{cert.domain}'s certificate (bundle) to redis"
15
15
  connection.set "#{cert.domain}.key", cert.key
16
- connection.set "#{cert.domain}.crt", cert.certificate
16
+ connection.set "#{cert.domain}.crt", cert.bundle
17
+ end
18
+
19
+ # Delete certificate from redis.
20
+ def delete(cert)
21
+ return unless cert.key.present? && cert.certificate.present?
22
+ LetsEncrypt.logger.info "Delete #{cert.domain}'s certificate from redis"
23
+ connection.del "#{cert.domain}.key"
24
+ connection.del "#{cert.domain}.crt"
17
25
  end
18
26
  end
19
27
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LetsEncrypt
4
- VERSION = '0.5.5'
4
+ VERSION = '0.10.0'
5
5
  end
@@ -1,17 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  namespace :letsencrypt do
4
- desc 'Renew the certificates will epxired'
4
+ desc "Renew certificates that already expired or expiring soon"
5
5
  task renew: :environment do
6
6
  count = 0
7
7
  failed = 0
8
- LetsEncrypt::Certificate.renewable do |certificate|
8
+
9
+ LetsEncrypt.certificate_model.renewable.each do |certificate|
9
10
  count += 1
11
+
10
12
  next if certificate.renew
13
+
11
14
  failed += 1
12
- log "Could not renew domain: #{certificate.domain}"
15
+ puts "Could not renew domain: #{certificate.domain}"
13
16
  end
14
17
 
15
- puts "Total #{count} domains should renew, and #{failed} domains cannot be renewed."
18
+ puts "Renewed #{count - failed} out of #{count} domains"
16
19
  end
17
20
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-letsencrypt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.5
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - 蒼時弦也
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-20 00:00:00.000000000 Z
11
+ date: 2020-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4.1'
19
+ version: '5.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '4.1'
26
+ version: '5.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: acme-client
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.0'
33
+ version: 2.0.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.0'
40
+ version: 2.0.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: redis
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -84,30 +84,30 @@ dependencies:
84
84
  name: simplecov
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: 0.16.1
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: 0.16.1
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: coveralls
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0'
103
+ version: 0.8.23
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ">="
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0'
110
+ version: 0.8.23
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: codeclimate-test-reporter
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -156,7 +156,7 @@ homepage: https://github.com/elct9620/rails-letsencrypt
156
156
  licenses:
157
157
  - MIT
158
158
  metadata: {}
159
- post_install_message:
159
+ post_install_message:
160
160
  rdoc_options: []
161
161
  require_paths:
162
162
  - lib
@@ -171,9 +171,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
171
  - !ruby/object:Gem::Version
172
172
  version: '0'
173
173
  requirements: []
174
- rubyforge_project:
175
- rubygems_version: 2.6.14
176
- signing_key:
174
+ rubygems_version: 3.0.3
175
+ signing_key:
177
176
  specification_version: 4
178
177
  summary: The Let's Encrypt certificate manager for rails
179
178
  test_files: []