<?php
/**
- * See user.doc
+ * See user.txt
*
* @package MediaWiki
*/
/**
* 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; }
# 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;
$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;
}
else
wfDebug( "User::loadFromSession() unable to save to memcached\n" );
}
- $user->spreadBlock();
return $user;
}
return new User(); # Can't log in from session
# 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;
}
$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");
}
/**
$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(),
// 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;
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
* 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 );
}
/**
* 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 ) );
}
}