From f0141530b99427a7c9ef7f5088b45616b89b6aab Mon Sep 17 00:00:00 2001 From: Eric Espie Date: Thu, 24 Nov 2022 16:12:53 +0100 Subject: [PATCH] =?UTF-8?q?N=C2=B05725=20-=20Twig=20update=20'filter',=20'?= =?UTF-8?q?map'=20and=20'reduce'=20filters=20(+1=20squashed=20commits)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Squashed commits: [00148dec5] N°5725 - Twig update 'filter', 'map' and 'reduce' filters --- .../portal/src/Twig/AppExtension.php | 32 ++++++- test/twig/TwigTest.php | 5 + test/twig/test.html | 79 +++++++++------- test/twig/test.html.twig | 92 ++++++++++--------- 4 files changed, 131 insertions(+), 77 deletions(-) diff --git a/datamodels/2.x/itop-portal-base/portal/src/Twig/AppExtension.php b/datamodels/2.x/itop-portal-base/portal/src/Twig/AppExtension.php index b44f62e869..c4f51f9c76 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/Twig/AppExtension.php +++ b/datamodels/2.x/itop-portal-base/portal/src/Twig/AppExtension.php @@ -100,15 +100,41 @@ class AppExtension extends AbstractExtension //since 2.7.7 3.0.2 3.1.0 N°4867 "Twig content not allowed" error when use the extkey widget search icon in the user portal //overwrite native twig filter : disable use of 'system' filter $filters[] = new Twig_SimpleFilter('filter', function ($array, $arrow) { - if ($arrow == 'system'){ - return json_encode($array); + $ret = $this->SanitizeFilter($array, $arrow); + if ($ret !== false) { + return [$ret]; } - return twig_array_filter($array, $arrow); + return twig_array_filter($array, $arrow); + }); + $filters[] = new Twig_SimpleFilter('map', function ($array, $arrow) { + $ret = $this->SanitizeFilter($array, $arrow); + if ($ret !== false) { + return [$ret]; + } + return twig_array_map($array, $arrow); + }); + $filters[] = new Twig_SimpleFilter('reduce', function ($array, $arrow, $initial = null) { + $ret = $this->SanitizeFilter($array, $arrow); + if ($ret !== false) { + return $ret; + } + // reduce return mixed results not only arrays + return twig_array_reduce($array, $arrow, $initial); }); return $filters; } + private function SanitizeFilter($array, $arrow) + { + if (is_string($arrow)) { + if (in_array(strtolower($arrow), ['system', 'exec', 'passthru', 'popen'])) { + return json_encode($array); + } + } + return false; + } + /** * @return array|\Twig\TwigFunction[]|\Twig_SimpleFunction[] */ diff --git a/test/twig/TwigTest.php b/test/twig/TwigTest.php index f47bc10bed..f14420c817 100644 --- a/test/twig/TwigTest.php +++ b/test/twig/TwigTest.php @@ -5,6 +5,11 @@ use Combodo\iTop\Portal\Twig\AppExtension; use Twig_Environment; use Twig_Loader_Array; +/** + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + * @backupGlobals disabled + */ class TwigTest extends ItopDataTestCase { protected function setUp(): void diff --git a/test/twig/test.html b/test/twig/test.html index 2406bbfd4f..3fb370a80a 100644 --- a/test/twig/test.html +++ b/test/twig/test.html @@ -1,33 +1,46 @@ -
- User Name -
- ['id']|filter('system') -
- ["id"] -
- ['touch+/tmp/test+']|filter('system')|join(',') -
- ["touch+\/tmp\/test+"] -
- set sizes = [34, 36, 38, 40, 42] - sizes|filter(v => v > 38)|join(', ') -
- 40, 42 -
- app.request.server.all|join(',') -
- self -
- [0]|reduce('system','echo') -
- ["echo"] -
- ['echo']|map('system')|join -
- ["echo"] -
- ['echo',1]|sort('system')|join -
- echo1 - POST /subscribe?0=cat+/etc/passwd HTTP/1.1 - email=""@attacker.tld \ No newline at end of file +
User Name
+ +
['id']|filter('system')|join
+["id"] + +
['echo']|filter('passthru')|join
+["echo"] + +
['echo']|filter('popen')|join
+["echo"] + +
['echo']|filter('exec')|join
+["echo"] + +
['id']|filter('SysteM')|join
+["id"] + +
['touch+/tmp/test+']|filter('system')|join(',')
+["touch+\/tmp\/test+"] + +
[34, 36, 38, 40, 42]|filter(v => v > 38)|join(', ')
+40, 42 + +
app.request.server.all|join(',')
+ + +
self
+ + +
[0]|reduce('system','echo')
+[0] + +
[1, 2, 3]|reduce((carry, v) => carry + v)
+6 + +
['echo']|map('system')|join
+["echo"] + +
{"Bob": "Smith", "Alice": "Dupond"}|map((value, key) => "#{key} #{value}")|join(', ')
+Bob Smith, Alice Dupond + +
['echo',1]|sort('system')|join
+echo1 + +POST /subscribe?0=cat+/etc/passwd HTTP/1.1 +email=""@attacker.tld \ No newline at end of file diff --git a/test/twig/test.html.twig b/test/twig/test.html.twig index 5825249c30..1e350299f0 100644 --- a/test/twig/test.html.twig +++ b/test/twig/test.html.twig @@ -1,41 +1,51 @@ -{% spaceless %} -
- {{ 'UI:Login:UserNamePrompt'|dict_s }} -
-
- ['id']|filter('system') -
- {{ ['id']|filter('system') }} -
- ['touch+/tmp/test+']|filter('system')|join(',') -
- {{ ['touch+/tmp/test+']|filter('system')|join(',') }} -
- set sizes = [34, 36, 38, 40, 42] - sizes|filter(v => v > 38)|join(', ') -
- {% set sizes = [34, 36, 38, 40, 42] %} - {{ sizes|filter(v => v > 38)|join(', ') }} -
- app.request.server.all|join(',') -
- {{ app.request.server.all|join(',') }} {# needs syfony #} -
- self -
- {{ self }} {# ??? not sure #} -
- [0]|reduce('system','echo') -
- {{ [0]|reduce('system','echo') }} -
- ['echo']|map('system')|join -
- {{ ['echo']|map('system')|join }} -
- ['echo',1]|sort('system')|join -
- {{ ['echo',1]|sort('system')|join }} - POST /subscribe?0=cat+/etc/passwd HTTP/1.1 - email="{{ app.request.query.filter(0,0,1024,{'options':'system'}) }}"@attacker.tld -{% endspaceless %} \ No newline at end of file +
{{ 'UI:Login:UserNamePrompt'|dict_s }}
+ +
['id']|filter('system')|join
+{{ ['id']|filter('system')|join }} + +
['echo']|filter('passthru')|join
+{{ ['echo']|filter('passthru')|join }} + +
['echo']|filter('popen')|join
+{{ ['echo']|filter('popen')|join }} + +
['echo']|filter('exec')|join
+{{ ['echo']|filter('exec')|join }} + +
['id']|filter('SysteM')|join
+{{ ['id']|filter('SysteM')|join }} + +
['touch+/tmp/test+']|filter('system')|join(',')
+{{ ['touch+/tmp/test+']|filter('system')|join(',') }} + +
[34, 36, 38, 40, 42]|filter(v => v > 38)|join(', ')
+{{ [34, 36, 38, 40, 42]|filter(v => v > 38)|join(', ') }} + +
app.request.server.all|join(',')
+{{ app.request.server.all|join(',')}} + +
self
+{{ self }} + +
[0]|reduce('system','echo')
+{{ [0]|reduce('system','echo') }} + +
[1, 2, 3]|reduce((carry, v) => carry + v)
+{% set numbers = [1, 2, 3] %} +{{ numbers|reduce((carry, v) => carry + v) }} + +
['echo']|map('system')|join
+{{ ['echo']|map('system')|join }} + +
{"Bob": "Smith", "Alice": "Dupond"}|map((value, key) => "#{key} #{value}")|join(', ')
+{% set people = { +"Bob": "Smith", +"Alice": "Dupond", +} %} +{{ people|map((value, key) => "#{key} #{value}")|join(', ') }} + +
['echo',1]|sort('system')|join
+{{ ['echo',1]|sort('system')|join }} + +POST /subscribe?0=cat+/etc/passwd HTTP/1.1 +email="{{ app.request.query.filter(0,0,1024,{'options':'system'}) }}"@attacker.tld \ No newline at end of file