diff --git a/README.md b/README.md index 775b3fc..2ad7a24 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,13 @@ SslCertificate::download() ->forHost($hostName); ``` +This also works with IPv6 addresses +```php +SslCertificate::download() + ->fromIpAddress('2a00:1450:4001:80e::200e') + ->forHost('google.com'); +``` + You can specify [socket context options](https://www.php.net/manual/en/context.socket.php). ```php SslCertificate::download() diff --git a/src/Downloader.php b/src/Downloader.php index 586c0ee..9327bde 100644 --- a/src/Downloader.php +++ b/src/Downloader.php @@ -11,6 +11,8 @@ class Downloader protected ?string $ipAddress = null; + protected bool $isIPv6 = false; + protected bool $usingIpAddress = false; protected int $timeout = 30; @@ -85,9 +87,14 @@ public function setFollowLocation(int $followLocation): self public function fromIpAddress(string $ipAddress): self { - if (! filter_var($ipAddress, FILTER_VALIDATE_IP)) { + $isValidIPv4 = filter_var($ipAddress, FILTER_VALIDATE_IP) !== false; + $isValidIPv6 = filter_var($ipAddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false; + if (!$isValidIPv4 && !$isValidIPv6) { throw InvalidIpAddress::couldNotValidate($ipAddress); } + if($isValidIPv6) { + $this->isIPv6 = true; + } $this->ipAddress = $ipAddress; $this->usingIpAddress = true; @@ -164,9 +171,11 @@ protected function fetchCertificates(string $hostName): array 'ssl' => $sslOptions, ]); - $connectTo = ($this->usingIpAddress) - ? $this->ipAddress - : $hostName; + if($this->usingIpAddress) { + $connectTo = ($this->isIPv6) ? "[" . $this->ipAddress . ']' : $this->ipAddress; + } else { + $connectTo = $hostName; + } $client = @stream_socket_client( "ssl://{$connectTo}:{$this->port}", diff --git a/tests/DownloaderTest.php b/tests/DownloaderTest.php index 9added5..a9e50d8 100644 --- a/tests/DownloaderTest.php +++ b/tests/DownloaderTest.php @@ -59,7 +59,7 @@ public function it_can_download_a_certificate_from_a_host_name_with_strange_char public function it_can_download_a_certificate_for_a_host_name_from_an_ip_address() { $sslCertificate = SslCertificate::download() - ->fromIpAddress('138.197.187.74') + ->fromIpAddress('164.92.244.169') ->forHost('spatie.be'); $this->assertInstanceOf(SslCertificate::class, $sslCertificate); @@ -75,6 +75,19 @@ public function it_can_download_a_certificate_for_a_host_name_from_an_ip_address $this->assertInstanceOf(SslCertificate::class, $sslCertificate); } + /** @test */ + public function it_can_download_a_certificate_for_a_host_name_from_an_ipv6_address() + { + if(getenv('GITHUB_ACTIONS')) { + $this->markTestSkipped('Github Actions have no IPv6 Support'); + } + $sslCertificate = SslCertificate::download() + ->fromIpAddress('2a00:1450:4001:80e::200e') + ->forHost('google.com'); + + $this->assertInstanceOf(SslCertificate::class, $sslCertificate); + } + /** @test */ public function it_sets_a_fingerprint_on_the_downloaded_certificate() { @@ -142,7 +155,7 @@ public function it_can_retrieve_the_ip_address_of_the_server_that_served_the_cer { $sslCertificate = Downloader::downloadCertificateFromUrl('spatie.be'); - $this->assertEquals('138.197.187.74:443', $sslCertificate->getRemoteAddress()); + $this->assertEquals('164.92.244.169:443', $sslCertificate->getRemoteAddress()); } /** @test */