WordPress.org

Make WordPress Core

Ticket #16042: 16042-full.patch

File 16042-full.patch, 17.4 KB (added by hakre, 7 years ago)

Patch against branch 2.9

  • wp-includes/kses.php

     
    11<?php
    22/**
    3  * HTML/XHTML filter that only allows some elements and attributes
     3 * kses 0.2.2 - HTML/XHTML filter that only allows some elements and attributes
     4 * Copyright (C) 2002, 2003, 2005  Ulf Harnhammar
    45 *
     6 * This program is free software and open source software; you can redistribute
     7 * it and/or modify it under the terms of the GNU General Public License as
     8 * published by the Free Software Foundation; either version 2 of the License,
     9 * or (at your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will be useful, but WITHOUT
     12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
     14 * more details.
     15 *
     16 * You should have received a copy of the GNU General Public License along
     17 * with this program; if not, write to the Free Software Foundation, Inc.,
     18 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  or visit
     19 * http://www.gnu.org/licenses/gpl.html
     20 *
     21 * [kses strips evil scripts!]
     22 *
    523 * Added wp_ prefix to avoid conflicts with existing kses users
    624 *
    725 * @version 0.2.2
     
    1028 *
    1129 * @package External
    1230 * @subpackage KSES
    13  *
    14  * @internal
    15  * *** CONTACT INFORMATION ***
    16  * E-mail:      metaur at users dot sourceforge dot net
    17  * Web page:    http://sourceforge.net/projects/kses
    18  * Paper mail:  Ulf Harnhammar
    19  *              Ymergatan 17 C
    20  *              753 25  Uppsala
    21  *              SWEDEN
    22  *
    23  * [kses strips evil scripts!]
    2431 */
    2532
    2633/**
     
    2936 *
    3037 * @since 1.2.0
    3138 */
    32 if (!defined('CUSTOM_TAGS'))
    33         define('CUSTOM_TAGS', false);
     39if ( ! defined( 'CUSTOM_TAGS' ) )
     40        define( 'CUSTOM_TAGS', false );
    3441
    35 if (!CUSTOM_TAGS) {
     42if ( ! CUSTOM_TAGS ) {
    3643        /**
    3744         * Kses global for default allowable HTML tags.
    3845         *
     
    5764                        'title' => array ()),
    5865                'acronym' => array(
    5966                        'title' => array ()),
     67                'article' => array(
     68                        'align' => array (),
     69                        'class' => array (),
     70                        'dir' => array (),
     71                        'lang' => array(),
     72                        'style' => array (),
     73                        'xml:lang' => array(),
     74                ),
     75                'aside' => array(
     76                        'align' => array (),
     77                        'class' => array (),
     78                        'dir' => array (),
     79                        'lang' => array(),
     80                        'style' => array (),
     81                        'xml:lang' => array(),
     82                ),
    6083                'b' => array(),
    6184                'big' => array(),
    6285                'blockquote' => array(
     
    94117                'del' => array(
    95118                        'datetime' => array ()),
    96119                'dd' => array(),
     120                'details' => array(
     121                        'align' => array (),
     122                        'class' => array (),
     123                        'dir' => array (),
     124                        'lang' => array(),
     125                        'open' => array (),
     126                        'style' => array (),
     127                        'xml:lang' => array(),
     128                ),
    97129                'div' => array(
    98130                        'align' => array (),
    99131                        'class' => array (),
     
    105137                'dt' => array(),
    106138                'em' => array(),
    107139                'fieldset' => array(),
     140                'figure' => array(
     141                        'align' => array (),
     142                        'class' => array (),
     143                        'dir' => array (),
     144                        'lang' => array(),
     145                        'style' => array (),
     146                        'xml:lang' => array(),
     147                ),
     148                'figcaption' => array(
     149                        'align' => array (),
     150                        'class' => array (),
     151                        'dir' => array (),
     152                        'lang' => array(),
     153                        'style' => array (),
     154                        'xml:lang' => array(),
     155                ),
    108156                'font' => array(
    109157                        'color' => array (),
    110158                        'face' => array (),
    111159                        'size' => array ()),
     160                'footer' => array(
     161                        'align' => array (),
     162                        'class' => array (),
     163                        'dir' => array (),
     164                        'lang' => array(),
     165                        'style' => array (),
     166                        'xml:lang' => array(),
     167                ),
    112168                'form' => array(
    113169                        'action' => array (),
    114170                        'accept' => array (),
     
    147203                        'class' => array (),
    148204                        'id'    => array (),
    149205                        'style' => array ()),
     206                'header' => array(
     207                        'align' => array (),
     208                        'class' => array (),
     209                        'dir' => array (),
     210                        'lang' => array(),
     211                        'style' => array (),
     212                        'xml:lang' => array(),
     213                ),
     214                'hgroup' => array(
     215                        'align' => array (),
     216                        'class' => array (),
     217                        'dir' => array (),
     218                        'lang' => array(),
     219                        'style' => array (),
     220                        'xml:lang' => array(),
     221                ),
    150222                'hr' => array (
    151223                        'align' => array (),
    152224                        'class' => array (),
     
    177249                'li' => array (
    178250                        'align' => array (),
    179251                        'class' => array ()),
     252                'menu' => array (
     253                        'class' => array (),
     254                        'style' => array (),
     255                        'type' => array ()),
     256                'nav' => array(
     257                        'align' => array (),
     258                        'class' => array (),
     259                        'dir' => array (),
     260                        'lang' => array(),
     261                        'style' => array (),
     262                        'xml:lang' => array(),
     263                ),
    180264                'p' => array(
    181265                        'class' => array (),
    182266                        'align' => array (),
     
    198282                        'style' => array (),
    199283                        'title' => array (),
    200284                        'xml:lang' => array()),
     285                'section' => array(
     286                        'align' => array (),
     287                        'class' => array (),
     288                        'dir' => array (),
     289                        'lang' => array(),
     290                        'style' => array (),
     291                        'xml:lang' => array(),
     292                ),
    201293                'strike' => array(),
    202294                'strong' => array(),
    203295                'sub' => array(),
     296                'summary' => array(
     297                        'align' => array (),
     298                        'class' => array (),
     299                        'dir' => array (),
     300                        'lang' => array(),
     301                        'style' => array (),
     302                        'xml:lang' => array(),
     303                ),
    204304                'sup' => array(),
    205305                'table' => array(
    206306                        'align' => array (),
     
    333433                //      'u' => array(),
    334434                //      'ul' => array(),
    335435        );
     436
     437        $allowedentitynames = array(
     438                'nbsp',    'iexcl',  'cent',    'pound',  'curren', 'yen',
     439                'brvbar',  'sect',   'uml',     'copy',   'ordf',   'laquo',
     440                'not',     'shy',    'reg',     'macr',   'deg',    'plusmn',
     441                'acute',   'micro',  'para',    'middot', 'cedil',  'ordm',
     442                'raquo',   'iquest', 'Agrave',  'Aacute', 'Acirc',  'Atilde',
     443                'Auml',    'Aring',  'AElig',   'Ccedil', 'Egrave', 'Eacute',
     444                'Ecirc',   'Euml',   'Igrave',  'Iacute', 'Icirc',  'Iuml',
     445                'ETH',     'Ntilde', 'Ograve',  'Oacute', 'Ocirc',  'Otilde',
     446                'Ouml',    'times',  'Oslash',  'Ugrave', 'Uacute', 'Ucirc',
     447                'Uuml',    'Yacute', 'THORN',   'szlig',  'agrave', 'aacute',
     448                'acirc',   'atilde', 'auml',    'aring',  'aelig',  'ccedil',
     449                'egrave',  'eacute', 'ecirc',   'euml',   'igrave', 'iacute',
     450                'icirc',   'iuml',   'eth',     'ntilde', 'ograve', 'oacute',
     451                'ocirc',   'otilde', 'ouml',    'divide', 'oslash', 'ugrave',
     452                'uacute',  'ucirc',  'uuml',    'yacute', 'thorn',  'yuml',
     453                'quot',    'amp',    'lt',      'gt',     'apos',   'OElig',
     454                'oelig',   'Scaron', 'scaron',  'Yuml',   'circ',   'tilde',
     455                'ensp',    'emsp',   'thinsp',  'zwnj',   'zwj',    'lrm',
     456                'rlm',     'ndash',  'mdash',   'lsquo',  'rsquo',  'sbquo',
     457                'ldquo',   'rdquo',  'bdquo',   'dagger', 'Dagger', 'permil',
     458                'lsaquo',  'rsaquo', 'euro',    'fnof',   'Alpha',  'Beta',
     459                'Gamma',   'Delta',  'Epsilon', 'Zeta',   'Eta',    'Theta',
     460                'Iota',    'Kappa',  'Lambda',  'Mu',     'Nu',     'Xi',
     461                'Omicron', 'Pi',     'Rho',     'Sigma',  'Tau',    'Upsilon',
     462                'Phi',     'Chi',    'Psi',     'Omega',  'alpha',  'beta',
     463                'gamma',   'delta',  'epsilon', 'zeta',   'eta',    'theta',
     464                'iota',    'kappa',  'lambda',  'mu',     'nu',     'xi',
     465                'omicron', 'pi',     'rho',     'sigmaf', 'sigma',  'tau',
     466                'upsilon', 'phi',    'chi',     'psi',    'omega',  'thetasym',
     467                'upsih',   'piv',    'bull',    'hellip', 'prime',  'Prime',
     468                'oline',   'frasl',  'weierp',  'image',  'real',   'trade',
     469                'alefsym', 'larr',   'uarr',    'rarr',   'darr',   'harr',
     470                'crarr',   'lArr',   'uArr',    'rArr',   'dArr',   'hArr',
     471                'forall',  'part',   'exist',   'empty',  'nabla',  'isin',
     472                'notin',   'ni',     'prod',    'sum',    'minus',  'lowast',
     473                'radic',   'prop',   'infin',   'ang',    'and',    'or',
     474                'cap',     'cup',    'int',     'sim',    'cong',   'asymp',
     475                'ne',      'equiv',  'le',      'ge',     'sub',    'sup',
     476                'nsub',    'sube',   'supe',    'oplus',  'otimes', 'perp',
     477                'sdot',    'lceil',  'rceil',   'lfloor', 'rfloor', 'lang',
     478                'rang',    'loz',    'spades',  'clubs',  'hearts', 'diams',
     479        );
    336480}
    337481
    338482/**
     
    344488 * call this function.
    345489 *
    346490 * The default allowed protocols are 'http', 'https', 'ftp', 'mailto', 'news',
    347  * 'irc', 'gopher', 'nntp', 'feed', and finally 'telnet. This covers all common
    348  * link protocols, except for 'javascript' which should not be allowed for
    349  * untrusted users.
     491 * 'irc', 'gopher', 'nntp', 'feed', 'telnet, 'mms', 'rtsp' and 'svn'. This
     492 * covers all common link protocols, except for 'javascript' which should not
     493 * be allowed for untrusted users.
    350494 *
    351495 * @since 1.0.0
    352496 *
     
    355499 * @param array $allowed_protocols Optional. Allowed protocol in links.
    356500 * @return string Filtered content with only allowed HTML elements
    357501 */
    358 function wp_kses($string, $allowed_html, $allowed_protocols = array ('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet')) {
     502function wp_kses($string, $allowed_html, $allowed_protocols = array ()) {
     503        $allowed_protocols = wp_parse_args( $allowed_protocols, apply_filters('kses_allowed_protocols', array ('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn') ));
    359504        $string = wp_kses_no_null($string);
    360505        $string = wp_kses_js_entities($string);
    361506        $string = wp_kses_normalize_entities($string);
     
    409554        global $pass_allowed_html, $pass_allowed_protocols;
    410555        $pass_allowed_html = $allowed_html;
    411556        $pass_allowed_protocols = $allowed_protocols;
    412         return preg_replace_callback('%((<!--.*?(-->|$))|(<[^>]*(>|$)|>))%',
    413                 create_function('$match', 'global $pass_allowed_html, $pass_allowed_protocols; return wp_kses_split2($match[1], $pass_allowed_html, $pass_allowed_protocols);'), $string);
     557        return preg_replace_callback( '%((<!--.*?(-->|$))|(<[^>]*(>|$)|>))%', '_wp_kses_split_callback', $string );
    414558}
    415559
    416560/**
     561 * Callback for wp_kses_split.
     562 *
     563 * @since 3.1.0
     564 * @access private
     565 */
     566function _wp_kses_split_callback( $match ) {
     567        global $pass_allowed_html, $pass_allowed_protocols;
     568        return wp_kses_split2( $match[1], $pass_allowed_html, $pass_allowed_protocols );
     569}
     570
     571/**
    417572 * Callback for wp_kses_split for fixing malformed HTML tags.
    418573 *
    419574 * This function does a lot of work. It rejects some very malformed things like
     
    495650        # Is there a closing XHTML slash at the end of the attributes?
    496651
    497652        $xhtml_slash = '';
    498         if (preg_match('%\s/\s*$%', $attr))
     653        if (preg_match('%\s*/\s*$%', $attr))
    499654                $xhtml_slash = ' /';
    500655
    501656        # Are any attributes allowed at all for this element?
     
    533688                                        break;
    534689                                }
    535690
    536                         if ( $arreach['name'] == 'style' ) {
     691                        if ( strtolower($arreach['name']) == 'style' ) {
    537692                                $orig_value = $arreach['value'];
    538693
    539694                                $value = safecss_filter_attr($orig_value);
     
    621776
    622777                        case 2 : # attribute value, a URL after href= for instance
    623778
    624                                 if (preg_match('/^"([^"]*)"(\s+|$)/', $attr, $match))
     779                                if (preg_match('%^"([^"]*)"(\s+|/?$)%', $attr, $match))
    625780                                        # "value"
    626781                                        {
    627782                                        $thisval = $match[1];
    628                                         if ( in_array($attrname, $uris) )
     783                                        if ( in_array(strtolower($attrname), $uris) )
    629784                                                $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols);
    630785
    631786                                        if(FALSE === array_key_exists($attrname, $attrarr)) {
     
    637792                                        break;
    638793                                }
    639794
    640                                 if (preg_match("/^'([^']*)'(\s+|$)/", $attr, $match))
     795                                if (preg_match("%^'([^']*)'(\s+|/?$)%", $attr, $match))
    641796                                        # 'value'
    642797                                        {
    643798                                        $thisval = $match[1];
    644                                         if ( in_array($attrname, $uris) )
     799                                        if ( in_array(strtolower($attrname), $uris) )
    645800                                                $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols);
    646801
    647802                                        if(FALSE === array_key_exists($attrname, $attrarr)) {
     
    653808                                        break;
    654809                                }
    655810
    656                                 if (preg_match("%^([^\s\"']+)(\s+|$)%", $attr, $match))
     811                                if (preg_match("%^([^\s\"']+)(\s+|/?$)%", $attr, $match))
    657812                                        # value
    658813                                        {
    659814                                        $thisval = $match[1];
    660                                         if ( in_array($attrname, $uris) )
     815                                        if ( in_array(strtolower($attrname), $uris) )
    661816                                                $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols);
    662817
    663818                                        if(FALSE === array_key_exists($attrname, $attrarr)) {
     
    699854 * @param string $vless Whether the value is valueless or not. Use 'y' or 'n'
    700855 * @param string $checkname What $checkvalue is checking for.
    701856 * @param mixed $checkvalue What constraint the value should pass
    702  * @return bool Whether check passes (true) or not (false)
     857 * @return bool Whether check passes
    703858 */
    704859function wp_kses_check_attr_val($value, $vless, $checkname, $checkvalue) {
    705860        $ok = true;
     
    8801035 * @return string Sanitized content
    8811036 */
    8821037function wp_kses_bad_protocol_once($string, $allowed_protocols) {
    883         global $_kses_allowed_protocols;
    884         $_kses_allowed_protocols = $allowed_protocols;
     1038        $string2 = preg_split( '/:|&#0*58;|&#x0*3a;/i', $string, 2 );
     1039        if ( isset($string2[1]) && ! preg_match('%/\?%', $string2[0]) )
     1040                $string = wp_kses_bad_protocol_once2( $string2[0], $allowed_protocols ) . trim( $string2[1] );
    8851041
    886         $string2 = preg_split('/:|&#58;|&#x3a;/i', $string, 2);
    887         if ( isset($string2[1]) && !preg_match('%/\?%', $string2[0]) )
    888                 $string = wp_kses_bad_protocol_once2($string2[0]) . trim($string2[1]);
    889         else
    890                 $string = preg_replace_callback('/^((&[^;]*;|[\sA-Za-z0-9])*)'.'(:|&#58;|&#[Xx]3[Aa];)\s*/', 'wp_kses_bad_protocol_once2', $string);
    891 
    8921042        return $string;
    8931043}
    8941044
     
    9011051 * @access private
    9021052 * @since 1.0.0
    9031053 *
    904  * @param mixed $matches string or preg_replace_callback() matches array to check for bad protocols
     1054 * @param string $string URI scheme to check against the whitelist
     1055 * @param string $allowed_protocols Allowed protocols
    9051056 * @return string Sanitized content
    9061057 */
    907 function wp_kses_bad_protocol_once2($matches) {
    908         global $_kses_allowed_protocols;
    909 
    910         if ( is_array($matches) ) {
    911                 if ( ! isset($matches[1]) || empty($matches[1]) )
    912                         return '';
    913 
    914                 $string = $matches[1];
    915         } else {
    916                 $string = $matches;
    917         }
    918 
     1058function wp_kses_bad_protocol_once2( $string, $allowed_protocols ) {
    9191059        $string2 = wp_kses_decode_entities($string);
    9201060        $string2 = preg_replace('/\s/', '', $string2);
    9211061        $string2 = wp_kses_no_null($string2);
    9221062        $string2 = strtolower($string2);
    9231063
    9241064        $allowed = false;
    925         foreach ( (array) $_kses_allowed_protocols as $one_protocol)
    926                 if (strtolower($one_protocol) == $string2) {
     1065        foreach ( (array) $allowed_protocols as $one_protocol )
     1066                if ( strtolower($one_protocol) == $string2 ) {
    9271067                        $allowed = true;
    9281068                        break;
    9291069                }
     
    9521092
    9531093        # Change back the allowed entities in our entity whitelist
    9541094
    955         $string = preg_replace('/&amp;([A-Za-z][A-Za-z0-9]{0,19});/', '&\\1;', $string);
    956         $string = preg_replace_callback('/&amp;#0*([0-9]{1,5});/', 'wp_kses_normalize_entities2', $string);
    957         $string = preg_replace_callback('/&amp;#([Xx])0*(([0-9A-Fa-f]{2}){1,2});/', 'wp_kses_normalize_entities3', $string);
     1095        $string = preg_replace_callback('/&amp;([A-Za-z]{2,8});/', 'wp_kses_named_entities', $string);
     1096        $string = preg_replace_callback('/&amp;#(0*[0-9]{1,7});/', 'wp_kses_normalize_entities2', $string);
     1097        $string = preg_replace_callback('/&amp;#[Xx](0*[0-9A-Fa-f]{1,6});/', 'wp_kses_normalize_entities3', $string);
    9581098
    9591099        return $string;
    9601100}
     
    9621102/**
    9631103 * Callback for wp_kses_normalize_entities() regular expression.
    9641104 *
     1105 * This function only accepts valid named entity references, which are finite,
     1106 * case-sensitive, and highly scrutinized by HTML and XML validators.
     1107 *
     1108 * @since 3.0.0
     1109 *
     1110 * @param array $matches preg_replace_callback() matches array
     1111 * @return string Correctly encoded entity
     1112 */
     1113function wp_kses_named_entities($matches) {
     1114        global $allowedentitynames;
     1115
     1116        if ( empty($matches[1]) )
     1117                return '';
     1118
     1119        $i = $matches[1];
     1120        return ( ( ! in_array($i, $allowedentitynames) ) ? "&amp;$i;" : "&$i;" );
     1121}
     1122
     1123/**
     1124 * Callback for wp_kses_normalize_entities() regular expression.
     1125 *
    9651126 * This function helps wp_kses_normalize_entities() to only accept 16 bit values
    9661127 * and nothing more for &#number; entities.
    9671128 *
     
    9721133 * @return string Correctly encoded entity
    9731134 */
    9741135function wp_kses_normalize_entities2($matches) {
    975         if ( ! isset($matches[1]) || empty($matches[1]) )
     1136        if ( empty($matches[1]) )
    9761137                return '';
    9771138
    9781139        $i = $matches[1];
    979         return ( ( ! valid_unicode($i) ) || ($i > 65535) ? "&amp;#$i;" : "&#$i;" );
     1140        if (valid_unicode($i)) {
     1141                $i = str_pad(ltrim($i,'0'), 3, '0', STR_PAD_LEFT);
     1142                $i = "&#$i;";
     1143        } else {
     1144                $i = "&amp;#$i;";
     1145        }
     1146
     1147        return $i;
    9801148}
    9811149
    9821150/**
     
    9911159 * @return string Correctly encoded entity
    9921160 */
    9931161function wp_kses_normalize_entities3($matches) {
    994         if ( ! isset($matches[2]) || empty($matches[2]) )
     1162        if ( empty($matches[1]) )
    9951163                return '';
    9961164
    997         $hexchars = $matches[2];
    998         return ( ( ! valid_unicode(hexdec($hexchars)) ) ? "&amp;#x$hexchars;" : "&#x$hexchars;" );
     1165        $hexchars = $matches[1];
     1166        return ( ( ! valid_unicode(hexdec($hexchars)) ) ? "&amp;#x$hexchars;" : '&#x'.ltrim($hexchars,'0').';' );
    9991167}
    10001168
    10011169/**
     
    11961364add_action('init', 'kses_init');
    11971365add_action('set_current_user', 'kses_init');
    11981366
     1367/**
     1368 * Inline CSS filter
     1369 *
     1370 * @since 2.8.1
     1371 */
    11991372function safecss_filter_attr( $css, $deprecated = '' ) {
    12001373        $css = wp_kses_no_null($css);
    12011374        $css = str_replace(array("\n","\r","\t"), '', $css);
    12021375
    1203         if ( preg_match( '%[\\(&]|/\*%', $css ) ) // remove any inline css containing \ ( & or comments
     1376        if ( preg_match( '%[\\(&=}]|/\*%', $css ) ) // remove any inline css containing \ ( & } = or comments
    12041377                return '';
    12051378
    1206         $css_array = split( ';', trim( $css ) );
     1379        $css_array = explode( ';', trim( $css ) );
    12071380        $allowed_attr = apply_filters( 'safe_style_css', array( 'text-align', 'margin', 'color', 'float',
    12081381        'border', 'background', 'background-color', 'border-bottom', 'border-bottom-color',
    12091382        'border-bottom-style', 'border-bottom-width', 'border-collapse', 'border-color', 'border-left',