bullion 0.1.2 → 0.3.0
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/.roxanne.yml +14 -0
- data/.rubocop.yml +25 -6
- data/.ruby-version +1 -0
- data/.travis.yml +2 -1
- data/Dockerfile +2 -2
- data/Gemfile +1 -1
- data/Gemfile.lock +99 -89
- data/README.md +2 -2
- data/Rakefile +40 -37
- data/bin/console +3 -3
- data/bullion.gemspec +38 -36
- data/config/puma.rb +1 -1
- data/config.ru +5 -5
- data/db/migrate/20210104060422_create_certificates.rb +1 -1
- data/db/migrate/20210105060406_create_orders.rb +1 -1
- data/db/migrate/20210106052306_create_authorizations.rb +1 -1
- data/db/schema.rb +20 -21
- data/lib/bullion/acme/error.rb +9 -9
- data/lib/bullion/challenge_client.rb +4 -4
- data/lib/bullion/challenge_clients/dns.rb +36 -21
- data/lib/bullion/challenge_clients/http.rb +12 -8
- data/lib/bullion/helpers/acme.rb +30 -40
- data/lib/bullion/helpers/service.rb +2 -2
- data/lib/bullion/helpers/ssl.rb +50 -42
- data/lib/bullion/models/account.rb +1 -1
- data/lib/bullion/models/certificate.rb +2 -2
- data/lib/bullion/models/challenge.rb +5 -5
- data/lib/bullion/models/nonce.rb +1 -1
- data/lib/bullion/models.rb +6 -6
- data/lib/bullion/rspec/challenge_clients/dns.rb +22 -0
- data/lib/bullion/rspec/challenge_clients/http.rb +16 -0
- data/lib/bullion/service.rb +3 -2
- data/lib/bullion/services/ca.rb +107 -91
- data/lib/bullion/services/ping.rb +6 -6
- data/lib/bullion/version.rb +3 -3
- data/lib/bullion.rb +58 -45
- data/scripts/build.sh +3 -0
- data/scripts/release.sh +9 -0
- data/scripts/test.sh +6 -0
- metadata +65 -30
data/lib/bullion/services/ca.rb
CHANGED
@@ -15,174 +15,174 @@ module Bullion
|
|
15
15
|
|
16
16
|
after do
|
17
17
|
if request.options?
|
18
|
-
@allowed_types ||= [
|
19
|
-
headers
|
18
|
+
@allowed_types ||= ["POST"]
|
19
|
+
headers "Access-Control-Allow-Methods" => @allowed_types
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
options
|
24
|
-
@allowed_types = [
|
23
|
+
options "/directory" do
|
24
|
+
@allowed_types = ["GET"]
|
25
25
|
halt 200
|
26
26
|
end
|
27
27
|
|
28
|
-
options
|
28
|
+
options "/nonces" do
|
29
29
|
@allowed_types = %w[HEAD GET]
|
30
30
|
halt 200
|
31
31
|
end
|
32
32
|
|
33
|
-
options
|
33
|
+
options "/accounts" do
|
34
34
|
halt 200
|
35
35
|
end
|
36
36
|
|
37
|
-
options
|
37
|
+
options "/accounts/:id" do
|
38
38
|
halt 200
|
39
39
|
end
|
40
40
|
|
41
|
-
options
|
41
|
+
options "/accounts/:id/orders" do
|
42
42
|
halt 200
|
43
43
|
end
|
44
44
|
|
45
|
-
options
|
45
|
+
options "/orders" do
|
46
46
|
halt 200
|
47
47
|
end
|
48
48
|
|
49
|
-
options
|
49
|
+
options "/orders/:id" do
|
50
50
|
halt 200
|
51
51
|
end
|
52
52
|
|
53
|
-
options
|
53
|
+
options "/orders/:id/finalize" do
|
54
54
|
halt 200
|
55
55
|
end
|
56
56
|
|
57
|
-
options
|
57
|
+
options "/authorizations/:id" do
|
58
58
|
halt 200
|
59
59
|
end
|
60
60
|
|
61
|
-
options
|
61
|
+
options "/challenges/:id" do
|
62
62
|
halt 200
|
63
63
|
end
|
64
64
|
|
65
|
-
options
|
65
|
+
options "/certificates/:id" do
|
66
66
|
halt 200
|
67
67
|
end
|
68
68
|
|
69
69
|
# Non-standard endpoint that returns the CA bundle for Bullion
|
70
70
|
# Trusting this bundle should be sufficient to trust all Bullion-issued certs
|
71
|
-
options
|
72
|
-
@allowed_types = [
|
71
|
+
options "/cabundle" do
|
72
|
+
@allowed_types = ["GET"]
|
73
73
|
halt 200
|
74
74
|
end
|
75
75
|
|
76
76
|
# The directory is used to find all required URLs for the ACME endpoints
|
77
77
|
# @see https://tools.ietf.org/html/rfc8555#section-7.1.1
|
78
|
-
get
|
79
|
-
content_type
|
78
|
+
get "/directory" do
|
79
|
+
content_type "application/json"
|
80
80
|
|
81
81
|
{
|
82
|
-
newNonce: uri(
|
83
|
-
newAccount: uri(
|
84
|
-
newOrder: uri(
|
85
|
-
revokeCert: uri(
|
86
|
-
keyChange: uri(
|
82
|
+
newNonce: uri("/nonces"),
|
83
|
+
newAccount: uri("/accounts"),
|
84
|
+
newOrder: uri("/orders"),
|
85
|
+
revokeCert: uri("/revokecert"),
|
86
|
+
keyChange: uri("/keychanges"),
|
87
87
|
# non-standard entries:
|
88
|
-
caBundle: uri(
|
88
|
+
caBundle: uri("/cabundle")
|
89
89
|
}.to_json
|
90
90
|
end
|
91
91
|
|
92
92
|
# Responds with Bullion's PEM-encoded public cert
|
93
|
-
get
|
93
|
+
get "/cabundle" do
|
94
94
|
expires 3600 * 48, :public, :must_revalidate
|
95
|
-
content_type
|
95
|
+
content_type "application/x-pem-file"
|
96
96
|
|
97
|
-
attachment
|
97
|
+
attachment "cabundle.pem"
|
98
98
|
Bullion.ca_cert.to_pem
|
99
99
|
end
|
100
100
|
|
101
101
|
# Retrieves a Nonce via a HEAD request
|
102
102
|
# @see https://tools.ietf.org/html/rfc8555#section-7.2
|
103
|
-
head
|
104
|
-
add_acme_headers @new_nonce, additional: {
|
103
|
+
head "/nonces" do
|
104
|
+
add_acme_headers @new_nonce, additional: { "Cache-Control" => "no-store" }
|
105
105
|
|
106
106
|
halt 200
|
107
107
|
end
|
108
108
|
|
109
109
|
# Retrieves a Nonce via a GET request
|
110
110
|
# @see https://tools.ietf.org/html/rfc8555#section-7.2
|
111
|
-
get
|
112
|
-
add_acme_headers @new_nonce, additional: {
|
111
|
+
get "/nonces" do
|
112
|
+
add_acme_headers @new_nonce, additional: { "Cache-Control" => "no-store" }
|
113
113
|
|
114
114
|
halt 204
|
115
115
|
end
|
116
116
|
|
117
117
|
# Creates an account or verifies that an account exists
|
118
118
|
# @see https://tools.ietf.org/html/rfc8555#section-7.3
|
119
|
-
post
|
119
|
+
post "/accounts" do
|
120
120
|
header_data = JSON.parse(Base64.decode64(@json_body[:protected]))
|
121
121
|
begin
|
122
|
-
parse_acme_jwt(header_data[
|
122
|
+
parse_acme_jwt(header_data["jwk"], validate_nonce: false)
|
123
123
|
|
124
124
|
validate_account_data(@payload_data)
|
125
125
|
rescue Bullion::Acme::Error => e
|
126
|
-
content_type
|
126
|
+
content_type "application/problem+json"
|
127
127
|
halt 400, { type: e.acme_error, detail: e.message }.to_json
|
128
128
|
end
|
129
129
|
|
130
130
|
user = Models::Account.where(
|
131
|
-
public_key: header_data[
|
131
|
+
public_key: header_data["jwk"]
|
132
132
|
).first
|
133
133
|
|
134
|
-
if @payload_data[
|
135
|
-
content_type
|
136
|
-
halt 400, { type:
|
134
|
+
if @payload_data["onlyReturnExisting"]
|
135
|
+
content_type "application/problem+json"
|
136
|
+
halt 400, { type: "urn:ietf:params:acme:error:accountDoesNotExist" }.to_json unless user
|
137
137
|
end
|
138
138
|
|
139
|
-
user ||= Models::Account.new(public_key: header_data[
|
139
|
+
user ||= Models::Account.new(public_key: header_data["jwk"])
|
140
140
|
user.tos_agreed = true
|
141
|
-
user.contacts = @payload_data[
|
141
|
+
user.contacts = @payload_data["contact"]
|
142
142
|
user.save
|
143
143
|
|
144
|
-
content_type
|
145
|
-
add_acme_headers @new_nonce, additional: {
|
144
|
+
content_type "application/json"
|
145
|
+
add_acme_headers @new_nonce, additional: { "Location" => uri("/accounts/#{user.id}") }
|
146
146
|
|
147
147
|
halt 201, {
|
148
|
-
|
149
|
-
|
150
|
-
|
148
|
+
status: user.tos_agreed? ? "valid" : "pending",
|
149
|
+
contact: user.contacts,
|
150
|
+
orders: uri("/accounts/#{user.id}/orders")
|
151
151
|
}.to_json
|
152
152
|
end
|
153
153
|
|
154
154
|
# Endpoint for updating accounts
|
155
155
|
# @see https://tools.ietf.org/html/rfc8555#section-7.3.2
|
156
|
-
post
|
156
|
+
post "/accounts/:id" do
|
157
157
|
parse_acme_jwt
|
158
158
|
|
159
159
|
unless params[:id] == @user.id
|
160
|
-
content_type
|
160
|
+
content_type "application/json"
|
161
161
|
add_acme_headers @new_nonce
|
162
162
|
|
163
|
-
halt 403, { error:
|
163
|
+
halt 403, { error: "Accounts can only view or update themselves" }.to_json
|
164
164
|
end
|
165
165
|
|
166
|
-
content_type
|
166
|
+
content_type "application/json"
|
167
167
|
|
168
168
|
{
|
169
|
-
|
170
|
-
|
171
|
-
|
169
|
+
status: "valid",
|
170
|
+
orders: uri("/accounts/#{@user.id}/orders"),
|
171
|
+
contact: @user.contacts
|
172
172
|
}.to_json
|
173
173
|
end
|
174
174
|
|
175
|
-
post
|
175
|
+
post "/accounts/:id/orders" do
|
176
176
|
parse_acme_jwt
|
177
177
|
|
178
178
|
unless params[:id] == @user.id
|
179
|
-
content_type
|
179
|
+
content_type "application/json"
|
180
180
|
add_acme_headers @new_nonce
|
181
181
|
|
182
|
-
halt 403, { error:
|
182
|
+
halt 403, { error: "Accounts can only view or update themselves" }.to_json
|
183
183
|
end
|
184
184
|
|
185
|
-
content_type
|
185
|
+
content_type "application/json"
|
186
186
|
add_acme_headers @new_nonce
|
187
187
|
|
188
188
|
{
|
@@ -192,22 +192,22 @@ module Bullion
|
|
192
192
|
|
193
193
|
# Endpoint for creating new orders
|
194
194
|
# @see https://tools.ietf.org/html/rfc8555#section-7.4
|
195
|
-
post
|
195
|
+
post "/orders" do
|
196
196
|
parse_acme_jwt
|
197
197
|
|
198
198
|
# Only identifiers of type "dns" are supported
|
199
|
-
identifiers = @payload_data[
|
199
|
+
identifiers = @payload_data["identifiers"].select { |i| i["type"] == "dns" }
|
200
200
|
|
201
201
|
validate_order(@payload_data)
|
202
202
|
|
203
203
|
order = @user.start_order(
|
204
|
-
identifiers
|
205
|
-
not_before: @payload_data[
|
206
|
-
not_after: @payload_data[
|
204
|
+
identifiers:,
|
205
|
+
not_before: @payload_data["notBefore"],
|
206
|
+
not_after: @payload_data["notAfter"]
|
207
207
|
)
|
208
208
|
|
209
|
-
content_type
|
210
|
-
add_acme_headers @new_nonce, additional: {
|
209
|
+
content_type "application/json"
|
210
|
+
add_acme_headers @new_nonce, additional: { "Location" => uri("/orders/#{order.id}") }
|
211
211
|
|
212
212
|
halt 201, {
|
213
213
|
status: order.status,
|
@@ -219,15 +219,15 @@ module Bullion
|
|
219
219
|
finalize: uri("/orders/#{order.id}/finalize")
|
220
220
|
}.to_json
|
221
221
|
rescue Bullion::Acme::Error => e
|
222
|
-
content_type
|
222
|
+
content_type "application/problem+json"
|
223
223
|
halt 400, { type: e.acme_error, detail: e.message }.to_json
|
224
224
|
end
|
225
225
|
|
226
226
|
# Retrieve existing Orders
|
227
|
-
post
|
227
|
+
post "/orders/:id" do
|
228
228
|
parse_acme_jwt
|
229
229
|
|
230
|
-
content_type
|
230
|
+
content_type "application/json"
|
231
231
|
add_acme_headers @new_nonce
|
232
232
|
|
233
233
|
order = Models::Order.find(params[:id])
|
@@ -242,40 +242,43 @@ module Bullion
|
|
242
242
|
finalize: uri("/orders/#{order.id}/finalize")
|
243
243
|
}
|
244
244
|
|
245
|
-
data[:certificate] = uri("/certificates/#{order.certificate.id}") if order.status ==
|
245
|
+
data[:certificate] = uri("/certificates/#{order.certificate.id}") if order.status == "valid"
|
246
246
|
|
247
247
|
data.to_json
|
248
|
+
rescue Bullion::Acme::Error => e
|
249
|
+
content_type "application/problem+json"
|
250
|
+
halt 400, { type: e.acme_error, detail: e.message }.to_json
|
248
251
|
end
|
249
252
|
|
250
253
|
# Submit an order for finalization/signing
|
251
254
|
# @see https://tools.ietf.org/html/rfc8555#section-7.4
|
252
|
-
post
|
255
|
+
post "/orders/:id/finalize" do
|
253
256
|
parse_acme_jwt
|
254
257
|
|
255
|
-
|
256
|
-
add_acme_headers @new_nonce, additional: { 'Location' => uri("/orders/#{order.id}") }
|
258
|
+
order = Models::Order.find(params[:id])
|
257
259
|
|
258
|
-
|
260
|
+
content_type "application/json"
|
261
|
+
add_acme_headers @new_nonce, additional: { "Location" => uri("/orders/#{order.id}") }
|
262
|
+
|
263
|
+
raw_csr_data = Base64.urlsafe_decode64(@payload_data["csr"])
|
259
264
|
encoded_csr = Base64.encode64(raw_csr_data)
|
260
265
|
|
261
266
|
csr_data = openssl_compat_csr(encoded_csr)
|
262
267
|
|
263
268
|
csr = OpenSSL::X509::Request.new(csr_data)
|
264
269
|
|
265
|
-
order
|
266
|
-
|
267
|
-
unless validate_csr(csr) && validate_acme_csr(order, csr)
|
268
|
-
content_type 'application/problem+json'
|
270
|
+
unless validate_acme_csr(order, csr)
|
271
|
+
content_type "application/problem+json"
|
269
272
|
halt 400, {
|
270
|
-
type: Bullion::Acme::Errors::
|
271
|
-
detail:
|
273
|
+
type: Bullion::Acme::Errors::BadCsr.new.acme_error,
|
274
|
+
detail: "CSR failed validation"
|
272
275
|
}.to_json
|
273
276
|
end
|
274
277
|
|
275
|
-
cert_id = sign_csr(csr, @user.contacts.first
|
278
|
+
cert_id = sign_csr(csr, @user.contacts.first).last
|
276
279
|
|
277
280
|
order.certificate_id = cert_id
|
278
|
-
order.status =
|
281
|
+
order.status = "valid"
|
279
282
|
order.save
|
280
283
|
|
281
284
|
data = {
|
@@ -288,17 +291,20 @@ module Bullion
|
|
288
291
|
finalize: uri("/orders/#{order.id}/finalize")
|
289
292
|
}
|
290
293
|
|
291
|
-
data[:certificate] = uri("/certificates/#{order.certificate.id}") if order.status ==
|
294
|
+
data[:certificate] = uri("/certificates/#{order.certificate.id}") if order.status == "valid"
|
292
295
|
|
293
296
|
data.to_json
|
297
|
+
rescue Bullion::Acme::Error => e
|
298
|
+
content_type "application/problem+json"
|
299
|
+
halt 422, { type: e.acme_error, detail: e.message }.to_json
|
294
300
|
end
|
295
301
|
|
296
302
|
# Shows that the client controls the account private key
|
297
303
|
# @see https://tools.ietf.org/html/rfc8555#section-7.5
|
298
|
-
post
|
304
|
+
post "/authorizations/:id" do
|
299
305
|
parse_acme_jwt
|
300
306
|
|
301
|
-
content_type
|
307
|
+
content_type "application/json"
|
302
308
|
add_acme_headers @new_nonce
|
303
309
|
|
304
310
|
authorization = Models::Authorization.find(params[:id])
|
@@ -314,27 +320,30 @@ module Bullion
|
|
314
320
|
chash[:url] = uri("/challenges/#{c.id}")
|
315
321
|
chash[:token] = c.token
|
316
322
|
chash[:status] = c.status
|
317
|
-
chash[:validated] = c.validated if c.status ==
|
323
|
+
chash[:validated] = c.validated if c.status == "valid"
|
318
324
|
|
319
325
|
chash
|
320
326
|
end
|
321
327
|
}
|
322
328
|
|
323
329
|
data.to_json
|
330
|
+
rescue Bullion::Acme::Error => e
|
331
|
+
content_type "application/problem+json"
|
332
|
+
halt 422, { type: e.acme_error, detail: e.message }.to_json
|
324
333
|
end
|
325
334
|
|
326
335
|
# Starts server verification of a challenge (either HTTP call or DNS lookup)
|
327
336
|
# @see https://tools.ietf.org/html/rfc8555#section-7.5.1
|
328
|
-
post
|
337
|
+
post "/challenges/:id" do
|
329
338
|
parse_acme_jwt
|
330
339
|
|
331
|
-
content_type
|
340
|
+
content_type "application/json"
|
332
341
|
add_acme_headers @new_nonce
|
333
342
|
|
334
343
|
challenge = Models::Challenge.find(params[:id])
|
335
344
|
|
336
345
|
# Oddly enough, cert-manager uses a GET request for retrieving Challenge info
|
337
|
-
challenge.client.attempt unless @
|
346
|
+
challenge.client.attempt unless @json_body && @json_body[:payload] == ""
|
338
347
|
|
339
348
|
data = {
|
340
349
|
type: challenge.acme_type,
|
@@ -344,25 +353,32 @@ module Bullion
|
|
344
353
|
url: uri("/challenges/#{challenge.id}")
|
345
354
|
}
|
346
355
|
|
347
|
-
|
356
|
+
if challenge.status == "valid"
|
357
|
+
data[:validated] = challenge.validated
|
358
|
+
order = challenge.authorization.order
|
359
|
+
order.update!(status: "ready") unless order.status == "ready"
|
360
|
+
end
|
348
361
|
|
349
362
|
data.to_json
|
363
|
+
rescue Bullion::Acme::Error => e
|
364
|
+
content_type "application/problem+json"
|
365
|
+
halt 422, { type: e.acme_error, detail: e.message }.to_json
|
350
366
|
end
|
351
367
|
|
352
368
|
# Retrieves a signed certificate
|
353
369
|
# @see https://tools.ietf.org/html/rfc8555#section-7.4.2
|
354
|
-
post
|
370
|
+
post "/certificates/:id" do
|
355
371
|
parse_acme_jwt
|
356
372
|
|
357
373
|
order = Models::Order.where(certificate_id: params[:id]).first
|
358
|
-
if order && order.status ==
|
359
|
-
content_type
|
374
|
+
if order && order.status == "valid"
|
375
|
+
content_type "application/pem-certificate-chain"
|
360
376
|
|
361
377
|
cert = Models::Certificate.find(params[:id])
|
362
378
|
|
363
379
|
cert.data + Bullion.ca_cert.to_pem
|
364
380
|
else
|
365
|
-
halt(422, {
|
381
|
+
halt(422, { error: "Order not valid" }.to_json)
|
366
382
|
end
|
367
383
|
end
|
368
384
|
end
|
@@ -10,25 +10,25 @@ module Bullion
|
|
10
10
|
end
|
11
11
|
|
12
12
|
before do
|
13
|
-
content_type
|
13
|
+
content_type "application/json"
|
14
14
|
|
15
15
|
halt 403 unless request.get? || request.options?
|
16
16
|
|
17
17
|
if request.get?
|
18
|
-
headers
|
19
|
-
headers
|
18
|
+
headers "X-Frame-Options" => "SAMEORIGIN"
|
19
|
+
headers "X-XSS-Protection" => "1; mode=block"
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
after do
|
24
|
-
headers
|
24
|
+
headers "Access-Control-Allow-Methods" => %w[GET] if request.options?
|
25
25
|
end
|
26
26
|
|
27
|
-
get
|
27
|
+
get "/" do
|
28
28
|
'{ "status": "up" }'
|
29
29
|
end
|
30
30
|
|
31
|
-
options
|
31
|
+
options "/" do
|
32
32
|
halt 200
|
33
33
|
end
|
34
34
|
end
|
data/lib/bullion/version.rb
CHANGED
data/lib/bullion.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Standard Library requirements
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
4
|
+
require "base64"
|
5
|
+
require "resolv"
|
6
|
+
require "securerandom"
|
7
|
+
require "time"
|
8
|
+
require "logger"
|
9
|
+
require "openssl"
|
10
10
|
|
11
11
|
# External requirements
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
12
|
+
require "sinatra/base"
|
13
|
+
require "sinatra/custom_logger"
|
14
|
+
require "mysql2"
|
15
|
+
require "sinatra/activerecord"
|
16
|
+
require "jwt"
|
17
|
+
require "prometheus/client"
|
18
|
+
require "httparty"
|
19
19
|
|
20
20
|
# The top-level module for Bullion
|
21
21
|
module Bullion
|
@@ -25,33 +25,35 @@ module Bullion
|
|
25
25
|
LOGGER = Logger.new($stdout)
|
26
26
|
|
27
27
|
# Config through environment variables
|
28
|
-
CA_DIR = File.expand_path ENV.fetch(
|
29
|
-
CA_SECRET = ENV.fetch(
|
30
|
-
CA_KEY_PATH = ENV.fetch(
|
31
|
-
CA_CERT_PATH = ENV.fetch(
|
32
|
-
CA_DOMAINS = ENV.fetch(
|
28
|
+
CA_DIR = File.expand_path ENV.fetch("CA_DIR", "tmp")
|
29
|
+
CA_SECRET = ENV.fetch("CA_SECRET", "SomeS3cret")
|
30
|
+
CA_KEY_PATH = ENV.fetch("CA_KEY_PATH") { File.join(CA_DIR, "tls.key") }
|
31
|
+
CA_CERT_PATH = ENV.fetch("CA_CERT_PATH") { File.join(CA_DIR, "tls.crt") }
|
32
|
+
CA_DOMAINS = ENV.fetch("CA_DOMAINS", "example.com").split(",")
|
33
33
|
|
34
34
|
# Set up log level
|
35
|
-
LOGGER.level = ENV.fetch(
|
35
|
+
LOGGER.level = ENV.fetch("LOG_LEVEL", :warn)
|
36
36
|
|
37
37
|
# 90 days cert expiration
|
38
38
|
CERT_VALIDITY_DURATION = Integer(
|
39
|
-
ENV.fetch(
|
39
|
+
ENV.fetch("CERT_VALIDITY_DURATION", 60 * 60 * 24 * 30 * 3)
|
40
40
|
)
|
41
41
|
|
42
42
|
DB_CONNECTION_SETTINGS =
|
43
|
-
ENV
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
43
|
+
ENV.fetch("DATABASE_URL") do
|
44
|
+
{
|
45
|
+
adapter: "mysql2",
|
46
|
+
database: ENV.fetch("DB_NAME", "bullion"),
|
47
|
+
encoding: ENV.fetch("DB_ENCODING", "utf8mb4"),
|
48
|
+
pool: Integer(ENV.fetch("MAX_THREADS", 32)),
|
49
|
+
username: ENV.fetch("DB_USERNAME", "root"),
|
50
|
+
password: ENV.fetch("DB_PASSWORD", nil),
|
51
|
+
host: ENV.fetch("DB_HOST", "localhost")
|
52
|
+
}
|
53
|
+
end
|
52
54
|
DB_CONNECTION_SETTINGS.freeze
|
53
55
|
|
54
|
-
NAMESERVERS = ENV.fetch(
|
56
|
+
NAMESERVERS = ENV.fetch("DNS01_NAMESERVERS", "").split(",")
|
55
57
|
|
56
58
|
MetricsRegistry = Prometheus::Client.registry
|
57
59
|
|
@@ -74,24 +76,35 @@ module Bullion
|
|
74
76
|
# Ensures configuration settings are valid
|
75
77
|
# @see https://support.apple.com/en-us/HT211025
|
76
78
|
def self.validate_config!
|
77
|
-
raise ConfigError,
|
79
|
+
raise ConfigError, "Invalid Key Passphrase" unless CA_SECRET.is_a?(String)
|
78
80
|
raise ConfigError, "Invalid Key Path: #{CA_KEY_PATH}" unless File.readable?(CA_KEY_PATH)
|
79
81
|
raise ConfigError, "Invalid Cert Path: #{CA_CERT_PATH}" unless File.readable?(CA_CERT_PATH)
|
80
|
-
raise ConfigError,
|
81
|
-
raise ConfigError,
|
82
|
+
raise ConfigError, "Cert Validity Too Long" if CERT_VALIDITY_DURATION > 60 * 60 * 24 * 397
|
83
|
+
raise ConfigError, "Cert Validity Too Short" if CERT_VALIDITY_DURATION < 60 * 60 * 24 * 2
|
82
84
|
end
|
83
85
|
end
|
84
86
|
|
85
87
|
# Internal requirements
|
86
|
-
require
|
87
|
-
require
|
88
|
-
require
|
89
|
-
require
|
90
|
-
require
|
91
|
-
require
|
92
|
-
require
|
93
|
-
require
|
94
|
-
require
|
95
|
-
require
|
96
|
-
require
|
97
|
-
require
|
88
|
+
require "bullion/version"
|
89
|
+
require "bullion/acme/error"
|
90
|
+
require "bullion/helpers/acme"
|
91
|
+
require "bullion/helpers/service"
|
92
|
+
require "bullion/helpers/ssl"
|
93
|
+
require "bullion/models"
|
94
|
+
require "bullion/service"
|
95
|
+
require "bullion/services/ping"
|
96
|
+
require "bullion/services/ca"
|
97
|
+
require "bullion/challenge_client"
|
98
|
+
require "bullion/challenge_clients/dns"
|
99
|
+
require "bullion/challenge_clients/http"
|
100
|
+
|
101
|
+
if %w[development test].include?(ENV["RACK_ENV"])
|
102
|
+
require "bullion/rspec/challenge_clients/dns"
|
103
|
+
require "bullion/rspec/challenge_clients/http"
|
104
|
+
|
105
|
+
Bullion::DNS_CHALLENGE_CLIENT = Bullion::RSpec::ChallengeClients::DNS
|
106
|
+
Bullion::HTTP_CHALLENGE_CLIENT = Bullion::RSpec::ChallengeClients::HTTP
|
107
|
+
else
|
108
|
+
Bullion::DNS_CHALLENGE_CLIENT = Bullion::ChallengeClients::DNS
|
109
|
+
Bullion::HTTP_CHALLENGE_CLIENT = Bullion::ChallengeClients::HTTP
|
110
|
+
end
|
data/scripts/build.sh
ADDED
data/scripts/release.sh
ADDED