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 ( 75be2d...2cb665 )
by Freek
01:17
created

Downloader::buildFailureException()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 2
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
1
<?php
2
3
namespace Spatie\SslCertificate;
4
5
use Spatie\SslCertificate\Exceptions\CouldNotDownloadCertificate;
6
use Spatie\SslCertificate\Exceptions\InvalidIpAddress;
7
8
class Downloader
9
{
10
    /** @var int */
11
    protected $port = 443;
12
13
    /** @var string */
14
    protected $ipAddress = null;
15
16
    /** @var bool */
17
    protected $usingIpAddress = false;
18
19
    /** @var int */
20
    protected $timeout = 30;
21
22
    /** @var bool */
23
    protected $enableSni = true;
24
25
    /** @var bool */
26
    protected $capturePeerChain = false;
27
28
    /** @var bool */
29
    protected $verifyPeer = true;
30
31
    /** @var bool */
32
    protected $verifyPeerName = true;
33
34
    public function usingPort(int $port)
35
    {
36
        $this->port = $port;
37
38
        return $this;
39
    }
40
41
    public function usingSni(bool $sni)
42
    {
43
        $this->enableSni = $sni;
44
45
        return $this;
46
    }
47
48
    public function withFullChain(bool $fullChain)
49
    {
50
        $this->capturePeerChain = $fullChain;
51
52
        return $this;
53
    }
54
55
    public function withVerifyPeer(bool $verifyPeer)
56
    {
57
        $this->verifyPeer = $verifyPeer;
58
59
        return $this;
60
    }
61
62
    public function withVerifyPeerName(bool $verifyPeerName)
63
    {
64
        $this->verifyPeerName = $verifyPeerName;
65
66
        return $this;
67
    }
68
69
    public function setTimeout(int $timeOutInSeconds)
70
    {
71
        $this->timeout = $timeOutInSeconds;
72
73
        return $this;
74
    }
75
76
    public function fromIpAddress(string $ipAddress)
77
    {
78
        if (! filter_var($ipAddress, FILTER_VALIDATE_IP)) {
79
            throw InvalidIpAddress::couldNotValidate($ipAddress);
80
        }
81
82
        $this->ipAddress = $ipAddress;
83
        $this->usingIpAddress = true;
84
85
        return $this;
86
    }
87
88
    public function getCertificates(string $hostName): array
89
    {
90
        $response = $this->fetchCertificates($hostName);
91
        $remoteAddress = $response['remoteAddress'];
92
93
        $peerCertificate = $response['options']['ssl']['peer_certificate'];
94
95
        $peerCertificateChain = $response['options']['ssl']['peer_certificate_chain'] ?? [];
96
97
        $fullCertificateChain = array_merge([$peerCertificate], $peerCertificateChain);
98
99
        $certificates = array_map(function ($certificate) use ($remoteAddress) {
100
            $certificateFields = openssl_x509_parse($certificate);
101
102
            $fingerprint = openssl_x509_fingerprint($certificate);
103
            $fingerprintSha256 = openssl_x509_fingerprint($certificate, 'sha256');
104
105
            return new SslCertificate(
106
                $certificateFields,
107
                $fingerprint,
108
                $fingerprintSha256,
109
                $remoteAddress
110
            );
111
        }, $fullCertificateChain);
112
113
        return array_unique($certificates);
114
    }
115
116
    public function forHost(string $hostName): SslCertificate
117
    {
118
        $hostName = (new Url($hostName))->getHostName();
119
120
        $certificates = $this->getCertificates($hostName);
121
122
        return $certificates[0] ?? false;
123
    }
124
125
    public static function downloadCertificateFromUrl(string $url, int $timeout = 30): SslCertificate
126
    {
127
        return (new static())
128
            ->setTimeout($timeout)
129
            ->forHost($url);
130
    }
131
132
    protected function fetchCertificates(string $hostName): array
133
    {
134
        $hostName = (new Url($hostName))->getHostName();
135
136
        $sslOptions = [
137
            'capture_peer_cert' => true,
138
            'capture_peer_cert_chain' => $this->capturePeerChain,
139
            'SNI_enabled' => $this->enableSni,
140
            'peer_name' => $hostName,
141
            'verify_peer' => $this->verifyPeer,
142
            'verify_peer_name' => $this->verifyPeerName,
143
        ];
144
145
        $streamContext = stream_context_create([
146
            'ssl' => $sslOptions,
147
        ]);
148
149
        $connectTo = ($this->usingIpAddress)
150
            ? $this->ipAddress
151
            : $hostName;
152
153
        $client = @stream_socket_client(
154
            "ssl://{$connectTo}:{$this->port}",
155
            $errorNumber,
156
            $errorDescription,
157
            $this->timeout,
158
            STREAM_CLIENT_CONNECT,
159
            $streamContext
160
        );
161
162
        if (! empty($errorDescription)) {
163
            throw $this->buildFailureException($connectTo, $errorDescription);
164
        }
165
166
        if (! $client) {
167
            $clientErrorMessage = ($this->usingIpAddress)
168
                ? "Could not connect to `{$connectTo}` or it does not have a certificate matching `${hostName}`."
169
                : "Could not connect to `{$connectTo}`.";
170
171
            throw CouldNotDownloadCertificate::unknownError($hostName, $clientErrorMessage);
172
        }
173
174
        $response = stream_context_get_params($client);
175
176
        $response['remoteAddress'] = stream_socket_get_name($client, true);
177
178
        fclose($client);
179
180
        return $response;
181
    }
182
183
    protected function buildFailureException(string $hostName, string $errorDescription)
184
    {
185
        if (str_contains($errorDescription, 'getaddrinfo failed')) {
186
            return CouldNotDownloadCertificate::hostDoesNotExist($hostName);
187
        }
188
189
        if (str_contains($errorDescription, 'error:14090086')) {
190
            return CouldNotDownloadCertificate::noCertificateInstalled($hostName);
191
        }
192
193
        return CouldNotDownloadCertificate::unknownError($hostName, $errorDescription);
194
    }
195
}
196