MediaWiki
REL1_22
|
00001 <?php 00002 00006 class UploadBaseTest extends MediaWikiTestCase { 00007 00009 protected $upload; 00010 00011 protected function setUp() { 00012 global $wgHooks; 00013 parent::setUp(); 00014 00015 $this->upload = new UploadTestHandler; 00016 $this->hooks = $wgHooks; 00017 $wgHooks['InterwikiLoadPrefix'][] = function ( $prefix, &$data ) { 00018 return false; 00019 }; 00020 } 00021 00022 protected function tearDown() { 00023 global $wgHooks; 00024 $wgHooks = $this->hooks; 00025 00026 parent::tearDown(); 00027 } 00028 00029 00037 public function testTitleValidation( $srcFilename, $dstFilename, $code, $msg ) { 00038 /* Check the result code */ 00039 $this->assertEquals( $code, 00040 $this->upload->testTitleValidation( $srcFilename ), 00041 "$msg code" ); 00042 00043 /* If we expect a valid title, check the title itself. */ 00044 if ( $code == UploadBase::OK ) { 00045 $this->assertEquals( $dstFilename, 00046 $this->upload->getTitle()->getText(), 00047 "$msg text" ); 00048 } 00049 } 00050 00054 public static function provideTestTitleValidation() { 00055 return array( 00056 /* Test a valid title */ 00057 array( 'ValidTitle.jpg', 'ValidTitle.jpg', UploadBase::OK, 00058 'upload valid title' ), 00059 /* A title with a slash */ 00060 array( 'A/B.jpg', 'B.jpg', UploadBase::OK, 00061 'upload title with slash' ), 00062 /* A title with illegal char */ 00063 array( 'A:B.jpg', 'A-B.jpg', UploadBase::OK, 00064 'upload title with colon' ), 00065 /* Stripping leading File: prefix */ 00066 array( 'File:C.jpg', 'C.jpg', UploadBase::OK, 00067 'upload title with File prefix' ), 00068 /* Test illegal suggested title (r94601) */ 00069 array( '%281%29.JPG', null, UploadBase::ILLEGAL_FILENAME, 00070 'illegal title for upload' ), 00071 /* A title without extension */ 00072 array( 'A', null, UploadBase::FILETYPE_MISSING, 00073 'upload title without extension' ), 00074 /* A title with no basename */ 00075 array( '.jpg', null, UploadBase::MIN_LENGTH_PARTNAME, 00076 'upload title without basename' ), 00077 /* A title that is longer than 255 bytes */ 00078 array( str_repeat( 'a', 255 ) . '.jpg', null, UploadBase::FILENAME_TOO_LONG, 00079 'upload title longer than 255 bytes' ), 00080 /* A title that is longer than 240 bytes */ 00081 array( str_repeat( 'a', 240 ) . '.jpg', null, UploadBase::FILENAME_TOO_LONG, 00082 'upload title longer than 240 bytes' ), 00083 ); 00084 } 00085 00090 public function testVerifyUpload() { 00091 /* Setup with zero file size */ 00092 $this->upload->initializePathInfo( '', '', 0 ); 00093 $result = $this->upload->verifyUpload(); 00094 $this->assertEquals( UploadBase::EMPTY_FILE, 00095 $result['status'], 00096 'upload empty file' ); 00097 } 00098 00099 // Helper used to create an empty file of size $size. 00100 private function createFileOfSize( $size ) { 00101 $filename = tempnam( wfTempDir(), "mwuploadtest" ); 00102 00103 $fh = fopen( $filename, 'w' ); 00104 ftruncate( $fh, $size ); 00105 fclose( $fh ); 00106 00107 return $filename; 00108 } 00109 00115 public function testMaxUploadSize() { 00116 global $wgMaxUploadSize; 00117 $savedGlobal = $wgMaxUploadSize; // save global 00118 global $wgFileExtensions; 00119 $wgFileExtensions[] = 'txt'; 00120 00121 $wgMaxUploadSize = 100; 00122 00123 $filename = $this->createFileOfSize( $wgMaxUploadSize ); 00124 $this->upload->initializePathInfo( basename( $filename ) . '.txt', $filename, 100 ); 00125 $result = $this->upload->verifyUpload(); 00126 unlink( $filename ); 00127 00128 $this->assertEquals( 00129 array( 'status' => UploadBase::OK ), $result ); 00130 00131 $wgMaxUploadSize = $savedGlobal; // restore global 00132 } 00133 00134 00138 public function testCheckSvgScriptCallback( $svg, $wellFormed, $filterMatch, $message ) { 00139 list( $formed, $match ) = $this->upload->checkSvgString( $svg ); 00140 $this->assertSame( $wellFormed, $formed, $message ); 00141 $this->assertSame( $filterMatch, $match, $message ); 00142 } 00143 00144 public static function provideCheckSvgScriptCallback() { 00145 return array( 00146 // html5sec SVG vectors 00147 array( 00148 '<svg xmlns="http://www.w3.org/2000/svg"><script>alert(1)</script></svg>', 00149 true, 00150 true, 00151 'Script tag in svg (http://html5sec.org/#47)' 00152 ), 00153 array( 00154 '<svg xmlns="http://www.w3.org/2000/svg"><g onload="javascript:alert(1)"></g></svg>', 00155 true, 00156 true, 00157 'SVG with onload property (http://html5sec.org/#11)' 00158 ), 00159 array( 00160 '<svg onload="javascript:alert(1)" xmlns="http://www.w3.org/2000/svg"></svg>', 00161 true, 00162 true, 00163 'SVG with onload property (http://html5sec.org/#65)' 00164 ), 00165 array( 00166 '<svg xmlns="http://www.w3.org/2000/svg"> <a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="javascript:alert(1)"><rect width="1000" height="1000" fill="white"/></a> </svg>', 00167 true, 00168 true, 00169 'SVG with javascript xlink (http://html5sec.org/#87)' 00170 ), 00171 array( 00172 '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <animation xlink:href="javascript:alert(1)"/> </svg>', 00173 true, 00174 true, 00175 'SVG with Opera animation xlink (http://html5sec.org/#88 - a)' 00176 ), 00177 array( 00178 '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <animation xlink:href="data:text/xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' onload=\'alert(1)\'%3E%3C/svg%3E"/> </svg>', 00179 true, 00180 true, 00181 'SVG with Opera animation xlink (http://html5sec.org/#88 - b)' 00182 ), 00183 array( 00184 '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <image xlink:href="data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' onload=\'alert(1)\'%3E%3C/svg%3E"/> </svg>', 00185 true, 00186 true, 00187 'SVG with Opera image xlink (http://html5sec.org/#88 - c)' 00188 ), 00189 array( 00190 '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <foreignObject xlink:href="javascript:alert(1)"/> </svg>', 00191 true, 00192 true, 00193 'SVG with Opera foreignObject xlink (http://html5sec.org/#88 - d)' 00194 ), 00195 array( 00196 '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <foreignObject xlink:href="data:text/xml,%3Cscript xmlns=\'http://www.w3.org/1999/xhtml\'%3Ealert(1)%3C/script%3E"/> </svg>', 00197 true, 00198 true, 00199 'SVG with Opera foreignObject xlink (http://html5sec.org/#88 - e)' 00200 ), 00201 array( 00202 '<svg xmlns="http://www.w3.org/2000/svg"> <set attributeName="onmouseover" to="alert(1)"/> </svg>', 00203 true, 00204 true, 00205 'SVG with event handler set (http://html5sec.org/#89 - a)' 00206 ), 00207 array( 00208 '<svg xmlns="http://www.w3.org/2000/svg"> <animate attributeName="onunload" to="alert(1)"/> </svg>', 00209 true, 00210 true, 00211 'SVG with event handler animate (http://html5sec.org/#89 - a)' 00212 ), 00213 array( 00214 '<svg xmlns="http://www.w3.org/2000/svg"> <handler xmlns:ev="http://www.w3.org/2001/xml-events" ev:event="load">alert(1)</handler> </svg>', 00215 true, 00216 true, 00217 'SVG with element handler (http://html5sec.org/#94)' 00218 ), 00219 array( 00220 '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <feImage> <set attributeName="xlink:href" to="data:image/svg+xml;charset=utf-8;base64, PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxzY3JpcHQ%2BYWxlcnQoMSk8L3NjcmlwdD48L3N2Zz4NCg%3D%3D"/> </feImage> </svg>', 00221 true, 00222 true, 00223 'SVG with href to data: url (http://html5sec.org/#95)' 00224 ), 00225 array( 00226 '<svg xmlns="http://www.w3.org/2000/svg" id="foo"> <x xmlns="http://www.w3.org/2001/xml-events" event="load" observer="foo" handler="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%3Chandler%20xml%3Aid%3D%22bar%22%20type%3D%22application%2Fecmascript%22%3E alert(1) %3C%2Fhandler%3E%0A%3C%2Fsvg%3E%0A#bar"/> </svg>', 00227 true, 00228 true, 00229 'SVG with Tiny handler (http://html5sec.org/#104)' 00230 ), 00231 array( 00232 '<svg xmlns="http://www.w3.org/2000/svg"> <a id="x"><rect fill="white" width="1000" height="1000"/></a> <rect fill="white" style="clip-path:url(test3.svg#a);fill:url(#b);filter:url(#c);marker:url(#d);mask:url(#e);stroke:url(#f);"/> </svg>', 00233 true, 00234 true, 00235 'SVG with new CSS styles properties (http://html5sec.org/#109)' 00236 ), 00237 array( 00238 '<svg xmlns="http://www.w3.org/2000/svg"> <a id="x"><rect fill="white" width="1000" height="1000"/></a> <rect clip-path="url(test3.svg#a)" /> </svg>', 00239 true, 00240 true, 00241 'SVG with new CSS styles properties as attributes' 00242 ), 00243 array( 00244 '<svg xmlns="http://www.w3.org/2000/svg"> <a id="x"> <rect fill="white" width="1000" height="1000"/> </a> <rect fill="url(http://html5sec.org/test3.svg#a)" /> </svg>', 00245 true, 00246 true, 00247 'SVG with new CSS styles properties as attributes (2)' 00248 ), 00249 array( 00250 '<svg xmlns="http://www.w3.org/2000/svg"> <path d="M0,0" style="marker-start:url(test4.svg#a)"/> </svg>', 00251 true, 00252 true, 00253 'SVG with path marker-start (http://html5sec.org/#110)' 00254 ), 00255 array( 00256 '<?xml version="1.0"?> <?xml-stylesheet type="text/xml" href="#stylesheet"?> <!DOCTYPE doc [ <!ATTLIST xsl:stylesheet id ID #REQUIRED>]> <svg xmlns="http://www.w3.org/2000/svg"> <xsl:stylesheet id="stylesheet" version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <iframe xmlns="http://www.w3.org/1999/xhtml" src="javascript:alert(1)"></iframe> </xsl:template> </xsl:stylesheet> <circle fill="red" r="40"></circle> </svg>', 00257 true, 00258 true, 00259 'SVG with embedded stylesheet (http://html5sec.org/#125)' 00260 ), 00261 array( 00262 '<svg xmlns="http://www.w3.org/2000/svg" id="x"> <listener event="load" handler="#y" xmlns="http://www.w3.org/2001/xml-events" observer="x"/> <handler id="y">alert(1)</handler> </svg>', 00263 true, 00264 true, 00265 'SVG with handler attribute (http://html5sec.org/#127)' 00266 ), 00267 array( 00268 // Haven't found a browser that accepts this particular example, but we 00269 // don't want to allow embeded svgs, ever 00270 '<svg> <image style=\'filter:url("data:image/svg+xml;charset=utf-8;base64, PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxzY3JpcHQ/YWxlcnQoMSk8L3NjcmlwdD48L3N2Zz4NCg==")\' /> </svg>', 00271 true, 00272 true, 00273 'SVG with image filter via style (http://html5sec.org/#129)' 00274 ), 00275 array( 00276 // This doesn't seem possible without embedding the svg, but just in case 00277 '<svg> <a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="?"> <circle r="400"></circle> <animate attributeName="xlink:href" begin="0" from="javascript:alert(1)" to="" /> </a></svg>', 00278 true, 00279 true, 00280 'SVG with animate from (http://html5sec.org/#137)' 00281 ), 00282 00283 // Other hostile SVG's 00284 array( 00285 '<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns:xlink="http://www.w3.org/1999/xlink"> <image xlink:href="https://upload.wikimedia.org/wikipedia/commons/3/34/Bahnstrecke_Zeitz-Camburg_1930.png" /> </svg>', 00286 true, 00287 true, 00288 'SVG with non-local image href (bug 65839)' 00289 ), 00290 array( 00291 '<?xml version="1.0" ?> <?xml-stylesheet type="text/xsl" href="/w/index.php?title=User:Jeeves/test.xsl&action=raw&format=xml" ?> <svg> <height>50</height> <width>100</width> </svg>', 00292 true, 00293 true, 00294 'SVG with remote stylesheet (bug 57550)' 00295 ), 00296 array( 00297 '<svg xmlns="http://www.w3.org/2000/svg" viewbox="-1 -1 15 15"> <rect y="0" height="13" width="12" stroke="#179" rx="1" fill="#2ac"/> <text x="1.5" y="11" font-family="courier" stroke="white" font-size="16"><![CDATA[B]]></text> <iframe xmlns="http://www.w3.org/1999/xhtml" srcdoc="<script>alert('XSSED => Domain('+top.document.domain+')');</script>"></iframe> </svg>', 00298 true, 00299 true, 00300 'SVG with rembeded iframe (bug 60771)' 00301 ), 00302 array( 00303 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="6 3 177 153" xmlns:xlink="http://www.w3.org/1999/xlink"> <style>@import url("https://fonts.googleapis.com/css?family=Bitter:700&text=WebPlatform.org");</style> <g transform="translate(-.5,-.5)"> <text fill="#474747" x="95" y="150" text-anchor="middle" font-family="Bitter" font-size="20" font-weight="bold">WebPlatform.org</text> </g> </svg>', 00304 true, 00305 true, 00306 'SVG with @import in style element (bug 69008)' 00307 ), 00308 array( 00309 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="6 3 177 153" xmlns:xlink="http://www.w3.org/1999/xlink"> <style>@import url("https://fonts.googleapis.com/css?family=Bitter:700&text=WebPlatform.org");<foo/></style> <g transform="translate(-.5,-.5)"> <text fill="#474747" x="95" y="150" text-anchor="middle" font-family="Bitter" font-size="20" font-weight="bold">WebPlatform.org</text> </g> </svg>', 00310 true, 00311 true, 00312 'SVG with @import in style element and child element (bug 69008#c11)' 00313 ), 00314 array( 00315 '<svg xmlns="http://www.w3.org/2000/svg"> <rect width="100" height="100" style="background-image:url(https://www.google.com/images/srpr/logo11w.png)"/> </svg>', 00316 true, 00317 true, 00318 'SVG with remote background image (bug 69008)' 00319 ), 00320 array( 00321 '<svg xmlns="http://www.w3.org/2000/svg"> <rect width="100" height="100" style="background-image:\55rl(https://www.google.com/images/srpr/logo11w.png)"/> </svg>', 00322 true, 00323 true, 00324 'SVG with remote background image, encoded (bug 69008)' 00325 ), 00326 array( 00327 '<svg xmlns="http://www.w3.org/2000/svg"> <style> #a { background-image:\55rl(\'https://www.google.com/images/srpr/logo11w.png\'); } </style> <rect width="100" height="100" id="a"/> </svg>', 00328 true, 00329 true, 00330 'SVG with remote background image, in style element (bug 69008)' 00331 ), 00332 array( 00333 // This currently doesn't seem to work in any browsers, but in case 00334 // http://www.w3.org/TR/css3-images/ is implemented for SVG files 00335 '<svg xmlns="http://www.w3.org/2000/svg"> <rect width="100" height="100" style="background-image:image(\'sprites.svg#xywh=40,0,20,20\')"/> </svg>', 00336 true, 00337 true, 00338 'SVG with remote background image using image() (bug 69008)' 00339 ), 00340 00341 // Test good, but strange files that we want to allow 00342 array( 00343 '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <g> <a xlink:href="http://en.wikipedia.org/wiki/Main_Page"> <path transform="translate(0,496)" id="path6706" d="m 112.09375,107.6875 -5.0625,3.625 -4.3125,5.03125 -0.46875,0.5 -4.09375,3.34375 -9.125,5.28125 -8.625,-3.375 z" style="fill:#cccccc;fill-opacity:1;stroke:#6e6e6e;stroke-width:0.69999999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;display:inline" /> </a> </g> </svg>', 00344 true, 00345 false, 00346 'SVG with <a> link to a remote site' 00347 ), 00348 array( 00349 '<svg> <defs> <filter id="filter6226" x="-0.93243687" width="2.8648737" y="-0.24250539" height="1.4850108"> <feGaussianBlur stdDeviation="3.2344681" id="feGaussianBlur6228" /> </filter> <clipPath id="clipPath2436"> <path d="M 0,0 L 0,0 L 0,0 L 0,0 z" id="path2438" /> </clipPath> </defs> <g clip-path="url(#clipPath2436)" id="g2460"> <text id="text2466"> <tspan>12345</tspan> </text> </g> <path style="fill:#346733;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:bevel;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;filter:url(\'#filter6226\');fill-opacity:1;opacity:0.79807692" d="M 236.82371,332.63732 C 236.92217,332.63732 z" id="path5618" /> </svg>', 00350 true, 00351 false, 00352 'SVG with local urls, including filter: in style' 00353 ), 00354 00355 ); 00356 } 00357 } 00358 00359 class UploadTestHandler extends UploadBase { 00360 public function initializeFromRequest( &$request ) { 00361 } 00362 00363 public function testTitleValidation( $name ) { 00364 $this->mTitle = false; 00365 $this->mDesiredDestName = $name; 00366 $this->mTitleError = UploadBase::OK; 00367 $this->getTitle(); 00368 00369 return $this->mTitleError; 00370 } 00371 00377 public function checkSvgString( $svg ) { 00378 $check = new XmlTypeCheck( 00379 $svg, 00380 array( $this, 'checkSvgScriptCallback' ), 00381 false, 00382 array( 'processing_instruction_handler' => 'UploadBase::checkSvgPICallback' ) 00383 ); 00384 return array( $check->wellFormed, $check->filterMatch ); 00385 } 00386 }