lecli 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +13 -0
- data/.travis.yml +5 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +9 -1
- data/README.md +71 -17
- data/Rakefile +3 -3
- data/bin/console +4 -4
- data/exe/lecli +36 -41
- data/lecli.gemspec +17 -18
- data/lecli_diagram.png +0 -0
- data/lib/lecli.rb +3 -2
- data/lib/lecli/certificate_builder.rb +114 -63
- data/lib/lecli/version.rb +1 -1
- metadata +26 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da9e05e9c2100f24c17b18b0102812c9a1ef4de5
|
4
|
+
data.tar.gz: 0ded86f70fab0543811022364e58f83b30114df7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94b3f4c61d97431798588137ff64b0a48fba6f906e07396e1908428af9e46f0c883f950d759de42f451b8f51c19eb21100e3d02a8a2698b5ed32fcc8505734af
|
7
|
+
data.tar.gz: 2b9669dded2a38d7bfceb0b6b5f9bffcf806908ed7b4d303815f2d4407734c203a9234a8a7d2f7c0678acefe87492a16beec8445d9499e27dfd418a5c582c6f6
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
3
|
+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
4
4
|
|
5
5
|
# Specify your gem's dependencies in lecli.gemspec
|
6
6
|
gemspec
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
lecli (0.2.
|
4
|
+
lecli (0.2.4)
|
5
5
|
acme-client (~> 2.0.0)
|
6
6
|
thor (~> 0.20.0)
|
7
7
|
|
@@ -11,8 +11,10 @@ GEM
|
|
11
11
|
acme-client (2.0.0)
|
12
12
|
faraday (~> 0.9, >= 0.9.1)
|
13
13
|
diff-lcs (1.3)
|
14
|
+
docile (1.3.1)
|
14
15
|
faraday (0.15.2)
|
15
16
|
multipart-post (>= 1.2, < 3)
|
17
|
+
json (2.1.0)
|
16
18
|
multipart-post (2.0.0)
|
17
19
|
rake (10.5.0)
|
18
20
|
rspec (3.7.0)
|
@@ -28,6 +30,11 @@ GEM
|
|
28
30
|
diff-lcs (>= 1.2.0, < 2.0)
|
29
31
|
rspec-support (~> 3.7.0)
|
30
32
|
rspec-support (3.7.1)
|
33
|
+
simplecov (0.16.1)
|
34
|
+
docile (~> 1.1)
|
35
|
+
json (>= 1.8, < 3)
|
36
|
+
simplecov-html (~> 0.10.0)
|
37
|
+
simplecov-html (0.10.2)
|
31
38
|
thor (0.20.0)
|
32
39
|
|
33
40
|
PLATFORMS
|
@@ -38,6 +45,7 @@ DEPENDENCIES
|
|
38
45
|
lecli!
|
39
46
|
rake (~> 10.0)
|
40
47
|
rspec (~> 3.0)
|
48
|
+
simplecov (~> 0.16.1)
|
41
49
|
|
42
50
|
BUNDLED WITH
|
43
51
|
1.16.0
|
data/README.md
CHANGED
@@ -1,38 +1,92 @@
|
|
1
|
-
#
|
1
|
+
# lecli
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
3
|
+
lecli is a gem that provides a CLI to generate Let's Encrypt certificates. It wraps around the [ACME protocol Client gem](https://github.com/unixcharles/acme-client). It pairs well with cron jobs and the [whenever gem](https://github.com/javan/whenever) for a tighter grip on automation/scripting customization.
|
6
4
|
|
7
5
|
## Installation
|
8
6
|
|
9
|
-
|
7
|
+
$ gem install lecli
|
8
|
+
|
9
|
+
## Getting started
|
10
|
+
|
11
|
+
The CLI will use the Let's Encrypt staging endpoint unless explicitly passed with the `--production` flag. All other configuration data is managed by a config file - `.lecli.yml`. To help understand the available options you can run the following in your terminal and a sample YAML file will be generated for you
|
10
12
|
|
11
|
-
```
|
12
|
-
|
13
|
+
```
|
14
|
+
$ lecli yaml
|
13
15
|
```
|
14
16
|
|
15
|
-
|
17
|
+
Now let's see what's inside
|
16
18
|
|
17
|
-
|
19
|
+
### `lecli.yml`
|
18
20
|
|
19
|
-
|
21
|
+
```
|
22
|
+
---
|
23
|
+
domains:
|
24
|
+
- example.com
|
25
|
+
common_name: Let's Encrypt
|
26
|
+
account_email: test@account.com
|
27
|
+
request_key: request.pem
|
28
|
+
certificate_key: certificate.pem
|
29
|
+
challenges_relative_path: challenges
|
30
|
+
success_callback_script: deploy.sh
|
31
|
+
```
|
20
32
|
|
21
|
-
|
33
|
+
Most entries are optional, except those that specify the domains you are requesting and "identity fields". Meaning that at least **domains** (list of entries), **common_name** and **account_email** should always appear in order to perform a valid request.
|
22
34
|
|
23
|
-
|
35
|
+
### The flow
|
24
36
|
|
25
|
-
|
37
|
+
From the two available types of validation requests only HTTP (and not DNS) is supported [yet](#contributing). This means you'll need to serve a token (lecli will create them) behind each domain in the **list of domain addresses** requested, on a certain **port**.
|
26
38
|
|
27
|
-
|
39
|
+
The tokens are written to a single **challenges_relative_path** and need to be served behind each domain you are requesting, i.e. `example.com/.well-known/acme-challenge/#{token_filename}`. If requesting multiple domains at once you will need additional setup to route from each domain requested to where the tokens are persisted. When working with a single domain, for example, you can just make this relative path write the tokens on `/usr/share/nginx/html/.well-known/acme-challenge/` if working with an nginx server.
|
40
|
+
|
41
|
+

|
42
|
+
|
43
|
+
After Let's Encrypt is able to access both tokens on the list of domain addresses requested the certificates can be issued. The resulting certificate will be identified by the **email** and under the **common_name** provided. The name of the `.pem` files can be customized with **request_key** and **certificate_key**.
|
44
|
+
|
45
|
+
Optionally you can specify a script filename with **success_callback_script**. This script will function as a "callback hook" and it will be run after successfully exporting the domains' certificate.
|
46
|
+
|
47
|
+
In this section you've read about all `lecli.yml` options available (keywords in **bold**). Now, if you've made sure you: (1) Customized the options in this file to create the desired certificate, and (2) made sure the **success_callback_script** path is available for a public internet. You are now ready to kick off the validation process by executing the following on your terminal
|
48
|
+
|
49
|
+
```
|
50
|
+
lecli generate
|
51
|
+
```
|
28
52
|
|
29
|
-
|
53
|
+
### Making use of the result Certificates
|
30
54
|
|
31
|
-
|
55
|
+
A simple example `nginx.conf` excerpt to make use of the result certificates could be the following
|
56
|
+
|
57
|
+
```
|
58
|
+
server {
|
59
|
+
listen 443 ssl;
|
60
|
+
server_name example.com;
|
61
|
+
|
62
|
+
ssl_certificate /etc/nginx/ssl/request.pem;
|
63
|
+
ssl_certificate_key /etc/nginx/ssl/certificate.pem;
|
64
|
+
|
65
|
+
...
|
66
|
+
}
|
67
|
+
```
|
68
|
+
|
69
|
+
You can script a server restart if needed, or any other setup that you require to make use of the newly created certificates. Just make sure to point the **success_callback_script** path in your config file so the CLI can automatically execute it if the request result was success.
|
70
|
+
|
71
|
+
If you pair the CLI with a cron-job (specially using the [whenever](https://github.com/javan/whenever) gem) you've essentially put together a Let's Encrypt bot and can now leverage scripting for complex deployments. Your certificates will be renewed periodically. When using **whenever** you'll have lecli CLI in your crontab as easy as:
|
72
|
+
|
73
|
+
```
|
74
|
+
every :month, at: '4am' do
|
75
|
+
command "lecli --production -f /path/to/config/file.yml"
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
Be sure to run `lecli help` for more details.
|
80
|
+
|
81
|
+
## Development
|
82
|
+
|
83
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. To install this gem onto your local machine, run `bundle exec rake install`.
|
32
84
|
|
33
85
|
## Contributing
|
34
86
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
87
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/fdoxyz/lecli.
|
88
|
+
|
89
|
+
Please include tests if new features are added and make sure rubocop styling guide is met.
|
36
90
|
|
37
91
|
## License
|
38
92
|
|
data/Rakefile
CHANGED
data/bin/console
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'lecli'
|
5
5
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
8
8
|
|
9
9
|
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require
|
10
|
+
# require 'pry'
|
11
11
|
# Pry.start
|
12
12
|
|
13
|
-
require
|
13
|
+
require 'irb'
|
14
14
|
IRB.start(__FILE__)
|
data/exe/lecli
CHANGED
@@ -1,60 +1,55 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require 'thor'
|
4
|
+
require 'yaml'
|
5
|
+
require 'lecli'
|
6
6
|
|
7
|
+
# Class in charge of the CLI functionallity powered by Thor
|
7
8
|
class LECLIRunner < Thor
|
8
|
-
|
9
|
-
YAML_FILENAME = ".lecli.yml"
|
10
|
-
|
11
|
-
desc "version", "Prints out the gem version"
|
9
|
+
desc 'version', 'Prints out the gem version'
|
12
10
|
def version
|
13
|
-
puts
|
11
|
+
puts LECLI::VERSION
|
14
12
|
end
|
15
13
|
|
16
|
-
desc
|
14
|
+
desc 'yaml', 'Generates the options file with defaults to customize'
|
17
15
|
option :override,
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
type: :boolean,
|
17
|
+
aliases: [:o],
|
18
|
+
desc: 'Overrides the existing options file the defaults.'
|
21
19
|
def yaml
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
puts YAML_FILENAME
|
26
|
-
else
|
27
|
-
puts "ERROR: #{YAML_FILENAME} file already exists. Try `lecli help yaml`"
|
28
|
-
end
|
20
|
+
LECLI::CertificateBuilder.persist_defaults_file(
|
21
|
+
override: options[:override]
|
22
|
+
)
|
29
23
|
end
|
30
24
|
|
31
|
-
desc
|
25
|
+
desc 'generate', 'Requests and outputs Let\'s Encrypt SSL Certificates'
|
32
26
|
option :production,
|
33
|
-
|
34
|
-
|
35
|
-
|
27
|
+
type: :boolean,
|
28
|
+
aliases: [:p],
|
29
|
+
desc: 'Use Let\'s Encrypt production API endpoint.'
|
30
|
+
option :config_file,
|
31
|
+
default: '.lecli.yml',
|
32
|
+
aliases: [:f],
|
33
|
+
desc: 'Specify the path of the configuration file.'
|
36
34
|
def generate
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
rescue
|
44
|
-
puts "ERROR: Invalid format for file #{YAML_FILENAME}"
|
45
|
-
return 1
|
35
|
+
puts "LOL: #{options[:config_file]}"
|
36
|
+
return
|
37
|
+
opts = LECLI::CertificateBuilder.load_options(config_file: config_file)
|
38
|
+
if opts.nil? # Bail if options can't be loaded properly
|
39
|
+
puts 'Unable to locate .lecli.yml file. Try `lecli help generate`'
|
40
|
+
return
|
46
41
|
end
|
47
42
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
puts "Certificates generated successfully!"
|
52
|
-
|
53
|
-
script_path = hash["success_callback_script"]
|
54
|
-
if File.file?(script_path)
|
55
|
-
puts "Execution attempt of success callback script `#{script_path}`"
|
56
|
-
`./#{script_path}`
|
43
|
+
builder = LECLI::CertificateBuilder.new do |b|
|
44
|
+
b.production = options[:production]
|
57
45
|
end
|
46
|
+
builder.generate_certs(opts)
|
47
|
+
puts 'Certificates generated successfully!'
|
48
|
+
|
49
|
+
script_path = File.expand_path(opts['success_callback_script'])
|
50
|
+
return if File.file?(script_path)
|
51
|
+
puts "Executing now success callback script `#{script_path}`..."
|
52
|
+
`./#{script_path}`
|
58
53
|
end
|
59
54
|
end
|
60
55
|
|
data/lecli.gemspec
CHANGED
@@ -1,31 +1,30 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path("../lib", __FILE__)
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
3
|
+
require 'lecli/version'
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
6
|
+
spec.name = 'lecli'
|
8
7
|
spec.version = LECLI::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
8
|
+
spec.authors = ['Fernando Valverde Arredondo']
|
9
|
+
spec.email = ['fdov88@gmail.com']
|
11
10
|
|
12
|
-
spec.summary =
|
13
|
-
spec.description =
|
14
|
-
spec.homepage =
|
15
|
-
spec.license =
|
11
|
+
spec.summary = 'CLI to generate Let\'s Encrypt certificates'
|
12
|
+
spec.description = 'CLI to generate Let\'s Encrypt certificates'
|
13
|
+
spec.homepage = 'https://github.com/fdoxyz/lecli'
|
14
|
+
spec.license = 'MIT'
|
16
15
|
|
17
16
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
17
|
f.match(%r{^(test|spec|features)/})
|
19
18
|
end
|
20
|
-
spec.bindir =
|
19
|
+
spec.bindir = 'exe'
|
21
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
-
spec.require_paths = [
|
23
|
-
|
24
|
-
spec.add_dependency "thor", "~> 0.20.0"
|
25
|
-
spec.add_dependency "acme-client", "~> 2.0.0"
|
21
|
+
spec.require_paths = ['lib']
|
26
22
|
|
27
|
-
spec.
|
28
|
-
spec.
|
29
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
23
|
+
spec.add_dependency 'acme-client', '~> 2.0.0'
|
24
|
+
spec.add_dependency 'thor', '~> 0.20.0'
|
30
25
|
|
26
|
+
spec.add_development_dependency 'bundler', '~> 1.16'
|
27
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
28
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
29
|
+
spec.add_development_dependency 'simplecov', '~> 0.16.1'
|
31
30
|
end
|
data/lecli_diagram.png
ADDED
Binary file
|
data/lib/lecli.rb
CHANGED
@@ -1,92 +1,143 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require 'thor'
|
2
|
+
require 'acme-client'
|
3
|
+
require 'uri'
|
4
|
+
require 'fileutils'
|
5
5
|
|
6
6
|
module LECLI
|
7
|
+
# Helper class to generate certs and access the default options
|
7
8
|
class CertificateBuilder
|
9
|
+
attr_accessor :production
|
8
10
|
|
9
|
-
|
11
|
+
YAML_FILENAME = '.lecli.yml'.freeze
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@challenges = []
|
15
|
+
@production = false
|
16
|
+
|
17
|
+
# Pass a block to edit the new object for prod/staging or other options
|
18
|
+
yield self if block_given?
|
19
|
+
|
20
|
+
prod_url = 'https://acme-v02.api.letsencrypt.org/directory'
|
21
|
+
staging_url = 'https://acme-staging-v02.api.letsencrypt.org/directory'
|
22
|
+
@endpoint = @production ? prod_url : staging_url
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.default_options
|
10
26
|
{
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
"success_callback_script" => "deploy.sh"
|
27
|
+
'domains' => ['example.com'],
|
28
|
+
'common_name' => 'Let\'s Encrypt',
|
29
|
+
'account_email' => 'test@account.com',
|
30
|
+
'request_key' => 'request.pem',
|
31
|
+
'certificate_key' => 'certificate.pem',
|
32
|
+
'challenges_relative_path' => 'challenges',
|
33
|
+
'success_callback_script' => 'deploy.sh'
|
19
34
|
}
|
20
35
|
end
|
21
36
|
|
22
|
-
def self.
|
23
|
-
|
24
|
-
|
37
|
+
def self.load_options(config_file:)
|
38
|
+
opts = LECLI::CertificateBuilder.default_options
|
39
|
+
opts.merge(YAML.load_file(config_file)) if File.file?(config_file)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.persist_defaults_file(override:)
|
43
|
+
opts = LECLI::CertificateBuilder.default_options
|
44
|
+
if !File.file?(YAML_FILENAME) || override
|
45
|
+
File.write(YAML_FILENAME, opts.to_yaml)
|
46
|
+
puts YAML_FILENAME
|
25
47
|
else
|
26
|
-
|
48
|
+
puts "#{YAML_FILENAME} already exists. Try `lecli help yaml`"
|
27
49
|
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def generate_certs(options)
|
53
|
+
request_challenges(options: options)
|
54
|
+
sleep(3) # We are unaware of challenge hosting, better give them some time
|
28
55
|
|
29
|
-
|
30
|
-
|
56
|
+
request_challenge_validation
|
57
|
+
request_key = finalize_order(
|
58
|
+
domains: options['domains'],
|
59
|
+
title: options['common_name']
|
60
|
+
)
|
61
|
+
|
62
|
+
write_certificate(
|
63
|
+
cert: @order.certificate, relative_path: options['certificate_key']
|
64
|
+
)
|
65
|
+
write_certificate(
|
66
|
+
cert: request_key, relative_path: options['request_key']
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def request_challenges(options:)
|
73
|
+
create_order(email: options['account_email'], domains: options['domains'])
|
74
|
+
setup_challenges_dir(relative_path: options['challenges_relative_path'])
|
75
|
+
persist_challenge_tokens
|
76
|
+
end
|
77
|
+
|
78
|
+
def write_certificate(cert:, relative_path:)
|
79
|
+
full_path = File.expand_path(relative_path)
|
80
|
+
File.write(full_path, cert)
|
81
|
+
end
|
82
|
+
|
83
|
+
def finalize_order(domains:, title:)
|
84
|
+
request_key = OpenSSL::PKey::RSA.new(4096)
|
85
|
+
csr = Acme::Client::CertificateRequest.new(
|
86
|
+
private_key: request_key,
|
87
|
+
names: domains.values,
|
88
|
+
subject: { common_name: title }
|
89
|
+
)
|
90
|
+
@order.finalize(csr: csr)
|
91
|
+
sleep(1) while @order.status == 'processing'
|
92
|
+
request_key
|
93
|
+
end
|
94
|
+
|
95
|
+
def create_order(email:, domains:)
|
96
|
+
pkey = OpenSSL::PKey::RSA.new(4096)
|
97
|
+
client = Acme::Client.new(private_key: pkey, directory: @endpoint)
|
31
98
|
client.new_account(
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
order = client.new_order(identifiers:
|
36
|
-
|
37
|
-
# Setup if necessary & clear challenges directory
|
38
|
-
challenges_dir = File.expand_path(options["challenges_relative_path"])
|
39
|
-
FileUtils.mkdir_p(challenges_dir)
|
40
|
-
FileUtils.rm(Dir[File.join(challenges_dir, "*")])
|
41
|
-
|
42
|
-
challenges = []
|
43
|
-
order.authorizations.each do |authorization|
|
44
|
-
challenge = authorization.http
|
45
|
-
token_path = File.join(challenges_dir, challenge.token)
|
46
|
-
File.write(token_path, challenge.file_content)
|
47
|
-
challenges << challenge
|
48
|
-
end
|
99
|
+
contact: "mailto:#{email}",
|
100
|
+
terms_of_service_agreed: true
|
101
|
+
)
|
102
|
+
@order = client.new_order(identifiers: domains)
|
103
|
+
end
|
49
104
|
|
50
|
-
|
105
|
+
def setup_challenges_dir(relative_path:)
|
106
|
+
@challenges_dir = File.expand_path(relative_path)
|
107
|
+
FileUtils.mkdir_p(@challenges_dir)
|
108
|
+
FileUtils.rm(Dir[File.join(@challenges_dir, '*')])
|
109
|
+
end
|
51
110
|
|
111
|
+
def request_challenge_validation
|
52
112
|
wait_time = 5
|
53
113
|
pending = true
|
54
114
|
while pending
|
55
|
-
challenges.each do |challenge|
|
115
|
+
@challenges.each do |challenge|
|
56
116
|
begin
|
57
117
|
challenge.request_validation
|
58
118
|
rescue Acme::Client::Error::Malformed
|
59
|
-
print
|
119
|
+
print '.'
|
60
120
|
end
|
61
121
|
end
|
62
122
|
|
63
|
-
status = challenges.map(&:status)
|
64
|
-
pending = status.include?(
|
65
|
-
|
66
|
-
if pending
|
67
|
-
puts "At least one challenge still pending, waiting #{wait_time}s ..."
|
68
|
-
sleep(wait_time)
|
123
|
+
status = @challenges.map(&:status)
|
124
|
+
pending = status.include?('pending')
|
69
125
|
|
70
|
-
|
71
|
-
|
72
|
-
|
126
|
+
next unless pending
|
127
|
+
puts "At least one challenge still pending, waiting #{wait_time}s ..."
|
128
|
+
sleep(wait_time)
|
129
|
+
wait_time *= 2 if wait_time < 640 # Gradually increment retry max ~10min
|
73
130
|
end
|
74
|
-
puts
|
75
|
-
|
76
|
-
request_key = OpenSSL::PKey::RSA.new(4096)
|
77
|
-
csr = Acme::Client::CertificateRequest.new(
|
78
|
-
private_key: request_key,
|
79
|
-
names: domains.values,
|
80
|
-
subject: { common_name: options["common_name"] }
|
81
|
-
)
|
82
|
-
order.finalize(csr: csr)
|
83
|
-
sleep(1) while order.status == "processing"
|
84
|
-
|
85
|
-
certificate_path = File.expand_path(options["certificate_key"])
|
86
|
-
File.write(certificate_path, order.certificate)
|
87
|
-
request_path = File.expand_path(options["request_key"])
|
88
|
-
File.write(request_path, request_key)
|
131
|
+
puts 'Challenges are all valid now!'
|
89
132
|
end
|
90
133
|
|
134
|
+
def persist_challenge_tokens
|
135
|
+
@order.authorizations.each do |authorization|
|
136
|
+
challenge = authorization.http
|
137
|
+
token_path = File.join(@challenges_dir, challenge.token)
|
138
|
+
File.write(token_path, challenge.file_content)
|
139
|
+
@challenges << challenge
|
140
|
+
end
|
141
|
+
end
|
91
142
|
end
|
92
143
|
end
|
data/lib/lecli/version.rb
CHANGED
metadata
CHANGED
@@ -1,43 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lecli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fernando Valverde Arredondo
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-07-
|
11
|
+
date: 2018-07-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: acme-client
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 2.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 2.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: thor
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 0.20.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.20.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,7 +80,21 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '3.0'
|
83
|
-
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.16.1
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.16.1
|
97
|
+
description: CLI to generate Let's Encrypt certificates
|
84
98
|
email:
|
85
99
|
- fdov88@gmail.com
|
86
100
|
executables:
|
@@ -90,6 +104,7 @@ extra_rdoc_files: []
|
|
90
104
|
files:
|
91
105
|
- ".gitignore"
|
92
106
|
- ".rspec"
|
107
|
+
- ".rubocop.yml"
|
93
108
|
- ".travis.yml"
|
94
109
|
- Gemfile
|
95
110
|
- Gemfile.lock
|
@@ -100,6 +115,7 @@ files:
|
|
100
115
|
- bin/setup
|
101
116
|
- exe/lecli
|
102
117
|
- lecli.gemspec
|
118
|
+
- lecli_diagram.png
|
103
119
|
- lib/lecli.rb
|
104
120
|
- lib/lecli/certificate_builder.rb
|
105
121
|
- lib/lecli/version.rb
|
@@ -126,5 +142,5 @@ rubyforge_project:
|
|
126
142
|
rubygems_version: 2.6.14
|
127
143
|
signing_key:
|
128
144
|
specification_version: 4
|
129
|
-
summary: Let's Encrypt
|
145
|
+
summary: CLI to generate Let's Encrypt certificates
|
130
146
|
test_files: []
|