Class: LetsCert::Runner

Inherits:
Object
  • Object
show all
Defined in:
lib/letscert/runner.rb,
lib/letscert/runner/logger_formatter.rb

Overview

Runner class: analyse and execute CLI commands. rubocop:disable Metrics/ClassLength

Author:

  • Sylvain Daubert

Defined Under Namespace

Classes: LoggerFormatter

Constant Summary collapse

RETURN_OK =

Exit value for OK

1
RETURN_OK_CERT =

Exit value for OK but with creation/renewal of certificate data

0
RETURN_ERROR =

Exit value for error(s)

2
RSA_DEFAULT_KEY_SIZE =

Default key size for RSA certificates

2048
RSA_DEFAULT_ACCOUNT_KEY_SIZE =

Default account key size for RSA type

4096
ECDSA_DEFAULT_ACCOUNT_KEY_SIZE =

Default account key size for ECDSA type

384

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRunner

Returns a new instance of Runner.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/letscert/runner.rb', line 69

def initialize
  @options = {
    verbose: 0,
    domains: [],
    files: [],
    valid_min: ValidTime.new('30d'),
    account_key_type: 'rsa',
    tos_sha256: '33d233c8ab558ba6c8ebc370a509acdded8b80e5d587aa5d192193f3' \
                '5226540f',
    server: 'https://acme-v01.api.letsencrypt.org/directory'
  }

  @logger = Logger.new($stdout)
  @logger.formatter = LoggerFormatter.new
end

Instance Attribute Details

#loggerLogger

Returns:

  • (Logger)


58
59
60
# File 'lib/letscert/runner.rb', line 58

def logger
  @logger
end

#optionsHash (readonly)

Get options

Returns:

  • (Hash)


56
57
58
# File 'lib/letscert/runner.rb', line 56

def options
  @options
end

Class Method Details

.runInteger

Run LetsCert

Returns:

  • (Integer)

See Also:



63
64
65
66
67
# File 'lib/letscert/runner.rb', line 63

def self.run
  runner = new
  runner.parse_options
  runner.run
end

Instance Method Details

#check_persistedObject

Check all components are covered by plugins

Raises:



242
243
244
245
246
247
248
249
250
# File 'lib/letscert/runner.rb', line 242

def check_persisted
  persisted = persisted_data
  not_persisted = persisted.keys.find_all { |k| persisted[k].nil? }

  unless not_persisted.empty?
    raise Error, 'Selected IO plugins do not cover following components: ' +
                 not_persisted.join(', ')
  end
end

#parse_optionsvoid

This method returns an undefined value.

Parse line command options rubocop:disable Metrics/MethodLength rubocop:disable Metrics/BlockLength

Raises:

  • (OptionParser::InvalidOption)

    on unrecognized or malformed option



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/letscert/runner.rb', line 117

def parse_options
  @opt_parser = OptionParser.new do |opts|
    opts.banner = 'Usage: lestcert [options]'

    opts.separator('')

    opts.on('-h', '--help', 'Show this help message and exit') do
      @options[:print_help] = true
    end
    opts.on('-V', '--version', 'Show version and exit') do |v|
      @options[:show_version] = v
    end
    opts.on('-v', '--verbose', 'Run verbosely') do |v|
      @options[:verbose] += 1 if v
    end

    opts.separator("\nWebroot manager:")

    opts.on('-d', '--domain DOMAIN[:PATH]',
            'Domain name to include in the certificate.',
            'Must be specified at least once.',
            'Its path on the disk must also be provided.') do |domain|
      @options[:domains] << domain
    end

    opts.on('--default-root PATH', 'Default webroot path',
            'Use for domains without PATH part.') do |path|
      @options[:default_root] = path
    end

    opts.separator("\nCertificate data files:")

    opts.on('--revoke', 'Revoke existing certificates') do |revoke|
      @options[:revoke] = revoke
    end

    opts.on('-f', '--file FILE', 'Input/output file.',
            'Can be specified multiple times',
            'Allowed values: account_key.json, cert.der,',
            'cert.pem, chain.pem, full.pem,',
            'fullchain.pem, key.der, key.pem.') do |file|
      @options[:files] << file
    end

    opts.on('--cert-ecdsa CURVE', String,
            'Generate ECDSA certificate on CURVE') do |curve|
      @options[:cert_ecdsa] = curve
    end

    opts.on('--cert-rsa BITS', Integer,
            'Generate RSA certificate with a BITS-bit',
            'private key') do |bits|
      @options[:cert_rsa] = bits
    end
    opts.on('--cert-key-size BITS', Integer,
            'Certificate key size in bits',
            '(equivalent to --cert-rsa)',
            "(default: #{RSA_DEFAULT_KEY_SIZE})") do |bits|
      @options[:cert_rsa] = bits
    end

    opts.accept(ValidTime) do |valid_time|
      ValidTime.new(valid_time)
    end
    opts.on('--valid-min TIME', ValidTime,
            'Renew existing certificate if validity',
            'is lesser than TIME',
            "(default: #{@options[:valid_min]})") do |vt|
      @options[:valid_min] = vt
    end

    opts.on('--reuse-key', 'Reuse previous private key') do |rk|
      @options[:reuse_key] = rk
    end

    opts.separator("\nRegistration:")
    opts.separator('  Automatically register an account with he ACME CA' \
                   ' specified  by --server')
    opts.separator('')

    opts.on('--account-key-type TYPE', %w(rsa ecdsa),
            'Account key type: rsa or ecdsa',
            '(Defaul: rsa)') do |type|
      @options[:account_key_type] = type
    end

    opts.on('--account-key-size BITS', Integer,
            'Account key size (default: ' \
            "#{RSA_DEFAULT_ACCOUNT_KEY_SIZE} (RSA) or ",
            "#{ECDSA_DEFAULT_ACCOUNT_KEY_SIZE} (ECDSA))") do |bits|
      @options[:account_key_size] = bits
    end

    opts.on('--tos-sha256 HASH', String,
            'SHA-256 digest of the content of Terms',
            'Of Service URI') do |hash|
      @options[:tos_sha256] = hash
    end

    opts.on('--email EMAIL', String,
            'E-mail address. CA is likely to use it to',
            'remind about expiring certificates, as well',
            'as for account recovery. It is highly',
            'recommended to set this value.') do |email|
      @options[:email] = email
    end

    opts.separator("\nHTTP:")
    opts.separator('  Configure properties of HTTP requests and responses.')
    opts.separator('')

    opts.on('--server URI', 'URI for the CA ACME API endpoint',
            "(default: #{@options[:server]})") do |uri|
      @options[:server] = uri
    end
  end

  @opt_parser.parse!
  compute_roots
  select_default_cert_type_if_none_specified
  
end

#runInteger

Returns exit code

  • 0 if certificate data were created or updated

  • 1 if renewal was not necessery

  • 2 in case of errors.

Returns:

  • (Integer)

    exit code

    • 0 if certificate data were created or updated

    • 1 if renewal was not necessery

    • 2 in case of errors



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/letscert/runner.rb', line 89

def run
  print_help_if_needed
  show_version_if_needed
  set_logger_level
  set_logger

  begin
    check_domains
    if @options[:revoke]
      revoke
    else
      check_persisted
      get_certificate
    end
  rescue Error, Acme::Client::Error => ex
    msg = ex.message
    msg = "[Acme] #{msg}" if ex.is_a?(Acme::Client::Error)
    @logger.error msg
    $stderr.puts "Error: #{msg}"
    RETURN_ERROR
  end
end