mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-23 10:38:45 +02:00
Merge remote-tracking branch 'origin/support/2.7' into develop
# Conflicts: # datamodels/2.x/itop-portal-base/portal/src/Helper/ObjectFormHandlerHelper.php # datamodels/2.x/itop-portal-base/portal/templates/layout.html.twig
This commit is contained in:
@@ -1128,7 +1128,7 @@ class Config
|
||||
'svg_sanitizer' => [
|
||||
'type' => 'string',
|
||||
'description' => 'The class to use for SVG sanitization : allow to provide a custom made sanitizer',
|
||||
'default' => 'SvgDOMSanitizer',
|
||||
'default' => 'SVGDOMSanitizer',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
|
||||
@@ -419,7 +419,7 @@ class HTMLDOMSanitizer extends DOMSanitizer
|
||||
/**
|
||||
* @since 2.6.5 2.7.6 3.0.0 N°4360
|
||||
*/
|
||||
class SvgDOMSanitizer extends DOMSanitizer
|
||||
class SVGDOMSanitizer extends DOMSanitizer
|
||||
{
|
||||
public function GetTagsWhiteList()
|
||||
{
|
||||
|
||||
@@ -178,6 +178,12 @@ SQL;
|
||||
SetupLog::Info("Initializing attachment/item_org_id - zero to the container");
|
||||
$oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE item_org_id = 0");
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$oSet->OptimizeColumnLoad([
|
||||
'Attachment' => [
|
||||
'item_class',
|
||||
'item_id',
|
||||
]
|
||||
]);
|
||||
$iUpdated = 0;
|
||||
while ($oAttachment = $oSet->Fetch())
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Combodo\iTop\Portal\Form;
|
||||
|
||||
use AttachmentPlugIn;
|
||||
use AttributeDateTime;
|
||||
use AttributeTagSet;
|
||||
use AttributeSet;
|
||||
use CMDBChangeOpAttachmentAdded;
|
||||
use CMDBChangeOpAttachmentRemoved;
|
||||
use Combodo\iTop\Form\Field\Field;
|
||||
@@ -42,7 +42,6 @@ use Exception;
|
||||
use InlineImage;
|
||||
use IssueLog;
|
||||
use MetaModel;
|
||||
use ormTagSet;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
@@ -91,26 +90,34 @@ class ObjectFormManager extends FormManager
|
||||
* - formmode : view|edit|create
|
||||
* - values for parent
|
||||
*
|
||||
* @param bool $bTrustContent if false then won't allow TWIG content
|
||||
*
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
* @throws \SecurityException if twig content is present and $bTrustContent is false
|
||||
*/
|
||||
static function FromJSON($sJson)
|
||||
public static function FromJSON($sJson, $bTrustContent = false)
|
||||
{
|
||||
if (is_array($sJson))
|
||||
{
|
||||
if (is_array($sJson)) {
|
||||
$aJson = $sJson;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aJson = json_decode($sJson, true);
|
||||
}
|
||||
|
||||
if (false === $bTrustContent) {
|
||||
/** @noinspection NestedPositiveIfStatementsInspection */
|
||||
if (isset($aJson['formproperties']['layout']['type']) && ($aJson['formproperties']['layout']['type'] === 'twig')) {
|
||||
// There will be an IssueLog above in the hierarchy due to the exception, but we are logging here so that we can output the JSON data !
|
||||
IssueLog::Error('Portal received a query with forbidden twig content!', \LogChannels::PORTAL, ['formmanager_data' => $aJson]);
|
||||
throw new \SecurityException('Twig content not allowed in this context!');
|
||||
}
|
||||
}
|
||||
|
||||
/** @var \Combodo\iTop\Portal\Form\ObjectFormManager $oFormManager */
|
||||
$oFormManager = parent::FromJSON($sJson);
|
||||
|
||||
// Retrieving object to edit
|
||||
if (!isset($aJson['formobject_class']))
|
||||
{
|
||||
if (!isset($aJson['formobject_class'])) {
|
||||
throw new Exception('Object class must be defined in order to generate the form');
|
||||
}
|
||||
$sObjectClass = $aJson['formobject_class'];
|
||||
@@ -151,14 +158,44 @@ class ObjectFormManager extends FormManager
|
||||
}
|
||||
|
||||
// Retrieving callback urls
|
||||
if (!isset($aJson['formcallbacks']))
|
||||
{
|
||||
if (!isset($aJson['formcallbacks'])) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
return $oFormManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sPostedFormManagerData received data from the browser
|
||||
* @param array $aOriginalFormProperties data generated server side
|
||||
*
|
||||
* @return bool true if the data are identical
|
||||
*
|
||||
* @since 2.7.6 3.0.0 N°4384 check formmanager_data
|
||||
*/
|
||||
public static function CanTrustFormLayoutContent($sPostedFormManagerData, $aOriginalFormProperties)
|
||||
{
|
||||
$aPostedFormManagerData = json_decode($sPostedFormManagerData, true);
|
||||
$sPostedFormLayoutType = (isset($aPostedFormManagerData['formproperties']['layout']['type'])) ? $aPostedFormManagerData['formproperties']['layout']['type'] : '';
|
||||
|
||||
if ($sPostedFormLayoutType === 'xhtml') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// we need to parse the content so that autoclose tags are returned correctly (`<div />` => `<div></div>`)
|
||||
$oHtmlDocument = new \DOMDocument();
|
||||
|
||||
$sPostedFormLayoutContent = (isset($aPostedFormManagerData['formproperties']['layout']['content'])) ? $aPostedFormManagerData['formproperties']['layout']['content'] : '';
|
||||
$oHtmlDocument->loadXML('<root>'.$sPostedFormLayoutContent.'</root>');
|
||||
$sPostedFormLayoutRendered = $oHtmlDocument->saveHTML();
|
||||
|
||||
$sOriginalFormLayoutContent = (isset($aOriginalFormProperties['layout']['content'])) ? $aOriginalFormProperties['layout']['content'] : '';
|
||||
$oHtmlDocument->loadXML('<root>'.$sOriginalFormLayoutContent.'</root>');
|
||||
$sOriginalFormLayoutContentRendered = $oHtmlDocument->saveHTML();
|
||||
|
||||
return ($sPostedFormLayoutRendered === $sOriginalFormLayoutContentRendered);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return \Symfony\Component\DependencyInjection\ContainerInterface
|
||||
@@ -1299,25 +1336,19 @@ class ObjectFormManager extends FormManager
|
||||
|
||||
// Setting value in the object
|
||||
$this->oObject->Set($sAttCode, $oLinkSet);
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeTagSet)
|
||||
{
|
||||
/** @var \ormTagSet $oTagSet */
|
||||
$oTagSet = $this->oObject->Get($sAttCode);
|
||||
if (is_null($oTagSet))
|
||||
{
|
||||
$oTagSet = new ormTagSet(get_class($this->oObject), $sAttCode, $oAttDef->GetMaxItems());
|
||||
} elseif ($oAttDef instanceof AttributeSet) {
|
||||
/** @var \ormSet $oTagSet */
|
||||
$oOrmSet = $this->oObject->Get($sAttCode);
|
||||
if (is_null($oOrmSet)) {
|
||||
$oOrmSet = new \ormSet(get_class($this->oObject), $sAttCode, $oAttDef->GetMaxItems());
|
||||
}
|
||||
$oTagSet->ApplyDelta(json_decode($value, true));
|
||||
$this->oObject->Set($sAttCode, $oTagSet);
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime
|
||||
$oOrmSet->ApplyDelta(json_decode($value, true));
|
||||
$this->oObject->Set($sAttCode, $oOrmSet);
|
||||
} elseif ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime
|
||||
{
|
||||
if ($value != null)
|
||||
{
|
||||
if ($value != null) {
|
||||
$value = $oAttDef->GetFormat()->Parse($value);
|
||||
if (is_object($value))
|
||||
{
|
||||
if (is_object($value)) {
|
||||
$value = $value->format($oAttDef->GetInternalFormat());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,10 +108,10 @@ class ObjectFormHandlerHelper
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\HttpFoundation\Request $oRequest
|
||||
* @param string $sMode
|
||||
* @param string $sObjectClass
|
||||
* @param string $sObjectId
|
||||
* @param string $aFormProperties
|
||||
* @param string $sMode
|
||||
* @param string $sObjectClass
|
||||
* @param string $sObjectId
|
||||
* @param array $aFormProperties
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
@@ -127,9 +127,10 @@ class ObjectFormHandlerHelper
|
||||
$bModal = ($oRequest->isXmlHttpRequest() && empty($sOperation));
|
||||
|
||||
// - Retrieve form properties
|
||||
$aOriginalFormProperties = ApplicationHelper::GetLoadedFormFromClass($this->aCombodoPortalInstanceConf['forms'], $sObjectClass, $sMode);
|
||||
if ($aFormProperties === null)
|
||||
{
|
||||
$aFormProperties = ApplicationHelper::GetLoadedFormFromClass($this->aCombodoPortalInstanceConf['forms'], $sObjectClass, $sMode);
|
||||
$aFormProperties = $aOriginalFormProperties;
|
||||
}
|
||||
|
||||
// - Create and
|
||||
@@ -281,12 +282,11 @@ class ObjectFormHandlerHelper
|
||||
|
||||
$oFormManager->Build();
|
||||
$aFormData['hidden_fields'] = $oFormManager->GetHiddenFieldsId();
|
||||
// Check the number of editable fields
|
||||
// Check the number of editable fields
|
||||
$aFormData['editable_fields_count'] = $oFormManager->GetForm()->GetEditableFieldCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Update / Submit / Cancel
|
||||
/** @var \Combodo\iTop\Portal\Form\ObjectFormManager $sFormManagerClass */
|
||||
$sFormManagerClass = $this->oRequestManipulator->ReadParam('formmanager_class', '', FILTER_UNSAFE_RAW);
|
||||
$sFormManagerData = $this->oRequestManipulator->ReadParam('formmanager_data', '', FILTER_UNSAFE_RAW);
|
||||
if (empty($sFormManagerClass) || empty($sFormManagerData))
|
||||
@@ -295,13 +295,12 @@ class ObjectFormHandlerHelper
|
||||
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'Parameters formmanager_class and formmanager_data must be defined.');
|
||||
}
|
||||
|
||||
/** @var \Combodo\iTop\Portal\Form\ObjectFormManager $oFormManager */
|
||||
$oFormManager = $sFormManagerClass::FromJSON($sFormManagerData);
|
||||
$bTrustContent = $sFormManagerClass::CanTrustFormLayoutContent($sFormManagerData, $aOriginalFormProperties);
|
||||
$oFormManager = $sFormManagerClass::FromJSON($sFormManagerData, $bTrustContent);
|
||||
$oFormManager->SetContainer($this->oContainer);
|
||||
|
||||
// Applying action rules if present
|
||||
if (($oFormManager->GetActionRulesToken() !== null) && ($oFormManager->GetActionRulesToken() !== ''))
|
||||
{
|
||||
if (($oFormManager->GetActionRulesToken() !== null) && ($oFormManager->GetActionRulesToken() !== '')) {
|
||||
$aActionRules = ContextManipulatorHelper::DecodeRulesToken($oFormManager->GetActionRulesToken());
|
||||
$oObj = $oFormManager->GetObject();
|
||||
$this->oContextManipulator->PrepareObject($aActionRules, $oObj);
|
||||
|
||||
@@ -40,7 +40,8 @@ abstract class FormManager
|
||||
* - formrenderer_class : The class of the FormRenderer to use in the FormManager
|
||||
* - formrenderer_endpoint : The endpoint of the renderer
|
||||
*
|
||||
* @param string $sJson
|
||||
* @param string|string[] $sJson
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
static function FromJSON($sJson)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core\Sanitizer;
|
||||
|
||||
use SvgDOMSanitizer;
|
||||
use SVGDOMSanitizer;
|
||||
|
||||
|
||||
require_once __DIR__.'/AbstractDOMSanitizerTest.php';
|
||||
@@ -13,7 +13,7 @@ require_once __DIR__.'/AbstractDOMSanitizerTest.php';
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class SvgDOMSanitizerTest extends AbstractDOMSanitizerTest
|
||||
class SVGDOMSanitizerTest extends AbstractDOMSanitizerTest
|
||||
{
|
||||
/**
|
||||
* @dataProvider DoSanitizeProvider
|
||||
@@ -26,7 +26,7 @@ class SvgDOMSanitizerTest extends AbstractDOMSanitizerTest
|
||||
$sOutputHtml = $this->ReadTestFile($sFileToTest, self::OUTPUT_DIRECTORY);
|
||||
$sOutputHtml = $this->RemoveNewLines($sOutputHtml);
|
||||
|
||||
$oSanitizer = new SvgDOMSanitizer();
|
||||
$oSanitizer = new SVGDOMSanitizer();
|
||||
$sRes = $oSanitizer->DoSanitize($sInputHtml);
|
||||
|
||||
// Removing newlines as the parser gives different results depending on the PHP version
|
||||
|
||||
Reference in New Issue
Block a user