From 600b6c8cb3ea0a3e4f76ed6a7e9f524011dace63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1draic=20Brady?= Date: Mon, 24 Feb 2014 20:07:18 +0000 Subject: [PATCH] TLS support for Factory::createComposer() - for JsonFile remotes --- src/Composer/Command/Command.php | 5 ++-- src/Composer/Command/RequireCommand.php | 2 ++ src/Composer/Console/Application.php | 4 ++-- src/Composer/Factory.php | 32 +++++++++++++++++++++---- 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/Composer/Command/Command.php b/src/Composer/Command/Command.php index 862b54e58..fb8c8c814 100644 --- a/src/Composer/Command/Command.php +++ b/src/Composer/Command/Command.php @@ -17,6 +17,7 @@ use Composer\Console\Application; use Composer\IO\IOInterface; use Composer\IO\NullIO; use Symfony\Component\Console\Command\Command as BaseCommand; +use Symfony\Component\Console\Input\InputInterface; /** * Base class for Composer commands @@ -42,13 +43,13 @@ abstract class Command extends BaseCommand * @throws \RuntimeException * @return Composer */ - public function getComposer($required = true, $disablePlugins = false) + public function getComposer($required = true, $disablePlugins = false, InputInterface $input = null) { if (null === $this->composer) { $application = $this->getApplication(); if ($application instanceof Application) { /* @var $application Application */ - $this->composer = $application->getComposer($required, $disablePlugins); + $this->composer = $application->getComposer($required, $disablePlugins, $input); } elseif ($required) { throw new \RuntimeException( 'Could not create a Composer\Composer instance, you must inject '. diff --git a/src/Composer/Command/RequireCommand.php b/src/Composer/Command/RequireCommand.php index 4a005d809..6d7fd79cd 100644 --- a/src/Composer/Command/RequireCommand.php +++ b/src/Composer/Command/RequireCommand.php @@ -43,6 +43,8 @@ class RequireCommand extends InitCommand new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'), new InputOption('no-update', null, InputOption::VALUE_NONE, 'Disables the automatic update of the dependencies.'), new InputOption('update-with-dependencies', null, InputOption::VALUE_NONE, 'Allows inherited dependencies to be updated with explicit dependencies.'), + new InputOption('disable-tls', null, InputOption::VALUE_NONE, 'Disable SSL/TLS protection for HTTPS requests'), + new InputOption('cafile', null, InputOption::VALUE_REQUIRED, 'The path to a valid CA certificate file for SSL/TLS certificate verification'), )) ->setHelp(<<composer) { try { - $this->composer = Factory::create($this->io, null, $disablePlugins); + $this->composer = Factory::create($this->io, null, $disablePlugins, $input); } catch (\InvalidArgumentException $e) { if ($required) { $this->io->write($e->getMessage()); diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index 57f02d81a..3196f24d9 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -24,6 +24,7 @@ use Symfony\Component\Console\Formatter\OutputFormatterStyle; use Composer\EventDispatcher\EventDispatcher; use Composer\Autoload\AutoloadGenerator; use Composer\Package\Version\VersionParser; +use Symfony\Component\Console\Input\InputInterface; /** * Creates a configured instance of composer. @@ -184,7 +185,7 @@ class Factory * @throws \UnexpectedValueException * @return Composer */ - public function createComposer(IOInterface $io, $localConfig = null, $disablePlugins = false) + public function createComposer(IOInterface $io, $localConfig = null, $disablePlugins = false, InputInterface $input = null) { // load Composer configuration if (null === $localConfig) { @@ -193,7 +194,28 @@ class Factory if (is_string($localConfig)) { $composerFile = $localConfig; - $file = new JsonFile($localConfig, new RemoteFilesystem($io)); + + $rfs = null; + if (preg_match("|^https?://|i", $localConfig)) { + $disableTls = false; + if($input->getOption('disable-tls')) { + //$output->writeln('You are running Composer with SSL/TLS protection disabled.'); //TODO + $disableTls = true; + } elseif (!extension_loaded('openssl')) { + throw new \RuntimeException('The openssl extension is required for SSL/TLS protection but is not available. ' + . 'You can disable this error, at your own risk, by passing the \'--disable-tls\' option to this command.'); + } + + $rfsOptions = array(); + if ($disableTls === false) { + if (!is_null($input->get('cafile'))) { + $rfsOptions = array('ssl'=>array('cafile'=>$input->get('cafile'))); + } + } + $rfs = new RemoteFilesystem($io, $rfsOptions, $disableTls); + } + + $file = new JsonFile($localConfig, $rfs); if (!$file->exists()) { if ($localConfig === './composer.json' || $localConfig === 'composer.json') { @@ -275,7 +297,7 @@ class Factory $lockFile = "json" === pathinfo($composerFile, PATHINFO_EXTENSION) ? substr($composerFile, 0, -4).'lock' : $composerFile . '.lock'; - $locker = new Package\Locker($io, new JsonFile($lockFile, new RemoteFilesystem($io)), $rm, $im, md5_file($composerFile)); + $locker = new Package\Locker($io, new JsonFile($lockFile, $rfs), $rm, $im, md5_file($composerFile)); // can we reuse same object? $composer->setLocker($locker); } @@ -441,10 +463,10 @@ class Factory * @param bool $disablePlugins Whether plugins should not be loaded * @return Composer */ - public static function create(IOInterface $io, $config = null, $disablePlugins = false) + public static function create(IOInterface $io, $config = null, $disablePlugins = false, InputInterface $input = null) { $factory = new static(); - return $factory->createComposer($io, $config, $disablePlugins); + return $factory->createComposer($io, $config, $disablePlugins, $input); } }