bullion 0.7.3 → 0.9.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.
data/Itsi.rb ADDED
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is the default Itsi configuration file, installed when you run `itsi init`
4
+ # It contains a sane starting point for configuring your Itsi server.
5
+ # You can use this file in both development and production environments.
6
+ # Most of the options in this file can be overridden by command line options.
7
+ # Check out itsi -h to learn more about the command line options available to you.
8
+
9
+ env = ENV.fetch("APP_ENV") { ENV.fetch("RACK_ENV", "development") }
10
+
11
+ # Number of worker processes to spawn
12
+ # If more than 1, Itsi will be booted in Cluster mode
13
+ workers ENV["ITSI_WORKERS"]&.to_i || (env == "development" ? 1 : nil)
14
+
15
+ # Number of threads to spawn per worker process
16
+ # For pure CPU bound applicationss, you'll get the best results keeping this number low
17
+ # Setting a value of 1 is great for superficial benchmarks, but in reality
18
+ # it's better to set this a bit higher to allow expensive requests to get overtaken and minimize head-of-line blocking
19
+ threads ENV.fetch("ITSI_THREADS", 3)
20
+
21
+ # If your application is IO bound (e.g. performing a lot of proxied HTTP requests, or heavy queries etc)
22
+ # you can see *substantial* benefits from enabling this option.
23
+ # To set this option, pass a string, not a class (as we will not have loaded the class yet)
24
+ # E.g.
25
+ # `fiber_scheduler "Itsi::Scheduler"` - The default fast and light-weight scheduler that comes with Itsi
26
+ # `fiber_scheduler "Async::Scheduler"` - Bring your own scheduler!
27
+ fiber_scheduler nil
28
+
29
+ # If you bind to https, without specifying a certificate, Itsi will use a self-signed certificate.
30
+ # The self-signed certificate will use a CA generated for your
31
+ # host and stored inside `ITSI_LOCAL_CA_DIR` (Defaults to ~/.itsi)
32
+ # bind "https://0.0.0.0:3000"
33
+ # bind "https://0.0.0.0:3000?domains=dev.itsi.fyi"
34
+ #
35
+ # If you want to use let's encrypt to generate you a real certificate you
36
+ # and pass cert=acme and an acme_email address to generate one.
37
+ # bind "https://itsi.fyi?cert=acme&acme_email=admin@itsi.fyi"
38
+ # You can generate certificates for multiple domains at once, by passing a comma-separated list of domains
39
+ # bind "https://0.0.0.0?domains=foo.itsi.fyi,bar.itsi.fyi&cert=acme&acme_email=admin@itsi.fyi"
40
+ #
41
+ # If you already have a certificate you can specify it using the cert and key parameters
42
+ # bind "https://itsi.fyi?cert=/path/to/cert.pem&key=/path/to/key.pem"
43
+ #
44
+ # You can also bind to a unix socket or a tls unix socket. E.g.
45
+ # bind "unix:///tmp/itsi.sock"
46
+ # bind "tls:///tmp/itsi.secure.sock"
47
+
48
+ bind "http://0.0.0.0:9292"
49
+
50
+ # If you want to preload the application, set preload to true
51
+ # to load the entire rack-app defined in rack_file_name before forking.
52
+ # Alternatively, you can preload just a specific set of gems in a group in your gemfile,
53
+ # by providing the group name here.
54
+ # E.g.
55
+ #
56
+ # preload :preload # Load gems inside the preload group
57
+ # preload false # Don't preload.
58
+ #
59
+ # If you want to be able to perform zero-downtime deploys using a single itsi process,
60
+ # you should disable preloads, so that the application is loaded fresh each time a new worker boots
61
+ preload true
62
+
63
+ # Set the maximum memory limit for each worker process in bytes
64
+ # When this limit is reached, the worker will be gracefully restarted.
65
+ # Only one worker is restarted at a time to ensure we don't take down
66
+ # all of them at once, if they reach the threshold simultaneously.
67
+ worker_memory_limit 1024 * 1024 * 1024
68
+
69
+ # You can provide an optional block of code to run, when a worker hits its memory threshold
70
+ # (Use this to send yourself an alert,
71
+ # write metrics to disk etc. etc.)
72
+ after_memory_limit_reached do |pid|
73
+ puts "Worker #{pid} has reached its memory threshold and will restart"
74
+ end
75
+
76
+ # Do clean up of any non-threadsafe resources before forking a new worker here.
77
+ before_fork {}
78
+
79
+ # Reinitialize any non-threadsafe resources after forking a new worker here.
80
+ after_fork {}
81
+
82
+ # Shutdown timeout
83
+ # Number of seconds to wait for workers to gracefully shutdown before killing them.
84
+ shutdown_timeout 5
85
+
86
+ # Set this to false for application environments that require rack.input to be a rewindable body
87
+ # (like Rails). For rack applications that can stream inputs, you can set this to true for a more
88
+ # memory-efficient approach.
89
+ stream_body false
90
+
91
+ # OOB GC responses threshold
92
+ # Specifies how frequently OOB gc should be triggered during periods where there is a gap in queued requests.
93
+ # Setting this too low can substantially worsen performance
94
+ oob_gc_responses_threshold 512
95
+
96
+ # Log level
97
+ # Set this to one of the following values: debug, info, warn, error, fatal
98
+ # Can also be set using the ITSI_LOG environment variable
99
+ log_level :info
100
+
101
+ # Log Format
102
+ # Set this to be either :plain or :json. If you leave it blank Itsi will try
103
+ # and auto-detect the format based on the TTY environment.
104
+ log_format :plain
105
+ # You can mount several Ruby apps as either
106
+ # 1. rackup files
107
+ # 2. inline rack apps
108
+ # 3. inline Ruby endpoints
109
+ #
110
+ # 1. rackup_file
111
+ rackup_file "./config.ru"
112
+ #
113
+ # 2. inline rack app
114
+ # require 'rack'
115
+ # run(Rack::Builder.app do
116
+ # use Rack::CommonLogger
117
+ # run ->(env) { [200, { 'content-type' => 'text/plain' }, ['OK']] }
118
+ # end)
119
+ #
120
+ # 3. Endpoints
121
+ # endpoint "/" do |req|
122
+ # req.ok "Hello from Itsi"
123
+ # end
data/Rakefile CHANGED
@@ -48,7 +48,7 @@ task :prep do
48
48
  root_ca.version = 2
