From 0f961c6af4e39d388eab09e32bbab652e209a6d7 Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Sun, 16 Dec 2007 23:16:45 +0000 Subject: [PATCH] [3.0.0] [BACKPORT] More work for hire from Chris ! Experimental support for some proprietary CSS attributes allowed: opacity (and all of the browser-specific equivalents) and scrollbar colors. Enable by setting %CSS.Proprietary to true. - Colors missing # but in hex form will be corrected - CSS Number algorithm improved . New classes: + HTMLPurifier_AttrDef_CSS_AlphaValue + HTMLPurifier_AttrDef_CSS_Filter git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1473 48356398-32a2-884e-a903-53898d9a118a --- NEWS | 8 ++++ library/HTMLPurifier/AttrDef/CSS/AlphaValue.php | 22 +++++++++ library/HTMLPurifier/AttrDef/CSS/Color.php | 22 +++++---- library/HTMLPurifier/AttrDef/CSS/Filter.php | 54 +++++++++++++++++++++++ library/HTMLPurifier/AttrDef/CSS/Number.php | 10 +++-- library/HTMLPurifier/CSSDefinition.php | 33 ++++++++++++++ tests/HTMLPurifier/AttrDef/CSS/AlphaValueTest.php | 30 +++++++++++++ tests/HTMLPurifier/AttrDef/CSS/ColorTest.php | 7 +++ tests/HTMLPurifier/AttrDef/CSS/FilterTest.php | 29 ++++++++++++ tests/HTMLPurifier/AttrDef/CSS/NumberTest.php | 14 ++++++ tests/HTMLPurifier/AttrDef/CSSTest.php | 18 ++++++++ tests/test_files.php | 2 + 12 files changed, 237 insertions(+), 12 deletions(-) create mode 100644 library/HTMLPurifier/AttrDef/CSS/AlphaValue.php create mode 100644 library/HTMLPurifier/AttrDef/CSS/Filter.php create mode 100644 tests/HTMLPurifier/AttrDef/CSS/AlphaValueTest.php create mode 100644 tests/HTMLPurifier/AttrDef/CSS/FilterTest.php diff --git a/NEWS b/NEWS index bc632c29..d25aa407 100644 --- a/NEWS +++ b/NEWS @@ -22,7 +22,15 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier documents and cleaning their contents up. Requires the CSSTidy library . You can access the blocks with the 'StyleBlocks' Context variable ($purifier->context->get('StyleBlocks')) +! Experimental support for some proprietary CSS attributes allowed: + opacity (and all of the browser-specific equivalents) and scrollbar colors. + Enable by setting %CSS.Proprietary to true. +- Colors missing # but in hex form will be corrected +- CSS Number algorithm improved . Unit tests for Injector improved +. New classes: + + HTMLPurifier_AttrDef_CSS_AlphaValue + + HTMLPurifier_AttrDef_CSS_Filter 2.1.3, released 2007-11-05 ! tests/multitest.php allows you to test multiple versions by running diff --git a/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php b/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php new file mode 100644 index 00000000..2492ee2e --- /dev/null +++ b/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php @@ -0,0 +1,22 @@ + 1.0) $result = '1'; + return $result; + } + +} diff --git a/library/HTMLPurifier/AttrDef/CSS/Color.php b/library/HTMLPurifier/AttrDef/CSS/Color.php index 6b09ee5a..b86dc091 100644 --- a/library/HTMLPurifier/AttrDef/CSS/Color.php +++ b/library/HTMLPurifier/AttrDef/CSS/Color.php @@ -39,20 +39,13 @@ class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef if ($colors === null) $colors = $config->get('Core', 'ColorKeywords'); $color = trim($color); - if (!$color) return false; + if ($color === '') return false; $lower = strtolower($color); if (isset($colors[$lower])) return $colors[$lower]; - if ($color[0] === '#') { - // hexadecimal handling - $hex = substr($color, 1); - $length = strlen($hex); - if ($length !== 3 && $length !== 6) return false; - if (!ctype_xdigit($hex)) return false; - } else { + if (strpos($color, 'rgb(') !== false) { // rgb literal handling - if (strpos($color, 'rgb(')) return false; $length = strlen($color); if (strpos($color, ')') !== $length - 1) return false; $triad = substr($color, 4, $length - 4 - 1); @@ -90,6 +83,17 @@ class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef } $new_triad = implode(',', $new_parts); $color = "rgb($new_triad)"; + } else { + // hexadecimal handling + if ($color[0] === '#') { + $hex = substr($color, 1); + } else { + $hex = $color; + $color = '#' . $color; + } + $length = strlen($hex); + if ($length !== 3 && $length !== 6) return false; + if (!ctype_xdigit($hex)) return false; } return $color; diff --git a/library/HTMLPurifier/AttrDef/CSS/Filter.php b/library/HTMLPurifier/AttrDef/CSS/Filter.php new file mode 100644 index 00000000..31fe8bc9 --- /dev/null +++ b/library/HTMLPurifier/AttrDef/CSS/Filter.php @@ -0,0 +1,54 @@ +intValidator = new HTMLPurifier_AttrDef_Integer(); + } + + public function validate($value, $config, &$context) { + $value = $this->parseCDATA($value); + // if we looped this we could support multiple filters + $function_length = strcspn($value, '('); + $function = trim(substr($value, 0, $function_length)); + if ($function !== 'alpha' && + $function !== 'Alpha' && + $function !== 'progid:DXImageTransform.Microsoft.Alpha' + ) return false; + $cursor = $function_length + 1; + $parameters_length = strcspn($value, ')', $cursor); + $parameters = substr($value, $cursor, $parameters_length); + $params = explode(',', $parameters); + $ret_params = array(); + $lookup = array(); + foreach ($params as $param) { + list($key, $value) = explode('=', $param); + $key = trim($key); + $value = trim($value); + if (isset($lookup[$key])) continue; + if ($key !== 'opacity') continue; + $value = $this->intValidator->validate($value, $config, $context); + if ($value === false) continue; + $int = (int) $value; + if ($int > 100) $value = '100'; + if ($int < 0) $value = '0'; + $ret_params[] = "$key=$value"; + $lookup[$key] = true; + } + $ret_parameters = implode(',', $ret_params); + $ret_function = "$function($ret_parameters)"; + return $ret_function; + } + +} diff --git a/library/HTMLPurifier/AttrDef/CSS/Number.php b/library/HTMLPurifier/AttrDef/CSS/Number.php index 228600c9..c5f46399 100644 --- a/library/HTMLPurifier/AttrDef/CSS/Number.php +++ b/library/HTMLPurifier/AttrDef/CSS/Number.php @@ -23,6 +23,7 @@ class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef $number = $this->parseCDATA($number); if ($number === '') return false; + if ($number === '0') return '0'; $sign = ''; switch ($number[0]) { @@ -37,13 +38,16 @@ class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef $number = ltrim($number, '0'); return $number ? $sign . $number : '0'; } - if (!strpos($number, '.')) return false; + + // Period is the only non-numeric character allowed + if (strpos($number, '.') === false) return false; list($left, $right) = explode('.', $number, 2); - if (!ctype_digit($left)) return false; - $left = ltrim($left, '0'); + if ($left === '' && $right === '') return false; + if ($left !== '' && !ctype_digit($left)) return false; + $left = ltrim($left, '0'); $right = rtrim($right, '0'); if ($right === '') { diff --git a/library/HTMLPurifier/CSSDefinition.php b/library/HTMLPurifier/CSSDefinition.php index 123c69ed..5295dc4a 100644 --- a/library/HTMLPurifier/CSSDefinition.php +++ b/library/HTMLPurifier/CSSDefinition.php @@ -2,11 +2,13 @@ require_once 'HTMLPurifier/Definition.php'; +require_once 'HTMLPurifier/AttrDef/CSS/AlphaValue.php'; require_once 'HTMLPurifier/AttrDef/CSS/Background.php'; require_once 'HTMLPurifier/AttrDef/CSS/BackgroundPosition.php'; require_once 'HTMLPurifier/AttrDef/CSS/Border.php'; require_once 'HTMLPurifier/AttrDef/CSS/Color.php'; require_once 'HTMLPurifier/AttrDef/CSS/Composite.php'; +require_once 'HTMLPurifier/AttrDef/CSS/Filter.php'; require_once 'HTMLPurifier/AttrDef/CSS/Font.php'; require_once 'HTMLPurifier/AttrDef/CSS/FontFamily.php'; require_once 'HTMLPurifier/AttrDef/CSS/Length.php'; @@ -26,6 +28,14 @@ HTMLPurifier_ConfigSchema::define(

