From 01a262193067b0c89066451b1c9e04242aa2f2f9 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Tue, 27 Feb 2024 12:41:29 +0000 Subject: [PATCH] Add isExternal for validating safe domains --- composer.lock | 42 +++++++++++++++++++-------------------- src/Domains/Domain.php | 45 ++++++++++++++++++++++++++++++++---------- tests/DomainTest.php | 9 +++++++++ 3 files changed, 65 insertions(+), 31 deletions(-) diff --git a/composer.lock b/composer.lock index f23385c..c4f6431 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "utopia-php/framework", - "version": "0.31.x-dev", + "version": "0.x-dev", "source": { "type": "git", - "url": "https://github.com/utopia-php/framework.git", - "reference": "32e18aff924149221d660a5387bccd6d2b5e9ee7" + "url": "https://github.com/utopia-php/http.git", + "reference": "e3ff6b933082d57b48e7c4267bb605c0bf2250fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/32e18aff924149221d660a5387bccd6d2b5e9ee7", - "reference": "32e18aff924149221d660a5387bccd6d2b5e9ee7", + "url": "https://api.github.com/repos/utopia-php/http/zipball/e3ff6b933082d57b48e7c4267bb605c0bf2250fd", + "reference": "e3ff6b933082d57b48e7c4267bb605c0bf2250fd", "shasum": "" }, "require": { @@ -46,10 +46,10 @@ "upf" ], "support": { - "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/0.31.x" + "issues": "https://github.com/utopia-php/http/issues", + "source": "https://github.com/utopia-php/http/tree/0.33.0" }, - "time": "2023-12-08T18:46:26+00:00" + "time": "2024-01-08T13:30:27+00:00" } ], "packages-dev": [ @@ -196,12 +196,12 @@ "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "202aaf6b7c2e1e0a622b0298e9f3f537e4d84018" + "reference": "2f5294676c802a62b0549f6bc8983f14294ce369" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/202aaf6b7c2e1e0a622b0298e9f3f537e4d84018", - "reference": "202aaf6b7c2e1e0a622b0298e9f3f537e4d84018", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/2f5294676c802a62b0549f6bc8983f14294ce369", + "reference": "2f5294676c802a62b0549f6bc8983f14294ce369", "shasum": "" }, "require": { @@ -249,7 +249,7 @@ "type": "tidelift" } ], - "time": "2023-11-01T08:01:43+00:00" + "time": "2024-02-10T11:10:03+00:00" }, { "name": "nikic/php-parser", @@ -257,12 +257,12 @@ "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "1eeeb2d5252d6d8706c5a8d9d88b8d1e7ecf2109" + "reference": "af14fdb282aa0e288bfe7eb3b57893484b68dc27" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1eeeb2d5252d6d8706c5a8d9d88b8d1e7ecf2109", - "reference": "1eeeb2d5252d6d8706c5a8d9d88b8d1e7ecf2109", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/af14fdb282aa0e288bfe7eb3b57893484b68dc27", + "reference": "af14fdb282aa0e288bfe7eb3b57893484b68dc27", "shasum": "" }, "require": { @@ -308,7 +308,7 @@ "issues": "https://github.com/nikic/PHP-Parser/issues", "source": "https://github.com/nikic/PHP-Parser/tree/master" }, - "time": "2023-12-22T18:57:32+00:00" + "time": "2024-02-21T20:13:45+00:00" }, { "name": "phar-io/manifest", @@ -754,12 +754,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "37dcc921d6b2fdf5c3b8191d6bc9c9431abb05e8" + "reference": "92ff05570f3725ebbe69e10a704a1ae3fd904ade" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/37dcc921d6b2fdf5c3b8191d6bc9c9431abb05e8", - "reference": "37dcc921d6b2fdf5c3b8191d6bc9c9431abb05e8", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/92ff05570f3725ebbe69e10a704a1ae3fd904ade", + "reference": "92ff05570f3725ebbe69e10a704a1ae3fd904ade", "shasum": "" }, "require": { @@ -849,7 +849,7 @@ "type": "tidelift" } ], - "time": "2023-12-22T07:28:31+00:00" + "time": "2024-02-24T05:49:11+00:00" }, { "name": "sebastian/cli-parser", @@ -1875,5 +1875,5 @@ "php": ">=8.0" }, "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/src/Domains/Domain.php b/src/Domains/Domain.php index 3f7d088..1aef807 100644 --- a/src/Domains/Domain.php +++ b/src/Domains/Domain.php @@ -73,7 +73,7 @@ public function __construct(string $domain) $this->parts = \explode('.', $this->domain); if (empty(self::$list)) { - self::$list = include __DIR__.'/../../data/data.php'; + self::$list = include __DIR__ . '/../../data/data.php'; } } @@ -115,8 +115,8 @@ public function getSuffix(): string for ($i = 0; $i < count($this->parts); $i++) { $joined = \implode('.', \array_slice($this->parts, $i)); $next = \implode('.', \array_slice($this->parts, $i + 1)); - $exception = '!'.$joined; - $wildcard = '*.'.$next; + $exception = '!' . $joined; + $wildcard = '*.' . $next; if (\array_key_exists($exception, self::$list)) { $this->suffix = $next; @@ -145,7 +145,7 @@ public function getSuffix(): string public function getRule(): string { - if (! $this->rule) { + if (!$this->rule) { $this->getSuffix(); } return $this->rule; @@ -156,11 +156,11 @@ public function getRule(): string */ public function getRegisterable(): string { - if (! $this->isKnown()) { + if (!$this->isKnown()) { return ''; } - $registerable = $this->getName().'.'.$this->getSuffix(); + $registerable = $this->getName() . '.' . $this->getSuffix(); return $registerable; } @@ -175,7 +175,7 @@ public function getName(): string } $suffix = $this->getSuffix(); - $suffix = (! empty($suffix)) ? '.'.$suffix : '.'.$this->getTLD(); + $suffix = (!empty($suffix)) ? '.' . $suffix : '.' . $this->getTLD(); $name = \explode('.', \mb_substr($this->domain, 0, \mb_strlen($suffix) * -1)); @@ -190,12 +190,12 @@ public function getName(): string public function getSub(): string { $name = $this->getName(); - $name = (! empty($name)) ? '.'.$name : ''; + $name = (!empty($name)) ? '.' . $name : ''; $suffix = $this->getSuffix(); - $suffix = (! empty($suffix)) ? '.'.$suffix : '.'.$this->getTLD(); + $suffix = (!empty($suffix)) ? '.' . $suffix : '.' . $this->getTLD(); - $domain = $name.$suffix; + $domain = $name . $suffix; $sub = \explode('.', \mb_substr($this->domain, 0, \mb_strlen($domain) * -1)); @@ -240,6 +240,31 @@ public function isPrivate(): bool return false; } + /** + * Performs a DNS Lookup to check if the domain is valid and isn't within the private or reserved IP ranges + */ + public function isExternal(): bool + { + $ipV4s = dns_get_record($this->get(), DNS_A); + $ipV6s = dns_get_record($this->get(), DNS_AAAA); + + $ips = array_merge($ipV4s, $ipV6s); + + if (empty($ips)) { + return false; + } + + foreach ($ips as $record) { + $ipAddress = $record['ip'] ?? $record['ipv6'] ?? null; + + if ($ipAddress && !filter_var($ipAddress, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { + return false; + } + } + + return true; + } + /** * Returns true if the public suffix is reserved for testing purpose */ diff --git a/tests/DomainTest.php b/tests/DomainTest.php index 28e3f59..8a97285 100755 --- a/tests/DomainTest.php +++ b/tests/DomainTest.php @@ -355,4 +355,13 @@ public function testPrivateDomain(): void $this->assertEquals(true, $domain->isPrivate()); $this->assertEquals(false, $domain->isTest()); } + + public function testIsExternal() + { + $internalDomain = new Domain('127.0.0.1.nip.io'); + $this->assertFalse($internalDomain->isExternal()); + + $externalDomain = new Domain('example.com'); + $this->assertTrue($externalDomain->isExternal()); + } }