MediaWiki  REL1_22
UploadBaseTest.php
Go to the documentation of this file.
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&amp;action=raw&amp;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="&#x3C;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3E;&#x61;&#x6C;&#x65;&#x72;&#x74;&#x28;&#x27;&#x58;&#x53;&#x53;&#x45;&#x44;&#x20;&#x3D;&#x3E;&#x20;&#x44;&#x6F;&#x6D;&#x61;&#x69;&#x6E;&#x28;&#x27;&#x2B;&#x74;&#x6F;&#x70;&#x2E;&#x64;&#x6F;&#x63;&#x75;&#x6D;&#x65;&#x6E;&#x74;&#x2E;&#x64;&#x6F;&#x6D;&#x61;&#x69;&#x6E;&#x2B;&#x27;&#x29;&#x27;&#x29;&#x3B;&#x3C;&#x2F;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3E;"></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&amp;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&amp;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 }