'); +HTMLPurifier_ConfigSchema::define( + 'CSS', 'Proprietary', false, 'bool', ' +

+ Whether or not to allow safe, proprietary CSS values. This directive + has been available since 3.0.0. +

+'); + /** * Defines allowed CSS attributes and what their values are. * @see HTMLPurifier_HTMLDefinition @@ -224,6 +234,29 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition // partial support $this->info['white-space'] = new HTMLPurifier_AttrDef_Enum(array('nowrap')); + if ($config->get('CSS', 'Proprietary')) { + $this->doSetupProprietary($config); + } + + } + + protected function doSetupProprietary($config) { + // Internet Explorer only scrollbar colors + $this->info['scrollbar-arrow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-base-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-darkshadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-face-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-highlight-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-shadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + + // technically not proprietary, but CSS3, and no one supports it + $this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + $this->info['-moz-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + $this->info['-khtml-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + + // only opacity, for now + $this->info['filter'] = new HTMLPurifier_AttrDef_CSS_Filter(); + } } diff --git a/tests/HTMLPurifier/AttrDef/CSS/AlphaValueTest.php b/tests/HTMLPurifier/AttrDef/CSS/AlphaValueTest.php new file mode 100644 index 00000000..74fcb494 --- /dev/null +++ b/tests/HTMLPurifier/AttrDef/CSS/AlphaValueTest.php @@ -0,0 +1,30 @@ +def = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + + $this->assertDef('0'); + $this->assertDef('1'); + $this->assertDef('.2'); + + // clamping to [0.0, 1,0] + $this->assertDef('1.2', '1'); + $this->assertDef('-3', '0'); + + $this->assertDef('0.0', '0'); + $this->assertDef('1.0', '1'); + $this->assertDef('000', '0'); + + $this->assertDef('asdf', false); + + } + +} + diff --git a/tests/HTMLPurifier/AttrDef/CSS/ColorTest.php b/tests/HTMLPurifier/AttrDef/CSS/ColorTest.php index 030c6224..4cb8602b 100644 --- a/tests/HTMLPurifier/AttrDef/CSS/ColorTest.php +++ b/tests/HTMLPurifier/AttrDef/CSS/ColorTest.php @@ -11,6 +11,8 @@ class HTMLPurifier_AttrDef_CSS_ColorTest extends HTMLPurifier_AttrDefHarness $this->def = new HTMLPurifier_AttrDef_CSS_Color(); $this->assertDef('#F00'); + $this->assertDef('#fff'); + $this->assertDef('#eeeeee'); $this->assertDef('#808080'); $this->assertDef('rgb(255, 0, 0)', 'rgb(255,0,0)'); // rm spaces $this->assertDef('rgb(100%,0%,0%)'); @@ -27,6 +29,11 @@ class HTMLPurifier_AttrDef_CSS_ColorTest extends HTMLPurifier_AttrDefHarness // color keywords, of course $this->assertDef('red', '#FF0000'); + // malformed hex declaration + $this->assertDef('808080', '#808080'); + $this->assertDef('000000', '#000000'); + $this->assertDef('fed', '#fed'); + // maybe hex transformations would be another nice feature // at the very least transform rgb percent to rgb integer diff --git a/tests/HTMLPurifier/AttrDef/CSS/FilterTest.php b/tests/HTMLPurifier/AttrDef/CSS/FilterTest.php new file mode 100644 index 00000000..046d3bae --- /dev/null +++ b/tests/HTMLPurifier/AttrDef/CSS/FilterTest.php @@ -0,0 +1,29 @@ +def = new HTMLPurifier_AttrDef_CSS_Filter(); + + $this->assertDef('alpha(opacity=0)'); + $this->assertDef('alpha(opacity=100)'); + $this->assertDef('alpha(opacity=50)'); + $this->assertDef('alpha(opacity=342)', 'alpha(opacity=100)'); + $this->assertDef('alpha(opacity=-23)', 'alpha(opacity=0)'); + + $this->assertDef('alpha ( opacity = 0 )', 'alpha(opacity=0)'); + $this->assertDef('alpha(opacity=0,opacity=100)', 'alpha(opacity=0)'); + + $this->assertDef('progid:DXImageTransform.Microsoft.Alpha(opacity=20)'); + + $this->assertDef('progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)', false); + + } + +} + diff --git a/tests/HTMLPurifier/AttrDef/CSS/NumberTest.php b/tests/HTMLPurifier/AttrDef/CSS/NumberTest.php index 071135be..8aa3ce23 100644 --- a/tests/HTMLPurifier/AttrDef/CSS/NumberTest.php +++ b/tests/HTMLPurifier/AttrDef/CSS/NumberTest.php @@ -11,10 +11,24 @@ class HTMLPurifier_AttrDef_CSS_NumberTest extends HTMLPurifier_AttrDefHarness $this->def = new HTMLPurifier_AttrDef_CSS_Number(); $this->assertDef('0'); + $this->assertDef('0.0', '0'); + $this->assertDef('1.0', '1'); $this->assertDef('34'); $this->assertDef('4.5'); + $this->assertDef('.5'); + $this->assertDef('0.5', '.5'); $this->assertDef('-56.9'); + $this->assertDef('0.', '0'); + $this->assertDef('.0', '0'); + $this->assertDef('0.0', '0'); + + $this->assertDef('1.', '1'); + $this->assertDef('.1', '.1'); + + $this->assertDef('1.0', '1'); + $this->assertDef('0.1', '.1'); + $this->assertDef('000', '0'); $this->assertDef(' 9', '9'); $this->assertDef('+5.0000', '5'); diff --git a/tests/HTMLPurifier/AttrDef/CSSTest.php b/tests/HTMLPurifier/AttrDef/CSSTest.php index 59d86e2e..a4ffc50c 100644 --- a/tests/HTMLPurifier/AttrDef/CSSTest.php +++ b/tests/HTMLPurifier/AttrDef/CSSTest.php @@ -112,5 +112,23 @@ class HTMLPurifier_AttrDef_CSSTest extends HTMLPurifier_AttrDefHarness } + function testProprietary() { + $this->config->set('CSS', 'Proprietary', true); + $this->def = new HTMLPurifier_AttrDef_CSS(); + + $this->assertDef('scrollbar-arrow-color:#ff0;'); + $this->assertDef('scrollbar-base-color:#ff6347;'); + $this->assertDef('scrollbar-darkshadow-color:#ffa500;'); + $this->assertDef('scrollbar-face-color:#008080;'); + $this->assertDef('scrollbar-highlight-color:#ff69b4;'); + $this->assertDef('scrollbar-shadow-color:#f0f;'); + + $this->assertDef('opacity:.2;'); + $this->assertDef('-moz-opacity:.2;'); + $this->assertDef('-khtml-opacity:.2;'); + $this->assertDef('filter:alpha(opacity=20);'); + + } + } diff --git a/tests/test_files.php b/tests/test_files.php index 3e7126f8..35e385a4 100644 --- a/tests/test_files.php +++ b/tests/test_files.php @@ -7,11 +7,13 @@ if (!defined('HTMLPurifierTest')) exit; // HTML Purifier main library $test_files[] = 'HTMLPurifier/AttrCollectionsTest.php'; +$test_files[] = 'HTMLPurifier/AttrDef/CSS/AlphaValueTest.php'; $test_files[] = 'HTMLPurifier/AttrDef/CSS/BackgroundPositionTest.php'; $test_files[] = 'HTMLPurifier/AttrDef/CSS/BackgroundTest.php'; $test_files[] = 'HTMLPurifier/AttrDef/CSS/BorderTest.php'; $test_files[] = 'HTMLPurifier/AttrDef/CSS/ColorTest.php'; $test_files[] = 'HTMLPurifier/AttrDef/CSS/CompositeTest.php'; +$test_files[] = 'HTMLPurifier/AttrDef/CSS/FilterTest.php'; $test_files[] = 'HTMLPurifier/AttrDef/CSS/FontFamilyTest.php'; $test_files[] = 'HTMLPurifier/AttrDef/CSS/FontTest.php'; $test_files[] = 'HTMLPurifier/AttrDef/CSS/LengthTest.php'; -- 2.11.4.GIT