Fix input regression affecting HTMLForms that use VForm
[lhc/web/wiklou.git] / includes / User.php
index 588826c..e25bc1f 100644 (file)
  * @file
  */
 
-/**
- * Int Number of characters in user_token field.
- * @ingroup Constants
- */
-define( 'USER_TOKEN_LENGTH', 32 );
-
-/**
- * Int Serialized record version.
- * @ingroup Constants
- */
-define( 'MW_USER_VERSION', 10 );
-
 /**
  * String Some punctuation to prevent editing from broken text-mangling proxies.
  * @ingroup Constants
@@ -50,13 +38,21 @@ define( 'EDIT_TOKEN_SUFFIX', '+\\' );
  */
 class User implements IDBAccessObject {
        /**
-        * Global constants made accessible as class constants so that autoloader
+        * @const int Number of characters in user_token field.
+        */
+       const TOKEN_LENGTH = 32;
+
+       /**
+        * Global constant made accessible as class constants so that autoloader
         * magic can be used.
         */
-       const USER_TOKEN_LENGTH = USER_TOKEN_LENGTH;
-       const MW_USER_VERSION = MW_USER_VERSION;
        const EDIT_TOKEN_SUFFIX = EDIT_TOKEN_SUFFIX;
 
+       /**
+        * @const int Serialized record version.
+        */
+       const VERSION = 10;
+
        /**
         * Maximum items in $mWatchedItems
         */
@@ -185,8 +181,16 @@ class User implements IDBAccessObject {
 
        public $mRealName;
 
+       /**
+        * @todo Make this actually private
+        * @private
+        */
        public $mPassword;
 
+       /**
+        * @todo Make this actually private
+        * @private
+        */
        public $mNewpassword;
 
        public $mNewpassTime;
@@ -353,21 +357,14 @@ class User implements IDBAccessObject {
         * @return bool False if the ID does not exist, true otherwise
         */
        public function loadFromId() {
-               global $wgMemc;
                if ( $this->mId == 0 ) {
                        $this->loadDefaults();
                        return false;
                }
 
                // Try cache
-               $key = wfMemcKey( 'user', 'id', $this->mId );
-               $data = $wgMemc->get( $key );
-               if ( !is_array( $data ) || $data['mVersion'] != MW_USER_VERSION ) {
-                       // Object is expired, load from DB
-                       $data = false;
-               }
-
-               if ( !$data ) {
+               $cache = $this->loadFromCache();
+               if ( !$cache ) {
                        wfDebug( "User: cache miss for user {$this->mId}\n" );
                        // Load from DB
                        if ( !$this->loadFromDatabase() ) {
@@ -375,12 +372,6 @@ class User implements IDBAccessObject {
                                return false;
                        }
                        $this->saveToCache();
-               } else {
-                       wfDebug( "User: got user {$this->mId} from cache\n" );
-                       // Restore from cache
-                       foreach ( self::$mCacheVars as $name ) {
-                               $this->$name = $data[$name];
-                       }
                }
 
                $this->mLoadedItems = true;
@@ -388,6 +379,37 @@ class User implements IDBAccessObject {
                return true;
        }
 
+       /**
+        * Load user data from shared cache, given mId has already been set.
+        *
+        * @return bool false if the ID does not exist or data is invalid, true otherwise
+        * @since 1.25
+        */
+       public function loadFromCache() {
+               global $wgMemc;
+
+               if ( $this->mId == 0 ) {
+                       $this->loadDefaults();
+                       return false;
+               }
+
+               $key = wfMemcKey( 'user', 'id', $this->mId );
+               $data = $wgMemc->get( $key );
+               if ( !is_array( $data ) || $data['mVersion'] < self::VERSION ) {
+                       // Object is expired
+                       return false;
+               }
+
+               wfDebug( "User: got user {$this->mId} from cache\n" );
+
+               // Restore from cache
+               foreach ( self::$mCacheVars as $name ) {
+                       $this->$name = $data[$name];
+               }
+
+               return true;
+       }
+
        /**
         * Save user data to the shared cache
         */
@@ -403,7 +425,7 @@ class User implements IDBAccessObject {
                foreach ( self::$mCacheVars as $name ) {
                        $data[$name] = $this->$name;
                }
-               $data['mVersion'] = MW_USER_VERSION;
+               $data['mVersion'] = self::VERSION;
                $key = wfMemcKey( 'user', 'id', $this->mId );
                global $wgMemc;
                $wgMemc->set( $key, $data );
@@ -825,7 +847,7 @@ class User implements IDBAccessObject {
         * @param int $ts Optional timestamp to convert, default 0 for the current time
         */
        public function expirePassword( $ts = 0 ) {
-               $this->load();
+               $this->loadPasswords();
                $timestamp = wfTimestamp( TS_MW, $ts );
                $this->mPasswordExpires = $timestamp;
                $this->saveSettings();
@@ -911,8 +933,9 @@ class User implements IDBAccessObject {
                        return false;
                }
 
-               // Clean up name according to title rules
-               $t = ( $validate === 'valid' ) ?
+               // Clean up name according to title rules,
+               // but only when validation is requested (bug 12654)
+               $t = ( $validate !== false ) ?
                        Title::newFromText( $name ) : Title::makeTitle( NS_USER, $name );
                // Check for invalid titles
                if ( is_null( $t ) ) {
@@ -1880,7 +1903,6 @@ class User implements IDBAccessObject {
                        return $this->mLocked;
                }
                global $wgAuth;
-               StubObject::unstub( $wgAuth );
                $authUser = $wgAuth->getUserInstance( $this );
                $this->mLocked = (bool)$authUser->isLocked();
                return $this->mLocked;
@@ -1898,7 +1920,6 @@ class User implements IDBAccessObject {
                $this->getBlockedStatus();
                if ( !$this->mHideName ) {
                        global $wgAuth;
-                       StubObject::unstub( $wgAuth );
                        $authUser = $wgAuth->getUserInstance( $this );
                        $this->mHideName = (bool)$authUser->isHidden();
                }
@@ -2250,6 +2271,26 @@ class User implements IDBAccessObject {
                return $this->mTouched;
        }
 
+       /**
+        * @return Password
+        * @since 1.24
+        */
+       public function getPassword() {
+               $this->loadPasswords();
+
+               return $this->mPassword;
+       }
+
+       /**
+        * @return Password
+        * @since 1.24
+        */
+       public function getTemporaryPassword() {
+               $this->loadPasswords();
+
+               return $this->mNewpassword;
+       }
+
        /**
         * Set the password and reset the random token.
         * Calls through to authentication plugin if necessary;
@@ -2269,6 +2310,8 @@ class User implements IDBAccessObject {
        public function setPassword( $str ) {
                global $wgAuth;
 
+               $this->loadPasswords();
+
                if ( $str !== null ) {
                        if ( !$wgAuth->allowPasswordChange() ) {
                                throw new PasswordError( wfMessage( 'password-change-forbidden' )->text() );
@@ -2308,11 +2351,7 @@ class User implements IDBAccessObject {
                $this->setToken();
 
                $passwordFactory = self::getPasswordFactory();
-               if ( $str === null ) {
-                       $this->mPassword = $passwordFactory->newFromCiphertext( null );
-               } else {
-                       $this->mPassword = $passwordFactory->newFromPlaintext( $str );
-               }
+               $this->mPassword = $passwordFactory->newFromPlaintext( $str );
 
                $this->mNewpassword = $passwordFactory->newFromCiphertext( null );
                $this->mNewpassTime = null;
@@ -2341,7 +2380,7 @@ class User implements IDBAccessObject {
        public function setToken( $token = false ) {
                $this->load();
                if ( !$token ) {
-                       $this->mToken = MWCryptRand::generateHex( USER_TOKEN_LENGTH );
+                       $this->mToken = MWCryptRand::generateHex( self::TOKEN_LENGTH );
                } else {
                        $this->mToken = $token;
                }
@@ -2355,16 +2394,13 @@ class User implements IDBAccessObject {
         * @param bool $throttle If true, reset the throttle timestamp to the present
         */
        public function setNewpassword( $str, $throttle = true ) {
-               $this->load();
+               $this->loadPasswords();
 
+               $this->mNewpassword = self::getPasswordFactory()->newFromPlaintext( $str );
                if ( $str === null ) {
-                       $this->mNewpassword = '';
                        $this->mNewpassTime = null;
-               } else {
-                       $this->mNewpassword = self::getPasswordFactory()->newFromPlaintext( $str );
-                       if ( $throttle ) {
-                               $this->mNewpassTime = wfTimestampNow();
-                       }
+               } elseif ( $throttle ) {
+                       $this->mNewpassTime = wfTimestampNow();
                }
        }
 
@@ -2706,7 +2742,7 @@ class User implements IDBAccessObject {
 
                                foreach ( $columns as $column ) {
                                        foreach ( $rows as $row ) {
-                                               $checkmatrixOptions["$prefix-$column-$row"] = true;
+                                               $checkmatrixOptions["$prefix$column-$row"] = true;
                                        }
                                }
 
@@ -3059,10 +3095,8 @@ class User implements IDBAccessObject {
        /**
         * Check if user is allowed to access a feature / make an action
         *
-        * @internal param \String $varargs permissions to test
+        * @param string $permissions,... Permissions to test
         * @return bool True if user is allowed to perform *any* of the given actions
-        *
-        * @return bool
         */
        public function isAllowedAny( /*...*/ ) {
                $permissions = func_get_args();
@@ -3076,7 +3110,7 @@ class User implements IDBAccessObject {
 
        /**
         *
-        * @internal param $varargs string
+        * @param string $permissions,... Permissions to test
         * @return bool True if the user is allowed to perform *all* of the given actions
         */
        public function isAllowedAll( /*...*/ ) {
@@ -3763,12 +3797,14 @@ class User implements IDBAccessObject {
         */
        public function checkPassword( $password ) {
                global $wgAuth, $wgLegacyEncoding;
+
+               $section = new ProfileSection( __METHOD__ );
+
                $this->loadPasswords();
 
                // Certain authentication plugins do NOT want to save
                // domain passwords in a mysql database, so we should
                // check this (in case $wgAuth->strict() is false).
-
                if ( $wgAuth->authenticate( $this->getName(), $password ) ) {
                        return true;
                } elseif ( $wgAuth->strict() ) {
@@ -3856,7 +3892,7 @@ class User implements IDBAccessObject {
                }
 
                if ( $this->isAnon() ) {
-                       return EDIT_TOKEN_SUFFIX;
+                       return self::EDIT_TOKEN_SUFFIX;
                } else {
                        $token = $request->getSessionData( 'wsEditToken' );
                        if ( $token === null ) {
@@ -3866,7 +3902,7 @@ class User implements IDBAccessObject {
                        if ( is_array( $salt ) ) {
                                $salt = implode( '|', $salt );
                        }
-                       return md5( $token . $salt ) . EDIT_TOKEN_SUFFIX;
+                       return md5( $token . $salt ) . self::EDIT_TOKEN_SUFFIX;
                }
        }
 
@@ -3967,10 +4003,10 @@ class User implements IDBAccessObject {
                        $sender = new MailAddress( $wgPasswordSender,
                                wfMessage( 'emailsender' )->inContentLanguage()->text() );
                } else {
-                       $sender = new MailAddress( $from );
+                       $sender = MailAddress::newFromUser( $from );
                }
 
-               $to = new MailAddress( $this );
+               $to = MailAddress::newFromUser( $this );
                return UserMailer::send( $to, $sender, $subject, $body, $replyto );
        }