Make WordPress Core


Ignore:
Timestamp:
10/22/2018 04:03:07 AM (8 years ago)
Author:
pento
Message:

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.

Props peterwilsoncc, azaozz, pento, dd32.
See #45067.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/5.0/src/wp-includes/kses.php

    r43731 r43781  
    17081708 */
    17091709function safecss_filter_attr( $css, $deprecated = '' ) {
    1710         if ( !empty( $deprecated ) )
     1710        if ( ! empty( $deprecated ) ) {
    17111711                _deprecated_argument( __FUNCTION__, '2.8.1' ); // Never implemented
    1712 
    1713         $css = wp_kses_no_null($css);
    1714         $css = str_replace(array("\n","\r","\t"), '', $css);
    1715 
    1716         if ( preg_match( '%[\\\\(&=}]|/\*%', $css ) ) // remove any inline css containing \ ( & } = or comments
    1717                 return '';
     1712        }
     1713
     1714        $css = wp_kses_no_null( $css );
     1715        $css = str_replace( array( "\n", "\r", "\t" ), '', $css );
     1716
     1717        $allowed_protocols = wp_allowed_protocols();
    17181718
    17191719        $css_array = explode( ';', trim( $css ) );
     
    17251725         * @since 4.4.0 Added support for `min-height`, `max-height`, `min-width`, and `max-width`.
    17261726         * @since 4.6.0 Added support for `list-style-type`.
     1727         * @since 5.0.0 Added support for `background-image`.
    17271728         *
    17281729         * @param array $attr List of allowed CSS attributes.
     
    17311732                'background',
    17321733                'background-color',
     1734                'background-image',
    17331735
    17341736                'border',
     
    17991801        ) );
    18001802
    1801         if ( empty($allowed_attr) )
     1803
     1804        /*
     1805         * CSS attributes that accept URL data types.
     1806         *
     1807         * This is in accordance to the CSS spec and unrelated to
     1808         * the sub-set of supported attributes above.
     1809         *
     1810         * See: https://developer.mozilla.org/en-US/docs/Web/CSS/url
     1811         */
     1812        $css_url_data_types = array(
     1813                'background',
     1814                'background-image',
     1815
     1816                'cursor',
     1817
     1818                'list-style',
     1819                'list-style-image',
     1820        );
     1821
     1822        if ( empty( $allowed_attr ) ) {
    18021823                return $css;
     1824        }
    18031825
    18041826        $css = '';
    18051827        foreach ( $css_array as $css_item ) {
    1806                 if ( $css_item == '' )
     1828                if ( $css_item == '' ) {
    18071829                        continue;
    1808                 $css_item = trim( $css_item );
    1809                 $found = false;
     1830                }
     1831
     1832                $css_item        = trim( $css_item );
     1833                $css_test_string = $css_item;
     1834                $found           = false;
     1835                $url_attr        = false;
     1836
    18101837                if ( strpos( $css_item, ':' ) === false ) {
    18111838                        $found = true;
    18121839                } else {
    1813                         $parts = explode( ':', $css_item );
    1814                         if ( in_array( trim( $parts[0] ), $allowed_attr ) )
     1840                        $parts = explode( ':', $css_item, 2 );
     1841                        $css_selector = trim( $parts[0] );
     1842
     1843                        if ( in_array( $css_selector, $allowed_attr, true ) ) {
    18151844                                $found = true;
     1845                                $url_attr = in_array( $css_selector, $css_url_data_types, true );
     1846                        }
    18161847                }
    1817                 if ( $found ) {
    1818                         if( $css != '' )
     1848
     1849                if ( $found && $url_attr ) {
     1850                        // Simplified: matches the sequence `url(*)`.
     1851                        preg_match_all( '/url\([^)]+\)/', $parts[1], $url_matches );
     1852
     1853                        foreach ( $url_matches[0] as $url_match ) {
     1854                                // Clean up the URL from each of the matches above.
     1855                                preg_match( '/^url\(\s*([\'\"]?)(.*)(\g1)\s*\)$/', $url_match, $url_pieces );
     1856
     1857                                if ( empty( $url_pieces[2] ) ) {
     1858                                        $found = false;
     1859                                        break;
     1860                                }
     1861
     1862                                $url = trim( $url_pieces[2] );
     1863
     1864                                if ( empty( $url ) || $url !== wp_kses_bad_protocol( $url, $allowed_protocols ) ) {
     1865                                        $found = false;
     1866                                        break;
     1867                                } else {
     1868                                        // Remove the whole `url(*)` bit that was matched above from the CSS.
     1869                                        $css_test_string = str_replace( $url_match, '', $css_test_string );
     1870                                }
     1871                        }
     1872                }
     1873
     1874                // Remove any CSS containing containing \ ( & } = or comments, except for url() useage checked above.
     1875                if ( $found && ! preg_match( '%[\\\(&=}]|/\*%', $css_test_string ) ) {
     1876                        if ( $css != '' ) {
    18191877                                $css .= ';';
     1878                        }
     1879
    18201880                        $css .= $css_item;
    18211881                }
Note: See TracChangeset for help on using the changeset viewer.