diff options
author | Richard Steinmetz <richard@steinmetz.cloud> | 2021-06-16 12:05:53 +0300 |
---|---|---|
committer | Richard Steinmetz <richard@steinmetz.cloud> | 2021-06-16 14:37:43 +0300 |
commit | 4bdcc023a36eca8000e08249cbaba086ee42a328 (patch) | |
tree | b4af7374f9347afd874c7f117b90f81cc66c7708 /lib/Service | |
parent | 70f08fda44dd8e0f107ef4989cc536dc04fe554a (diff) |
Sanitize urls in css style sheets
Signed-off-by: Richard Steinmetz <richard@steinmetz.cloud>
Diffstat (limited to 'lib/Service')
-rwxr-xr-x | lib/Service/Html.php | 54 | ||||
-rwxr-xr-x | lib/Service/HtmlPurify/TransformStyleURLs.php (renamed from lib/Service/HtmlPurify/TransformCSSBackground.php) | 12 |
2 files changed, 50 insertions, 16 deletions
diff --git a/lib/Service/Html.php b/lib/Service/Html.php index 7983b35d3..feb36307e 100755 --- a/lib/Service/Html.php +++ b/lib/Service/Html.php @@ -7,6 +7,7 @@ declare(strict_types=1); * @author Jakob Sack <jakob@owncloud.org> * @author Jakob Sack <mail@jakobsack.de> * @author Lukas Reschke <lukas@statuscode.ch> + * @author Richard Steinmetz <richard@steinmetz.cloud> * @author Thomas Müller <thomas.mueller@tmit.eu> * * Mail @@ -34,7 +35,7 @@ use HTMLPurifier_HTMLDefinition; use HTMLPurifier_URIDefinition; use HTMLPurifier_URISchemeRegistry; use OCA\Mail\Service\HtmlPurify\CidURIScheme; -use OCA\Mail\Service\HtmlPurify\TransformCSSBackground; +use OCA\Mail\Service\HtmlPurify\TransformStyleURLs; use OCA\Mail\Service\HtmlPurify\TransformHTMLLinks; use OCA\Mail\Service\HtmlPurify\TransformImageSrc; use OCA\Mail\Service\HtmlPurify\TransformNoReferrer; @@ -42,6 +43,10 @@ use OCA\Mail\Service\HtmlPurify\TransformURLScheme; use OCP\IRequest; use OCP\IURLGenerator; use OCP\Util; +use Sabberworm\CSS\OutputFormat; +use Sabberworm\CSS\Parser; +use Sabberworm\CSS\Value\CSSString; +use Sabberworm\CSS\Value\URL; use Youthweb\UrlLinker\UrlLinker; require_once __DIR__ . '/../../vendor/cerdic/css-tidy/class.csstidy.php'; @@ -134,7 +139,7 @@ class Html { /** @var HTMLPurifier_HTMLDefinition $html */ $html = $config->getDefinition('HTML'); $html->info_attr_transform_post['imagesrc'] = new TransformImageSrc($this->urlGenerator); - $html->info_attr_transform_post['cssbackground'] = new TransformCSSBackground($this->urlGenerator); + $html->info_attr_transform_post['cssbackground'] = new TransformStyleURLs($this->urlGenerator); $html->info_attr_transform_post['htmllinks'] = new TransformHTMLLinks($this->urlGenerator); /** @var HTMLPurifier_URIDefinition $uri */ @@ -143,22 +148,53 @@ class Html { HTMLPurifier_URISchemeRegistry::instance()->register('cid', new CidURIScheme()); - $purifier = new HTMLPurifier($config); $result = $purifier->purify($mailBody); // eat xml parse errors within HTMLPurifier libxml_clear_errors(); - // Add back the style tag + // Sanitize CSS rules $styles = $purifier->context->get('StyleBlocks'); if ($styles) { - $result = implode("\n", [ - '<style type="text/css">', - implode("\n", $styles), - '</style>', - $result,]); + $joinedStyles = implode("\n", $styles); + $result = $this->sanitizeStyleSheet($joinedStyles) . $result; } return $result; } + + /** + * Block all URLs in the given CSS style sheet and return a formatted html style tag. + * + * @param string $styles The CSS style sheet to sanitize. + * @return string Rendered style tag to be used in a html response. + */ + public function sanitizeStyleSheet(string $styles): string { + $cssParser = new Parser($styles); + $css = $cssParser->parse(); + + // Replace urls with blocked image + $blockedUrl = new CSSString($this->urlGenerator->imagePath('mail', 'blocked-image.png')); + $hasBlockedContent = false; + foreach ($css->getAllValues() as $value) { + if ($value instanceof URL) { + $value->setURL($blockedUrl); + $hasBlockedContent = true; + } + } + + // Save original styles to be able to restore them later + $savedStyles = ''; + if ($hasBlockedContent) { + $savedStyles = 'data-original-content="' . htmlspecialchars($styles) . '"'; + $styles = $css->render(OutputFormat::createCompact()); + } + + // Render style tag + return implode('', [ + '<style type="text/css" ', $savedStyles, '>', + $styles, + '</style>', + ]); + } } diff --git a/lib/Service/HtmlPurify/TransformCSSBackground.php b/lib/Service/HtmlPurify/TransformStyleURLs.php index 933a4803b..16b791db1 100755 --- a/lib/Service/HtmlPurify/TransformCSSBackground.php +++ b/lib/Service/HtmlPurify/TransformStyleURLs.php @@ -31,9 +31,9 @@ use HTMLPurifier_Context; use OCP\IURLGenerator; /** - * Adds copies src to data-src on all img tags. + * Blocks urls in style attributes and backups original styles for restoring them later. */ -class TransformCSSBackground extends HTMLPurifier_AttrTransform { +class TransformStyleURLs extends HTMLPurifier_AttrTransform { /** @var IURLGenerator */ private $urlGenerator; @@ -49,8 +49,7 @@ class TransformCSSBackground extends HTMLPurifier_AttrTransform { * @return array */ public function transform($attr, $config, $context) { - if (!isset($attr['style']) || - strpos($attr['style'], 'background') === false) { + if (!isset($attr['style']) || strpos($attr['style'], 'url(') === false) { return $attr; } @@ -64,10 +63,9 @@ class TransformCSSBackground extends HTMLPurifier_AttrTransform { } [$name, $value] = explode(':', $cssAttribute, 2); - if (strpos($name, 'background') !== false && - strpos($value, 'url(') !== false) { + if (strpos($value, 'url(') !== false) { // Replace image URL - $value = preg_replace('/url\("?http.*\)/i', + $value = preg_replace('/url\(("|\')?http.*\)/i', 'url(' . $this->urlGenerator->imagePath('mail', 'blocked-image.png') . ')', $value); return $name . ':' . $value; |