kelunik/acme

Acme HTTP Errors

barryvdh opened this issue · 9 comments

The Acme service can return certain error codes, as described here: https://letsencrypt.github.io/acme-spec/#rfc.section.5.4

Currently, HTTP errors will be thrown with the response body as plain text in the message.

It would be more useful to create a AcmeHttpException which can be constructed using the response object and provides an actual useful message?

Invalid response code: 400 {"type":"urn:acme:error:badNonce","detail":"Unable to read/verify body :: JWS has invalid anti-replay nonce","status":400}

Could be:

Invalid Acme HTTP Response: badNonce (code 400). Unable to read/verify body :: JWS has invalid anti-replay nonce.

BadCsrException, BadNonceException, ConnectException, DnssecException, MalformedRequestException, InternalServerException, TlsException, UnauthorizedException, UnknownHostException.

I'm not happy with some of these names, do you have suggestions?

Another alternative would be to return the type in AcmeException::getCode.

I agree that all of those errors should be represented by 1 class (not 1 each) which then provides a method to further determine the underlying error

I have improved the error messages, please review d3805a6.

What about doing the type/detail handling inside the exception?

You can change the Exception constructor when extending, for example to typehint a Response object. You can then apply the same logic in your Eception.
You could also create a static factory for your AcmeException, to create on from a Response.

class AcmeException extends Exception {
    public function __construct($message, Response $response = null, Exception $previous = null)
    {
        parent::__construct($message, 0, $previous);

        if ($response) {
            $info = json_decode($response->getBody(), true);

            if ($info && isset($info['type'], $info['detail'])) {
                $this->code = $info['type'];
                $this->message .= ' ' . $info['detail'];
            }
        }

    }
}

https://3v4l.org/WgOnF

Should the default error code be internal, generic, general or unknown?

Don't know, could just leave it 0, the Exception default.

Can I close this?

Hmm, using a string as code might give unexpected results when stacking exceptions, see: zenire/da-letsencrypt#40
Testcase: https://3v4l.org/ObN47