diff --git a/src/Composer/Config.php b/src/Composer/Config.php index 74db60bb9..adc7e6021 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -107,6 +107,8 @@ class Config private $useEnvironment; /** @var array */ private $warnedHosts = array(); + /** @var array */ + private $sslVerifyWarnedHosts = array(); /** @var array */ private $sourceOfConfigValue = array(); @@ -575,10 +577,11 @@ class Config * * @param string $url * @param IOInterface $io + * @param mixed[] $repoOptions * * @return void */ - public function prohibitUrlByConfig(string $url, IOInterface $io = null): void + public function prohibitUrlByConfig(string $url, IOInterface $io = null, array $repoOptions = []): void { // Return right away if the URL is malformed or custom (see issue #5173) if (false === filter_var($url, FILTER_VALIDATE_URL)) { @@ -600,16 +603,31 @@ class Config throw new TransportException("Your configuration does not allow connections to $url. See https://getcomposer.org/doc/06-config.md#secure-http for details."); } - if ($io) { - $host = parse_url($url, PHP_URL_HOST); - if (is_string($host)) { - if (!isset($this->warnedHosts[$host])) { - $io->writeError("Warning: Accessing $host over $scheme which is an insecure protocol."); + if ($io !== null) { + if (is_string($hostname)) { + if (!isset($this->warnedHosts[$hostname])) { + $io->writeError("Warning: Accessing $hostname over $scheme which is an insecure protocol."); } - $this->warnedHosts[$host] = true; + $this->warnedHosts[$hostname] = true; } } } + + if ($io !== null && is_string($hostname) && !isset($this->sslVerifyWarnedHosts[$hostname])) { + $warning = null; + if (isset($repoOptions['ssl']['verify_peer']) && !(bool) $repoOptions['ssl']['verify_peer']) { + $warning = 'verify_peer'; + } + + if (isset($repoOptions['ssl']['verify_peer_name']) && !(bool) $repoOptions['ssl']['verify_peer_name']) { + $warning = $warning === null ? 'verify_peer_name' : $warning . ' and verify_peer_name'; + } + + if ($warning !== null) { + $io->writeError("Warning: Accessing $hostname with $warning disabled."); + $this->sslVerifyWarnedHosts[$hostname] = true; + } + } } /** diff --git a/src/Composer/Util/Http/CurlDownloader.php b/src/Composer/Util/Http/CurlDownloader.php index 1b3a4647b..54628204e 100644 --- a/src/Composer/Util/Http/CurlDownloader.php +++ b/src/Composer/Util/Http/CurlDownloader.php @@ -168,7 +168,7 @@ class CurlDownloader // check URL can be accessed (i.e. is not insecure), but allow insecure Packagist calls to $hashed providers as file integrity is verified with sha256 if (!Preg::isMatch('{^http://(repo\.)?packagist\.org/p/}', $url) || (false === strpos($url, '$') && false === strpos($url, '%24'))) { - $this->config->prohibitUrlByConfig($url, $this->io); + $this->config->prohibitUrlByConfig($url, $this->io, $options); } $curlHandle = curl_init(); diff --git a/tests/Composer/Test/ConfigTest.php b/tests/Composer/Test/ConfigTest.php index 73d20f58a..201fa7832 100644 --- a/tests/Composer/Test/ConfigTest.php +++ b/tests/Composer/Test/ConfigTest.php @@ -13,6 +13,9 @@ namespace Composer\Test; use Composer\Config; +use Composer\IO\BaseIO; +use Composer\IO\IOInterface; +use Composer\IO\NullIO; use Composer\Util\Platform; class ConfigTest extends TestCase @@ -308,6 +311,24 @@ class ConfigTest extends TestCase }, $urls)); } + public function testProhibitedUrlsWarningVerifyPeer(): void + { + $io = $this->getMockBuilder(IOInterface::class)->disableOriginalConstructor()->getMock(); + + $io + ->expects($this->once()) + ->method('writeError') + ->with($this->equalTo('Warning: Accessing example.org with verify_peer and verify_peer_name disabled.')); + + $config = new Config(false); + $config->prohibitUrlByConfig('https://example.org', $io, [ + 'ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => false, + ] + ]); + } + /** * @group TLS */