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.



13
14
15
16
# File 'lib/letsencrypt_plugin.rb', line 13

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

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.



11
12
13
# File 'lib/letsencrypt_plugin.rb', line 11

def options
  @options
end

Instance Method Details

#authorize(domain = common_domain_name) ⇒ Object



89
90
91
92
# File 'lib/letsencrypt_plugin.rb', line 89

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



18
19
20
21
22
23
24
25
26
27
28
# File 'lib/letsencrypt_plugin.rb', line 18

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



85
86
87
# File 'lib/letsencrypt_plugin.rb', line 85

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

#create_clientObject



43
44
45
46
47
48
# File 'lib/letsencrypt_plugin.rb', line 43

def create_client
  @client ||= Acme::Client.new(private_key: load_private_key, endpoint: @options[:endpoint])
rescue Exception => e
  Rails.logger.error(e.to_s)
  raise e
end

#generate_certificateObject



30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/letsencrypt_plugin.rb', line 30

def generate_certificate
  create_client
  register

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

#handle_challengeObject



103
104
105
106
# File 'lib/letsencrypt_plugin.rb', line 103

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

#load_private_keyObject



66
67
68
69
70
71
72
# File 'lib/letsencrypt_plugin.rb', line 66

def load_private_key
  Rails.logger.info('Loading private key...')
  private_key = open_priv_key
  fail "Invalid key size: #{private_key.n.num_bits}." \
    ' Required size is between 2048 - 4096 bits' unless valid_key_size?(private_key)
  private_key
end

#open_priv_keyObject



60
61
62
63
64
# File 'lib/letsencrypt_plugin.rb', line 60

def open_priv_key
  private_key_path = privkey_path
  fail "Can not open private key: #{private_key_path}" unless File.exist?(private_key_path) && !File.directory?(private_key_path)
  OpenSSL::PKey::RSA.new(File.read(private_key_path))
end

#privkey_pathObject



54
55
56
57
58
# File 'lib/letsencrypt_plugin.rb', line 54

def privkey_path
  fail 'Private key is not set, please check your '\
    'config/letsencrypt_plugin.yml file!' if @options[:private_key].nil? || @options[:private_key].empty?
  File.join(Rails.root, @options[:private_key])
end

#registerObject



74
75
76
77
78
79
80
81
82
83
# File 'lib/letsencrypt_plugin.rb', line 74

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

#request_challenge_verificationObject



108
109
110
# File 'lib/letsencrypt_plugin.rb', line 108

def request_challenge_verification
  @challenge.request_verification
end

#save_certificate(certificate) ⇒ Object

Save the certificate and key



132
133
134
135
136
137
138
139
# File 'lib/letsencrypt_plugin.rb', line 132

def save_certificate(certificate)
  begin
    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 unless certificate.nil?
end

#store_challenge(challenge) ⇒ Object



94
95
96
97
98
99
100
101
# File 'lib/letsencrypt_plugin.rb', line 94

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_key_size?(key) ⇒ Boolean

Returns:

  • (Boolean)


50
51
52
# File 'lib/letsencrypt_plugin.rb', line 50

def valid_key_size?(key)
  key.n.num_bits >= 2048 && key.n.num_bits <= 4096
end

#valid_verification_statusObject



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

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

#wait_for_status(challenge) ⇒ Object



112
113
114
115
116
117
118
119
# File 'lib/letsencrypt_plugin.rb', line 112

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