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
Pull Request — master (#123)
by
unknown
01:07
created

SslCertificate::createFromString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13

Duplication

Lines 13
Ratio 100 %

Importance

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