* @author Daniel Kesselberg * @author Joas Schilling * @author Lukas Reschke * @author Mohammed Abdellatif * @author Morris Jobke * @author Robin Appelman * @author Roeland Jago Douma * @author Scott Shambarger * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see * */ namespace OC\Http\Client; 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; /** * Class Client * * @package OC\Http */ class Client implements IClient { /** @var GuzzleClient */ private $client; /** @var IConfig */ private $config; /** @var ILogger */ private $logger; /** @var ICertificateManager */ private $certificateManager; public function __construct( IConfig $config, ILogger $logger, ICertificateManager $certificateManager, GuzzleClient $client ) { $this->config = $config; $this->logger = $logger; $this->client = $client; $this->certificateManager = $certificateManager; } private function buildRequestOptions(array $options): array { $proxy = $this->getProxyUri(); $defaults = [ RequestOptions::VERIFY => $this->getCertBundle(), RequestOptions::TIMEOUT => 30, ]; // Only add RequestOptions::PROXY if Nextcloud is explicitly // configured to use a proxy. This is needed in order not to override // Guzzle default values. if ($proxy !== null) { $defaults[RequestOptions::PROXY] = $proxy; } $options = array_merge($defaults, $options); if (!isset($options[RequestOptions::HEADERS]['User-Agent'])) { $options[RequestOptions::HEADERS]['User-Agent'] = 'Nextcloud Server Crawler'; } if (!isset($options[RequestOptions::HEADERS]['Accept-Encoding'])) { $options[RequestOptions::HEADERS]['Accept-Encoding'] = 'gzip'; } return $options; } private function getCertBundle(): string { if ($this->certificateManager->listCertificates() !== []) { return $this->certificateManager->getAbsoluteBundlePath(); } // If the instance is not yet setup we need to use the static path as // $this->certificateManager->getAbsoluteBundlePath() tries to instantiate // a view if ($this->config->getSystemValue('installed', false)) { return $this->certificateManager->getAbsoluteBundlePath(null); } return \OC::$SERVERROOT . '/resources/config/ca-bundle.crt'; } /** * Returns a null or an associative array specifiying the proxy URI for * 'http' and 'https' schemes, in addition to a 'no' key value pair * providing a list of host names that should not be proxied to. * * @return array|null * * The return array looks like: * [ * 'http' => 'username:password@proxy.example.com', * 'https' => 'username:password@proxy.example.com', * 'no' => ['foo.com', 'bar.com'] * ] * */ private function getProxyUri(): ?array { $proxyHost = $this->config->getSystemValue('proxy', ''); if ($proxyHost === '' || $proxyHost === null) { return null; } $proxyUserPwd = $this->config->getSystemValue('proxyuserpwd', ''); if ($proxyUserPwd !== '' && $proxyUserPwd !== null) { $proxyHost = $proxyUserPwd . '@' . $proxyHost; } $proxy = [ 'http' => $proxyHost, 'https' => $proxyHost, ]; $proxyExclude = $this->config->getSystemValue('proxyexclude', []); if ($proxyExclude !== [] && $proxyExclude !== null) { $proxy['no'] = $proxyExclude; } return $proxy; } protected function preventLocalAddress(string $uri, array $options): void { 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); } // 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'); } 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'); } // 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'); } } } /** * Sends a GET request * * @param string $uri * @param array $options Arra
/*
 * Copyright 2011 gitblit.com.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitblit;

import java.io.IOException;

/**
 * GitBlitException is a marginally useful class. :)
 *
 * @author James Moger
 *
 */
public class GitBlitException extends IOException {

	private static final long serialVersionUID = 1L;

	public GitBlitException(String message) {
		super(message);
	}

	public GitBlitException(Throwable cause) {
		super(cause);
	}

	/**
	 * Exception to indicate that the client should prompt for credentials
	 * because the requested action requires authentication.
	 */
	public static class UnauthorizedException extends GitBlitException {

		private static final long serialVersionUID = 1L;

		public UnauthorizedException(String message) {
			super(message);
		}
	}

	/**
	 * Exception to indicate that the requested action can not be executed by
	 * the specified user.
	 */
	public static class ForbiddenException extends GitBlitException {

		private static final long serialVersionUID = 1L;

		public ForbiddenException(String message) {
			super(message);
		}
	}

	/**
	 * Exception to indicate that the requested action has been disabled on the
	 * Gitblit server.
	 */
	public static class NotAllowedException extends GitBlitException {

		private static final long serialVersionUID = 1L;

		public NotAllowedException(String message) {
			super(message);
		}
	}

	/**
	 * Exception to indicate that the requested action can not be executed by
	 * the server because it does not recognize the request type.
	 */
	public static class UnknownRequestException extends GitBlitException {

		private static final long serialVersionUID = 1L;

		public UnknownRequestException(String message) {
			super(message);
		}
	}
}