Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/wp-includes/kses.php
Original file line number Diff line number Diff line change
Expand Up @@ -2756,6 +2756,27 @@ function safecss_filter_attr( $css, $deprecated = '' ) {
'list-style-image',
);

/*
* CSS attributes that accept rgb(a) color data types.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency with the above:

Suggested change
* CSS attributes that accept rgb(a) color data types.
* CSS attributes that accept rgb(a) color data types.
*
* See https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb

*/
$css_color_data_types = array(
'color',

'border',
'border-color',
'border-right',
'border-right-color',
'border-bottom',
'border-bottom-color',
'border-left',
'border-left-color',
'border-top',
'border-top-color',

'background',
'background-color',
);

/*
* CSS attributes that accept gradient data types.
*
Expand All @@ -2779,6 +2800,7 @@ function safecss_filter_attr( $css, $deprecated = '' ) {
$css_test_string = $css_item;
$found = false;
$url_attr = false;
$color_attr = false;
$gradient_attr = false;
$is_custom_var = false;

Expand All @@ -2798,6 +2820,7 @@ function safecss_filter_attr( $css, $deprecated = '' ) {
$found = true;
$url_attr = in_array( $css_selector, $css_url_data_types, true );
$gradient_attr = in_array( $css_selector, $css_gradient_data_types, true );
$color_attr = in_array( $css_selector, $css_color_data_types, true );
}

if ( $is_custom_var ) {
Expand Down Expand Up @@ -2840,6 +2863,20 @@ function safecss_filter_attr( $css, $deprecated = '' ) {
}
}

if ( $found && $color_attr ) {
// Simplified: matches the sequence `rgb(*)` or `rgba(*)`.
$comma_syntax = '/rgba?\(\s*([+-]?\d*\.?\d+)(%)?\s*,\s*([+-]?\d*\.?\d+)(%)?\s*,\s*([+-]?\d*\.?\d+)(%)?\s*(?:,\s*([+-]?\d*\.?\d+)(%)?\s*)?\)/i';
$space_syntax = '/rgba?\(\s*([+-]?\d*\.?\d+)(%)?\s+([+-]?\d*\.?\d+)(%)?\s+([+-]?\d*\.?\d+)(%)?\s*(?:\/\s*([+-]?\d*\.?\d+)(%)?\s*)?\)/i';
Comment on lines +2868 to +2869
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude pointed out there is a none keyword in CSS level 4: https://www.w3.org/TR/css-color-4/#missing

It is only available in the non-comma modern syntax: https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/rgb#formal_syntax

The following implements none while also factoring out the common terms to avoid duplication:

Suggested change
$comma_syntax = '/rgba?\(\s*([+-]?\d*\.?\d+)(%)?\s*,\s*([+-]?\d*\.?\d+)(%)?\s*,\s*([+-]?\d*\.?\d+)(%)?\s*(?:,\s*([+-]?\d*\.?\d+)(%)?\s*)?\)/i';
$space_syntax = '/rgba?\(\s*([+-]?\d*\.?\d+)(%)?\s+([+-]?\d*\.?\d+)(%)?\s+([+-]?\d*\.?\d+)(%)?\s*(?:\/\s*([+-]?\d*\.?\d+)(%)?\s*)?\)/i';
$term = '(?:[+-]?\d*\.?\d+)%?';
$comma_syntax = '/rgba?\(\s*' . join( '\s*,\s*', array_fill( 0, 3, $term ) ) . '\s*(?:,\s*' . $term . ')?\s*\)/i';
$term = '(?:(?:[+-]?\d*\.?\d+)%?|none)';
$space_syntax = '/rgba?\(\s*' . join( '\s+', array_fill( 0, 3, $term ) ) . '\s*(?:\/\s*' . $term . ')?\s*\)/i';

Tests should be added for the none case as well.


preg_match_all( $comma_syntax, $parts[1], $color_matches_comma );
preg_match_all( $space_syntax, $parts[1], $color_matches_space );

foreach ( array_merge( $color_matches_comma[0], $color_matches_space[0] ) as $color_match ) {
// Remove the whole `rgb(*)` or `rgba(*)` bit that was matched above from the CSS.
$css_test_string = str_replace( $color_match, '', $css_test_string );
}
}

if ( $found ) {
/*
* Allow CSS functions like var(), calc(), etc. by removing them from the test string.
Expand Down
107 changes: 101 additions & 6 deletions tests/phpunit/tests/kses.php
Original file line number Diff line number Diff line change
Expand Up @@ -1203,15 +1203,30 @@ public function data_safecss_filter_attr() {
'css' => 'height: expression( body.scrollTop + 50 + "px" )',
'expected' => '',
),
// RGB color values are not allowed.
// RGBA background color are allowed.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// RGBA background color are allowed.
// RGBA background colors are allowed.

array(
'css' => 'color: rgb( 100, 100, 100 )',
'expected' => '',
'css' => 'background-color: rgba(0,0,0,0)',
'expected' => 'background-color: rgba(0,0,0,0)',
),
// RGBA color values are not allowed.
array(
'css' => 'color: rgb( 100, 100, 100, .4 )',
'expected' => '',
'css' => 'background-color: rgba(0, 0, 0, 0)',
'expected' => 'background-color: rgba(0, 0, 0, 0)',
),
array(
'css' => 'background-color: rgba(100, 100, 100, 0)',
'expected' => 'background-color: rgba(100, 100, 100, 0)',
),
array(
'css' => 'background-color: rgba(10%, 10%, 10%, 0)',
'expected' => 'background-color: rgba(10%, 10%, 10%, 0)',
),
array(
'css' => 'background-color: rgba(0, 0, 0, 0.1)',
'expected' => 'background-color: rgba(0, 0, 0, 0.1)',
),
array(
'css' => 'background-color: rgba(0, 0, 0, .1)',
'expected' => 'background-color: rgba(0, 0, 0, .1)',
),
// Allow min().
array(
Expand Down Expand Up @@ -1333,6 +1348,86 @@ public function data_safecss_filter_attr() {
'css' => 'gap: 10px;column-gap: 5px;row-gap: 20px',
'expected' => 'gap: 10px;column-gap: 5px;row-gap: 20px',
),
// RGB color.
array(
'css' => 'color: rgb(255, 0, 0)',
'expected' => 'color: rgb(255, 0, 0)',
),
array(
'css' => 'color: rgb(255 0 0)',
'expected' => 'color: rgb(255 0 0)',
),
array(
'css' => 'color: rgb(100%, 0%, 50%)',
'expected' => 'color: rgb(100%, 0%, 50%)',
),
array(
'css' => 'color: rgb(255 50% 0)',
'expected' => 'color: rgb(255 50% 0)',
),
Comment on lines +1364 to +1367
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mixing integers with a percentage here isn't valid:

body {
   background: rgb(255, 50%, 0);
}
Image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for noticing, I have corrected the invalid values in 129c006

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's fixed? The problem is the 50%. Apparently CSS doesn't like mixing percentages and non-percentages. The above is still marked as invalid CSS by the CSS Validator.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I try validating:

body {
   color: rgb(255 50% 0);
}

I get:

Image

Is the CSS Validator out of date?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chrome seems fine with it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, and PhpStorm is fine with the comma-less version:

image

// RGBA color.
array(
'css' => 'color: rgba(255, 128, 0, 0.5)',
'expected' => 'color: rgba(255, 128, 0, 0.5)',
),
array(
'css' => 'color: rgb(255 128 0 / 50%)',
'expected' => 'color: rgb(255 128 0 / 50%)',
),
// RGB color with extra whitespace.
array(
'css' => 'color: rgb( 255 , 128 , 0 )',
'expected' => 'color: rgb( 255 , 128 , 0 )',
),
// RGB background color.
array(
'css' => 'background-color: rgb(200, 100, 50)',
'expected' => 'background-color: rgb(200, 100, 50)',
),
// RGBA border color.
array(
'css' => 'border-color: rgba(100, 200, 250, 0.8)',
'expected' => 'border-color: rgba(100, 200, 250, 0.8)',
),
// RGB color in `border` shorthand.
array(
'css' => 'border: 1px solid rgb(0, 0, 0)',
'expected' => 'border: 1px solid rgb(0, 0, 0)',
),
// RGBA color in `border` shorthand.
array(
'css' => 'border: 1px solid rgba(0, 0, 0, 0.5)',
'expected' => 'border: 1px solid rgba(0, 0, 0, 0.5)',
),
// RGB color in `background` shorthand.
array(
'css' => 'background: rgb(0, 0, 0) center',
'expected' => 'background: rgb(0, 0, 0) center',
),
// Malformed RGB color, invalid number of values.
array(
'css' => 'color: rgb(255, 128, 0, 0.5, 100)',
'expected' => '',
),
array(
'css' => 'color: rgb(255, 128)',
'expected' => '',
),
// Malformed RGB color, non-numeric values.
array(
'css' => 'color: rgb(red, green, blue)',
'expected' => '',
),
// Malformed RGB color, unmatched parentheses.
array(
'css' => 'color: rgb(255, 128, 0',
'expected' => '',
),
// Malformed RGB color, empty values.
array(
'css' => 'color: rgb(, , )',
'expected' => '',
),
// Margin and padding logical properties introduced in 6.1.
array(
'css' => 'margin-block-start: 1px;margin-block-end: 2px;margin-inline-start: 3px;margin-inline-end: 4px;',
Expand Down
Loading