N°5725 - Twig update 'filter', 'map' and 'reduce' filters (+1 squashed commits)

Squashed commits:

[00148dec5] N°5725 - Twig update 'filter', 'map' and 'reduce' filters
This commit is contained in:
Eric Espie
2022-11-24 16:12:53 +01:00
parent ce5096a896
commit f0141530b9
4 changed files with 131 additions and 77 deletions

View File

@@ -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 //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 //overwrite native twig filter : disable use of 'system' filter
$filters[] = new Twig_SimpleFilter('filter', function ($array, $arrow) { $filters[] = new Twig_SimpleFilter('filter', function ($array, $arrow) {
if ($arrow == 'system'){ $ret = $this->SanitizeFilter($array, $arrow);
return json_encode($array); 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; 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[] * @return array|\Twig\TwigFunction[]|\Twig_SimpleFunction[]
*/ */

View File

@@ -5,6 +5,11 @@ use Combodo\iTop\Portal\Twig\AppExtension;
use Twig_Environment; use Twig_Environment;
use Twig_Loader_Array; use Twig_Loader_Array;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class TwigTest extends ItopDataTestCase class TwigTest extends ItopDataTestCase
{ {
protected function setUp(): void protected function setUp(): void

View File

@@ -1,33 +1,46 @@
<div> <div>User Name</div>
User Name
</div><div> <div>['id']|filter('system')|join</div>
['id']|filter('system') [&quot;id&quot;]
</div>
[&quot;id&quot;] <div>['echo']|filter('passthru')|join</div>
<div> [&quot;echo&quot;]
['touch+/tmp/test+']|filter('system')|join(',')
</div> <div>['echo']|filter('popen')|join</div>
[&quot;touch+\/tmp\/test+&quot;] [&quot;echo&quot;]
<div>
set sizes = [34, 36, 38, 40, 42] <div>['echo']|filter('exec')|join</div>
sizes|filter(v => v > 38)|join(', ') [&quot;echo&quot;]
</div>
40, 42 <div>['id']|filter('SysteM')|join</div>
<div> [&quot;id&quot;]
app.request.server.all|join(',')
</div><div> <div>['touch+/tmp/test+']|filter('system')|join(',')</div>
self [&quot;touch+\/tmp\/test+&quot;]
</div><div>
[0]|reduce('system','echo') <div>[34, 36, 38, 40, 42]|filter(v => v > 38)|join(', ')</div>
</div> 40, 42
[&quot;echo&quot;]
<div> <div>app.request.server.all|join(',')</div>
['echo']|map('system')|join
</div>
[&quot;echo&quot;] <div>self</div>
<div>
['echo',1]|sort('system')|join
</div> <div>[0]|reduce('system','echo')</div>
echo1 [0]
POST /subscribe?0=cat+/etc/passwd HTTP/1.1
email=""@attacker.tld <div>[1, 2, 3]|reduce((carry, v) => carry + v)</div>
6
<div>['echo']|map('system')|join</div>
[&quot;echo&quot;]
<div>{"Bob": "Smith", "Alice": "Dupond"}|map((value, key) => "#{key} #{value}")|join(', ')</div>
Bob Smith, Alice Dupond
<div>['echo',1]|sort('system')|join</div>
echo1
POST /subscribe?0=cat+/etc/passwd HTTP/1.1
email=""@attacker.tld

View File

@@ -1,41 +1,51 @@
{% spaceless %} <div>{{ 'UI:Login:UserNamePrompt'|dict_s }}</div>
<div>
{{ 'UI:Login:UserNamePrompt'|dict_s }} <div>['id']|filter('system')|join</div>
</div> {{ ['id']|filter('system')|join }}
<div>
['id']|filter('system') <div>['echo']|filter('passthru')|join</div>
</div> {{ ['echo']|filter('passthru')|join }}
{{ ['id']|filter('system') }}
<div> <div>['echo']|filter('popen')|join</div>
['touch+/tmp/test+']|filter('system')|join(',') {{ ['echo']|filter('popen')|join }}
</div>
{{ ['touch+/tmp/test+']|filter('system')|join(',') }} <div>['echo']|filter('exec')|join</div>
<div> {{ ['echo']|filter('exec')|join }}
set sizes = [34, 36, 38, 40, 42]
sizes|filter(v => v > 38)|join(', ') <div>['id']|filter('SysteM')|join</div>
</div> {{ ['id']|filter('SysteM')|join }}
{% set sizes = [34, 36, 38, 40, 42] %}
{{ sizes|filter(v => v > 38)|join(', ') }} <div>['touch+/tmp/test+']|filter('system')|join(',')</div>
<div> {{ ['touch+/tmp/test+']|filter('system')|join(',') }}
app.request.server.all|join(',')
</div> <div>[34, 36, 38, 40, 42]|filter(v => v > 38)|join(', ')</div>
{{ app.request.server.all|join(',') }} {# needs syfony #} {{ [34, 36, 38, 40, 42]|filter(v => v > 38)|join(', ') }}
<div>
self <div>app.request.server.all|join(',')</div>
</div> {{ app.request.server.all|join(',')}}
{{ self }} {# ??? not sure #}
<div> <div>self</div>
[0]|reduce('system','echo') {{ self }}
</div>
{{ [0]|reduce('system','echo') }} <div>[0]|reduce('system','echo')</div>
<div> {{ [0]|reduce('system','echo') }}
['echo']|map('system')|join
</div> <div>[1, 2, 3]|reduce((carry, v) => carry + v)</div>
{{ ['echo']|map('system')|join }} {% set numbers = [1, 2, 3] %}
<div> {{ numbers|reduce((carry, v) => carry + v) }}
['echo',1]|sort('system')|join
</div> <div>['echo']|map('system')|join</div>
{{ ['echo',1]|sort('system')|join }} {{ ['echo']|map('system')|join }}
POST /subscribe?0=cat+/etc/passwd HTTP/1.1
email="{{ app.request.query.filter(0,0,1024,{'options':'system'}) }}"@attacker.tld <div>{"Bob": "Smith", "Alice": "Dupond"}|map((value, key) => "#{key} #{value}")|join(', ')</div>
{% endspaceless %} {% set people = {
"Bob": "Smith",
"Alice": "Dupond",
} %}
{{ people|map((value, key) => "#{key} #{value}")|join(', ') }}
<div>['echo',1]|sort('system')|join</div>
{{ ['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