Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/acme/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Acme::Client; end
require 'acme/client/faraday_middleware'
require 'acme/client/jwk'
require 'acme/client/error'
require 'acme/client/error/rate_limited'
require 'acme/client/util'

class Acme::Client
Expand Down
6 changes: 5 additions & 1 deletion lib/acme/client/error.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
class Acme::Client::Error < StandardError
def initialize(message = nil, env = nil)
super(message)
@env = env
end

class NotFound < Acme::Client::Error; end
class BadCSR < Acme::Client::Error; end
class BadNonce < Acme::Client::Error; end
Expand All @@ -10,7 +15,6 @@ class Acme::Tls < Acme::Client::Error; end
class Unauthorized < Acme::Client::Error; end
class UnknownHost < Acme::Client::Error; end
class Timeout < Acme::Client::Error; end
class RateLimited < Acme::Client::Error; end
class RejectedIdentifier < Acme::Client::Error; end
class UnsupportedIdentifier < Acme::Client::Error; end
end
7 changes: 7 additions & 0 deletions lib/acme/client/error/rate_limited.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Acme::Client::Error::RateLimited < Acme::Client::Error
DEFAULT_RETRY_AFTER = 10

def retry_after
@env.response_headers.fetch('Retry-After', DEFAULT_RETRY_AFTER).to_i
end
end
2 changes: 1 addition & 1 deletion lib/acme/client/faraday_middleware.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def raise_on_not_found!
end

def raise_on_error!
raise error_class, error_message
raise error_class.new(error_message, env)
end

def error_message
Expand Down
270 changes: 0 additions & 270 deletions spec/cassettes/new_certificate_success.yml

Large diffs are not rendered by default.

272 changes: 272 additions & 0 deletions spec/cassettes/new_reg_success.yml

Large diffs are not rendered by default.

48 changes: 39 additions & 9 deletions spec/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,17 @@
let(:request) { Acme::Client::CertificateRequest.new(common_name: domain, private_key: generate_private_key) }

before(:each) do
registration = client.register(contact: 'mailto:[email protected]')
registration.agree_terms
authorization = client.authorize(domain: domain)
http01 = authorization.http01

serve_once(http01.file_content) do
http01.request_verification
retry_until(condition: lambda { http01.status != 'pending' }) do
http01.verify_status
VCR.use_cassette 'new_reg_success' do
registration = client.register(contact: 'mailto:[email protected]')
registration.agree_terms
authorization = client.authorize(domain: domain)
http01 = authorization.http01

serve_once(http01.file_content) do
http01.request_verification
retry_until(condition: lambda { http01.status != 'pending' }) do
http01.verify_status
end
end
end
end
Expand Down Expand Up @@ -169,6 +171,34 @@
expect(certificate.x509_fullchain.first).to be(certificate.x509)
expect(certificate.url).to eq('http://127.0.0.1:4000/acme/cert/ff87f2112cf6596eddb5df39113701b1572a')
end

it 'fails to create when rate limited and raises the proper exception' do
seven_days = 7 * 24 * 60 * 60 # 7 days
error_message = "Error creating new cert :: too many certificates already issued for exact set of domains: #{domain}"

stub_request(:post, 'http://127.0.0.1:4000/acme/new-cert').with(
headers: {
'Accept' => '*/*',
'User-Agent' => Acme::Client::FaradayMiddleware::USER_AGENT
}
).to_return(
body: {
type: 'urn:acme:error:rateLimited',
detail: error_message
}.to_json,
status: 429,
headers: {
'Content-Type' => 'application/problem+json',
'Retry-After' => seven_days.to_s
}
)

expect { client.new_certificate(request) }.to raise_error { |error|
expect(error).to be_a(Acme::Client::Error::RateLimited)
expect(error.retry_after).to eq(seven_days)
expect(error.message).to eq(error_message)
}
end
end

context '#revoke_certificate' do
Expand Down