upload = new UploadTestHandler;
$this->setMwGlobals( 'wgHooks', array(
'InterwikiLoadPrefix' => array(
function ( $prefix, &$data ) {
return false;
}
),
) );
}
/**
* First checks the return code
* of UploadBase::getTitle() and then the actual returned title
*
* @dataProvider provideTestTitleValidation
* @covers UploadBase::getTitle
*/
public function testTitleValidation( $srcFilename, $dstFilename, $code, $msg ) {
/* Check the result code */
$this->assertEquals( $code,
$this->upload->testTitleValidation( $srcFilename ),
"$msg code" );
/* If we expect a valid title, check the title itself. */
if ( $code == UploadBase::OK ) {
$this->assertEquals( $dstFilename,
$this->upload->getTitle()->getText(),
"$msg text" );
}
}
/**
* Test various forms of valid and invalid titles that can be supplied.
*/
public static function provideTestTitleValidation() {
return array(
/* Test a valid title */
array( 'ValidTitle.jpg', 'ValidTitle.jpg', UploadBase::OK,
'upload valid title' ),
/* A title with a slash */
array( 'A/B.jpg', 'B.jpg', UploadBase::OK,
'upload title with slash' ),
/* A title with illegal char */
array( 'A:B.jpg', 'A-B.jpg', UploadBase::OK,
'upload title with colon' ),
/* Stripping leading File: prefix */
array( 'File:C.jpg', 'C.jpg', UploadBase::OK,
'upload title with File prefix' ),
/* Test illegal suggested title (r94601) */
array( '%281%29.JPG', null, UploadBase::ILLEGAL_FILENAME,
'illegal title for upload' ),
/* A title without extension */
array( 'A', null, UploadBase::FILETYPE_MISSING,
'upload title without extension' ),
/* A title with no basename */
array( '.jpg', null, UploadBase::MIN_LENGTH_PARTNAME,
'upload title without basename' ),
/* A title that is longer than 255 bytes */
array( str_repeat( 'a', 255 ) . '.jpg', null, UploadBase::FILENAME_TOO_LONG,
'upload title longer than 255 bytes' ),
/* A title that is longer than 240 bytes */
array( str_repeat( 'a', 240 ) . '.jpg', null, UploadBase::FILENAME_TOO_LONG,
'upload title longer than 240 bytes' ),
);
}
/**
* Test the upload verification functions
* @covers UploadBase::verifyUpload
*/
public function testVerifyUpload() {
/* Setup with zero file size */
$this->upload->initializePathInfo( '', '', 0 );
$result = $this->upload->verifyUpload();
$this->assertEquals( UploadBase::EMPTY_FILE,
$result['status'],
'upload empty file' );
}
// Helper used to create an empty file of size $size.
private function createFileOfSize( $size ) {
$filename = $this->getNewTempFile();
$fh = fopen( $filename, 'w' );
ftruncate( $fh, $size );
fclose( $fh );
return $filename;
}
/**
* test uploading a 100 bytes file with $wgMaxUploadSize = 100
*
* This method should be abstracted so we can test different settings.
*/
public function testMaxUploadSize() {
$this->setMwGlobals( array(
'wgMaxUploadSize' => 100,
'wgFileExtensions' => array(
'txt',
),
) );
$filename = $this->createFileOfSize( 100 );
$this->upload->initializePathInfo( basename( $filename ) . '.txt', $filename, 100 );
$result = $this->upload->verifyUpload();
$this->assertEquals(
array( 'status' => UploadBase::OK ),
$result
);
}
/**
* @dataProvider provideCheckSvgScriptCallback
*/
public function testCheckSvgScriptCallback( $svg, $wellFormed, $filterMatch, $message ) {
list( $formed, $match ) = $this->upload->checkSvgString( $svg );
$this->assertSame( $wellFormed, $formed, $message );
$this->assertSame( $filterMatch, $match, $message );
}
public static function provideCheckSvgScriptCallback() {
return array(
// html5sec SVG vectors
array(
'',
true,
true,
'Script tag in svg (http://html5sec.org/#47)'
),
array(
'',
true,
true,
'SVG with onload property (http://html5sec.org/#11)'
),
array(
'',
true,
true,
'SVG with onload property (http://html5sec.org/#65)'
),
array(
'',
true,
true,
'SVG with javascript xlink (http://html5sec.org/#87)'
),
array(
'',
true,
true,
'SVG with Opera image xlink (http://html5sec.org/#88 - c)'
),
array(
'',
true,
true,
'SVG with Opera animation xlink (http://html5sec.org/#88 - a)'
),
array(
'',
true,
true,
'SVG with Opera animation xlink (http://html5sec.org/#88 - b)'
),
array(
'',
true,
true,
'SVG with Opera image xlink (http://html5sec.org/#88 - c)'
),
array(
'',
true,
true,
'SVG with Opera foreignObject xlink (http://html5sec.org/#88 - d)'
),
array(
'',
true,
true,
'SVG with Opera foreignObject xlink (http://html5sec.org/#88 - e)'
),
array(
'',
true,
true,
'SVG with event handler set (http://html5sec.org/#89 - a)'
),
array(
'',
true,
true,
'SVG with event handler animate (http://html5sec.org/#89 - a)'
),
array(
'',
true,
true,
'SVG with element handler (http://html5sec.org/#94)'
),
array(
'',
true,
true,
'SVG with href to data: url (http://html5sec.org/#95)'
),
array(
'',
true,
true,
'SVG with Tiny handler (http://html5sec.org/#104)'
),
array(
'',
true,
true,
'SVG with new CSS styles properties (http://html5sec.org/#109)'
),
array(
'',
true,
true,
'SVG with new CSS styles properties as attributes'
),
array(
'',
true,
true,
'SVG with new CSS styles properties as attributes (2)'
),
array(
'',
true,
true,
'SVG with path marker-start (http://html5sec.org/#110)'
),
array(
' ]> ',
true,
true,
'SVG with embedded stylesheet (http://html5sec.org/#125)'
),
array(
'',
true,
true,
'SVG with handler attribute (http://html5sec.org/#127)'
),
array(
// Haven't found a browser that accepts this particular example, but we
// don't want to allow embeded svgs, ever
'',
true,
true,
'SVG with image filter via style (http://html5sec.org/#129)'
),
array(
// This doesn't seem possible without embedding the svg, but just in case
'',
true,
true,
'SVG with animate from (http://html5sec.org/#137)'
),
array(
'',
true,
true,
'SVG with animate xlink:href (http://html5sec.org/#137)'
),
array(
'',
true,
true,
'SVG with animate y:href (http://html5sec.org/#137)'
),
// Other hostile SVG's
array(
' ',
true,
true,
'SVG with non-local image href (bug 65839)'
),
array(
' ',
true,
true,
'SVG with remote stylesheet (bug 57550)'
),
array(
'',
true,
true,
'SVG with rembeded iframe (bug 60771)'
),
array(
'',
true,
true,
'SVG with @import in style element (bug 69008)'
),
array(
'',
true,
true,
'SVG with @import in style element and child element (bug 69008#c11)'
),
array(
'',
true,
true,
'SVG with case-insensitive @import in style element (bug T85349)'
),
array(
'',
true,
true,
'SVG with remote background image (bug 69008)'
),
array(
'',
true,
true,
'SVG with remote background image, encoded (bug 69008)'
),
array(
'',
true,
true,
'SVG with remote background image, in style element (bug 69008)'
),
array(
// This currently doesn't seem to work in any browsers, but in case
// http://www.w3.org/TR/css3-images/ is implemented for SVG files
'',
true,
true,
'SVG with remote background image using image() (bug 69008)'
),
array(
// As reported by Cure53
'',
true,
true,
'SVG with data:text/html link target (firefox only)'
),
array(
' ]> ',
true,
true,
'SVG with encoded script tag in internal entity (reported by Beyond Security)'
),
array(
' ]> ',
false,
false,
'SVG with external entity'
),
// Test good, but strange files that we want to allow
array(
'',
true,
false,
'SVG with link to a remote site'
),
array(
'',
true,
false,
'SVG with local urls, including filter: in style'
),
);
}
}
class UploadTestHandler extends UploadBase {
public function initializeFromRequest( &$request ) {
}
public function testTitleValidation( $name ) {
$this->mTitle = false;
$this->mDesiredDestName = $name;
$this->mTitleError = UploadBase::OK;
$this->getTitle();
return $this->mTitleError;
}
/**
* Almost the same as UploadBase::detectScriptInSvg, except it's
* public, works on an xml string instead of filename, and returns
* the result instead of interpreting them.
*/
public function checkSvgString( $svg ) {
$check = new XmlTypeCheck(
$svg,
array( $this, 'checkSvgScriptCallback' ),
false,
array( 'processing_instruction_handler' => 'UploadBase::checkSvgPICallback' )
);
return array( $check->wellFormed, $check->filterMatch );
}
}