]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blobdiff - includes/User.php
MediaWiki 1.17.4
[autoinstalls/mediawiki.git] / includes / User.php
index 5760003bbc85b3b3bb3c7ef7f8360c3337c7066d..c0de2023b8f9b4d6ff8c5bb8fdbbe848e545d448 100644 (file)
@@ -99,7 +99,6 @@ class User {
                'deletedhistory',
                'deletedtext',
                'deleterevision',
-               'disableaccount',
                'edit',
                'editinterface',
                'editusercssjs', #deprecated
@@ -787,23 +786,20 @@ class User {
        }
 
        /**
-        * Return a random password. Sourced from mt_rand, so it's not particularly secure.
-        * @todo hash random numbers to improve security, like generateToken()
+        * Return a random password.
         *
         * @return \string New random password
         */
        static function randomPassword() {
-               global $wgMinimalPasswordLength;
-               $pwchars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz';
-               $l = strlen( $pwchars ) - 1;
-
-               $pwlength = max( 7, $wgMinimalPasswordLength );
-               $digit = mt_rand( 0, $pwlength - 1 );
-               $np = '';
-               for ( $i = 0; $i < $pwlength; $i++ ) {
-                       $np .= $i == $digit ? chr( mt_rand( 48, 57 ) ) : $pwchars{ mt_rand( 0, $l ) };
-               }
-               return $np;
+               global $wgMinimalPasswordLength;
+               // Decide the final password length based on our min password length, stopping at a minimum of 10 chars
+               $length = max( 10, $wgMinimalPasswordLength );
+               // Multiply by 1.25 to get the number of hex characters we need
+               $length = $length * 1.25;
+               // Generate random hex chars
+               $hex = MWCryptRand::generateHex( $length );
+               // Convert from base 16 to base 32 to get a proper password like string
+               return wfBaseConvert( $hex, 16, 32 );
        }
 
        /**
@@ -833,7 +829,7 @@ class User {
                        $this->mTouched = '0'; # Allow any pages to be cached
                }
 
-               $this->setToken(); # Random
+               $this->mToken = null; // Don't run cryptographic functions till we need a token
                $this->mEmailAuthenticated = null;
                $this->mEmailToken = '';
                $this->mEmailTokenExpires = null;
@@ -920,11 +916,11 @@ class User {
                        return false;
                }
 
-               if ( isset( $_SESSION['wsToken'] ) ) {
-                       $passwordCorrect = $proposedUser->getToken() === $_SESSION['wsToken'];
+               if ( isset( $_SESSION['wsToken'] ) && $_SESSION['wsToken'] ) {
+                       $passwordCorrect = $proposedUser->getToken( false ) === $_SESSION['wsToken'];
                        $from = 'session';
-               } else if ( $wgRequest->getCookie( 'Token' ) !== null ) {
-                       $passwordCorrect = $proposedUser->getToken() === $wgRequest->getCookie( 'Token' );
+               } elseif ( $wgRequest->getCookie( 'Token' ) ) {
+                       $passwordCorrect = $proposedUser->getToken( false ) === $wgRequest->getCookie( 'Token' );
                        $from = 'cookie';
                } else {
                        # No session or persistent login cookie
@@ -1013,6 +1009,9 @@ class User {
                $this->decodeOptions( $row->user_options );
                $this->mTouched = wfTimestamp(TS_MW,$row->user_touched);
                $this->mToken = $row->user_token;
+               if ( $this->mToken == '' ) {
+                       $this->mToken = null;
+               }
                $this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $row->user_email_authenticated );
                $this->mEmailToken = $row->user_email_token;
                $this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $row->user_email_token_expires );
@@ -1842,10 +1841,14 @@ class User {
 
        /**
         * Get the user's current token.
+        * @param $forceCreation Force the generation of a new token if the user doesn't have one (default=true for backwards compatibility)
         * @return \string Token
         */
-       function getToken() {
+       function getToken( $forceCreation = true ) {
                $this->load();
+               if ( !$this->mToken && $forceCreation ) {
+                       $this->setToken();
+               }
                return $this->mToken;
        }
 
@@ -1860,14 +1863,7 @@ class User {
                global $wgSecretKey, $wgProxyKey;
                $this->load();
                if ( !$token ) {
-                       if ( $wgSecretKey ) {
-                               $key = $wgSecretKey;
-                       } elseif ( $wgProxyKey ) {
-                               $key = $wgProxyKey;
-                       } else {
-                               $key = microtime();
-                       }
-                       $this->mToken = md5( $key . mt_rand( 0, 0x7fffffff ) . wfWikiID() . $this->mId );
+                       $this->mToken = MWCryptRand::generateHex( USER_TOKEN_LENGTH );
                } else {
                        $this->mToken = $token;
                }
@@ -2478,6 +2474,14 @@ class User {
        function setCookies() {
                $this->load();
                if ( 0 == $this->mId ) return;
+               if ( !$this->mToken ) {
+                       // When token is empty or NULL generate a new one and then save it to the database
+                       // This allows a wiki to re-secure itself after a leak of it's user table or $wgSecretKey
+                       // Simply by setting every cell in the user_token column to NULL and letting them be
+                       // regenerated as users log back into the wiki.
+                       $this->setToken();
+                       $this->saveSettings();
+               }
                $session = array(
                        'wsUserID' => $this->mId,
                        'wsToken' => $this->mToken,
@@ -2556,7 +2560,7 @@ class User {
                                'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
                                'user_options' => '',
                                'user_touched' => $dbw->timestamp( $this->mTouched ),
-                               'user_token' => $this->mToken,
+                               'user_token' => strval( $this->mToken ),
                                'user_email_token' => $this->mEmailToken,
                                'user_email_token_expires' => $dbw->timestampOrNull( $this->mEmailTokenExpires ),
                        ), array( /* WHERE */
@@ -2622,7 +2626,7 @@ class User {
                        'user_email_authenticated' => $dbw->timestampOrNull( $user->mEmailAuthenticated ),
                        'user_real_name' => $user->mRealName,
                        'user_options' => '',
-                       'user_token' => $user->mToken,
+                       'user_token' => strval( $user->mToken ),
                        'user_registration' => $dbw->timestamp( $user->mRegistration ),
                        'user_editcount' => 0,
                );
@@ -2656,7 +2660,7 @@ class User {
                                'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
                                'user_real_name' => $this->mRealName,
                                'user_options' => '',
-                               'user_token' => $this->mToken,
+                               'user_token' => strval( $this->mToken ),
                                'user_registration' => $dbw->timestamp( $this->mRegistration ),
                                'user_editcount' => 0,
                        ), __METHOD__
@@ -2882,7 +2886,7 @@ class User {
                        return EDIT_TOKEN_SUFFIX;
                } else {
                        if( !isset( $_SESSION['wsEditToken'] ) ) {
-                               $token = self::generateToken();
+                               $token = MWCryptRand::generateHex( 32 );
                                $_SESSION['wsEditToken'] = $token;
                        } else {
                                $token = $_SESSION['wsEditToken'];
@@ -2901,8 +2905,7 @@ class User {
         * @return \string The new random token
         */
        public static function generateToken( $salt = '' ) {
-               $token = dechex( mt_rand() ) . dechex( mt_rand() );
-               return md5( $token . $salt );
+               return MWCryptRand::generateHex( 32 );
        }
 
        /**
@@ -3007,7 +3010,7 @@ class User {
                $now = time();
                $expires = $now + 7 * 24 * 60 * 60;
                $expiration = wfTimestamp( TS_MW, $expires );
-               $token = self::generateToken( $this->mId . $this->mEmail . $expires );
+               $token = MWCryptRand::generateHex( 32 );
                $hash = md5( $token );
                $this->load();
                $this->mEmailToken = $hash;
@@ -3561,7 +3564,7 @@ class User {
 
                if( $wgPasswordSalt ) {
                        if ( $salt === false ) {
-                               $salt = substr( wfGenerateToken(), 0, 8 );
+                               $salt = MWCryptRand::generateHex( 8 );
                        }
                        return ':B:' . $salt . ':' . md5( $salt . '-' . md5( $password ) );
                } else {
@@ -3592,7 +3595,7 @@ class User {
                } elseif ( $type == ':B:' ) {
                        # Salted
                        list( $salt, $realHash ) = explode( ':', substr( $hash, 3 ), 2 );
-                       return md5( $salt.'-'.md5( $password ) ) == $realHash;
+                       return md5( $salt.'-'.md5( $password ) ) === $realHash;
                } else {
                        # Old-style
                        return self::oldCrypt( $password, $userId ) === $hash;