Issue #3210486 by Spokje, longwave, andypost, alexpott: Remove typo3/phar-stream-wrapper and associated code

merge-requests/1721/head
catch 2022-01-26 08:51:43 +00:00
parent ca3ce56a2d
commit 9f5c2e9907
8 changed files with 3 additions and 238 deletions

60
composer.lock generated
View File

@ -448,7 +448,7 @@
"dist": {
"type": "path",
"url": "core",
"reference": "eefc18dedeaf145e81deed18c914b87cc2c62bd8"
"reference": "f6e86b91c8d470e57aa22b05e003a389d43a0813"
},
"require": {
"asm89/stack-cors": "^2.0.2",
@ -489,8 +489,7 @@
"symfony/serializer": "^5.4",
"symfony/validator": "^5.4",
"symfony/yaml": "^5.4",
"twig/twig": "^3.0",
"typo3/phar-stream-wrapper": "^3.1.3"
"twig/twig": "^3.0"
},
"conflict": {
"drush/drush": "<8.1.10"
@ -4468,61 +4467,6 @@
}
],
"time": "2022-01-03T21:15:37+00:00"
},
{
"name": "typo3/phar-stream-wrapper",
"version": "v3.1.7",
"source": {
"type": "git",
"url": "https://github.com/TYPO3/phar-stream-wrapper.git",
"reference": "5cc2f04a4e2f5c7e9cc02a3bdf80fae0f3e11a8c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/TYPO3/phar-stream-wrapper/zipball/5cc2f04a4e2f5c7e9cc02a3bdf80fae0f3e11a8c",
"reference": "5cc2f04a4e2f5c7e9cc02a3bdf80fae0f3e11a8c",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": "^7.0 || ^8.0"
},
"require-dev": {
"ext-xdebug": "*",
"phpspec/prophecy": "^1.10",
"symfony/phpunit-bridge": "^5.1"
},
"suggest": {
"ext-fileinfo": "For PHP builtin file type guessing, otherwise uses internal processing"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "v3.x-dev"
}
},
"autoload": {
"psr-4": {
"TYPO3\\PharStreamWrapper\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Interceptors for PHP's native phar:// stream handling",
"homepage": "https://typo3.org/",
"keywords": [
"phar",
"php",
"security",
"stream-wrapper"
],
"support": {
"issues": "https://github.com/TYPO3/phar-stream-wrapper/issues",
"source": "https://github.com/TYPO3/phar-stream-wrapper/tree/v3.1.7"
},
"time": "2021-09-20T19:19:13+00:00"
}
],
"packages-dev": [

View File

@ -60,7 +60,6 @@
"symfony/validator": "v5.4.2",
"symfony/var-dumper": "v5.4.2",
"symfony/yaml": "v5.4.2",
"twig/twig": "v3.3.7",
"typo3/phar-stream-wrapper": "v3.1.7"
"twig/twig": "v3.3.7"
}
}

View File

@ -31,7 +31,6 @@
"symfony/polyfill-iconv": "^1.0",
"symfony/polyfill-php80": "^1.16",
"symfony/yaml": "^5.4",
"typo3/phar-stream-wrapper": "^3.1.3",
"twig/twig": "^3.0",
"doctrine/annotations": "^1.12",
"guzzlehttp/guzzle": "^7.3.0",

View File