49
49
  root_ca.serial = (2**rand(10..20)) - 1
50
50
  root_ca.subject = OpenSSL::X509::Name.parse(
51
- %w[test domain].reverse.map { |piece| "DC=#{piece}" }.join("/") + "/CN=bullion"
51
+ %w[test domain].reverse.map { "DC=#{it}" }.join("/") + "/CN=bullion"
52
52
  )
53
53
  root_ca.issuer = root_ca.subject # root CA's are "self-signed"
54
54
  root_ca.public_key = root_key.public_key
@@ -116,20 +116,23 @@ task :demo do
116
116
  system(
117
117
  "RACK_ENV=\"#{rack_env}\" DATABASE_URL=\"#{database_url}\" " \
118
118
  "LOG_LEVEL='#{ENV.fetch("LOG_LEVEL", "info")}' " \
119
- "rackup -D -P #{File.expand_path(".")}/tmp/daemon.pid"
119
+ "itsi --daemonize"
120
120
  )
121
+ FileUtils.touch(File.join(File.expand_path("."), "tmp", "daemon.pid"))
121
122
  end
122
123
 
123
124
  desc "Runs a foregrounded demo environment"
124
125
  task :foreground_demo do
125
- system("rackup -o 0.0.0.0 -P #{File.expand_path(".")}/tmp/daemon.pid")
126
+ system("itsi")
126
127
  end
127
128
 
128
129
  desc "Cleans up test or demo environment"
129
130
  task :cleanup do
130
131
  at_exit do
131
- if File.exist?("#{File.expand_path(".")}/tmp/daemon.pid")
132
- system("kill $(cat #{File.expand_path(".")}/tmp/daemon.pid) > /dev/null 2>&1")
132
+ pid_file = File.join(File.expand_path("."), "tmp", "daemon.pid")
133
+ if File.exist?(pid_file)
134
+ system("itsi stop")
135
+ FileUtils.rm_f(pid_file)
133
136
  end
134
137
  FileUtils.rm_f(File.join(File.expand_path("."), "tmp", "tls.crt"))
135
138
  FileUtils.rm_f(File.join(File.expand_path("."), "tmp", "tls.key"))
