summaryrefslogtreecommitdiff
path: root/lib/leap_cli/acme.rb
blob: 6c7dbe982db216d32b87934f5878a689ac73744d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
require 'openssl'
require 'acme-client'

#
# A little bit of sugar around gem acme-client
#

module LeapCli
  class Acme

    if ENV['ACME_STAGING']
      ENDPOINT = 'https://acme-staging.api.letsencrypt.org/'
      puts "using endpoint " + ENDPOINT
    else
      ENDPOINT = 'https://acme-v01.api.letsencrypt.org/'
    end

    def initialize(domain: nil, key:)
      @client = ::Acme::Client.new(
        private_key: key,
        endpoint: ENDPOINT,
        connection_options: {request: {open_timeout: 5, timeout: 5}}
      )
      @domain = domain
    end

    #
    # static methods
    #

    def self.new_private_key
      return OpenSSL::PKey::RSA.new(4096)
    end

    def self.load_private_key(pem_encoded_key)
      return OpenSSL::PKey::RSA.new(pem_encoded_key)
    end

    def self.load_csr(pem_encoded_csr)
      return OpenSSL::X509::Request.new(pem_encoded_csr)
    end

    #
    # instance methods
    #

    #
    # register a new account key with CA
    #
    def register(contact)
      registration = @client.register(contact: 'mailto:' + contact)
      if registration && registration.agree_terms
        return registration
      else
        return false
      end
    end

    #
    # authorize account key for domain
    #
    def authorize
      authorization = @client.authorize(domain: @domain)
      challenge = nil
      begin
        while true
          if authorization.status == 'pending'
            challenge = authorization.http01
            yield challenge
            challenge.request_verification
            sleep 1
            authorization.verify_status
            if challenge.error
              return 'error', challenge.error
            end
          elsif authorization.status == 'invalid'
            challenge_msg = (challenge.nil? ? '' : challenge.error)
            return 'error', 'Something bad happened. %s' % challenge_msg
          elsif authorization.status == 'valid'
            return 'valid', nil
          else
            challenge_msg = (challenge.nil? ? '' : challenge.error)
            return 'error', 'status: %s, response message: %s' % [authorization.status, challenge_msg]
          end
        end
      rescue Interrupt
        return 'error', 'interrupted'
      end
    rescue ::Acme::Client::Error::Unauthorized => exc
      return 'unauthorized', exc.to_s
    end

    #
    # get new certificate
    #
    def get_certificate(csr)
      return @client.new_certificate(csr)
    end

  end
end