diff --git a/composer.lock b/composer.lock index 9ecaabd188fa470403ec0980a9f464fdbe25f271..a33732c64f2a7cdd110a2075464678ba1eb835f9 100644 --- a/composer.lock +++ b/composer.lock @@ -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": [ diff --git a/composer/Metapackage/CoreRecommended/composer.json b/composer/Metapackage/CoreRecommended/composer.json index 6d202741ca804b443bd3afb0c0da232ef9d0dc6f..78cbf42176ef67e9656d6312b473f123f7eb219e 100644 --- a/composer/Metapackage/CoreRecommended/composer.json +++ b/composer/Metapackage/CoreRecommended/composer.json @@ -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" } } diff --git a/core/composer.json b/core/composer.json index aef3c04fc576e842a33a9ce9961c93568c251725..f2f4f1749782e84cf9df5c716704e1b8a7ef9b86 100644 --- a/core/composer.json +++ b/core/composer.json @@ -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", diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index 40e49dcef9a33ee488d9bd24fb550b74814aa07c..485c3ce9e4a8390f84340ad13f9c9653dbff21cd 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -21,7 +21,6 @@ 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\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 @@ public function boot() { $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; diff --git a/core/lib/Drupal/Core/Security/PharExtensionInterceptor.php b/core/lib/Drupal/Core/Security/PharExtensionInterceptor.php deleted file mode 100644 index 8622dbb77a378e803c28fcd5fc56dce34e181e6b..0000000000000000000000000000000000000000 --- a/core/lib/Drupal/Core/Security/PharExtensionInterceptor.php +++ /dev/null @@ -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'; - } - -} diff --git a/core/tests/Drupal/KernelTests/Core/File/PharWrapperTest.php b/core/tests/Drupal/KernelTests/Core/File/PharWrapperTest.php deleted file mode 100644 index e528636ff530b05e60ba0f1ba18e9d98e2626998..0000000000000000000000000000000000000000 --- a/core/tests/Drupal/KernelTests/Core/File/PharWrapperTest.php +++ /dev/null @@ -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")); - } - } - -} diff --git a/core/tests/Drupal/KernelTests/Core/File/StreamWrapperTest.php b/core/tests/Drupal/KernelTests/Core/File/StreamWrapperTest.php index 43b999e93feddde0d61295e36e09518598190e00..3e0404183a7f2dabfb96d9cb03023cdbb3d5d59e 100644 --- a/core/tests/Drupal/KernelTests/Core/File/StreamWrapperTest.php +++ b/core/tests/Drupal/KernelTests/Core/File/StreamWrapperTest.php @@ -152,31 +152,4 @@ public function testGetValidStreamScheme() { $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()); - } - } diff --git a/core/tests/fixtures/files/phar-1.phar b/core/tests/fixtures/files/phar-1.phar deleted file mode 100644 index 8d25e6d4403979bf0fb37b7d10ff721bc804130d..0000000000000000000000000000000000000000 --- a/core/tests/fixtures/files/phar-1.phar +++ /dev/null @@ -1,301 +0,0 @@ -<?php - -$web = 'index.php'; - -if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { -Phar::interceptFileFuncs(); -set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path()); -Phar::webPhar(null, $web); -include 'phar://' . __FILE__ . '/' . Extract_Phar::START; -return; -} - -if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) { -Extract_Phar::go(true); -$mimes = array( -'phps' => 2, -'c' => 'text/plain', -'cc' => 'text/plain', -'cpp' => 'text/plain', -'c++' => 'text/plain', -'dtd' => 'text/plain', -'h' => 'text/plain', -'log' => 'text/plain', -'rng' => 'text/plain', -'txt' => 'text/plain', -'xsd' => 'text/plain', -'php' => 1, -'inc' => 1, -'avi' => 'video/avi', -'bmp' => 'image/bmp', -'css' => 'text/css', -'gif' => 'image/gif', -'htm' => 'text/html', -'html' => 'text/html', -'htmls' => 'text/html', -'ico' => 'image/x-ico', -'jpe' => 'image/jpeg', -'jpg' => 'image/jpeg', -'jpeg' => 'image/jpeg', -'js' => 'application/x-javascript', -'midi' => 'audio/midi', -'mid' => 'audio/midi', -'mod' => 'audio/mod', -'mov' => 'movie/quicktime', -'mp3' => 'audio/mp3', -'mpg' => 'video/mpeg', -'mpeg' => 'video/mpeg', -'pdf' => 'application/pdf', -'png' => 'image/png', -'swf' => 'application/shockwave-flash', -'tif' => 'image/tiff', -'tiff' => 'image/tiff', -'wav' => 'audio/wav', -'xbm' => 'image/xbm', -'xml' => 'text/xml', -); - -header("Cache-Control: no-cache, must-revalidate"); -header("Pragma: no-cache"); - -$basename = basename(__FILE__); -if (!strpos($_SERVER['REQUEST_URI'], $basename)) { -chdir(Extract_Phar::$temp); -include $web; -return; -} -$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename)); -if (!$pt || $pt == '/') { -$pt = $web; -header('HTTP/1.1 301 Moved Permanently'); -header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt); -exit; -} -$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt); -if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) { -header('HTTP/1.0 404 Not Found'); -echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File Not Found</h1>\n </body>\n</html>"; -exit; -} -$b = pathinfo($a); -if (!isset($b['extension'])) { -header('Content-Type: text/plain'); -header('Content-Length: ' . filesize($a)); -readfile($a); -exit; -} -if (isset($mimes[$b['extension']])) { -if ($mimes[$b['extension']] === 1) { -include $a; -exit; -} -if ($mimes[$b['extension']] === 2) { -highlight_file($a); -exit; -} -header('Content-Type: ' .$mimes[$b['extension']]); -header('Content-Length: ' . filesize($a)); -readfile($a); -exit; -} -} - -class Extract_Phar -{ -static $temp; -static $origdir; -const GZ = 0x1000; -const BZ2 = 0x2000; -const MASK = 0x3000; -const START = 'index.php'; -const LEN = 6643; - -static function go($return = false) -{ -$fp = fopen(__FILE__, 'rb'); -fseek($fp, self::LEN); -$L = unpack('V', $a = fread($fp, 4)); -$m = ''; - -do { -$read = 8192; -if ($L[1] - strlen($m) < 8192) { -$read = $L[1] - strlen($m); -} -$last = fread($fp, $read); -$m .= $last; -} while (strlen($last) && strlen($m) < $L[1]); - -if (strlen($m) < $L[1]) { -die('ERROR: manifest length read was "' . -strlen($m) .'" should be "' . -$L[1] . '"'); -} - -$info = self::_unpack($m); -$f = $info['c']; - -if ($f & self::GZ) { -if (!function_exists('gzinflate')) { -die('Error: zlib extension is not enabled -' . -' gzinflate() function needed for zlib-compressed .phars'); -} -} - -if ($f & self::BZ2) { -if (!function_exists('bzdecompress')) { -die('Error: bzip2 extension is not enabled -' . -' bzdecompress() function needed for bz2-compressed .phars'); -} -} - -$temp = self::tmpdir(); - -if (!$temp || !is_writable($temp)) { -$sessionpath = session_save_path(); -if (strpos ($sessionpath, ";") !== false) -$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1); -if (!file_exists($sessionpath) || !is_dir($sessionpath)) { -die('Could not locate temporary directory to extract phar'); -} -$temp = $sessionpath; -} - -$temp .= '/pharextract/'.basename(__FILE__, '.phar'); -self::$temp = $temp; -self::$origdir = getcwd(); -@mkdir($temp, 0777, true); -$temp = realpath($temp); - -if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) { -self::_removeTmpFiles($temp, getcwd()); -@mkdir($temp, 0777, true); -@file_put_contents($temp . '/' . md5_file(__FILE__), ''); - -foreach ($info['m'] as $path => $file) { -$a = !file_exists(dirname($temp . '/' . $path)); -@mkdir(dirname($temp . '/' . $path), 0777, true); -clearstatcache(); - -if ($path[strlen($path) - 1] == '/') { -@mkdir($temp . '/' . $path, 0777); -} else { -file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp)); -@chmod($temp . '/' . $path, 0666); -} -} -} - -chdir($temp); - -if (!$return) { -include self::START; -} -} - -static function tmpdir() -{ -if (strpos(PHP_OS, 'WIN') !== false) { -if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) { -return $var; -} -if (is_dir('/temp') || mkdir('/temp')) { -return realpath('/temp'); -} -return false; -} -if ($var = getenv('TMPDIR')) { -return $var; -} -return realpath('/tmp'); -} - -static function _unpack($m) -{ -$info = unpack('V', substr($m, 0, 4)); - $l = unpack('V', substr($m, 10, 4)); -$m = substr($m, 14 + $l[1]); -$s = unpack('V', substr($m, 0, 4)); -$o = 0; -$start = 4 + $s[1]; -$ret['c'] = 0; - -for ($i = 0; $i < $info[1]; $i++) { - $len = unpack('V', substr($m, $start, 4)); -$start += 4; - $savepath = substr($m, $start, $len[1]); -$start += $len[1]; - $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24))); -$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3] -& 0xffffffff); -$ret['m'][$savepath][7] = $o; -$o += $ret['m'][$savepath][2]; -$start += 24 + $ret['m'][$savepath][5]; -$ret['c'] |= $ret['m'][$savepath][4] & self::MASK; -} -return $ret; -} - -static function extractFile($path, $entry, $fp) -{ -$data = ''; -$c = $entry[2]; - -while ($c) { -if ($c < 8192) { -$data .= @fread($fp, $c); -$c = 0; -} else { -$c -= 8192; -$data .= @fread($fp, 8192); -} -} - -if ($entry[4] & self::GZ) { -$data = gzinflate($data); -} elseif ($entry[4] & self::BZ2) { -$data = bzdecompress($data); -} - -if (strlen($data) != $entry[0]) { -die("Invalid internal .phar file (size error " . strlen($data) . " != " . -$stat[7] . ")"); -} - -if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) { -die("Invalid internal .phar file (checksum error)"); -} - -return $data; -} - -static function _removeTmpFiles($temp, $origdir) -{ -chdir($temp); - -foreach (glob('*') as $f) { -if (file_exists($f)) { -is_dir($f) ? @rmdir($f) : @unlink($f); -if (file_exists($f) && is_dir($f)) { -self::_removeTmpFiles($f, getcwd()); -} -} -} - -@rmdir($temp); -clearstatcache(); -chdir($origdir); -} -} - -Extract_Phar::go(); -__HALT_COMPILER(); ?>7������������������ ���index.phpµ���8!¾[µ���u‰¾¶������<?php -/** - * @file - * This test file is used to test Drupal's phar stream wrapper functionality. - * - * @see \Drupal\KernelTests\Core\File\PharWrapperTest - */ - -echo 'Hello, world!'; -å1qV«5õ['áyß R£CØA���GBMB \ No newline at end of file