Merge branch 'support/3.0' into develop

# Conflicts:
#	datamodels/2.x/itop-portal-base/portal/src/Twig/AppExtension.php
#	test/twig/test.html
#	test/twig/test.html.twig
This commit is contained in:
Eric Espie
2022-11-30 13:57:28 +01:00
4 changed files with 130 additions and 66 deletions

View File

@@ -165,16 +165,53 @@ 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 TwigFilter('filter', function ($array, $arrow) {
if ($arrow == 'system'){
return json_encode($array);
$ret = $this->SanitizeFilter($array, $arrow);
if ($ret !== false) {
return [$ret];
}
$oEnv = new Environment(new FilesystemLoader());
return twig_array_filter($oEnv, $array, $arrow);
return twig_array_filter($oEnv, $array, $arrow);
});
$filters[] = new TwigFilter('map', function ($array, $arrow) {
$ret = $this->SanitizeFilter($array, $arrow);
if ($ret !== false) {
return [$ret];
}
$oEnv = new Environment(new FilesystemLoader());
return twig_array_map($oEnv, $array, $arrow);
});
$filters[] = new TwigFilter('reduce', function ($array, $arrow, $initial = null) {
$ret = $this->SanitizeFilter($array, $arrow);
if ($ret !== false) {
return $ret;
}
// reduce return mixed results not only arrays
$oEnv = new Environment(new FilesystemLoader());
return twig_array_reduce($oEnv, $array, $arrow, $initial);
});
$filters[] = new TwigFilter('sort', function ($array, $arrow, $initial = null) {
$ret = $this->SanitizeFilter($array, $arrow);
if ($ret !== false) {
return $ret;
}
// reduce return mixed results not only arrays
$oEnv = new Environment(new FilesystemLoader());
return twig_array_reduce($oEnv, $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\TwigFunction[]
*/

View File

@@ -7,6 +7,11 @@ use Twig\Loader\ArrayLoader;
use Twig_Environment;
use Twig_Loader_Array;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class TwigTest extends ItopDataTestCase
{
protected function setUp(): void

View File

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

View File

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