|
@@ -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);
|
|
|
+ }
|
|
|
}
|