Completed
Push — master ( ad7ee3...c08a34 )
by Rogier
29s queued 12s
created

DomainValidation::allChallengesPassed()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
c 0
b 0
f 0
dl 0
loc 20
rs 9.6111
cc 5
nc 3
nop 1
1
<?php
2
3
namespace Rogierw\RwAcme\Endpoints;
4
5
use Rogierw\RwAcme\DTO\AccountData;
6
use Rogierw\RwAcme\DTO\DomainValidationData;
7
use Rogierw\RwAcme\DTO\OrderData;
8
use Rogierw\RwAcme\Enums\AuthorizationChallengeEnum;
9
use Rogierw\RwAcme\Http\Response;
10
use Rogierw\RwAcme\Support\Arr;
11
use Rogierw\RwAcme\Support\DnsDigest;
12
use Rogierw\RwAcme\Support\JsonWebKey;
13
use Rogierw\RwAcme\Support\LocalChallengeTest;
14
use Rogierw\RwAcme\Support\Thumbprint;
15
16
class DomainValidation extends Endpoint
17
{
18
    /** @return DomainValidationData[] */
19
    public function status(OrderData $orderData): array
20
    {
21
        $data = [];
22
23
        foreach ($orderData->domainValidationUrls as $domainValidationUrl) {
24
            $response = $this->client
25
                ->getHttpClient()
26
                ->post(
27
                    $domainValidationUrl,
28
                    $this->createKeyId($orderData->accountUrl, $domainValidationUrl)
29
                );
30
31
            if ($response->getHttpResponseCode() === 200) {
32
                $data[] = DomainValidationData::fromResponse($response);
33
            }
34
        }
35
36
        return $data;
37
    }
38
39
    /** @param DomainValidationData[] $challenges */
40
    public function getValidationData(array $challenges, ?AuthorizationChallengeEnum $authChallenge = null): array
41
    {
42
        $thumbprint = Thumbprint::make($this->getAccountPrivateKey());
43
44
        $authorizations = [];
45
        foreach ($challenges as $domainValidationData) {
46
            if ((is_null($authChallenge) || $authChallenge === AuthorizationChallengeEnum::HTTP)) {
47
                $authorizations[] = [
48
                    'identifier' => $domainValidationData->identifier['value'],
49
                    'type' => $domainValidationData->file['type'],
50
                    'filename' => $domainValidationData->file['token'],
51
                    'content' => $domainValidationData->file['token'] . '.' . $thumbprint,
52
                ];
53
            }
54
55
            if ((is_null($authChallenge) || $authChallenge === AuthorizationChallengeEnum::DNS)) {
56
                $authorizations[] = [
57
                    'identifier' => $domainValidationData->identifier['value'],
58
                    'type' => $domainValidationData->dns['type'],
59
                    'name' => '_acme-challenge',
60
                    'value' => DnsDigest::make($domainValidationData->dns['token'], $thumbprint),
61
                ];
62
            }
63
        }
64
65
        return $authorizations;
66
    }
67
68
    /** @throws \Rogierw\RwAcme\Exceptions\DomainValidationException */
69
    public function start(
70
        AccountData $accountData,
71
        DomainValidationData $domainValidation,
72
        AuthorizationChallengeEnum $authChallenge,
73
        bool $localTest = true
74
    ): Response {
75
        $this->client->logger('info', sprintf(
76
            'Start %s challenge for %s',
77
            $authChallenge->value,
78
            Arr::get($domainValidation->identifier, 'value', '')
79
        ));
80
81
        $type = $authChallenge === AuthorizationChallengeEnum::DNS ? 'dns' : 'file';
82
        $thumbprint = JsonWebKey::thumbprint(JsonWebKey::compute($this->getAccountPrivateKey()));
83
        $keyAuthorization = $domainValidation->{$type}['token'] . '.' . $thumbprint;
84
85
        if ($localTest) {
86
            if ($authChallenge === AuthorizationChallengeEnum::HTTP) {
87
                LocalChallengeTest::http(
88
                    $domainValidation->identifier['value'],
89
                    $domainValidation->file['token'],
90
                    $keyAuthorization
91
                );
92
            }
93
94
            if ($authChallenge === AuthorizationChallengeEnum::DNS) {
95
                LocalChallengeTest::dns(
96
                    $domainValidation->identifier['value'],
97
                    '_acme-challenge',
98
                    DnsDigest::make($domainValidation->{$type}['token'], $thumbprint),
99
                );
100
            }
101
        }
102
103
        $payload = [
104
            'keyAuthorization' => $keyAuthorization,
105
        ];
106
107
        $data = $this->createKeyId($accountData->url, $domainValidation->{$type}['url'], $payload);
108
109
        return $this->client->getHttpClient()->post($domainValidation->{$type}['url'], $data);
110
    }
111
112
    public function allChallengesPassed(OrderData $orderData): bool
113
    {
114
        $count = 0;
115
        while (($status = $this->status($orderData)) && $count < 4) {
116
            if ($this->challengeSucceeded($status)) {
117
                break;
118
            }
119
120
            if ($count === 3) {
121
                return false;
122
            }
123
124
            $this->client->logger('info', 'Challenge is not valid yet. Another attempt in 5 seconds.');
125
126
            sleep(5);
127
128
            $count++;
129
        }
130
131
        return true;
132
    }
133
134
    /** @param DomainValidationData[] $domainValidation */
135
    private function challengeSucceeded(array $domainValidation): bool
136
    {
137
        // Verify if the challenges has been passed.
138
        foreach ($domainValidation as $status) {
139
            $this->client->logger(
140
                'info',
141
                "Check {$status->identifier['type']} challenge of {$status->identifier['value']}."
142
            );
143
144
            if (!$status->isValid()) {
145
                return false;
146
            }
147
        }
148
149
        $this->client->logger('info', 'Challenge has been passed.');
150
151
        return true;
152
    }
153
}
154