class Acme::Client::FaradayMiddleware
def call(env)
def call(env) @env = env @env.body = crypto.generate_signed_jws(header: { nonce: pop_nonce }, payload: env.body) @app.call(env).on_complete { |response_env| on_complete(response_env) } rescue Faraday::TimeoutError raise Acme::Client::Error::Timeout end
def crypto
def crypto @crypto ||= Acme::Client::Crypto.new(private_key) end
def decode_body
def decode_body content_type = env.response_headers['Content-Type'] if content_type == 'application/json' || content_type == 'application/problem+json' JSON.load(env.body) else env.body end end
def decode_link_headers
def decode_link_headers return unless env.response_headers.key?('Link') link_header = env.response_headers['Link'] links = link_header.split(', ').map { |entry| _, link, name = *entry.match(LINK_MATCH) [name, link] } Hash[*links.flatten] end
def error_class
def error_class if error_name.present? && Acme::Client::Error.qualified_const_defined?(error_name) "Acme::Client::Error::#{error_name}".constantize else Acme::Client::Error end end
def error_message
def error_message if env.body.is_a? Hash env.body['detail'] else "Error message: #{env.body}" end end
def error_name
def error_name @error_name ||= begin return unless env.present? && env.body.present? && env.body.key?('type') env.body['type'].gsub('urn:acme:error:', '').classify end end
def get_nonce
def get_nonce response = Faraday.head(env.url) response.headers['replay-nonce'] end
def initialize(app, client:)
def initialize(app, client:) super(app) @client = client end
def nonces
def nonces client.nonces end
def on_complete(env)
def on_complete(env) @env = env raise_on_not_found! store_nonce env.body = decode_body env.response_headers['Link'] = decode_link_headers return if env.success? raise_on_error! end
def pop_nonce
def pop_nonce if nonces.empty? get_nonce else nonces.pop end end
def private_key
def private_key client.private_key end
def raise_on_error!
def raise_on_error! raise error_class, error_message end
def raise_on_not_found!
def raise_on_not_found! raise Acme::Client::Error::NotFound, env.url.to_s if env.status == 404 end
def store_nonce
def store_nonce nonces << env.response_headers['replay-nonce'] end