data/bullion.gemspec CHANGED
@@ -24,20 +24,21 @@ Gem::Specification.new do |spec|
24
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
25
  spec.require_paths = ["lib"]
26
26
 
27
- spec.required_ruby_version = "~> 3.2"
27
+ spec.required_ruby_version = "~> 3.4"
28
28
 
29
+ spec.add_dependency "benchmark", "~> 0.4"
29
30
  spec.add_dependency "dry-configurable", "~> 1.1"
30
31
  spec.add_dependency "httparty", "~> 0.21"
32
+ spec.add_dependency "itsi", "~> 0.2"
31
33
  spec.add_dependency "json", "~> 2.6"
32
34
  spec.add_dependency "jwt", "~> 2.7"
33
35
  spec.add_dependency "mysql2", "~> 0.5"
34
36
  spec.add_dependency "openssl", "~> 3.0"
35
37
  spec.add_dependency "prometheus-client", "~> 4.2"
36
- spec.add_dependency "puma", "~> 6.4"
37
38
  spec.add_dependency "sinatra", "~> 3.1"
38
39
  spec.add_dependency "sinatra-activerecord", "~> 2.0"
39
40
  spec.add_dependency "sinatra-contrib", "~> 3.1"
40
- spec.add_dependency "sqlite3", "~> 1.6"
41
+ spec.add_dependency "sqlite3", "~> 2.7"
41
42
 
42
43
  spec.add_development_dependency "acme-client", "~> 2.0"
43
44
  spec.add_development_dependency "bundler", "~> 2.4"
@@ -47,7 +48,7 @@ Gem::Specification.new do |spec|
47
48
  spec.add_development_dependency "rspec", "~> 3.12"
48
49
  spec.add_development_dependency "rubocop", "~> 1.57"
49
50
  spec.add_development_dependency "rubocop-rake", "~> 0.6"
50
- spec.add_development_dependency "rubocop-rspec", "~> 2.25"
51
+ spec.add_development_dependency "rubocop-rspec", "~> 3.5"
51
52
  spec.add_development_dependency "simplecov", "~> 0.22"
52
53
  spec.add_development_dependency "simplecov-cobertura", "~> 2.1"
53
54
  spec.add_development_dependency "solargraph", "~> 0.49"
data/config.ru CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # \ -s puma
4
-
5
3
  require "bullion"
6
4
  Bullion.validate_config!
7
5
 
data/db/schema.rb CHANGED
@@ -10,7 +10,7 @@
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema[7.2].define(version: 2021_01_06_060335) do
13
+ ActiveRecord::Schema[8.0].define(version: 2021_01_06_060335) do
14
14
  create_table "accounts", force: :cascade do |t|
15
15
  t.boolean "tos_agreed", default: true, null: false
16
16
  t.text "public_key", null: false
@@ -27,7 +27,7 @@ module Bullion
27
27
  benchtime = Benchmark.realtime do
28
28
  until success || tries >= retries
29
29
  tries += 1
30
- success = perform
30
+ success = performs_challenge?
31
31
  if success
32
32
  LOGGER.info "Validated #{type} #{identifier}"
33
33
  challenge.status = "valid"
@@ -59,5 +59,9 @@ module Bullion
59
59
  def identifier
60
60
  challenge.identifier
61
61
  end
62
+
63
+ def performs_challenge?
64
+ raise NotImplementedError
65
+ end
62
66
  end
63
67
  end
@@ -8,7 +8,7 @@ module Bullion
8
8
  def self.acme_type = "dns-01"
9
9
  def type = "DNS01"
10
10
 
11
- def perform
11
+ def performs_challenge?
12
12
  value = dns_value
13
13
  expected_value = digest_value("#{challenge.token}.#{challenge.thumbprint}")
14
14
 
@@ -8,7 +8,7 @@ module Bullion
8
8
  def self.acme_type = "http-01"
9
9
  def type = "HTTP01"
10
10
 
11
- def perform
11
+ def performs_challenge?
12
12
  response = begin
13
13
  retrieve_body(challenge_url)
14
14
  rescue SocketError
@@ -88,7 +88,7 @@ module Bullion
88
88
 
89
89
  # Validation helpers
90
90
 
91
- def validate_account_data(hash)
91
+ def account_data_valid?(hash)
92
92
  unless [true, false, nil].include?(hash["onlyReturnExisting"])
93
93
  raise Bullion::Acme::Errors::Malformed,
