class LetsencryptWebfaction::Application::Run

Constants

RENEWAL_DELTA

Public Class Methods

new(args) click to toggle source
# File lib/letsencrypt_webfaction/application/run.rb, line 18
def initialize(args)
  @config_path = DefaultConfigPath.new
  parse_options(args)
  @config_path.validate!

  @options = LetsencryptWebfaction::Options.from_toml(@config_path.path)
end

Public Instance Methods

run!() click to toggle source
# File lib/letsencrypt_webfaction/application/run.rb, line 26
def run!
  validate_options

  # Check credentials
  unless api_credentials.valid?
    $stderr.puts 'WebFaction API username, password, and/or servername are incorrect. Login failed.'
    raise AppExitError, 'WebFaction credentials failed'
  end

  register_key

  process_certs
end

Private Instance Methods

api_credentials() click to toggle source
# File lib/letsencrypt_webfaction/application/run.rb, line 123
def api_credentials
  @_api_credentials ||= LetsencryptWebfaction::WebfactionApiCredentials.new username: @options.username, password: @options.password, servername: @options.servername, api_server: @options.api_url
end
client() click to toggle source
# File lib/letsencrypt_webfaction/application/run.rb, line 161
def client
  @_client ||= Acme::Client.new(private_key: private_key, directory: @options.directory)
end
key_registered?() click to toggle source
# File lib/letsencrypt_webfaction/application/run.rb, line 165
def key_registered?
  !client.kid.nil?
rescue Acme::Client::Error::AccountDoesNotExist
  false
end
parse_options(args) click to toggle source
# File lib/letsencrypt_webfaction/application/run.rb, line 76
def parse_options(args) # rubocop:disable Metrics/MethodLength
  OptionParser.new do |opts|
    opts.banner = 'Usage: letsencrypt_webfaction run [options]'

    opts.on('--quiet', 'Run with minimal output (useful for cron)') do |q|
      Out.quiet = q
    end

    opts.on('--config=CONFIG', 'Alternative configuration path') do |c|
      @config_path = CustomConfigPath.new(c)
    end

    opts.on('--force', 'When passed, all certs are re-issued regardless of expiration') do |d|
      @force_refresh = d
    end
  end.parse!(args)
end
print_error(field, error) click to toggle source
private_key() click to toggle source
# File lib/letsencrypt_webfaction/application/run.rb, line 150
def private_key
  @_private_key ||= begin
    key_path = Options.default_config_path.join('account_key.pem')
    unless key_path.exist?
      $stderr.puts 'Account key missing'
      raise AppExitError, 'Account key missing'
    end
    OpenSSL::PKey::RSA.new(Options.default_config_path.join('account_key.pem').read)
  end
end
process_certs() click to toggle source
# File lib/letsencrypt_webfaction/application/run.rb, line 94
def process_certs # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
  wf_cert_list = api_credentials.call('list_certificates')
  @options.certificates.each do |cert|
    wf_cert = wf_cert_list.find { |c| c['name'] == cert.cert_name }
    if @force_refresh
      # Issue because nonexistent
      Out.puts "Force issuing #{cert.cert_name}."
    elsif wf_cert.nil?
      # Issue because nonexistent
      Out.puts "Issuing #{cert.cert_name} for the first time."
    elsif wf_cert['domains'].split(',').map(&:strip).sort == cert.domains.sort
      days_remaining = (Date.parse(wf_cert['expiry_date']) - Date.today).to_i
      if days_remaining < RENEWAL_DELTA
        # Renew because nearing expiration
        Out.puts "#{days_remaining} days until expiration of #{cert.cert_name}. Renewing..."
      else
        # Ignore because active
        Out.puts "#{days_remaining} days until expiration of #{cert.cert_name}. Skipping..."
        next
      end
    else
      # Reissue because different
      Out.puts "Reissuing #{cert.cert_name} due to a change in the domain list."
    end

    CertificateIssuer.new(certificate: cert, api_credentials: api_credentials, client: client).call
  end
end
register_key() click to toggle source
# File lib/letsencrypt_webfaction/application/run.rb, line 171
def register_key
  return if key_registered?

  # If the private key is not known to the server, we need to register it for the first time.
  client.new_account(contact: "mailto:#{@options.letsencrypt_account_email}", terms_of_service_agreed: true)
end
validate_options() click to toggle source
# File lib/letsencrypt_webfaction/application/run.rb, line 127
def validate_options # rubocop:disable Metrics/MethodLength
  return if @options.valid?

  $stderr.puts 'The configuration file has an error:'
  @options.errors.each do |field, error|
    case error
    when String
      print_error(field, error)
    when Array
      error.each { |inner_field, inner_err| print_error("#{field} #{inner_field}", inner_err) }
    else
      # :nocov:
      raise 'Unexpected internal error type'
      # :nocov:
    end
  end
  raise AppExitError, 'config invalid'
end