This commit is contained in:
Bachir Soussi Chiadmi 2023-09-19 12:50:55 +02:00
parent 131ffd7020
commit adc7d775dc
47 changed files with 757 additions and 401 deletions

View File

@ -1,3 +1,115 @@
# v1.7.42.3
## 07/18/2023
2. [](#improved)
* Fixed a typo in `Utils::isDangerousFunction`
# v1.7.42.2
## 07/18/2023
2. [](#improved)
* In `Utils::isDangerousFunction`, handle double `\\` in `|map` twig filter to mitigate SSTI attack
* Better handle empty email in `Validatoin::typeEmail()`
# v1.7.42.1
## 06/15/2023
2. [](#improved)
* Quick fix for `isDangerousFunction` when `$name` was a closure [#3727](https://github.com/getgrav/grav/issues/3727)
# v1.7.42
## 06/14/2023
1. [](#new)
* Added a new `system.languages.debug` option that adds a `<span class="translate-debug"></span>` around strings translated with `|t`. This can be styled by the theme as needed.
1. [](#improved)
* More robust SSTI handling in `filter`, `map`, and `reduce` Twig filters and functions
* Various SSTI improvements `Utils::isDangerousFunction()`
1. [](#bugfix)
* Fixed Twig `|map()` allowing code execution
* Fixed Twig `|reduce()` allowing code execution
# v1.7.41.2
## 06/01/2023
1. [](#improved)
* Added the ability to set a configurable 'key' for the Twig Cache Tag: `{% cache 'my-key' 600 %}`
1. [](#bugfix)
* Fixed an issue with special characters in slug's would cause redirect loops
# v1.7.41.1
## 05/10/2023
1. [](#bugfix)
* Fixed certain UTF-8 characters breaking `Truncator` class [#3716](https://github.com/getgrav/grav/issues/3716)
# v1.7.41
## 05/09/2023
1. [](#improved)
* Removed `FILTER_SANITIZE_STRING` input filter in favor of `htmlspecialchars(strip_tags())` for PHP 8.2+
* Added `GRAV_SANITIZE_STRING` constant to replace `FILTER_SANITIZE_STRING` for PHP 8.2+
* Support non-deprecated style dynamic properties in `Parsedown` class via `ParseDownGravTrait` for PHP 8.2+
* Modified `Truncator` to not use deprecated `mb_convert_encoding()` for PHP 8.2+
* Fixed passing null into `mb_strpos()` deprecated for PHP 8.2+
* Updated internal `TwigDeferredExtension` to be PHP 8.2+ compatible
* Upgraded `getgrav/image` fork to take advantage of various PHP 8.2+ fixes
* Use `UserGroupObject::groupNames` method in blueprints for PHP 8.2+
* Comment out `files-upload` deprecated message as this is not going to be removed
* Added various public `Twig` class variables used by admin to address deprecated messages for PHP 8.2+
* Added `parse_url` to list of PHP functions supported in Twig Extension
* Added support for dynamic functions in `Parsedown` to stop deprecation messages in PHP 8.2+
# v1.7.40
## 03/22/2023
1. [](#new)
* Added a new `timestamp: true|false` option for individual assets
1. [](#improved)
* Removed outdated `xcache` setting [#3615](https://github.com/getgrav/grav/pull/3615)
* Updated `robots.txt` [#3625](https://github.com/getgrav/grav/pull/3625)
1. [](#bugfix)
* Fixed `force_ssl` redirect in case of undefined hostname [#3702](https://github.com/getgrav/grav/pull/3702)
* Fixed an issue with duplicate identical page paths
* Fixed `BlueprintSchema:flattenData` to properly handle ignored fields
* Fixed LogViewer regex greediness [#3684](https://github.com/getgrav/grav/pull/3684)
* Fixed `whoami` command [#3695](https://github.com/getgrav/grav/pull/3695)
# v1.7.39.4
## 02/22/2023
1. [](#bugfix)
* Reverted a reorganization of `account.yaml` that caused username to be disabled [admin#2344](https://github.com/getgrav/grav-plugin-admin/issues/2344)
# v1.7.39.3
## 02/21/2023
1. [](#bugfix)
* Fix for overzealous modular page template rendering fix in 1.7.39 causing Feed plugin to break [#3689](https://github.com/getgrav/grav/issues/3689)
# v1.7.39.2
## 02/20/2023
1. [](#bugfix)
* Fix for invalid session breaking Flex Accounts (when switching from Regular to Flex)
# v1.7.39.1
## 02/20/2023
1. [](#bugfix)
* Fix for broken image CSS with the latest version of DebugBar
# v1.7.39
## 02/19/2023
1. [](#improved)
* Vendor library updates to latest versions
1. [](#bugfix)
* Various PHP 8.2 fixes
* Fixed an issue with modular pages rendering thew wrong template when dynamically changing the page
* Fixed an issue with `email` validation that was failing on UTF-8 characters. Following best practices and now only check for `@` and length.
* Fixed PHPUnit tests to remove deprecation warnings
# v1.7.38
## 01/02/2023
@ -7,7 +119,6 @@
* Vendor library updates to latest versions
* Updated `bin/composer.phar` to latest `2.4.4` version [#3627](https://github.com/getgrav/grav/issues/3627)
1. [](#bugfix)
* Don't fail hard if pages recurse with same path
* Github workflows security hardening [#3624](https://github.com/getgrav/grav/pull/3624)

510
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -14,11 +14,8 @@ div.phpdebugbar {
padding: 5px 8px;
}
.phpdebugbar div.phpdebugbar-header, .phpdebugbar a.phpdebugbar-restore-btn {
background-image: url(data:image/png;base64,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);
}
.phpdebugbar a.phpdebugbar-restore-btn {
background-image: url(data:image/png;base64,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);
width: 13px;
}

View File

@ -448,6 +448,17 @@ form:
validate:
type: bool
languages.debug:
type: toggle
label: PLUGIN_ADMIN.LANGUAGE_DEBUG
help: PLUGIN_ADMIN.LANGUAGE_DEBUG_HELP
highlight: 0
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
http_headers:
type: tab
title: PLUGIN_ADMIN.HTTP_HEADERS
@ -608,7 +619,6 @@ form:
file: File
apc: APC
apcu: APCu
xcache: Xcache
memcache: Memcache
memcached: Memcached
wincache: WinCache

View File

@ -140,7 +140,7 @@ form:
multiple: true
size: large
label: PLUGIN_ADMIN.GROUPS
data-options@: '\Grav\Common\User\Group::groupNames'
data-options@: 'Grav\Common\Flex\Types\UserGroups\UserGroupObject::groupNames'
classes: fancy
help: PLUGIN_ADMIN.GROUPS_HELP
validate:

View File

@ -28,6 +28,7 @@ languages:
override_locale: false # Override the default or system locale with language specific one
content_fallback: {} # Custom language fallbacks. eg: {fr: ['fr', 'en']}
pages_fallback_only: false # DEPRECATED: Use `content_fallback` instead
debug: false # Debug language detection
home:
alias: '/home' # Default path for home, ie /

View File

@ -9,7 +9,7 @@
// Some standard defines
define('GRAV', true);
define('GRAV_VERSION', '1.7.38');
define('GRAV_VERSION', '1.7.42.3');
define('GRAV_SCHEMA', '1.7.0_2020-11-20_1');
define('GRAV_TESTING', false);
@ -99,3 +99,6 @@ define('RAW_CONTENT', 1);
define('TWIG_CONTENT', 2);
define('TWIG_CONTENT_LIST', 3);
define('TWIG_TEMPLATES', 4);
// Filters
define('GRAV_SANITIZE_STRING', 5001);

View File

@ -268,7 +268,13 @@ class Assets extends PropertyObject
}
// Add timestamp
$options['timestamp'] = $this->timestamp;
$timestamp_override = $options['timestamp'] ?? true;
if (filter_var($timestamp_override, FILTER_VALIDATE_BOOLEAN)) {
$options['timestamp'] = $this->timestamp;
} else {
$options['timestamp'] = null;
}
// Set order
$group = $options['group'] ?? 'head';

View File

@ -192,6 +192,7 @@ trait AssetUtilsTrait
$querystring = '';
$asset = $asset ?? $this->asset;
$attributes = $this->attributes;
if (!empty($this->query)) {
if (Utils::contains($asset, '?')) {

View File

@ -129,7 +129,8 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
$items = $name !== '' ? $this->getProperty($name)['fields'] ?? [] : $this->items;
foreach ($items as $key => $rules) {
$type = $rules['type'] ?? '';
if (!str_starts_with($type, '_') && !str_contains($key, '*')) {
$ignore = (bool) array_filter((array)($rules['validate']['ignore'] ?? [])) ?? false;
if (!str_starts_with($type, '_') && !str_contains($key, '*') && $ignore !== true) {
$list[$prefix . $key] = null;
}
}

View File

@ -631,6 +631,10 @@ class Validation
*/
public static function typeEmail($value, array $params, array $field)
{
if (empty($value)) {
return false;
}
if (!isset($params['max'])) {
$params['max'] = 320;
}
@ -638,7 +642,7 @@ class Validation
$values = !is_array($value) ? explode(',', preg_replace('/\s+/', '', $value)) : $value;
foreach ($values as $val) {
if (!(self::typeText($val, $params, $field) && filter_var($val, FILTER_VALIDATE_EMAIL))) {
if (!(self::typeText($val, $params, $field) && strpos($val, '@', 1))) {
return false;
}
}

View File

@ -57,7 +57,7 @@ class SimplePageHandler extends Handler
$vars = array(
'stylesheet' => file_get_contents($cssFile),
'code' => $code,
'message' => filter_var(rawurldecode($message), FILTER_SANITIZE_STRING),
'message' => htmlspecialchars(strip_tags(rawurldecode($message)), ENT_QUOTES, 'UTF-8'),
);
$helper->setVariables($vars);

View File

@ -12,6 +12,7 @@ declare(strict_types=1);
namespace Grav\Common\Flex\Types\UserGroups;
use Grav\Common\Flex\FlexObject;
use Grav\Common\Grav;
use Grav\Common\User\Access;
use Grav\Common\User\Interfaces\UserGroupInterface;
use function is_bool;
@ -74,6 +75,18 @@ class UserGroupObject extends FlexObject implements UserGroupInterface
return $access->authorize('admin.super') ? true : null;
}
public static function groupNames(): array
{
$groups = [];
$user_groups = Grav::instance()['user_groups'];
foreach ($user_groups as $key => $group) {
$groups[$key] = $group->readableName;
}
return $groups;
}
/**
* @return Access
*/

View File

@ -21,7 +21,7 @@ use function is_string;
class LogViewer
{
/** @var string */
protected $pattern = '/\[(?P<date>.*)\] (?P<logger>\w+).(?P<level>\w+): (?P<message>.*[^ ]+) (?P<context>[^ ]+) (?P<extra>[^ ]+)/';
protected $pattern = '/\[(?P<date>.*?)\] (?P<logger>\w+)\.(?P<level>\w+): (?P<message>.*[^ ]+) (?P<context>[^ ]+) (?P<extra>[^ ]+)/';
/**
* Get the objects of a tailed file

View File

@ -144,7 +144,7 @@ class Truncator
}
// Transform multibyte entities which otherwise display incorrectly.
$html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');
$html = mb_encode_numericentity($html, [0x80, 0x10FFFF, 0, ~0], 'UTF-8');
// Internal errors enabled as HTML5 not fully supported.
libxml_use_internal_errors(true);

View File

@ -18,6 +18,7 @@ use Grav\Common\Page\Markdown\Excerpts;
*/
class Parsedown extends \Parsedown
{
use ParsedownGravTrait;
/**

View File

@ -25,6 +25,7 @@ trait ParsedownGravTrait
public $completable_blocks = [];
/** @var array */
public $continuable_blocks = [];
public $plugins = [];
/** @var Excerpts */
protected $excerpts;
@ -292,7 +293,12 @@ trait ParsedownGravTrait
#[\ReturnTypeWillChange]
public function __call($method, $args)
{
if (isset($this->{$method}) === true) {
if (isset($this->plugins[$method]) === true) {
$func = $this->plugins[$method];
return call_user_func_array($func, $args);
} elseif (isset($this->{$method}) === true) {
$func = $this->{$method};
return call_user_func_array($func, $args);
@ -300,4 +306,14 @@ trait ParsedownGravTrait
return null;
}
public function __set($name, $value)
{
if (is_callable($value)) {
$this->plugins[$name] = $value;
}
}
}

View File

@ -62,8 +62,8 @@ class ImageMedium extends Medium implements ImageMediaInterface, ImageManipulate
if (!($this->offsetExists('width') && $this->offsetExists('height') && $this->offsetExists('mime'))) {
$image_info = getimagesize($path);
if ($image_info) {
$this->def('width', $image_info[0]);
$this->def('height', $image_info[1]);
$this->def('width', (int) $image_info[0]);
$this->def('height', (int) $image_info[1]);
$this->def('mime', $image_info['mime']);
}
}
@ -299,7 +299,7 @@ class ImageMedium extends Medium implements ImageMediaInterface, ImageManipulate
}
if ($width && $height) {
$this->__call('cropResize', [$width, $height]);
$this->__call('cropResize', [(int) $width, (int) $height]);
}
return parent::lightbox($width, $height, $reset);
@ -361,8 +361,8 @@ class ImageMedium extends Medium implements ImageMediaInterface, ImageManipulate
// Scaling operations
$scale = ($scale ?? $config->get('system.images.watermark.scale', 100)) / 100;
$wwidth = (int)$this->get('width') * $scale;
$wheight = (int)$this->get('height') * $scale;
$wwidth = (int) ($this->get('width') * $scale);
$wheight = (int) ($this->get('height') * $scale);
$watermark->resize($wwidth, $wheight);
// Position operations
@ -392,11 +392,11 @@ class ImageMedium extends Medium implements ImageMediaInterface, ImageManipulate
break;
case 'right':
$positionX = (int)$this->get('width')-$wwidth;
$positionX = (int) ($this->get('width')-$wwidth);
break;
case 'center':
$positionX = ((int)$this->get('width')/2) - ($wwidth/2);
$positionX = (int) (($this->get('width')/2) - ($wwidth/2));
break;
}
@ -431,8 +431,8 @@ class ImageMedium extends Medium implements ImageMediaInterface, ImageManipulate
return $this;
}
$dst_width = $image->width()+2*$border;
$dst_height = $image->height()+2*$border;
$dst_width = (int) ($image->width()+2*$border);
$dst_height = (int) ($image->height()+2*$border);
$frame = ImageFile::create($dst_width, $dst_height);

View File

@ -1270,9 +1270,14 @@ class Page implements PageInterface
*/
public function blueprintName()
{
$blueprint_name = filter_input(INPUT_POST, 'blueprint', FILTER_SANITIZE_STRING) ?: $this->template();
if (!isset($_POST['blueprint'])) {
return $this->template();
}
return $blueprint_name;
$post_value = $_POST['blueprint'];
$sanitized_value = htmlspecialchars(strip_tags($post_value), ENT_QUOTES, 'UTF-8');
return $sanitized_value ?: $this->template();
}
/**
@ -1802,7 +1807,7 @@ class Page implements PageInterface
}
if (empty($this->slug)) {
$this->slug = $this->adjustRouteCase(preg_replace(PAGE_ORDER_PREFIX_REGEX, '', $this->folder)) ?: null;
$this->slug = $this->adjustRouteCase(preg_replace(PAGE_ORDER_PREFIX_REGEX, '', (string) $this->folder)) ?: null;
}
return $this->slug;

View File

@ -26,6 +26,7 @@ use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\Taxonomy;
use Grav\Common\Uri;
use Grav\Common\Utils;
use Grav\Events\TypesEvent;
use Grav\Framework\Flex\Flex;
use Grav\Framework\Flex\FlexDirectory;
use Grav\Framework\Flex\Interfaces\FlexTranslateInterface;
@ -1289,7 +1290,7 @@ class Pages
$scanBlueprintsAndTemplates = static function (Types $types) use ($grav) {
// Scan blueprints
$event = new Event();
$event = new TypesEvent();
$event->types = $types;
$grav->fireEvent('onGetPageBlueprints', $event);
@ -1303,7 +1304,7 @@ class Pages
$types->scanBlueprints($lookup);
// Scan templates
$event = new Event();
$event = new TypesEvent();
$event->types = $types;
$grav->fireEvent('onGetPageTemplates', $event);
@ -1773,7 +1774,7 @@ class Pages
$dirs = (array) $grav['config']->get('system.pages.dirs', ['page://']);
foreach ($dirs as $dir) {
$path = $locator->findResource($dir);
if (file_exists($path)) {
if (file_exists($path) && !in_array($path, $paths, true)) {
$paths[] = $path;
}
}

View File

@ -10,6 +10,7 @@
namespace Grav\Common\Processors;
use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Events\PageEvent;
use Grav\Framework\RequestHandler\Exception\RequestException;
use Grav\Plugin\Form\Forms;
use RocketTheme\Toolbox\Event\Event;
@ -66,7 +67,7 @@ class PagesProcessor extends ProcessorBase
if (!$page->routable()) {
$exception = new RequestException($request, 'Page Not Found', 404);
// If no page found, fire event
$event = new Event([
$event = new PageEvent([
'page' => $page,
'code' => $exception->getCode(),
'message' => $exception->getMessage(),

View File

@ -357,7 +357,7 @@ class Scheduler
*/
public function whoami()
{
$process = new Process('whoami');
$process = new Process(['whoami']);
$process->run();
if ($process->isSuccessful()) {

View File

@ -59,7 +59,7 @@ class PagesServiceProvider implements ServiceProviderInterface
/** @var Uri $uri */
$uri = $grav['uri'];
$path = $uri->path() ?: '/'; // Don't trim to support trailing slash default routes
$path = $uri->path() ? urldecode($uri->path()) : '/'; // Don't trim to support trailing slash default routes
$page = $pages->dispatch($path);
// Redirection tests
@ -72,7 +72,7 @@ class PagesServiceProvider implements ServiceProviderInterface
if ($config->get('system.force_ssl')) {
$scheme = $uri->scheme(true);
if ($scheme !== 'https') {
$url = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$url = 'https://' . $uri->host() . $uri->uri();
$grav->redirect($url);
}
}

View File

@ -33,7 +33,7 @@ class TaskServiceProvider implements ServiceProviderInterface
$task = $body['task'] ?? $c['uri']->param('task');
if (null !== $task) {
$task = filter_var($task, FILTER_SANITIZE_STRING);
$task = htmlspecialchars(strip_tags($task), ENT_QUOTES, 'UTF-8');
}
return $task ?: null;
@ -46,7 +46,7 @@ class TaskServiceProvider implements ServiceProviderInterface
$action = $body['action'] ?? $c['uri']->param('action');
if (null !== $action) {
$action = filter_var($action, FILTER_SANITIZE_STRING);
$action = htmlspecialchars(strip_tags($action), ENT_QUOTES, 'UTF-8');
}
return $action ?: null;

View File

@ -122,10 +122,10 @@ class Session extends \Grav\Framework\Session\Session
// Make sure that Forms 3.0+ has been installed.
if (null === $object && isset($grav['forms'])) {
user_error(
__CLASS__ . '::' . __FUNCTION__ . '(\'files-upload\') is deprecated since Grav 1.6, use $form->getFlash()->getLegacyFiles() instead',
E_USER_DEPRECATED
);
// user_error(
// __CLASS__ . '::' . __FUNCTION__ . '(\'files-upload\') is deprecated since Grav 1.6, use $form->getFlash()->getLegacyFiles() instead',
// E_USER_DEPRECATED
// );
/** @var Uri $uri */
$uri = $grav['uri'];

View File

@ -46,6 +46,7 @@ use Twig\Error\RuntimeError;
use Twig\Extension\AbstractExtension;
use Twig\Extension\GlobalsInterface;
use Twig\Loader\FilesystemLoader;
use Twig\Markup;
use Twig\TwigFilter;
use Twig\TwigFunction;
use function array_slice;
@ -170,8 +171,10 @@ class GravExtension extends AbstractExtension implements GlobalsInterface
new TwigFilter('count', 'count'),
new TwigFilter('array_diff', 'array_diff'),
// Security fix
new TwigFilter('filter', [$this, 'filterFilter'], ['needs_environment' => true]),
// Security fixes
new TwigFilter('filter', [$this, 'filterFunc'], ['needs_environment' => true]),
new TwigFilter('map', [$this, 'mapFunc'], ['needs_environment' => true]),
new TwigFilter('reduce', [$this, 'reduceFunc'], ['needs_environment' => true]),
];
}
@ -247,6 +250,12 @@ class GravExtension extends AbstractExtension implements GlobalsInterface
new TwigFunction('is_object', 'is_object'),
new TwigFunction('count', 'count'),
new TwigFunction('array_diff', 'array_diff'),
new TwigFunction('parse_url', 'parse_url'),
// Security fixes
new TwigFunction('filter', [$this, 'filterFunc'], ['needs_environment' => true]),
new TwigFunction('map', [$this, 'mapFunc'], ['needs_environment' => true]),
new TwigFunction('reduce', [$this, 'reduceFunc'], ['needs_environment' => true]),
];
}
@ -468,7 +477,7 @@ class GravExtension extends AbstractExtension implements GlobalsInterface
*/
public function base64EncodeFilter($str)
{
return base64_encode($str);
return base64_encode((string) $str);
}
/**
@ -904,8 +913,13 @@ class GravExtension extends AbstractExtension implements GlobalsInterface
return $this->grav['admin']->translate($args, $lang);
}
// else use the default grav translate functionality
return $this->grav['language']->translate($args);
$translation = $this->grav['language']->translate($args);
if ($this->config->get('system.languages.debug', false)) {
return new Markup("<span class=\"translate-debug\" data-toggle=\"tooltip\" title=\"" . $args[0] . "\">$translation</span>", 'UTF-8');
} else {
return $translation;
}
}
/**
@ -949,7 +963,7 @@ class GravExtension extends AbstractExtension implements GlobalsInterface
*/
public function repeatFunc($input, $multiplier)
{
return str_repeat($input, $multiplier);
return str_repeat($input, (int) $multiplier);
}
/**
@ -1203,6 +1217,9 @@ class GravExtension extends AbstractExtension implements GlobalsInterface
*/
public function jsonDecodeFilter($str, $assoc = false, $depth = 512, $options = 0)
{
if ($str === null) {
$str = '';
}
return json_decode(html_entity_decode($str, ENT_COMPAT | ENT_HTML401, 'UTF-8'), $assoc, $depth, $options);
}
@ -1214,7 +1231,13 @@ class GravExtension extends AbstractExtension implements GlobalsInterface
*/
public function getCookie($key)
{
return filter_input(INPUT_COOKIE, $key, FILTER_SANITIZE_STRING);
$cookie_value = filter_input(INPUT_COOKIE, $key);
if ($cookie_value === null) {
return null;
}
return htmlspecialchars(strip_tags($cookie_value), ENT_QUOTES, 'UTF-8');
}
/**
@ -1689,12 +1712,44 @@ class GravExtension extends AbstractExtension implements GlobalsInterface
* @return array|CallbackFilterIterator
* @throws RuntimeError
*/
function filterFilter(Environment $env, $array, $arrow)
function filterFunc(Environment $env, $array, $arrow)
{
if (is_string($arrow) && Utils::isDangerousFunction($arrow)) {
if (!$arrow instanceof \Closure && !is_string($arrow) || Utils::isDangerousFunction($arrow)) {
throw new RuntimeError('Twig |filter("' . $arrow . '") is not allowed.');
}
return twig_array_filter($env, $array, $arrow);
}
/**
* @param Environment $env
* @param array $array
* @param callable|string $arrow
* @return array|CallbackFilterIterator
* @throws RuntimeError
*/
function mapFunc(Environment $env, $array, $arrow)
{
if (!$arrow instanceof \Closure && !is_string($arrow) || Utils::isDangerousFunction($arrow)) {
throw new RuntimeError('Twig |map("' . $arrow . '") is not allowed.');
}
return twig_array_map($env, $array, $arrow);
}
/**
* @param Environment $env
* @param array $array
* @param callable|string $arrow
* @return array|CallbackFilterIterator
* @throws RuntimeError
*/
function reduceFunc(Environment $env, $array, $arrow)
{
if (!$arrow instanceof \Closure && !is_string($arrow) || Utils::isDangerousFunction($arrow)) {
throw new RuntimeError('Twig |reduce("' . $arrow . '") is not allowed.');
}
return twig_array_map($env, $array, $arrow);
}
}

View File

@ -10,13 +10,15 @@
namespace Grav\Common\Twig\Node;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Node;
use Twig\Node\NodeOutputInterface;
/**
* Class TwigNodeCache
* @package Grav\Common\Twig\Node
*/
class TwigNodeCache extends Node
class TwigNodeCache extends Node implements NodeOutputInterface
{
/**
* @param string $key unique name for key
@ -25,25 +27,58 @@ class TwigNodeCache extends Node
* @param integer $lineno
* @param string|null $tag
*/
public function __construct(string $key, int $lifetime, Node $body, $lineno, $tag = null)
public function __construct(Node $body, ?AbstractExpression $key, ?AbstractExpression $lifetime, array $defaults, int $lineno, string $tag)
{
parent::__construct(array('body' => $body), array( 'key' => $key, 'lifetime' => $lifetime), $lineno, $tag);
$nodes = ['body' => $body];
if ($key !== null) {
$nodes['key'] = $key;
}
if ($lifetime !== null) {
$nodes['lifetime'] = $lifetime;
}
parent::__construct($nodes, $defaults, $lineno, $tag);
}
/**
* {@inheritDoc}
*/
public function compile(Compiler $compiler): void
{
$boo = $this->getAttribute('key');
$compiler->addDebugInfo($this);
// Generate the cache key
if ($this->hasNode('key')) {
$compiler
->write('$key = "twigcache-" . ')
->subcompile($this->getNode('key'))
->raw(";\n");
} else {
$compiler
->write('$key = ')
->string($this->getAttribute('key'))
->raw(";\n");
}
// Set the cache timeout
if ($this->hasNode('lifetime')) {
$compiler
->write('$lifetime = ')
->subcompile($this->getNode('lifetime'))
->raw(";\n");
} else {
$compiler
->write('$lifetime = ')
->write($this->getAttribute('lifetime'))
->raw(";\n");
}
$compiler
->addDebugInfo($this)
->write("\$cache = \\Grav\\Common\\Grav::instance()['cache'];\n")
->write("\$key = \"twigcache-\" . \"" . $this->getAttribute('key') . "\";\n")
->write("\$lifetime = " . $this->getAttribute('lifetime') . ";\n")
->write("\$cache_body = \$cache->fetch(\$key);\n")
->write("if (\$cache_body === false) {\n")
->indent()
->write("\\Grav\\Common\\Grav::instance()['debugger']->addMessage(\"Cache Key: \$key, Lifetime: \$lifetime\");\n")
->write("ob_start();\n")
->indent()
->subcompile($this->getNode('body'))
@ -53,6 +88,6 @@ class TwigNodeCache extends Node
->write("\$cache->save(\$key, \$cache_body, \$lifetime);\n")
->outdent()
->write("}\n")
->write("echo \$cache_body;\n");
->write("echo '' === \$cache_body ? '' : new Markup(\$cache_body, \$this->env->getCharset());\n");
}
}
}

View File

@ -11,7 +11,6 @@ namespace Grav\Common\Twig\TokenParser;
use Grav\Common\Grav;
use Grav\Common\Twig\Node\TwigNodeCache;
use Twig\Error\SyntaxError;
use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;
@ -22,50 +21,54 @@ use Twig\TokenParser\AbstractTokenParser;
* {{ some_complex_work() }}
* {% endcache %}
*
* Where the `600` is an optional lifetime in seconds
* Also can provide a unique key for the cache:
*
* {% cache "prefix-"~lang 600 %}
*
* Where the "prefix-"~lang will use a unique key based on the current language. "prefix-en" for example
*/
class TwigTokenParserCache extends AbstractTokenParser
{
/**
* @param Token $token
* @return TwigNodeCache
* @throws SyntaxError
*/
public function parse(Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
$key = $this->parser->getVarName() . $lineno;
$lifetime = Grav::instance()['cache']->getLifetime();
$lineno = $token->getLine();
// Check for optional lifetime override
if (!$stream->test(Token::BLOCK_END_TYPE)) {
$lifetime_expr = $this->parser->getExpressionParser()->parseExpression();
$lifetime = $lifetime_expr->getAttribute('value');
// Parse the optional key and timeout parameters
$defaults = [
'key' => $this->parser->getVarName() . $lineno,
'lifetime' => Grav::instance()['cache']->getLifetime()
];
$key = null;
$lifetime = null;
while (!$stream->test(Token::BLOCK_END_TYPE)) {
if ($stream->test(Token::STRING_TYPE)) {
$key = $this->parser->getExpressionParser()->parseExpression();
} elseif ($stream->test(Token::NUMBER_TYPE)) {
$lifetime = $this->parser->getExpressionParser()->parseExpression();
} else {
throw new \Twig\Error\SyntaxError("Unexpected token type in cache tag.", $token->getLine(), $stream->getSourceContext());
}
}
$stream->expect(Token::BLOCK_END_TYPE);
$body = $this->parser->subparse(array($this, 'decideCacheEnd'), true);
// Parse the content inside the cache block
$body = $this->parser->subparse([$this, 'decideCacheEnd'], true);
$stream->expect(Token::BLOCK_END_TYPE);
return new TwigNodeCache($key, $lifetime, $body, $lineno, $this->getTag());
return new TwigNodeCache($body, $key, $lifetime, $defaults, $lineno, $this->getTag());
}
/**
* Decide if current token marks end of cache block.
*
* @param Token $token
* @return bool
*/
public function decideCacheEnd(Token $token): bool
{
return $token->test('endcache');
}
/**
* {@inheritDoc}
*/
public function getTag(): string
{
return 'cache';
}
}
}

View File

@ -57,6 +57,15 @@ class Twig
/** @var string */
public $template;
/** @var array */
public $plugins_hooked_nav = [];
/** @var array */
public $plugins_quick_tray = [];
/** @var array */
public $plugins_hooked_dashboard_widgets_top = [];
/** @var array */
public $plugins_hooked_dashboard_widgets_main = [];
/** @var Grav */
protected $grav;
/** @var FilesystemLoader */
@ -493,13 +502,19 @@ class Twig
/**
* Simple helper method to get the twig template if it has already been set, else return
* the one being passed in
* NOTE: Modular pages that are injected should not use this pre-set template as it's usually set at the page level
*
* @param string $template the template name
* @return string the template name
*/
public function template($template)
public function template(string $template): string
{
return $this->template ?? $template;
if (isset($this->template)) {
$template = $this->template;
unset($this->template);
}
return $template;
}
/**
@ -513,7 +528,7 @@ class Twig
$default = $page->isModule() ? 'modular/default' : 'default';
$extension = $format ?: $page->templateFormat();
$twig_extension = $extension ? '.'. $extension .TWIG_EXT : TEMPLATE_EXT;
$template_file = $this->template($page->template() . $twig_extension);
$template_file = $this->template($template . $twig_extension);
// TODO: no longer needed in Twig 3.
/** @var ExistsLoaderInterface $loader */

View File

@ -1005,7 +1005,7 @@ class Uri
foreach ($matches as $match) {
$param = explode($delimiter, $match[1]);
if (count($param) === 2) {
$plain_var = filter_var(rawurldecode($param[1]), FILTER_SANITIZE_STRING);
$plain_var = htmlspecialchars(strip_tags(rawurldecode($param[1])), ENT_QUOTES, 'UTF-8');
$params[$param[0]] = $plain_var;
$uri = str_replace($match[0], '', $uri);
}
@ -1388,7 +1388,11 @@ class Uri
if ($this->post && null !== $element) {
$item = Utils::getDotNotation($this->post, $element);
if ($filter_type) {
$item = filter_var($item, $filter_type);
if ($filter_type === FILTER_SANITIZE_STRING || $filter_type === GRAV_SANITIZE_STRING) {
$item = htmlspecialchars(strip_tags($item), ENT_QUOTES, 'UTF-8');
} else {
$item = filter_var($item, $filter_type);
}
}
return $item;
}
@ -1514,7 +1518,7 @@ class Uri
foreach ($matches as $match) {
$param = explode($delimiter, $match[1]);
if (count($param) === 2) {
$plain_var = filter_var($param[1], FILTER_SANITIZE_STRING);
$plain_var = htmlspecialchars(strip_tags($param[1]), ENT_QUOTES, 'UTF-8');
$this->params[$param[0]] = $plain_var;
$uri = str_replace($match[0], '', $uri);
}

View File

@ -201,7 +201,7 @@ abstract class Utils
$compare_func = $case_sensitive ? 'mb_strpos' : 'mb_stripos';
foreach ((array)$needle as $each_needle) {
$status = $each_needle === '' || $compare_func($haystack, $each_needle) === 0;
$status = $each_needle === '' || $compare_func((string) $haystack, $each_needle) === 0;
if ($status) {
break;
}
@ -225,8 +225,8 @@ abstract class Utils
$compare_func = $case_sensitive ? 'mb_strrpos' : 'mb_strripos';
foreach ((array)$needle as $each_needle) {
$expectedPosition = mb_strlen($haystack) - mb_strlen($each_needle);
$status = $each_needle === '' || $compare_func($haystack, $each_needle, 0) === $expectedPosition;
$expectedPosition = mb_strlen((string) $haystack) - mb_strlen($each_needle);
$status = $each_needle === '' || $compare_func((string) $haystack, $each_needle, 0) === $expectedPosition;
if ($status) {
break;
}
@ -250,7 +250,7 @@ abstract class Utils
$compare_func = $case_sensitive ? 'mb_strpos' : 'mb_stripos';
foreach ((array)$needle as $each_needle) {
$status = $each_needle === '' || $compare_func($haystack, $each_needle) !== false;
$status = $each_needle === '' || $compare_func((string) $haystack, $each_needle) !== false;
if ($status) {
break;
}
@ -1145,9 +1145,9 @@ abstract class Utils
$offset_prefix = $offset < 0 ? '-' : '+';
$offset_formatted = gmdate('H:i', abs($offset));
$pretty_offset = "UTC${offset_prefix}${offset_formatted}";
$pretty_offset = "UTC{$offset_prefix}{$offset_formatted}";
$timezone_list[$timezone] = "(${pretty_offset}) " . str_replace('_', ' ', $timezone);
$timezone_list[$timezone] = "({$pretty_offset}) " . str_replace('_', ' ', $timezone);
}
return $timezone_list;
@ -1874,9 +1874,9 @@ abstract class Utils
}
if ($block) {
$string = $parsedown->text($string);
$string = $parsedown->text((string) $string);
} else {
$string = $parsedown->line($string);
$string = $parsedown->line((string) $string);
}
return $string;
@ -1950,10 +1950,10 @@ abstract class Utils
}
/**
* @param string $name
* @param string|array|Closure $name
* @return bool
*/
public static function isDangerousFunction(string $name): bool
public static function isDangerousFunction($name): bool
{
static $commandExecutionFunctions = [
'exec',
@ -2048,8 +2048,30 @@ abstract class Utils
'posix_setpgid',
'posix_setsid',
'posix_setuid',
'unserialize',
'ini_alter',
'simplexml_load_file',
'simplexml_load_string',
'forward_static_call',
'forward_static_call_array',
];
if (is_string($name)) {
$name = strtolower($name);
}
if ($name instanceof \Closure) {
return false;
}
if (is_array($name) || strpos($name, ":") !== false) {
return true;
}
if (strpos($name, "\\") !== false) {
return true;
}
if (in_array($name, $commandExecutionFunctions)) {
return true;
}

View File

@ -82,7 +82,7 @@ class LogViewerCommand extends GravCommand
if ($log['trace'] && $verbose) {
$output .= " <white>{$log['message']}</white>\n";
foreach ((array) $log['trace'] as $index => $tracerow) {
$output .= "<white>{$index}</white>${tracerow}\n";
$output .= "<white>{$index}</white>{$tracerow}\n";
}
} else {
$output .= " {$log['message']}";

View File

@ -317,7 +317,7 @@ class InstallCommand extends GpmCommand
$questionNoun = 'packages';
}
$question = new ConfirmationQuestion("${questionAction} {$questionArticle} {$questionNoun}? [Y|n] ", true);
$question = new ConfirmationQuestion("{$questionAction} {$questionArticle} {$questionNoun}? [Y|n] ", true);
$answer = $this->all_yes ? true : $io->askQuestion($question);
if ($answer) {

View File

@ -0,0 +1,18 @@
<?php
/**
* @package Grav\Events
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Events;
use Grav\Framework\Flex\Flex;
use RocketTheme\Toolbox\Event\Event;
class PageEvent extends Event
{
public $page;
}

View File

@ -0,0 +1,18 @@
<?php
/**
* @package Grav\Events
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Events;
use Grav\Framework\Flex\Flex;
use RocketTheme\Toolbox\Event\Event;
class TypesEvent extends Event
{
public $types;
}

View File

@ -23,6 +23,8 @@ class RecursiveActionIterator implements RecursiveIterator, \Countable
{
use Constructor, Iterator, Countable;
public $items;
/**
* @see \Iterator::key()
* @return string

View File

@ -366,9 +366,14 @@ trait PageLegacyTrait
*/
public function blueprintName(): string
{
$blueprint_name = filter_input(INPUT_POST, 'blueprint', FILTER_SANITIZE_STRING) ?: $this->template();
if (!isset($_POST['blueprint'])) {
return $this->template();
}
return $blueprint_name;
$post_value = $_POST['blueprint'];
$sanitized_value = htmlspecialchars(strip_tags($post_value), ENT_QUOTES, 'UTF-8');
return $sanitized_value ?: $this->template();
}
/**

View File

@ -42,7 +42,7 @@ trait NestedPropertyTrait
public function getNestedProperty($property, $default = null, $separator = null)
{
$separator = $separator ?: '.';
$path = explode($separator, $property);
$path = explode($separator, (string) $property);
$offset = array_shift($path);
if (!$this->hasProperty($offset)) {

View File

@ -11,6 +11,7 @@ namespace Grav\Framework\Session;
use ArrayIterator;
use Exception;
use Throwable;
use Grav\Common\Debugger;
use Grav\Common\Grav;
use Grav\Common\User\Interfaces\UserInterface;
@ -254,13 +255,17 @@ class Session implements SessionInterface
$this->started = true;
$this->onSessionStart();
$user = $this->__get('user');
if ($user && (!$user instanceof UserInterface || (method_exists($user, 'isValid') && !$user->isValid()))) {
try {
$user = $this->__get('user');
if ($user && (!$user instanceof UserInterface || (method_exists($user, 'isValid') && !$user->isValid()))) {
throw new RuntimeException('Bad user');
}
} catch (Throwable $e) {
$this->invalidate();
throw new SessionException('Invalid User object, session destroyed.', 500);
}
// Extend the lifetime of the session.
if ($sessionExists) {
$this->setCookie();

View File

@ -93,7 +93,7 @@ class UriFactory
}
// Support ngnix routes.
if (strpos($query, '_url=') === 0) {
if (strpos((string) $query, '_url=') === 0) {
parse_str($query, $q);
unset($q['_url']);
$query = http_build_query($q);

View File

@ -0,0 +1,27 @@
<?php
/**
* This file is part of the rybakit/twig-deferred-extension package.
*
* (c) Eugene Leonovich <gen.work@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Twig\DeferredExtension;
use Twig\Compiler;
use Twig\Node\Node;
final class DeferredDeclareNode extends Node
{
public function compile(Compiler $compiler) : void
{
$compiler
->write("private \$deferred;\n")
;
}
}

View File

@ -16,7 +16,7 @@ namespace Twig\DeferredExtension;
use Twig\Compiler;
use Twig\Node\Node;
final class DeferredExtensionNode extends Node
final class DeferredInitializeNode extends Node
{
public function compile(Compiler $compiler) : void
{

View File

@ -34,8 +34,9 @@ final class DeferredNodeVisitor implements NodeVisitorInterface
public function leaveNode(Node $node, Environment $env) : ?Node
{
if ($this->hasDeferred && $node instanceof ModuleNode) {
$node->setNode('constructor_end', new Node([new DeferredExtensionNode(), $node->getNode('constructor_end')]));
$node->setNode('display_end', new Node([new DeferredNode(), $node->getNode('display_end')]));
$node->getNode('constructor_end')->setNode('deferred_initialize', new DeferredInitializeNode());
$node->getNode('display_end')->setNode('deferred_resolve', new DeferredResolveNode());
$node->getNode('class_end')->setNode('deferred_declare', new DeferredDeclareNode());
$this->hasDeferred = false;
}

View File

@ -46,8 +46,9 @@ final class DeferredNodeVisitorCompat implements NodeVisitorInterface
public function leaveNode(\Twig_NodeInterface $node, Environment $env): ?Node
{
if ($this->hasDeferred && $node instanceof ModuleNode) {
$node->setNode('constructor_end', new Node([new DeferredExtensionNode(), $node->getNode('constructor_end')]));
$node->setNode('display_end', new Node([new DeferredNode(), $node->getNode('display_end')]));
$node->getNode('constructor_end')->setNode('deferred_initialize', new DeferredInitializeNode());
$node->getNode('display_end')->setNode('deferred_resolve', new DeferredResolveNode());
$node->getNode('class_end')->setNode('deferred_declare', new DeferredDeclareNode());
$this->hasDeferred = false;
}

View File

@ -0,0 +1,27 @@
<?php
/**
* This file is part of the rybakit/twig-deferred-extension package.
*
* (c) Eugene Leonovich <gen.work@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Twig\DeferredExtension;
use Twig\Compiler;
use Twig\Node\Node;
final class DeferredResolveNode extends Node
{
public function compile(Compiler $compiler) : void
{
$compiler
->write("\$this->deferred->resolve(\$this, \$context, \$blocks);\n")
;
}
}

View File

@ -1,6 +1,6 @@
core:
grav:
version: 1.7.38
version: 1.7.42.3
schema: 1.7.0_2020-11-20_1
history:
- { version: 1.7.16, date: '2021-06-10 14:03:35' }
@ -8,3 +8,4 @@ core:
- { version: 1.7.25, date: '2021-12-06 12:22:00' }
- { version: 1.7.31, date: '2022-03-15 08:48:47' }
- { version: 1.7.38, date: '2023-01-03 15:06:08' }
- { version: 1.7.42.3, date: '2023-09-19 10:47:33' }

View File

@ -30,7 +30,7 @@ server {
## Begin - PHP
location ~ \.php$ {
# Choose either a socket or TCP/IP address
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
fastcgi_pass unix:/var/run/php/php-fpm.sock;
# fastcgi_pass unix:/var/run/php5-fpm.sock; #legacy
# fastcgi_pass 127.0.0.1:9000;