diff --git a/doc/03-cli.md b/doc/03-cli.md index cbb67a508..4f7d3c061 100644 --- a/doc/03-cli.md +++ b/doc/03-cli.md @@ -898,4 +898,9 @@ If set to 1, this env changes the default path repository strategy to `mirror` i of `symlink`. As it is the default strategy being set it can still be overwritten by repository options. +### COMPOSER_HTACCESS_PROTECT + +Defaults to `1`. If set to `0`, Composer will not create `.htaccess` files in the +composer home, cache, and data directories. + ← [Libraries](02-libraries.md) | [Schema](04-schema.md) → diff --git a/doc/06-config.md b/doc/06-config.md index 2a86394e8..2980e1c31 100644 --- a/doc/06-config.md +++ b/doc/06-config.md @@ -265,4 +265,9 @@ Example: } ``` +## htaccess-protect + +Defaults to `true`. If set to `false`, Composer will not create `.htaccess` files +in the composer home, cache, and data directories. + ← [Repositories](05-repositories.md) | [Community](07-community.md) → diff --git a/res/composer-schema.json b/res/composer-schema.json index b21abf214..49929bdb8 100644 --- a/res/composer-schema.json +++ b/res/composer-schema.json @@ -274,6 +274,10 @@ "archive-dir": { "type": "string", "description": "The default archive path when not provided on cli, defaults to \".\"." + }, + "htaccess-protect": { + "type": "boolean", + "description": "Defaults to true. If set to false, Composer will not create .htaccess files in the composer home, cache, and data directories." } } }, diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php index 4d50f88da..1761402ee 100644 --- a/src/Composer/Command/ConfigCommand.php +++ b/src/Composer/Command/ConfigCommand.php @@ -402,6 +402,7 @@ EOT }, ), 'github-expose-hostname' => array($booleanValidator, $booleanNormalizer), + 'htaccess-protect' => array($booleanValidator, $booleanNormalizer), ); $multiConfigValues = array( 'github-protocols' => array( diff --git a/src/Composer/Config.php b/src/Composer/Config.php index d51fe6905..a7fca2988 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -60,6 +60,7 @@ class Config 'platform' => array(), 'archive-format' => 'tar', 'archive-dir' => '.', + 'htaccess-protect' => true, // valid keys without defaults (auth config stuff): // bitbucket-oauth // github-oauth @@ -215,6 +216,7 @@ class Config case 'cache-vcs-dir': case 'cafile': case 'capath': + case 'htaccess-protect': // convert foo-bar to COMPOSER_FOO_BAR and check if it exists since it overrides the local config $env = 'COMPOSER_' . strtoupper(strtr($key, '-', '_')); diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index a0ca79785..42be783c8 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -164,16 +164,19 @@ class Factory 'data-dir' => self::getDataDir($home), ))); - // Protect directory against web access. Since HOME could be - // the www-data's user home and be web-accessible it is a - // potential security risk - $dirs = array($config->get('home'), $config->get('cache-dir'), $config->get('data-dir')); - foreach ($dirs as $dir) { - if (!file_exists($dir . '/.htaccess')) { - if (!is_dir($dir)) { - Silencer::call('mkdir', $dir, 0777, true); + $htaccessProtect = (bool) $config->get('htaccess-protect'); + if ($htaccessProtect) { + // Protect directory against web access. Since HOME could be + // the www-data's user home and be web-accessible it is a + // potential security risk + $dirs = array($config->get('home'), $config->get('cache-dir'), $config->get('data-dir')); + foreach ($dirs as $dir) { + if (!file_exists($dir . '/.htaccess')) { + if (!is_dir($dir)) { + Silencer::call('mkdir', $dir, 0777, true); + } + Silencer::call('file_put_contents', $dir . '/.htaccess', 'Deny from all'); } - Silencer::call('file_put_contents', $dir . '/.htaccess', 'Deny from all'); } } diff --git a/tests/Composer/Test/ConfigTest.php b/tests/Composer/Test/ConfigTest.php index 79c124fc5..890ec19fb 100644 --- a/tests/Composer/Test/ConfigTest.php +++ b/tests/Composer/Test/ConfigTest.php @@ -310,4 +310,12 @@ class ConfigTest extends \PHPUnit_Framework_TestCase $this->assertEquals(0, $config->get('process-timeout')); putenv('COMPOSER_PROCESS_TIMEOUT'); } + + public function testHtaccessProtect() + { + putenv('COMPOSER_HTACCESS_PROTECT=0'); + $config = new Config(true); + $this->assertEquals(0, $config->get('htaccess-protect')); + putenv('COMPOSER_HTACCESS_PROTECT'); + } }