diff --git a/core/dbobjectset.class.php b/core/dbobjectset.class.php
index fb8ebb43b..f6d440136 100644
--- a/core/dbobjectset.class.php
+++ b/core/dbobjectset.class.php
@@ -141,7 +141,7 @@ class DBObjectSet implements iDBObjectSetIterator
{
$sRet = '';
$this->Rewind();
- $sRet .= "Set (".$this->m_oFilter->ToOQL().")
\n";
+ $sRet .= "Set (".$this->m_oFilter->ToOQL(true).")
\n";
$sRet .= "Query:
".$this->m_oFilter->MakeSelectQuery().")
\n";
$sRet .= $this->Count()." records
\n";
@@ -154,6 +154,7 @@ class DBObjectSet implements iDBObjectSetIterator
}
$sRet .= "\n";
}
+ $this->Rewind();
return $sRet;
}
diff --git a/core/dbsearch.class.php b/core/dbsearch.class.php
index e0eb85cbe..fa1c99929 100644
--- a/core/dbsearch.class.php
+++ b/core/dbsearch.class.php
@@ -1717,6 +1717,6 @@ abstract class DBSearch
*/
public function __toString()
{
- return $this->ToOQL();
+ return $this->ToOQL(true);
}
}
diff --git a/core/restservices.class.inc.php b/core/restservices.class.inc.php
index 50aa18ce4..c64df552f 100644
--- a/core/restservices.class.inc.php
+++ b/core/restservices.class.inc.php
@@ -575,7 +575,7 @@ class CoreServices implements iRestServiceProvider
$oObject = $oElement->GetProperty('object');
if ($oObject)
{
- if ($bEnableRedundancy)
+ if ($bEnableRedundancy && $sDirection == 'down')
{
// Add only the "reached" objects
if ($oElement->GetProperty('is_reached'))
diff --git a/pages/ajax.render.php b/pages/ajax.render.php
index 66e5b1931..440f8bb8e 100644
--- a/pages/ajax.render.php
+++ b/pages/ajax.render.php
@@ -1103,7 +1103,7 @@ EOF
$aParams = utils::ReadParam('params', '', false, 'raw_data');
$sDashletClass = $aParams['attr_dashlet_class'];
$sDashletType = $aParams['attr_dashlet_type'];
- $sDashletId = $aParams['attr_dashlet_id'];
+ $sDashletId = utils::HtmlEntities($aParams['attr_dashlet_id']);
$aUpdatedProperties = $aParams['updated']; // Code of the changed properties as an array: 'attr_xxx', 'attr_xxy', etc...
$aPreviousValues = $aParams['previous_values']; // hash array: 'attr_xxx' => 'old_value'
if (is_subclass_of($sDashletClass, 'Dashlet')) {
diff --git a/test/twig/TwigTest.php b/test/twig/TwigTest.php
index 1457b30f6..f47bc10be 100644
--- a/test/twig/TwigTest.php
+++ b/test/twig/TwigTest.php
@@ -1,33 +1,55 @@
render($sFileName.'.twig');
- $this->assertSame($sHtml, $expected);
+ // Creating sandbox twig env. to load and test the custom form template
+ $oTwig = new Twig_Environment(new Twig_Loader_Array([$sId => $sFileName]));
+
+ // Manually registering filters and functions as we didn't find how to do it automatically
+ $aFilters = $oAppExtension->getFilters();
+ foreach ($aFilters as $oFilter)
+ {
+ $oTwig->addFilter($oFilter);
+ }
+ $aFunctions = $oAppExtension->getFunctions();
+ foreach ($aFunctions as $oFunction)
+ {
+ $oTwig->addFunction($oFunction);
+ }
+
+ $sHtml = $oTwig->render($sId, ['AttackerURL' => 'file://'.__DIR__.'/attacker']);
+
+ $this->assertEquals($sExpected, $sHtml);
}
- public static function testTemplateProvider()
+ public static function TemplateProvider()
{
$aReturn = array();
$aReturn['filter_system'] = [
- 'sFileName' => 'test.html',
- 'expected' =>file_get_contents(dirname(__FILE__).'/test.html'),
+ 'sFileName' => file_get_contents(__DIR__.'/test.html.twig'),
+ 'expected' => file_get_contents(__DIR__.'/test.html'),
];
return $aReturn;
diff --git a/test/twig/attacker/backdoor b/test/twig/attacker/backdoor
new file mode 100644
index 000000000..f56435e7a
--- /dev/null
+++ b/test/twig/attacker/backdoor
@@ -0,0 +1 @@
+!!! BACKDOOR !!!
\ No newline at end of file
diff --git a/test/twig/test.html b/test/twig/test.html
index 06cd232d3..2406bbfd4 100644
--- a/test/twig/test.html
+++ b/test/twig/test.html
@@ -1,12 +1,33 @@
- User Name
-
-
- ["id"]
-
-
- ["touch+\/tmp\/test+"]
-
-
- 40, 42
-
\ No newline at end of file
+ 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
diff --git a/test/twig/test.html.twig b/test/twig/test.html.twig
index b2ae9dd5a..5825249c3 100644
--- a/test/twig/test.html.twig
+++ b/test/twig/test.html.twig
@@ -1,13 +1,41 @@
-
- {{ 'UI:Login:UserNamePrompt'|dict_s }}
-
-
- {{['id']|filter('system')}}
-
-
- {{['touch+/tmp/test+']|filter('system')|join(',')}}
-
-
-{% set sizes = [34, 36, 38, 40, 42] %}
- {{ sizes|filter(v => v > 38)|join(', ') }}
-
\ No newline at end of file
+{% 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
diff --git a/webservices/export-v2.php b/webservices/export-v2.php
index 5bf17f629..d7338a3cf 100644
--- a/webservices/export-v2.php
+++ b/webservices/export-v2.php
@@ -14,7 +14,6 @@ use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectOptionUIBlockF
use Combodo\iTop\Application\UI\Base\Component\Input\SelectUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Input\TextArea;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
-use Combodo\iTop\Application\UI\Base\Component\Title\TitleUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
if (!defined('__DIR__')) {
@@ -27,19 +26,15 @@ require_once(APPROOT.'/core/bulkexport.class.inc.php');
require_once(APPROOT.'/application/startup.inc.php');
-
-
const EXIT_CODE_ERROR = -1;
const EXIT_CODE_FATAL = -2;
-
-
function ReportErrorAndExit($sErrorMessage)
{
if (utils::IsModeCLI())
{
$oP = new CLIPage("iTop - Export");
- $oP->p('ERROR: '.$sErrorMessage);
+ $oP->p('ERROR: '.utils::HtmlEntities($sErrorMessage));
$oP->output();
exit(EXIT_CODE_ERROR);
}
@@ -47,7 +42,7 @@ function ReportErrorAndExit($sErrorMessage)
{
$oP = new WebPage("iTop - Export");
$oP->add_xframe_options();
- $oP->p('ERROR: '.$sErrorMessage);
+ $oP->p('ERROR: '.utils::HtmlEntities($sErrorMessage));
$oP->output();
exit(EXIT_CODE_ERROR);
}