'deletelogentry',
'deleterevision',
'edit',
+ 'editcontentmodel',
'editinterface',
'editprotected',
'editmyoptions',
global $wgContLang, $wgMaxNameChars;
if ( $name == ''
- || User::isIP( $name )
- || strpos( $name, '/' ) !== false
- || strlen( $name ) > $wgMaxNameChars
- || $name != $wgContLang->ucfirst( $name ) ) {
+ || User::isIP( $name )
+ || strpos( $name, '/' ) !== false
+ || strlen( $name ) > $wgMaxNameChars
+ || $name != $wgContLang->ucfirst( $name )
+ ) {
wfDebugLog( 'username', __METHOD__ .
": '$name' invalid due to empty, IP, slash, length, or lowercase" );
return false;
return false;
}
- $passwordFactory = self::getPasswordFactory();
if ( !$this->mPassword->equals( $password ) ) {
if ( $wgLegacyEncoding ) {
// Some wikis were converted from ISO 8859-1 to UTF-8, the passwords can't be converted
}
}
+ $passwordFactory = self::getPasswordFactory();
if ( $passwordFactory->needsUpdate( $this->mPassword ) ) {
$this->mPassword = $passwordFactory->newFromPlaintext( $password );
$this->saveSettings();
}
/**
- * Initialize (if necessary) and return a session token value
- * which can be used in edit forms to show that the user's
- * login credentials aren't being hijacked with a foreign form
- * submission.
- *
- * @since 1.19
+ * Internal implementation for self::getEditToken() and
+ * self::matchEditToken().
*
- * @param string|array $salt Array of Strings Optional function-specific data for hashing
- * @param WebRequest|null $request WebRequest object to use or null to use $wgRequest
- * @return string The new edit token
+ * @param string|array $salt
+ * @param WebRequest $request
+ * @param string|int $timestamp
+ * @return string
*/
- public function getEditToken( $salt = '', $request = null ) {
- if ( $request == null ) {
- $request = $this->getRequest();
- }
-
+ private function getEditTokenAtTimestamp( $salt, $request, $timestamp ) {
if ( $this->isAnon() ) {
return self::EDIT_TOKEN_SUFFIX;
} else {
if ( is_array( $salt ) ) {
$salt = implode( '|', $salt );
}
- return md5( $token . $salt ) . self::EDIT_TOKEN_SUFFIX;
+ return hash_hmac( 'md5', $timestamp . $salt, $token, false ) .
+ dechex( $timestamp ) .
+ self::EDIT_TOKEN_SUFFIX;
}
}
+ /**
+ * Initialize (if necessary) and return a session token value
+ * which can be used in edit forms to show that the user's
+ * login credentials aren't being hijacked with a foreign form
+ * submission.
+ *
+ * @since 1.19
+ *
+ * @param string|array $salt Array of Strings Optional function-specific data for hashing
+ * @param WebRequest|null $request WebRequest object to use or null to use $wgRequest
+ * @return string The new edit token
+ */
+ public function getEditToken( $salt = '', $request = null ) {
+ return $this->getEditTokenAtTimestamp(
+ $salt, $request ?: $this->getRequest(), wfTimestamp()
+ );
+ }
+
/**
* Generate a looking random token for various uses.
*
* @param string $val Input value to compare
* @param string $salt Optional function-specific data for hashing
* @param WebRequest|null $request Object to use or null to use $wgRequest
+ * @param int $maxage Fail tokens older than this, in seconds
* @return bool Whether the token matches
*/
- public function matchEditToken( $val, $salt = '', $request = null ) {
- $sessionToken = $this->getEditToken( $salt, $request );
+ public function matchEditToken( $val, $salt = '', $request = null, $maxage = null ) {
+ if ( $this->isAnon() ) {
+ return $val === self::EDIT_TOKEN_SUFFIX;
+ }
+
+ $suffixLen = strlen( self::EDIT_TOKEN_SUFFIX );
+ if ( strlen( $val ) <= 32 + $suffixLen ) {
+ return false;
+ }
+
+ $timestamp = hexdec( substr( $val, 32, -$suffixLen ) );
+ if ( $maxage !== null && $timestamp < wfTimestamp() - $maxage ) {
+ // Expired token
+ return false;
+ }
+
+ $sessionToken = $this->getEditTokenAtTimestamp(
+ $salt, $request ?: $this->getRequest(), $timestamp
+ );
+
if ( $val != $sessionToken ) {
wfDebug( "User::matchEditToken: broken session data\n" );
}
- return $val == $sessionToken;
+ return hash_equals( $sessionToken, $val );
}
/**
* @param string $val Input value to compare
* @param string $salt Optional function-specific data for hashing
* @param WebRequest|null $request Object to use or null to use $wgRequest
+ * @param int $maxage Fail tokens older than this, in seconds
* @return bool Whether the token matches
*/
- public function matchEditTokenNoSuffix( $val, $salt = '', $request = null ) {
- $sessionToken = $this->getEditToken( $salt, $request );
- return substr( $sessionToken, 0, 32 ) == substr( $val, 0, 32 );
+ public function matchEditTokenNoSuffix( $val, $salt = '', $request = null, $maxage = null ) {
+ $val = substr( $val, 0, strspn( $val, '0123456789abcdef' ) ) . self::EDIT_TOKEN_SUFFIX;
+ return $this->matchEditToken( $val, $salt, $request, $maxage );
}
/**
global $wgImplicitGroups;
$groups = $wgImplicitGroups;
- # Deprecated, use $wgImplictGroups instead
- wfRunHooks( 'UserGetImplicitGroups', array( &$groups ) );
+ # Deprecated, use $wgImplicitGroups instead
+ wfRunHooks( 'UserGetImplicitGroups', array( &$groups ), '1.25' );
return $groups;
}
}
$title = self::getGroupPage( $group );
if ( $title ) {
- $page = $title->getPrefixedText();
+ $page = $title->getFullText();
return "[[$page|$text]]";
} else {
return $text;
// Same thing for remove
if ( empty( $wgRemoveGroups[$group] ) ) {
+ // Do nothing
} elseif ( $wgRemoveGroups[$group] === true ) {
$groups['remove'] = self::getAllGroups();
} elseif ( is_array( $wgRemoveGroups[$group] ) ) {
// Now figure out what groups the user can add to him/herself
if ( empty( $wgGroupsAddToSelf[$group] ) ) {
+ // Do nothing
} elseif ( $wgGroupsAddToSelf[$group] === true ) {
// No idea WHY this would be used, but it's there
$groups['add-self'] = User::getAllGroups();
}
if ( empty( $wgGroupsRemoveFromSelf[$group] ) ) {
+ // Do nothing
} elseif ( $wgGroupsRemoveFromSelf[$group] === true ) {
$groups['remove-self'] = User::getAllGroups();
} elseif ( is_array( $wgGroupsRemoveFromSelf[$group] ) ) {