summaryrefslogtreecommitdiff
path: root/program
diff options
context:
space:
mode:
authorthomascube <thomas@roundcube.net>2011-12-09 21:13:54 +0000
committerthomascube <thomas@roundcube.net>2011-12-09 21:13:54 +0000
commit2b017e7f79be26563ab767bb9e97fee5d88a01f4 (patch)
treec49206a19eb06f4af4b0967a4930dade83730544 /program
parent231fae7ad45cf2fb5bdbe62f78e043171af1e18e (diff)
Allow clean background:url(...) styles in safe mode. This will make Roundcube pass the Email Standards Acid Test
Diffstat (limited to 'program')
-rw-r--r--program/include/main.inc14
-rw-r--r--program/lib/washtml.php10
-rw-r--r--program/steps/mail/func.inc15
3 files changed, 25 insertions, 14 deletions
diff --git a/program/include/main.inc b/program/include/main.inc
index 8aa38c8d1..2d18567e7 100644
--- a/program/include/main.inc
+++ b/program/include/main.inc
@@ -883,19 +883,19 @@ function rcmail_get_edit_field($col, $value, $attrib, $type='text')
* @param string Container ID to use as prefix
* @return string Modified CSS source
*/
-function rcmail_mod_css_styles($source, $container_id)
+function rcmail_mod_css_styles($source, $container_id, $allow_remote=false)
{
$last_pos = 0;
$replacements = new rcube_string_replacer;
// ignore the whole block if evil styles are detected
- $stripped = preg_replace('/[^a-z\(:;]/', '', rcmail_xss_entity_decode($source));
- if (preg_match('/expression|behavior|url\(|import[^a]/', $stripped))
+ $source = rcmail_xss_entity_decode($source);
+ $stripped = preg_replace('/[^a-z\(:;]/i', '', $source);
+ $evilexpr = 'expression|behavior' . (!$allow_remote ? '|url\(|import[^a]' : '');
+ if (preg_match("/$evilexpr/i", $stripped) // don't accept No-Gos
+ || (strpos($stripped, 'url(') && !preg_match('!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Ui', $source))) // only allow clean urls
return '/* evil! */';
- // remove css comments (sometimes used for some ugly hacks)
- $source = preg_replace('!/\*(.+)\*/!Ums', '', $source);
-
// cut out all contents between { and }
while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos)))
{
@@ -937,7 +937,7 @@ function rcmail_xss_entity_decode($content)
{
$out = html_entity_decode(html_entity_decode($content));
$out = preg_replace_callback('/\\\([0-9a-f]{4})/i', 'rcmail_xss_entity_decode_callback', $out);
- $out = preg_replace('#/\*.*\*/#Um', '', $out);
+ $out = preg_replace('#/\*.*\*/#Ums', '', $out);
return $out;
}
diff --git a/program/lib/washtml.php b/program/lib/washtml.php
index 9c8625f30..8bbc136e1 100644
--- a/program/lib/washtml.php
+++ b/program/lib/washtml.php
@@ -243,7 +243,7 @@ class washtml
case XML_ELEMENT_NODE: //Check element
$tagName = strtolower($node->tagName);
if ($callback = $this->handlers[$tagName]) {
- $dump .= call_user_func($callback, $tagName, $this->wash_attribs($node), $this->dumpHtml($node));
+ $dump .= call_user_func($callback, $tagName, $this->wash_attribs($node), $this->dumpHtml($node), $this);
}
else if (isset($this->_html_elements[$tagName])) {
$content = $this->dumpHtml($node);
@@ -301,6 +301,14 @@ class washtml
return $this->dumpHtml($node);
}
+ /**
+ * Getter for config parameters
+ */
+ public function get_config($prop)
+ {
+ return $this->config[$prop];
+ }
+
}
?>
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 1063c8ddf..62474f16a 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -822,7 +822,7 @@ function rcmail_plain_body($body, $flowed=false)
/**
* Callback function for washtml cleaning class
*/
-function rcmail_washtml_callback($tagname, $attrib, $content)
+function rcmail_washtml_callback($tagname, $attrib, $content, $washtml)
{
switch ($tagname) {
case 'form':
@@ -834,8 +834,11 @@ function rcmail_washtml_callback($tagname, $attrib, $content)
$stripped = preg_replace('/[^a-zA-Z\(:;]/', '', rcmail_xss_entity_decode($content));
// now check for evil strings like expression, behavior or url()
- if (!preg_match('/expression|behavior|url\(|import[^a]/', $stripped)) {
- $out = html::tag('style', array('type' => 'text/css'), $content);
+ if (!preg_match('/expression|behavior/i', $stripped)) {
+ if (!$washtml->get_config('allow_remote') && preg_match('/url\(|import[^a]/i', $stripped))
+ $washtml->extlinks = true;
+ else
+ $out = html::tag('style', array('type' => 'text/css'), $content);
break;
}
@@ -1021,7 +1024,7 @@ function rcmail_message_body($attrib)
$body = rcmail_print_body($part, array('safe' => $safe_mode, 'plain' => !$CONFIG['prefer_html']));
if ($part->ctype_secondary == 'html') {
- $body = rcmail_html4inline($body, $attrib['id'], 'rcmBody', $attrs);
+ $body = rcmail_html4inline($body, $attrib['id'], 'rcmBody', $attrs, $safe_mode);
$div_attr = array('class' => 'message-htmlpart');
$style = array();
@@ -1104,7 +1107,7 @@ function rcmail_resolve_base($body)
/**
* modify a HTML message that it can be displayed inside a HTML page
*/
-function rcmail_html4inline($body, $container_id, $body_id='', &$attributes=null)
+function rcmail_html4inline($body, $container_id, $body_id='', &$attributes=null, $allow_remote=false)
{
$last_style_pos = 0;
$cont_id = $container_id.($body_id ? ' div.'.$body_id : '');
@@ -1116,7 +1119,7 @@ function rcmail_html4inline($body, $container_id, $body_id='', &$attributes=null
// replace all css definitions with #container [def]
$styles = rcmail_mod_css_styles(
- substr($body, $pos, $pos2-$pos), $cont_id);
+ substr($body, $pos, $pos2-$pos), $cont_id, $allow_remote);
$body = substr_replace($body, $styles, $pos, $pos2-$pos);
$last_style_pos = $pos2;