oops
[lhc/web/wiklou.git] / includes / User.php
index a116389..4775713 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * See user.doc
+ * See user.txt
  *
  * @package MediaWiki
  */
@@ -242,9 +242,17 @@ class User {
        /**
         * Get blocking information
         * @access private
+        * @param bool $bFromSlave Specify whether to check slave or master. To improve performance,
+        *  non-critical checks are done against slaves. Check when actually saving should be done against
+        *  master.
+        *
+        * Note that even if $bFromSlave is false, the check is done first against slave, then master.
+        * The logic is that if blocked on slave, we'll assume it's either blocked on master or
+        * just slightly outta sync and soon corrected - safer to block slightly more that less.
+        * And it's cheaper to check slave first, then master if needed, than master always.
         */
        function getBlockedStatus() {
-               global $wgIP, $wgBlockCache, $wgProxyList;
+               global $wgIP, $wgBlockCache, $wgProxyList, $wgEnableSorbs, $bFromSlave;
 
                if ( -1 != $this->mBlockedby ) { return; }
 
@@ -253,15 +261,24 @@ class User {
                # User blocking
                if ( $this->mId ) {
                        $block = new Block();
-                       if ( $block->load( $wgIP , $this->mId ) ) {
+                       $block->forUpdate( $bFromSlave );
+                       if ( $block->load( $wgIP , $this->mId ) ) {
                                $this->mBlockedby = $block->mBy;
                                $this->mBlockreason = $block->mReason;
+                               $this->spreadBlock();
                        }
                }
 
                # IP/range blocking
                if ( !$this->mBlockedby ) {
-                       $block = $wgBlockCache->get( $wgIP );
+                       # Check first against slave, and optionally from master.
+                       $block = $wgBlockCache->get( $wgIP, true );
+                       if ( !$block && !$bFromSlave )
+                               {
+                               # Not blocked: check against master, to make sure.
+                               $wgBlockCache->clearLocal( );
+                               $block = $wgBlockCache->get( $wgIP, false );
+                               }
                        if ( $block !== false ) {
                                $this->mBlockedby = $block->mBy;
                                $this->mBlockreason = $block->mReason;
@@ -275,14 +292,52 @@ class User {
                                $this->mBlockreason = wfMsg( 'proxyblockreason' );
                        }
                }
+
+               # DNSBL
+               if ( !$this->mBlockedby && $wgEnableSorbs ) {
+                       if ( $this->inSorbsBlacklist( $wgIP ) ) {
+                               $this->mBlockedby = wfMsg( 'sorbs' );
+                               $this->mBlockreason = wfMsg( 'sorbsreason' );
+                       }
+               }
+                       
        }
 
+       function inSorbsBlacklist( $ip ) {
+               $fname = 'User::inSorbsBlacklist';
+               wfProfileIn( $fname );
+               
+               $found = false;
+               $host = '';
+               
+               if ( preg_match( '/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/', $ip, $m ) ) {
+                       # Make hostname
+                       for ( $i=4; $i>=1; $i-- ) {
+                               $host .= $m[$i] . '.';
+                       }
+                       $host .= 'http.dnsbl.sorbs.net.';
+
+                       # Send query
+                       $ipList = gethostbynamel( $host );
+                       
+                       if ( $ipList ) {
+                               wfDebug( "Hostname $host is {$ipList[0]}, it's a proxy!\n" );
+                               $found = true;
+                       } else {
+                               wfDebug( "Requested $host, not found.\n" );
+                       }
+               }
+
+               wfProfileOut( $fname );
+               return $found;
+       }
+       
        /**
         * Check if user is blocked
         * @return bool True if blocked, false otherwise
         */
-       function isBlocked() {
-               $this->getBlockedStatus();
+       function isBlocked( $bFromSlave = false ) {
+               $this->getBlockedStatus( $bFromSlave );
                if ( 0 === $this->mBlockedby ) { return false; }
                return true;
        }
@@ -376,7 +431,6 @@ class User {
                                else
                                        wfDebug( "User::loadFromSession() unable to save to memcached\n" );
                        }
-                       $user->spreadBlock();
                        return $user;
                }
                return new User(); # Can't log in from session
@@ -576,13 +630,16 @@ class User {
 
        # Set the random token (used for persistent authentication)
        function setToken( $token = false ) {
+               global $wgSecretKey, $wgProxyKey, $wgDBname;
                if ( !$token ) {
-                       $this->mToken = '';
-                       # Take random data from PRNG
-                       # This is reasonably secure if the PRNG has been seeded correctly
-                       for ($i = 0; $i<USER_TOKEN_LENGTH / 4; $i++) {
-                               $this->mToken .= sprintf( "%04X", mt_rand( 0, 65535 ) );
+                       if ( $wgSecretKey ) {
+                               $key = $wgSecretKey;
+                       } elseif ( $wgProxyKey ) {
+                               $key = $wgProxyKey;
+                       } else {
+                               $key = microtime();
                        }
+                       $this->mToken = md5( $wgSecretKey . mt_rand( 0, 0x7fffffff ) . $wgDBname . $this->mId );
                } else {
                        $this->mToken = $token;
                }
@@ -665,41 +722,43 @@ class User {
                $this->invalidateCache();
        }
 
+       /**
+        * A more legible check for non-anonymousness.
+        * Returns true if the user is not an anonymous visitor.
+        *
+        * @return bool
+        */
+       function isLoggedIn() {
+               return( $this->getID() != 0 );
+       }
+       
+       /**
+        * A more legible check for anonymousness.
+        * Returns true if the user is an anonymous visitor.
+        *
+        * @return bool
+        */
+       function isAnon() {
+               return !$this->isLoggedIn();
+       }
+       
        /**
         * Check if a user is sysop
         * Die with backtrace. Use User:isAllowed() instead.
         * @deprecated
         */
        function isSysop() {
-       /**
-               $this->loadFromDatabase();
-               if ( 0 == $this->mId ) { return false; }
-
-               return in_array( 'sysop', $this->mRights );
-       */
-       wfDebugDieBacktrace("User::isSysop() is deprecated. Use User::isAllowed() instead");
+               wfDebugDieBacktrace("User::isSysop() is deprecated. Use User::isAllowed() instead");
        }
 
        /** @deprecated */
        function isDeveloper() {
-       /**
-               $this->loadFromDatabase();
-               if ( 0 == $this->mId ) { return false; }
-
-               return in_array( 'developer', $this->mRights );
-       */
-       wfDebugDieBacktrace("User::isDeveloper() is deprecated. Use User::isAllowed() instead");
+               wfDebugDieBacktrace("User::isDeveloper() is deprecated. Use User::isAllowed() instead");
        }
 
        /** @deprecated */
        function isBureaucrat() {
-       /**
-               $this->loadFromDatabase();
-               if ( 0 == $this->mId ) { return false; }
-
-               return in_array( 'bureaucrat', $this->mRights );
-       */
-       wfDebugDieBacktrace("User::isBureaucrat() is deprecated. Use User::isAllowed() instead");
+               wfDebugDieBacktrace("User::isBureaucrat() is deprecated. Use User::isAllowed() instead");
        }
 
        /**
@@ -827,7 +886,7 @@ class User {
                $dbw =& wfGetDB( DB_MASTER );
                $success = $dbw->update( 'watchlist',
                                array( /* SET */
-                                       'wl_notificationtimestamp' => $dbw->timestamp(0)
+                                       'wl_notificationtimestamp' => 0
                                ), array( /* WHERE */
                                        'wl_title' => $title->getDBkey(),
                                        'wl_namespace' => $title->getNamespace(),
@@ -1096,14 +1155,12 @@ class User {
                // it will always be 0 when this function is called by parsercache.
 
                $confstr =        $this->getOption( 'math' );
-               $confstr .= '!' . $this->getOption( 'highlightbroken' );
                $confstr .= '!' . $this->getOption( 'stubthreshold' );
                $confstr .= '!' . $this->getOption( 'editsection' );
-               $confstr .= '!' . $this->getOption( 'editsectiononrightclick' );
-               $confstr .= '!' . $this->getOption( 'showtoc' );
                $confstr .= '!' . $this->getOption( 'date' );
                $confstr .= '!' . $this->getOption( 'numberheadings' );
                $confstr .= '!' . $this->getOption( 'language' );
+               $confstr .= '!' . $this->getOption( 'thumbsize' );
                // add in language specific options, if any
                $extra = $wgContLang->getExtraHashOptions();
                $confstr .= $extra;
@@ -1132,9 +1189,26 @@ class User {
                return wfSetVar( $this->mDataLoaded, $loaded );
        }
 
+       /**
+        * Get this user's personal page title.
+        *
+        * @return Title
+        * @access public
+        */
        function getUserPage() {
                return Title::makeTitle( NS_USER, $this->mName );
        }
+       
+       /**
+        * Get this user's talk page title.
+        *
+        * @return Title
+        * @access public
+        */
+       function getTalkPage() {
+               $title = $this->getUserPage();
+               return $title->getTalkPage();
+       }
 
        /**
         * @static
@@ -1194,15 +1268,22 @@ class User {
         * login credentials aren't being hijacked with a foreign form
         * submission.
         *
+        * @param mixed $salt - Optional function-specific data for hash.
+        *                      Use a string or an array of strings.
         * @return string
         * @access public
         */
-       function editToken() {
+       function editToken( $salt = '' ) {
                if( !isset( $_SESSION['wsEditToken'] ) ) {
                        $token = dechex( mt_rand() ) . dechex( mt_rand() );
                        $_SESSION['wsEditToken'] = $token;
+               } else {
+                       $token = $_SESSION['wsEditToken'];
+               }
+               if( is_array( $salt ) ) {
+                       $salt = implode( '|', $salt );
                }
-               return $_SESSION['wsEditToken'];
+               return md5( $token . $salt );
        }
        
        /**
@@ -1211,14 +1292,13 @@ class User {
         * user's own login session, not a form submission from a third-party
         * site.
         *
-        * @param string $val
+        * @param string $val - the input value to compare
+        * @param string $salt - Optional function-specific data for hash
         * @return bool
         * @access public
         */
-       function matchEditToken( $val ) {
-               if( !isset( $_SESSION['wsEditToken'] ) ) 
-                       return false;
-               return $_SESSION['wsEditToken'] == $val;
+       function matchEditToken( $val, $salt = '' ) {
+               return ( $val == $this->editToken( $salt ) );
        }
 }