@ -21,7 +21,6 @@ use Drupal\Core\Http\TrustedHostsRequestFactory;
use Drupal\Core\Installer\InstallerKernel;
use Drupal\Core\Installer\InstallerRedirectTrait;
use Drupal\Core\Language\Language;
use Drupal\Core\Security\PharExtensionInterceptor;
use Drupal\Core\Security\RequestSanitizer;
use Drupal\Core\Site\Settings;
use Drupal\Core\Test\TestDatabase;
@ -33,9 +32,6 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpKernel\TerminableInterface;
use TYPO3\PharStreamWrapper\Manager as PharStreamWrapperManager;
use TYPO3\PharStreamWrapper\Behavior as PharStreamWrapperBehavior;
use TYPO3\PharStreamWrapper\PharStreamWrapper;
/**
* The DrupalKernel class is the core of Drupal itself.
@ -479,27 +475,6 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
$this->classLoader->setApcuPrefix($prefix);
}
// @todo clean-up for PHP 8.0+ https://www.drupal.org/node/3210486
if (PHP_VERSION_ID < 80000 && in_array('phar', stream_get_wrappers(), TRUE)) {
// Set up a stream wrapper to handle insecurities due to PHP's builtin
// phar stream wrapper. This is not registered as a regular stream wrapper
// to prevent \Drupal\Core\File\FileSystem::validScheme() treating "phar"
// as a valid scheme.
try {
$behavior = new PharStreamWrapperBehavior();
PharStreamWrapperManager::initialize(
$behavior->withAssertion(new PharExtensionInterceptor())
);
}
catch (\LogicException $e) {
// Continue if the PharStreamWrapperManager is already initialized. For
// example, this occurs during a module install.
// @see \Drupal\Core\Extension\ModuleInstaller::install()
}
stream_wrapper_unregister('phar');
stream_wrapper_register('phar', PharStreamWrapper::class);
}
$this->booted = TRUE;
return $this;

View File

@ -1,85 +0,0 @@
<?php
namespace Drupal\Core\Security;
use TYPO3\PharStreamWrapper\Assertable;
use TYPO3\PharStreamWrapper\Helper;
use TYPO3\PharStreamWrapper\Exception;
/**
* An alternate PharExtensionInterceptor to support phar-based CLI tools.
*
* @internal
*
* @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. No replacement
* is provided.
*
* @see https://www.drupal.org/project/drupal/issues/3252439
* @see \TYPO3\PharStreamWrapper\Interceptor\PharExtensionInterceptor
*/
class PharExtensionInterceptor implements Assertable {
/**
* Determines whether phar file is allowed to execute.
*
* The phar file is allowed to execute if:
* - the base file name has a ".phar" suffix.
* - it is the CLI tool that has invoked the interceptor.
*
* @param string $path
* The path of the phar file to check.
* @param string $command
* The command being carried out.
*
* @return bool
* TRUE if the phar file is allowed to execute.
*
* @throws \TYPO3\PharStreamWrapper\Exception
* Thrown when the file is not allowed to execute.
*/
public function assert(string $path, string $command): bool {
if ($this->baseFileContainsPharExtension($path)) {
return TRUE;
}
throw new Exception(
sprintf(
'Unexpected file extension in "%s"',
$path
),
1535198703
);
}
/**
* Determines if a path has a .phar extension or invoked execution.
*
* @param string $path
* The path of the phar file to check.
*
* @return bool
* TRUE if the file has a .phar extension or if the execution has been
* invoked by the phar file.
*/
private function baseFileContainsPharExtension($path) {
$baseFile = Helper::determineBaseFile($path);
if ($baseFile === NULL) {
return FALSE;
}
// If the stream wrapper is registered by invoking a phar file that does
// not have .phar extension then this should be allowed. For example, some
// CLI tools recommend removing the extension.
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// Find the last entry in the backtrace containing a 'file' key as
// sometimes the last caller is executed outside the scope of a file. For
// example, this occurs with shutdown functions.
do {
$caller = array_pop($backtrace);
} while (empty($caller['file']) && !empty($backtrace));
if (isset($caller['file']) && $baseFile === Helper::determineBaseFile($caller['file'])) {
return TRUE;
}
$fileExtension = pathinfo($baseFile, PATHINFO_EXTENSION);
return strtolower($fileExtension) === 'phar';
}
}

View File

@ -1,40 +0,0 @@
<?php
namespace Drupal\KernelTests\Core\File;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests that the phar stream wrapper works.
*
* @group File
*/
class PharWrapperTest extends KernelTestBase {
/**
* Tests that only valid phar files can be used.
*/
public function testPharFile() {
$base = $this->getDrupalRoot() . '/core/tests/fixtures/files';
// Ensure that file operations via the phar:// stream wrapper work for phar
// files with the .phar extension.
$this->assertFileDoesNotExist("phar://$base/phar-1.phar/no-such-file.php");
$this->assertFileExists("phar://$base/phar-1.phar/index.php");
$file_contents = file_get_contents("phar://$base/phar-1.phar/index.php");
$expected_hash = 'c7e7904ea573c5ebea3ef00bb08c1f86af1a45961fbfbeb1892ff4a98fd73ad5';
$this->assertSame($expected_hash, hash('sha256', $file_contents));
// @todo clean-up for PHP 8.0+ https://www.drupal.org/node/3210486
if (PHP_VERSION_ID < 80000) {
// Ensure that file operations via the phar:// stream wrapper throw an
// exception for files without the .phar extension.
$this->expectException('TYPO3\PharStreamWrapper\Exception');
file_exists("phar://$base/image-2.jpg/index.php");
}
else {
// PHP 8 fixed via https://wiki.php.net/rfc/phar_stop_autoloading_metadata
$this->assertFalse(file_exists("phar://$base/image-2.jpg/index.php"));
}
}
}

View File

@ -152,31 +152,4 @@ class StreamWrapperTest extends FileTestBase {
$this->assertFalse($stream_wrapper_manager->isValidScheme($stream_wrapper_manager::getScheme('foo://asdf')), 'Did not get a valid stream scheme from foo://asdf');
}
/**
* Tests that phar stream wrapper is registered as expected.
*
* @see \Drupal\Core\StreamWrapper\StreamWrapperManager::register()
*/
public function testPharStreamWrapperRegistration() {
if (!in_array('phar', stream_get_wrappers(), TRUE)) {
$this->markTestSkipped('There is no phar stream wrapper registered. PHP is probably compiled without phar support.');
}
// Ensure that phar is not treated as a valid scheme.
$stream_wrapper_manager = $this->container->get('stream_wrapper_manager');
$this->assertFalse($stream_wrapper_manager->getViaScheme('phar'));
// Ensure that calling register again and unregister do not create errors
// due to the PharStreamWrapperManager singleton.
$stream_wrapper_manager->register();
$this->assertContains('public', stream_get_wrappers());
$this->assertContains('phar', stream_get_wrappers());
$stream_wrapper_manager->unregister();
$this->assertNotContains('public', stream_get_wrappers());
// This will have reverted to the builtin phar stream wrapper.
$this->assertContains('phar', stream_get_wrappers());
$stream_wrapper_manager->register();
$this->assertContains('public', stream_get_wrappers());
$this->assertContains('phar', stream_get_wrappers());
}
}

Binary file not shown.