letsencrypt-cli 0.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://travis-ci.org/zealot128/ruby-letsencrypt-cli.svg?branch=travis)](https://travis-ci.org/zealot128/ruby-letsencrypt-cli)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/letsencrypt-cli.svg)](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: []
|