0
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2024-12-22 08:21:52 +00:00

feat: Allow universal CSS values for all properties (#410)

This commit is contained in:
John Flatness 2024-06-28 08:37:00 -04:00 committed by GitHub
parent 93bee73349
commit 972326785d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 43 additions and 21 deletions

View File

@ -27,6 +27,13 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
$definition = $config->getCSSDefinition(); $definition = $config->getCSSDefinition();
$allow_duplicates = $config->get("CSS.AllowDuplicates"); $allow_duplicates = $config->get("CSS.AllowDuplicates");
$universal_attrdef = new HTMLPurifier_AttrDef_Enum(
array(
'initial',
'inherit',
'unset',
)
);
// According to the CSS2.1 spec, the places where a // According to the CSS2.1 spec, the places where a
// non-delimiting semicolon can appear are in strings // non-delimiting semicolon can appear are in strings
@ -96,16 +103,13 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
if (!$ok) { if (!$ok) {
continue; continue;
} }
// inefficient call, since the validator will do this again $result = $universal_attrdef->validate($value, $config, $context);
if (strtolower(trim($value)) !== 'inherit') { if ($result === false) {
// inherit works for everything (but only on the base property)
$result = $definition->info[$property]->validate( $result = $definition->info[$property]->validate(
$value, $value,
$config, $config,
$context $context
); );
} else {
$result = 'inherit';
} }
if ($result === false) { if ($result === false) {
continue; continue;

View File

@ -116,8 +116,6 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
'auto', 'auto',
'cover', 'cover',
'contain', 'contain',
'initial',
'inherit',
] ]
), ),
new HTMLPurifier_AttrDef_CSS_Percentage(), new HTMLPurifier_AttrDef_CSS_Percentage(),
@ -236,21 +234,20 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
[ [
new HTMLPurifier_AttrDef_CSS_Length('0'), new HTMLPurifier_AttrDef_CSS_Length('0'),
new HTMLPurifier_AttrDef_CSS_Percentage(true), new HTMLPurifier_AttrDef_CSS_Percentage(true),
new HTMLPurifier_AttrDef_Enum(['auto', 'initial', 'inherit']) new HTMLPurifier_AttrDef_Enum(['auto'])
] ]
); );
$trusted_min_wh = new HTMLPurifier_AttrDef_CSS_Composite( $trusted_min_wh = new HTMLPurifier_AttrDef_CSS_Composite(
[ [
new HTMLPurifier_AttrDef_CSS_Length('0'), new HTMLPurifier_AttrDef_CSS_Length('0'),
new HTMLPurifier_AttrDef_CSS_Percentage(true), new HTMLPurifier_AttrDef_CSS_Percentage(true),
new HTMLPurifier_AttrDef_Enum(['initial', 'inherit'])
] ]
); );
$trusted_max_wh = new HTMLPurifier_AttrDef_CSS_Composite( $trusted_max_wh = new HTMLPurifier_AttrDef_CSS_Composite(
[ [
new HTMLPurifier_AttrDef_CSS_Length('0'), new HTMLPurifier_AttrDef_CSS_Length('0'),
new HTMLPurifier_AttrDef_CSS_Percentage(true), new HTMLPurifier_AttrDef_CSS_Percentage(true),
new HTMLPurifier_AttrDef_Enum(['none', 'initial', 'inherit']) new HTMLPurifier_AttrDef_Enum(['none'])
] ]
); );
$max = $config->get('CSS.MaxImgLength'); $max = $config->get('CSS.MaxImgLength');
@ -278,12 +275,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
new HTMLPurifier_AttrDef_Switch( new HTMLPurifier_AttrDef_Switch(
'img', 'img',
// For img tags: // For img tags:
new HTMLPurifier_AttrDef_CSS_Composite( new HTMLPurifier_AttrDef_CSS_Length('0', $max),
[
new HTMLPurifier_AttrDef_CSS_Length('0', $max),
new HTMLPurifier_AttrDef_Enum(['initial', 'inherit'])
]
),
// For everyone else: // For everyone else:
$trusted_min_wh $trusted_min_wh
); );
@ -297,7 +289,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
new HTMLPurifier_AttrDef_CSS_Composite( new HTMLPurifier_AttrDef_CSS_Composite(
[ [
new HTMLPurifier_AttrDef_CSS_Length('0', $max), new HTMLPurifier_AttrDef_CSS_Length('0', $max),
new HTMLPurifier_AttrDef_Enum(['none', 'initial', 'inherit']) new HTMLPurifier_AttrDef_Enum(['none'])
] ]
), ),
// For everyone else: // For everyone else:
@ -315,11 +307,11 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration(); $this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration();
$this->info['text-decoration-line'] = new HTMLPurifier_AttrDef_Enum( $this->info['text-decoration-line'] = new HTMLPurifier_AttrDef_Enum(
['none', 'underline', 'overline', 'line-through', 'initial', 'inherit'] ['none', 'underline', 'overline', 'line-through']
); );
$this->info['text-decoration-style'] = new HTMLPurifier_AttrDef_Enum( $this->info['text-decoration-style'] = new HTMLPurifier_AttrDef_Enum(
['solid', 'double', 'dotted', 'dashed', 'wavy', 'initial', 'inherit'] ['solid', 'double', 'dotted', 'dashed', 'wavy']
); );
$this->info['text-decoration-color'] = new HTMLPurifier_AttrDef_CSS_Color(); $this->info['text-decoration-color'] = new HTMLPurifier_AttrDef_CSS_Color();
@ -327,7 +319,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['text-decoration-thickness'] = new HTMLPurifier_AttrDef_CSS_Composite([ $this->info['text-decoration-thickness'] = new HTMLPurifier_AttrDef_CSS_Composite([
new HTMLPurifier_AttrDef_CSS_Length(), new HTMLPurifier_AttrDef_CSS_Length(),
new HTMLPurifier_AttrDef_CSS_Percentage(), new HTMLPurifier_AttrDef_CSS_Percentage(),
new HTMLPurifier_AttrDef_Enum(['auto', 'from-font', 'initial', 'inherit']) new HTMLPurifier_AttrDef_Enum(['auto', 'from-font'])
]); ]);
$this->info['font-family'] = new HTMLPurifier_AttrDef_CSS_FontFamily(); $this->info['font-family'] = new HTMLPurifier_AttrDef_CSS_FontFamily();

