From 1947e4424acc493e0f2f7dd1e71f3952398bfcfc Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Fri, 14 Dec 2018 01:41:36 +0000 Subject: [PATCH] KSES: Allow `url()` to be used in inline CSS. The cover image block uses the `url()` function in its inline CSS, to show the cover image. KSES didn't allow this, causing the block to not save correctly for Author and Contributor users. As KSES does already check each attribute name against an allowed list, we're able to add an extra check for certain attributes to be able to use the `url()` function, too. Merges [43781] from the 5.0 branch to core. Props peterwilsoncc, azaozz, pento, dd32. Fixes #45067. Built from https://develop.svn.wordpress.org/trunk@44136 git-svn-id: http://core.svn.wordpress.org/trunk@43966 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/kses.php | 71 +++++++++++++++++++++++++++++++++++------ wp-includes/version.php | 2 +- 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/wp-includes/kses.php b/wp-includes/kses.php index 8cc521346a..964ef7fd6e 100644 --- a/wp-includes/kses.php +++ b/wp-includes/kses.php @@ -1985,9 +1985,7 @@ function safecss_filter_attr( $css, $deprecated = '' ) { $css = wp_kses_no_null( $css ); $css = str_replace( array( "\n", "\r", "\t" ), '', $css ); - if ( preg_match( '%[\\\\(&=}]|/\*%', $css ) ) { // remove any inline css containing \ ( & } = or comments - return ''; - } + $allowed_protocols = wp_allowed_protocols(); $css_array = explode( ';', trim( $css ) ); @@ -1998,6 +1996,7 @@ function safecss_filter_attr( $css, $deprecated = '' ) { * @since 4.4.0 Added support for `min-height`, `max-height`, `min-width`, and `max-width`. * @since 4.6.0 Added support for `list-style-type`. * @since 5.0.0 Added support for `text-transform`. + * @since 5.0.0 Added support for `background-image`. * * @param string[] $attr Array of allowed CSS attributes. */ @@ -2006,6 +2005,7 @@ function safecss_filter_attr( $css, $deprecated = '' ) { array( 'background', 'background-color', + 'background-image', 'border', 'border-width', @@ -2076,6 +2076,24 @@ function safecss_filter_attr( $css, $deprecated = '' ) { ) ); + /* + * CSS attributes that accept URL data types. + * + * This is in accordance to the CSS spec and unrelated to + * the sub-set of supported attributes above. + * + * See: https://developer.mozilla.org/en-US/docs/Web/CSS/url + */ + $css_url_data_types = array( + 'background', + 'background-image', + + 'cursor', + + 'list-style', + 'list-style-image', + ); + if ( empty( $allowed_attr ) ) { return $css; } @@ -2085,20 +2103,55 @@ function safecss_filter_attr( $css, $deprecated = '' ) { if ( $css_item == '' ) { continue; } - $css_item = trim( $css_item ); - $found = false; + + $css_item = trim( $css_item ); + $css_test_string = $css_item; + $found = false; + $url_attr = false; + if ( strpos( $css_item, ':' ) === false ) { $found = true; } else { - $parts = explode( ':', $css_item ); - if ( in_array( trim( $parts[0] ), $allowed_attr ) ) { - $found = true; + $parts = explode( ':', $css_item, 2 ); + $css_selector = trim( $parts[0] ); + + if ( in_array( $css_selector, $allowed_attr, true ) ) { + $found = true; + $url_attr = in_array( $css_selector, $css_url_data_types, true ); } } - if ( $found ) { + + if ( $found && $url_attr ) { + // Simplified: matches the sequence `url(*)`. + preg_match_all( '/url\([^)]+\)/', $parts[1], $url_matches ); + + foreach ( $url_matches[0] as $url_match ) { + // Clean up the URL from each of the matches above. + preg_match( '/^url\(\s*([\'\"]?)(.*)(\g1)\s*\)$/', $url_match, $url_pieces ); + + if ( empty( $url_pieces[2] ) ) { + $found = false; + break; + } + + $url = trim( $url_pieces[2] ); + + if ( empty( $url ) || $url !== wp_kses_bad_protocol( $url, $allowed_protocols ) ) { + $found = false; + break; + } else { + // Remove the whole `url(*)` bit that was matched above from the CSS. + $css_test_string = str_replace( $url_match, '', $css_test_string ); + } + } + } + + // Remove any CSS containing containing \ ( & } = or comments, except for url() useage checked above. + if ( $found && ! preg_match( '%[\\\(&=}]|/\*%', $css_test_string ) ) { if ( $css != '' ) { $css .= ';'; } + $css .= $css_item; } } diff --git a/wp-includes/version.php b/wp-includes/version.php index 831a2b52bd..2889bc6514 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -13,7 +13,7 @@ * * @global string $wp_version */ -$wp_version = '5.1-alpha-44135'; +$wp_version = '5.1-alpha-44136'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.