mirror of
https://github.com/gosticks/wordpress-develop.git
synced 2025-10-16 12:05:38 +00:00
Per the documentation standards, it should not be used outside of the default bundled themes. Follow-up to [38767], [47055], [49697], [50956], [51003], [52069], [53255]. See #54729. git-svn-id: https://develop.svn.wordpress.org/trunk@53331 602fd350-edb4-49c9-b593-d223f7449a82
1995 lines
59 KiB
PHP
1995 lines
59 KiB
PHP
<?php
|
|
/**
|
|
* Some simple test cases for KSES post content filtering
|
|
*
|
|
* @group formatting
|
|
* @group kses
|
|
*/
|
|
class Tests_Kses extends WP_UnitTestCase {
|
|
|
|
/**
|
|
* @dataProvider data_wp_filter_post_kses_address
|
|
* @ticket 20210
|
|
*
|
|
* @param string $string Test string for kses.
|
|
* @param string $expect_string Expected result after passing through kses.
|
|
*/
|
|
public function test_wp_filter_post_kses_address( $string, $expect_string ) {
|
|
global $allowedposttags;
|
|
|
|
$this->assertSame( $expect_string, wp_kses( $string, $allowedposttags ) );
|
|
}
|
|
|
|
/**
|
|
* Data provider for test_wp_filter_post_kses_address.
|
|
*
|
|
* @return array[] Arguments {
|
|
* @type string $string Test string for kses.
|
|
* @type string $expect_string Expected result after passing through kses.
|
|
* }
|
|
*/
|
|
public function data_wp_filter_post_kses_address() {
|
|
$attributes = array(
|
|
'class' => 'classname',
|
|
'id' => 'id',
|
|
'style' => array(
|
|
'color: red;',
|
|
'color: red',
|
|
'color: red; text-align:center',
|
|
'color: red; text-align:center;',
|
|
),
|
|
'title' => 'title',
|
|
);
|
|
|
|
$data = array();
|
|
|
|
foreach ( $attributes as $name => $values ) {
|
|
foreach ( (array) $values as $value ) {
|
|
$string = "<address $name='$value'>1 WordPress Avenue, The Internet.</address>";
|
|
$expect_string = "<address $name='" . str_replace( '; ', ';', trim( $value, ';' ) ) . "'>1 WordPress Avenue, The Internet.</address>";
|
|
|
|
$data[] = array( $string, $expect_string );
|
|
}
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* @dataProvider data_wp_filter_post_kses_a
|
|
* @ticket 20210
|
|
*
|
|
* @param string $string Test string for kses.
|
|
* @param string $expect_string Expected result after passing through kses.
|
|
*/
|
|
public function test_wp_filter_post_kses_a( $string, $expect_string ) {
|
|
global $allowedposttags;
|
|
|
|
$this->assertSame( $expect_string, wp_kses( $string, $allowedposttags ) );
|
|
}
|
|
|
|
/**
|
|
* Data provider for test_wp_filter_post_kses_a.
|
|
*
|
|
* @return array[] Arguments {
|
|
* @type string $string Test string for kses.
|
|
* @type string $expect_string Expected result after passing through kses.
|
|
* }
|
|
*/
|
|
public function data_wp_filter_post_kses_a() {
|
|
$attributes = array(
|
|
'class' => 'classname',
|
|
'id' => 'id',
|
|
'style' => 'color: red;',
|
|
'title' => 'title',
|
|
'href' => 'http://example.com',
|
|
'rel' => 'related',
|
|
'rev' => 'revision',
|
|
'name' => 'name',
|
|
'target' => '_blank',
|
|
'download' => '',
|
|
);
|
|
|
|
$data = array();
|
|
|
|
foreach ( $attributes as $name => $value ) {
|
|
if ( $value ) {
|
|
$attr = "$name='$value'";
|
|
$expected_attr = "$name='" . trim( $value, ';' ) . "'";
|
|
} else {
|
|
$attr = $name;
|
|
$expected_attr = $name;
|
|
}
|
|
$string = "<a $attr>I link this</a>";
|
|
$expect_string = "<a $expected_attr>I link this</a>";
|
|
$data[] = array( $string, $expect_string );
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Test video tag.
|
|
*
|
|
* @ticket 50167
|
|
* @ticket 29826
|
|
* @dataProvider data_wp_kses_video
|
|
*
|
|
* @param string $source Source HTML.
|
|
* @param string $context Context to use for parsing source.
|
|
* @param string $expected Expected output following KSES parsing.
|
|
*/
|
|
public function test_wp_kses_video( $source, $context, $expected ) {
|
|
$actual = wp_kses( $source, $context );
|
|
$this->assertSame( $expected, $actual );
|
|
}
|
|
|
|
/**
|
|
* Data provider for test_wp_kses_video
|
|
*
|
|
* @return array[] Array containing test data {
|
|
* @type string $source Source HTML.
|
|
* @type string $context Context to use for parsing source.
|
|
* @type string $expected Expected output following KSES parsing.
|
|
* }
|
|
*/
|
|
public function data_wp_kses_video() {
|
|
return array(
|
|
// Set 0: Valid post object params in post context.
|
|
array(
|
|
'<video src="movie.mov" autoplay controls height=9 loop muted poster="still.gif" playsinline preload width=16 />',
|
|
'post',
|
|
'<video src="movie.mov" autoplay controls height="9" loop muted poster="still.gif" playsinline preload width="16" />',
|
|
),
|
|
// Set 1: Valid post object params in data context.
|
|
array(
|
|
'<video src="movie.mov" autoplay controls height=9 loop muted poster="still.gif" playsinline preload width=16 />',
|
|
'data',
|
|
'',
|
|
),
|
|
// Set 2: Disallowed urls in post context.
|
|
array(
|
|
'<video src="bad://w.org/movie.mov" poster="bad://w.org/movie.jpg" />',
|
|
'post',
|
|
'<video src="//w.org/movie.mov" poster="//w.org/movie.jpg" />',
|
|
),
|
|
// Set 3: Disallowed attributes in post context.
|
|
array(
|
|
'<video onload="alert(1);" src="https://videos.files.wordpress.com/DZEMDKxc/video-0f9c363010.mp4" />',
|
|
'post',
|
|
'<video src="https://videos.files.wordpress.com/DZEMDKxc/video-0f9c363010.mp4" />',
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider data_wp_filter_post_kses_abbr
|
|
* @ticket 20210
|
|
*
|
|
* @param string $string Test string for kses.
|
|
* @param string $expect_string Expected result after passing through kses.
|
|
*/
|
|
public function test_wp_filter_post_kses_abbr( $string, $expect_string ) {
|
|
global $allowedposttags;
|
|
|
|
$this->assertSame( $expect_string, wp_kses( $string, $allowedposttags ) );
|
|
}
|
|
|
|
/**
|
|
* Data provider for data_wp_filter_post_kses_abbr.
|
|
*
|
|
* @return array[] Arguments {
|
|
* @type string $string Test string for kses.
|
|
* @type string $expect_string Expected result after passing through kses.
|
|
* }
|
|
*/
|
|
public function data_wp_filter_post_kses_abbr() {
|
|
$attributes = array(
|
|
'class' => 'classname',
|
|
'id' => 'id',
|
|
'style' => 'color: red;',
|
|
'title' => 'title',
|
|
);
|
|
|
|
$data = array();
|
|
|
|
foreach ( $attributes as $name => $value ) {
|
|
$string = "<abbr $name='$value'>WP</abbr>";
|
|
$expect_string = "<abbr $name='" . trim( $value, ';' ) . "'>WP</abbr>";
|
|
$data[] = array( $string, $expect_string );
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
public function test_feed_links() {
|
|
global $allowedposttags;
|
|
|
|
$content = <<<EOF
|
|
<a href="feed:javascript:alert(1)">CLICK ME</a>
|
|
<a href="feed:javascript:feed:alert(1)">CLICK ME</a>
|
|
<a href="feed:feed:javascript:alert(1)">CLICK ME</a>
|
|
<a href="javascript:feed:alert(1)">CLICK ME</a>
|
|
<a href="javascript:feed:javascript:alert(1)">CLICK ME</a>
|
|
<a href="feed:feed:feed:javascript:alert(1)">CLICK ME</a>
|
|
<a href="feed:feed:feed:feed:javascript:alert(1)">CLICK ME</a>
|
|
<a href="feed:feed:feed:feed:feed:javascript:alert(1)">CLICK ME</a>
|
|
<a href="feed:javascript:feed:javascript:feed:javascript:alert(1)">CLICK ME</a>
|
|
<a href="feed:javascript:feed:javascript:feed:javascript:feed:javascript:feed:javascript:alert(1)">CLICK ME</a>
|
|
<a href="feed:feed:feed:http:alert(1)">CLICK ME</a>
|
|
EOF;
|
|
|
|
$expected = <<<EOF
|
|
<a href="feed:alert(1)">CLICK ME</a>
|
|
<a href="feed:feed:alert(1)">CLICK ME</a>
|
|
<a href="feed:feed:alert(1)">CLICK ME</a>
|
|
<a href="feed:alert(1)">CLICK ME</a>
|
|
<a href="feed:alert(1)">CLICK ME</a>
|
|
<a href="">CLICK ME</a>
|
|
<a href="">CLICK ME</a>
|
|
<a href="">CLICK ME</a>
|
|
<a href="">CLICK ME</a>
|
|
<a href="">CLICK ME</a>
|
|
<a href="">CLICK ME</a>
|
|
EOF;
|
|
|
|
$this->assertSame( $expected, wp_kses( $content, $allowedposttags ) );
|
|
}
|
|
|
|
public function test_wp_kses_bad_protocol() {
|
|
$bad = array(
|
|
'dummy:alert(1)',
|
|
'javascript:alert(1)',
|
|
'JaVaScRiPt:alert(1)',
|
|
'javascript:alert(1);',
|
|
'javascript:alert(1);',
|
|
'javascript:alert(1);',
|
|
'javascript:alert(1);',
|
|
'javascript:alert(1);',
|
|
'javascript:alert(1);',
|
|
'javascript:alert(1);',
|
|
'javascript:alert(1);',
|
|
'javascript:alert(1);',
|
|
'javascript:alert('XSS')',
|
|
'jav ascript:alert(1);',
|
|
'jav	ascript:alert(1);',
|
|
'jav
ascript:alert(1);',
|
|
'jav
ascript:alert(1);',
|
|
'  javascript:alert(1);',
|
|
'javascript:javascript:alert(1);',
|
|
'javascript:javascript:alert(1);',
|
|
'javascript:javascript:alert(1);',
|
|
'javascript:javascript:alert(1);',
|
|
'javascript:javascript:alert(1);',
|
|
'javascript:alert(1)//?:',
|
|
'feed:javascript:alert(1)',
|
|
'feed:javascript:feed:javascript:feed:javascript:alert(1)',
|
|
'javascript:alert(1)',
|
|
'javascript:x=1;alert(1)',
|
|
);
|
|
foreach ( $bad as $k => $x ) {
|
|
$result = wp_kses_bad_protocol( wp_kses_normalize_entities( $x ), wp_allowed_protocols() );
|
|
if ( ! empty( $result ) && 'alert(1);' !== $result && 'alert(1)' !== $result ) {
|
|
switch ( $k ) {
|
|
case 6:
|
|
$this->assertSame( 'javascript&#0000058alert(1);', $result );
|
|
break;
|
|
case 12:
|
|
$this->assertSame( str_replace( '&', '&', $x ), $result );
|
|
break;
|
|
case 22:
|
|
$this->assertSame( 'javascript&#0000058alert(1);', $result );
|
|
break;
|
|
case 23:
|
|
$this->assertSame( 'javascript&#0000058alert(1)//?:', $result );
|
|
break;
|
|
case 24:
|
|
$this->assertSame( 'feed:alert(1)', $result );
|
|
break;
|
|
case 26:
|
|
$this->assertSame( 'javascript&#58alert(1)', $result );
|
|
break;
|
|
case 27:
|
|
$this->assertSame( 'javascript&#x3ax=1;alert(1)', $result );
|
|
break;
|
|
default:
|
|
$this->fail( "wp_kses_bad_protocol failed on $k, $x. Result: $result" );
|
|
}
|
|
}
|
|
}
|
|
|
|
$bad_not_normalized = array(
|
|
'dummy:alert(1)',
|
|
'javascript:alert(1)',
|
|
'javascript&CoLon;alert(1)',
|
|
'javascript&COLON;alert(1);',
|
|
'javascript:alert(1);',
|
|
'javascript:alert(1);',
|
|
'javascript:alert(1);',
|
|
'jav ascript&COLON;alert(1);',
|
|
'javascript:javascript:alert(1);',
|
|
'javascript:javascript:alert(1);',
|
|
'javascript:javascript:alert(1);',
|
|
'javascript:javascript:alert(1);',
|
|
'javascript:alert(1)',
|
|
);
|
|
foreach ( $bad_not_normalized as $k => $x ) {
|
|
$result = wp_kses_bad_protocol( $x, wp_allowed_protocols() );
|
|
if ( ! empty( $result ) && 'alert(1);' !== $result && 'alert(1)' !== $result ) {
|
|
$this->fail( "wp_kses_bad_protocol failed on $k, $x. Result: $result" );
|
|
}
|
|
}
|
|
|
|
$safe = array(
|
|
'dummy:alert(1)',
|
|
'HTTP://example.org/',
|
|
'http://example.org/',
|
|
'http://example.org/',
|
|
'http://example.org/',
|
|
'https://example.org',
|
|
'http://example.org/wp-admin/post.php?post=2&action=edit',
|
|
'http://example.org/index.php?test='blah'',
|
|
);
|
|
foreach ( $safe as $x ) {
|
|
$result = wp_kses_bad_protocol( wp_kses_normalize_entities( $x ), array( 'http', 'https', 'dummy' ) );
|
|
if ( $result !== $x && 'http://example.org/' !== $result ) {
|
|
$this->fail( "wp_kses_bad_protocol incorrectly blocked $x" );
|
|
}
|
|
}
|
|
}
|
|
|
|
public function test_hackers_attacks() {
|
|
$xss = simplexml_load_file( DIR_TESTDATA . '/formatting/xssAttacks.xml' );
|
|
foreach ( $xss->attack as $attack ) {
|
|
if ( in_array( (string) $attack->name, array( 'IMG Embedded commands 2', 'US-ASCII encoding', 'OBJECT w/Flash 2', 'Character Encoding Example' ), true ) ) {
|
|
continue;
|
|
}
|
|
|
|
$code = (string) $attack->code;
|
|
|
|
if ( 'See Below' === $code ) {
|
|
continue;
|
|
}
|
|
|
|
if ( substr( $code, 0, 4 ) === 'perl' ) {
|
|
$pos = strpos( $code, '"' ) + 1;
|
|
$code = substr( $code, $pos, strrpos( $code, '"' ) - $pos );
|
|
$code = str_replace( '\0', "\0", $code );
|
|
}
|
|
|
|
$result = trim( wp_kses_data( $code ) );
|
|
|
|
if ( in_array( $result, array( '', 'XSS', 'alert("XSS");', "alert('XSS');" ), true ) ) {
|
|
continue;
|
|
}
|
|
|
|
switch ( $attack->name ) {
|
|
case 'XSS Locator':
|
|
$this->assertSame( '\';alert(String.fromCharCode(88,83,83))//\\\';alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//\\";alert(String.fromCharCode(88,83,83))//-->">\'>alert(String.fromCharCode(88,83,83))=&{}', $result );
|
|
break;
|
|
case 'XSS Quick Test':
|
|
$this->assertSame( '\'\';!--"=&{()}', $result );
|
|
break;
|
|
case 'SCRIPT w/Alert()':
|
|
$this->assertSame( "alert('XSS')", $result );
|
|
break;
|
|
case 'SCRIPT w/Char Code':
|
|
$this->assertSame( 'alert(String.fromCharCode(88,83,83))', $result );
|
|
break;
|
|
case 'IMG STYLE w/expression':
|
|
$this->assertSame( 'exp/*', $result );
|
|
break;
|
|
case 'List-style-image':
|
|
$this->assertSame( 'li {list-style-image: url("javascript:alert(\'XSS\')");}XSS', $result );
|
|
break;
|
|
case 'STYLE':
|
|
$this->assertSame( "alert('XSS');", $result );
|
|
break;
|
|
case 'STYLE w/background-image':
|
|
$this->assertSame( '.XSS{background-image:url("javascript:alert(\'XSS\')");}<A></A>', $result );
|
|
break;
|
|
case 'STYLE w/background':
|
|
$this->assertSame( 'BODY{background:url("javascript:alert(\'XSS\')")}', $result );
|
|
break;
|
|
case 'Remote Stylesheet 2':
|
|
$this->assertSame( "@import'http://ha.ckers.org/xss.css';", $result );
|
|
break;
|
|
case 'Remote Stylesheet 3':
|
|
$this->assertSame( '<META HTTP-EQUIV="Link" Content="; REL=stylesheet">', $result );
|
|
break;
|
|
case 'Remote Stylesheet 4':
|
|
$this->assertSame( 'BODY{-moz-binding:url("http://ha.ckers.org/xssmoz.xml#xss")}', $result );
|
|
break;
|
|
case 'XML data island w/CDATA':
|
|
$this->assertSame( '<![CDATA[]]>', $result );
|
|
break;
|
|
case 'XML data island w/comment':
|
|
$this->assertSame( "<I><B><IMG SRC="javas<!-- -->cript:alert('XSS')\"></B></I>", $result );
|
|
break;
|
|
case 'XML HTML+TIME':
|
|
$this->assertSame( '<t:set attributeName="innerHTML" to="XSSalert(\'XSS\')">', $result );
|
|
break;
|
|
case 'Commented-out Block':
|
|
$this->assertSame( "<!--[if gte IE 4]>-->\nalert('XSS');", $result );
|
|
break;
|
|
case 'Cookie Manipulation':
|
|
$this->assertSame( '<META HTTP-EQUIV="Set-Cookie" Content="USERID=alert(\'XSS\')">', $result );
|
|
break;
|
|
case 'SSI':
|
|
$this->assertSame( '<!--#exec cmd="/bin/echo '<!--#exec cmd="/bin/echo \'=http://ha.ckers.org/xss.js>\'"-->', $result );
|
|
break;
|
|
case 'PHP':
|
|
$this->assertSame( '<? echo('alert("XSS")\'); ?>', $result );
|
|
break;
|
|
case 'UTF-7 Encoding':
|
|
$this->assertSame( '+ADw-SCRIPT+AD4-alert(\'XSS\');+ADw-/SCRIPT+AD4-', $result );
|
|
break;
|
|
case 'Escaping JavaScript escapes':
|
|
$this->assertSame( '\";alert(\'XSS\');//', $result );
|
|
break;
|
|
case 'STYLE w/broken up JavaScript':
|
|
$this->assertSame( '@im\port\'\ja\vasc\ript:alert("XSS")\';', $result );
|
|
break;
|
|
case 'Null Chars 2':
|
|
$this->assertSame( '&alert("XSS")', $result );
|
|
break;
|
|
case 'No Closing Script Tag':
|
|
$this->assertSame( '<SCRIPT SRC=http://ha.ckers.org/xss.js', $result );
|
|
break;
|
|
case 'Half-Open HTML/JavaScript':
|
|
$this->assertSame( '<IMG SRC="javascript:alert('XSS')"', $result );
|
|
break;
|
|
case 'Double open angle brackets':
|
|
$this->assertSame( '<IFRAME SRC=http://ha.ckers.org/scriptlet.html <', $result );
|
|
break;
|
|
case 'Extraneous Open Brackets':
|
|
$this->assertSame( '<alert("XSS");//<', $result );
|
|
break;
|
|
case 'Malformed IMG Tags':
|
|
$this->assertSame( 'alert("XSS")">', $result );
|
|
break;
|
|
case 'No Quotes/Semicolons':
|
|
$this->assertSame( "a=/XSS/\nalert(a.source)", $result );
|
|
break;
|
|
case 'Evade Regex Filter 1':
|
|
$this->assertSame( '" SRC="http://ha.ckers.org/xss.js">', $result );
|
|
break;
|
|
case 'Evade Regex Filter 4':
|
|
$this->assertSame( '\'" SRC="http://ha.ckers.org/xss.js">', $result );
|
|
break;
|
|
case 'Evade Regex Filter 5':
|
|
$this->assertSame( '` SRC="http://ha.ckers.org/xss.js">', $result );
|
|
break;
|
|
case 'Filter Evasion 1':
|
|
$this->assertSame( 'document.write("<SCRI");PT SRC="http://ha.ckers.org/xss.js">', $result );
|
|
break;
|
|
case 'Filter Evasion 2':
|
|
$this->assertSame( '\'>" SRC="http://ha.ckers.org/xss.js">', $result );
|
|
break;
|
|
default:
|
|
$this->fail( 'KSES failed on ' . $attack->name . ': ' . $result );
|
|
}
|
|
}
|
|
}
|
|
|
|
public function wp_kses_allowed_html_filter( $html, $context ) {
|
|
if ( 'post' === $context ) {
|
|
return array( 'a' => array( 'href' => true ) );
|
|
} else {
|
|
return array( 'a' => array( 'href' => false ) );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @ticket 20210
|
|
*/
|
|
public function test_wp_kses_allowed_html() {
|
|
global $allowedposttags, $allowedtags, $allowedentitynames;
|
|
|
|
$this->assertSame( $allowedposttags, wp_kses_allowed_html( 'post' ) );
|
|
|
|
$tags = wp_kses_allowed_html( 'post' );
|
|
|
|
foreach ( $tags as $tag ) {
|
|
$this->assertTrue( $tag['class'] );
|
|
$this->assertTrue( $tag['dir'] );
|
|
$this->assertTrue( $tag['id'] );
|
|
$this->assertTrue( $tag['lang'] );
|
|
$this->assertTrue( $tag['style'] );
|
|
$this->assertTrue( $tag['title'] );
|
|
$this->assertTrue( $tag['xml:lang'] );
|
|
}
|
|
|
|
$this->assertSame( $allowedtags, wp_kses_allowed_html( 'data' ) );
|
|
$this->assertSame( $allowedtags, wp_kses_allowed_html( '' ) );
|
|
$this->assertSame( $allowedtags, wp_kses_allowed_html() );
|
|
|
|
$tags = wp_kses_allowed_html( 'user_description' );
|
|
$this->assertTrue( $tags['a']['rel'] );
|
|
|
|
$tags = wp_kses_allowed_html();
|
|
$this->assertArrayNotHasKey( 'rel', $tags['a'] );
|
|
|
|
$this->assertSame( array(), wp_kses_allowed_html( 'strip' ) );
|
|
|
|
$custom_tags = array(
|
|
'a' => array(
|
|
'href' => true,
|
|
'rel' => true,
|
|
'rev' => true,
|
|
'name' => true,
|
|
'target' => true,
|
|
),
|
|
);
|
|
|
|
$this->assertSame( $custom_tags, wp_kses_allowed_html( $custom_tags ) );
|
|
|
|
add_filter( 'wp_kses_allowed_html', array( $this, 'wp_kses_allowed_html_filter' ), 10, 2 );
|
|
|
|
$this->assertSame( array( 'a' => array( 'href' => true ) ), wp_kses_allowed_html( 'post' ) );
|
|
$this->assertSame( array( 'a' => array( 'href' => false ) ), wp_kses_allowed_html( 'data' ) );
|
|
|
|
remove_filter( 'wp_kses_allowed_html', array( $this, 'wp_kses_allowed_html_filter' ) );
|
|
$this->assertSame( $allowedposttags, wp_kses_allowed_html( 'post' ) );
|
|
$this->assertSame( $allowedtags, wp_kses_allowed_html( 'data' ) );
|
|
}
|
|
|
|
public function test_hyphenated_tag() {
|
|
$string = '<hyphenated-tag attribute="value" otherattribute="value2">Alot of hyphens.</hyphenated-tag>';
|
|
$custom_tags = array(
|
|
'hyphenated-tag' => array(
|
|
'attribute' => true,
|
|
),
|
|
);
|
|
$expect_stripped_string = 'Alot of hyphens.';
|
|
|
|
$expect_valid_string = '<hyphenated-tag attribute="value">Alot of hyphens.</hyphenated-tag>';
|
|
$this->assertSame( $expect_stripped_string, wp_kses_post( $string ) );
|
|
$this->assertSame( $expect_valid_string, wp_kses( $string, $custom_tags ) );
|
|
}
|
|
|
|
/**
|
|
* @ticket 26290
|
|
*/
|
|
public function test_wp_kses_normalize_entities() {
|
|
$this->assertSame( '♠', wp_kses_normalize_entities( '♠' ) );
|
|
|
|
$this->assertSame( '¹', wp_kses_normalize_entities( '¹' ) );
|
|
$this->assertSame( '²', wp_kses_normalize_entities( '²' ) );
|
|
$this->assertSame( '³', wp_kses_normalize_entities( '³' ) );
|
|
$this->assertSame( '¼', wp_kses_normalize_entities( '¼' ) );
|
|
$this->assertSame( '½', wp_kses_normalize_entities( '½' ) );
|
|
$this->assertSame( '¾', wp_kses_normalize_entities( '¾' ) );
|
|
$this->assertSame( '∴', wp_kses_normalize_entities( '∴' ) );
|
|
}
|
|
|
|
/**
|
|
* Test removal of invalid binary data for HTML.
|
|
*
|
|
* @ticket 28506
|
|
* @dataProvider data_ctrl_removal
|
|
*/
|
|
public function test_ctrl_removal( $input, $output ) {
|
|
global $allowedposttags;
|
|
|
|
return $this->assertSame( $output, wp_kses( $input, $allowedposttags ) );
|
|
}
|
|
|
|
public function data_ctrl_removal() {
|
|
return array(
|
|
array(
|
|
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\X1C\x1D\x1E\x1F",
|
|
'',
|
|
),
|
|
array(
|
|
"\x00h\x01e\x02l\x03l\x04o\x05 \x06w\x07o\x08r\x0Bl\x0Cd\x0E.\x0F \x10W\x11O\x12R\x13D\x14P\x15R\x16E\x17S\x18S\x19 \x1AK\x1BS\X1CE\x1DS\x1E.\x1F/",
|
|
'hello world. WORDPRESS KSES./',
|
|
),
|
|
array(
|
|
"\x1F\x1E\x1D\x1C\x1B\x1A\x19\x18\x17\x16\x15\x14\x13\x12\x11\x10\x0F\x0E\x0C\x0B\x08\x07\x06\x05\x04\X03\x02\x01\x00",
|
|
'',
|
|
),
|
|
array(
|
|
"\x1Fh\x1Ee\x1Dl\x1Cl\x1Bo\x1A \x19w\x18o\x17r\x16l\x15d\x14.\x13 \x12W\x11O\x10R\x0FD\x0EP\x0CR\x0BE\x08S\x07S\x06 \x05K\x04S\X03E\x02S\x01.\x00/",
|
|
'hello world. WORDPRESS KSES./',
|
|
),
|
|
array(
|
|
"\t\r\n word \n\r\t",
|
|
"\t\r\n word \n\r\t",
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test removal of '\0' strings.
|
|
*
|
|
* @ticket 28699
|
|
* @dataProvider data_slash_zero_removal
|
|
*/
|
|
public function test_slash_zero_removal( $input, $output ) {
|
|
global $allowedposttags;
|
|
|
|
return $this->assertSame( $output, wp_kses( $input, $allowedposttags ) );
|
|
}
|
|
|
|
public function data_slash_zero_removal() {
|
|
return array(
|
|
array(
|
|
'This \\0 should be no big deal.',
|
|
'This \\0 should be no big deal.',
|
|
),
|
|
array(
|
|
'<div>This \\0 should be no big deal.</div>',
|
|
'<div>This \\0 should be no big deal.</div>',
|
|
),
|
|
array(
|
|
'<div align="\\0left">This should be no big deal.</div>',
|
|
'<div align="\\0left">This should be no big deal.</div>',
|
|
),
|
|
array(
|
|
'This <div style="float:\\0left"> is more of a concern.',
|
|
'This <div style="float:left"> is more of a concern.',
|
|
),
|
|
array(
|
|
'This <div style="float:\\0\\0left"> is more of a concern.',
|
|
'This <div style="float:left"> is more of a concern.',
|
|
),
|
|
array(
|
|
'This <div style="float:\\\\00left"> is more of a concern.',
|
|
'This <div style="float:left"> is more of a concern.',
|
|
),
|
|
array(
|
|
'This <div style="float:\\\\\\\\0000left"> is more of a concern.',
|
|
'This <div style="float:left"> is more of a concern.',
|
|
),
|
|
array(
|
|
'This <div style="float:\\0000left"> is more of a concern.',
|
|
'This <div style="float:left"> is more of a concern.',
|
|
),
|
|
array(
|
|
'<style type="text/css">div {background-image:\\0}</style>',
|
|
'div {background-image:\\0}',
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test new function wp_kses_hair_parse().
|
|
*
|
|
* @dataProvider data_hair_parse
|
|
*/
|
|
public function test_hair_parse( $input, $output ) {
|
|
return $this->assertSame( $output, wp_kses_hair_parse( $input ) );
|
|
}
|
|
|
|
public function data_hair_parse() {
|
|
return array(
|
|
array(
|
|
'title="hello" href="#" id="my_id" ',
|
|
array( 'title="hello" ', 'href="#" ', 'id="my_id" ' ),
|
|
),
|
|
array(
|
|
'[shortcode attr="value"] href="http://www.google.com/"title="moo"disabled',
|
|
array( '[shortcode attr="value"] ', 'href="http://www.google.com/"', 'title="moo"', 'disabled' ),
|
|
),
|
|
array(
|
|
'',
|
|
array(),
|
|
),
|
|
array(
|
|
'a',
|
|
array( 'a' ),
|
|
),
|
|
array(
|
|
'title="hello"disabled href=# id=\'my_id\'',
|
|
array( 'title="hello"', 'disabled ', 'href=# ', "id='my_id'" ),
|
|
),
|
|
array(
|
|
' ', // Calling function is expected to strip leading whitespace.
|
|
false,
|
|
),
|
|
array(
|
|
'abcd=abcd"abcd"',
|
|
false,
|
|
),
|
|
array(
|
|
"array[1]='z'z'z'z",
|
|
false,
|
|
),
|
|
// Using a digit in attribute name should work.
|
|
array(
|
|
'href="https://example.com/[shortcode attr=\'value\']" data-op3-timer-seconds="0"',
|
|
array( 'href="https://example.com/[shortcode attr=\'value\']" ', 'data-op3-timer-seconds="0"' ),
|
|
),
|
|
// Using an underscore in attribute name should work.
|
|
array(
|
|
'href="https://example.com/[shortcode attr=\'value\']" data-op_timer-seconds="0"',
|
|
array( 'href="https://example.com/[shortcode attr=\'value\']" ', 'data-op_timer-seconds="0"' ),
|
|
),
|
|
// Using a period in attribute name should work.
|
|
array(
|
|
'href="https://example.com/[shortcode attr=\'value\']" data-op.timer-seconds="0"',
|
|
array( 'href="https://example.com/[shortcode attr=\'value\']" ', 'data-op.timer-seconds="0"' ),
|
|
),
|
|
// Using a digit at the beginning of attribute name should return false.
|
|
array(
|
|
'href="https://example.com/[shortcode attr=\'value\']" 3data-op-timer-seconds="0"',
|
|
false,
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test new function wp_kses_attr_parse().
|
|
*
|
|
* @dataProvider data_attr_parse
|
|
*/
|
|
public function test_attr_parse( $input, $output ) {
|
|
return $this->assertSame( $output, wp_kses_attr_parse( $input ) );
|
|
}
|
|
|
|
public function data_attr_parse() {
|
|
return array(
|
|
array(
|
|
'<a title="hello" href="#" id="my_id" >',
|
|
array( '<a ', 'title="hello" ', 'href="#" ', 'id="my_id" ', '>' ),
|
|
),
|
|
array(
|
|
'<a [shortcode attr="value"] href="http://www.google.com/"title="moo"disabled>',
|
|
array( '<a ', '[shortcode attr="value"] ', 'href="http://www.google.com/"', 'title="moo"', 'disabled', '>' ),
|
|
),
|
|
array(
|
|
'',
|
|
false,
|
|
),
|
|
array(
|
|
'a',
|
|
false,
|
|
),
|
|
array(
|
|
'<a>',
|
|
array( '<a', '>' ),
|
|
),
|
|
array(
|
|
'<a%%&&**>',
|
|
false,
|
|
),
|
|
array(
|
|
'<a title="hello"disabled href=# id=\'my_id\'>',
|
|
array( '<a ', 'title="hello"', 'disabled ', 'href=# ', "id='my_id'", '>' ),
|
|
),
|
|
array(
|
|
'<a >',
|
|
array( '<a ', '>' ),
|
|
),
|
|
array(
|
|
'<a abcd=abcd"abcd">',
|
|
false,
|
|
),
|
|
array(
|
|
"<a array[1]='z'z'z'z>",
|
|
false,
|
|
),
|
|
array(
|
|
'<img title="hello" src="#" id="my_id" />',
|
|
array( '<img ', 'title="hello" ', 'src="#" ', 'id="my_id"', ' />' ),
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test new function wp_kses_one_attr().
|
|
*
|
|
* @dataProvider data_one_attr
|
|
*/
|
|
public function test_one_attr( $element, $input, $output ) {
|
|
return $this->assertSame( $output, wp_kses_one_attr( $input, $element ) );
|
|
}
|
|
|
|
public function data_one_attr() {
|
|
return array(
|
|
array(
|
|
'a',
|
|
' title="hello" ',
|
|
' title="hello" ',
|
|
),
|
|
array(
|
|
'a',
|
|
'title = "hello"',
|
|
'title="hello"',
|
|
),
|
|
array(
|
|
'a',
|
|
"title='hello'",
|
|
"title='hello'",
|
|
),
|
|
array(
|
|
'a',
|
|
'title=hello',
|
|
'title="hello"',
|
|
),
|
|
array(
|
|
'a',
|
|
'href="javascript:alert(1)"',
|
|
'href="alert(1)"',
|
|
),
|
|
array(
|
|
'a',
|
|
'style ="style "',
|
|
'style="style"',
|
|
),
|
|
array(
|
|
'a',
|
|
'style="style "',
|
|
'style="style"',
|
|
),
|
|
array(
|
|
'a',
|
|
'style ="style ="',
|
|
'',
|
|
),
|
|
array(
|
|
'img',
|
|
'src="mypic.jpg"',
|
|
'src="mypic.jpg"',
|
|
),
|
|
array(
|
|
'img',
|
|
'loading="lazy"',
|
|
'loading="lazy"',
|
|
),
|
|
array(
|
|
'img',
|
|
'onerror=alert(1)',
|
|
'',
|
|
),
|
|
array(
|
|
'img',
|
|
'title=>',
|
|
'title=">"',
|
|
),
|
|
array(
|
|
'img',
|
|
'title="&garbage";"',
|
|
'title="&garbage";"',
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @ticket 34063
|
|
*/
|
|
public function test_bdo_tag_allowed() {
|
|
global $allowedposttags;
|
|
|
|
$input = '<p>This is <bdo dir="rtl">a BDO tag</bdo>. Weird, <bdo dir="ltr">right?</bdo></p>';
|
|
|
|
$this->assertSame( $input, wp_kses( $input, $allowedposttags ) );
|
|
}
|
|
|
|
/**
|
|
* @ticket 54698
|
|
*/
|
|
public function test_ruby_tag_allowed() {
|
|
global $allowedposttags;
|
|
|
|
$input = '<ruby>✶<rp>: </rp><rt>Star</rt><rp>, </rp><rt lang="fr">Étoile</rt><rp>.</rp></ruby>';
|
|
|
|
$this->assertSame( $input, wp_kses( $input, $allowedposttags ) );
|
|
}
|
|
|
|
/**
|
|
* @ticket 35079
|
|
*/
|
|
public function test_ol_reversed_attribute_allowed() {
|
|
global $allowedposttags;
|
|
|
|
$input = '<ol reversed="reversed"><li>Item 1</li><li>Item 2</li><li>Item 3</li></ol>';
|
|
|
|
$this->assertSame( $input, wp_kses( $input, $allowedposttags ) );
|
|
}
|
|
|
|
/**
|
|
* @ticket 40680
|
|
*/
|
|
public function test_wp_kses_attr_no_attributes_allowed_with_empty_array() {
|
|
$element = 'foo';
|
|
$attribute = 'title="foo" class="bar"';
|
|
|
|
$this->assertSame( "<{$element}>", wp_kses_attr( $element, $attribute, array( 'foo' => array() ), array() ) );
|
|
}
|
|
|
|
/**
|
|
* @ticket 40680
|
|
*/
|
|
public function test_wp_kses_attr_no_attributes_allowed_with_true() {
|
|
$element = 'foo';
|
|
$attribute = 'title="foo" class="bar"';
|
|
|
|
$this->assertSame( "<{$element}>", wp_kses_attr( $element, $attribute, array( 'foo' => true ), array() ) );
|
|
}
|
|
|
|
/**
|
|
* @ticket 40680
|
|
*/
|
|
public function test_wp_kses_attr_single_attribute_is_allowed() {
|
|
$element = 'foo';
|
|
$attribute = 'title="foo" class="bar"';
|
|
|
|
$this->assertSame( "<{$element} title=\"foo\">", wp_kses_attr( $element, $attribute, array( 'foo' => array( 'title' => true ) ), array() ) );
|
|
}
|
|
|
|
/**
|
|
* @ticket 43312
|
|
*/
|
|
public function test_wp_kses_attr_no_attributes_allowed_with_false() {
|
|
$element = 'foo';
|
|
$attribute = 'title="foo" class="bar"';
|
|
|
|
$this->assertSame( "<{$element}>", wp_kses_attr( $element, $attribute, array( 'foo' => false ), array() ) );
|
|
}
|
|
|
|
/**
|
|
* Testing the safecss_filter_attr() function.
|
|
*
|
|
* @ticket 37248
|
|
* @ticket 42729
|
|
* @ticket 48376
|
|
* @dataProvider data_test_safecss_filter_attr
|
|
*
|
|
* @param string $css A string of CSS rules.
|
|
* @param string $expected Expected string of CSS rules.
|
|
*/
|
|
public function test_safecss_filter_attr( $css, $expected ) {
|
|
$this->assertSame( $expected, safecss_filter_attr( $css ) );
|
|
}
|
|
|
|
/**
|
|
* Data Provider for test_safecss_filter_attr().
|
|
*
|
|
* @return array {
|
|
* @type array {
|
|
* @string string $css A string of CSS rules.
|
|
* @string string $expected Expected string of CSS rules.
|
|
* }
|
|
* }
|
|
*/
|
|
public function data_test_safecss_filter_attr() {
|
|
return array(
|
|
// Empty input, empty output.
|
|
array(
|
|
'css' => '',
|
|
'expected' => '',
|
|
),
|
|
// An arbitrary attribute name isn't allowed.
|
|
array(
|
|
'css' => 'foo:bar',
|
|
'expected' => '',
|
|
),
|
|
// A single attribute name, with a single value.
|
|
array(
|
|
'css' => 'margin-top: 2px',
|
|
'expected' => 'margin-top: 2px',
|
|
),
|
|
// Backslash \ isn't supported.
|
|
array(
|
|
'css' => 'margin-top: \2px',
|
|
'expected' => '',
|
|
),
|
|
// Curly bracket } isn't supported.
|
|
array(
|
|
'css' => 'margin-bottom: 2px}',
|
|
'expected' => '',
|
|
),
|
|
// A single attribute name, with a single text value.
|
|
array(
|
|
'css' => 'text-transform: uppercase',
|
|
'expected' => 'text-transform: uppercase',
|
|
),
|
|
// Only lowercase attribute names are supported.
|
|
array(
|
|
'css' => 'Text-transform: capitalize',
|
|
'expected' => '',
|
|
),
|
|
// Uppercase attribute values goes through.
|
|
array(
|
|
'css' => 'text-transform: None',
|
|
'expected' => 'text-transform: None',
|
|
),
|
|
// A single attribute, with multiple values.
|
|
array(
|
|
'css' => 'font: bold 15px arial, sans-serif',
|
|
'expected' => 'font: bold 15px arial, sans-serif',
|
|
),
|
|
// Multiple attributes, with single values.
|
|
array(
|
|
'css' => 'font-weight: bold;font-size: 15px',
|
|
'expected' => 'font-weight: bold;font-size: 15px',
|
|
),
|
|
// Multiple attributes, separated by a space.
|
|
array(
|
|
'css' => 'font-weight: bold; font-size: 15px',
|
|
'expected' => 'font-weight: bold;font-size: 15px',
|
|
),
|
|
// Multiple attributes, with multiple values.
|
|
array(
|
|
'css' => 'margin: 10px 20px;padding: 5px 10px',
|
|
'expected' => 'margin: 10px 20px;padding: 5px 10px',
|
|
),
|
|
// Parenthesis ( is supported for some attributes.
|
|
array(
|
|
'css' => 'background: green url("foo.jpg") no-repeat fixed center',
|
|
'expected' => 'background: green url("foo.jpg") no-repeat fixed center',
|
|
),
|
|
// Additional background attributes introduced in 5.3.
|
|
array(
|
|
'css' => 'background-size: cover;background-size: 200px 100px;background-attachment: local, scroll;background-blend-mode: hard-light',
|
|
'expected' => 'background-size: cover;background-size: 200px 100px;background-attachment: local, scroll;background-blend-mode: hard-light',
|
|
),
|
|
// `border-radius` attribute introduced in 5.3.
|
|
array(
|
|
'css' => 'border-radius: 10% 30% 50% 70%;border-radius: 30px',
|
|
'expected' => 'border-radius: 10% 30% 50% 70%;border-radius: 30px',
|
|
),
|
|
// `flex` and related attributes introduced in 5.3.
|
|
array(
|
|
'css' => 'flex: 0 1 auto;flex-basis: 75%;flex-direction: row-reverse;flex-flow: row-reverse nowrap;flex-grow: 2;flex-shrink: 1',
|
|
'expected' => 'flex: 0 1 auto;flex-basis: 75%;flex-direction: row-reverse;flex-flow: row-reverse nowrap;flex-grow: 2;flex-shrink: 1',
|
|
),
|
|
// `grid` and related attributes introduced in 5.3.
|
|
array(
|
|
'css' => 'grid-template-columns: 1fr 60px;grid-auto-columns: min-content;grid-column-start: span 2;grid-column-end: -1;grid-column-gap: 10%;grid-gap: 10px 20px',
|
|
'expected' => 'grid-template-columns: 1fr 60px;grid-auto-columns: min-content;grid-column-start: span 2;grid-column-end: -1;grid-column-gap: 10%;grid-gap: 10px 20px',
|
|
),
|
|
array(
|
|
'css' => 'grid-template-rows: 40px 4em 40px;grid-auto-rows: min-content;grid-row-start: -1;grid-row-end: 3;grid-row-gap: 1em',
|
|
'expected' => 'grid-template-rows: 40px 4em 40px;grid-auto-rows: min-content;grid-row-start: -1;grid-row-end: 3;grid-row-gap: 1em',
|
|
),
|
|
// `grid` does not yet support functions or `\`.
|
|
array(
|
|
'css' => 'grid-template-columns: repeat(2, 50px 1fr);grid-template: 1em / 20% 20px 1fr',
|
|
'expected' => '',
|
|
),
|
|
// `flex` and `grid` alignments introduced in 5.3.
|
|
array(
|
|
'css' => 'align-content: space-between;align-items: start;align-self: center;justify-items: center;justify-content: space-between;justify-self: end',
|
|
'expected' => 'align-content: space-between;align-items: start;align-self: center;justify-items: center;justify-content: space-between;justify-self: end',
|
|
),
|
|
// `columns` and related attributes introduced in 5.3.
|
|
array(
|
|
'css' => 'columns: 6rem auto;column-count: 4;column-fill: balance;column-gap: 9px;column-rule: thick inset blue;column-span: none;column-width: 120px',
|
|
'expected' => 'columns: 6rem auto;column-count: 4;column-fill: balance;column-gap: 9px;column-rule: thick inset blue;column-span: none;column-width: 120px',
|
|
),
|
|
// Gradients introduced in 5.3.
|
|
array(
|
|
'css' => 'background: linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)',
|
|
'expected' => 'background: linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)',
|
|
),
|
|
array(
|
|
'css' => 'background: linear-gradient(135deg,rgba(6,147,227,1) ) (0%,rgb(155,81,224) 100%)',
|
|
'expected' => '',
|
|
),
|
|
array(
|
|
'css' => 'background-image: linear-gradient(red,yellow);',
|
|
'expected' => 'background-image: linear-gradient(red,yellow)',
|
|
),
|
|
array(
|
|
'css' => 'color: linear-gradient(red,yellow);',
|
|
'expected' => '',
|
|
),
|
|
array(
|
|
'css' => 'background-image: linear-gradient(red,yellow); background: prop( red,yellow); width: 100px;',
|
|
'expected' => 'background-image: linear-gradient(red,yellow);width: 100px',
|
|
),
|
|
array(
|
|
'css' => 'background: unknown-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)',
|
|
'expected' => '',
|
|
),
|
|
array(
|
|
'css' => 'background: repeating-linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)',
|
|
'expected' => 'background: repeating-linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)',
|
|
),
|
|
array(
|
|
'css' => 'width: 100px; height: 100px; background: linear-gradient(135deg,rgba(0,208,132,1) 0%,rgba(6,147,227,1) 100%);',
|
|
'expected' => 'width: 100px;height: 100px;background: linear-gradient(135deg,rgba(0,208,132,1) 0%,rgba(6,147,227,1) 100%)',
|
|
),
|
|
array(
|
|
'css' => 'background: radial-gradient(#ff0, red, yellow, green, rgba(6,147,227,1), rgb(155,81,224) 90%);',
|
|
'expected' => 'background: radial-gradient(#ff0, red, yellow, green, rgba(6,147,227,1), rgb(155,81,224) 90%)',
|
|
),
|
|
array(
|
|
'css' => 'background: radial-gradient(#ff0, red, yellow, green, rgba(6,147,227,1), rgb(155,81,224) 90%);',
|
|
'expected' => 'background: radial-gradient(#ff0, red, yellow, green, rgba(6,147,227,1), rgb(155,81,224) 90%)',
|
|
),
|
|
array(
|
|
'css' => 'background: conic-gradient(at 0% 30%, red 10%, yellow 30%, #1e90ff 50%)',
|
|
'expected' => 'background: conic-gradient(at 0% 30%, red 10%, yellow 30%, #1e90ff 50%)',
|
|
),
|
|
// Expressions are not allowed.
|
|
array(
|
|
'css' => 'height: expression( body.scrollTop + 50 + "px" )',
|
|
'expected' => '',
|
|
),
|
|
// RGB color values are not allowed.
|
|
array(
|
|
'css' => 'color: rgb( 100, 100, 100 )',
|
|
'expected' => '',
|
|
),
|
|
// RGBA color values are not allowed.
|
|
array(
|
|
'css' => 'color: rgb( 100, 100, 100, .4 )',
|
|
'expected' => '',
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Data attributes are globally accepted.
|
|
*
|
|
* @ticket 33121
|
|
*/
|
|
public function test_wp_kses_attr_data_attribute_is_allowed() {
|
|
$test = '<div data-foo="foo" data-bar="bar" datainvalid="gone" data--invaild="gone" data-also-invaild-="gone" data-two-hyphens="remains">Pens and pencils</div>';
|
|
$expected = '<div data-foo="foo" data-bar="bar" data-two-hyphens="remains">Pens and pencils</div>';
|
|
|
|
$this->assertSame( $expected, wp_kses_post( $test ) );
|
|
}
|
|
|
|
/**
|
|
* Ensure wildcard attributes block unprefixed wildcard uses.
|
|
*
|
|
* @ticket 33121
|
|
*/
|
|
public function test_wildcard_requires_hyphen_after_prefix() {
|
|
$allowed_html = array(
|
|
'div' => array(
|
|
'data-*' => true,
|
|
'on-*' => true,
|
|
),
|
|
);
|
|
|
|
$string = '<div datamelformed-prefix="gone" data="gone" data-="gone" onclick="alert(1)">Malformed attributes</div>';
|
|
$expected = '<div>Malformed attributes</div>';
|
|
|
|
$actual = wp_kses( $string, $allowed_html );
|
|
|
|
$this->assertSame( $expected, $actual );
|
|
}
|
|
|
|
/**
|
|
* Ensure wildcard allows two hyphen.
|
|
*
|
|
* @ticket 33121
|
|
*/
|
|
public function test_wildcard_allows_two_hyphens() {
|
|
$allowed_html = array(
|
|
'div' => array(
|
|
'data-*' => true,
|
|
),
|
|
);
|
|
|
|
$string = '<div data-wp-id="pens-and-pencils">Well formed attribute</div>';
|
|
$expected = '<div data-wp-id="pens-and-pencils">Well formed attribute</div>';
|
|
|
|
$actual = wp_kses( $string, $allowed_html );
|
|
|
|
$this->assertSame( $expected, $actual );
|
|
}
|
|
|
|
/**
|
|
* Ensure wildcard attributes only support valid prefixes.
|
|
*
|
|
* @dataProvider data_wildcard_attribute_prefixes
|
|
*
|
|
* @ticket 33121
|
|
*/
|
|
public function test_wildcard_attribute_prefixes( $wildcard_attribute, $expected ) {
|
|
$allowed_html = array(
|
|
'div' => array(
|
|
$wildcard_attribute => true,
|
|
),
|
|
);
|
|
|
|
$name = str_replace( '*', strtolower( __FUNCTION__ ), $wildcard_attribute );
|
|
$value = __FUNCTION__;
|
|
$whole = "{$name}=\"{$value}\"";
|
|
|
|
$actual = wp_kses_attr_check( $name, $value, $whole, 'n', 'div', $allowed_html );
|
|
|
|
$this->assertSame( $expected, $actual );
|
|
}
|
|
|
|
/**
|
|
* @return array Array of arguments for wildcard testing
|
|
* [0] The prefix being tested.
|
|
* [1] The outcome of `wp_kses_attr_check` for the prefix.
|
|
*/
|
|
public function data_wildcard_attribute_prefixes() {
|
|
return array(
|
|
// Ends correctly.
|
|
array( 'data-*', true ),
|
|
|
|
// Does not end with trialing `-`.
|
|
array( 'data*', false ),
|
|
|
|
// Multiple wildcards.
|
|
array( 'd*ta-*', false ),
|
|
array( 'data**', false ),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test URL sanitization in the style tag.
|
|
*
|
|
* @dataProvider data_kses_style_attr_with_url
|
|
*
|
|
* @ticket 45067
|
|
* @ticket 46197
|
|
* @ticket 46498
|
|
*
|
|
* @param $input string The style attribute saved in the editor.
|
|
* @param $expected string The sanitized style attribute.
|
|
*/
|
|
public function test_kses_style_attr_with_url( $input, $expected ) {
|
|
$actual = safecss_filter_attr( $input );
|
|
|
|
$this->assertSame( $expected, $actual );
|
|
}
|
|
|
|
/**
|
|
* Data provider testing style attribute sanitization.
|
|
*
|
|
* @return array Nested array of input, expected pairs.
|
|
*/
|
|
public function data_kses_style_attr_with_url() {
|
|
return array(
|
|
/*
|
|
* Valid use cases.
|
|
*/
|
|
|
|
// Double quotes.
|
|
array(
|
|
'background-image: url( "http://example.com/valid.gif" );',
|
|
'background-image: url( "http://example.com/valid.gif" )',
|
|
),
|
|
|
|
// Single quotes.
|
|
array(
|
|
"background-image: url( 'http://example.com/valid.gif' );",
|
|
"background-image: url( 'http://example.com/valid.gif' )",
|
|
),
|
|
|
|
// No quotes.
|
|
array(
|
|
'background-image: url( http://example.com/valid.gif );',
|
|
'background-image: url( http://example.com/valid.gif )',
|
|
),
|
|
|
|
// Single quotes, extra spaces.
|
|
array(
|
|
"background-image: url( ' http://example.com/valid.gif ' );",
|
|
"background-image: url( ' http://example.com/valid.gif ' )",
|
|
),
|
|
|
|
// Line breaks, single quotes.
|
|
array(
|
|
"background-image: url(\n'http://example.com/valid.gif' );",
|
|
"background-image: url('http://example.com/valid.gif' )",
|
|
),
|
|
|
|
// Tabs not spaces, single quotes.
|
|
array(
|
|
"background-image: url(\t'http://example.com/valid.gif'\t\t);",
|
|
"background-image: url('http://example.com/valid.gif')",
|
|
),
|
|
|
|
// Single quotes, absolute path.
|
|
array(
|
|
"background: url('/valid.gif');",
|
|
"background: url('/valid.gif')",
|
|
),
|
|
|
|
// Single quotes, relative path.
|
|
array(
|
|
"background: url('../wp-content/uploads/2018/10/valid.gif');",
|
|
"background: url('../wp-content/uploads/2018/10/valid.gif')",
|
|
),
|
|
|
|
// Error check: valid property not containing a URL.
|
|
array(
|
|
'background: red',
|
|
'background: red',
|
|
),
|
|
|
|
// CSS calc().
|
|
array(
|
|
'width: calc(2em + 3px)',
|
|
'width: calc(2em + 3px)',
|
|
),
|
|
|
|
// CSS variable.
|
|
array(
|
|
'padding: var(--wp-var1) var(--wp-var2)',
|
|
'padding: var(--wp-var1) var(--wp-var2)',
|
|
),
|
|
|
|
// CSS calc() with var().
|
|
array(
|
|
'margin-top: calc(var(--wp-var1) * 3 + 2em)',
|
|
'margin-top: calc(var(--wp-var1) * 3 + 2em)',
|
|
),
|
|
|
|
/*
|
|
* Invalid use cases.
|
|
*/
|
|
|
|
// Attribute doesn't support URL properties.
|
|
array(
|
|
'color: url( "http://example.com/invalid.gif" );',
|
|
'',
|
|
),
|
|
|
|
// Mismatched quotes.
|
|
array(
|
|
'background-image: url( "http://example.com/valid.gif\' );',
|
|
'',
|
|
),
|
|
|
|
// Bad protocol, double quotes.
|
|
array(
|
|
'background-image: url( "bad://example.com/invalid.gif" );',
|
|
'',
|
|
),
|
|
|
|
// Bad protocol, single quotes.
|
|
array(
|
|
"background-image: url( 'bad://example.com/invalid.gif' );",
|
|
'',
|
|
),
|
|
|
|
// Bad protocol, single quotes.
|
|
array(
|
|
"background-image: url( 'bad://example.com/invalid.gif' );",
|
|
'',
|
|
),
|
|
|
|
// Bad protocol, single quotes, strange spacing.
|
|
array(
|
|
"background-image: url( ' \tbad://example.com/invalid.gif ' );",
|
|
'',
|
|
),
|
|
|
|
// Bad protocol, no quotes.
|
|
array(
|
|
'background-image: url( bad://example.com/invalid.gif );',
|
|
'',
|
|
),
|
|
|
|
// No URL inside url().
|
|
array(
|
|
'background-image: url();',
|
|
'',
|
|
),
|
|
|
|
// Malformed, no closing `)`.
|
|
array(
|
|
'background-image: url( "http://example.com" ;',
|
|
'',
|
|
),
|
|
|
|
// Malformed, no closing `"`.
|
|
array(
|
|
'background-image: url( "http://example.com );',
|
|
'',
|
|
),
|
|
|
|
// Malformed calc, no closing `)`.
|
|
array(
|
|
'width: calc(3em + 10px',
|
|
'',
|
|
),
|
|
|
|
// Malformed var, no closing `)`.
|
|
array(
|
|
'width: var(--wp-var1',
|
|
'',
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Testing the safecss_filter_attr() function with the safecss_filter_attr_allow_css filter.
|
|
*
|
|
* @ticket 37134
|
|
*
|
|
* @dataProvider data_test_safecss_filter_attr_filtered
|
|
*
|
|
* @param string $css A string of CSS rules.
|
|
* @param string $expected Expected string of CSS rules.
|
|
*/
|
|
public function test_safecss_filter_attr_filtered( $css, $expected ) {
|
|
add_filter( 'safecss_filter_attr_allow_css', '__return_true' );
|
|
$this->assertSame( $expected, safecss_filter_attr( $css ) );
|
|
remove_filter( 'safecss_filter_attr_allow_css', '__return_true' );
|
|
}
|
|
|
|
/**
|
|
* Data Provider for test_safecss_filter_attr_filtered().
|
|
*
|
|
* @return array {
|
|
* @type array {
|
|
* @string string $css A string of CSS rules.
|
|
* @string string $expected Expected string of CSS rules.
|
|
* }
|
|
* }
|
|
*/
|
|
public function data_test_safecss_filter_attr_filtered() {
|
|
return array(
|
|
|
|
// A single attribute name, with a single value.
|
|
array(
|
|
'css' => 'margin-top: 2px',
|
|
'expected' => 'margin-top: 2px',
|
|
),
|
|
// Backslash \ can be allowed with the 'safecss_filter_attr_allow_css' filter.
|
|
array(
|
|
'css' => 'margin-top: \2px',
|
|
'expected' => 'margin-top: \2px',
|
|
),
|
|
// Curly bracket } can be allowed with the 'safecss_filter_attr_allow_css' filter.
|
|
array(
|
|
'css' => 'margin-bottom: 2px}',
|
|
'expected' => 'margin-bottom: 2px}',
|
|
),
|
|
// Parenthesis ) can be allowed with the 'safecss_filter_attr_allow_css' filter.
|
|
array(
|
|
'css' => 'margin-bottom: 2px)',
|
|
'expected' => 'margin-bottom: 2px)',
|
|
),
|
|
// Ampersand & can be allowed with the 'safecss_filter_attr_allow_css' filter.
|
|
array(
|
|
'css' => 'margin-bottom: 2px&',
|
|
'expected' => 'margin-bottom: 2px&',
|
|
),
|
|
// Expressions can be allowed with the 'safecss_filter_attr_allow_css' filter.
|
|
array(
|
|
'css' => 'height: expression( body.scrollTop + 50 + "px" )',
|
|
'expected' => 'height: expression( body.scrollTop + 50 + "px" )',
|
|
),
|
|
// RGB color values can be allowed with the 'safecss_filter_attr_allow_css' filter.
|
|
array(
|
|
'css' => 'color: rgb( 100, 100, 100 )',
|
|
'expected' => 'color: rgb( 100, 100, 100 )',
|
|
),
|
|
// RGBA color values can be allowed with the 'safecss_filter_attr_allow_css' filter.
|
|
array(
|
|
'css' => 'color: rgb( 100, 100, 100, .4 )',
|
|
'expected' => 'color: rgb( 100, 100, 100, .4 )',
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test filtering a standard img tag.
|
|
*
|
|
* @ticket 50731
|
|
*/
|
|
public function test_wp_kses_img_tag_standard_attributes() {
|
|
$html = array(
|
|
'<img',
|
|
'loading="lazy"',
|
|
'src="https://example.com/img.jpg"',
|
|
'width="1000"',
|
|
'height="1000"',
|
|
'alt=""',
|
|
'class="wp-image-1000"',
|
|
'/>',
|
|
);
|
|
|
|
$html = implode( ' ', $html );
|
|
|
|
$this->assertSame( $html, wp_kses_post( $html ) );
|
|
}
|
|
|
|
/**
|
|
* Test filtering a standard main tag.
|
|
*
|
|
* @ticket 53156
|
|
*/
|
|
public function test_wp_kses_main_tag_standard_attributes() {
|
|
$test = array(
|
|
'<main',
|
|
'class="wp-group-block"',
|
|
'style="padding:10px"',
|
|
'/>',
|
|
);
|
|
|
|
$html = implode( ' ', $test );
|
|
|
|
$this->assertSame( $html, wp_kses_post( $html ) );
|
|
}
|
|
|
|
/**
|
|
* Test that object tags are allowed under limited circumstances.
|
|
*
|
|
* @ticket 54261
|
|
*
|
|
* @dataProvider data_wp_kses_object_tag_allowed
|
|
*
|
|
* @param string $html A string of HTML to test.
|
|
* @param string $expected The expected result from KSES.
|
|
*/
|
|
function test_wp_kses_object_tag_allowed( $html, $expected ) {
|
|
$this->assertSame( $expected, wp_kses_post( $html ) );
|
|
}
|
|
|
|
/**
|
|
* Data provider for test_wp_kses_object_tag_allowed().
|
|
*/
|
|
function data_wp_kses_object_tag_allowed() {
|
|
return array(
|
|
'valid value for type' => array(
|
|
'<object type="application/pdf" data="https://example.org/foo.pdf" />',
|
|
'<object type="application/pdf" data="https://example.org/foo.pdf" />',
|
|
),
|
|
'invalid value for type' => array(
|
|
'<object type="application/exe" data="https://example.org/foo.exe" />',
|
|
'',
|
|
),
|
|
'multiple type attributes, last invalid' => array(
|
|
'<object type="application/pdf" type="application/exe" data="https://example.org/foo.pdf" />',
|
|
'<object type="application/pdf" data="https://example.org/foo.pdf" />',
|
|
),
|
|
'multiple type attributes, first uppercase, last invalid' => array(
|
|
'<object TYPE="application/pdf" type="application/exe" data="https://example.org/foo.pdf" />',
|
|
'<object TYPE="application/pdf" data="https://example.org/foo.pdf" />',
|
|
),
|
|
'multiple type attributes, last upper case and invalid' => array(
|
|
'<object type="application/pdf" TYPE="application/exe" data="https://example.org/foo.pdf" />',
|
|
'<object type="application/pdf" data="https://example.org/foo.pdf" />',
|
|
),
|
|
'multiple type attributes, first invalid' => array(
|
|
'<object type="application/exe" type="application/pdf" data="https://example.org/foo.pdf" />',
|
|
'',
|
|
),
|
|
'multiple type attributes, first upper case and invalid' => array(
|
|
'<object TYPE="application/exe" type="application/pdf" data="https://example.org/foo.pdf" />',
|
|
'',
|
|
),
|
|
'multiple type attributes, first invalid, last uppercase' => array(
|
|
'<object type="application/exe" TYPE="application/pdf" data="https://example.org/foo.pdf" />',
|
|
'',
|
|
),
|
|
'multiple object tags, last invalid' => array(
|
|
'<object type="application/pdf" data="https://example.org/foo.pdf" /><object type="application/exe" data="https://example.org/foo.exe" />',
|
|
'<object type="application/pdf" data="https://example.org/foo.pdf" />',
|
|
),
|
|
'multiple object tags, first invalid' => array(
|
|
'<object type="application/exe" data="https://example.org/foo.exe" /><object type="application/pdf" data="https://example.org/foo.pdf" />',
|
|
'<object type="application/pdf" data="https://example.org/foo.pdf" />',
|
|
),
|
|
'type attribute with partially incorrect value' => array(
|
|
'<object type="application/pdfa" data="https://example.org/foo.pdf" />',
|
|
'',
|
|
),
|
|
'type attribute with empty value' => array(
|
|
'<object type="" data="https://example.org/foo.pdf" />',
|
|
'',
|
|
),
|
|
'type attribute with no value' => array(
|
|
'<object type data="https://example.org/foo.pdf" />',
|
|
'',
|
|
),
|
|
'no type attribute' => array(
|
|
'<object data="https://example.org/foo.pdf" />',
|
|
'',
|
|
),
|
|
'different protocol in url' => array(
|
|
'<object type="application/pdf" data="http://example.org/foo.pdf" />',
|
|
'<object type="application/pdf" data="http://example.org/foo.pdf" />',
|
|
),
|
|
'query string on url' => array(
|
|
'<object type="application/pdf" data="https://example.org/foo.pdf?lol=.pdf" />',
|
|
'',
|
|
),
|
|
'fragment on url' => array(
|
|
'<object type="application/pdf" data="https://example.org/foo.pdf#lol.pdf" />',
|
|
'',
|
|
),
|
|
'wrong extension' => array(
|
|
'<object type="application/pdf" data="https://example.org/foo.php" />',
|
|
'',
|
|
),
|
|
'protocol-relative url' => array(
|
|
'<object type="application/pdf" data="//example.org/foo.pdf" />',
|
|
'',
|
|
),
|
|
'unsupported protocol' => array(
|
|
'<object type="application/pdf" data="ftp://example.org/foo.pdf" />',
|
|
'',
|
|
),
|
|
'relative url' => array(
|
|
'<object type="application/pdf" data="/cat/foo.pdf" />',
|
|
'',
|
|
),
|
|
'url with port number-like path' => array(
|
|
'<object type="application/pdf" data="https://example.org/cat:8888/foo.pdf" />',
|
|
'<object type="application/pdf" data="https://example.org/cat:8888/foo.pdf" />',
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test that object tags are allowed when there is a port number in the URL.
|
|
*
|
|
* @ticket 54261
|
|
*
|
|
* @dataProvider data_wp_kses_object_data_url_with_port_number_allowed
|
|
*
|
|
* @param string $html A string of HTML to test.
|
|
* @param string $expected The expected result from KSES.
|
|
*/
|
|
function test_wp_kses_object_data_url_with_port_number_allowed( $html, $expected ) {
|
|
add_filter( 'upload_dir', array( $this, 'wp_kses_upload_dir_filter' ), 10, 2 );
|
|
$this->assertSame( $expected, wp_kses_post( $html ) );
|
|
}
|
|
|
|
/**
|
|
* Data provider for test_wp_kses_object_data_url_with_port_number_allowed().
|
|
*/
|
|
function data_wp_kses_object_data_url_with_port_number_allowed() {
|
|
return array(
|
|
'url with port number' => array(
|
|
'<object type="application/pdf" data="https://example.org:8888/cat/foo.pdf" />',
|
|
'<object type="application/pdf" data="https://example.org:8888/cat/foo.pdf" />',
|
|
),
|
|
'url with port number and http protocol' => array(
|
|
'<object type="application/pdf" data="http://example.org:8888/cat/foo.pdf" />',
|
|
'<object type="application/pdf" data="http://example.org:8888/cat/foo.pdf" />',
|
|
),
|
|
'url with wrong port number' => array(
|
|
'<object type="application/pdf" data="http://example.org:3333/cat/foo.pdf" />',
|
|
'',
|
|
),
|
|
'url without port number' => array(
|
|
'<object type="application/pdf" data="http://example.org/cat/foo.pdf" />',
|
|
'',
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Filter upload directory for tests using port number.
|
|
*
|
|
* @param array $param See wp_upload_dir()
|
|
* @return array $param with a modified `url`.
|
|
*/
|
|
public function wp_kses_upload_dir_filter( $param ) {
|
|
$url_with_port_number = is_string( $param['url'] ) ? str_replace( 'example.org', 'example.org:8888', $param['url'] ) : $param['url'];
|
|
$param['url'] = $url_with_port_number;
|
|
return $param;
|
|
}
|
|
|
|
/**
|
|
* Test that object tags will continue to function if they've been added using the
|
|
* 'wp_kses_allowed_html' filter.
|
|
*
|
|
* @ticket 54261
|
|
*/
|
|
function test_wp_kses_object_added_in_html_filter() {
|
|
$html = <<<HTML
|
|
<object type="application/pdf" data="https://wordpress.org/foo.pdf" />
|
|
<object type="application/x-shockwave-flash" data="https://wordpress.org/foo.swf">
|
|
<param name="foo" value="bar" />
|
|
</object>
|
|
HTML;
|
|
|
|
add_filter( 'wp_kses_allowed_html', array( $this, 'filter_wp_kses_object_added_in_html_filter' ), 10, 2 );
|
|
|
|
$filtered_html = wp_kses_post( $html );
|
|
|
|
remove_filter( 'wp_kses_allowed_html', array( $this, 'filter_wp_kses_object_added_in_html_filter' ) );
|
|
|
|
$this->assertSame( $html, $filtered_html );
|
|
}
|
|
|
|
function filter_wp_kses_object_added_in_html_filter( $tags, $context ) {
|
|
if ( 'post' === $context ) {
|
|
$tags['object'] = array(
|
|
'type' => true,
|
|
'data' => true,
|
|
);
|
|
|
|
$tags['param'] = array(
|
|
'name' => true,
|
|
'value' => true,
|
|
);
|
|
}
|
|
|
|
return $tags;
|
|
}
|
|
|
|
/**
|
|
* Test that attributes with a list of allowed values are filtered correctly.
|
|
*
|
|
* @ticket 54261
|
|
*
|
|
* @dataProvider data_wp_kses_allowed_values_list
|
|
*
|
|
* @param string $html A string of HTML to test.
|
|
* @param string $expected The expected result from KSES.
|
|
* @param array $allowed_html The allowed HTML to pass to KSES.
|
|
*/
|
|
function test_wp_kses_allowed_values_list( $html, $expected, $allowed_html ) {
|
|
$this->assertSame( $expected, wp_kses( $html, $allowed_html ) );
|
|
}
|
|
|
|
/**
|
|
* Data provider for test_wp_kses_allowed_values_list().
|
|
*/
|
|
function data_wp_kses_allowed_values_list() {
|
|
$data = array(
|
|
'valid dir attribute value' => array(
|
|
'<p dir="ltr">foo</p>',
|
|
'<p dir="ltr">foo</p>',
|
|
),
|
|
'valid dir attribute value, upper case' => array(
|
|
'<p DIR="RTL">foo</p>',
|
|
'<p DIR="RTL">foo</p>',
|
|
),
|
|
'invalid dir attribute value' => array(
|
|
'<p dir="up">foo</p>',
|
|
'<p>foo</p>',
|
|
),
|
|
'dir attribute with empty value' => array(
|
|
'<p dir="">foo</p>',
|
|
'<p>foo</p>',
|
|
),
|
|
'dir attribute with no value' => array(
|
|
'<p dir>foo</p>',
|
|
'<p>foo</p>',
|
|
),
|
|
);
|
|
|
|
return array_map(
|
|
function ( $datum ) {
|
|
$datum[] = array(
|
|
'p' => array(
|
|
'dir' => array(
|
|
'values' => array( 'ltr', 'rtl' ),
|
|
),
|
|
),
|
|
);
|
|
|
|
return $datum;
|
|
},
|
|
$data
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test that attributes with the required flag are handled correctly.
|
|
*
|
|
* @ticket 54261
|
|
*
|
|
* @dataProvider data_wp_kses_required_attribute
|
|
*
|
|
* @param string $html A string of HTML to test.
|
|
* @param string $expected The expected result from KSES.
|
|
* @param array $allowed_html The allowed HTML to pass to KSES.
|
|
*/
|
|
function test_wp_kses_required_attribute( $html, $expected, $allowed_html ) {
|
|
$this->assertSame( $expected, wp_kses( $html, $allowed_html ) );
|
|
}
|
|
|
|
/**
|
|
* Data provider for test_wp_kses_required_attribute().
|
|
*/
|
|
function data_wp_kses_required_attribute() {
|
|
$data = array(
|
|
'valid dir attribute value' => array(
|
|
'<p dir="ltr">foo</p>', // Test HTML.
|
|
'<p dir="ltr">foo</p>', // Expected result when dir is not required.
|
|
'<p dir="ltr">foo</p>', // Expected result when dir is required.
|
|
'<p dir="ltr">foo</p>', // Expected result when dir is required, but has no value filter.
|
|
),
|
|
'valid dir attribute value, upper case' => array(
|
|
'<p DIR="RTL">foo</p>',
|
|
'<p DIR="RTL">foo</p>',
|
|
'<p DIR="RTL">foo</p>',
|
|
'<p DIR="RTL">foo</p>',
|
|
),
|
|
'invalid dir attribute value' => array(
|
|
'<p dir="up">foo</p>',
|
|
'<p>foo</p>',
|
|
'<p>foo</p>',
|
|
'<p dir="up">foo</p>',
|
|
),
|
|
'dir attribute with empty value' => array(
|
|
'<p dir="">foo</p>',
|
|
'<p>foo</p>',
|
|
'<p>foo</p>',
|
|
'<p dir="">foo</p>',
|
|
),
|
|
'dir attribute with no value' => array(
|
|
'<p dir>foo</p>',
|
|
'<p>foo</p>',
|
|
'<p>foo</p>',
|
|
'<p dir>foo</p>',
|
|
),
|
|
'dir attribute not set' => array(
|
|
'<p>foo</p>',
|
|
'<p>foo</p>',
|
|
'<p>foo</p>',
|
|
'<p>foo</p>',
|
|
),
|
|
);
|
|
|
|
$return_data = array();
|
|
|
|
foreach ( $data as $description => $datum ) {
|
|
// Test that the required flag defaults to false.
|
|
$return_data[ "$description - required flag not set" ] = array(
|
|
$datum[0],
|
|
$datum[1],
|
|
array(
|
|
'p' => array(
|
|
'dir' => array(
|
|
'values' => array( 'ltr', 'rtl' ),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
// Test when the attribute is not required, but has allowed values.
|
|
$return_data[ "$description - required flag set to false" ] = array(
|
|
$datum[0],
|
|
$datum[1],
|
|
array(
|
|
'p' => array(
|
|
'dir' => array(
|
|
'required' => false,
|
|
'values' => array( 'ltr', 'rtl' ),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
// Test when the attribute is required, but has allowed values.
|
|
$return_data[ "$description - required flag set to true" ] = array(
|
|
$datum[0],
|
|
$datum[2],
|
|
array(
|
|
'p' => array(
|
|
'dir' => array(
|
|
'required' => true,
|
|
'values' => array( 'ltr', 'rtl' ),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
// Test when the attribute is required, but has no allowed values.
|
|
$return_data[ "$description - required flag set to true, no allowed values specified" ] = array(
|
|
$datum[0],
|
|
$datum[3],
|
|
array(
|
|
'p' => array(
|
|
'dir' => array(
|
|
'required' => true,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
return $return_data;
|
|
}
|
|
|
|
/**
|
|
* Test that XML named entities are encoded correctly.
|
|
*
|
|
* @dataProvider data_wp_kses_xml_named_entities
|
|
*
|
|
* @ticket 54060
|
|
* @covers ::wp_kses_xml_named_entities
|
|
*
|
|
* @param array $input The input to wp_kses_xml_named_entities().
|
|
* @param string $expected The expected output.
|
|
*/
|
|
public function test_wp_kses_xml_named_entities( $input, $expected ) {
|
|
$this->assertSame( $expected, wp_kses_xml_named_entities( $input ) );
|
|
}
|
|
|
|
/**
|
|
* Data provider for test_wp_kses_xml_named_entities().
|
|
*
|
|
* @return array Nested array of input, expected pairs.
|
|
*/
|
|
public function data_wp_kses_xml_named_entities() {
|
|
return array(
|
|
// Empty string value testing.
|
|
'empty string' => array(
|
|
'input' => '',
|
|
'expected' => '',
|
|
),
|
|
|
|
// Empty string array value testing.
|
|
'empty string array' => array(
|
|
'input' => array( '', '' ),
|
|
'expected' => '',
|
|
),
|
|
|
|
// $allowedxmlentitynames values testing.
|
|
'amp' => array(
|
|
'input' => array( '', 'amp' ),
|
|
'expected' => '&',
|
|
),
|
|
'lt' => array(
|
|
'input' => array( '', 'lt' ),
|
|
'expected' => '<',
|
|
),
|
|
'gt' => array(
|
|
'input' => array( '', 'gt' ),
|
|
'expected' => '>',
|
|
),
|
|
|
|
// $allowedentitynames values testing.
|
|
'nbsp' => array(
|
|
'input' => array( '', 'nbsp' ),
|
|
'expected' => utf8_encode( chr( 160 ) ),
|
|
),
|
|
'iexcl' => array(
|
|
'input' => array( '', 'iexcl' ),
|
|
'expected' => '¡',
|
|
),
|
|
'cent' => array(
|
|
'input' => array( '', 'cent' ),
|
|
'expected' => '¢',
|
|
),
|
|
|
|
// Some other value testing.
|
|
'test' => array(
|
|
'input' => array( '', 'test' ),
|
|
'expected' => '&test;',
|
|
),
|
|
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test that KSES globals are defined.
|
|
*
|
|
* @dataProvider data_kses_globals_are_defined
|
|
*
|
|
* @ticket 54060
|
|
*
|
|
* @param string $global The name of the global variable.
|
|
*/
|
|
public function test_kses_globals_are_defined( $global ) {
|
|
$this->assertArrayHasKey( $global, $GLOBALS );
|
|
}
|
|
|
|
/**
|
|
* Data provider for test_kses_globals_are_defined().
|
|
*
|
|
* @return array
|
|
*/
|
|
public function data_kses_globals_are_defined() {
|
|
return array(
|
|
'allowedposttags' => array(
|
|
'global' => 'allowedposttags',
|
|
),
|
|
'allowedtags' => array(
|
|
'global' => 'allowedtags',
|
|
),
|
|
'allowedentitynames' => array(
|
|
'global' => 'allowedentitynames',
|
|
),
|
|
'allowedxmlentitynames' => array(
|
|
'global' => 'allowedxmlentitynames',
|
|
),
|
|
);
|
|
}
|
|
}
|