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 ( 900ec4...d96f34 )
by Freek
01:06
created

SslCertificate::createFromFile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
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
Bug introduced by
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
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 isExpired(): bool
138
    {
139
        return $this->expirationDate()->isPast();
140
    }
141
142
    public function isValid(string $url = null)
143
    {
144
        if (! Carbon::now()->between($this->validFromDate(), $this->expirationDate())) {
145
            return false;
146
        }
147
148
        if (! empty($url)) {
149
            return $this->appliesToUrl($url ?? $this->getDomain());
150
        }
151
152
        return true;
153
    }
154
155
    public function isSelfSigned(): bool
156
    {
157
        return $this->getIssuer() === $this->getDomain();
158
    }
159
160
    public function usesSha1Hash(): bool
161
    {
162
        $certificateFields = $this->getRawCertificateFields();
163
164
        if ($certificateFields['signatureTypeSN'] === 'RSA-SHA1') {
165
            return true;
166
        }
167
168
        if ($certificateFields['signatureTypeLN'] === 'sha1WithRSAEncryption') {
169
            return true;
170
        }
171
172
        return false;
173
    }
174
175
    public function isValidUntil(Carbon $carbon, string $url = null): bool
176
    {
177
        if ($this->expirationDate()->lte($carbon)) {
178
            return false;
179
        }
180
181
        return $this->isValid($url);
182
    }
183
184
    public function daysUntilExpirationDate(): int
185
    {
186
        $endDate = $this->expirationDate();
187
188
        $interval = Carbon::now()->diff($endDate);
189
190
        return (int) $interval->format('%r%a');
191
    }
192
193
    public function getDomains(): array
194
    {
195
        $allDomains = $this->getAdditionalDomains();
196
        $allDomains[] = $this->getDomain();
197
        $uniqueDomains = array_unique($allDomains);
198
199
        return array_values(array_filter($uniqueDomains));
200
    }
201
202
    public function appliesToUrl(string $url): bool
203
    {
204
        if (filter_var($url, FILTER_VALIDATE_IP)) {
205
            $host = $url;
206
        } else {
207
            $host = (new Url($url))->getHostName();
208
        }
209
210
        $certificateHosts = $this->getDomains();
211
212
        foreach ($certificateHosts as $certificateHost) {
213
            $certificateHost = str_replace('ip address:', '', strtolower($certificateHost));
214
            if ($host === $certificateHost) {
215
                return true;
216
            }
217
218
            if ($this->wildcardHostCoversHost($certificateHost, $host)) {
219
                return true;
220
            }
221
        }
222
223
        return false;
224
    }
225
226
    protected function wildcardHostCoversHost(string $wildcardHost, string $host): bool
227
    {
228
        if ($host === $wildcardHost) {
229
            return true;
230
        }
231
232
        if (! starts_with($wildcardHost, '*')) {
233
            return false;
234
        }
235
236
        if (substr_count($wildcardHost, '.') < substr_count($host, '.')) {
237
            return false;
238
        }
239
240
        $wildcardHostWithoutWildcard = substr($wildcardHost, 1);
241
242
        $hostWithDottedPrefix = ".{$host}";
243
244
        return ends_with($hostWithDottedPrefix, $wildcardHostWithoutWildcard);
245
    }
246
247
    public function getRawCertificateFieldsJson(): string
248
    {
249
        return json_encode($this->getRawCertificateFields());
250
    }
251
252
    public function getHash(): string
253
    {
254
        return md5($this->getRawCertificateFieldsJson());
255
    }
256
257
    public function getRemoteAddress(): string
258
    {
259
        return $this->remoteAddress;
260
    }
261
262
    public function __toString(): string
263
    {
264
        return $this->getRawCertificateFieldsJson();
265
    }
266
267
    public function containsDomain(string $domain): bool
268
    {
269
        $certificateHosts = $this->getDomains();
270
271
        foreach ($certificateHosts as $certificateHost) {
272
            if ($certificateHost == $domain) {
273
                return true;
274
            }
275
276
            if (ends_with($domain, '.'.$certificateHost)) {
277
                return true;
278
            }
279
        }
280
281
        return false;
282
    }
283
284
    public function isPreCertificate(): bool
285
    {
286
        if (! array_key_exists('extensions', $this->rawCertificateFields)) {
287
            return false;
288
        }
289
290
        if (! array_key_exists('ct_precert_poison', $this->rawCertificateFields['extensions'])) {
291
            return false;
292
        }
293
294
        return true;
295
    }
296
}
297