summaryrefslogtreecommitdiff
path: root/includes/User.php
diff options
context:
space:
mode:
Diffstat (limited to 'includes/User.php')
-rw-r--r--includes/User.php77
1 files changed, 40 insertions, 37 deletions
diff --git a/includes/User.php b/includes/User.php
index cebcf604..705fd291 100644
--- a/includes/User.php
+++ b/includes/User.php
@@ -831,23 +831,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
*/
public 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;
+ // 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 );
}
/**
@@ -877,7 +874,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;
@@ -984,11 +981,11 @@ class User {
return false;
}
- if ( $request->getSessionData( 'wsToken' ) !== null ) {
- $passwordCorrect = $proposedUser->getToken() === $request->getSessionData( 'wsToken' );
+ if ( $request->getSessionData( 'wsToken' ) ) {
+ $passwordCorrect = $proposedUser->getToken( false ) === $request->getSessionData( 'wsToken' );
$from = 'session';
- } elseif ( $request->getCookie( 'Token' ) !== null ) {
- $passwordCorrect = $proposedUser->getToken() === $request->getCookie( 'Token' );
+ } elseif ( $request->getCookie( 'Token' ) ) {
+ $passwordCorrect = $proposedUser->getToken( false ) === $request->getCookie( 'Token' );
$from = 'cookie';
} else {
# No session or persistent login cookie
@@ -1083,6 +1080,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 );
@@ -1989,10 +1989,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
*/
- public function getToken() {
+ public function getToken( $forceCreation = true ) {
$this->load();
+ if ( !$this->mToken && $forceCreation ) {
+ $this->setToken();
+ }
return $this->mToken;
}
@@ -2006,14 +2010,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;
}
@@ -2718,6 +2715,14 @@ class User {
$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,
@@ -2795,7 +2800,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 */
@@ -2862,7 +2867,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,
);
@@ -2896,7 +2901,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__
@@ -3144,7 +3149,7 @@ class User {
} else {
$token = $request->getSessionData( 'wsEditToken' );
if ( $token === null ) {
- $token = self::generateToken();
+ $token = MWCryptRand::generateHex( 32 );
$request->setSessionData( 'wsEditToken', $token );
}
if( is_array( $salt ) ) {
@@ -3161,8 +3166,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 );
}
/**
@@ -3268,12 +3272,11 @@ class User {
global $wgUserEmailConfirmationTokenExpiry;
$now = time();
$expires = $now + $wgUserEmailConfirmationTokenExpiry;
- $expiration = wfTimestamp( TS_MW, $expires );
- $token = self::generateToken( $this->mId . $this->mEmail . $expires );
- $hash = md5( $token );
$this->load();
+ $token = MWCryptRand::generateHex( 32 );
+ $hash = md5( $token );
$this->mEmailToken = $hash;
- $this->mEmailTokenExpires = $expiration;
+ $this->mEmailTokenExpires = wfTimestamp( TS_MW, $expires );
return $token;
}
@@ -3828,7 +3831,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 {