class Acmesmith::Client

Public Class Methods

new(config: nil) click to toggle source
# File lib/acmesmith/client.rb, line 10
def initialize(config: nil)
  @config ||= config
end

Public Instance Methods

add_san(common_name, *add_sans) click to toggle source
# File lib/acmesmith/client.rb, line 155
def add_san(common_name, *add_sans)
  puts "=> reissuing CN=#{common_name} with new SANs #{add_sans.join(?,)}"
  cert = storage.get_certificate(common_name)
  sans = cert.sans + add_sans
  puts " * SANs will be: #{sans.join(?,)}"
  order(cert.common_name, *sans)
end
authorize(*identifiers) click to toggle source
# File lib/acmesmith/client.rb, line 46
def authorize(*identifiers)
  raise NotImplementedError, "Domain authorization in advance is still not available in acme-client (v2). Required authorizations will be performed when ordering certificates"
end
autorenew(days: 7, common_names: nil) click to toggle source
# File lib/acmesmith/client.rb, line 142
def autorenew(days: 7, common_names: nil)
  (common_names || storage.list_certificates).each do |cn|
    puts "=> #{cn}"
    cert = storage.get_certificate(cn)
    not_after = cert.certificate.not_after.utc

    puts "   Not valid after: #{not_after}"
    next unless (cert.certificate.not_after.utc - Time.now.utc) < (days.to_i * 86400)
    puts " * Renewing: CN=#{cert.common_name}, SANs=#{cert.sans.join(',')}"
    order(cert.common_name, *cert.sans)
  end
end
certificate_versions(common_name) click to toggle source
# File lib/acmesmith/client.rb, line 65
def certificate_versions(common_name)
  storage.list_certificate_versions(common_name).sort
end
certificates_list() click to toggle source
# File lib/acmesmith/client.rb, line 69
def certificates_list
  storage.list_certificates.sort
end
current(common_name) click to toggle source
# File lib/acmesmith/client.rb, line 73
def current(common_name)
  storage.get_current_certificate_version(common_name)
end
execute_post_issue_hooks(certificate) click to toggle source
# File lib/acmesmith/client.rb, line 55
def execute_post_issue_hooks(certificate)
  hooks = config.post_issuing_hooks(certificate.common_name)
  return if hooks.empty?
  puts "=> Executing post issuing hooks for CN=#{certificate.common_name}"
  hooks.each do |hook|
    hook.run(certificate: certificate)
  end
  puts
end
get_certificate(common_name, version: 'current', type: 'text') click to toggle source
# File lib/acmesmith/client.rb, line 77
def get_certificate(common_name, version: 'current', type: 'text')
  cert = storage.get_certificate(common_name, version: version)

  certs = []
  case type
  when 'text'
    certs << cert.certificate.to_text
    certs << cert.certificate.to_pem
  when 'certificate'
    certs << cert.certificate.to_pem
  when 'chain'
    certs << cert.chain
  when 'fullchain'
    certs << cert.fullchain
  end

  certs
end
get_private_key(common_name, version: 'current') click to toggle source
# File lib/acmesmith/client.rb, line 110
def get_private_key(common_name, version: 'current')
  cert = storage.get_certificate(common_name, version: version)
  cert.key_passphrase = certificate_key_passphrase if certificate_key_passphrase

  cert.private_key.to_pem
end
new_account(contact, tos_agreed: true) click to toggle source
# File lib/acmesmith/client.rb, line 14
def new_account(contact, tos_agreed: true)
  key = AccountKey.generate
  acme = Acme::Client.new(private_key: key.private_key, directory: config.directory, connection_options: config.connection_options, bad_nonce_retry: config.bad_nonce_retry)
  acme.new_account(contact: contact, terms_of_service_agreed: tos_agreed)

  storage.put_account_key(key, account_key_passphrase)

  key
