# Sample usage: # LE_HTTP_CHALLENGE_CONTACT_EMAIL=admin@example.com LE_HTTP_CHALLENGE_CERTIFICATE_DOMAINS=“www.example.com example.com” bundle exec rake generate_letsencrypt_cert # Using the staging endpoint by default. Also set # LE_HTTP_CHALLENGE_ENDPOINT='acme-v01.api.letsencrypt.org/' # for production

# LE_HTTP_CHALLENGE_ENDPOINT - (Optional) The staging endpoint will be used unless defined. # LE_HTTP_CHALLENGE_CONTACT_EMAIL - Domain contact email. # LE_HTTP_CHALLENGE_CERTIFICATE_DOMAINS - The domains and sub-domains for which the certificate is requested. # The first domain in the list will be the “Common Name” of the certificate.

# LE_HTTP_CHALLENGE_RESPONSE - The response to provide to the ACME challenge; Must be defined for the web server.

desc “Generate Let's Encrypt certificate with the http challenge” task :generate_letsencrypt_cert do

require 'io/console'
require 'openssl'
require 'acme-client'

options = {
    endpoint: ENV.fetch('LE_HTTP_CHALLENGE_ENDPOINT', 'https://acme-staging.api.letsencrypt.org/'),
    contact_email: ENV.fetch('LE_HTTP_CHALLENGE_CONTACT_EMAIL'),
    domains: ENV.fetch('LE_HTTP_CHALLENGE_CERTIFICATE_DOMAINS').split
}

def generate_cert(options)
  client = Acme::Client.new(private_key: OpenSSL::PKey::RSA.new(2048), endpoint: options[:endpoint])

  puts 'Registering with Let\'s Encrypt service...'
  registration = client.register(contact: "mailto:#{options[:contact_email]}")
  if registration.agree_terms
    puts 'Success'
  else
    puts 'Failed'
    return
  end

  puts 'Sending authorization request(s)...'
  options[:domains].each do |domain|
    authorization = client.authorize(domain: domain)
    challenge = authorization.http01

    puts ''
    puts 'Set'
    puts "LE_HTTP_CHALLENGE_RESPONSE=#{challenge.file_content}"
    puts 'on your Rails web server and restart it.'
    puts ''
    puts 'You can test by pointing your browser to'
    puts "#{domain}/#{challenge.filename}"
    puts ''

    puts 'Looking good?'
    press_any_key

    puts 'Requesting verification...'
    challenge.request_verification
    sleep(1) while 'pending' == challenge.verify_status

    puts "Validation failed for #{domain}" unless 'valid' == challenge.verify_status
  end

  puts ''
  puts 'Requesting the certificate...'
  csr = Acme::Client::CertificateRequest.new(names: options[:domains])
  certificate = client.new_certificate(csr)

  if certificate.nil?
    puts 'Failed to obtain certificate'
  else
    File.write('privkey.pem', certificate.request.private_key.to_pem)
    File.write('cert.pem', certificate.to_pem)
    File.write('chain.pem', certificate.chain_to_pem)
    File.write('fullchain.pem', certificate.fullchain_to_pem)
    puts 'Certificate saved'
  end
end

def press_any_key
  puts 'Press any key to continue.'
  STDIN.getch
end

generate_cert(options)

end