diff --git a/CHANGELOG.md b/CHANGELOG.md index 20d762567..8c75c6c17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,13 +22,17 @@ * Fixed calls to undefined `Media` methods, they will now return `null` in order to fix twig templates with undefined variables # v1.7.34 -## mm/dd/2022 +## 06/14/2022 1. [](#new) * Added back Yiddish to Language Codes [#3336](https://github.com/getgrav/grav/pull/3336) + * Ignore upcoming `media.json` file in media 1. [](#bugfix) * Regression: Fixed saving page with a new language causing cache corruption [getgrav/grav-plugin-admin#2282](https://github.com/getgrav/grav-plugin-admin/issues/2282) * Fixed a potential fatal error when using watermark in images + * Fixed `bin/grav install` command with arbitrary destination folder name + * Fixed Twig `|filter()` allowing code execution + * Fixed login and user search by email not being case-insensitive when using Flex Users # v1.7.33 ## 04/25/2022 diff --git a/composer.lock b/composer.lock index a4a06ee67..868e1da77 100644 --- a/composer.lock +++ b/composer.lock @@ -2004,23 +2004,23 @@ }, { "name": "rockettheme/toolbox", - "version": "1.6.1", + "version": "1.6.2", "source": { "type": "git", "url": "https://github.com/rockettheme/toolbox.git", - "reference": "fdf0195ced25b83525d3b084c3e81f05de96ac8c" + "reference": "99448a20a2f78d6480035d72821ecb9e4dc17032" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rockettheme/toolbox/zipball/fdf0195ced25b83525d3b084c3e81f05de96ac8c", - "reference": "fdf0195ced25b83525d3b084c3e81f05de96ac8c", + "url": "https://api.github.com/repos/rockettheme/toolbox/zipball/99448a20a2f78d6480035d72821ecb9e4dc17032", + "reference": "99448a20a2f78d6480035d72821ecb9e4dc17032", "shasum": "" }, "require": { "ext-json": "*", "php": ">=5.6.0", "pimple/pimple": "^3.0", - "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/event-dispatcher": "^3.4|^4.0", "symfony/yaml": "^3.4|^4.0|^5.0" }, "type": "library", @@ -2052,9 +2052,9 @@ ], "support": { "issues": "https://github.com/rockettheme/toolbox/issues", - "source": "https://github.com/rockettheme/toolbox/tree/1.6.1" + "source": "https://github.com/rockettheme/toolbox/tree/1.6.2" }, - "time": "2022-02-08T08:36:03+00:00" + "time": "2022-06-14T16:24:33+00:00" }, { "name": "seld/cli-prompt", @@ -4572,16 +4572,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.7.12", + "version": "1.7.14", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "32f10779d9cd88a9cbd972ec611a4148a3cbbc7e" + "reference": "e6f145f196a59c7ca91ea926c87ef3d936c4305f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/32f10779d9cd88a9cbd972ec611a4148a3cbbc7e", - "reference": "32f10779d9cd88a9cbd972ec611a4148a3cbbc7e", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e6f145f196a59c7ca91ea926c87ef3d936c4305f", + "reference": "e6f145f196a59c7ca91ea926c87ef3d936c4305f", "shasum": "" }, "require": { @@ -4607,7 +4607,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.7.12" + "source": "https://github.com/phpstan/phpstan/tree/1.7.14" }, "funding": [ { @@ -4627,7 +4627,7 @@ "type": "tidelift" } ], - "time": "2022-06-09T12:39:36+00:00" + "time": "2022-06-14T13:09:35+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", diff --git a/system/src/Grav/Common/Flex/Types/Users/UserIndex.php b/system/src/Grav/Common/Flex/Types/Users/UserIndex.php index 4a33b7304..aff6e1570 100644 --- a/system/src/Grav/Common/Flex/Types/Users/UserIndex.php +++ b/system/src/Grav/Common/Flex/Types/Users/UserIndex.php @@ -142,7 +142,7 @@ class UserIndex extends FlexIndex implements UserCollectionInterface } elseif ($field === 'flex_key') { $user = $this->withKeyField('flex_key')->get($query); } elseif ($field === 'email') { - $user = $this->withKeyField('email')->get($query); + $user = $this->withKeyField('email')->get(static::filterUsername($query, $this->getFlexDirectory()->getStorage())); } elseif ($field === 'username') { $user = $this->get(static::filterUsername($query, $this->getFlexDirectory()->getStorage())); } else { diff --git a/system/src/Grav/Common/GPM/GPM.php b/system/src/Grav/Common/GPM/GPM.php index 7031945b2..4ca84e3f0 100644 --- a/system/src/Grav/Common/GPM/GPM.php +++ b/system/src/Grav/Common/GPM/GPM.php @@ -12,6 +12,7 @@ namespace Grav\Common\GPM; use Exception; use Grav\Common\Grav; use Grav\Common\Filesystem\Folder; +use Grav\Common\HTTP\Response; use Grav\Common\Inflector; use Grav\Common\Iterator; use Grav\Common\Utils; diff --git a/system/src/Grav/Common/GPM/Remote/AbstractPackageCollection.php b/system/src/Grav/Common/GPM/Remote/AbstractPackageCollection.php index 02e98e759..d8663dc8d 100644 --- a/system/src/Grav/Common/GPM/Remote/AbstractPackageCollection.php +++ b/system/src/Grav/Common/GPM/Remote/AbstractPackageCollection.php @@ -10,8 +10,8 @@ namespace Grav\Common\GPM\Remote; use Grav\Common\Grav; +use Grav\Common\HTTP\Response; use Grav\Common\GPM\Common\AbstractPackageCollection as BaseCollection; -use Grav\Common\GPM\Response; use \Doctrine\Common\Cache\FilesystemCache; use RuntimeException; diff --git a/system/src/Grav/Common/Service/FlexServiceProvider.php b/system/src/Grav/Common/Service/FlexServiceProvider.php index e7b283ab0..21192926f 100644 --- a/system/src/Grav/Common/Service/FlexServiceProvider.php +++ b/system/src/Grav/Common/Service/FlexServiceProvider.php @@ -97,7 +97,9 @@ class FlexServiceProvider implements ServiceProviderInterface 'options' => [ 'file' => 'user', 'pattern' => '{FOLDER}/{KEY:2}/{KEY}/{FILE}{EXT}', - 'key' => 'storage_key' + 'key' => 'storage_key', + 'indexed' => true, + 'case_sensitive' => false ], ]; } @@ -107,7 +109,9 @@ class FlexServiceProvider implements ServiceProviderInterface 'class' => UserFileStorage::class, 'options' => [ 'pattern' => '{FOLDER}/{KEY}{EXT}', - 'key' => 'username' + 'key' => 'username', + 'indexed' => true, + 'case_sensitive' => false ], ]; } diff --git a/system/src/Grav/Common/Twig/Extension/GravExtension.php b/system/src/Grav/Common/Twig/Extension/GravExtension.php index 16affc41c..500c520d9 100644 --- a/system/src/Grav/Common/Twig/Extension/GravExtension.php +++ b/system/src/Grav/Common/Twig/Extension/GravExtension.php @@ -9,6 +9,7 @@ namespace Grav\Common\Twig\Extension; +use CallbackFilterIterator; use Cron\CronExpression; use Grav\Common\Config\Config; use Grav\Common\Data\Data; @@ -41,6 +42,7 @@ use JsonSerializable; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use Traversable; use Twig\Environment; +use Twig\Error\RuntimeError; use Twig\Extension\AbstractExtension; use Twig\Extension\GlobalsInterface; use Twig\Loader\FilesystemLoader; @@ -167,6 +169,9 @@ class GravExtension extends AbstractExtension implements GlobalsInterface // PHP methods new TwigFilter('count', 'count'), new TwigFilter('array_diff', 'array_diff'), + + // Security fix + new TwigFilter('filter', [$this, 'filterFilter'], ['needs_environment' => true]), ]; } @@ -1686,4 +1691,20 @@ class GravExtension extends AbstractExtension implements GlobalsInterface return is_string($var); } } + + /** + * @param Environment $env + * @param array $array + * @param callable|string $arrow + * @return array|CallbackFilterIterator + * @throws RuntimeError + */ + function filterFilter(Environment $env, $array, $arrow) + { + if (is_string($arrow) && Utils::isDangerousFunction($arrow)) { + throw new RuntimeError('Twig |filter("' . $arrow . '") is not allowed.'); + } + + return twig_array_filter($env, $array, $arrow); + } } diff --git a/system/src/Grav/Console/Cli/InstallCommand.php b/system/src/Grav/Console/Cli/InstallCommand.php index 33198cb5f..ae3825330 100644 --- a/system/src/Grav/Console/Cli/InstallCommand.php +++ b/system/src/Grav/Console/Cli/InstallCommand.php @@ -147,7 +147,7 @@ class InstallCommand extends GravCommand foreach ($this->config['git'] as $repo => $data) { $path = $this->destination . DS . $data['path']; if (!file_exists($path)) { - exec('cd "' . $this->destination . '" && git clone -b ' . $data['branch'] . ' --depth 1 ' . $data['url'] . ' ' . $data['path'], $output, $return); + exec('cd ' . escapeshellarg($this->destination) . ' && git clone -b ' . $data['branch'] . ' --depth 1 ' . $data['url'] . ' ' . $data['path'], $output, $return); if (!$return) { $io->writeln('SUCCESS cloned ' . $data['url'] . ' -> ' . $path . ''); diff --git a/system/src/Grav/Console/ConsoleTrait.php b/system/src/Grav/Console/ConsoleTrait.php index 0af4075ab..d35fc7cfe 100644 --- a/system/src/Grav/Console/ConsoleTrait.php +++ b/system/src/Grav/Console/ConsoleTrait.php @@ -288,7 +288,7 @@ trait ConsoleTrait { $composer = Composer::getComposerExecutor(); - return system($composer . ' --working-dir="'.$path.'" --no-interaction --no-dev --prefer-dist -o '. $action); + return system($composer . ' --working-dir=' . escapeshellarg($path) . ' --no-interaction --no-dev --prefer-dist -o '. $action); } /** diff --git a/system/src/Grav/Console/Gpm/DirectInstallCommand.php b/system/src/Grav/Console/Gpm/DirectInstallCommand.php index fbb02207c..881d6f950 100644 --- a/system/src/Grav/Console/Gpm/DirectInstallCommand.php +++ b/system/src/Grav/Console/Gpm/DirectInstallCommand.php @@ -10,12 +10,11 @@ namespace Grav\Console\Gpm; use Exception; -use Grav\Common\Cache; use Grav\Common\Grav; use Grav\Common\Filesystem\Folder; +use Grav\Common\HTTP\Response; use Grav\Common\GPM\GPM; use Grav\Common\GPM\Installer; -use Grav\Common\GPM\Response; use Grav\Console\GpmCommand; use RuntimeException; use Symfony\Component\Console\Input\InputArgument; diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index d25ebe3c5..5ad47f8d4 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -11,10 +11,10 @@ namespace Grav\Console\Gpm; use Exception; use Grav\Common\Filesystem\Folder; +use Grav\Common\HTTP\Response; use Grav\Common\GPM\GPM; use Grav\Common\GPM\Installer; use Grav\Common\GPM\Licenses; -use Grav\Common\GPM\Response; use Grav\Common\GPM\Remote\Package; use Grav\Common\Grav; use Grav\Common\Utils; @@ -485,7 +485,7 @@ class InstallCommand extends GpmCommand { $io = $this->getIO(); - exec('cd ' . $this->destination); + exec('cd ' . escapeshellarg($this->destination)); $to = $this->destination . DS . $package->install_path; $from = $this->getSymlinkSource($package); diff --git a/system/src/Grav/Console/Gpm/SelfupgradeCommand.php b/system/src/Grav/Console/Gpm/SelfupgradeCommand.php index a3d53ffee..30bc5f5ab 100644 --- a/system/src/Grav/Console/Gpm/SelfupgradeCommand.php +++ b/system/src/Grav/Console/Gpm/SelfupgradeCommand.php @@ -11,8 +11,8 @@ namespace Grav\Console\Gpm; use Exception; use Grav\Common\Filesystem\Folder; +use Grav\Common\HTTP\Response; use Grav\Common\GPM\Installer; -use Grav\Common\GPM\Response; use Grav\Common\GPM\Upgrader; use Grav\Common\Grav; use Grav\Console\GpmCommand; diff --git a/tests/phpstan/phpstan.neon b/tests/phpstan/phpstan.neon index 5f5cf5a74..d79cd6d2f 100644 --- a/tests/phpstan/phpstan.neon +++ b/tests/phpstan/phpstan.neon @@ -159,13 +159,20 @@ parameters: - '#Call to deprecated method stopPropagation\(\) of class Symfony\\Component\\EventDispatcher\\Event#' - '#Parameter \#2 \$listener of method Symfony\\Component\\EventDispatcher\\EventDispatcher::addListener\(\)#' - '#Parameter \#2 \$listener of method Symfony\\Component\\EventDispatcher\\EventDispatcher::removeListener\(\)#' + - '#Class Grav\\Common\\GPM\\Response not found#' # Installer updates - message: '#Variable \$this in PHPDoc tag @var does not exist#' path: '*/system/src/Grav/Installer/updates/*' + - + message: '#YamlUpdater::isInlineComment\(\) is unused#' + path: '*/system/src/Grav/Installer/YamlUpdater.php' # Twig Deferred extension compatibility - message: '#typehint with deprecated interface#' path: '*/system/src/Twig/DeferredExtension/DeferredNodeVisitorCompat.php' + - + message: '#Function twig_array_filter not found#' + path: '*/system/src/Grav/Common/Twig/Extension/GravExtension.php'