class Object

Constants

ACME_DIR_L
ACME_DIR_S
CHALLENGE_DIR

location /.well-known{

     rewrite ^\.well-known(.*)$ $1 break;
     alias /srv/letsencrypt/challenge;
     add_header Content-Type text/plain;
}
SSL_CERT
SSL_DIR
SSL_KEY
TIMEOUT

Public Instance Methods

backup_file(dir, file) click to toggle source
# File lib/blix/letsencrypt.rb, line 99
def backup_file(dir, file)
  orig_path = File.join(dir, file)
  orig_file = File.basename(orig_path)
  orig_dir  = File.dirname(orig_path)

  fatal_error "backup file does not exist:#{orig_path}" unless File.exist?(orig_path)

  seq = 1
  loop  do
    prefix = '%04d_' % seq
    new_file = prefix + orig_file
    new_path = File.join(orig_dir, new_file)
    if File.exist?(new_path)
      seq += 1
      next
    else
      content = File.read(orig_path)
      File.write(new_path, content)
      break new_path
    end
  end
end
certificate_expiry_is_soon(ssl_dir, certificate_file, days = 30) click to toggle source

check if certificate is about to expire.

# File lib/blix/letsencrypt.rb, line 56
def certificate_expiry_is_soon(ssl_dir, certificate_file, days = 30)
  file = File.join(ssl_dir, certificate_file)
  return true unless File.file?(file)

  cert = OpenSSL::X509::Certificate.new(File.read(file))
  cert.not_after < Time.now + days * (24 * 60 * 60)
end
fatal_error(message) click to toggle source
# File lib/blix/letsencrypt.rb, line 71
def fatal_error(message)
  STDERR.puts "error: #{message}"
  exit(false)
end
perform_authorization(challenge_dir, authorization) click to toggle source

perform an authorization by creating the challenge files and waiting for validation to occur.

# File lib/blix/letsencrypt.rb, line 132
def perform_authorization(challenge_dir, authorization)
  http_challenge = authorization.http

  # write the challenge to file

  http_challenge.content_type # => 'text/plain'
  http_challenge.file_content # => example_token.TO1xJ0UDgfQ8WY5zT3txynup87UU3PhcDEIcuPyw4QU
  http_challenge.filename # => '.well-known/acme-challenge/example_token'
  http_challenge.token

  challenge_file = tidy_challenge_file(http_challenge.filename)
  challenge_path = write_file(challenge_dir, challenge_file, http_challenge.file_content)

  puts "challenge has been written to :#{challenge_path}"

  # now wait for the challenge ..

  http_challenge.request_validation
  timeout_time = Time.now + TIMEOUT

  while http_challenge.status == 'pending'
    if Time.now > timeout_time
      remove_file(challenge_dir, challenge_file)
      fatal_error 'Challenge timeout'
    end
    sleep(2)
    http_challenge.reload
  end

  remove_file(challenge_dir, challenge_file)
  fatal_error 'challenge failed' unless http_challenge.status == 'valid' # => 'valid'
end
remove_file(dir, file) click to toggle source

delete the challenge files

# File lib/blix/letsencrypt.rb, line 123
def remove_file(dir, file)
  file = tidy_challenge_file(file)
  path = File.join(dir, file)
  File.unlink(path) if File.file?(path)
  true
end
tidy_challenge_file(file) click to toggle source
# File lib/blix/letsencrypt.rb, line 64
def tidy_challenge_file(file)
  file = file[1..-1] if file[0, 1] == '/'
  str = '.well-known'
  file = file[str.length..-1] if file[0, str.length] == str
  file
end
write_file(dir, file, content) click to toggle source

write the challenge file and ensure that intermediate dirs exist

# File lib/blix/letsencrypt.rb, line 77
def write_file(dir, file, content)
  file = tidy_challenge_file(file)
  parts = file.split('/')
  last_index = parts.length - 1
  path = nil
  parts.each_with_index do |_part, idx|
    path = File.join(dir, *parts[0, idx + 1])
    if idx == last_index # the file name
      File.write(path, content)
    else
      if File.file?(path)
        fatal_error "invalid challenge path: #{path}"
      elsif File.directory?(path)

      else
        Dir.mkdir(path)
      end
    end
  end
  path
end