diff --git a/README.md b/README.md index ee40869..ef1f513 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,36 @@ foreach ($authorizations as $authorization) { The code above will first perform a self test and, if successful, will do 15 attempts to ask Let’s Encrypt to validate the challenge (with 1 second intervals) and retrieve an updated status (it might take Let’s Encrypt a few seconds to validate the challenge). +In the event the validation fails more detail can be found by interrogating the authorizations/challenges for example: +```php +$validated = $client->validate($authorization->getDnsChallenge(), 15); +if(!$validated){ + $authorizations = $client->authorize($order); + /** @var \Afosto\Acme\Data\Authorization $authorization */ + foreach($authorizations as $authorization){ + echo 'processing authorization for: '.$authorization->getDomain().PHP_EOL; + + /** @var \Afosto\Acme\Data\Challenge $challenge */ + foreach($authorization->getChallenges() as $challenge){ + echo 'processing challenge: '.$challenge->getToken().' ('.$challenge->getType().')'.PHP_EOL; + echo 'status: '.$challenge->getStatus().PHP_EOL; + if($challenge->hasError()){ + echo 'error:'.PHP_EOL; + echo ' type: '.$challenge->getError()->getType().PHP_EOL; + echo ' status: '.$challenge->getError()->getStatus().PHP_EOL; + echo ' detail: '.$challenge->getError()->getDetail().PHP_EOL; + } + if($challenge->hasValidationRecord()){ + echo 'validation record'.PHP_EOL.print_r($challenge->getValidationRecord(), true).PHP_EOL; + } + echo 'validated at: '.$challenge->getValidated().PHP_EOL; + } + } +} +``` +- The challenge error will give you information about: the specific error code, the response status code, a human description of the error +- The validation record will give imformation about the request made to validate (endpoint, resolved address etc...) + ### Get the certificate diff --git a/src/Client.php b/src/Client.php index 17fef64..e0c0710 100644 --- a/src/Client.php +++ b/src/Client.php @@ -244,10 +244,7 @@ public function authorize(Order $order): array foreach ($data['challenges'] as $challengeData) { $challenge = new Challenge( $authorizationURL, - $challengeData['type'], - $challengeData['status'], - $challengeData['url'], - $challengeData['token'] + $challengeData ); $authorization->addChallenge($challenge); } diff --git a/src/Data/Challenge.php b/src/Data/Challenge.php index 95493b3..a4a6f51 100644 --- a/src/Data/Challenge.php +++ b/src/Data/Challenge.php @@ -2,6 +2,8 @@ namespace Afosto\Acme\Data; +use Afosto\Acme\Data\Challenge\Error as ChallengeError; + class Challenge { @@ -30,21 +32,54 @@ class Challenge */ protected $token; + /** + * @var null|ChallengeError + */ + protected $error; + + /** + * @var array|null + */ + protected $validationRecord; + + /** + * @var string|null + */ + protected $validated; + /** * Challenge constructor. * @param string $authorizationURL - * @param string $type - * @param string $status - * @param string $url - * @param string $token + * @param array $data + * @throws \InvalidArgumentException */ - public function __construct(string $authorizationURL, string $type, string $status, string $url, string $token) + public function __construct(string $authorizationURL, array $data) { $this->authorizationURL = $authorizationURL; - $this->type = $type; - $this->status = $status; - $this->url = $url; - $this->token = $token; + + // mandatory data + foreach([ + 'type', + 'status', + 'url', + 'token' + ] as $attribute){ + if(!isset($data[$attribute])){ + throw new \InvalidArgumentException('When constructing challenge object the $data array passed in must contain "'.$attribute.'". $data provided: '.json_encode($data)); + } + $this->$attribute = $data[$attribute]; + } + + // optional data + if(isset($data['error'])){ + $this->error = new ChallengeError($data['error']); + } + if(isset($data['validationRecord'])){ + $this->validationRecord = $data['validationRecord']; + } + if(isset($data['validated'])){ + $this->validated = $data['validated']; + } } /** @@ -91,4 +126,49 @@ public function getAuthorizationURL(): string { return $this->authorizationURL; } + + /** + * Returns if the challenge has an error + * @return bool + */ + public function hasError() + { + return $this->getError() !== null; + } + + /** + * Returns the challenge error (if present) + * @return null|ChallengeError + */ + public function getError() + { + return $this->error; + } + + /** + * Returns if the record has a validation record + * @return bool + */ + public function hasValidationRecord() + { + return $this->getValidationRecord() !== null; + } + + /** + * Returns the validation record (if present) + * @return array|null + */ + public function getValidationRecord() + { + return $this->validationRecord; + } + + /** + * Returns the validation time for the challenge + * @return string|null + */ + public function getValidated() + { + return $this->validated; + } } diff --git a/src/Data/Challenge/Error.php b/src/Data/Challenge/Error.php new file mode 100644 index 0000000..0d78fa6 --- /dev/null +++ b/src/Data/Challenge/Error.php @@ -0,0 +1,46 @@ +type = isset($data['type'])? $data['type'] : null; + $this->detail = isset($data['detail'])? $data['detail'] : null; + $this->status = isset($data['status'])? $data['status'] : null; + } + + /** + * @return string|null + */ + public function getType() + { + return $this->type; + } + + /** + * @return string|null + */ + public function getDetail() + { + return $this->detail; + } + + /** + * @return string|null + */ + public function getStatus() + { + return $this->status; + } +}