acmesmith 0.6.1 → 0.7.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 +4 -4
- data/lib/acmesmith/client.rb +235 -0
- data/lib/acmesmith/command.rb +20 -181
- data/lib/acmesmith/config.rb +4 -0
- data/lib/acmesmith/version.rb +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c4a9da6141839cd8a3b4850091f05ab7e024a252
|
4
|
+
data.tar.gz: 64807174e4ee28afd2a4be93d7ae8cbcdcf8cde1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1be84d5808225cf30cd6dc324a4a7924f1dacfdb310cc5872e7bdfa74d12ef93e7de5c234ba9ad4fe0679ce03ded44e832a66065544cb9dd808360fb7da4e5a3
|
7
|
+
data.tar.gz: 549065d60f3774ab1ef4be20da4b90d4f02f0e7b13af912b62128c65026ae5c1fb76880754251a3b69a929fe2d3a1581c8d09f5a8184829c57c33e317d875d4c
|
@@ -0,0 +1,235 @@
|
|
1
|
+
require 'acmesmith/account_key'
|
2
|
+
require 'acmesmith/certificate'
|
3
|
+
|
4
|
+
require 'acme-client'
|
5
|
+
|
6
|
+
module Acmesmith
|
7
|
+
class Client
|
8
|
+
def initialize(config: nil)
|
9
|
+
@config ||= config
|
10
|
+
end
|
11
|
+
|
12
|
+
def register(contact)
|
13
|
+
key = AccountKey.generate
|
14
|
+
acme = Acme::Client.new(private_key: key.private_key, endpoint: config['endpoint'])
|
15
|
+
registration = acme.register(contact: contact)
|
16
|
+
registration.agree_terms
|
17
|
+
|
18
|
+
storage.put_account_key(key, account_key_passphrase)
|
19
|
+
|
20
|
+
key
|
21
|
+
end
|
22
|
+
|
23
|
+
def authorize(*domains)
|
24
|
+
targets = domains.map do |domain|
|
25
|
+
authz = acme.authorize(domain: domain)
|
26
|
+
challenges = [authz.http01, authz.dns01, authz.tls_sni01].compact
|
27
|
+
challenge = nil
|
28
|
+
responder = config.challenge_responders.find do |x|
|
29
|
+
challenge = challenges.find { |_| x.support?(_.class::CHALLENGE_TYPE) }
|
30
|
+
end
|
31
|
+
{domain: domain, authz: authz, responder: responder, challenge: challenge}
|
32
|
+
end
|
33
|
+
|
34
|
+
begin
|
35
|
+
targets.each do |target|
|
36
|
+
target[:responder].respond(target[:domain], target[:challenge])
|
37
|
+
end
|
38
|
+
|
39
|
+
targets.each do |target|
|
40
|
+
puts "=> Requesting verifications..."
|
41
|
+
target[:challenge].request_verification
|
42
|
+
end
|
43
|
+
loop do
|
44
|
+
all_valid = true
|
45
|
+
targets.each do |target|
|
46
|
+
next if target[:valid]
|
47
|
+
|
48
|
+
status = target[:challenge].verify_status
|
49
|
+
puts " * [#{target[:domain]}] verify_status: #{status}"
|
50
|
+
|
51
|
+
if status == 'valid'
|
52
|
+
target[:valid] = true
|
53
|
+
next
|
54
|
+
end
|
55
|
+
|
56
|
+
all_valid = false
|
57
|
+
if status == "invalid"
|
58
|
+
err = target[:challenge].error
|
59
|
+
puts " ! [#{target[:domain]}] #{err["type"]}: #{err["detail"]}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
break if all_valid
|
63
|
+
sleep 3
|
64
|
+
end
|
65
|
+
puts "=> Done"
|
66
|
+
ensure
|
67
|
+
targets.each do |target|
|
68
|
+
target[:responder].cleanup(target[:domain], target[:challenge])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def request(common_name, *sans)
|
74
|
+
csr = Acme::Client::CertificateRequest.new(common_name: common_name, names: sans)
|
75
|
+
retried = false
|
76
|
+
acme_cert = begin
|
77
|
+
acme.new_certificate(csr)
|
78
|
+
rescue Acme::Client::Error::Unauthorized => e
|
79
|
+
raise unless config.auto_authorize_on_request
|
80
|
+
raise if retried
|
81
|
+
|
82
|
+
puts "=> Authorizing unauthorized domain names"
|
83
|
+
# https://github.com/letsencrypt/boulder/blob/b9369a481415b3fe31e010b34e2ff570b89e42aa/ra/ra.go#L604
|
84
|
+
m = e.message.match(/authorizations for these names not found or expired: ((?:[a-zA-Z0-9_.\-]+(?:,\s+|$))+)/)
|
85
|
+
if m && m[1]
|
86
|
+
domains = m[1].split(/,\s+/)
|
87
|
+
else
|
88
|
+
warn " ! Error message on certificate request was #{e.message.inspect} and acmesmith couldn't determine which domain names are unauthorized (maybe a bug)"
|
89
|
+
warn " ! Attempting to authorize all domains in this certificate reuqest for now."
|
90
|
+
domains = [common_name, *sans]
|
91
|
+
end
|
92
|
+
puts " * #{domains.join(', ')}"
|
93
|
+
authorize(*domains)
|
94
|
+
retried = true
|
95
|
+
retry
|
96
|
+
end
|
97
|
+
|
98
|
+
cert = Certificate.from_acme_client_certificate(acme_cert)
|
99
|
+
storage.put_certificate(cert, certificate_key_passphrase)
|
100
|
+
|
101
|
+
execute_post_issue_hooks(common_name)
|
102
|
+
|
103
|
+
cert
|
104
|
+
end
|
105
|
+
|
106
|
+
def execute_post_issue_hooks(common_name)
|
107
|
+
post_issues_hooks_for_common_name = config.post_issueing_hooks(common_name)
|
108
|
+
if post_issues_hooks_for_common_name
|
109
|
+
post_issues_hooks_for_common_name.each do |hook|
|
110
|
+
hook.execute
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def certificate_versions(common_name)
|
116
|
+
storage.list_certificate_versions(common_name).sort
|
117
|
+
end
|
118
|
+
|
119
|
+
def certificates_list
|
120
|
+
storage.list_certificates.sort
|
121
|
+
end
|
122
|
+
|
123
|
+
def current(common_name)
|
124
|
+
storage.get_current_certificate_version(common_name)
|
125
|
+
end
|
126
|
+
|
127
|
+
def get_certificate(common_name, version: 'current', type: 'text')
|
128
|
+
cert = storage.get_certificate(common_name, version: version)
|
129
|
+
|
130
|
+
certs = []
|
131
|
+
case type
|
132
|
+
when 'text'
|
133
|
+
certs << cert.certificate.to_text
|
134
|
+
certs << cert.certificate.to_pem
|
135
|
+
when 'certificate'
|
136
|
+
certs << cert.certificate.to_pem
|
137
|
+
when 'chain'
|
138
|
+
certs << cert.chain
|
139
|
+
when 'fullchain'
|
140
|
+
certs << cert.fullchain
|
141
|
+
end
|
142
|
+
|
143
|
+
certs
|
144
|
+
end
|
145
|
+
|
146
|
+
def save_certificate(common_name, version: 'current', mode: '0600', output:)
|
147
|
+
cert = storage.get_certificate(common_name, version: version)
|
148
|
+
File.open(output, 'w', mode.to_i(8)) do |f|
|
149
|
+
f.puts(cert.fullchain)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def get_private_key(common_name, version: 'current')
|
154
|
+
cert = storage.get_certificate(common_name, version: version)
|
155
|
+
cert.key_passphrase = certificate_key_passphrase if certificate_key_passphrase
|
156
|
+
|
157
|
+
cert.private_key.to_pem
|
158
|
+
end
|
159
|
+
|
160
|
+
def save_private_key(common_name, version: 'current', mode: '0600', output:)
|
161
|
+
cert = storage.get_certificate(common_name, version: version)
|
162
|
+
cert.key_passphrase = certificate_key_passphrase if certificate_key_passphrase
|
163
|
+
File.open(output, 'w', mode.to_i(8)) do |f|
|
164
|
+
f.puts(cert.private_key)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def save_pkcs12(common_name, version: 'current', mode: '0600', output:, passphrase:)
|
169
|
+
cert = storage.get_certificate(common_name, version: version)
|
170
|
+
cert.key_passphrase = certificate_key_passphrase if certificate_key_passphrase
|
171
|
+
|
172
|
+
p12 = OpenSSL::PKCS12.create(passphrase, cert.common_name, cert.private_key, cert.certificate)
|
173
|
+
File.open(output, 'w', mode.to_i(8)) do |f|
|
174
|
+
f.puts p12.to_der
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def autorenew(days)
|
179
|
+
storage.list_certificates.each do |cn|
|
180
|
+
puts "=> #{cn}"
|
181
|
+
cert = storage.get_certificate(cn)
|
182
|
+
not_after = cert.certificate.not_after.utc
|
183
|
+
|
184
|
+
puts " Not valid after: #{not_after}"
|
185
|
+
next unless (cert.certificate.not_after.utc - Time.now.utc) < (days.to_i * 86400)
|
186
|
+
puts " * Renewing: CN=#{cert.common_name}, SANs=#{cert.sans.join(',')}"
|
187
|
+
request(cert.common_name, *cert.sans)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def add_san(common_name, *add_sans)
|
192
|
+
puts "=> reissuing CN=#{common_name} with new SANs #{add_sans.join(?,)}"
|
193
|
+
cert = storage.get_certificate(common_name)
|
194
|
+
sans = cert.sans + add_sans
|
195
|
+
puts " * SANs will be: #{sans.join(?,)}"
|
196
|
+
request(cert.common_name, *sans)
|
197
|
+
end
|
198
|
+
|
199
|
+
private
|
200
|
+
|
201
|
+
def config
|
202
|
+
@config
|
203
|
+
end
|
204
|
+
|
205
|
+
def storage
|
206
|
+
config.storage
|
207
|
+
end
|
208
|
+
|
209
|
+
def account_key
|
210
|
+
@account_key ||= storage.get_account_key.tap do |x|
|
211
|
+
x.key_passphrase = account_key_passphrase if account_key_passphrase
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def acme
|
216
|
+
@acme ||= Acme::Client.new(private_key: account_key.private_key, endpoint: config['endpoint'])
|
217
|
+
end
|
218
|
+
|
219
|
+
def certificate_key_passphrase
|
220
|
+
if config['passphrase_from_env']
|
221
|
+
ENV['ACMESMITH_CERTIFICATE_KEY_PASSPHRASE'] || config['certificate_key_passphrase']
|
222
|
+
else
|
223
|
+
config['certificate_key_passphrase']
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def account_key_passphrase
|
228
|
+
if config['passphrase_from_env']
|
229
|
+
ENV['ACMESMITH_ACCOUNT_KEY_PASSPHRASE'] || config['account_key_passphrase']
|
230
|
+
else
|
231
|
+
config['account_key_passphrase']
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
data/lib/acmesmith/command.rb
CHANGED
@@ -1,10 +1,7 @@
|
|
1
1
|
require 'thor'
|
2
2
|
|
3
3
|
require 'acmesmith/config'
|
4
|
-
require 'acmesmith/
|
5
|
-
require 'acmesmith/certificate'
|
6
|
-
|
7
|
-
require 'acme-client'
|
4
|
+
require 'acmesmith/client'
|
8
5
|
|
9
6
|
module Acmesmith
|
10
7
|
class Command < Thor
|
@@ -13,138 +10,48 @@ module Acmesmith
|
|
13
10
|
|
14
11
|
desc "register CONTACT", "Create account key (contact e.g. mailto:xxx@example.org)"
|
15
12
|
def register(contact)
|
16
|
-
key =
|
17
|
-
acme = Acme::Client.new(private_key: key.private_key, endpoint: config['endpoint'])
|
18
|
-
registration = acme.register(contact: contact)
|
19
|
-
registration.agree_terms
|
20
|
-
|
21
|
-
storage.put_account_key(key, account_key_passphrase)
|
13
|
+
key = client.register(contact)
|
22
14
|
puts "Generated:\n#{key.private_key.public_key.to_pem}"
|
23
15
|
end
|
24
16
|
|
25
17
|
desc "authorize DOMAIN [DOMAIN ...]", "Get authz for DOMAIN."
|
26
18
|
def authorize(*domains)
|
27
|
-
|
28
|
-
authz = acme.authorize(domain: domain)
|
29
|
-
challenges = [authz.http01, authz.dns01, authz.tls_sni01].compact
|
30
|
-
challenge = nil
|
31
|
-
responder = config.challenge_responders.find do |x|
|
32
|
-
challenge = challenges.find { |_| x.support?(_.class::CHALLENGE_TYPE) }
|
33
|
-
end
|
34
|
-
{domain: domain, authz: authz, responder: responder, challenge: challenge}
|
35
|
-
end
|
36
|
-
|
37
|
-
begin
|
38
|
-
targets.each do |target|
|
39
|
-
target[:responder].respond(target[:domain], target[:challenge])
|
40
|
-
end
|
41
|
-
|
42
|
-
targets.each do |target|
|
43
|
-
puts "=> Requesting verifications..."
|
44
|
-
target[:challenge].request_verification
|
45
|
-
end
|
46
|
-
loop do
|
47
|
-
all_valid = true
|
48
|
-
targets.each do |target|
|
49
|
-
next if target[:valid]
|
50
|
-
|
51
|
-
status = target[:challenge].verify_status
|
52
|
-
puts " * [#{target[:domain]}] verify_status: #{status}"
|
53
|
-
|
54
|
-
if status == 'valid'
|
55
|
-
target[:valid] = true
|
56
|
-
next
|
57
|
-
end
|
58
|
-
|
59
|
-
all_valid = false
|
60
|
-
if status == "invalid"
|
61
|
-
err = target[:challenge].error
|
62
|
-
puts " ! [#{target[:domain]}] #{err["type"]}: #{err["detail"]}"
|
63
|
-
end
|
64
|
-
end
|
65
|
-
break if all_valid
|
66
|
-
sleep 3
|
67
|
-
end
|
68
|
-
puts "=> Done"
|
69
|
-
ensure
|
70
|
-
targets.each do |target|
|
71
|
-
target[:responder].cleanup(target[:domain], target[:challenge])
|
72
|
-
end
|
73
|
-
end
|
19
|
+
client.authorize(*domains)
|
74
20
|
end
|
75
21
|
|
76
22
|
desc "request COMMON_NAME [SAN]", "request certificate for CN +COMMON_NAME+ with SANs +SAN+"
|
77
23
|
def request(common_name, *sans)
|
78
|
-
|
79
|
-
retried = false
|
80
|
-
acme_cert = begin
|
81
|
-
acme.new_certificate(csr)
|
82
|
-
rescue Acme::Client::Error::Unauthorized => e
|
83
|
-
raise unless config.auto_authorize_on_request
|
84
|
-
raise if retried
|
85
|
-
|
86
|
-
puts "=> Authorizing unauthorized domain names"
|
87
|
-
# https://github.com/letsencrypt/boulder/blob/b9369a481415b3fe31e010b34e2ff570b89e42aa/ra/ra.go#L604
|
88
|
-
m = e.message.match(/authorizations for these names not found or expired: ((?:[a-zA-Z0-9_.\-]+(?:,\s+|$))+)/)
|
89
|
-
if m && m[1]
|
90
|
-
domains = m[1].split(/,\s+/)
|
91
|
-
else
|
92
|
-
warn " ! Error message on certificate request was #{e.message.inspect} and acmesmith couldn't determine which domain names are unauthorized (maybe a bug)"
|
93
|
-
warn " ! Attempting to authorize all domains in this certificate reuqest for now."
|
94
|
-
domains = [common_name, *sans]
|
95
|
-
end
|
96
|
-
puts " * #{domains.join(', ')}"
|
97
|
-
authorize(*domains)
|
98
|
-
retried = true
|
99
|
-
retry
|
100
|
-
end
|
101
|
-
|
102
|
-
cert = Certificate.from_acme_client_certificate(acme_cert)
|
103
|
-
storage.put_certificate(cert, certificate_key_passphrase)
|
104
|
-
|
24
|
+
cert = client.request(common_name, *sans)
|
105
25
|
puts cert.certificate.to_text
|
106
26
|
puts cert.certificate.to_pem
|
107
|
-
|
108
|
-
execute_post_issue_hooks(common_name)
|
109
27
|
end
|
110
28
|
|
111
29
|
desc "post-issue-hooks COMMON_NAME", "Run all post-issueing hooks for common name. (for testing purpose)"
|
112
30
|
def post_issue_hooks(common_name)
|
113
|
-
|
31
|
+
client.post_issue_hooks(common_name)
|
114
32
|
end
|
115
33
|
map 'post-issue-hooks' => :post_issue_hooks
|
116
34
|
|
117
35
|
desc "list [COMMON_NAME]", "list certificates or its versions"
|
118
36
|
def list(common_name = nil)
|
119
37
|
if common_name
|
120
|
-
puts
|
38
|
+
puts client.certificate_versions(common_name)
|
121
39
|
else
|
122
|
-
puts
|
40
|
+
puts client.certificates_list
|
123
41
|
end
|
124
42
|
end
|
125
43
|
|
126
44
|
desc "current COMMON_NAME", "show current version for certificate"
|
127
45
|
def current(common_name)
|
128
|
-
puts
|
46
|
+
puts client.current(common_name)
|
129
47
|
end
|
130
48
|
|
131
49
|
desc "show-certificate COMMON_NAME", "show certificate"
|
132
50
|
method_option :version, type: :string, default: 'current'
|
133
51
|
method_option :type, type: :string, enum: %w(text certificate chain fullchain), default: 'text'
|
134
52
|
def show_certificate(common_name)
|
135
|
-
|
136
|
-
|
137
|
-
case options[:type]
|
138
|
-
when 'text'
|
139
|
-
puts cert.certificate.to_text
|
140
|
-
puts cert.certificate.to_pem
|
141
|
-
when 'certificate'
|
142
|
-
puts cert.certificate.to_pem
|
143
|
-
when 'chain'
|
144
|
-
puts cert.chain
|
145
|
-
when 'fullchain'
|
146
|
-
puts cert.fullchain
|
147
|
-
end
|
53
|
+
certs = client.get_certificate(common_name, version: options[:version], type: options[:type])
|
54
|
+
puts certs
|
148
55
|
end
|
149
56
|
map 'show-certiticate' => :show_certificate
|
150
57
|
|
@@ -153,19 +60,13 @@ module Acmesmith
|
|
153
60
|
method_option :output, type: :string, required: true, banner: 'PATH', desc: 'Path to output file'
|
154
61
|
method_option :mode, type: :string, default: '0600', desc: 'Mode (permission) of the output file on create'
|
155
62
|
def save_certificate(common_name)
|
156
|
-
|
157
|
-
File.open(options[:output], 'w', options[:mode].to_i(8)) do |f|
|
158
|
-
f.puts(cert.fullchain)
|
159
|
-
end
|
63
|
+
client.save_certificate(common_name, version: options[:version], mode: options[:mode], output: options[:output])
|
160
64
|
end
|
161
65
|
|
162
66
|
desc "show-private-key COMMON_NAME", "show private key"
|
163
67
|
method_option :version, type: :string, default: 'current'
|
164
68
|
def show_private_key(common_name)
|
165
|
-
|
166
|
-
cert.key_passphrase = certificate_key_passphrase if certificate_key_passphrase
|
167
|
-
|
168
|
-
puts cert.private_key.to_pem
|
69
|
+
puts client.get_private_key(common_name, version: options[:version])
|
169
70
|
end
|
170
71
|
map 'show-private-key' => :show_private_key
|
171
72
|
|
@@ -174,11 +75,7 @@ module Acmesmith
|
|
174
75
|
method_option :output, type: :string, required: true, banner: 'PATH', desc: 'Path to output file'
|
175
76
|
method_option :mode, type: :string, default: '0600', desc: 'Mode (permission) of the output file on create'
|
176
77
|
def save_private_key(common_name)
|
177
|
-
|
178
|
-
cert.key_passphrase = certificate_key_passphrase if certificate_key_passphrase
|
179
|
-
File.open(options[:output], 'w', options[:mode].to_i(8)) do |f|
|
180
|
-
f.puts(cert.private_key)
|
181
|
-
end
|
78
|
+
client.save_private_key(common_name, version: options[:version], mode: options[:mode], output: options[:output])
|
182
79
|
end
|
183
80
|
|
184
81
|
desc 'save-pkcs12 COMMON_NAME', 'Save ceriticate and private key to .p12 file'
|
@@ -186,9 +83,6 @@ module Acmesmith
|
|
186
83
|
method_option :output, type: :string, required: true, banner: 'PATH', desc: 'Path to output file'
|
187
84
|
method_option :mode, type: :string, default: '0600', desc: 'Mode (permission) of the output file on create'
|
188
85
|
def save_pkcs12(common_name)
|
189
|
-
cert = storage.get_certificate(common_name, version: options[:version])
|
190
|
-
cert.key_passphrase = certificate_key_passphrase if certificate_key_passphrase
|
191
|
-
|
192
86
|
print 'Passphrase: '
|
193
87
|
passphrase = $stdin.noecho { $stdin.gets }.chomp
|
194
88
|
print "\nPassphrase (confirm): "
|
@@ -196,81 +90,26 @@ module Acmesmith
|
|
196
90
|
puts
|
197
91
|
|
198
92
|
raise ArgumentError, "Passphrase doesn't match" if passphrase != passphrase2
|
199
|
-
|
200
|
-
p12 = OpenSSL::PKCS12.create(passphrase, cert.common_name, cert.private_key, cert.certificate)
|
201
|
-
File.open(options[:output], 'w', options[:mode].to_i(8)) do |f|
|
202
|
-
f.puts p12.to_der
|
203
|
-
end
|
93
|
+
client.save_pkcs12(common_name, version: options[:version], mode: options[:mode], output: options[:output], passphrase: passphrase)
|
204
94
|
end
|
205
95
|
|
206
96
|
desc "autorenew", "request renewal of certificates which expires soon"
|
207
97
|
method_option :days, type: :numeric, aliases: %w(-d), default: 7, desc: 'specify threshold in days to select certificates to renew'
|
208
98
|
def autorenew
|
209
|
-
|
210
|
-
puts "=> #{cn}"
|
211
|
-
cert = storage.get_certificate(cn)
|
212
|
-
not_after = cert.certificate.not_after.utc
|
213
|
-
|
214
|
-
puts " Not valid after: #{not_after}"
|
215
|
-
next unless (cert.certificate.not_after.utc - Time.now.utc) < (options[:days].to_i * 86400)
|
216
|
-
puts " * Renewing: CN=#{cert.common_name}, SANs=#{cert.sans.join(',')}"
|
217
|
-
request(cert.common_name, *cert.sans)
|
218
|
-
end
|
99
|
+
client.autorenew(options[:days])
|
219
100
|
end
|
220
101
|
|
221
102
|
desc "add-san COMMON_NAME [ADDITIONAL_SANS]", "request renewal of existing certificate with additional SANs"
|
222
103
|
def add_san(common_name, *add_sans)
|
223
|
-
|
224
|
-
cert = storage.get_certificate(common_name)
|
225
|
-
sans = cert.sans + add_sans
|
226
|
-
puts " * SANs will be: #{sans.join(?,)}"
|
227
|
-
request(cert.common_name, *sans)
|
104
|
+
client.add_san(common_name, *add_sans)
|
228
105
|
end
|
229
106
|
|
230
107
|
private
|
231
108
|
|
232
|
-
def
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
def storage
|
237
|
-
config.storage
|
109
|
+
def client
|
110
|
+
config = Config.load_yaml(options[:config])
|
111
|
+
config.merge!("passphrase_from_env" => options[:passphrase_from_env]) unless options[:passphrase_from_env].nil?
|
112
|
+
@client = Client.new(config: config)
|
238
113
|
end
|
239
|
-
|
240
|
-
def account_key
|
241
|
-
@account_key ||= storage.get_account_key.tap do |x|
|
242
|
-
x.key_passphrase = account_key_passphrase if account_key_passphrase
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
def acme
|
247
|
-
@acme ||= Acme::Client.new(private_key: account_key.private_key, endpoint: config['endpoint'])
|
248
|
-
end
|
249
|
-
|
250
|
-
def certificate_key_passphrase
|
251
|
-
if options[:passphrase_from_env] || config['passphrase_from_env']
|
252
|
-
ENV['ACMESMITH_CERTIFICATE_KEY_PASSPHRASE'] || config['certificate_key_passphrase']
|
253
|
-
else
|
254
|
-
config['certificate_key_passphrase']
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
|
-
def account_key_passphrase
|
259
|
-
if options[:passphrase_from_env] || config['passphrase_from_env']
|
260
|
-
ENV['ACMESMITH_ACCOUNT_KEY_PASSPHRASE'] || config['account_key_passphrase']
|
261
|
-
else
|
262
|
-
config['account_key_passphrase']
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
def execute_post_issue_hooks(common_name)
|
267
|
-
post_issues_hooks_for_common_name = config.post_issueing_hooks(common_name)
|
268
|
-
if post_issues_hooks_for_common_name
|
269
|
-
post_issues_hooks_for_common_name.each do |hook|
|
270
|
-
hook.execute
|
271
|
-
end
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
114
|
end
|
276
115
|
end
|
data/lib/acmesmith/config.rb
CHANGED
data/lib/acmesmith/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acmesmith
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- sorah (Shota Fukumori)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-07-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: acme-client
|
@@ -124,6 +124,7 @@ files:
|
|
124
124
|
- lib/acmesmith/challenge_responders.rb
|
125
125
|
- lib/acmesmith/challenge_responders/base.rb
|
126
126
|
- lib/acmesmith/challenge_responders/route53.rb
|
127
|
+
- lib/acmesmith/client.rb
|
127
128
|
- lib/acmesmith/command.rb
|
128
129
|
- lib/acmesmith/config.rb
|
129
130
|
- lib/acmesmith/post_issueing_hooks.rb
|
@@ -152,12 +153,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
152
153
|
version: '0'
|
153
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
154
155
|
requirements:
|
155
|
-
- - "
|
156
|
+
- - ">"
|
156
157
|
- !ruby/object:Gem::Version
|
157
|
-
version:
|
158
|
+
version: 1.3.1
|
158
159
|
requirements: []
|
159
160
|
rubyforge_project:
|
160
|
-
rubygems_version: 2.6.
|
161
|
+
rubygems_version: 2.6.11
|
161
162
|
signing_key:
|
162
163
|
specification_version: 4
|
163
164
|
summary: ACME client (Let's encrypt client) to manage certificate in multi server
|