94
94
  "Invalid onlyReturnExisting: #{hash["onlyReturnExisting"]}"
@@ -113,31 +113,31 @@ module Bullion
113
113
  true
114
114
  end
115
115
 
116
- def validate_acme_csr(order, csr)
116
+ def acme_csr_valid?(order_csr)
117
+ csr = order_csr.csr
118
+ order = order_csr.order
117
119
  csr_attrs = extract_csr_attrs(csr)
118
120
  csr_sans = extract_csr_sans(csr_attrs)
119
121
  csr_domains = extract_csr_domains(csr_sans)
120
122
  csr_cn = cn_from_csr(csr)
121
123
 
122
- order_domains = order.identifiers.map { |i| i["value"] }
123
-
124
124
  # Make sure the CSR has a valid public key
125
125
  raise Bullion::Acme::Errors::BadCsr unless csr.verify(csr.public_key)
126
126
 
127
- return false unless order.status == "ready"
127
+ return false unless order.ready_status?
128
128
  raise Bullion::Acme::Errors::BadCsr unless csr_domains.include?(csr_cn)
129
- raise Bullion::Acme::Errors::BadCsr unless csr_domains.sort == order_domains.sort
129
+ raise Bullion::Acme::Errors::BadCsr unless csr_domains.sort == order.domains.sort
130
130
 
131
131
  true
132
132
  end
133
133
 
134
- def validate_order(hash)
134
+ def order_valid?(hash)
135
135
  validate_order_nb_and_na(hash["notBefore"], hash["notAfter"])
136
136
 
137
137
  # Don't approve empty orders
138
138
  raise Bullion::Acme::Errors::InvalidOrder, "Empty order!" if hash["identifiers"].empty?
139
139
 
140
- order_domains = hash["identifiers"].select { |ident| ident["type"] == "dns" }
140
+ order_domains = hash["identifiers"].select { it["type"] == "dns" }
141
141
 
142
142
  # Don't approve an order with identifiers that _aren't_ of type 'dns'
143
143
  unless hash["identifiers"] == order_domains
@@ -188,7 +188,7 @@ module Bullion
188
188
 
189
189
  def extract_valid_order_domains(order_domains)
190
190
  order_domains.reject do |domain|
191
- Bullion.config.ca.domains.none? { domain["value"].end_with?(_1) }
191
+ Bullion.config.ca.domains.none? { domain["value"].end_with?(it) }
192
192
  end
193
193
  end
194
194
  end
@@ -14,11 +14,6 @@ module Bullion
14
14
  end
15
15
  end
16
16
 
17
- def openssl_compat_csr(csrdata)
18
- "-----BEGIN CERTIFICATE REQUEST-----\n" \
19
- "#{csrdata}-----END CERTIFICATE REQUEST-----"
20
- end
21
-
22
17
  # @see https://tools.ietf.org/html/rfc7518#page-30
23
18
  def key_data_to_rsa(key_data)
24
19
  exponent = base64_to_long(key_data["e"])
@@ -205,7 +200,7 @@ module Bullion
205
200
  # Create a OpenSSL cert using select info from the CSR
206
201
  csr_cert = OpenSSL::X509::Certificate.new
207
202
  csr_cert.serial = cert.serial
208
- csr_cert.version = 2
203
+ csr_cert.version = 3
209
204
  csr_cert.not_before = Time.now
210
205
  # only 90 days for ACMEv2
211
206
  csr_cert.not_after = csr_cert.not_before + (3 * 30 * 24 * 60 * 60)
@@ -13,6 +13,15 @@ module Bullion
13
13
 
14
14
  validates :status, inclusion: { in: %w[invalid pending ready processing valid deactivated] }
15
15
 
16
+ enum :status, {
17
+ invalid: "invalid",
18
+ pending: "pending",
19
+ ready: "ready",
20
+ processing: "processing",
21
+ valid: "valid",
22
+ deactivated: "deactivated"
23
+ }, suffix: "status"
24
+
16
25
  def init_values
17
26
  self.expires ||= Time.now + (60 * 60)
18
27
  end
@@ -10,6 +10,8 @@ module Bullion
10
10
 
11
11
  validates_presence_of :subject
12
12
 
13
+ has_one :order
14
+
13
15
  def init_values
14
16
  self.serial ||= SecureRandom.hex(4).to_i(16)
15
17
  end
