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 ( cba02a...14fda8 )
by Freek
01:19
created

SslCertificate::wildcardHostCoversHost()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 12
nc 5
nop 2
dl 0
loc 22
rs 8.6737
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
    public static function download(): Downloader
19
    {
20
        return new Downloader();
21
    }
22
23
    public static function createForHostName(string $url, int $timeout = 30): self
24
    {
25
        $sslCertificate = Downloader::downloadCertificateFromUrl($url, $timeout);
26
27
        return $sslCertificate;
28
    }
29
30
    public function __construct(array $rawCertificateFields, string $fingerprint = '')
31
    {
32
        $this->rawCertificateFields = $rawCertificateFields;
33
34
        $this->fingerprint = $fingerprint;
35
    }
36
37
    public function getRawCertificateFields(): array
38
    {
39
        return $this->rawCertificateFields;
40
    }
41
42
    public function getIssuer(): string
43
    {
44
        return $this->rawCertificateFields['issuer']['CN'] ?? '';
45
    }
46
47
    public function getDomain(): string
48
    {
49
        if (! array_key_exists('CN', $this->rawCertificateFields['subject'])) {
50
            return '';
51
        }
52
53
        /* Common Name is a string */
54
        if (is_string($this->rawCertificateFields['subject']['CN'])) {
55
            return $this->rawCertificateFields['subject']['CN'];
56
        }
57
58
        /* Common name is an array consisting of multiple domains, take the first one */
59
        if (is_array($this->rawCertificateFields['subject']['CN'])) {
60
            return $this->rawCertificateFields['subject']['CN'][0];
61
        }
62
63
        return '';
64
    }
65
66
    public function getSignatureAlgorithm(): string
67
    {
68
        return $this->rawCertificateFields['signatureTypeSN'] ?? '';
69
    }
70
71
    public function getFingerprint(): string
72
    {
73
        return $this->fingerprint;
74
    }
75
76
    public function getAdditionalDomains(): array
77
    {
78
        $additionalDomains = explode(', ', $this->rawCertificateFields['extensions']['subjectAltName'] ?? '');
79
80
        return array_map(function (string $domain) {
81
            return str_replace('DNS:', '', $domain);
82
        }, $additionalDomains);
83
    }
84
85
    public function validFromDate(): Carbon
86
    {
87
        return Carbon::createFromTimestampUTC($this->rawCertificateFields['validFrom_time_t']);
88
    }
89
90
    public function expirationDate(): Carbon
91
    {
92
        return Carbon::createFromTimestampUTC($this->rawCertificateFields['validTo_time_t']);
93
    }
94
95
    public function isExpired(): bool
96
    {
97
        return $this->expirationDate()->isPast();
98
    }
99
100
    public function isValid(string $url = null)
101
    {
102
        if (! Carbon::now()->between($this->validFromDate(), $this->expirationDate())) {
103
            return false;
104
        }
105
106
        if (! empty($url)) {
107
            return $this->appliesToUrl($url ?? $this->getDomain());
108
        }
109
110
        return true;
111
    }
112
113
    public function isSelfSigned(): bool
114
    {
115
        return $this->getIssuer() === $this->getDomain();
116
    }
117
118
    public function usesSha1Hash(): bool
119
    {
120
        $certificateFields = $this->getRawCertificateFields();
121
122
        if ($certificateFields['signatureTypeSN'] === 'RSA-SHA1') {
123
            return true;
124
        }
125
126
        if ($certificateFields['signatureTypeLN'] === 'sha1WithRSAEncryption') {
127
            return true;
128
        }
129
130
        return false;
131
    }
132
133
    public function isValidUntil(Carbon $carbon, string $url = null): bool
134
    {
135
        if ($this->expirationDate()->lte($carbon)) {
136
            return false;
137
        }
138
139
        return $this->isValid($url);
140
    }
141
142
    public function daysUntilExpirationDate(): int
143
    {
144
        $endDate = $this->expirationDate();
145
146
        $interval = Carbon::now()->diff($endDate);
147
148
        return (int) $interval->format('%r%a');
149
    }
150
151
    public function getDomains(): array
152
    {
153
        $allDomains = $this->getAdditionalDomains();
154
155
        $uniqueDomains = array_unique($allDomains);
156
157
        return array_values(array_filter($uniqueDomains));
158
    }
159
160
    public function appliesToUrl(string $url): bool
161
    {
162
        $host = (new Url($url))->getHostName();
163
164
        $certificateHosts = $this->getDomains();
165
166
        foreach ($certificateHosts as $certificateHost) {
167
            if ($host === $certificateHost) {
168
                return true;
169
            }
170
171
            if ($this->wildcardHostCoversHost($certificateHost, $host)) {
172
                return true;
173
            }
174
        }
175
176
        return false;
177
    }
178
179
    protected function wildcardHostCoversHost(string $wildcardHost, string $host): bool
180
    {
181
        if ($host === $wildcardHost) {
182
            return true;
183
        }
184
185
        if (! starts_with($wildcardHost, '*')) {
186
            return false;
187
        }
188
189
        if (substr_count($wildcardHost, '.') < substr_count($host, '.')) {
190
            return false;
191
        }
192
193
        $wildcardHostWithoutWildcard = substr($wildcardHost, 1);
194
        $hostWithDottedPrefix = '.'.$host;
195
        if (ends_with($hostWithDottedPrefix, $wildcardHostWithoutWildcard)) {
196
            return true;
197
        }
198
199
        return false;
200
    }
201
202
    public function getRawCertificateFieldsJson(): string
203
    {
204
        return json_encode($this->getRawCertificateFields());
205
    }
206
207
    public function getHash(): string
208
    {
209
        return md5($this->getRawCertificateFieldsJson());
210
    }
211
212
    public function __toString(): string
213
    {
214
        return $this->getRawCertificateFieldsJson();
215
    }
216
217
    public function containsDomain(string $domain): bool
218
    {
219
        $certificateHosts = $this->getDomains();
220
221
        foreach ($certificateHosts as $certificateHost) {
222
            if ($certificateHost == $domain) {
223
                return true;
224
            }
225
226
            if (ends_with($domain, '.'.$certificateHost)) {
227
                return true;
228
            }
229
        }
230
231
        return false;
232
    }
233
}
234