diff options
Diffstat (limited to 'includes/specials')
-rw-r--r-- | includes/specials/SpecialImport.php | 30 | ||||
-rw-r--r-- | includes/specials/SpecialUndelete.php | 35 | ||||
-rw-r--r-- | includes/specials/SpecialUpload.php | 65 |
3 files changed, 110 insertions, 20 deletions
diff --git a/includes/specials/SpecialImport.php b/includes/specials/SpecialImport.php index 4c37f1f9..1623245d 100644 --- a/includes/specials/SpecialImport.php +++ b/includes/specials/SpecialImport.php @@ -43,26 +43,30 @@ function wfSpecialImport( $page = '' ) { if( $wgRequest->wasPosted() && $wgRequest->getVal( 'action' ) == 'submit') { $isUpload = false; $namespace = $wgRequest->getIntOrNull( 'namespace' ); + $sourceName = $wgRequest->getVal( "source" ); - switch( $wgRequest->getVal( "source" ) ) { - case "upload": + if ( !$wgUser->matchEditToken( $wgRequest->getVal( 'editToken' ) ) ) { + $source = new WikiErrorMsg( 'import-token-mismatch' ); + } elseif ( $sourceName == 'upload' ) { $isUpload = true; if( $wgUser->isAllowed( 'importupload' ) ) { $source = ImportStreamSource::newFromUpload( "xmlimport" ); } else { return $wgOut->permissionRequired( 'importupload' ); } - break; - case "interwiki": + } elseif ( $sourceName == "interwiki" ) { $interwiki = $wgRequest->getVal( 'interwiki' ); - $history = $wgRequest->getCheck( 'interwikiHistory' ); - $frompage = $wgRequest->getText( "frompage" ); - $source = ImportStreamSource::newFromInterwiki( - $interwiki, - $frompage, - $history ); - break; - default: + if ( !in_array( $interwiki, $wgImportSources ) ) { + $source = new WikiErrorMsg( "import-invalid-interwiki" ); + } else { + $history = $wgRequest->getCheck( 'interwikiHistory' ); + $frompage = $wgRequest->getText( "frompage" ); + $source = ImportStreamSource::newFromInterwiki( + $interwiki, + $frompage, + $history ); + } + } else { $source = new WikiErrorMsg( "importunknownsource" ); } @@ -106,6 +110,7 @@ function wfSpecialImport( $page = '' ) { Xml::hidden( 'action', 'submit' ) . Xml::hidden( 'source', 'upload' ) . Xml::input( 'xmlimport', 50, '', array( 'type' => 'file' ) ) . ' ' . + Xml::hidden( 'editToken', $wgUser->editToken() ) . Xml::submitButton( wfMsg( 'uploadbtn' ) ) . Xml::closeElement( 'form' ) . Xml::closeElement( 'fieldset' ) @@ -124,6 +129,7 @@ function wfSpecialImport( $page = '' ) { wfMsgExt( 'import-interwiki-text', array( 'parse' ) ) . Xml::hidden( 'action', 'submit' ) . Xml::hidden( 'source', 'interwiki' ) . + Xml::hidden( 'editToken', $wgUser->editToken() ) . Xml::openElement( 'table', array( 'id' => 'mw-import-table' ) ) . "<tr> <td>" . diff --git a/includes/specials/SpecialUndelete.php b/includes/specials/SpecialUndelete.php index fbbf89d6..d862ebb3 100644 --- a/includes/specials/SpecialUndelete.php +++ b/includes/specials/SpecialUndelete.php @@ -571,7 +571,7 @@ class PageArchive { */ class UndeleteForm { var $mAction, $mTarget, $mTimestamp, $mRestore, $mTargetObj; - var $mTargetTimestamp, $mAllowed, $mComment; + var $mTargetTimestamp, $mAllowed, $mComment, $mToken; function UndeleteForm( $request, $par = "" ) { global $wgUser; @@ -589,6 +589,7 @@ class UndeleteForm { $this->mDiff = $request->getCheck( 'diff' ); $this->mComment = $request->getText( 'wpComment' ); $this->mUnsuppress = $request->getVal( 'wpUnsuppress' ) && $wgUser->isAllowed( 'suppressrevision' ); + $this->mToken = $request->getVal( 'token' ); if( $par != "" ) { $this->mTarget = $par; @@ -655,6 +656,9 @@ class UndeleteForm { if( !$file->userCan( File::DELETED_FILE ) ) { $wgOut->permissionRequired( 'suppressrevision' ); return false; + } elseif ( !$wgUser->matchEditToken( $this->mToken, $this->mFile ) ) { + $this->showFileConfirmationForm( $this->mFile ); + return false; } else { return $this->showFile( $this->mFile ); } @@ -880,6 +884,29 @@ class UndeleteForm { } /** + * Show a form confirming whether a tokenless user really wants to see a file + */ + private function showFileConfirmationForm( $key ) { + global $wgOut, $wgUser, $wgLang; + $file = new ArchivedFile( $this->mTargetObj, '', $this->mFile ); + $wgOut->addWikiMsg( 'undelete-show-file-confirm', + $this->mTargetObj->getText(), + $wgLang->timeanddate( $file->getTimestamp() ) ); + $wgOut->addHTML( + Xml::openElement( 'form', array( + 'method' => 'POST', + 'action' => SpecialPage::getTitleFor( 'Undelete' )->getLocalUrl( + 'target=' . urlencode( $this->mTarget ) . + '&file=' . urlencode( $key ) . + '&token=' . urlencode( $wgUser->editToken( $key ) ) ) + ) + ) . + Xml::submitButton( wfMsg( 'undelete-show-file-submit' ) ) . + '</form>' + ); + } + + /** * Show a deleted file version requested by the visitor. */ private function showFile( $key ) { @@ -1191,13 +1218,15 @@ class UndeleteForm { * @return string */ function getFileLink( $file, $titleObj, $ts, $key, $sk ) { - global $wgLang; + global $wgLang, $wgUser; if( !$file->userCan(File::DELETED_FILE) ) { return '<span class="history-deleted">' . $wgLang->timeanddate( $ts, true ) . '</span>'; } else { $link = $sk->makeKnownLinkObj( $titleObj, $wgLang->timeanddate( $ts, true ), - "target=".$this->mTargetObj->getPrefixedUrl()."&file=$key" ); + "target=".$this->mTargetObj->getPrefixedUrl(). + "&file=$key" . + "&token=" . urlencode( $wgUser->editToken( $key ) ) ); if( $file->isDeleted(File::DELETED_FILE) ) $link = '<span class="history-deleted">' . $link . '</span>'; return $link; diff --git a/includes/specials/SpecialUpload.php b/includes/specials/SpecialUpload.php index 8fe2f52f..3a79e052 100644 --- a/includes/specials/SpecialUpload.php +++ b/includes/specials/SpecialUpload.php @@ -1326,11 +1326,11 @@ wgUploadAutoFill = {$autofill}; $magic = MimeMagic::singleton(); $mime = $magic->guessMimeType($tmpfile,false); + #check mime type, if desired global $wgVerifyMimeType; if ($wgVerifyMimeType) { - - wfDebug ( "\n\nmime: <$mime> extension: <$extension>\n\n"); + wfDebug ( "\n\nmime: <$mime> extension: <$extension>\n\n"); #check mime type against file extension if( !self::verifyExtension( $mime, $extension ) ) { return new WikiErrorMsg( 'uploadcorrupt' ); @@ -1338,9 +1338,22 @@ wgUploadAutoFill = {$autofill}; #check mime type blacklist global $wgMimeTypeBlacklist; - if( isset($wgMimeTypeBlacklist) && !is_null($wgMimeTypeBlacklist) - && $this->checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) { - return new WikiErrorMsg( 'filetype-badmime', htmlspecialchars( $mime ) ); + if( isset($wgMimeTypeBlacklist) && !is_null($wgMimeTypeBlacklist) ) { + if ( $this->checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) { + return new WikiErrorMsg( 'filetype-badmime', htmlspecialchars( $mime ) ); + } + + # Check IE type + $fp = fopen( $tmpfile, 'rb' ); + $chunk = fread( $fp, 256 ); + fclose( $fp ); + $extMime = $magic->guessTypesForExtension( $extension ); + $ieTypes = $magic->getIEMimeTypes( $tmpfile, $chunk, $extMime ); + foreach ( $ieTypes as $ieType ) { + if ( $this->checkFileExtension( $ieType, $wgMimeTypeBlacklist ) ) { + return new WikiErrorMsg( 'filetype-bad-ie-mime', $ieType ); + } + } } } @@ -1348,6 +1361,11 @@ wgUploadAutoFill = {$autofill}; if( $this->detectScript ( $tmpfile, $mime, $extension ) ) { return new WikiErrorMsg( 'uploadscripted' ); } + if( $extension == 'svg' || $mime == 'image/svg+xml' ) { + if( $this->detectScriptInSvg( $tmpfile ) ) { + return new WikiErrorMsg( 'uploadscripted' ); + } + } /** * Scan the uploaded file for viruses @@ -1399,6 +1417,7 @@ wgUploadAutoFill = {$autofill}; } } + /** * Heuristic for detecting files that *could* contain JavaScript instructions or * things that may look like HTML to a browser and are thus @@ -1459,6 +1478,7 @@ wgUploadAutoFill = {$autofill}; */ $tags = array( + '<a href', '<body', '<head', '<html', #also in safari @@ -1497,6 +1517,41 @@ wgUploadAutoFill = {$autofill}; return false; } + function detectScriptInSvg( $filename ) { + $check = new XmlTypeCheck( $filename, array( $this, 'checkSvgScriptCallback' ) ); + return $check->filterMatch; + } + + /** + * @todo Replace this with a whitelist filter! + */ + function checkSvgScriptCallback( $element, $attribs ) { + $stripped = $this->stripXmlNamespace( $element ); + + if( $stripped == 'script' ) { + wfDebug( __METHOD__ . ": Found script element '$element' in uploaded file.\n" ); + return true; + } + + foreach( $attribs as $attrib => $value ) { + $stripped = $this->stripXmlNamespace( $attrib ); + if( substr( $stripped, 0, 2 ) == 'on' ) { + wfDebug( __METHOD__ . ": Found script attribute '$attrib'='value' in uploaded file.\n" ); + return true; + } + if( $stripped == 'href' && strpos( strtolower( $value ), 'javascript:' ) !== false ) { + wfDebug( __METHOD__ . ": Found script href attribute '$attrib'='$value' in uploaded file.\n" ); + return true; + } + } + } + + private function stripXmlNamespace( $name ) { + // 'http://www.w3.org/2000/svg:script' -> 'script' + $parts = explode( ':', strtolower( $name ) ); + return array_pop( $parts ); + } + /** * Generic wrapper function for a virus scanner program. * This relies on the $wgAntivirus and $wgAntivirusSetup variables. |