MediaWiki
REL1_21
|
00001 <?php 00002 00003 class SanitizerTest extends MediaWikiTestCase { 00004 00005 protected function setUp() { 00006 parent::setUp(); 00007 00008 AutoLoader::loadClass( 'Sanitizer' ); 00009 } 00010 00011 function testDecodeNamedEntities() { 00012 $this->assertEquals( 00013 "\xc3\xa9cole", 00014 Sanitizer::decodeCharReferences( 'école' ), 00015 'decode named entities' 00016 ); 00017 } 00018 00019 function testDecodeNumericEntities() { 00020 $this->assertEquals( 00021 "\xc4\x88io bonas dans l'\xc3\xa9cole!", 00022 Sanitizer::decodeCharReferences( "Ĉio bonas dans l'école!" ), 00023 'decode numeric entities' 00024 ); 00025 } 00026 00027 function testDecodeMixedEntities() { 00028 $this->assertEquals( 00029 "\xc4\x88io bonas dans l'\xc3\xa9cole!", 00030 Sanitizer::decodeCharReferences( "Ĉio bonas dans l'école!" ), 00031 'decode mixed numeric/named entities' 00032 ); 00033 } 00034 00035 function testDecodeMixedComplexEntities() { 00036 $this->assertEquals( 00037 "\xc4\x88io bonas dans l'\xc3\xa9cole! (mais pas Ĉio dans l'école)", 00038 Sanitizer::decodeCharReferences( 00039 "Ĉio bonas dans l'école! (mais pas &#x108;io dans l'&eacute;cole)" 00040 ), 00041 'decode mixed complex entities' 00042 ); 00043 } 00044 00045 function testInvalidAmpersand() { 00046 $this->assertEquals( 00047 'a & b', 00048 Sanitizer::decodeCharReferences( 'a & b' ), 00049 'Invalid ampersand' 00050 ); 00051 } 00052 00053 function testInvalidEntities() { 00054 $this->assertEquals( 00055 '&foo;', 00056 Sanitizer::decodeCharReferences( '&foo;' ), 00057 'Invalid named entity' 00058 ); 00059 } 00060 00061 function testInvalidNumberedEntities() { 00062 $this->assertEquals( UTF8_REPLACEMENT, Sanitizer::decodeCharReferences( "�" ), 'Invalid numbered entity' ); 00063 } 00064 00072 function testRemovehtmltagsOnHtml5Tags( $tag, $escaped ) { 00073 $this->setMwGlobals( array( 00074 # Enable HTML5 mode 00075 'wgHtml5' => true, 00076 'wgUseTidy' => false 00077 ) ); 00078 00079 if ( $escaped ) { 00080 $this->assertEquals( "<$tag>", 00081 Sanitizer::removeHTMLtags( "<$tag>" ) 00082 ); 00083 } else { 00084 $this->assertEquals( "<$tag></$tag>\n", 00085 Sanitizer::removeHTMLtags( "<$tag>" ) 00086 ); 00087 } 00088 } 00089 00093 function provideHtml5Tags() { 00094 $ESCAPED = true; # We want tag to be escaped 00095 $VERBATIM = false; # We want to keep the tag 00096 return array( 00097 array( 'data', $VERBATIM ), 00098 array( 'mark', $VERBATIM ), 00099 array( 'time', $VERBATIM ), 00100 array( 'video', $ESCAPED ), 00101 ); 00102 } 00103 00104 function testSelfClosingTag() { 00105 $this->setMwGlobals( array( 00106 'wgUseTidy' => false 00107 ) ); 00108 00109 $this->assertEquals( 00110 '<div>Hello world</div>', 00111 Sanitizer::removeHTMLtags( '<div>Hello world</div />' ), 00112 'Self-closing closing div' 00113 ); 00114 } 00115 00116 00121 function testDecodeTagAttributes( $expected, $attributes, $message = '' ) { 00122 $this->assertEquals( $expected, 00123 Sanitizer::decodeTagAttributes( $attributes ), 00124 $message 00125 ); 00126 } 00127 00128 function provideTagAttributesToDecode() { 00129 return array( 00130 array( array( 'foo' => 'bar' ), 'foo=bar', 'Unquoted attribute' ), 00131 array( array( 'foo' => 'bar' ), ' foo = bar ', 'Spaced attribute' ), 00132 array( array( 'foo' => 'bar' ), 'foo="bar"', 'Double-quoted attribute' ), 00133 array( array( 'foo' => 'bar' ), 'foo=\'bar\'', 'Single-quoted attribute' ), 00134 array( array( 'foo' => 'bar', 'baz' => 'foo' ), 'foo=\'bar\' baz="foo"', 'Several attributes' ), 00135 array( array( 'foo' => 'bar', 'baz' => 'foo' ), 'foo=\'bar\' baz="foo"', 'Several attributes' ), 00136 array( array( 'foo' => 'bar', 'baz' => 'foo' ), 'foo=\'bar\' baz="foo"', 'Several attributes' ), 00137 array( array( ':foo' => 'bar' ), ':foo=\'bar\'', 'Leading :' ), 00138 array( array( '_foo' => 'bar' ), '_foo=\'bar\'', 'Leading _' ), 00139 array( array( 'foo' => 'bar' ), 'Foo=\'bar\'', 'Leading capital' ), 00140 array( array( 'foo' => 'BAR' ), 'FOO=BAR', 'Attribute keys are normalized to lowercase' ), 00141 00142 # Invalid beginning 00143 array( array(), '-foo=bar', 'Leading - is forbidden' ), 00144 array( array(), '.foo=bar', 'Leading . is forbidden' ), 00145 array( array( 'foo-bar' => 'bar' ), 'foo-bar=bar', 'A - is allowed inside the attribute' ), 00146 array( array( 'foo-' => 'bar' ), 'foo-=bar', 'A - is allowed inside the attribute' ), 00147 array( array( 'foo.bar' => 'baz' ), 'foo.bar=baz', 'A . is allowed inside the attribute' ), 00148 array( array( 'foo.' => 'baz' ), 'foo.=baz', 'A . is allowed as last character' ), 00149 array( array( 'foo6' => 'baz' ), 'foo6=baz', 'Numbers are allowed' ), 00150 00151 00152 # This bit is more relaxed than XML rules, but some extensions use 00153 # it, like ProofreadPage (see bug 27539) 00154 array( array( '1foo' => 'baz' ), '1foo=baz', 'Leading numbers are allowed' ), 00155 array( array(), 'foo$=baz', 'Symbols are not allowed' ), 00156 array( array(), 'foo@=baz', 'Symbols are not allowed' ), 00157 array( array(), 'foo~=baz', 'Symbols are not allowed' ), 00158 array( array( 'foo' => '1[#^`*%w/(' ), 'foo=1[#^`*%w/(', 'All kind of characters are allowed as values' ), 00159 array( array( 'foo' => '1[#^`*%\'w/(' ), 'foo="1[#^`*%\'w/("', 'Double quotes are allowed if quoted by single quotes' ), 00160 array( array( 'foo' => '1[#^`*%"w/(' ), 'foo=\'1[#^`*%"w/(\'', 'Single quotes are allowed if quoted by double quotes' ), 00161 array( array( 'foo' => '&"' ), 'foo=&"', 'Special chars can be provided as entities' ), 00162 array( array( 'foo' => '&foobar;' ), 'foo=&foobar;', 'Entity-like items are accepted' ), 00163 ); 00164 } 00165 00170 function testDeprecatedAttributesUnaltered( $inputAttr, $inputEl, $message = '' ) { 00171 $this->assertEquals( " $inputAttr", 00172 Sanitizer::fixTagAttributes( $inputAttr, $inputEl ), 00173 $message 00174 ); 00175 } 00176 00177 public static function provideDeprecatedAttributes() { 00179 return array( 00180 array( 'clear="left"', 'br' ), 00181 array( 'clear="all"', 'br' ), 00182 array( 'width="100"', 'td' ), 00183 array( 'nowrap="true"', 'td' ), 00184 array( 'nowrap=""', 'td' ), 00185 array( 'align="right"', 'td' ), 00186 array( 'align="center"', 'table' ), 00187 array( 'align="left"', 'tr' ), 00188 array( 'align="center"', 'div' ), 00189 array( 'align="left"', 'h1' ), 00190 array( 'align="left"', 'span' ), 00191 ); 00192 } 00193 00198 function testCssCommentsChecking( $expected, $css, $message = '' ) { 00199 $this->assertEquals( $expected, 00200 Sanitizer::checkCss( $css ), 00201 $message 00202 ); 00203 } 00204 00205 public static function provideCssCommentsFixtures() { 00207 return array( 00208 array( ' ', '/**/' ), 00209 array( ' ', '/****/' ), 00210 array( ' ', '/* comment */' ), 00211 array( ' ', "\\2f\\2a foo \\2a\\2f", 00212 'Backslash-escaped comments must be stripped (bug 28450)' ), 00213 array( '', '/* unfinished comment structure', 00214 'Remove anything after a comment-start token' ), 00215 array( '', "\\2f\\2a unifinished comment'", 00216 'Remove anything after a backslash-escaped comment-start token' ), 00217 array( '/* insecure input */', 'filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'asdf.png\',sizingMethod=\'scale\');' ), 00218 array( '/* insecure input */', '-ms-filter: "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'asdf.png\',sizingMethod=\'scale\')";' ), 00219 array( '/* insecure input */', 'width: expression(1+1);' ), 00220 array( '/* insecure input */', 'background-image: image(asdf.png);' ), 00221 array( '/* insecure input */', 'background-image: -webkit-image(asdf.png);' ), 00222 array( '/* insecure input */', 'background-image: -moz-image(asdf.png);' ), 00223 array( '/* insecure input */', 'background-image: image-set("asdf.png" 1x, "asdf.png" 2x);' ), 00224 array( '/* insecure input */', 'background-image: -webkit-image-set("asdf.png" 1x, "asdf.png" 2x);' ), 00225 array( '/* insecure input */', 'background-image: -moz-image-set("asdf.png" 1x, "asdf.png" 2x);' ), 00226 ); 00227 } 00228 00232 function provideAttributeSupport() { 00234 return array( 00235 array( 'div', ' role="presentation"', ' role="presentation"', 'Support for WAI-ARIA\'s role="presentation".' ), 00236 array( 'div', ' role="main"', '', "Other WAI-ARIA roles are currently not supported." ), 00237 ); 00238 } 00239 00243 function testAttributeSupport( $tag, $attributes, $expected, $message ) { 00244 $this->assertEquals( $expected, 00245 Sanitizer::fixTagAttributes( $attributes, $tag ), 00246 $message 00247 ); 00248 } 00249 00250 }