1
0
Fork 0

Added Exceptions, errors and info messages for self-update command and TLS defaults to RemoteFilesystem

pull/2745/head
Pádraic Brady 2014-02-23 12:36:27 +00:00
parent d081aa0784
commit ca4b4696b0
2 changed files with 190 additions and 7 deletions

View File

@ -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];

View File

@ -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;
}
}