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 ( 9f10f0...5e7f1e )
by Daniel
09:13
created

SslCertificate::parseCrlLinks()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 9
nc 2
nop 1
dl 0
loc 14
ccs 9
cts 9
cp 1
crap 2
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 3
    public static function createForHostName(string $url, int $timeout = 30): SslCertificate
47
    {
48 3
        $downloadResults = Downloader::downloadCertificateFromUrl($url, $timeout);
49
50 3
        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 24
    private static function parseCertChains(array $chains): array
102
    {
103 24
        $output = [];
104 24
        foreach ($chains as $cert) {
105 23
            array_push($output, new SslChain($cert));
106
        }
107
108 24
        return $output;
109
    }
110
111 24
    public function __construct(array $downloadResults)
112
    {
113 24
        $this->inputDomain = $downloadResults['inputDomain'];
114 24
        $this->testedDomain = $downloadResults['tested'];
115 24
        $this->trusted = $downloadResults['trusted'];
116 24
        $this->ip = $downloadResults['dns-resolves-to'];
117 24
        $this->certificateFields = $downloadResults['cert'];
118 24
        $this->certificateChains = self::parseCertChains($downloadResults['full_chain']);
119 24
        $this->connectionMeta = $downloadResults['connection'];
120 24
        $this->serial = new BigInteger($downloadResults['cert']['serialNumber']);
121
122 24
        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 24
    }
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 getCertificateFields(): array
140
    {
141 1
        return $this->certificateFields;
142
    }
143
144 1
    public function getCertificateChains(): array
145
    {
146 1
        return $this->certificateChains;
147
    }
148
149 1
    public function getSerialNumber(): string
150
    {
151 1
        return strtoupper($this->serial->toHex());
152
    }
153
154 3
    public function hasCrlLink(): bool
155
    {
156 3
        return isset($this->certificateFields['extensions']['crlDistributionPoints']);
157
    }
158
159 3
    public function getCrlLinks()
160
    {
161 3
        if (! $this->hasCrlLink()) {
162
            return;
163
        }
164
165 3
        return $this->crlLinks;
166
    }
167
168
    public function getCrl()
169
    {
170
        if (! $this->hasCrlLink()) {
171
            return;
172
        }
173
174
        return $this->crl;
175
    }
176
177 6
    public function isRevoked()
178
    {
179 6
        return $this->revoked;
180
    }
181
182 1
    public function getCrlRevokedTime()
183
    {
184 1
        if ($this->isRevoked()) {
185 1
            return $this->revokedTime;
186
        }
187
    }
188
189 1
    public function getResolvedIp(): string
190
    {
191 1
        return $this->ip;
192
    }
193
194 2
    public function getIssuer(): string
195
    {
196 2
        return $this->certificateFields['issuer']['CN'];
197
    }
198
199 4
    public function getDomain(): string
200
    {
201 4
        $certDomain = $this->getCertificateDomain();
202 4
        if (str_contains($certDomain, $this->inputDomain) === false) {
203
            return $this->inputDomain;
204
        }
205
206 4
        return $certDomain ?? '';
207
    }
208
209 1
    public function getTestedDomain(): string
210
    {
211 1
        return $this->testedDomain;
212
    }
213
214
    public function getInputDomain(): string
215
    {
216
        return $this->inputDomain;
217
    }
218
219 9
    public function getCertificateDomain(): string
220
    {
221 9
        return $this->certificateFields['subject']['CN'];
222
    }
223
224 8
    public function getAdditionalDomains(): array
225
    {
226 8
        $additionalDomains = explode(', ', $this->certificateFields['extensions']['subjectAltName'] ?? '');
227
228 8
        return array_map(function (string $domain) {
229 8
            return str_replace('DNS:', '', $domain);
230 8
        }, $additionalDomains);
231
    }
232
233 1
    public function getSignatureAlgorithm(): string
234
    {
235 1
        return $this->certificateFields['signatureTypeSN'] ?? '';
236
    }
237
238
    public function getConnectionMeta(): array
239
    {
240
        return $this->connectionMeta;
241
    }
242
243 6
    public function validFromDate(): Carbon
244
    {
245 6
        return Carbon::createFromTimestampUTC($this->certificateFields['validFrom_time_t']);
246
    }
247
248 7
    public function expirationDate(): Carbon
249
    {
250 7
        return Carbon::createFromTimestampUTC($this->certificateFields['validTo_time_t']);
251
    }
252
253 1
    public function isExpired(): bool
254
    {
255 1
        return $this->expirationDate()->isPast();
256
    }
257
258 1
    public function isTrusted(): bool
259
    {
260 1
        return $this->trusted;
261
    }
262
263 5
    public function isValid(string $url = null): bool
264
    {
265
        // Verify SSL not expired
266 5
        if (! Carbon::now()->between($this->validFromDate(), $this->expirationDate())) {
267 2
            return false;
268
        }
269
        // Verify the SSL applies to the domain; use $url if provided, other wise use input
270 5
        if ($this->appliesToUrl($url ?? $this->inputDomain) === false) {
271 1
            return false;
272
        }
273
        // Check SerialNumber for CRL list
274 5
        if ($this->isRevoked()) {
275 1
            return false;
276
        }
277
278 4
        return true;
279
    }
280
281 1
    public function isValidUntil(Carbon $carbon, string $url = null): bool
282
    {
283 1
        if ($this->isValidDate($carbon) === false) {
284 1
            return false;
285
        }
286
287 1
        return $this->isValid($url);
288
    }
289
290 1
    public function isValidDate(Carbon $carbon): bool
291
    {
292
        if ($carbon->between($this->validFromDate(), $this->expirationDate()) === false) {
293 1
            return false;
294
        }
295 1
296
        return true;
297
    }
298
299
    public function isSelfSigned()
300 1
    {
301 1
      // Get the issuer data
302
        $url = $this->getIssuer();
303 1
      // make sure we don't include wildcard if it's there...
304
        if (starts_with($url, '*.') === true) {
305
            $url = substr($url, 2);
306
        }
307
      //Try to parse the string
308
        try {
309
            $issuerUrl = new Url($url);
0 ignored issues
show
Unused Code introduced by
$issuerUrl is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
310
        } catch (\Exception $e) {
311
            // if we hit this exception then the string is not likely a URL
312
            return false;
313
        }
314 7
      // If it is a domain, run appliesToUrl($this->getIssuer())
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
315
        if ($this->appliesToUrl($url) === true) {
316 7
            return true;
317 1
        }
318
319 7
      // default to return null; this means maybe
320
        return null;
321 7
    }
322
323 7
    public function appliesToUrl(string $url): bool
324 7
    {
325 5
        if (starts_with($url, '*.') === true) {
326
            $url = substr($url, 2);
327
        }
328 3
        $host = (new Url($url))->getHostName();
329 3
330
        $certificateHosts = array_merge([$this->getCertificateDomain()], $this->getAdditionalDomains());
331
332
        foreach ($certificateHosts as $certificateHost) {
333 2
            if ($host === $certificateHost) {
334
                return true;
335
            }
336 3
337
            if ($this->wildcardHostCoversHost($certificateHost, $host)) {
338 3
                return true;
339 2
            }
340
        }
341
342 2
        return false;
343
    }
344 2
345
    protected function wildcardHostCoversHost(string $wildcardHost, string $host): bool
346
    {
347
        if (! starts_with($wildcardHost, '*')) {
348
            return false;
349
        }
350
351
        $wildcardHostWithoutWildcard = substr($wildcardHost, 2);
352
353
        return ends_with($host, $wildcardHostWithoutWildcard);
354
    }
355
}
356