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 ( edd496...fc0775 )
by Freek
01:31
created

src/SslCertificate.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Spatie\SslCertificate;
4
5
use Carbon\Carbon;
6
use Spatie\Macroable\Macroable;
7
8
class SslCertificate
9
{
10
    use Macroable;
11
12
    /** @var array */
13
    protected $rawCertificateFields = [];
14
15
    /** @var string */
16
    protected $fingerprint = '';
17
18
    /** @var string */
19
    private $fingerprintSha256 = '';
20
21
    /** @var string */
22
    private $remoteAddress = '';
23
24
    public static function download(): Downloader
25
    {
26
        return new Downloader();
27
    }
28
29
    public static function createForHostName(string $url, int $timeout = 30): self
30
    {
31
        return Downloader::downloadCertificateFromUrl($url, $timeout);
32
    }
33
34
    public static function createFromFile(string $pathToCertificate): self
35
    {
36
        return $this->createFromString(file_get_contents($pathToCertificate));
0 ignored issues
show
The variable $this does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
37
    }
38
39 View Code Duplication
    public static function createFromString(string $certificatePem): self
40
    {
41
        $certificateFields = openssl_x509_parse($certificatePem);
42
43
        $fingerprint = openssl_x509_fingerprint($certificatePem);
44
        $fingerprintSha256 = openssl_x509_fingerprint($certificatePem, 'sha256');
45
46
        return new self(
47
            $certificateFields,
48
            $fingerprint,
49
            $fingerprintSha256
50
        );
51
    }
52
53
    public function __construct(
54
        array $rawCertificateFields,
55
        string $fingerprint = '',
56
        string $fingerprintSha256 = '',
57
        string $remoteAddress = ''
58
    ) {
59
        $this->rawCertificateFields = $rawCertificateFields;
60
61
        $this->fingerprint = $fingerprint;
62
63
        $this->fingerprintSha256 = $fingerprintSha256;
64
65
        $this->remoteAddress = $remoteAddress;
66
    }
67
68
    public function getRawCertificateFields(): array
69
    {
70
        return $this->rawCertificateFields;
71
    }
72
73
    public function getIssuer(): string
74
    {
75
        return $this->rawCertificateFields['issuer']['CN'] ?? '';
76
    }
77
78
    public function getDomain(): string
79
    {
80
        if (! array_key_exists('CN', $this->rawCertificateFields['subject'])) {
81
            return '';
82
        }
83
84
        if (is_string($this->rawCertificateFields['subject']['CN'])) {
85
            return $this->rawCertificateFields['subject']['CN'];
86
        }
87
88
        if (is_array($this->rawCertificateFields['subject']['CN'])) {
89
            return $this->rawCertificateFields['subject']['CN'][0];
90
        }
91
92
        return '';
93
    }
94
95
    public function getSignatureAlgorithm(): string
96
    {
97
        return $this->rawCertificateFields['signatureTypeSN'] ?? '';
98
    }
99
100
    public function getOrganization(): string
101
    {
102
        return $this->rawCertificateFields['subject']['O'] ?? '';
103
    }
104
105
    public function getFingerprint(): string
106
    {
107
        return $this->fingerprint;
108
    }
109
110
    /**
111
     * @return string
112
     */
113
    public function getFingerprintSha256(): string
114
    {
115
        return $this->fingerprintSha256;
116
    }
117
118
    public function getAdditionalDomains(): array
119
    {
120
        $additionalDomains = explode(', ', $this->rawCertificateFields['extensions']['subjectAltName'] ?? '');
121
122
        return array_map(function (string $domain) {
123
            return str_replace('DNS:', '', $domain);
124
        }, $additionalDomains);
125
    }
126
127
    public function validFromDate(): Carbon
128
    {
129
        return Carbon::createFromTimestampUTC($this->rawCertificateFields['validFrom_time_t']);
130
    }
131
132
    public function expirationDate(): Carbon
133
    {
134
        return Carbon::createFromTimestampUTC($this->rawCertificateFields['validTo_time_t']);
135
    }
136
137
    public function lifespanInDays(): int
138
    {
139
        return $this->validFromDate()->diffInDays($this->expirationDate());
140
    }
141
142
    public function isExpired(): bool
143
    {
144
        return $this->expirationDate()->isPast();
145
    }
146
147
    public function isValid(string $url = null)
148
    {
149
        if (! Carbon::now()->between($this->validFromDate(), $this->expirationDate())) {
150
            return false;
151
        }
152
153
        if (! empty($url)) {
154
            return $this->appliesToUrl($url ?? $this->getDomain());
155
        }
156
157
        return true;
158
    }
159
160
    public function isSelfSigned(): bool
161
    {
162
        return $this->getIssuer() === $this->getDomain();
163
    }
164
165
    public function usesSha1Hash(): bool
166
    {
167
        $certificateFields = $this->getRawCertificateFields();
168
169
        if ($certificateFields['signatureTypeSN'] === 'RSA-SHA1') {
170
            return true;
171
        }
172
173
        if ($certificateFields['signatureTypeLN'] === 'sha1WithRSAEncryption') {
174
            return true;
175
        }
176
177
        return false;
178
    }
179
180
    public function isValidUntil(Carbon $carbon, string $url = null): bool
181
    {
182
        if ($this->expirationDate()->lte($carbon)) {
183
            return false;
184
        }
185
186
        return $this->isValid($url);
187
    }
188
189
    public function daysUntilExpirationDate(): int
190
    {
191
        $endDate = $this->expirationDate();
192
193
        $interval = Carbon::now()->diff($endDate);
194
195
        return (int) $interval->format('%r%a');
196
    }
197
198
    public function getDomains(): array
199
    {
200
        $allDomains = $this->getAdditionalDomains();
201
        $allDomains[] = $this->getDomain();
202
        $uniqueDomains = array_unique($allDomains);
203
204
        return array_values(array_filter($uniqueDomains));
205
    }
206
207
    public function appliesToUrl(string $url): bool
208
    {
209
        if (filter_var($url, FILTER_VALIDATE_IP)) {
210
            $host = $url;
211
        } else {
212
            $host = (new Url($url))->getHostName();
213
        }
214
215
        $certificateHosts = $this->getDomains();
216
217
        foreach ($certificateHosts as $certificateHost) {
218
            $certificateHost = str_replace('ip address:', '', strtolower($certificateHost));
219
            if ($host === $certificateHost) {
220
                return true;
221
            }
222
223
            if ($this->wildcardHostCoversHost($certificateHost, $host)) {
224
                return true;
225
            }
226
        }
227
228
        return false;
229
    }
230
231
    protected function wildcardHostCoversHost(string $wildcardHost, string $host): bool
232
    {
233
        if ($host === $wildcardHost) {
234
            return true;
235
        }
236
237
        if (! starts_with($wildcardHost, '*')) {
238
            return false;
239
        }
240
241
        if (substr_count($wildcardHost, '.') < substr_count($host, '.')) {
242
            return false;
243
        }
244
245
        $wildcardHostWithoutWildcard = substr($wildcardHost, 1);
246
247
        $hostWithDottedPrefix = ".{$host}";
248
249
        return ends_with($hostWithDottedPrefix, $wildcardHostWithoutWildcard);
250
    }
251
252
    public function getRawCertificateFieldsJson(): string
253
    {
254
        return json_encode($this->getRawCertificateFields());
255
    }
256
257
    public function getHash(): string
258
    {
259
        return md5($this->getRawCertificateFieldsJson());
260
    }
261
262
    public function getRemoteAddress(): string
263
    {
264
        return $this->remoteAddress;
265
    }
266
267
    public function __toString(): string
268
    {
269
        return $this->getRawCertificateFieldsJson();
270
    }
271
272
    public function containsDomain(string $domain): bool
273
    {
274
        $certificateHosts = $this->getDomains();
275
276
        foreach ($certificateHosts as $certificateHost) {
277
            if ($certificateHost == $domain) {
278
                return true;
279
            }
280
281
            if (ends_with($domain, '.'.$certificateHost)) {
282
                return true;
283
            }
284
        }
285
286
        return false;
287
    }
288
289
    public function isPreCertificate(): bool
290
    {
291
        if (! array_key_exists('extensions', $this->rawCertificateFields)) {
292
            return false;
293
        }
294
295
        if (! array_key_exists('ct_precert_poison', $this->rawCertificateFields['extensions'])) {
296
            return false;
297
        }
298
299
        return true;
300
    }
301
}
302