summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorthomascube <thomas@roundcube.net>2007-09-29 18:15:05 +0000
committerthomascube <thomas@roundcube.net>2007-09-29 18:15:05 +0000
commit97bd2c0537bc3edb3751b3020f37e680944ac41c (patch)
tree3845f62069bbfc9ddb67447f07e504f0f455077a
parentca2b4ddfcc7a506925c9d5b3a798a4c74147c2e1 (diff)
Filter linked/imported CSS files (#1484056)
-rw-r--r--CHANGELOG5
-rw-r--r--bin/modcss.php67
-rw-r--r--program/include/main.inc45
-rw-r--r--program/include/rcube_shared.inc4
-rw-r--r--program/steps/mail/func.inc74
5 files changed, 152 insertions, 43 deletions
diff --git a/CHANGELOG b/CHANGELOG
index a53992c18..34926868b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,11 @@
CHANGELOG RoundCube Webmail
---------------------------
+2007/09/29 (thomasb)
+----------
+- Filter linked/imported CSS files (closes #1484056)
+
+
2007/09/27 (tomekp)
----------
- Update brazilian portuguese localization (#1484580)
diff --git a/bin/modcss.php b/bin/modcss.php
new file mode 100644
index 000000000..e482389a8
--- /dev/null
+++ b/bin/modcss.php
@@ -0,0 +1,67 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/bin/modcss.php |
+ | |
+ | This file is part of the RoundCube Webmail client |
+ | Copyright (C) 2007, RoundCube Dev. - Switzerland |
+ | Licensed under the GNU GPL |
+ | |
+ | PURPOSE: |
+ | Modify CSS source from a URL |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com> |
+ +-----------------------------------------------------------------------+
+
+ $Id: $
+
+*/
+
+$INSTALL_PATH = realpath("./../") . "/";
+ini_set('include_path', $INSTALL_PATH.PATH_SEPARATOR.$INSTALL_PATH.'program'.PATH_SEPARATOR.ini_get('include_path'));
+
+require 'include/main.inc';
+
+$source = "";
+if ($url = preg_replace('/[^a-z0-9.-_\?\$&=%]/i', '', $_GET['u']))
+{
+ $a_uri = parse_url($url);
+ $port = $a_uri['port'] ? $a_uri['port'] : 80;
+ $host = $a_uri['host'];
+ $path = $a_uri['path'] . ($a_uri['query'] ? '?'.$a_uri['query'] : '');
+
+
+ if ($fp = fsockopen($host, $port, $errno, $errstr, 30))
+ {
+ $out = "GET $path HTTP/1.0\r\n";
+ $out .= "Host: $host\r\n";
+ $out .= "Connection: Close\r\n\r\n";
+ fwrite($fp, $out);
+
+ $header = true;
+ while (!feof($fp))
+ {
+ $line = trim(fgets($fp, 4048));
+
+ if ($header && preg_match('/^HTTP\/1\..\s+(\d+)/', $line, $regs) && intval($regs[1]) != 200)
+ break;
+ else if (empty($line) && $header)
+ $header = false;
+ else if (!$header)
+ $source .= "$line\n";
+ }
+ fclose($fp);
+ }
+}
+
+if (!empty($source))
+{
+ header("Content-Type: text/css");
+ echo rcmail_mod_css_styles($source, preg_replace('/[^a-z0-9]/i', '', $_GET['c']), $url);
+}
+else
+ header("HTTP/1.0 404 Not Found");
+
+?>
diff --git a/program/include/main.inc b/program/include/main.inc
index 9809865d4..db0ee6c07 100644
--- a/program/include/main.inc
+++ b/program/include/main.inc
@@ -29,6 +29,7 @@
require_once('lib/des.inc');
require_once('lib/utf7.inc');
require_once('lib/utf8.class.php');
+require_once('include/rcube_shared.inc');
require_once('include/rcmail_template.inc');
@@ -1450,6 +1451,50 @@ function rcmail_mail_domain($host)
/**
+ * Replace all css definitions with #container [def]
+ *
+ * @param string CSS source code
+ * @param string Container ID to use as prefix
+ * @return string Modified CSS source
+ */
+function rcmail_mod_css_styles($source, $container_id, $base_url = '')
+ {
+ $a_css_values = array();
+ $last_pos = 0;
+
+ // cut out all contents between { and }
+ while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos)))
+ {
+ $key = sizeof($a_css_values);
+ $a_css_values[$key] = substr($source, $pos+1, $pos2-($pos+1));
+ $source = substr($source, 0, $pos+1) . "<<str_replacement[$key]>>" . substr($source, $pos2, strlen($source)-$pos2);
+ $last_pos = $pos+2;
+ }
+
+ // remove html commends and add #container to each tag selector.
+ // also replace body definition because we also stripped off the <body> tag
+ $styles = preg_replace(
+ array(
+ '/(^\s*<!--)|(-->\s*$)/',
+ '/(^\s*|,\s*|\}\s*)([a-z0-9\._#][a-z0-9\.\-_]*)/im',
+ '/@import\s+(url\()?[\'"]?([^\)\'"]+)[\'"]?(\))?/ime',
+ '/<<str_replacement\[([0-9]+)\]>>/e',
+ "/$container_id\s+body/i"
+ ),
+ array(
+ '',
+ "\\1#$container_id \\2",
+ "sprintf(\"@import url('./bin/modcss.php?u=%s&c=%s')\", urlencode(make_absolute_url('\\2','$base_url')), urlencode($container_id))",
+ "\$a_css_values[\\1]",
+ "$container_id div.rcmBody"
+ ),
+ $source);
+
+ return $styles;
+ }
+
+
+/**
* Compose a valid attribute string for HTML tags
*
* @param array Named tag attributes
diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc
index a5a3ca64e..05fa7a2bc 100644
--- a/program/include/rcube_shared.inc
+++ b/program/include/rcube_shared.inc
@@ -434,6 +434,10 @@ function make_absolute_url($path, $base_url)
{
$host_url = $base_url;
$abs_path = $path;
+
+ // check if path is an absolute URL
+ if (preg_match('/^[fhtps]+:\/\//', $path))
+ return $path;
// cut base_url to the last directory
if (strpos($base_url, '/')>7)
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 0712ef8df..30d60e6da 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -946,16 +946,21 @@ function rcmail_sanitize_html($body, $container_id)
// remove any null-byte characters before parsing
$body = preg_replace('/\x00/', '', $body);
+ $base_url = "";
$last_style_pos = 0;
$body_lc = strtolower($body);
+ // check for <base href>
+ if (preg_match(($base_reg = '/(<base.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i'), $body, $base_regs))
+ $base_url = $base_regs[2];
+
// find STYLE tags
while (($pos = strpos($body_lc, '<style', $last_style_pos)) && ($pos2 = strpos($body_lc, '</style>', $pos)))
{
$pos = strpos($body_lc, '>', $pos)+1;
// replace all css definitions with #container [def]
- $styles = rcmail_mod_css_styles(substr($body, $pos, $pos2-$pos), $container_id);
+ $styles = rcmail_mod_css_styles(substr($body, $pos, $pos2-$pos), $container_id, $base_url);
$body = substr($body, 0, $pos) . $styles . substr($body, $pos2);
$body_lc = strtolower($body);
@@ -983,17 +988,15 @@ function rcmail_sanitize_html($body, $container_id)
}
// resolve <base href>
- $base_reg = '/(<base.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i';
- if (preg_match($base_reg, $body, $regs))
+ if ($base_url)
{
- $base_url = $regs[2];
$body = preg_replace('/(src|background|href)=(["\']?)([\.\/]+[^"\'\s]+)(\2|\s|>)/Uie', "'\\1=\"'.make_absolute_url('\\3', '$base_url').'\"'", $body);
$body = preg_replace('/(url\s*\()(["\']?)([\.\/]+[^"\'\)\s]+)(\2)\)/Uie', "'\\1\''.make_absolute_url('\\3', '$base_url').'\')'", $body);
$body = preg_replace($base_reg, '', $body);
}
// modify HTML links to open a new window if clicked
- $body = preg_replace('/<a\s+([^>]+)>/Uie', "rcmail_alter_html_link('\\1');", $body);
+ $body = preg_replace('/<(a|link)\s+([^>]+)>/Uie', "rcmail_alter_html_link('\\1','\\2', '$container_id');", $body);
// add comments arround html and other tags
$out = preg_replace(array(
@@ -1005,11 +1008,16 @@ function rcmail_sanitize_html($body, $container_id)
'<!--\\1-->',
$body);
- $out = preg_replace(array('/<body([^>]*)>/i',
- '/<\/body>/i'),
- array('<div class="rcmBody"\\1>',
- '</div>'),
- $out);
+ $out = preg_replace(
+ array(
+ '/<body([^>]*)>/i',
+ '/<\/body>/i',
+ ),
+ array(
+ '<div class="rcmBody"\\1>',
+ '</div>',
+ ),
+ $out);
// quote <? of php and xml files that are specified as text/html
$out = preg_replace(array('/<\?/', '/\?>/'), array('&lt;?', '?&gt;'), $out);
@@ -1019,44 +1027,24 @@ function rcmail_sanitize_html($body, $container_id)
// parse link attributes and set correct target
-function rcmail_alter_html_link($in)
+function rcmail_alter_html_link($tag, $attrs, $container_id)
{
$in = preg_replace('/=([^("|\'|\s)]+)(\s|$)/', '="\1"', $in);
- $attrib = parse_attrib_string($in);
-
- if (stristr((string)$attrib['href'], 'mailto:'))
- $attrib['onclick'] = sprintf("return %s.command('compose','%s',this)",
- JS_OBJECT_NAME,
- JQ(substr($attrib['href'], 7)));
- else if (!empty($attrib['href']) && $attrib['href']{0}!='#')
- $attrib['target'] = '_blank';
+ $attrib = parse_attrib_string($attrs);
- return '<a' . create_attrib_string($attrib, array('href', 'name', 'target', 'onclick', 'id', 'class', 'style', 'title')) . '>';
- }
-
-
-// replace all css definitions with #container [def]
-function rcmail_mod_css_styles($source, $container_id)
- {
- $a_css_values = array();
- $last_pos = 0;
+ if ($tag == 'link' && preg_match('/^https?:\/\//i', $attrib['href']))
+ $attrib['href'] = "./bin/modcss.php?u=" . urlencode($attrib['href']) . "&amp;c=" . urlencode($container_id);
+
+ else if (stristr((string)$attrib['href'], 'mailto:'))
+ $attrib['onclick'] = sprintf(
+ "return %s.command('compose','%s',this)",
+ JS_OBJECT_NAME,
+ JQ(substr($attrib['href'], 7)));
- // cut out all contents between { and }
- while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos)))
- {
- $key = sizeof($a_css_values);
- $a_css_values[$key] = substr($source, $pos+1, $pos2-($pos+1));
- $source = substr($source, 0, $pos+1) . "<<str_replacement[$key]>>" . substr($source, $pos2, strlen($source)-$pos2);
- $last_pos = $pos+2;
- }
-
- // remove html commends and add #container to each tag selector.
- // also replace body definition because we also stripped off the <body> tag
- $styles = preg_replace(array('/(^\s*<!--)|(-->\s*$)/', '/(^\s*|,\s*|\}\s*)([a-z0-9\._][a-z0-9\.\-_]*)/im', '/<<str_replacement\[([0-9]+)\]>>/e', "/$container_id\s+body/i"),
- array('', "\\1#$container_id \\2", "\$a_css_values[\\1]", "$container_id div.rcmBody"),
- $source);
+ else if (!empty($attrib['href']) && $attrib['href']{0}!='#')
+ $attrib['target'] = '_blank';
- return $styles;
+ return "<$tag" . create_attrib_string($attrib, array('href','name','target','onclick','id','class','style','title','rel','type','media')) . ' />';
}