letsencrypt-cli 0.1.0.beta1
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 +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +16 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +87 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/exe/letsencrypt-cli +5 -0
- data/letsencrypt-cli.gemspec +34 -0
- data/lib/letsencrypt-cli.rb +1 -0
- data/lib/letsencrypt/cli.rb +10 -0
- data/lib/letsencrypt/cli/acme_wrapper.rb +131 -0
- data/lib/letsencrypt/cli/app.rb +72 -0
- data/lib/letsencrypt/cli/version.rb +5 -0
- metadata +216 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 101dcc9fbc8cd59d85926f5fc726c13393306292
|
4
|
+
data.tar.gz: b829a1224e1b3f9ae59d656034cf791f958c978b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c267226d7a856b80b6b8979acba3682687444546cdd2fe9adfc08990ad88ba1800ed48360f9148ea6fd2537d3dd6d8374a32018f8e40caa6250f51268ba05c5d
|
7
|
+
data.tar.gz: eab63e043424e82abc9e95d639deb339bd61a693983c6cbee4a6e925517b2f2b3d1ec4f0055131d81e2047fe6bdb7cf0c20cffbb1f3cc8a38df51e8f575da278
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 TODO: Write your name
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# Letsencrypt::Cli
|
2
|
+
|
3
|
+
[](https://travis-ci.org/zealot128/ruby-letsencrypt-cli)
|
4
|
+
[](https://badge.fury.io/rb/letsencrypt-cli)
|
5
|
+
|
6
|
+
Yet another Letsencrypt client using Ruby.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
* This tool needs Ruby > 2.0 (as the dependency acme needs that).
|
11
|
+
* openssl bindings
|
12
|
+
* no sudo! (Just access to webserver root .well-known alias)
|
13
|
+
|
14
|
+
$ gem install letsencrypt-cli
|
15
|
+
|
16
|
+
## Usage
|
17
|
+
|
18
|
+
Specify ``-t`` to use Letsencrypt test server. Without it, all requests are called against the production server, that might have same more strict rate limiting. If you are just toying around, add the -t flag.
|
19
|
+
|
20
|
+
```bash
|
21
|
+
# show all commands
|
22
|
+
|
23
|
+
letsencrypt-cli help
|
24
|
+
|
25
|
+
# show options for an individual command
|
26
|
+
letsencrypt-cli help cert
|
27
|
+
|
28
|
+
# creates account_key.json in current_dir
|
29
|
+
letsencrypt-cli register -t myemail@example.com
|
30
|
+
|
31
|
+
|
32
|
+
# authorize one or more domains/subdomains
|
33
|
+
letsencrypt-cli authorize -t --webroot-path /var/www/default example.com www.example.com somedir.example.com
|
34
|
+
|
35
|
+
# experimental: authorize all server_names in /etc/nginx/sites-enabled/*
|
36
|
+
letsencrypt-cli authorize_all -t --webroot-path /var/www/default
|
37
|
+
|
38
|
+
|
39
|
+
# create a certificate for before authorized domains.
|
40
|
+
# the first domain will be the cn subject. All other are subjectAlternateName
|
41
|
+
letsencrypt-cli cert -t example.com www.example.com somdir.example.com
|
42
|
+
# will create key.pem fullchain.pem chain.pem and cert.pem
|
43
|
+
```
|
44
|
+
|
45
|
+
|
46
|
+
## Example integration nginx:
|
47
|
+
|
48
|
+
|
49
|
+
```nginx
|
50
|
+
server {
|
51
|
+
listen 80;
|
52
|
+
server_name example.com www.example.com somedir.example.com
|
53
|
+
location /.well-known/acme-challenge {
|
54
|
+
alias /home/letsencrypt/webroot/.well-known/acme-challenge;
|
55
|
+
default_type "text/plain";
|
56
|
+
try_files $uri =404;
|
57
|
+
}
|
58
|
+
```
|
59
|
+
|
60
|
+
notice the location - alias. Use this dir with ``--webroot-path`` for authorization.
|
61
|
+
|
62
|
+
Afterwards, use the fullchain.pem and key.pem:
|
63
|
+
|
64
|
+
```nginx
|
65
|
+
server {
|
66
|
+
listen 443 ssl;
|
67
|
+
server_name stefanwienert.de www.stefanwienert.de;
|
68
|
+
ssl on;
|
69
|
+
ssl_certificate_key /path/to/key.pem;
|
70
|
+
ssl_certificate /path/to/fullchain.pem;
|
71
|
+
|
72
|
+
# use the settings from: https://gist.github.com/konklone/6532544
|
73
|
+
```
|
74
|
+
|
75
|
+
## Development
|
76
|
+
|
77
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
78
|
+
|
79
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
80
|
+
|
81
|
+
## Contributing
|
82
|
+
|
83
|
+
1. Fork it ( https://github.com/zealot128/letsencrypt-cli/fork )
|
84
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
85
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
86
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
87
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "letsencrypt/cli"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/exe/letsencrypt-cli
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'letsencrypt/cli/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "letsencrypt-cli"
|
8
|
+
spec.version = Letsencrypt::Cli::VERSION
|
9
|
+
spec.authors = ["Stefan Wienert"]
|
10
|
+
spec.email = ["stwienert@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{slim letsencrypt client for quickly authorizing (multiple) domains and issuing certificates}
|
13
|
+
spec.homepage = "https://github.com/zealot28/letsencrypt-cli"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = '>= 2.0.0'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_runtime_dependency 'acme-client'
|
23
|
+
spec.add_runtime_dependency 'thor'
|
24
|
+
spec.add_runtime_dependency 'colorize'
|
25
|
+
|
26
|
+
spec.add_development_dependency 'pry'
|
27
|
+
spec.add_development_dependency 'simplecov'
|
28
|
+
spec.add_development_dependency 'vcr', "~> 3.0"
|
29
|
+
spec.add_development_dependency 'webmock', "~> 1.22"
|
30
|
+
spec.add_development_dependency 'timecop', "~> 0.8"
|
31
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
32
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
33
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
34
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'letsencrypt/cli'
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'acme-client'
|
3
|
+
require 'pry'
|
4
|
+
|
5
|
+
class AcmeWrapper
|
6
|
+
def initialize(options)
|
7
|
+
@options = options
|
8
|
+
if !@options[:color]
|
9
|
+
String.disable_colorization = true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def log(message, severity=:info)
|
14
|
+
@logger ||= Logger.new(STDOUT).tap {|logger|
|
15
|
+
logger.level = Logger::SEV_LABEL.index(@options[:log_level].upcase)
|
16
|
+
logger.formatter = proc do |sev, datetime, progname, msg|
|
17
|
+
"#{datetime.to_s.light_black}: #{msg}\n"
|
18
|
+
end
|
19
|
+
}
|
20
|
+
@logger.send(severity, message)
|
21
|
+
end
|
22
|
+
|
23
|
+
def client
|
24
|
+
@client ||= Acme::Client.new(private_key: account_key, endpoint: endpoint)
|
25
|
+
end
|
26
|
+
|
27
|
+
def authorize(domain)
|
28
|
+
FileUtils.mkdir_p(@options[:webroot_path])
|
29
|
+
log "Authorizing #{domain.blue}.."
|
30
|
+
authorization = client.authorize(domain: domain)
|
31
|
+
|
32
|
+
challenge = authorization.http01
|
33
|
+
|
34
|
+
challenge_file = File.join(@options[:webroot_path], challenge.filename.split('/').last)
|
35
|
+
log "Writing challenge to #{challenge_file}", :debug
|
36
|
+
File.write(challenge_file, challenge.file_content)
|
37
|
+
|
38
|
+
challenge.request_verification
|
39
|
+
|
40
|
+
5.times do
|
41
|
+
log "Checking verification...", :debug
|
42
|
+
sleep 1
|
43
|
+
break if challenge.verify_status != 'pending'
|
44
|
+
end
|
45
|
+
if challenge.verify_status == 'valid'
|
46
|
+
log "Authorization successful for #{domain.green}"
|
47
|
+
File.unlink(challenge_file)
|
48
|
+
true
|
49
|
+
else
|
50
|
+
log "Authorization error for #{domain.red}", :error
|
51
|
+
log challenge.error['detail']
|
52
|
+
false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def cert(domains)
|
57
|
+
return if certificate_exists_and_valid?
|
58
|
+
csr = OpenSSL::X509::Request.new
|
59
|
+
certificate_private_key = find_or_create_pkey(@options[:private_key_path], "private key", @options[:key_length] || 2048)
|
60
|
+
|
61
|
+
csr.subject = OpenSSL::X509::Name.new([
|
62
|
+
# ['C', options[:country], OpenSSL::ASN1::PRINTABLESTRING],
|
63
|
+
# ['ST', options[:state], OpenSSL::ASN1::PRINTABLESTRING],
|
64
|
+
# ['L', options[:city], OpenSSL::ASN1::PRINTABLESTRING],
|
65
|
+
# ['O', options[:organization], OpenSSL::ASN1::UTF8STRING],
|
66
|
+
# ['OU', options[:department], OpenSSL::ASN1::UTF8STRING],
|
67
|
+
# ['CN', options[:common_name], OpenSSL::ASN1::UTF8STRING],
|
68
|
+
# ['emailAddress', options[:email], OpenSSL::ASN1::UTF8STRING]
|
69
|
+
['CN', domains.first, OpenSSL::ASN1::UTF8STRING]
|
70
|
+
])
|
71
|
+
if domains.count > 1
|
72
|
+
ef = OpenSSL::X509::ExtensionFactory.new
|
73
|
+
exts = [ ef.create_extension( "subjectAltName", domains.map{|domain| "DNS:#{domain}"}.join(','), false ) ]
|
74
|
+
attrval = OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence(exts)])
|
75
|
+
attrs = [
|
76
|
+
OpenSSL::X509::Attribute.new('extReq', attrval),
|
77
|
+
OpenSSL::X509::Attribute.new('msExtReq', attrval),
|
78
|
+
]
|
79
|
+
attrs.each do |attr|
|
80
|
+
csr.add_attribute(attr)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
csr.public_key = certificate_private_key.public_key
|
84
|
+
csr.sign(certificate_private_key, OpenSSL::Digest::SHA256.new)
|
85
|
+
certificate = client.new_certificate(csr)
|
86
|
+
File.write(@options[:fullchain_path], certificate.fullchain_to_pem)
|
87
|
+
File.write(@options[:chain_path], certificate.chain_to_pem)
|
88
|
+
File.write(@options[:certificate_path], certificate.to_pem)
|
89
|
+
log "Certificate successfully created to #{@options[:fullchain_path]} #{@options[:chain_path]} and #{@options[:certificate_path]}!".green
|
90
|
+
log "Certificate valid until: #{certificate.x509.not_after}"
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def certificate_exists_and_valid?
|
96
|
+
if File.exists?(@options[:certificate_path])
|
97
|
+
cert = OpenSSL::X509::Certificate.new(File.read(@options[:certificate_path]))
|
98
|
+
renew_on = cert.not_after.to_date - @options[:days_valid]
|
99
|
+
if renew_on > Date.today
|
100
|
+
log "Certificate '#{@options[:certificate_path]}' still valid till #{cert.not_after.to_date}.", :warn
|
101
|
+
log "Won't renew until #{renew_on} (#{@options[:days_valid]} days before)", :warn
|
102
|
+
exit 1
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def endpoint
|
108
|
+
if @options[:test]
|
109
|
+
"https://acme-staging.api.letsencrypt.org"
|
110
|
+
else
|
111
|
+
""
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
def account_key
|
117
|
+
@account_key ||= find_or_create_pkey(@options[:account_key], "account key", @options[:key_length] || 4096)
|
118
|
+
end
|
119
|
+
|
120
|
+
def find_or_create_pkey(file_path, name, length)
|
121
|
+
if File.exists?(file_path)
|
122
|
+
log "existing account key found"
|
123
|
+
OpenSSL::PKey::RSA.new File.read file_path
|
124
|
+
else
|
125
|
+
log "creating new private key to #{file_path}..."
|
126
|
+
private_key = OpenSSL::PKey::RSA.new(length)
|
127
|
+
File.write(file_path, private_key.to_s)
|
128
|
+
private_key
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'colorize'
|
3
|
+
require 'fileutils'
|
4
|
+
module Letsencrypt
|
5
|
+
module Cli
|
6
|
+
class App < Thor
|
7
|
+
class_option :account_key, desc: "Path to private key file (will be created if not exists)", aliases: "-a", default: 'account_key.pem'
|
8
|
+
class_option :test, desc: "Use staging url of Letsencrypt instead of production server", aliases: "-t", type: :boolean
|
9
|
+
class_option :log_level, desc: "Log Level (debug, info, warn, error, fatal)", default: "info"
|
10
|
+
class_option :color, desc: "Disable colorize", default: true, type: :boolean
|
11
|
+
|
12
|
+
desc 'register EMAIL', 'Register account'
|
13
|
+
method_option :key_length, desc: "Length of generated private key", type: :numeric, default: 4096
|
14
|
+
def register(email)
|
15
|
+
if email.nil? || email == ""
|
16
|
+
log "no E-Mail specified!", :fatal
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
if !email[/.*@.*/]
|
20
|
+
log "not an email", :fatal
|
21
|
+
exit 1
|
22
|
+
end
|
23
|
+
registration = wrapper.client.register(contact: "mailto:" + email)
|
24
|
+
registration.agree_terms
|
25
|
+
wrapper.log "Account created, Terms accepted"
|
26
|
+
end
|
27
|
+
|
28
|
+
desc 'authorize_all', "Verify all server_names in /etc/nginx/sites-enabled/* (needs read access)"
|
29
|
+
method_option :webroot_path, desc: "Path to mapped .acme-challenge folder (no subdir)", aliases: '-w', required: true
|
30
|
+
def authorize_all
|
31
|
+
lines = Dir['/etc/nginx/sites-enabled/*'].map{|file| File.read(file).lines.grep(/^\s*server_name/) }.flatten
|
32
|
+
domains = lines.flatten.map{|i| i.strip.split(/[; ]/).drop(1) }.flatten.reject{|i| i.length < 3 }.uniq
|
33
|
+
authorize(*domains)
|
34
|
+
end
|
35
|
+
|
36
|
+
desc 'authorize [DOMAINS]', 'Authorize all domains'
|
37
|
+
method_option :webroot_path, desc: "Path to mapped .well-known/acme-challenge folder (no subdirs will be created)", aliases: '-w', required: true
|
38
|
+
def authorize(*domains)
|
39
|
+
rc = 0
|
40
|
+
domains.each do |domain|
|
41
|
+
if !wrapper.authorize(domain)
|
42
|
+
rc = 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
if rc != 0
|
46
|
+
exit rc
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "cert [DOMAINS]", "create certificate and private key pair for domains. The first domain is the main CN domain, the reset will be added as SAN. If the given certificate-path already exists, script will exit non-zero if the certificate is still valid until the given number of days before."
|
51
|
+
method_option :private_key_path, desc: "Path to private key. Will be created if non existant", aliases: '-k', default: 'key.pem'
|
52
|
+
method_option :key_length, desc: "Length of private key", default: 2048, type: :numeric
|
53
|
+
method_option :fullchain_path, desc: "Path to fullchain certificate (Nginx) (will be overwritten if exists!)", aliases: '-f', default: 'fullchain.pem'
|
54
|
+
method_option :certificate_path, desc: "Path to certificate (Apache)", aliases: '-c', default: 'cert.pem'
|
55
|
+
method_option :chain_path, desc: "Path to chain (Apache)", aliases: '-n', default: 'chain.pem'
|
56
|
+
method_option :days_valid, desc: "If the --certificate-path already exists, only create new stuff, if that certificate isn't valid for less than the given number of days", default: 30, type: :numeric
|
57
|
+
def cert(*domains)
|
58
|
+
if domains.length == 0
|
59
|
+
$stderr.puts "no domains given"
|
60
|
+
exit 1
|
61
|
+
end
|
62
|
+
wrapper.cert(domains)
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def wrapper
|
68
|
+
@wrapper ||= AcmeWrapper.new(options)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
metadata
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: letsencrypt-cli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0.beta1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stefan Wienert
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: acme-client
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: thor
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: colorize
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: vcr
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: webmock
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.22'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.22'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: timecop
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.8'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.8'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: bundler
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.7'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.7'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rake
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '10.0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '10.0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rspec
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '3.0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '3.0'
|
167
|
+
description:
|
168
|
+
email:
|
169
|
+
- stwienert@gmail.com
|
170
|
+
executables:
|
171
|
+
- letsencrypt-cli
|
172
|
+
extensions: []
|
173
|
+
extra_rdoc_files: []
|
174
|
+
files:
|
175
|
+
- ".gitignore"
|
176
|
+
- ".rspec"
|
177
|
+
- ".travis.yml"
|
178
|
+
- Gemfile
|
179
|
+
- LICENSE.txt
|
180
|
+
- README.md
|
181
|
+
- Rakefile
|
182
|
+
- bin/console
|
183
|
+
- bin/setup
|
184
|
+
- exe/letsencrypt-cli
|
185
|
+
- letsencrypt-cli.gemspec
|
186
|
+
- lib/letsencrypt-cli.rb
|
187
|
+
- lib/letsencrypt/cli.rb
|
188
|
+
- lib/letsencrypt/cli/acme_wrapper.rb
|
189
|
+
- lib/letsencrypt/cli/app.rb
|
190
|
+
- lib/letsencrypt/cli/version.rb
|
191
|
+
homepage: https://github.com/zealot28/letsencrypt-cli
|
192
|
+
licenses:
|
193
|
+
- MIT
|
194
|
+
metadata: {}
|
195
|
+
post_install_message:
|
196
|
+
rdoc_options: []
|
197
|
+
require_paths:
|
198
|
+
- lib
|
199
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
200
|
+
requirements:
|
201
|
+
- - ">="
|
202
|
+
- !ruby/object:Gem::Version
|
203
|
+
version: 2.0.0
|
204
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">"
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: 1.3.1
|
209
|
+
requirements: []
|
210
|
+
rubyforge_project:
|
211
|
+
rubygems_version: 2.2.2
|
212
|
+
signing_key:
|
213
|
+
specification_version: 4
|
214
|
+
summary: slim letsencrypt client for quickly authorizing (multiple) domains and issuing
|
215
|
+
certificates
|
216
|
+
test_files: []
|