@@ -13,6 +13,13 @@ module Bullion
13
13
  }
14
14
  validates :status, inclusion: { in: %w[invalid pending processing valid] }
15
15
 
16
+ enum :status, {
17
+ invalid: "invalid",
18
+ pending: "pending",
19
+ processing: "processing",
20
+ valid: "valid"
21
+ }, suffix: "status"
22
+
16
23
  def identifier
17
24
  authorization.identifier["value"]
18
25
  end
@@ -29,7 +36,7 @@ module Bullion
29
36
  end
30
37
 
31
38
  def client
32
- challenge_class = Bullion.acme.challenge_clients.find { _1.acme_type == acme_type }
39
+ challenge_class = Bullion.acme.challenge_clients.find { it.acme_type == acme_type }
33
40
 
34
41
  unless challenge_class
35
42
  raise Bullion::Acme::Errors::UnsupportedChallengeType,
@@ -9,10 +9,19 @@ module Bullion
9
9
  after_initialize :init_values, unless: :persisted?
10
10
 
11
11
  belongs_to :account
12
+ belongs_to :certificate
12
13
  has_many :authorizations
13
14
 
14
15
  validates :status, inclusion: { in: %w[invalid pending ready processing valid] }
15
16
 
17
+ enum :status, {
18
+ invalid: "invalid",
19
+ pending: "pending",
20
+ ready: "ready",
21
+ processing: "processing",
22
+ valid: "valid"
23
+ }, suffix: "status"
24
+
16
25
  def init_values
17
26
  self.expires ||= Time.now + (60 * 60)
18
27
  self.not_before ||= Time.now
@@ -31,9 +40,8 @@ module Bullion
31
40
  end
32
41
  end
33
42
 
34
- def certificate
35
- Certificate.find(certificate_id)
36
- end
43
+ # Used to extract domains from order (mostly for comparison with CSR)
44
+ def domains = identifiers.map { it["value"] }
37
45
  end
38
46
  end
39
47
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bullion
4
+ module Models
5
+ # Pseudo-model for ACMEv2 Order CSR
6
+ class OrderCsr
7
+ class << self
8
+ def from_acme_request(order, raw_data)
9
+ decoded_data = Base64.urlsafe_decode64(raw_data)
10
+ reencoded_data = Base64.encode64(decoded_data)
11
+ csr_string = openssl_compat_csr(reencoded_data)
12
+
13
+ new(order, csr_string)
14
+ end
15
+
16
+ private
17
+
18
+ def openssl_compat_csr(csrdata)
19
+ "-----BEGIN CERTIFICATE REQUEST-----\n" \
20
+ "#{csrdata}-----END CERTIFICATE REQUEST-----"
21
+ end
22
+ end
23
+
24
+ attr_reader :csr, :order
25
+
26
+ def initialize(order, csr)
27
+ @order = order.is_a?(Order) ? order : Order.find(order)
28
+ @csr = if csr.is_a?(String)
29
+ OpenSSL::X509::Request.new(csr)
30
+ else
31
+ csr
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -6,3 +6,6 @@ require "bullion/models/certificate"
6
6
  require "bullion/models/challenge"
7
7
  require "bullion/models/nonce"
8
8
  require "bullion/models/order"
9
+
10
+ # Pseudo-models (not in DB)
11
+ require "bullion/models/order_csr"
@@ -121,7 +121,7 @@ module Bullion
121
121
  begin
122
122
  parse_acme_jwt(header_data["jwk"], validate_nonce: false)
123
123
 
124
- validate_account_data(@payload_data)
124
+ account_data_valid?(@payload_data)
125
125
  rescue Bullion::Acme::Error => e
126
126
  content_type "application/problem+json"
127
127
  halt 400, { type: e.acme_error, detail: e.message }.to_json
@@ -186,7 +186,7 @@ module Bullion
186
186
  add_acme_headers @new_nonce
187
187
 
188
188
  {
189
- orders: @user.orders.map { |order| uri("/orders/#{order.id}") }
189
+ orders: @user.orders.map { uri("/orders/#{it.id}") }
190
190
  }
191
191
  end
192
192
 
@@ -196,9 +196,9 @@ module Bullion
196
196
  parse_acme_jwt
197
197
 
198
198
  # Only identifiers of type "dns" are supported
