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 */