From 0aab80917a14e26af821fac2c0dc1e87bbe1fded Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Wed, 30 Jan 2019 09:44:38 +0100 Subject: [PATCH] =?UTF-8?q?N=C2=B01921=20Process=20InlineImage=20from=20an?= =?UTF-8?q?other=20iTop=20as=20external=20images=20*=20Notifications=20:?= =?UTF-8?q?=20do=20not=20embed=20InlineImage=20with=20wrong=20secret=20*?= =?UTF-8?q?=20HtmlSanitizer=20:=20remove=20data-img-*=20attributes=20if=20?= =?UTF-8?q?not=20the=20same=20iTop=20(using=20approot=20from=20Config)=20*?= =?UTF-8?q?=20move=20\HTMLDOMSanitizer::ProcessImage=20to=20\InlineImage::?= =?UTF-8?q?ProcessImageTag=20*=20data-img-*=20attributes=20name=20are=20no?= =?UTF-8?q?w=20InlineImage=20class=20constants?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/email.class.inc.php | 17 +++++++++--- core/htmlsanitizer.class.inc.php | 21 ++------------- core/inlineimage.class.inc.php | 44 +++++++++++++++++++++++++++++++- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/core/email.class.inc.php b/core/email.class.inc.php index 3f6616f71..b8fd2a2ec 100644 --- a/core/email.class.inc.php +++ b/core/email.class.inc.php @@ -234,19 +234,28 @@ class EMail $oDOMDoc = new DOMDocument(); $oDOMDoc->preserveWhitespace = true; @$oDOMDoc->loadHTML(''.$this->m_aData['body']['body']); // For loading HTML chunks where the character set is not specified - + $oXPath = new DOMXPath($oDOMDoc); - $sXPath = "//img[@data-img-id]"; + $sXPath = '//img[@'.InlineImage::DOM_ATTR_ID.']'; $oImagesList = $oXPath->query($sXPath); - + if ($oImagesList->length != 0) { foreach($oImagesList as $oImg) { - $iAttId = $oImg->getAttribute('data-img-id'); + $iAttId = $oImg->getAttribute(InlineImage::DOM_ATTR_ID); $oAttachment = MetaModel::GetObject('InlineImage', $iAttId, false, true /* Allow All Data */); if ($oAttachment) { + $sImageSecret = $oImg->getAttribute('data-img-secret'); + $sAttachmentSecret = $oAttachment->Get('secret'); + if ($sImageSecret !== $sAttachmentSecret) + { + // @see N°1921 + // If copying from another iTop we could get an IMG pointing to an InlineImage with wrong secret + continue; + } + $oDoc = $oAttachment->Get('contents'); $oSwiftImage = new Swift_Image($oDoc->GetData(), $oDoc->GetFileName(), $oDoc->GetMimeType()); $sCid = $this->m_oMessage->embed($oSwiftImage); diff --git a/core/htmlsanitizer.class.inc.php b/core/htmlsanitizer.class.inc.php index cbb5c8804..7746b797a 100644 --- a/core/htmlsanitizer.class.inc.php +++ b/core/htmlsanitizer.class.inc.php @@ -346,7 +346,7 @@ class HTMLDOMSanitizer extends HTMLSanitizer $this->CleanNode($oNode); if (($oNode instanceof DOMElement) && (strtolower($oNode->tagName) == 'img')) { - $this->ProcessImage($oNode); + InlineImage::ProcessImageTag($oNode); } } } @@ -357,24 +357,7 @@ class HTMLDOMSanitizer extends HTMLSanitizer } } } - - /** - * Add an extra attribute data-img-id for images which are based on an actual InlineImage - * so that we can later reconstruct the full "src" URL when needed - * @param DOMNode $oElement - */ - protected function ProcessImage(DOMNode $oElement) - { - $sSrc = $oElement->getAttribute('src'); - $sDownloadUrl = str_replace(array('.', '?'), array('\.', '\?'), INLINEIMAGE_DOWNLOAD_URL); // Escape . and ? - $sUrlPattern = '|'.$sDownloadUrl.'([0-9]+)&s=([0-9a-f]+)|'; - if (preg_match($sUrlPattern, $sSrc, $aMatches)) - { - $oElement->setAttribute('data-img-id', $aMatches[1]); - $oElement->setAttribute('data-img-secret', $aMatches[2]); - } - } - + protected function CleanStyle($sStyle) { $aAllowedStyles = array(); diff --git a/core/inlineimage.class.inc.php b/core/inlineimage.class.inc.php index 690616ca6..5fd242de4 100644 --- a/core/inlineimage.class.inc.php +++ b/core/inlineimage.class.inc.php @@ -27,6 +27,11 @@ define('INLINEIMAGE_DOWNLOAD_URL', 'pages/ajax.document.php?operation=download_i class InlineImage extends DBObject { + /** @var string attribute to be added to IMG tags to contain ID */ + const DOM_ATTR_ID = 'data-img-id'; + /** @var string attribute to be added to IMG tags to contain secret */ + const DOM_ATTR_SECRET = 'data-img-secret'; + public static function Init() { $aParams = array @@ -208,7 +213,8 @@ class InlineImage extends DBObject $aNeedles = array(); $aReplacements = array(); // Find img tags with an attribute data-img-id - if (preg_match_all('/]*)data-img-id="([0-9]+)"([^>]*)>/i', $sHtml, $aMatches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) + if (preg_match_all('/]*)'.self::DOM_ATTR_ID.'="([0-9]+)"([^>]*)>/i', + $sHtml, $aMatches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { $sUrl = utils::GetAbsoluteUrlAppRoot().INLINEIMAGE_DOWNLOAD_URL; foreach($aMatches as $aImgInfo) @@ -230,6 +236,42 @@ class InlineImage extends DBObject return $sHtml; } + /** + * Add an extra attribute data-img-id for images which are based on an actual InlineImage + * so that we can later reconstruct the full "src" URL when needed + * + * @param \DOMElement $oElement + */ + public static function ProcessImageTag(DOMElement $oElement) + { + $sSrc = $oElement->getAttribute('src'); + $sDownloadUrl = str_replace(array('.', '?'), array('\.', '\?'), INLINEIMAGE_DOWNLOAD_URL); // Escape . and ? + $sUrlPattern = '|'.$sDownloadUrl.'([0-9]+)&s=([0-9a-f]+)|'; + $bIsInlineImage = preg_match($sUrlPattern, $sSrc, $aMatches); + if (!$bIsInlineImage) + { + return; + } + $iInlineImageId = $aMatches[1]; + $sInlineIMageSecret = $aMatches[2]; + + $sAppRoot = utils::GetAbsoluteUrlAppRoot(); + $sAppRootPattern = '/^'.preg_quote($sAppRoot, '/').'/'; + $bIsSameItop = preg_match($sAppRootPattern, $sSrc); + if (!$bIsSameItop) + { + // @see N°1921 + // image from another iTop should be treated as external images + $oElement->removeAttribute(self::DOM_ATTR_ID); + $oElement->removeAttribute(self::DOM_ATTR_SECRET); + + return; + } + + $oElement->setAttribute(self::DOM_ATTR_ID, $iInlineImageId); + $oElement->setAttribute(self::DOM_ATTR_SECRET, $sInlineIMageSecret); + } + /** * Get the javascript fragment - to be added to "on document ready" - to adjust (on the fly) the width on Inline Images */