From f4f0f80d2118437e5047ba266f92d7acb3c38fb7 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Mon, 11 Apr 2011 16:41:01 +0400 Subject: update HTMLPurifier; enable embedded flash video in articles --- .../library/HTMLPurifier/AttrDef/CSS.php | 0 .../HTMLPurifier/AttrDef/CSS/AlphaValue.php | 0 .../HTMLPurifier/AttrDef/CSS/Background.php | 0 .../AttrDef/CSS/BackgroundPosition.php | 21 ++- .../library/HTMLPurifier/AttrDef/CSS/Border.php | 0 .../library/HTMLPurifier/AttrDef/CSS/Color.php | 2 +- .../library/HTMLPurifier/AttrDef/CSS/Composite.php | 0 .../AttrDef/CSS/DenyElementDecorator.php | 0 .../library/HTMLPurifier/AttrDef/CSS/Filter.php | 0 .../library/HTMLPurifier/AttrDef/CSS/Font.php | 0 .../HTMLPurifier/AttrDef/CSS/FontFamily.php | 177 +++++++++++++++++---- .../AttrDef/CSS/ImportantDecorator.php | 0 .../library/HTMLPurifier/AttrDef/CSS/Length.php | 0 .../library/HTMLPurifier/AttrDef/CSS/ListStyle.php | 0 .../library/HTMLPurifier/AttrDef/CSS/Multiple.php | 0 .../library/HTMLPurifier/AttrDef/CSS/Number.php | 0 .../HTMLPurifier/AttrDef/CSS/Percentage.php | 0 .../HTMLPurifier/AttrDef/CSS/TextDecoration.php | 0 .../library/HTMLPurifier/AttrDef/CSS/URI.php | 21 ++- .../library/HTMLPurifier/AttrDef/Enum.php | 0 .../library/HTMLPurifier/AttrDef/HTML/Bool.php | 0 .../library/HTMLPurifier/AttrDef/HTML/Class.php | 34 ++++ .../library/HTMLPurifier/AttrDef/HTML/Color.php | 2 +- .../HTMLPurifier/AttrDef/HTML/FrameTarget.php | 2 +- .../library/HTMLPurifier/AttrDef/HTML/ID.php | 10 +- .../library/HTMLPurifier/AttrDef/HTML/Length.php | 0 .../HTMLPurifier/AttrDef/HTML/LinkTypes.php | 2 +- .../HTMLPurifier/AttrDef/HTML/MultiLength.php | 0 .../library/HTMLPurifier/AttrDef/HTML/Nmtokens.php | 36 +++-- .../library/HTMLPurifier/AttrDef/HTML/Pixels.php | 0 .../library/HTMLPurifier/AttrDef/Integer.php | 0 .../library/HTMLPurifier/AttrDef/Lang.php | 0 .../library/HTMLPurifier/AttrDef/Switch.php | 0 .../library/HTMLPurifier/AttrDef/Text.php | 0 .../library/HTMLPurifier/AttrDef/URI.php | 2 +- .../library/HTMLPurifier/AttrDef/URI/Email.php | 0 .../HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php | 0 .../library/HTMLPurifier/AttrDef/URI/Host.php | 6 + .../library/HTMLPurifier/AttrDef/URI/IPv4.php | 0 .../library/HTMLPurifier/AttrDef/URI/IPv6.php | 0 40 files changed, 239 insertions(+), 76 deletions(-) mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php create mode 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php mode change 100755 => 100644 lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php (limited to 'lib/htmlpurifier/library/HTMLPurifier/AttrDef') diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php old mode 100755 new mode 100644 index 35df3985e..fae82eaec --- a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php +++ b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php @@ -59,7 +59,8 @@ class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef $keywords = array(); $keywords['h'] = false; // left, right $keywords['v'] = false; // top, bottom - $keywords['c'] = false; // center + $keywords['ch'] = false; // center (first word) + $keywords['cv'] = false; // center (second word) $measures = array(); $i = 0; @@ -79,6 +80,13 @@ class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef $lbit = ctype_lower($bit) ? $bit : strtolower($bit); if (isset($lookup[$lbit])) { $status = $lookup[$lbit]; + if ($status == 'c') { + if ($i == 0) { + $status = 'ch'; + } else { + $status = 'cv'; + } + } $keywords[$status] = $lbit; $i++; } @@ -101,20 +109,19 @@ class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef if (!$i) return false; // no valid values were caught - $ret = array(); // first keyword if ($keywords['h']) $ret[] = $keywords['h']; - elseif (count($measures)) $ret[] = array_shift($measures); - elseif ($keywords['c']) { - $ret[] = $keywords['c']; - $keywords['c'] = false; // prevent re-use: center = center center + elseif ($keywords['ch']) { + $ret[] = $keywords['ch']; + $keywords['cv'] = false; // prevent re-use: center = center center } + elseif (count($measures)) $ret[] = array_shift($measures); if ($keywords['v']) $ret[] = $keywords['v']; + elseif ($keywords['cv']) $ret[] = $keywords['cv']; elseif (count($measures)) $ret[] = array_shift($measures); - elseif ($keywords['c']) $ret[] = $keywords['c']; if (empty($ret)) return false; return implode(' ', $ret); diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php old mode 100755 new mode 100644 index 14c6594b6..07f95a671 --- a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php +++ b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php @@ -9,7 +9,7 @@ class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef public function validate($color, $config, $context) { static $colors = null; - if ($colors === null) $colors = $config->get('Core', 'ColorKeywords'); + if ($colors === null) $colors = $config->get('Core.ColorKeywords'); $color = trim($color); if ($color === '') return false; diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php old mode 100755 new mode 100644 index 705ac893d..0d9a4e12c --- a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php +++ b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php @@ -2,11 +2,43 @@ /** * Validates a font family list according to CSS spec - * @todo whitelisting allowed fonts would be nice */ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef { + protected $mask = null; + + public function __construct() { + $this->mask = '- '; + for ($c = 'a'; $c <= 'z'; $c++) $this->mask .= $c; + for ($c = 'A'; $c <= 'Z'; $c++) $this->mask .= $c; + for ($c = '0'; $c <= '9'; $c++) $this->mask .= $c; // cast-y, but should be fine + // special bytes used by UTF-8 + for ($i = 0x80; $i <= 0xFF; $i++) { + // We don't bother excluding invalid bytes in this range, + // because the our restriction of well-formed UTF-8 will + // prevent these from ever occurring. + $this->mask .= chr($i); + } + + /* + PHP's internal strcspn implementation is + O(length of string * length of mask), making it inefficient + for large masks. However, it's still faster than + preg_match 8) + for (p = s1;;) { + spanp = s2; + do { + if (*spanp == c || p == s1_end) { + return p - s1; + } + } while (spanp++ < (s2_end - 1)); + c = *++p; + } + */ + // possible optimization: invert the mask. + } + public function validate($string, $config, $context) { static $generic_names = array( 'serif' => true, @@ -15,6 +47,7 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef 'fantasy' => true, 'cursive' => true ); + $allowed_fonts = $config->get('CSS.AllowedFonts'); // assume that no font names contain commas in them $fonts = explode(',', $string); @@ -24,7 +57,9 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef if ($font === '') continue; // match a generic name if (isset($generic_names[$font])) { - $final .= $font . ', '; + if ($allowed_fonts === null || isset($allowed_fonts[$font])) { + $final .= $font . ', '; + } continue; } // match a quoted name @@ -34,50 +69,122 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef $quote = $font[0]; if ($font[$length - 1] !== $quote) continue; $font = substr($font, 1, $length - 2); + } - $new_font = ''; - for ($i = 0, $c = strlen($font); $i < $c; $i++) { - if ($font[$i] === '\\') { - $i++; - if ($i >= $c) { - $new_font .= '\\'; - break; - } - if (ctype_xdigit($font[$i])) { - $code = $font[$i]; - for ($a = 1, $i++; $i < $c && $a < 6; $i++, $a++) { - if (!ctype_xdigit($font[$i])) break; - $code .= $font[$i]; - } - // We have to be extremely careful when adding - // new characters, to make sure we're not breaking - // the encoding. - $char = HTMLPurifier_Encoder::unichr(hexdec($code)); - if (HTMLPurifier_Encoder::cleanUTF8($char) === '') continue; - $new_font .= $char; - if ($i < $c && trim($font[$i]) !== '') $i--; - continue; - } - if ($font[$i] === "\n") continue; - } - $new_font .= $font[$i]; - } + $font = $this->expandCSSEscape($font); - $font = $new_font; - } // $font is a pure representation of the font name + if ($allowed_fonts !== null && !isset($allowed_fonts[$font])) { + continue; + } + if (ctype_alnum($font) && $font !== '') { // very simple font, allow it in unharmed $final .= $font . ', '; continue; } - // complicated font, requires quoting + // bugger out on whitespace. form feed (0C) really + // shouldn't show up regardless + $font = str_replace(array("\n", "\t", "\r", "\x0C"), ' ', $font); + + // Here, there are various classes of characters which need + // to be treated differently: + // - Alphanumeric characters are essentially safe. We + // handled these above. + // - Spaces require quoting, though most parsers will do + // the right thing if there aren't any characters that + // can be misinterpreted + // - Dashes rarely occur, but they fairly unproblematic + // for parsing/rendering purposes. + // The above characters cover the majority of Western font + // names. + // - Arbitrary Unicode characters not in ASCII. Because + // most parsers give little thought to Unicode, treatment + // of these codepoints is basically uniform, even for + // punctuation-like codepoints. These characters can + // show up in non-Western pages and are supported by most + // major browsers, for example: "MS 明朝" is a + // legitimate font-name + // . See + // the CSS3 spec for more examples: + // + // You can see live samples of these on the Internet: + // + // However, most of these fonts have ASCII equivalents: + // for example, 'MS Mincho', and it's considered + // professional to use ASCII font names instead of + // Unicode font names. Thanks Takeshi Terada for + // providing this information. + // The following characters, to my knowledge, have not been + // used to name font names. + // - Single quote. While theoretically you might find a + // font name that has a single quote in its name (serving + // as an apostrophe, e.g. Dave's Scribble), I haven't + // been able to find any actual examples of this. + // Internet Explorer's cssText translation (which I + // believe is invoked by innerHTML) normalizes any + // quoting to single quotes, and fails to escape single + // quotes. (Note that this is not IE's behavior for all + // CSS properties, just some sort of special casing for + // font-family). So a single quote *cannot* be used + // safely in the font-family context if there will be an + // innerHTML/cssText translation. Note that Firefox 3.x + // does this too. + // - Double quote. In IE, these get normalized to + // single-quotes, no matter what the encoding. (Fun + // fact, in IE8, the 'content' CSS property gained + // support, where they special cased to preserve encoded + // double quotes, but still translate unadorned double + // quotes into single quotes.) So, because their + // fixpoint behavior is identical to single quotes, they + // cannot be allowed either. Firefox 3.x displays + // single-quote style behavior. + // - Backslashes are reduced by one (so \\ -> \) every + // iteration, so they cannot be used safely. This shows + // up in IE7, IE8 and FF3 + // - Semicolons, commas and backticks are handled properly. + // - The rest of the ASCII punctuation is handled properly. + // We haven't checked what browsers do to unadorned + // versions, but this is not important as long as the + // browser doesn't /remove/ surrounding quotes (as IE does + // for HTML). + // + // With these results in hand, we conclude that there are + // various levels of safety: + // - Paranoid: alphanumeric, spaces and dashes(?) + // - International: Paranoid + non-ASCII Unicode + // - Edgy: Everything except quotes, backslashes + // - NoJS: Standards compliance, e.g. sod IE. Note that + // with some judicious character escaping (since certain + // types of escaping doesn't work) this is theoretically + // OK as long as innerHTML/cssText is not called. + // We believe that international is a reasonable default + // (that we will implement now), and once we do more + // extensive research, we may feel comfortable with dropping + // it down to edgy. + + // Edgy: alphanumeric, spaces, dashes and Unicode. Use of + // str(c)spn assumes that the string was already well formed + // Unicode (which of course it is). + if (strspn($font, $this->mask) !== strlen($font)) { + continue; + } + + // Historical: + // In the absence of innerHTML/cssText, these ugly + // transforms don't pose a security risk (as \\ and \" + // might--these escapes are not supported by most browsers). + // We could try to be clever and use single-quote wrapping + // when there is a double quote present, but I have choosen + // not to implement that. (NOTE: you can reduce the amount + // of escapes by one depending on what quoting style you use) + // $font = str_replace('\\', '\\5C ', $font); + // $font = str_replace('"', '\\22 ', $font); + // $font = str_replace("'", '\\27 ', $font); - // armor single quotes and new lines - $font = str_replace("\\", "\\\\", $font); - $font = str_replace("'", "\\'", $font); + // font possibly with spaces, requires quoting $final .= "'$font', "; } $final = rtrim($final, ', '); diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php old mode 100755 new mode 100644 index 435d7930b..c2f767e57 --- a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php +++ b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php @@ -34,20 +34,25 @@ class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI $uri = substr($uri, 1, $new_length - 1); } - $keys = array( '(', ')', ',', ' ', '"', "'"); - $values = array('\\(', '\\)', '\\,', '\\ ', '\\"', "\\'"); - $uri = str_replace($values, $keys, $uri); + $uri = $this->expandCSSEscape($uri); $result = parent::validate($uri, $config, $context); if ($result === false) return false; - // escape necessary characters according to CSS spec - // except for the comma, none of these should appear in the - // URI at all - $result = str_replace($keys, $values, $result); + // extra sanity check; should have been done by URI + $result = str_replace(array('"', "\\", "\n", "\x0c", "\r"), "", $result); - return "url($result)"; + // suspicious characters are ()'; we're going to percent encode + // them for safety. + $result = str_replace(array('(', ')', "'"), array('%28', '%29', '%27'), $result); + + // there's an extra bug where ampersands lose their escaping on + // an innerHTML cycle, so a very unlucky query parameter could + // then change the meaning of the URL. Unfortunately, there's + // not much we can do about that... + + return "url(\"$result\")"; } diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php new file mode 100644 index 000000000..370068d97 --- /dev/null +++ b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php @@ -0,0 +1,34 @@ +getDefinition('HTML')->doctype->name; + if ($name == "XHTML 1.1" || $name == "XHTML 2.0") { + return parent::split($string, $config, $context); + } else { + return preg_split('/\s+/', $string); + } + } + protected function filter($tokens, $config, $context) { + $allowed = $config->get('Attr.AllowedClasses'); + $forbidden = $config->get('Attr.ForbiddenClasses'); + $ret = array(); + foreach ($tokens as $token) { + if ( + ($allowed === null || isset($allowed[$token])) && + !isset($forbidden[$token]) && + // We need this O(n) check because of PHP's array + // implementation that casts -0 to 0. + !in_array($token, $ret, true) + ) { + $ret[] = $token; + } + } + return $ret; + } +} diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php old mode 100755 new mode 100644 index 5311a3c61..d01e20454 --- a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php +++ b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php @@ -9,7 +9,7 @@ class HTMLPurifier_AttrDef_HTML_Color extends HTMLPurifier_AttrDef public function validate($string, $config, $context) { static $colors = null; - if ($colors === null) $colors = $config->get('Core', 'ColorKeywords'); + if ($colors === null) $colors = $config->get('Core.ColorKeywords'); $string = trim($string); diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php old mode 100755 new mode 100644 index bd281a89f..ae6ea7c01 --- a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php +++ b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php @@ -12,7 +12,7 @@ class HTMLPurifier_AttrDef_HTML_FrameTarget extends HTMLPurifier_AttrDef_Enum public function __construct() {} public function validate($string, $config, $context) { - if ($this->valid_values === false) $this->valid_values = $config->get('Attr', 'AllowedFrameTargets'); + if ($this->valid_values === false) $this->valid_values = $config->get('Attr.AllowedFrameTargets'); return parent::validate($string, $config, $context); } diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php old mode 100755 new mode 100644 index 7c5c169c2..81d03762d --- a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php +++ b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php @@ -17,18 +17,18 @@ class HTMLPurifier_AttrDef_HTML_ID extends HTMLPurifier_AttrDef public function validate($id, $config, $context) { - if (!$config->get('Attr', 'EnableID')) return false; + if (!$config->get('Attr.EnableID')) return false; $id = trim($id); // trim it first if ($id === '') return false; - $prefix = $config->get('Attr', 'IDPrefix'); + $prefix = $config->get('Attr.IDPrefix'); if ($prefix !== '') { - $prefix .= $config->get('Attr', 'IDPrefixLocal'); + $prefix .= $config->get('Attr.IDPrefixLocal'); // prevent re-appending the prefix if (strpos($id, $prefix) !== 0) $id = $prefix . $id; - } elseif ($config->get('Attr', 'IDPrefixLocal') !== '') { + } elseif ($config->get('Attr.IDPrefixLocal') !== '') { trigger_error('%Attr.IDPrefixLocal cannot be used unless '. '%Attr.IDPrefix is set', E_USER_WARNING); } @@ -51,7 +51,7 @@ class HTMLPurifier_AttrDef_HTML_ID extends HTMLPurifier_AttrDef $result = ($trim === ''); } - $regexp = $config->get('Attr', 'IDBlacklistRegexp'); + $regexp = $config->get('Attr.IDBlacklistRegexp'); if ($regexp && preg_match($regexp, $id)) { return false; } diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php old mode 100755 new mode 100644 index 8a0da0c89..76d25ed08 --- a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php +++ b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php @@ -27,7 +27,7 @@ class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef public function validate($string, $config, $context) { - $allowed = $config->get('Attr', $this->name); + $allowed = $config->get('Attr.' . $this->name); if (empty($allowed)) return false; $string = $this->parseCDATA($string); diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php old mode 100755 new mode 100644 index 55035c4d0..aa34120bd --- a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php +++ b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php @@ -2,10 +2,6 @@ /** * Validates contents based on NMTOKENS attribute type. - * @note The only current use for this is the class attribute in HTML - * @note Could have some functionality factored out into Nmtoken class - * @warning We cannot assume this class will be used only for 'class' - * attributes. Not sure how to hook in magic behavior, then. */ class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef { @@ -17,6 +13,17 @@ class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef // early abort: '' and '0' (strings that convert to false) are invalid if (!$string) return false; + $tokens = $this->split($string, $config, $context); + $tokens = $this->filter($tokens, $config, $context); + if (empty($tokens)) return false; + return implode(' ', $tokens); + + } + + /** + * Splits a space separated list of tokens into its constituent parts. + */ + protected function split($string, $config, $context) { // OPTIMIZABLE! // do the preg_match, capture all subpatterns for reformulation @@ -24,23 +31,20 @@ class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef // escaping because I don't know how to do that with regexps // and plus it would complicate optimization efforts (you never // see that anyway). - $matches = array(); $pattern = '/(?:(?<=\s)|\A)'. // look behind for space or string start '((?:--|-?[A-Za-z_])[A-Za-z_\-0-9]*)'. '(?:(?=\s)|\z)/'; // look ahead for space or string end preg_match_all($pattern, $string, $matches); + return $matches[1]; + } - if (empty($matches[1])) return false; - - // reconstruct string - $new_string = ''; - foreach ($matches[1] as $token) { - $new_string .= $token . ' '; - } - $new_string = rtrim($new_string); - - return $new_string; - + /** + * Template method for removing certain tokens based on arbitrary criteria. + * @note If we wanted to be really functional, we'd do an array_filter + * with a callback. But... we're not. + */ + protected function filter($tokens, $config, $context) { + return $tokens; } } diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php old mode 100755 new mode 100644 index 93d2f0bbf..01a6d83e9 --- a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php +++ b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php @@ -25,7 +25,7 @@ class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef public function validate($uri, $config, $context) { - if ($config->get('URI', 'Disable')) return false; + if ($config->get('URI.Disable')) return false; $uri = $this->parseCDATA($uri); diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php old mode 100755 new mode 100644 index 2156c10c6..feca469d7 --- a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php +++ b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php @@ -23,6 +23,12 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef public function validate($string, $config, $context) { $length = strlen($string); + // empty hostname is OK; it's usually semantically equivalent: + // the default host as defined by a URI scheme is used: + // + // If the URI scheme defines a default for host, then that + // default applies when the host subcomponent is undefined + // or when the registered name is empty (zero length). if ($string === '') return ''; if ($length > 1 && $string[0] === '[' && $string[$length-1] === ']') { //IPv6 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php old mode 100755 new mode 100644 diff --git a/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php b/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php old mode 100755 new mode 100644 -- cgit v1.2.3