From 4b8e1891bd0595de9e10c6b9374eb1a1783030c0 Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Sun, 28 Jun 2020 23:31:56 +0200 Subject: [PATCH 1/3] Update html_to_markdown.rst --- doc/filters/html_to_markdown.rst | 52 +++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/doc/filters/html_to_markdown.rst b/doc/filters/html_to_markdown.rst index 4cb55459e..6a827b2c6 100644 --- a/doc/filters/html_to_markdown.rst +++ b/doc/filters/html_to_markdown.rst @@ -14,26 +14,19 @@ The ``html_to_markdown`` filter converts a block of HTML to Markdown: {% endapply %} -You can also add some options by passing them as an argument to the filter: - -.. code-block:: twig - - {% apply html_to_markdown({hard_break: false}) %} - -

Hello!

- - {% endapply %} - -.. note:: - - The options are the ones provided by the ``league/html-to-markdown`` package. - -You can also use the filter on an included file: +You can also use the filter on an entire template which you ``include``: .. code-block:: twig {{ include('some_template.html.twig')|html_to_markdown }} +Output: + +.. code-block:: markdown + + Hello! + ====== + .. note:: The ``html_to_markdown`` filter is part of the ``MarkdownExtension`` which @@ -43,8 +36,14 @@ You can also use the filter on an included file: $ composer req twig/markdown-extra - Then, use the ``twig/extra-bundle`` on Symfony projects or add the extension - explicitly on the Twig environment:: + On Symfony projects, you can automatically enable it by installing the + ``twig/extra-bundle``: + + .. code-block:: bash + + $ composer req twig/extra-bundle + + Or add the extension explicitly on the Twig environment:: use Twig\Extra\Markdown\MarkdownExtension; @@ -64,3 +63,22 @@ You can also use the filter on an included file: } } }); + +``html_to_markdown`` is just a frontend; the actual conversion is done by one of +the following compatible libraries, from which you can choose: + +* [erusev/parsedown](https://github.com/erusev/parsedown) +* [thephpleague/html-to-markdown](https://github.com/thephpleague/html-to-markdown) +* [michelf/php-markdown](https://github.com/michelf/php-markdown) + +Depending on the library, you can also add some options by passing them as an argument +to the filter. Example for ``league/html-to-markdown``: + +.. code-block:: twig + + {% apply html_to_markdown({hard_break: false}) %} + +

Hello!

+ + {% endapply %} + From 5e1c4a63be0df7a5d09edd5051fd6ad0d37d9d3b Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 5 Jul 2020 15:27:01 +0200 Subject: [PATCH 2/3] Fix CS --- doc/filters/html_to_markdown.rst | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/doc/filters/html_to_markdown.rst b/doc/filters/html_to_markdown.rst index 6a827b2c6..81751c120 100644 --- a/doc/filters/html_to_markdown.rst +++ b/doc/filters/html_to_markdown.rst @@ -20,13 +20,6 @@ You can also use the filter on an entire template which you ``include``: {{ include('some_template.html.twig')|html_to_markdown }} -Output: - -.. code-block:: markdown - - Hello! - ====== - .. note:: The ``html_to_markdown`` filter is part of the ``MarkdownExtension`` which @@ -42,7 +35,7 @@ Output: .. code-block:: bash $ composer req twig/extra-bundle - + Or add the extension explicitly on the Twig environment:: use Twig\Extra\Markdown\MarkdownExtension; From d8259519c057360d1ba0fcb4ae9c3808977915d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Thu, 2 Apr 2020 23:47:53 +0200 Subject: [PATCH 3/3] Restrict callables to closures in filters --- CHANGELOG | 1 + src/Extension/CoreExtension.php | 24 ++++++++++++++++++------ tests/Extension/SandboxTest.php | 24 ++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9447b58ee..41022f515 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,7 @@ * Fix PHP 8 compatibility * Drop PHP 5.5 5.6, and 7.0 support * Fix ambiguous syntax parsing + * In sandbox, the `filter`, `map` and `reduce` filters require Closures in `arrow` parameter # 1.42.5 (2020-02-11) diff --git a/src/Extension/CoreExtension.php b/src/Extension/CoreExtension.php index 2f24848a4..a17af0606 100644 --- a/src/Extension/CoreExtension.php +++ b/src/Extension/CoreExtension.php @@ -194,9 +194,9 @@ class CoreExtension extends AbstractExtension new TwigFilter('sort', 'twig_sort_filter'), new TwigFilter('merge', 'twig_array_merge'), new TwigFilter('batch', 'twig_array_batch'), - new TwigFilter('filter', 'twig_array_filter'), - new TwigFilter('map', 'twig_array_map'), - new TwigFilter('reduce', 'twig_array_reduce'), + new TwigFilter('filter', 'twig_array_filter', ['needs_environment' => true]), + new TwigFilter('map', 'twig_array_map', ['needs_environment' => true]), + new TwigFilter('reduce', 'twig_array_reduce', ['needs_environment' => true]), // string/array filters new TwigFilter('reverse', 'twig_reverse_filter', ['needs_environment' => true]), @@ -1693,12 +1693,16 @@ function twig_array_batch($items, $size, $fill = null, $preserveKeys = true) return $result; } -function twig_array_filter($array, $arrow) +function twig_array_filter(Environment $env, $array, $arrow) { if (!twig_test_iterable($array)) { throw new RuntimeError(sprintf('The "filter" filter expects an array or "Traversable", got "%s".', \is_object($array) ? \get_class($array) : \gettype($array))); } + if (!$arrow instanceof Closure && $env->hasExtension('\Twig\Extension\SandboxExtension') && $env->getExtension('\Twig\Extension\SandboxExtension')->isSandboxed()) { + throw new RuntimeError('The callable passed to "filter" filter must be a Closure in sandbox mode.'); + } + if (\is_array($array)) { if (\PHP_VERSION_ID >= 50600) { return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH); @@ -1711,8 +1715,12 @@ function twig_array_filter($array, $arrow) return new \CallbackFilterIterator(new \IteratorIterator($array), $arrow); } -function twig_array_map($array, $arrow) +function twig_array_map(Environment $env, $array, $arrow) { + if (!$arrow instanceof Closure && $env->hasExtension('\Twig\Extension\SandboxExtension') && $env->getExtension('\Twig\Extension\SandboxExtension')->isSandboxed()) { + throw new RuntimeError('The callable passed to the "map" filter must be a Closure in sandbox mode.'); + } + $r = []; foreach ($array as $k => $v) { $r[$k] = $arrow($v, $k); @@ -1721,8 +1729,12 @@ function twig_array_map($array, $arrow) return $r; } -function twig_array_reduce($array, $arrow, $initial = null) +function twig_array_reduce(Environment $env, $array, $arrow, $initial = null) { + if (!$arrow instanceof Closure && $env->hasExtension('\Twig\Extension\SandboxExtension') && $env->getExtension('\Twig\Extension\SandboxExtension')->isSandboxed()) { + throw new RuntimeError('The callable passed to the "reduce" filter must be a Closure in sandbox mode.'); + } + if (!\is_array($array)) { $array = iterator_to_array($array); } diff --git a/tests/Extension/SandboxTest.php b/tests/Extension/SandboxTest.php index 7b7107988..2fe692a2e 100644 --- a/tests/Extension/SandboxTest.php +++ b/tests/Extension/SandboxTest.php @@ -315,6 +315,30 @@ EOF $this->assertFalse($twig->getExtension('\Twig\Extension\SandboxExtension')->isSandboxed(), 'Sandboxed include() function call should not leave Sandbox enabled when an error occurs.'); } + public function testSandboxWithNoClosureFilter() + { + $this->expectException('\Twig\Error\RuntimeError'); + $this->expectExceptionMessage('The callable passed to "filter" filter must be a Closure in sandbox mode in "index" at line 1.'); + + + $twig = $this->getEnvironment(true, ['autoescape' => 'html'], ['index' => <<load('index')->render([]); + } + + public function testSandboxWithClosureFilter() + { + $twig = $this->getEnvironment(true, ['autoescape' => 'html'], ['index' => << v != "")|join(", ") }} +EOF + ], [], ['escape', 'filter', 'join']); + + $this->assertSame('foo, bar', $twig->load('index')->render([])); + } + protected function getEnvironment($sandboxed, $options, $templates, $tags = [], $filters = [], $methods = [], $properties = [], $functions = []) { $loader = new ArrayLoader($templates);