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\RemoteFilesystem;
|
||||
use Composer\Downloader\FilesystemException;
|
||||
use Composer\Downloader\TransportException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
|
@ -57,17 +58,34 @@ EOT
|
|||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$config = Factory::createConfig();
|
||||
if (!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 setting the \'disable-tls\' option to "false".</error>');
|
||||
return 1;
|
||||
} elseif($config->get('disable-tls') === true) {
|
||||
|
||||
if($config->get('disable-tls') === true || $input->getOption('disable-tls')) {
|
||||
$output->writeln('<info>You are running Composer with SSL/TLS protection disabled.</info>');
|
||||
$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 {
|
||||
$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');
|
||||
$rollbackDir = $config->get('home');
|
||||
$localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0];
|
||||
|
|
|
@ -43,7 +43,20 @@ class RemoteFilesystem
|
|||
public function __construct(IOInterface $io, $options = array())
|
||||
{
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup TLS options CN_match and SNI_server_name based on URL given
|
||||
*/
|
||||
$parts = parse_url($originUrl);
|
||||
|
||||
|
||||
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