fix: localhost case

This commit is contained in:
loks0n 2025-01-31 22:01:41 +00:00
parent ade25ec845
commit 2e8b8367ed
2 changed files with 10 additions and 18 deletions

View file

@ -65,32 +65,22 @@ class Redirect extends Host
return false;
}
// `\parse_url` returns false when the URL contains a scheme without a hostname.
// In this case, we use a regex to reliably extract the scheme.
$url = \parse_url($value);
if (
!isset($url["hostname"]) &&
!preg_match('/^([a-z][a-z0-9+\.-]*):\/+$/i', $value, $matches)
) {
return false;
// Then check for scheme
$scheme = '';
if (preg_match('/^([a-z][a-z0-9+\.-]*):\/+/i', $value, $matches)) {
$scheme = strtolower($matches[1]);
}
$scheme = $url["scheme"] ?? $matches[1];
if (empty($scheme)) {
return false;
}
$scheme = strtolower($scheme);
// These are dangerous schemes, may expose XSS vulnerabilities
if (in_array($scheme, ["javascript", "data", "blob", "file"])) {
return false;
}
// When the scheme is HTTP or HTTPS, use the hostname validator.
if (empty($scheme) || in_array($scheme, ["http", "https"])) {
return parent::isValid($value);
// When the scheme is in the allowed list, the URL is valid.
if (!empty($this->schemes) && in_array($scheme, $this->schemes)) {
return true;
}
// Otherwise, check if the scheme is allowed.
return in_array($scheme, $this->schemes);
return parent::isValid($value);
}
}

View file

@ -10,6 +10,8 @@ class RedirectTest extends TestCase
public function redirectsProvider(): array
{
return [
"localhost" => [["localhost"], [], "http://localhost", true],
"localhost-no-scheme" => [["localhost"], [], "localhost", false],
"expo scheme" => [[], ["exp"], "exp://192.168.0.1", true],
"custom scheme" => [[], ["myapp"], "myapp://", true],
"custom scheme triple slash" => [[], ["myapp"], "myapp:///", true],