diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php b/rainloop/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php
index b38670d80..0a3c96b94 100644
--- a/rainloop/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php
+++ b/rainloop/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php
@@ -272,7 +272,7 @@ class HtmlUtils
$sHtml = \str_replace('', '', $sHtml);
}
- $sHtml = \str_replace('', '', $sHtml);
+ $sHtml = \str_replace('', '', $sHtml);
$sHtml = \str_replace('', '', $sHtml);
return $sHtml;
@@ -337,16 +337,23 @@ class HtmlUtils
$aRemoveTags[] = 'style';
}
+ $aHtmlAllowedTags = isset(\MailSo\Config::$HtmlStrictAllowedTags) &&
+ \is_array(\MailSo\Config::$HtmlStrictAllowedTags) && 0 < \count(\MailSo\Config::$HtmlStrictAllowedTags) ?
+ \MailSo\Config::$HtmlStrictAllowedTags : null;
+
$aRemove = array();
$aNodes = $oDom->getElementsByTagName('*');
foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement)
{
if ($oElement)
{
- $sTagNameLower = \strtolower($oElement->tagName);
- if ('' !== $sTagNameLower && \in_array($sTagNameLower, $aRemoveTags))
+ $sTagNameLower = \trim(\strtolower($oElement->tagName));
+ if ('' !== $sTagNameLower)
{
- $aRemove[] = @$oElement;
+ if (\in_array($sTagNameLower, $aRemoveTags) || ($aHtmlAllowedTags && !\in_array($sTagNameLower, $aHtmlAllowedTags)))
+ {
+ $aRemove[] = @$oElement;
+ }
}
}
}
@@ -913,6 +920,7 @@ class HtmlUtils
$aNodes = $oDom->getElementsByTagName('*');
foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement)
{
+ $aRemovedAttrs = array();
$sTagNameLower = \strtolower($oElement->tagName);
// convert body attributes to styles
@@ -929,14 +937,14 @@ class HtmlUtils
if (isset($oElement->attributes))
{
- foreach ($oElement->attributes as $sAttributeName => /* @var $oAttributeNode \DOMNode */ $oAttributeNode)
+ foreach ($oElement->attributes as $sAttrName => /* @var $oAttributeNode \DOMNode */ $oAttributeNode)
{
if ($oAttributeNode && isset($oAttributeNode->nodeValue))
{
- $sAttributeNameLower = \strtolower($sAttributeName);
- if (isset($aAttrs[$sAttributeNameLower]) && '' === $aAttrs[$sAttributeNameLower])
+ $sAttrNameLower = \trim(\strtolower($sAttrName));
+ if (isset($aAttrs[$sAttrNameLower]) && '' === $aAttrs[$sAttrNameLower])
{
- $aAttrs[$sAttributeNameLower] = array($sAttributeName, \trim($oAttributeNode->nodeValue));
+ $aAttrs[$sAttrNameLower] = array($sAttrName, \trim($oAttributeNode->nodeValue));
}
}
}
@@ -998,33 +1006,43 @@ class HtmlUtils
'color: '.$sLinkColor.\trim((empty($sStyles) ? '' : '; '.$sStyles)));
}
- if (\in_array($sTagNameLower, array('a', 'form', 'area')))
- {
- $oElement->setAttribute('target', '_blank');
- }
-
- if (\in_array($sTagNameLower, array('a', 'form', 'area', 'input', 'button', 'textarea')))
- {
- $oElement->setAttribute('tabindex', '-1');
- }
-
if ($oElement->hasAttributes() && isset($oElement->attributes) && $oElement->attributes)
{
- foreach ($oElement->attributes as $oAttr)
+ $aHtmlAllowedAttributes = isset(\MailSo\Config::$HtmlStrictAllowedAttributes) &&
+ \is_array(\MailSo\Config::$HtmlStrictAllowedAttributes) && 0 < \count(\MailSo\Config::$HtmlStrictAllowedAttributes) ?
+ \MailSo\Config::$HtmlStrictAllowedAttributes : null;
+
+ $sAttrsForRemove = array();
+ foreach ($oElement->attributes as $sAttrName => $oAttr)
{
- if ($oAttr && !empty($oAttr->nodeName))
+ if ($sAttrName && $oAttr)
{
- $sAttrName = \trim(\strtolower($oAttr->nodeName));
- if ('on' === \substr($sAttrName, 0, 2) || in_array($sAttrName, array(
- 'id', 'class', 'contenteditable', 'designmode', 'formaction', 'manifest',
+ $sAttrNameLower = \trim(\strtolower($sAttrName));
+ if ($aHtmlAllowedAttributes && !\in_array($sAttrNameLower, $aHtmlAllowedAttributes))
+ {
+ $sAttrsForRemove[] = $sAttrName;
+ }
+ else if ('on' === \substr($sAttrNameLower, 0, 2) || in_array($sAttrNameLower, array(
+ 'id', 'class', 'contenteditable', 'designmode', 'formaction', 'manifest', 'action',
'data-bind', 'data-reactid', 'xmlns', 'srcset', 'data-x-skip-style',
'fscommand', 'seeksegmenttime'
)))
{
- @$oElement->removeAttribute($oAttr->nodeName);
+ $sAttrsForRemove[] = $sAttrName;
}
}
}
+
+ if (0 < \count($sAttrsForRemove))
+ {
+ foreach ($sAttrsForRemove as $sName)
+ {
+ @$oElement->removeAttribute($sName);
+ $aRemovedAttrs[\trim(\strtolower($sName))] = true;
+ }
+ }
+
+ unset($sAttrsForRemove);
}
if ($oElement->hasAttribute('href'))
@@ -1038,10 +1056,20 @@ class HtmlUtils
if ('a' === $sTagNameLower)
{
- $oElement->setAttribute('rel', 'external nofollow');
+ $oElement->setAttribute('rel', 'external nofollow noopener noreferrer');
}
}
+ if (\in_array($sTagNameLower, array('a', 'form', 'area')))
+ {
+ $oElement->setAttribute('target', '_blank');
+ }
+
+ if (\in_array($sTagNameLower, array('a', 'form', 'area', 'input', 'button', 'textarea')))
+ {
+ $oElement->setAttribute('tabindex', '-1');
+ }
+
if ($bTryToDetectHiddenImages && 'img' === $sTagNameLower)
{
$sAlt = $oElement->hasAttribute('alt')
@@ -1177,6 +1205,17 @@ class HtmlUtils
}
$oElement->removeAttribute('data-x-skip-style');
+
+ if (\MailSo\Config::$HtmlStrictDebug && 0 < \count($aRemovedAttrs))
+ {
+ unset($aRemovedAttrs['class'], $aRemovedAttrs['target'], $aRemovedAttrs['id'], $aRemovedAttrs['name']);
+
+ $aRemovedAttrs = \array_keys($aRemovedAttrs);
+ if (0 < \count($aRemovedAttrs))
+ {
+ $oElement->setAttribute('data-removed-attrs', \implode(',', $aRemovedAttrs));
+ }
+ }
}
$sResult = \MailSo\Base\HtmlUtils::GetTextFromDom($oDom, $bWrapByFakeHtmlAndBodyDiv);
@@ -1251,16 +1290,6 @@ class HtmlUtils
$oElement->removeAttribute('data-x-href');
}
- if ($oElement->hasAttribute('data-x-additional-src'))
- {
- $oElement->removeAttribute('data-x-additional-src');
- }
-
- if ($oElement->hasAttribute('data-x-additional-style-url'))
- {
- $oElement->removeAttribute('data-x-additional-style-url');
- }
-
if ($oElement->hasAttribute('data-x-style-cid-name') && $oElement->hasAttribute('data-x-style-cid'))
{
$sCidName = $oElement->getAttribute('data-x-style-cid-name');
@@ -1290,14 +1319,15 @@ class HtmlUtils
}
}
- if ($oElement->hasAttribute('data-original'))
+ foreach (array(
+ 'data-x-additional-src', 'data-x-additional-style-url', 'data-removed-attrs',
+ 'data-original', 'data-x-div-type', 'data-wrp', 'data-bind'
+ ) as $sName)
{
- $oElement->removeAttribute('data-original');
- }
-
- if ($oElement->hasAttribute('data-x-div-type'))
- {
- $oElement->removeAttribute('data-x-div-type');
+ if ($oElement->hasAttribute($sName))
+ {
+ $oElement->removeAttribute($sName);
+ }
}
if ($oElement->hasAttribute('data-x-style-url'))
diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Config.php b/rainloop/v/0.0.0/app/libraries/MailSo/Config.php
index f5b84ab45..3ffb0f5db 100644
--- a/rainloop/v/0.0.0/app/libraries/MailSo/Config.php
+++ b/rainloop/v/0.0.0/app/libraries/MailSo/Config.php
@@ -26,6 +26,21 @@ class Config
*/
public static $MBSTRING = true;
+ /**
+ * @var array|null
+ */
+ public static $HtmlStrictAllowedTags = null;
+
+ /**
+ * @var array|null
+ */
+ public static $HtmlStrictAllowedAttributes = null;
+
+ /**
+ * @var boolean
+ */
+ public static $HtmlStrictDebug = false;
+
/**
* @var bool
*/
diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php
index ff44a088f..c9e4d3fb3 100644
--- a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php
+++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php
@@ -9968,24 +9968,6 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack
$mResult['InReplyTo'] = $mResponse->InReplyTo();
$mResult['References'] = $mResponse->References();
- $fAdditionalDomReader = null;
- if (0 < \strlen($sHtml) && $this->Config()->Get('labs', 'emogrifier', false))
- {
- if (!\class_exists('RainLoopVendor\Pelago\Emogrifier', false))
- {
- include_once APP_VERSION_ROOT_PATH.'app/libraries/emogrifier/Emogrifier.php';
- }
-
- if (\class_exists('RainLoopVendor\Pelago\Emogrifier', false))
- {
- $fAdditionalDomReader = function ($oDom) {
- $oEmogrifier = new \RainLoopVendor\Pelago\Emogrifier();
- $oEmogrifier->preserveEncoding = false;
- return $oEmogrifier->emogrify($oDom);
- };
- }
- }
-
$fAdditionalExternalFilter = null;
if (!!$this->Config()->Get('labs', 'use_local_proxy_for_external_images', false))
{
@@ -10004,8 +9986,7 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack
$mResult['Html'] = 0 === \strlen($sHtml) ? '' : \MailSo\Base\HtmlUtils::ClearHtml(
$sHtml, $bHasExternals, $mFoundedCIDs, $aContentLocationUrls, $mFoundedContentLocationUrls, false, false,
- $fAdditionalExternalFilter, $fAdditionalDomReader,
- !!$this->Config()->Get('labs', 'try_to_detect_hidden_images', false)
+ $fAdditionalExternalFilter, null, !!$this->Config()->Get('labs', 'try_to_detect_hidden_images', false)
);
$mResult['ExternalProxy'] = null !== $fAdditionalExternalFilter;
diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php
index 04af66ea2..2bf4f75e0 100644
--- a/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php
+++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php
@@ -134,6 +134,52 @@ class Api
}
});
}
+
+ \MailSo\Config::$HtmlStrictDebug = !!\RainLoop\Api::Config()->Get('debug', 'enable', false);
+
+ if (\RainLoop\Api::Config()->Get('labs', 'strict_html_parser', true))
+ {
+ \MailSo\Config::$HtmlStrictAllowedAttributes = array(
+ // rainloop
+ 'data-wrp',
+ // defaults
+ 'name',
+ 'dir', 'lang', 'style', 'title',
+ 'background', 'bgcolor', 'alt', 'height', 'width', 'src', 'href',
+ 'border', 'bordercolor', 'charset', 'direction', 'language',
+ // a
+ 'coords', 'download', 'hreflang', 'shape',
+ // body
+ 'alink', 'bgproperties', 'bottommargin', 'leftmargin', 'link', 'rightmargin', 'text', 'topmargin', 'vlink',
+ 'marginwidth', 'marginheight', 'offset',
+ // button,
+ 'disabled', 'type', 'value',
+ // col
+ 'align', 'valign',
+ // font
+ 'color', 'face', 'size',
+ // form
+ 'novalidate',
+ // hr
+ 'noshade',
+ // img
+ 'hspace', 'sizes', 'srcset', 'vspace', 'usemap',
+ // input, textarea
+ 'checked', 'max', 'min', 'maxlength', 'multiple', 'pattern', 'placeholder', 'readonly', 'required', 'step', 'wrap',
+ // label
+ 'for',
+ // meter
+ 'low', 'high', 'optimum',
+ // ol
+ 'reversed', 'start',
+ // option
+ 'selected', 'label',
+ // table
+ 'cols', 'rows', 'frame', 'rules', 'summary', 'cellpadding', 'cellspacing',
+ // td
+ 'abbr', 'axis', 'colspan', 'rowspan', 'headers', 'nowrap'
+ );
+ }
}
}
diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php
index 7e0bac54c..15b589e1d 100644
--- a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php
+++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php
@@ -446,8 +446,8 @@ Enables caching in the system'),
'cookie_default_secure' => array(false),
'replace_env_in_configuration' => array(''),
'startup_url' => array(''),
- 'emogrifier' => array(true),
'nice_social_redirect' => array(true),
+ 'strict_html_parser' => array(false),
'dev_email' => array(''),
'dev_password' => array('')
),
diff --git a/rainloop/v/0.0.0/app/libraries/emogrifier/CHANGELOG.TXT b/rainloop/v/0.0.0/app/libraries/emogrifier/CHANGELOG.TXT
deleted file mode 100644
index 55c062e72..000000000
--- a/rainloop/v/0.0.0/app/libraries/emogrifier/CHANGELOG.TXT
+++ /dev/null
@@ -1,73 +0,0 @@
-2012-05-01
-Made removal of invisible nodes operate in a case-insensitive manner... Thanks Juha P.!
-
-2012-02-07
-Fixed some recent code introductions to use class constants rather than global constants.
-Fixed some recent code introductions to make it cleaner to read.
-
-2012-01-31
-Fixed a bug that was introduced with the 2011-12-22 revision... Thanks Sagi L. and M. Bąkowski!
-Added extraction of