Merge "Add a 'revdelete-selected-file' message on Special:RevisionDelete"
[lhc/web/wiklou.git] / includes / upload / UploadBase.php
index 67bffc3..d4be08c 100644 (file)
@@ -42,7 +42,7 @@ abstract class UploadBase {
        protected $mFilteredName, $mFinalExtension;
        protected $mLocalFile, $mFileSize, $mFileProps;
        protected $mBlackListedExtensions;
-       protected $mJavaDetected;
+       protected $mJavaDetected, $mSVGNSError;
 
        protected static $safeXmlEncodings = array( 'UTF-8', 'ISO-8859-1', 'ISO-8859-2', 'UTF-16', 'UTF-32' );
 
@@ -786,7 +786,7 @@ abstract class UploadBase {
                        return $this->mTitle;
                } elseif ( $blackListedExtensions ||
                                ( $wgCheckFileExtensions && $wgStrictFileExtensions &&
-                                       !$this->checkFileExtensionList( $ext, $wgFileExtensions ) ) ) {
+                                       !$this->checkFileExtension( $this->mFinalExtension, $wgFileExtensions ) ) ) {
                        $this->mBlackListedExtensions = $blackListedExtensions;
                        $this->mTitleError = self::FILETYPE_BADTYPE;
                        $this->mTitle = null;
@@ -1168,6 +1168,7 @@ abstract class UploadBase {
         * @return mixed false of the file is verified (does not contain scripts), array otherwise.
         */
        protected function detectScriptInSvg( $filename ) {
+               $this->mSVGNSError = false;
                $check = new XmlTypeCheck(
                        $filename,
                        array( $this, 'checkSvgScriptCallback' ),
@@ -1178,6 +1179,9 @@ abstract class UploadBase {
                        // Invalid xml (bug 58553)
                        return array( 'uploadinvalidxml' );
                } elseif ( $check->filterMatch ) {
+                       if ( $this->mSVGNSError ) {
+                               return array( 'uploadscriptednamespace', $this->mSVGNSError );
+                       }
                        return array( 'uploadscripted' );
                }
                return false;
@@ -1191,7 +1195,7 @@ abstract class UploadBase {
         */
        public static function checkSvgPICallback( $target, $data ) {
                // Don't allow external stylesheets (bug 57550)
-               if ( preg_match( '/xml-stylesheet/i', $target) ) {
+               if ( preg_match( '/xml-stylesheet/i', $target ) ) {
                        return true;
                }
                return false;
@@ -1204,7 +1208,51 @@ abstract class UploadBase {
         * @return bool
         */
        public function checkSvgScriptCallback( $element, $attribs ) {
-               $strippedElement = $this->stripXmlNamespace( $element );
+               list( $namespace, $strippedElement ) = $this->splitXmlNamespace( $element );
+
+               static $validNamespaces = array(
+                       '',
+                       'adobe:ns:meta/',
+                       'http://creativecommons.org/ns#',
+                       'http://inkscape.sourceforge.net/dtd/sodipodi-0.dtd',
+                       'http://ns.adobe.com/adobeillustrator/10.0/',
+                       'http://ns.adobe.com/adobesvgviewerextensions/3.0/',
+                       'http://ns.adobe.com/extensibility/1.0/',
+                       'http://ns.adobe.com/flows/1.0/',
+                       'http://ns.adobe.com/illustrator/1.0/',
+                       'http://ns.adobe.com/imagereplacement/1.0/',
+                       'http://ns.adobe.com/pdf/1.3/',
+                       'http://ns.adobe.com/photoshop/1.0/',
+                       'http://ns.adobe.com/saveforweb/1.0/',
+                       'http://ns.adobe.com/variables/1.0/',
+                       'http://ns.adobe.com/xap/1.0/',
+                       'http://ns.adobe.com/xap/1.0/g/',
+                       'http://ns.adobe.com/xap/1.0/g/img/',
+                       'http://ns.adobe.com/xap/1.0/mm/',
+                       'http://ns.adobe.com/xap/1.0/rights/',
+                       'http://ns.adobe.com/xap/1.0/stype/dimensions#',
+                       'http://ns.adobe.com/xap/1.0/stype/font#',
+                       'http://ns.adobe.com/xap/1.0/stype/manifestitem#',
+                       'http://ns.adobe.com/xap/1.0/stype/resourceevent#',
+                       'http://ns.adobe.com/xap/1.0/stype/resourceref#',
+                       'http://ns.adobe.com/xap/1.0/t/pg/',
+                       'http://purl.org/dc/elements/1.1/',
+                       'http://purl.org/dc/elements/1.1',
+                       'http://schemas.microsoft.com/visio/2003/svgextensions/',
+                       'http://sodipodi.sourceforge.net/dtd/sodipodi-0.dtd',
+                       'http://web.resource.org/cc/',
+                       'http://www.freesoftware.fsf.org/bkchem/cdml',
+                       'http://www.inkscape.org/namespaces/inkscape',
+                       'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
+                       'http://www.w3.org/2000/svg',
+               );
+
+               if ( !in_array( $namespace, $validNamespaces ) ) {
+                       wfDebug( __METHOD__ . ": Non-svg namespace '$namespace' in uploaded file.\n" );
+                       // @TODO return a status object to a closure in XmlTypeCheck, for MW1.21+
+                       $this->mSVGNSError = $namespace;
+                       return true;
+               }
 
                /*
                 * check for elements that can contain javascript
@@ -1226,6 +1274,12 @@ abstract class UploadBase {
                        return true;
                }
 
+               # Block iframes, in case they pass the namespace check
+               if ( $strippedElement == 'iframe' ) {
+                       wfDebug( __METHOD__ . ": iframe in uploaded file.\n" );
+                       return true;
+               }
+
                foreach ( $attribs as $attrib => $value ) {
                        $stripped = $this->stripXmlNamespace( $attrib );
                        $value = strtolower( $value );
@@ -1299,6 +1353,19 @@ abstract class UploadBase {
                return false; //No scripts detected
        }
 
+       /**
+        * Divide the element name passed by the xml parser to the callback into URI and prifix.
+        * @param $name string
+        * @return array containing the namespace URI and prefix
+        */
+       private static function splitXmlNamespace( $element ) {
+               // 'http://www.w3.org/2000/svg:script' -> array( 'http://www.w3.org/2000/svg', 'script' )
+               $parts = explode( ':', strtolower( $element ) );
+               $name = array_pop( $parts );
+               $ns = implode( ':', $parts );
+               return array( $ns, $name );
+       }
+
        /**
         * @param $name string
         * @return string