Merge "Improved rate limit log to mention IP"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 13 May 2014 19:33:19 +0000 (19:33 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 13 May 2014 19:33:19 +0000 (19:33 +0000)
1  2 
includes/User.php

diff --combined includes/User.php
@@@ -76,7 -76,7 +76,7 @@@ class User 
         * corresponding database fields must call a cache-clearing function.
         * @showinitializer
         */
 -      static $mCacheVars = array(
 +      protected static $mCacheVars = array(
                // user table
                'mId',
                'mName',
         * "right-$right".
         * @showinitializer
         */
 -      static $mCoreRights = array(
 +      protected static $mCoreRights = array(
                'apihighlimits',
                'autoconfirmed',
                'autopatrol',
                'minoredit',
                'move',
                'movefile',
 +              'move-categorypages',
                'move-rootuserpages',
                'move-subpages',
                'nominornewtalk',
                'viewmywatchlist',
                'writeapi',
        );
 +
        /**
         * String Cached results of getAllRights()
         */
 -      static $mAllRights = false;
 +      protected static $mAllRights = false;
  
        /** @name Cache variables */
        //@{
 -      var $mId, $mName, $mRealName, $mPassword, $mNewpassword, $mNewpassTime,
 -              $mEmail, $mTouched, $mToken, $mEmailAuthenticated,
 -              $mEmailToken, $mEmailTokenExpires, $mRegistration, $mEditCount,
 -              $mGroups, $mOptionOverrides;
 +      public $mId;
 +
 +      public $mName;
 +
 +      public $mRealName;
 +
 +      public $mPassword;
 +
 +      public $mNewpassword;
 +
 +      public $mNewpassTime;
 +
 +      public $mEmail;
 +
 +      public $mTouched;
 +
 +      protected $mToken;
 +
 +      public $mEmailAuthenticated;
 +
 +      protected $mEmailToken;
 +
 +      protected $mEmailTokenExpires;
 +
 +      protected $mRegistration;
 +
 +      protected $mEditCount;
 +
 +      public $mGroups;
 +
 +      protected $mOptionOverrides;
  
        protected $mPasswordExpires;
        //@}
         * Bool Whether the cache variables have been loaded.
         */
        //@{
 -      var $mOptionsLoaded;
 +      public $mOptionsLoaded;
  
        /**
         * Array with already loaded items or true if all items have been loaded.
         */
 -      private $mLoadedItems = array();
 +      protected $mLoadedItems = array();
        //@}
  
        /**
         *
         * Use the User::newFrom*() family of functions to set this.
         */
 -      var $mFrom;
 +      public $mFrom;
  
        /**
         * Lazy-initialized variables, invalidated with clearInstanceCache
         */
 -      var $mNewtalk, $mDatePreference, $mBlockedby, $mHash, $mRights,
 -              $mBlockreason, $mEffectiveGroups, $mImplicitGroups, $mFormerGroups, $mBlockedGlobally,
 -              $mLocked, $mHideName, $mOptions;
 +      protected $mNewtalk;
 +
 +      protected $mDatePreference;
 +
 +      public $mBlockedby;
 +
 +      protected $mHash;
 +
 +      public $mRights;
 +
 +      protected $mBlockreason;
 +
 +      protected $mEffectiveGroups;
 +
 +      protected $mImplicitGroups;
 +
 +      protected $mFormerGroups;
 +
 +      protected $mBlockedGlobally;
 +
 +      protected $mLocked;
 +
 +      public $mHideName;
 +
 +      public $mOptions;
  
        /**
         * @var WebRequest
         */
        private $mRequest;
  
 -      /**
 -       * @var Block
 -       */
 -      var $mBlock;
 +      /** @var Block */
 +      public $mBlock;
  
 -      /**
 -       * @var bool
 -       */
 -      var $mAllowUsertalk;
 +      /** @var bool */
 +      protected $mAllowUsertalk;
  
 -      /**
 -       * @var Block
 -       */
 +      /** @var Block */
        private $mBlockedFromCreateAccount = false;
  
 -      /**
 -       * @var array
 -       */
 +      /** @var array */
        private $mWatchedItems = array();
  
 -      static $idCacheByName = array();
 +      public static $idCacheByName = array();
  
        /**
         * Lightweight constructor for an anonymous user.
                }
  
                $dbr = wfGetDB( DB_SLAVE );
 -              $s = $dbr->selectRow( 'user', array( 'user_id' ), array( 'user_name' => $nt->getText() ), __METHOD__ );
 +              $s = $dbr->selectRow(
 +                      'user',
 +                      array( 'user_id' ),
 +                      array( 'user_name' => $nt->getText() ),
 +                      __METHOD__
 +              );
  
                if ( $s === false ) {
                        $result = null;
         * @return bool
         */
        public static function isIP( $name ) {
 -              return preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.(?:xxx|\d{1,3})$/', $name ) || IP::isIPv6( $name );
 +              return preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.(?:xxx|\d{1,3})$/', $name )
 +                      || IP::isIPv6( $name );
        }
  
        /**
                        } elseif ( $wgContLang->lc( $password ) == $wgContLang->lc( $this->mName ) ) {
                                $status->error( 'password-name-match' );
                                return $status;
 -                      } elseif ( isset( $blockedLogins[$this->getName()] ) && $password == $blockedLogins[$this->getName()] ) {
 +                      } elseif ( isset( $blockedLogins[$this->getName()] )
 +                              && $password == $blockedLogins[$this->getName()]
 +                      ) {
                                $status->error( 'password-login-forbidden' );
                                return $status;
                        } else {
         */
        public static function randomPassword() {
                global $wgMinimalPasswordLength;
 -              // Decide the final password length based on our min password length, stopping at a minimum of 10 chars
 +              // 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;
                }
  
                if ( $request->getSessionData( 'wsToken' ) ) {
 -                      $passwordCorrect = ( $proposedUser->getToken( false ) === $request->getSessionData( 'wsToken' ) );
 +                      $passwordCorrect =
 +                              ( $proposedUser->getToken( false ) === $request->getSessionData( 'wsToken' ) );
                        $from = 'session';
                } elseif ( $request->getCookie( 'Token' ) ) {
                        # Get the token from DB/cache and clean it up to remove garbage padding.
                        # This deals with historical problems with bugs and the default column value.
                        $token = rtrim( $proposedUser->getToken( false ) ); // correct token
                        // Make comparison in constant time (bug 61346)
 -                      $passwordCorrect = strlen( $token ) && $this->compareSecrets( $token, $request->getCookie( 'Token' ) );
 +                      $passwordCorrect = strlen( $token )
 +                              && $this->compareSecrets( $token, $request->getCookie( 'Token' ) );
                        $from = 'cookie';
                } else {
                        // No session or persistent login cookie
                        $passwordCorrect = false;
                } else {
                        $result = 0;
 -                      for ( $i = 0; $i < strlen( $answer ); $i++ ) {
 +                      $answerLength = strlen( $answer );
 +                      for ( $i = 0; $i < $answerLength; $i++ ) {
                                $result |= ord( $answer[$i] ) ^ ord( $test[$i] );
                        }
                        $passwordCorrect = ( $result == 0 );
                }
 +
                return $passwordCorrect;
        }
  
                }
  
                $dbr = wfGetDB( DB_MASTER );
 -              $s = $dbr->selectRow( 'user', self::selectFields(), array( 'user_id' => $this->mId ), __METHOD__ );
 +              $s = $dbr->selectRow(
 +                      'user',
 +                      self::selectFields(),
 +                      array( 'user_id' => $this->mId ),
 +                      __METHOD__
 +              );
  
                wfRunHooks( 'UserLoadFromDatabase', array( $this, &$s ) );
  
                        // Already pinged?
                        if ( $count ) {
                                if ( $count >= $max ) {
-                                       wfDebugLog( 'ratelimit', $this->getName() . " tripped! $key at $count $summary" );
+                                       wfDebugLog( 'ratelimit', "User '{$this->getName()}' " .
+                                               "(IP {$this->getRequest()->getIP()}) tripped $key at $count $summary" );
                                        $triggered = true;
                                } else {
                                        wfDebug( __METHOD__ . ": ok. $key at $count $summary\n" );
        /**
         * Check if user is blocked
         *
 -       * @param bool $bFromSlave Whether to check the slave database instead of the master
 +       * @param bool $bFromSlave Whether to check the slave database instead of
 +       *   the master. Hacked from false due to horrible probs on site.
         * @return bool True if blocked, false otherwise
         */
 -      public function isBlocked( $bFromSlave = true ) { // hacked from false due to horrible probs on site
 +      public function isBlocked( $bFromSlave = true ) {
                return $this->getBlock( $bFromSlave ) instanceof Block && $this->getBlock()->prevents( 'edit' );
        }
  
        /**
         * Update the 'You have new messages!' status.
         * @param bool $val Whether the user has new messages
 -       * @param Revision $curRev New, as yet unseen revision of the user talk page. Ignored if null or !$val.
 +       * @param Revision $curRev New, as yet unseen revision of the user talk
 +       *   page. Ignored if null or !$val.
         */
        public function setNewtalk( $val, $curRev = null ) {
                if ( wfReadOnly() ) {
  
        /**
         * Get the user's current token.
 -       * @param bool $forceCreation Force the generation of a new token if the user doesn't have one (default=true for backwards compatibility)
 +       * @param bool $forceCreation Force the generation of a new token if the
 +       *   user doesn't have one (default=true for backwards compatibility).
         * @return string Token
         */
        public function getToken( $forceCreation = true ) {
         *
         * @see User::listOptionKinds
         * @param IContextSource $context
 -       * @param array $options Assoc. array with options keys to check as keys. Defaults to $this->mOptions.
 +       * @param array $options Assoc. array with options keys to check as keys.
 +       *   Defaults to $this->mOptions.
         * @return array the key => kind mapping data
         */
        public function getOptionKinds( IContextSource $context, $options = null ) {
         * Add a user to the database, return the user object
         *
         * @param string $name Username to add
 -       * @param array $params Array of Strings Non-default parameters to save to the database as user_* fields:
 -       *   - password             The user's password hash. Password logins will be disabled if this is omitted.
 -       *   - newpassword          Hash for a temporary password that has been mailed to the user
 -       *   - email                The user's email address
 -       *   - email_authenticated  The email authentication timestamp
 -       *   - real_name            The user's real name
 -       *   - options              An associative array of non-default options
 -       *   - token                Random authentication token. Do not set.
 -       *   - registration         Registration timestamp. Do not set.
 -       *
 -       * @return User|null User object, or null if the username already exists
 +       * @param array $params Array of Strings Non-default parameters to save to
 +       *   the database as user_* fields:
 +       *   - password: The user's password hash. Password logins will be disabled
 +       *     if this is omitted.
 +       *   - newpassword: Hash for a temporary password that has been mailed to
 +       *     the user.
 +       *   - email: The user's email address.
 +       *   - email_authenticated: The email authentication timestamp.
 +       *   - real_name: The user's real name.
 +       *   - options: An associative array of non-default options.
 +       *   - token: Random authentication token. Do not set.
 +       *   - registration: Registration timestamp. Do not set.
 +       *
 +       * @return User|null User object, or null if the username already exists.
         */
        public static function createNew( $name, $params = array() ) {
                $user = new User;
                if ( $this->mBlockedFromCreateAccount === false && !$this->isAllowed( 'ipblock-exempt' ) ) {
                        $this->mBlockedFromCreateAccount = Block::newFromTarget( null, $this->getRequest()->getIP() );
                }
 -              return $this->mBlockedFromCreateAccount instanceof Block && $this->mBlockedFromCreateAccount->prevents( 'createaccount' )
 +              return $this->mBlockedFromCreateAccount instanceof Block
 +                      && $this->mBlockedFromCreateAccount->prevents( 'createaccount' )
                        ? $this->mBlockedFromCreateAccount
                        : false;
        }
         * Generate a looking random token for various uses.
         *
         * @return string The new random token
 -       * @deprecated since 1.20: Use MWCryptRand for secure purposes or wfRandomString for pseudo-randomness
 +       * @deprecated since 1.20: Use MWCryptRand for secure purposes or
 +       *   wfRandomString for pseudo-randomness.
         */
        public static function generateToken() {
                return MWCryptRand::generateHex( 32 );
                if ( $val != $sessionToken ) {
                        wfDebug( "User::matchEditToken: broken session data\n" );
                }
 +
                return $val == $sessionToken;
        }
  
         *
         * @param string $subject Message subject
         * @param string $body Message body
 -       * @param string $from Optional From address; if unspecified, default $wgPasswordSender will be used
 +       * @param string $from Optional From address; if unspecified, default
 +       *   $wgPasswordSender will be used.
         * @param string $replyto Reply-To address
         * @return Status
         */
         */
        public static function getImplicitGroups() {
                global $wgImplicitGroups;
 +
                $groups = $wgImplicitGroups;
 -              wfRunHooks( 'UserGetImplicitGroups', array( &$groups ) );       #deprecated, use $wgImplictGroups instead
 +              # Deprecated, use $wgImplictGroups instead
 +              wfRunHooks( 'UserGetImplicitGroups', array( &$groups ) );
 +
                return $groups;
        }
  
        public static function changeableByGroup( $group ) {
                global $wgAddGroups, $wgRemoveGroups, $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
  
 -              $groups = array( 'add' => array(), 'remove' => array(), 'add-self' => array(), 'remove-self' => array() );
 +              $groups = array(
 +                      'add' => array(),
 +                      'remove' => array(),
 +                      'add-self' => array(),
 +                      'remove-self' => array()
 +              );
 +
                if ( empty( $wgAddGroups[$group] ) ) {
                        // Don't add anything to $groups
                } elseif ( $wgAddGroups[$group] === true ) {