SECURITY: Throttle uploads
[lhc/web/wiklou.git] / includes / upload / UploadBase.php
index b06b91e..f600e32 100644 (file)
@@ -61,9 +61,6 @@ abstract class UploadBase {
        const FILETYPE_MISSING = 8;
        const FILETYPE_BADTYPE = 9;
        const VERIFICATION_ERROR = 10;
-
-       # HOOK_ABORTED is the new name of UPLOAD_VERIFICATION_ERROR
-       const UPLOAD_VERIFICATION_ERROR = 11;
        const HOOK_ABORTED = 11;
        const FILE_TOO_LARGE = 12;
        const WINDOWS_NONASCII_FILENAME = 13;
@@ -128,6 +125,16 @@ abstract class UploadBase {
                return true;
        }
 
+       /**
+        * Returns true if the user has surpassed the upload rate limit, false otherwise.
+        *
+        * @param User $user
+        * @return bool
+        */
+       public static function isThrottled( $user ) {
+               return $user->pingLimiter( 'upload' );
+       }
+
        // Upload handlers. Should probably just be a global.
        private static $uploadHandlers = array( 'Stash', 'File', 'Url' );
 
@@ -646,6 +653,10 @@ abstract class UploadBase {
                        $warnings['exists'] = $exists;
                }
 
+               if ( $localFile->wasDeleted() && !$localFile->exists() ) {
+                       $warnings['was-deleted'] = $filename;
+               }
+
                // Check dupes against existing files
                $hash = $this->getTempFileSha1Base36();
                $dupes = RepoGroup::singleton()->findBySha1( $hash );
@@ -1118,10 +1129,10 @@ abstract class UploadBase {
                        '<a href',
                        '<body',
                        '<head',
-                       '<html', #also in safari
+                       '<html', # also in safari
                        '<img',
                        '<pre',
-                       '<script', #also in safari
+                       '<script', # also in safari
                        '<table'
                );
 
@@ -1402,7 +1413,10 @@ abstract class UploadBase {
                        # image/svg, text/xml, application/xml, and text/html, which can contain scripts
                        if ( $stripped == 'href' && strncasecmp( 'data:', $value, 5 ) === 0 ) {
                                // rfc2397 parameters. This is only slightly slower than (;[\w;]+)*.
+                               // @codingStandardsIgnoreStart Generic.Files.LineLength
                                $parameters = '(?>;[a-zA-Z0-9\!#$&\'*+.^_`{|}~-]+=(?>[a-zA-Z0-9\!#$&\'*+.^_`{|}~-]+|"(?>[\0-\x0c\x0e-\x21\x23-\x5b\x5d-\x7f]+|\\\\[\0-\x7f])*"))*(?:;base64)?';
+                               // @codingStandardsIgnoreEnd
+
                                if ( !preg_match( "!^data:\s*image/(gif|jpeg|jpg|png)$parameters,!i", $value ) ) {
                                        wfDebug( __METHOD__ . ": Found href to unwhitelisted data: uri "
                                                . "\"<$strippedElement '$attrib'='$value'...\" in uploaded file.\n" );
@@ -1492,7 +1506,7 @@ abstract class UploadBase {
                        }
                }
 
-               return false; //No scripts detected
+               return false; // No scripts detected
        }
 
        /**
@@ -1655,7 +1669,7 @@ abstract class UploadBase {
                        $output = trim( $output );
 
                        if ( !$output ) {
-                               $output = true; #if there's no output, return true
+                               $output = true; # if there's no output, return true
                        } elseif ( $msgPattern ) {
                                $groups = array();
                                if ( preg_match( $msgPattern, $output, $groups ) ) {
@@ -1706,24 +1720,21 @@ abstract class UploadBase {
         * Check if a user is the last uploader
         *
         * @param User $user
-        * @param string $img Image name
+        * @param File $img
         * @return bool
         */
-       public static function userCanReUpload( User $user, $img ) {
+       public static function userCanReUpload( User $user, File $img ) {
                if ( $user->isAllowed( 'reupload' ) ) {
                        return true; // non-conditional
-               }
-               if ( !$user->isAllowed( 'reupload-own' ) ) {
+               } elseif ( !$user->isAllowed( 'reupload-own' ) ) {
                        return false;
                }
-               if ( is_string( $img ) ) {
-                       $img = wfLocalFile( $img );
-               }
+
                if ( !( $img instanceof LocalFile ) ) {
                        return false;
                }
 
-               $img->load( File::READ_LATEST );
+               $img->load();
 
                return $user->getId() == $img->getUser( 'id' );
        }
@@ -1748,10 +1759,6 @@ abstract class UploadBase {
                        return array( 'warning' => 'page-exists', 'file' => $file );
                }
 
-               if ( $file->wasDeleted() && !$file->exists() ) {
-                       return array( 'warning' => 'was-deleted', 'file' => $file );
-               }
-
                if ( strpos( $file->getName(), '.' ) == false ) {
                        $partname = $file->getName();
                        $extension = '';
@@ -1766,7 +1773,7 @@ abstract class UploadBase {
                        // We're not using the normalized form of the extension.
                        // Normal form is lowercase, using most common of alternate
                        // extensions (eg 'jpg' rather than 'JPEG').
-                       //
+
                        // Check for another file using the normalized form...
                        $nt_lc = Title::makeTitle( NS_FILE, "{$partname}.{$normalizedExtension}" );
                        $file_lc = wfLocalFile( $nt_lc );