199
- identifiers = @payload_data["identifiers"].select { |i| i["type"] == "dns" }
199
+ identifiers = @payload_data["identifiers"].select { it["type"] == "dns" }
200
200
 
201
- validate_order(@payload_data)
201
+ order_valid?(@payload_data)
202
202
 
203
203
  order = @user.start_order(
204
204
  identifiers:,
@@ -215,7 +215,7 @@ module Bullion
215
215
  notBefore: order.not_before,
216
216
  notAfter: order.not_after,
217
217
  identifiers: order.identifiers,
218
- authorizations: order.authorizations.map { |a| uri("/authorizations/#{a.id}") },
218
+ authorizations: order.authorizations.map { uri("/authorizations/#{it.id}") },
219
219
  finalize: uri("/orders/#{order.id}/finalize")
220
220
  }.to_json
221
221
  rescue Bullion::Acme::Error => e
@@ -238,11 +238,11 @@ module Bullion
238
238
  notBefore: order.not_before,
239
239
  notAfter: order.not_after,
240
240
  identifiers: order.identifiers,
241
- authorizations: order.authorizations.map { |a| uri("/authorizations/#{a.id}") },
241
+ authorizations: order.authorizations.map { uri("/authorizations/#{it.id}") },
242
242
  finalize: uri("/orders/#{order.id}/finalize")
243
243
  }
244
244
 
245
- data[:certificate] = uri("/certificates/#{order.certificate.id}") if order.status == "valid"
245
+ data[:certificate] = uri("/certificates/#{order.certificate.id}") if order.valid_status?
246
246
 
247
247
  data.to_json
248
248
  rescue Bullion::Acme::Error => e
@@ -260,14 +260,9 @@ module Bullion
260
260
  content_type "application/json"
261
261
  add_acme_headers @new_nonce, additional: { "Location" => uri("/orders/#{order.id}") }
262
262
 
263
- raw_csr_data = Base64.urlsafe_decode64(@payload_data["csr"])
264
- encoded_csr = Base64.encode64(raw_csr_data)
263
+ order_csr = Models::OrderCsr.from_acme_request(order, @payload_data["csr"])
265
264
 
266
- csr_data = openssl_compat_csr(encoded_csr)
267
-
268
- csr = OpenSSL::X509::Request.new(csr_data)
269
-
270
- unless validate_acme_csr(order, csr)
265
+ unless acme_csr_valid?(order_csr)
271
266
  content_type "application/problem+json"
272
267
  halt 400, {
273
268
  type: Bullion::Acme::Errors::BadCsr.new.acme_error,
@@ -275,7 +270,7 @@ module Bullion
275
270
  }.to_json
276
271
  end
277
272
 
278
- cert_id = sign_csr(csr, @user.contacts.first).last
273
+ cert_id = sign_csr(order_csr.csr, @user.contacts.first).last
279
274
 
280
275
  order.certificate_id = cert_id
281
276
  order.status = "valid"
@@ -287,11 +282,11 @@ module Bullion
287
282
  notBefore: order.not_before,
288
283
  notAfter: order.not_after,
289
284
  identifiers: order.identifiers,
290
- authorizations: order.authorizations.map { |a| uri("/authorizations/#{a.id}") },
285
+ authorizations: order.authorizations.map { uri("/authorizations/#{it.id}") },
291
286
  finalize: uri("/orders/#{order.id}/finalize")
292
287
  }
293
288
 
294
- data[:certificate] = uri("/certificates/#{order.certificate.id}") if order.status == "valid"
289
+ data[:certificate] = uri("/certificates/#{order.certificate.id}") if order.valid_status?
295
290
 
296
291
  data.to_json
297
292
  rescue Bullion::Acme::Error => e
@@ -320,7 +315,7 @@ module Bullion
320
315
  chash[:url] = uri("/challenges/#{c.id}")
321
316
  chash[:token] = c.token
322
317
  chash[:status] = c.status
323
- chash[:validated] = c.validated if c.status == "valid"
318
+ chash[:validated] = c.validated if c.valid_status?
324
319
 
325
320
  chash
326
321
  end
@@ -355,12 +350,12 @@ module Bullion
355
350
  url: uri("/challenges/#{challenge.id}")
356
351
  }
357
352
 
358
- if challenge.status == "valid"
353
+ if challenge.valid_status?
359
354
  data[:validated] = challenge.validated
360
355
  authorization = challenge.authorization
