Class: LetsencryptPlugin::CertGenerator

Inherits:
Object
  • Object
show all
Defined in:
lib/letsencrypt_plugin.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ CertGenerator

Returns a new instance of CertGenerator.



23
24
25
26
# File 'lib/letsencrypt_plugin.rb', line 23

def initialize(options = {})
  @options = options
  @options.freeze
end

Instance Attribute Details

#certObject (readonly)

Returns the value of attribute cert.



21
22
23
# File 'lib/letsencrypt_plugin.rb', line 21

def cert
  @cert
end

#clientObject (readonly)

Returns the value of attribute client.



21
22
23
# File 'lib/letsencrypt_plugin.rb', line 21

def client
  @client
end

#optionsObject (readonly)

Returns the value of attribute options.



21
22
23
# File 'lib/letsencrypt_plugin.rb', line 21

def options
  @options
end

Instance Method Details

#authorize(domain = common_domain_name) ⇒ Object



97
98
99
100
# File 'lib/letsencrypt_plugin.rb', line 97

def authorize(domain = common_domain_name)
  Rails.logger.info("Sending authorization request for: #{domain}...")
  @authorization = client.authorize(domain: domain)
end

#authorize_and_handle_challenge(domains) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
# File 'lib/letsencrypt_plugin.rb', line 39

def authorize_and_handle_challenge(domains)
  result = false
  domains.each do |domain|
    authorize(domain)
    handle_challenge
    request_challenge_verification
    result = valid_verification_status
    break unless result
  end
  result
end

#common_domain_nameObject



93
94
95
# File 'lib/letsencrypt_plugin.rb', line 93

def common_domain_name
  @domain ||= @options[:cert_name] || @options[:domain].split(' ').first.to_s
end

#generate_certificateObject



28
29
30
31
32
33
34
35
36
37
# File 'lib/letsencrypt_plugin.rb', line 28

def generate_certificate
  register
  domains = @options[:domain].split(' ')
  return unless authorize_and_handle_challenge(domains)
  # We can now request a certificate
  Rails.logger.info('Creating CSR...')
  @cert = @client.new_certificate(Acme::Client::CertificateRequest.new(names: domains))
  save_certificate(@cert)
  Rails.logger.info('Certificate has been generated.')
end

#handle_challengeObject



111
112
113
114
# File 'lib/letsencrypt_plugin.rb', line 111

def handle_challenge
  @challenge = @authorization.http01
  store_challenge(@challenge)
end

#private_keyObject



55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/letsencrypt_plugin.rb', line 55

def private_key
  store ||= PrivateKeyStore.new(private_key_from_db) if @options.fetch(:private_key_in_db, false)

  pk_id = @options.fetch(:private_key, nil)

  raise 'Private key is not set, please check your config/letsencrypt_plugin.yml file!' if pk_id.nil? || pk_id.empty?

  store ||= PrivateKeyStore.new(private_key_from_file(private_key_path(pk_id))) if File.file?(private_key_path(pk_id))

  raise "Can not open private key: #{private_key_path(pk_id)}" if File.directory?(private_key_path(pk_id))

  store ||= PrivateKeyStore.new(pk_id)
  store.retrieve
end

#private_key_from_dbObject



74
75
76
77
78
# File 'lib/letsencrypt_plugin.rb', line 74

def private_key_from_db
  settings = LetsencryptPlugin::Setting.first
  raise 'Empty private_key field in settings table!' if settings.private_key.nil?
  settings.private_key
end

#private_key_from_file(filepath) ⇒ Object



80
81
82
# File 'lib/letsencrypt_plugin.rb', line 80

def private_key_from_file(filepath)
  File.read(filepath)
end

#private_key_path(private_key_file) ⇒ Object



70
71
72
# File 'lib/letsencrypt_plugin.rb', line 70

def private_key_path(private_key_file)
  Rails.root.join(private_key_file)
end

#registerObject



84
85
86
87
88
89
90
91
# File 'lib/letsencrypt_plugin.rb', line 84

def register
  Rails.logger.info('Trying to register at Let\'s Encrypt service...')
  registration = client.register(contact: "mailto:#{@options[:email]}")
  registration.agree_terms
  Rails.logger.info('Registration succeed.')
rescue => e
  Rails.logger.info("#{e.class} - #{e.message}. Already registered.")
end

#request_challenge_verificationObject



116
117
118
# File 'lib/letsencrypt_plugin.rb', line 116

def request_challenge_verification
  @challenge.request_verification
end

#save_certificate(certificate) ⇒ Object

Save the certificate and key



138
139
140
141
142
143
144
# File 'lib/letsencrypt_plugin.rb', line 138

def save_certificate(certificate)
  return unless certificate
  return HerokuOutput.new(common_domain_name, certificate).output unless ENV['DYNO'].nil?
  output_dir = File.join(Rails.root, @options[:output_cert_dir])
  return FileOutput.new(common_domain_name, certificate, output_dir).output if File.directory?(output_dir)
  Rails.logger.error("Output directory: '#{output_dir}' does not exist!")
end

#store_challenge(challenge) ⇒ Object



102
103
104
105
106
107
108
109
# File 'lib/letsencrypt_plugin.rb', line 102

def store_challenge(challenge)
  if @options[:challenge_dir_name].nil? || @options[:challenge_dir_name].empty?
    DatabaseStore.new(challenge.file_content).store
  else
    FileStore.new(challenge.file_content, @options[:challenge_dir_name]).store
  end
  sleep(2)
end

#valid_verification_statusObject



129
130
131
132
133
134
135
# File 'lib/letsencrypt_plugin.rb', line 129

def valid_verification_status
  wait_for_status(@challenge)
  return true if @challenge.verify_status == 'valid'
  Rails.logger.error('Challenge verification failed! ' \
    "Error: #{@challenge.error['type']}: #{@challenge.error['detail']}")
  false
end

#wait_for_status(challenge) ⇒ Object



120
121
122
123
124
125
126
127
# File 'lib/letsencrypt_plugin.rb', line 120

def wait_for_status(challenge)
  Rails.logger.info('Waiting for challenge status...')
  counter = 0
  while challenge.verify_status == 'pending' && counter < 10
    sleep(1)
    counter += 1
  end
end