GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 16c344...9c0fcb )
by Daniel
03:37
created

SslCertificate::hasSslChain()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 2
nop 0
dl 0
loc 8
ccs 4
cts 4
cp 1
crap 3
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace LiquidWeb\SslCertificate;
4
5
use Carbon\Carbon;
6
use phpseclib\Math\BigInteger;
7
8
class SslCertificate
9
{
10
    /** @var bool */
11
    protected $trusted;
12
13
    /** @var bool */
14
    protected $revoked;
15
16
    /** @var string */
17
    protected $ip;
18
19
    /** @var BigInteger */
20
    protected $serial;
21
22
    /** @var string */
23
    protected $inputDomain;
24
25
    /** @var string */
26
    protected $testedDomain;
27
28
    /** @var array */
29
    protected $certificateFields = [];
30
31
    /** @var array */
32
    protected $certificateChains = [];
33
34
    /** @var array */
35
    protected $connectionMeta = [];
36
37
    /** @var SslRevocationList */
38
    protected $crl;
39
40
    /** @var array */
41
    protected $crlLinks = [];
42
43
    /** @var Carbon */
44
    protected $revokedTime;
45
46 2
    public static function createForHostName(string $url, int $timeout = 30): SslCertificate
47
    {
48 2
        $downloadResults = Downloader::downloadCertificateFromUrl($url, $timeout);
49
50 2
        return new static($downloadResults);
51
    }
52
53 3
    private static function extractCrlLinks($rawCrlPoints): string
54
    {
55 3
        $tempCrlItem = explode('URI:', $rawCrlPoints);
56 3
        $cleanCrlItem = trim($tempCrlItem[1]);
57
58 3
        return $cleanCrlItem;
59
    }
60
61 3
    private static function parseCrlLinks($rawCrlInput): array
62
    {
63 3
        $crlLinks = [];
64 3
        $crlRawItems = explode('Full Name:', $rawCrlInput);
65
        // Remove the stuff before the first 'Full Name:' item
66 3
        array_splice($crlRawItems, 0, 1);
67 3
        foreach ($crlRawItems as $item) {
68 3
            $crlLink = self::extractCrlLinks($item);
69 3
            array_push($crlLinks, $crlLink);
70 3
            unset($crlLink);
71
        }
72
73 3
        return $crlLinks;
74
    }
75
76 3
    private function getRevokedDate()
77
    {
78 3
        foreach ($this->crl->getRevokedList() as $broke) {
79 3
            if ($this->serial->equals($broke['userCertificate'])) {
80 3
                return new Carbon($broke['revocationDate']['utcTime']);
81
            }
82
        }
83 2
    }
84
85 3
    private function isClrRevoked()
86
    {
87 3
        if (! $this->hasCrlLink()) {
88
            return;
89
        }
90 3
        foreach ($this->crl->getRevokedList() as $broke) {
91 3
            if ($this->serial->equals($broke['userCertificate'])) {
92 1
                $this->trusted = false;
93
94 3
                return true;
95
            }
96
        }
97
98 2
        return false;
99
    }
100
101 23
    private static function parseCertChains(array $chains): array
102
    {
103 23
        $output = [];
104 23
        foreach ($chains as $cert) {
105 23
            array_push($output, new SslChain($cert));
106
        }
107
108 23
        return $output;
109
    }
110
111 23
    public function __construct(array $downloadResults)
112
    {
113 23
        $this->inputDomain = $downloadResults['inputDomain'];
114 23
        $this->testedDomain = $downloadResults['tested'];
115 23
        $this->trusted = $downloadResults['trusted'];
116 23
        $this->ip = $downloadResults['dns-resolves-to'];
117 23
        $this->certificateFields = $downloadResults['cert'];
118 23
        $this->certificateChains = self::parseCertChains($downloadResults['full_chain']);
119 23
        $this->connectionMeta = $downloadResults['connection'];
120 23
        $this->serial = new BigInteger($downloadResults['cert']['serialNumber']);
121
122 23
        if (isset($downloadResults['cert']['extensions']['crlDistributionPoints'])) {
123 3
            $this->crlLinks = self::parseCrlLinks($downloadResults['cert']['extensions']['crlDistributionPoints']);
124 3
            $this->crl = SslRevocationList::createFromUrl($this->getCrlLinks()[0]);
125 3
            $this->revoked = $this->isClrRevoked();
126 3
            $this->revokedTime = $this->getRevokedDate();
127
        }
128 23
    }
129
130 2
    public function hasSslChain(): bool
131
    {
132 2
        if (isset($this->certificateChains) && count($this->certificateChains) >= 1) {
133 1
            return true;
134
        }
135
136 1
        return false;
137
    }
138
139 1
    public function getTestedDomain(): string
140
    {
141 1
        return $this->testedDomain;
142
    }
143
144 1
    public function getCertificateFields(): array
145
    {
146 1
        return $this->certificateFields;
147
    }
148
149 1
    public function getCertificateChains(): array
150
    {
151 1
        return $this->certificateChains;
152
    }
153
154 1
    public function getSerialNumber(): string
155
    {
156 1
        return strtoupper($this->serial->toHex());
157
    }
158
159 3
    public function hasCrlLink(): bool
160
    {
161 3
        return isset($this->certificateFields['extensions']['crlDistributionPoints']);
162
    }
163
164 3
    public function getCrlLinks()
165
    {
166 3
        if (! $this->hasCrlLink()) {
167
            return;
168
        }
169
170 3
        return $this->crlLinks;
171
    }
172
173
    public function getCrl()
174
    {
175
        if (! $this->hasCrlLink()) {
176
            return;
177
        }
178
179
        return $this->crl;
180
    }
181
182 6
    public function isRevoked()
183
    {
184 6
        return $this->revoked;
185
    }
186
187 1
    public function getCrlRevokedTime()
188
    {
189 1
        if ($this->isRevoked()) {
190 1
            return $this->revokedTime;
191
        }
192
    }
193
194 1
    public function getResolvedIp(): string
195
    {
196 1
        return $this->ip;
197
    }
198
199 1
    public function getIssuer(): string
200
    {
201 1
        return $this->certificateFields['issuer']['CN'];
202
    }
203
204 8
    public function getDomain(): string
205
    {
206 8
        $certDomain = $this->getCertificateDomain();
207 8
        if (str_contains($certDomain, $this->inputDomain) === false) {
208
          return $this->inputDomain;
209
        }
210 8
        return $certDomain ?? '';
211
    }
212
213 8
    public function getCertificateDomain(): string
214
    {
215 8
        return $this->certificateFields['subject']['CN'];
216
    }
217
218 1
    public function getSignatureAlgorithm(): string
219
    {
220 1
        return $this->certificateFields['signatureTypeSN'] ?? '';
221
    }
222
223 7
    public function getAdditionalDomains(): array
224
    {
225 7
        $additionalDomains = explode(', ', $this->certificateFields['extensions']['subjectAltName'] ?? '');
226
227 7
        return array_map(function (string $domain) {
228 7
            return str_replace('DNS:', '', $domain);
229 7
        }, $additionalDomains);
230
    }
231
232
    public function getConnectionMeta(): array
233
    {
234
        return $this->connectionMeta;
235
    }
236
237 6
    public function validFromDate(): Carbon
238
    {
239 6
        return Carbon::createFromTimestampUTC($this->certificateFields['validFrom_time_t']);
240
    }
241
242 7
    public function expirationDate(): Carbon
243
    {
244 7
        return Carbon::createFromTimestampUTC($this->certificateFields['validTo_time_t']);
245
    }
246
247 1
    public function isExpired(): bool
248
    {
249 1
        return $this->expirationDate()->isPast();
250
    }
251
252 1
    public function isTrusted(): bool
253
    {
254 1
        return $this->trusted;
255
    }
256
257 5
    public function isValid(string $url = null): bool
258
    {
259
        // Verify SSL not expired
260 5
        if (! Carbon::now()->between($this->validFromDate(), $this->expirationDate())) {
261 2
            return false;
262
        }
263
        // If a URL is provided verify the SSL applies to the domain
264 5
        if ($this->appliesToUrl($url ?? $this->getDomain()) === false) {
265 1
            return false;
266
        }
267
        // Check SerialNumber for CRL list
268 5
        if ($this->isRevoked()) {
269 1
            return false;
270
        }
271
272 4
        return true;
273
    }
274
275 1
    public function isValidUntil(Carbon $carbon, string $url = null): bool
276
    {
277 1
        if ($this->expirationDate()->gt($carbon)) {
278 1
            return false;
279
        }
280
281 1
        return $this->isValid($url);
282
    }
283
284 6
    public function appliesToUrl(string $url): bool
285
    {
286 6
        if (starts_with($url, '*.') === true) {
287 1
            $url = substr($url, 2);
288
        }
289 6
        $host = (new Url($url))->getHostName();
290
291 6
        $certificateHosts = array_merge([$this->getDomain()], $this->getAdditionalDomains());
292
293 6
        foreach ($certificateHosts as $certificateHost) {
294 6
            if ($host === $certificateHost) {
295 5
                return true;
296
            }
297
298 2
            if ($this->wildcardHostCoversHost($certificateHost, $host)) {
299 2
                return true;
300
            }
301
        }
302
303 1
        return false;
304
    }
305
306 2
    protected function wildcardHostCoversHost(string $wildcardHost, string $host): bool
307
    {
308 2
        if (! starts_with($wildcardHost, '*')) {
309 1
            return false;
310
        }
311
312 2
        $wildcardHostWithoutWildcard = substr($wildcardHost, 2);
313
314 2
        return ends_with($host, $wildcardHostWithoutWildcard);
315
    }
316
}
317