361
- authorization.update!(status: "valid") unless authorization.status == "valid"
356
+ authorization.update!(status: "valid") unless authorization.valid_status?
362
357
  order = authorization.order
363
- order.update!(status: "ready") unless order.status == "ready"
358
+ order.update!(status: "ready") unless order.ready_status?
364
359
  end
365
360
 
366
361
  add_link_relation("up", uri("/authorizations/#{challenge.authorization.id}"))
@@ -378,7 +373,7 @@ module Bullion
378
373
  add_acme_headers @new_nonce
379
374
 
380
375
  order = Models::Order.where(certificate_id: params[:id]).first
381
- if order && order.status == "valid"
376
+ if order&.valid_status?
382
377
  content_type "application/pem-certificate-chain"
383
378
 
384
379
  cert = Models::Certificate.find(params[:id])
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bullion
4
- VERSION = [
5
- 0, # major
6
- 7, # minor
7
- 3 # patch
8
- ].join(".")
4
+ VERSION = "0.9.0"
9
5
  end
data/lib/bullion.rb CHANGED
@@ -9,6 +9,7 @@ require "logger"
9
9
  require "openssl"
10
10
 
11
11
  # External requirements
12
+ require "benchmark"
12
13
  require "dry-configurable"
13
14
  require "sinatra/base"
14
15
  require "sinatra/contrib"
@@ -31,7 +32,7 @@ module Bullion
31
32
  LOGGER.level = ENV.fetch("LOG_LEVEL", :warn)
32
33
 
33
34
  setting :ca, reader: true do
34
- setting :dir, default: "tmp", constructor: -> { File.expand_path(_1) }
35
+ setting :dir, default: "tmp", constructor: -> { File.expand_path(it) }
35
36
  setting :secret, default: "SomeS3cret"
36
37
  setting(
37
38
  :key_path,
@@ -47,22 +48,22 @@ module Bullion
47
48
  v.include?("/") ? File.expand_path(v) : File.join(Bullion.config.ca.dir, v)
48
49
  }
49
50
  )
50
- setting :domains, default: "example.com", constructor: -> { _1.split(",") }
51
+ setting :domains, default: "example.com", constructor: -> { it.split(",") }
51
52
  # 90 days cert expiration
52
- setting :cert_validity_duration, default: 60 * 60 * 24 * 30 * 3, constructor: -> { Integer(_1) }
53
+ setting :cert_validity_duration, default: 60 * 60 * 24 * 30 * 3, constructor: -> { Integer(it) }
53
54
  end
54
55
 
55
56
  setting :acme, reader: true do
56
57
  setting(
57
58
  :challenge_clients,
58
59
  default: ["Bullion::ChallengeClients::DNS", "Bullion::ChallengeClients::HTTP"],
59
- constructor: -> { _1.map { |n| Kernel.const_get(n.to_s) } }
60
+ constructor: -> { it.map { |n| Kernel.const_get(n.to_s) } }
60
61
  )
61
62
  end
62
63
 
63
64
  setting :db_url, reader: true
64
65
 
65
- setting :nameservers, default: [], constructor: -> { _1.split(",") }
66
+ setting :nameservers, default: [], constructor: -> { it.split(",") }
66
67
 
67
68
  MetricsRegistry = Prometheus::Client.registry
68
69
 
@@ -78,7 +79,7 @@ module Bullion
78
79
  @ca_cert ||= OpenSSL::X509::Certificate.new(ca_cert_file)
79
80
  end
80
81
 
81
- def self.rotate_keys!
82
+ def self.rotate_keys! # rubocop:disable Naming/PredicateMethod
82
83
  @ca_key = nil
83
84
  @ca_cert = nil
84
85
  ca_key
@@ -0,0 +1,15 @@
1
+ {
2
+ "bootstrap-sha": "e9c5861bb935613ced5a908487a122f9b4136de9",
3
+ "last-release-sha": "e9c5861bb935613ced5a908487a122f9b4136de9",
4
+ "packages": {
5
+ ".": {
6
+ "package-name": "bullion",
7
+ "changelog-path": "CHANGELOG.md",
8
+ "release-type": "ruby",
9
+ "bump-minor-pre-major": true,
10
+ "bump-patch-for-minor-pre-major": true,
11
+ "version-file": "lib/bullion/version.rb"
12
+ }
13
+ },
14
+ "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
15
+ }