end
order(*identifiers, not_before: nil, not_after: nil) click to toggle source
# File lib/acmesmith/client.rb, line 24
def order(*identifiers, not_before: nil, not_after: nil)
  order = OrderingService.new(
    acme: acme,
    identifiers: identifiers,
    challenge_responder_rules: config.challenge_responders,
    not_before: not_before,
    not_after: not_after
  )
  order.perform!
  cert = order.certificate

  puts
  print " * securing into the storage ..."
  storage.put_certificate(cert, certificate_key_passphrase)
  puts " [ ok ]"
  puts

  execute_post_issue_hooks(cert)

  cert
end
post_issue_hooks(common_name) click to toggle source
# File lib/acmesmith/client.rb, line 50
def post_issue_hooks(common_name)
  cert = storage.get_certificate(common_name)
  execute_post_issue_hooks(cert)
end
save(common_name, version: 'current', **kwargs) click to toggle source
# File lib/acmesmith/client.rb, line 135
def save(common_name, version: 'current', **kwargs)
  cert = storage.get_certificate(common_name, version: version)
  cert.key_passphrase = certificate_key_passphrase if certificate_key_passphrase

  SaveCertificateService.new(cert, **kwargs).perform!
end
save_certificate(common_name, version: 'current', mode: '0600', output:, type: 'fullchain') click to toggle source
# File lib/acmesmith/client.rb, line 96
def save_certificate(common_name, version: 'current', mode: '0600', output:, type: 'fullchain')
  cert = storage.get_certificate(common_name, version: version)
  File.open(output, 'w', mode.to_i(8)) do |f|
    case type
    when 'certificate'
      f.puts cert.certificate.to_pem
    when 'chain'
      f.puts cert.chain
    when 'fullchain'
      f.puts cert.fullchain
    end
  end
end
save_pkcs12(common_name, version: 'current', mode: '0600', output:, passphrase:) click to toggle source
# File lib/acmesmith/client.rb, line 125
def save_pkcs12(common_name, version: 'current', mode: '0600', output:, passphrase:)
  cert = storage.get_certificate(common_name, version: version)
  cert.key_passphrase = certificate_key_passphrase if certificate_key_passphrase
  
  p12 = cert.pkcs12(passphrase)
  File.open(output, 'w', mode.to_i(8)) do |f|
    f.puts p12.to_der
  end
end
save_private_key(common_name, version: 'current', mode: '0600', output:) click to toggle source
# File lib/acmesmith/client.rb, line 117
def save_private_key(common_name, version: 'current', mode: '0600', output:)
  cert = storage.get_certificate(common_name, version: version)
  cert.key_passphrase = certificate_key_passphrase if certificate_key_passphrase
  File.open(output, 'w', mode.to_i(8)) do |f|
    f.puts(cert.private_key)
  end
end

Private Instance Methods

account_key() click to toggle source
# File lib/acmesmith/client.rb, line 174
def account_key
  @account_key ||= storage.get_account_key.tap do |x|
    x.key_passphrase = account_key_passphrase if account_key_passphrase
  end
end
account_key_passphrase() click to toggle source
# File lib/acmesmith/client.rb, line 192
def account_key_passphrase
  if config['passphrase_from_env']
    ENV['ACMESMITH_ACCOUNT_KEY_PASSPHRASE'] || config['account_key_passphrase']
  else
    config['account_key_passphrase']
  end
end
acme() click to toggle source
# File lib/acmesmith/client.rb, line 180
def acme
  @acme ||= Acme::Client.new(private_key: account_key.private_key, directory: config.directory, connection_options: config.connection_options, bad_nonce_retry: config.bad_nonce_retry)
end
certificate_key_passphrase() click to toggle source
# File lib/acmesmith/client.rb, line 184
def certificate_key_passphrase
  if config['passphrase_from_env']
    ENV['ACMESMITH_CERTIFICATE_KEY_PASSPHRASE'] || config['certificate_key_passphrase']
  else
    config['certificate_key_passphrase']
  end
end
config() click to toggle source
# File lib/acmesmith/client.rb, line 166
def config
  @config
end
storage() click to toggle source
# File lib/acmesmith/client.rb, line 170
def storage
  config.storage
end