diff options
Diffstat (limited to 'lib/private/Http/Client/Client.php')
-rw-r--r-- | lib/private/Http/Client/Client.php | 68 |
1 files changed, 28 insertions, 40 deletions
diff --git a/lib/private/Http/Client/Client.php b/lib/private/Http/Client/Client.php index 12d1efb45a2..c1426d141d1 100644 --- a/lib/private/Http/Client/Client.php +++ b/lib/private/Http/Client/Client.php @@ -38,7 +38,6 @@ use GuzzleHttp\Client as GuzzleClient; use GuzzleHttp\RequestOptions; use OCP\Http\Client\IClient; use OCP\Http\Client\IResponse; -use OCP\Http\Client\LocalServerException; use OCP\ICertificateManager; use OCP\IConfig; use OCP\ILogger; @@ -57,17 +56,21 @@ class Client implements IClient { private $logger; /** @var ICertificateManager */ private $certificateManager; + /** @var LocalAddressChecker */ + private $localAddressChecker; public function __construct( IConfig $config, ILogger $logger, ICertificateManager $certificateManager, - GuzzleClient $client + GuzzleClient $client, + LocalAddressChecker $localAddressChecker ) { $this->config = $config; $this->logger = $logger; $this->client = $client; $this->certificateManager = $certificateManager; + $this->localAddressChecker = $localAddressChecker; } private function buildRequestOptions(array $options): array { @@ -78,6 +81,21 @@ class Client implements IClient { RequestOptions::TIMEOUT => 30, ]; + $options['nextcloud']['allow_local_address'] = $this->isLocalAddressAllowed($options); + if ($options['nextcloud']['allow_local_address'] === false) { + $onRedirectFunction = function ( + \Psr\Http\Message\RequestInterface $request, + \Psr\Http\Message\ResponseInterface $response, + \Psr\Http\Message\UriInterface $uri + ) use ($options) { + $this->preventLocalAddress($uri->__toString(), $options); + }; + + $defaults[RequestOptions::ALLOW_REDIRECTS] = [ + 'on_redirect' => $onRedirectFunction + ]; + } + // Only add RequestOptions::PROXY if Nextcloud is explicitly // configured to use a proxy. This is needed in order not to override // Guzzle default values. @@ -155,51 +173,21 @@ class Client implements IClient { return $proxy; } - protected function preventLocalAddress(string $uri, array $options): void { + private function isLocalAddressAllowed(array $options) : bool { if (($options['nextcloud']['allow_local_address'] ?? false) || $this->config->getSystemValueBool('allow_local_remote_servers', false)) { - return; - } - - $host = parse_url($uri, PHP_URL_HOST); - if ($host === false || $host === null) { - $this->logger->warning("Could not detect any host in $uri"); - throw new LocalServerException('Could not detect any host'); - } - - $host = strtolower($host); - // Remove brackets from IPv6 addresses - if (strpos($host, '[') === 0 && substr($host, -1) === ']') { - $host = substr($host, 1, -1); + return true; } - // Disallow localhost and local network - if ($host === 'localhost' || substr($host, -6) === '.local' || substr($host, -10) === '.localhost') { - $this->logger->warning("Host $host was not connected to because it violates local access rules"); - throw new LocalServerException('Host violates local access rules'); - } - - // Disallow hostname only - if (substr_count($host, '.') === 0) { - $this->logger->warning("Host $host was not connected to because it violates local access rules"); - throw new LocalServerException('Host violates local access rules'); - } + return false; + } - if ((bool)filter_var($host, FILTER_VALIDATE_IP) && !filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { - $this->logger->warning("Host $host was not connected to because it violates local access rules"); - throw new LocalServerException('Host violates local access rules'); + protected function preventLocalAddress(string $uri, array $options): void { + if ($this->isLocalAddressAllowed($options)) { + return; } - // Also check for IPv6 IPv4 nesting, because that's not covered by filter_var - if ((bool)filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) && substr_count($host, '.') > 0) { - $delimiter = strrpos($host, ':'); // Get last colon - $ipv4Address = substr($host, $delimiter + 1); - - if (!filter_var($ipv4Address, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { - $this->logger->warning("Host $host was not connected to because it violates local access rules"); - throw new LocalServerException('Host violates local access rules'); - } - } + $this->localAddressChecker->ThrowIfLocalAddress($uri); } /** |