View File

@ -54,6 +54,11 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
*/ */
private $_enum_attrdef; private $_enum_attrdef;
/**
* @type HTMLPurifier_AttrDef_Enum
*/
private $_universal_attrdef;
public function __construct() public function __construct()
{ {
$this->_tidy = new csstidy(); $this->_tidy = new csstidy();
@ -70,6 +75,13 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
'focus' 'focus'
) )
); );
$this->_universal_attrdef = new HTMLPurifier_AttrDef_Enum(
array(
'initial',
'inherit',
'unset',
)
);
} }
/** /**
@ -307,6 +319,11 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
unset($style[$name]); unset($style[$name]);
continue; continue;
} }
$uni_ret = $this->_universal_attrdef->validate($value, $config, $context);
if ($uni_ret !== false) {
$style[$name] = $uni_ret;
continue;
}
$def = $css_definition->info[$name]; $def = $css_definition->info[$name];
$ret = $def->validate($value, $config, $context); $ret = $def->validate($value, $config, $context);
if ($ret === false) { if ($ret === false) {

View File

@ -120,8 +120,10 @@ class HTMLPurifier_AttrDef_CSSTest extends HTMLPurifier_AttrDefHarness
$this->assertDef('text-transform:capitalize;destroy:it;', $this->assertDef('text-transform:capitalize;destroy:it;',
'text-transform:capitalize;'); 'text-transform:capitalize;');
// inherit works for everything // universal values work for everything
$this->assertDef('text-align:inherit;'); $this->assertDef('text-align:inherit;');
$this->assertDef('text-align:initial;');
$this->assertDef('text-align:unset;');
// bad props // bad props
$this->assertDef('nodice:foobar;', false); $this->assertDef('nodice:foobar;', false);

View File

@ -88,6 +88,13 @@ class HTMLPurifier_Filter_ExtractStyleBlocksTest extends HTMLPurifier_Harness
$this->assertCleanCSS("a .foo #id div.cl#foo {\nfont-weight:700\n}"); $this->assertCleanCSS("a .foo #id div.cl#foo {\nfont-weight:700\n}");
} }
public function test_cleanCSS_universals()
{
$this->assertCleanCSS("a {\nfont-weight:inherit\n}");
$this->assertCleanCSS("a {\nfont-weight:initial\n}");
$this->assertCleanCSS("a {\nfont-weight:unset\n}");
}
public function test_cleanCSS_angledBrackets() public function test_cleanCSS_angledBrackets()
{ {
// [Content] No longer can smuggle in angled brackets using // [Content] No longer can smuggle in angled brackets using