Added Exceptions, errors and info messages for self-update command and TLS defaults to RemoteFilesystem
parent
d081aa0784
commit
ca4b4696b0
|
@ -17,6 +17,7 @@ use Composer\Factory;
|
||||||
use Composer\Util\Filesystem;
|
use Composer\Util\Filesystem;
|
||||||
use Composer\Util\RemoteFilesystem;
|
use Composer\Util\RemoteFilesystem;
|
||||||
use Composer\Downloader\FilesystemException;
|
use Composer\Downloader\FilesystemException;
|
||||||
|
use Composer\Downloader\TransportException;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
@ -57,17 +58,34 @@ EOT
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
$config = Factory::createConfig();
|
$config = Factory::createConfig();
|
||||||
if (!extension_loaded('openssl')) {
|
|
||||||
$output->writeln('<error>The openssl extension is required for SSL/TLS protection.</error>');
|
if($config->get('disable-tls') === true || $input->getOption('disable-tls')) {
|
||||||
$output->writeln('<error>You can disable this error, at your own risk, by setting the \'disable-tls\' option to "false".</error>');
|
|
||||||
return 1;
|
|
||||||
} elseif($config->get('disable-tls') === true) {
|
|
||||||
$output->writeln('<info>You are running Composer with SSL/TLS protection disabled.</info>');
|
$output->writeln('<info>You are running Composer with SSL/TLS protection disabled.</info>');
|
||||||
$baseUrl = 'http://' . self::HOMEPAGE;
|
$baseUrl = 'http://' . self::HOMEPAGE;
|
||||||
|
} elseif (!extension_loaded('openssl')) {
|
||||||
|
$output->writeln('<error>The openssl extension is required for SSL/TLS protection.</error>');
|
||||||
|
$output->writeln('<error>You can disable this error, at your own risk, by enabling the \'disable-tls\' option.</error>');
|
||||||
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
$baseUrl = 'https://' . self::HOMEPAGE;
|
$baseUrl = 'https://' . self::HOMEPAGE;
|
||||||
}
|
}
|
||||||
$remoteFilesystem = new RemoteFilesystem($this->getIO());
|
|
||||||
|
try {
|
||||||
|
if (!is_null($config->get('cafile'))) {
|
||||||
|
$remoteFilesystemOptions = array('ssl'=>array('cafile'=>$config->get('cafile')));
|
||||||
|
}
|
||||||
|
$remoteFilesystem = new RemoteFilesystem($this->getIO(), $remoteFilesystemOptions);
|
||||||
|
} catch (TransportException $e) {
|
||||||
|
if (preg_match('|cafile|', $e->getMessage())) {
|
||||||
|
$output->writeln('<error>' . $e->getMessage() . '</error>');
|
||||||
|
$output->writeln('<error>Unable to locate a valid CA certificate file. You must set a valid \'cafile\' option.</error>');
|
||||||
|
$output->writeln('<error>You can disable this error, at your own risk, by enabling the \'disable-tls\' option.</error>');
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$cacheDir = $config->get('cache-dir');
|
$cacheDir = $config->get('cache-dir');
|
||||||
$rollbackDir = $config->get('home');
|
$rollbackDir = $config->get('home');
|
||||||
$localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0];
|
$localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0];
|
||||||
|
|
|
@ -43,7 +43,20 @@ class RemoteFilesystem
|
||||||
public function __construct(IOInterface $io, $options = array())
|
public function __construct(IOInterface $io, $options = array())
|
||||||
{
|
{
|
||||||
$this->io = $io;
|
$this->io = $io;
|
||||||
$this->options = $options;
|
|
||||||
|
/**
|
||||||
|
* Setup TLS options
|
||||||
|
* The cafile option can be set via config.json
|
||||||
|
*/
|
||||||
|
$this->options = $this->getTlsDefaults();
|
||||||
|
if (isset($options['ssl']['cafile'])
|
||||||
|
&& (!is_readable($options['ssl']['cafile'])
|
||||||
|
|| !openssl_x509_parse(file_get_contents($options['ssl']['cafile'])))) { //check return value and test (it's subject to change)
|
||||||
|
throw new TransportException('The configured cafile could was not valid or could not be read.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle the other externally set options normally.
|
||||||
|
$this->options = array_replace_recursive($this->options, $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -344,6 +357,158 @@ class RemoteFilesystem
|
||||||
$options['http']['header'][] = $header;
|
$options['http']['header'][] = $header;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup TLS options CN_match and SNI_server_name based on URL given
|
||||||
|
*/
|
||||||
|
$parts = parse_url($originUrl);
|
||||||
|
|
||||||
|
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getTlsDefaults()
|
||||||
|
{
|
||||||
|
$ciphers = implode(':', array(
|
||||||
|
'ECDHE-RSA-AES128-GCM-SHA256',
|
||||||
|
'ECDHE-ECDSA-AES128-GCM-SHA256',
|
||||||
|
'ECDHE-RSA-AES256-GCM-SHA384',
|
||||||
|
'ECDHE-ECDSA-AES256-GCM-SHA384',
|
||||||
|
'DHE-RSA-AES128-GCM-SHA256',
|
||||||
|
'DHE-DSS-AES128-GCM-SHA256',
|
||||||
|
'kEDH+AESGCM',
|
||||||
|
'ECDHE-RSA-AES128-SHA256',
|
||||||
|
'ECDHE-ECDSA-AES128-SHA256',
|
||||||
|
'ECDHE-RSA-AES128-SHA',
|
||||||
|
'ECDHE-ECDSA-AES128-SHA',
|
||||||
|
'ECDHE-RSA-AES256-SHA384',
|
||||||
|
'ECDHE-ECDSA-AES256-SHA384',
|
||||||
|
'ECDHE-RSA-AES256-SHA',
|
||||||
|
'ECDHE-ECDSA-AES256-SHA',
|
||||||
|
'DHE-RSA-AES128-SHA256',
|
||||||
|
'DHE-RSA-AES128-SHA',
|
||||||
|
'DHE-DSS-AES128-SHA256',
|
||||||
|
'DHE-RSA-AES256-SHA256',
|
||||||
|
'DHE-DSS-AES256-SHA',
|
||||||
|
'DHE-RSA-AES256-SHA',
|
||||||
|
'AES128-GCM-SHA256',
|
||||||
|
'AES256-GCM-SHA384',
|
||||||
|
'ECDHE-RSA-RC4-SHA',
|
||||||
|
'ECDHE-ECDSA-RC4-SHA',
|
||||||
|
'AES128',
|
||||||
|
'AES256',
|
||||||
|
'RC4-SHA',
|
||||||
|
'HIGH',
|
||||||
|
'!aNULL',
|
||||||
|
'!eNULL',
|
||||||
|
'!EXPORT',
|
||||||
|
'!DES',
|
||||||
|
'!3DES',
|
||||||
|
'!MD5',
|
||||||
|
'!PSK'
|
||||||
|
));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CN_match and SNI_server_name are only known once a URL is passed.
|
||||||
|
* They will be set in the getOptionsForUrl() method which receives a URL.
|
||||||
|
*
|
||||||
|
* cafile or capath can be overridden by passing in those options to constructor.
|
||||||
|
*/
|
||||||
|
$options = array(
|
||||||
|
'ssl' => array(
|
||||||
|
'ciphers' => $ciphers,
|
||||||
|
'verify_peer' => true,
|
||||||
|
'verify_depth' => 7,
|
||||||
|
'SNI_enabled' => true,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to find a local cafile or throw an exception.
|
||||||
|
* The user may go download one if this occurs.
|
||||||
|
*/
|
||||||
|
$result = $this->getSystemCaRootBundlePath();
|
||||||
|
if ($result) {
|
||||||
|
$options['ssl']['cafile'] = $result;
|
||||||
|
} else {
|
||||||
|
throw new TransportException('A valid cafile could not be located automatically.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable TLS compression to prevent CRIME attacks where supported.
|
||||||
|
*/
|
||||||
|
if (version_compare(PHP_VERSION, '5.4.13') >= 0) {
|
||||||
|
$options['ssl']['disable_compression'] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method was adapted from Sslurp.
|
||||||
|
* https://github.com/EvanDotPro/Sslurp
|
||||||
|
*
|
||||||
|
* (c) Evan Coury <me@evancoury.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please see below:
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Evan Coury
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
protected static function getSystemCaRootBundlePath()
|
||||||
|
{
|
||||||
|
if (isset($found)) {
|
||||||
|
return $found;
|
||||||
|
}
|
||||||
|
// If SSL_CERT_FILE env variable points to a valid certificate/bundle, use that.
|
||||||
|
// This mimics how OpenSSL uses the SSL_CERT_FILE env variable.
|
||||||
|
$envCertFile = getenv('SSL_CERT_FILE');
|
||||||
|
if ($envCertFile && is_readable($envCertFile) && openssl_x509_parse(file_get_contents($envCertFile))) {
|
||||||
|
// Possibly throw exception instead of ignoring SSL_CERT_FILE if it's invalid?
|
||||||
|
return $envCertFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
$caBundlePaths = array(
|
||||||
|
'/etc/pki/tls/certs/ca-bundle.crt', // Fedora, RHEL, CentOS (ca-certificates package)
|
||||||
|
'/etc/ssl/certs/ca-certificates.crt', // Debian, Ubuntu, Gentoo, Arch Linux (ca-certificates package)
|
||||||
|
'/etc/ssl/ca-bundle.pem', // SUSE, openSUSE (ca-certificates package)
|
||||||
|
'/usr/local/share/certs/ca-root-nss.crt', // FreeBSD (ca_root_nss_package)
|
||||||
|
'/usr/ssl/certs/ca-bundle.crt', // Cygwin
|
||||||
|
'/opt/local/share/curl/curl-ca-bundle.crt', // OS X macports, curl-ca-bundle package
|
||||||
|
'/usr/local/share/curl/curl-ca-bundle.crt', // Default cURL CA bunde path (without --with-ca-bundle option)
|
||||||
|
'/usr/share/ssl/certs/ca-bundle.crt', // Really old RedHat?
|
||||||
|
);
|
||||||
|
|
||||||
|
static $found = false;
|
||||||
|
foreach ($caBundlePaths as $caBundle) {
|
||||||
|
if (is_readable($caBundle) && openssl_x509_parse(file_get_contents($caBundle))) {
|
||||||
|
$found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($found) {
|
||||||
|
$found = $caBundle;
|
||||||
|
}
|
||||||
|
return $found;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue