Merge in Login rewrite, second time lucky.

This commit is contained in:
Happy-melon 2009-09-20 20:28:27 +00:00
parent 7db738a09e
commit d3f901b029
14 changed files with 1692 additions and 1427 deletions

View file

@ -87,6 +87,11 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
correctly (img_auth only)
* $wgUploadMaintenance added to disable file deletions and restorations during
maintenance
* UserLoginForm and UserCreateForm hooks, and AuthPlugin::modifyUITemplate, now receive a
SpecialPage subclass instead of a QuickTemplate subclass. Hence there is no
$template->set(), etc. The hook has access to most of the stuff that will go into the
Login/Create form; see the documentation on HTMLForm for syntax for extra fields.
LoginForm class is deprecated, its state constants are now in the Login class.
=== New features in 1.16 ===

View file

@ -244,8 +244,8 @@ $block: The block from which the autoblock is coming.
'AbortLogin': Return false to cancel account login.
$user: the User object being authenticated against
$password: the password being submitted, not yet checked for validity
&$retval: a LoginForm class constant to return from authenticateUserData();
default is LoginForm::ABORTED. Note that the client may be using
&$retval: a Login class constant to return from authenticateUserData();
default is Login::ABORTED. Note that the client may be using
a machine API rather than the HTML user interface.
'AbortMove': allows to abort moving an article (title)
@ -944,7 +944,7 @@ $code: language code
succeeded or failed. No return data is accepted; this hook is for auditing only.
$user: the User object being authenticated against
$password: the password being submitted and found wanting
$retval: a LoginForm class constant with authenticateUserData() return
$retval: a Login class constant with authenticateUserData() return
value (SUCCESS, WRONG_PASS, etc)
'LogLine': Processes a single log entry on Special:Log
@ -1526,7 +1526,7 @@ override the default password checks
determine if the password was valid
'UserCreateForm': change to manipulate the login form
$template: SimpleTemplate instance for the form
$sp: SpecialCreateAccount instance
'UserCryptPassword': called when hashing a password, return false to implement
your own hashing method
@ -1596,7 +1596,7 @@ $user: the user object that was created on login
$inject_html: Any HTML to inject after the "logged in" message.
'UserLoginForm': change to manipulate the login form
$template: SimpleTemplate instance for the form
$sp: SpecialCreateAccount instance
'UserLoginMailPassword': Block users from emailing passwords
$name: the username to email the password of.

View file

@ -62,12 +62,13 @@ class AuthPlugin {
/**
* Modify options in the login template.
*
* @param $template UserLoginTemplate object.
* @param $type String 'signup' or 'login'.
* @param $sp SpecialUserlogin or SpecialCreateAccount object.
* @param $type String 'signup' or 'login'. Redundant because
* you can just use instanceof to tell the two cases apart.
*/
public function modifyUITemplate( &$template, &$type ) {
public function modifyUITemplate( &$sp, $type=null ) {
# Override this!
$template->set( 'usedomain', false );
$sp->mDomains = false;
}
/**

View file

@ -134,6 +134,8 @@ $wgAutoloadLocalClasses = array(
'LinksUpdate' => 'includes/LinksUpdate.php',
'LocalisationCache' => 'includes/LocalisationCache.php',
'LocalisationCache_BulkLoad' => 'includes/LocalisationCache.php',
'LoginForm' => 'includes/Login.php', # For B/C
'Login' => 'includes/Login.php',
'LogPage' => 'includes/LogPage.php',
'LogPager' => 'includes/LogEventsList.php',
'LogEventsList' => 'includes/LogEventsList.php',
@ -493,6 +495,7 @@ $wgAutoloadLocalClasses = array(
'AncientPagesPage' => 'includes/specials/SpecialAncientpages.php',
'BrokenRedirectsPage' => 'includes/specials/SpecialBrokenRedirects.php',
'ContribsPager' => 'includes/specials/SpecialContributions.php',
'SpecialCreateAccount' => 'includes/specials/SpecialCreateAccount.php',
'DBLockForm' => 'includes/specials/SpecialLockdb.php',
'DBUnlockForm' => 'includes/specials/SpecialUnlockdb.php',
'DeadendPagesPage' => 'includes/specials/SpecialDeadendpages.php',
@ -513,7 +516,6 @@ $wgAutoloadLocalClasses = array(
'ImportStringSource' => 'includes/Import.php',
'LinkSearchPage' => 'includes/specials/SpecialLinkSearch.php',
'ListredirectsPage' => 'includes/specials/SpecialListredirects.php',
'LoginForm' => 'includes/specials/SpecialUserlogin.php',
'LonelyPagesPage' => 'includes/specials/SpecialLonelypages.php',
'LongPagesPage' => 'includes/specials/SpecialLongpages.php',
'MIMEsearchPage' => 'includes/specials/SpecialMIMEsearch.php',
@ -562,6 +564,7 @@ $wgAutoloadLocalClasses = array(
'UnwatchedpagesPage' => 'includes/specials/SpecialUnwatchedpages.php',
'UploadForm' => 'includes/specials/SpecialUpload.php',
'UploadFormMogile' => 'includes/specials/SpecialUploadMogile.php',
'SpecialUserLogin' => 'includes/specials/SpecialUserlogin.php',
'UserrightsPage' => 'includes/specials/SpecialUserrights.php',
'UsersPager' => 'includes/specials/SpecialListusers.php',
'WantedCategoriesPage' => 'includes/specials/SpecialWantedcategories.php',

565
includes/Login.php Normal file
View file

@ -0,0 +1,565 @@
<?php
/**
* Encapsulates the backend activities of logging a user into the wiki.
*/
class Login {
const SUCCESS = 0;
const NO_NAME = 1;
const ILLEGAL = 2;
const WRONG_PLUGIN_PASS = 3;
const NOT_EXISTS = 4;
const WRONG_PASS = 5;
const EMPTY_PASS = 6;
const RESET_PASS = 7;
const ABORTED = 8;
const THROTTLED = 10;
const FAILED = 11;
const READ_ONLY = 12;
const MAIL_PASSCHANGE_FORBIDDEN = 21;
const MAIL_BLOCKED = 22;
const MAIL_PING_THROTTLED = 23;
const MAIL_PASS_THROTTLED = 24;
const MAIL_EMPTY_EMAIL = 25;
const MAIL_BAD_IP = 26;
const MAIL_ERROR = 27;
const CREATE_BLOCKED = 40;
const CREATE_EXISTS = 41;
const CREATE_SORBS = 42;
const CREATE_BADDOMAIN = 43;
const CREATE_BADNAME = 44;
const CREATE_BADPASS = 45;
const CREATE_NEEDEMAIL = 46;
const CREATE_BADEMAIL = 47;
protected $mName;
protected $mPassword;
public $mRemember; # 0 or 1
public $mEmail;
public $mDomain;
public $mRealname;
private $mExtUser = null;
public $mUser;
public $mLoginResult = '';
public $mMailResult = '';
public $mCreateResult = '';
/**
* Constructor
* @param WebRequest $request A WebRequest object passed by reference.
* uses $wgRequest if not given.
*/
public function __construct( &$request=null ) {
global $wgRequest, $wgAuth, $wgHiddenPrefs, $wgEnableEmail, $wgRedirectOnLogin;
if( !$request ) $request = &$wgRequest;
$this->mName = $request->getText( 'wpName' );
$this->mPassword = $request->getText( 'wpPassword' );
$this->mDomain = $request->getText( 'wpDomain' );
$this->mRemember = $request->getCheck( 'wpRemember' ) ? 1 : 0;
if( $wgEnableEmail ) {
$this->mEmail = $request->getText( 'wpEmail' );
} else {
$this->mEmail = '';
}
if( !in_array( 'realname', $wgHiddenPrefs ) ) {
$this->mRealName = $request->getText( 'wpRealName' );
} else {
$this->mRealName = '';
}
if( !$wgAuth->validDomain( $this->mDomain ) ) {
$this->mDomain = 'invaliddomain';
}
$wgAuth->setDomain( $this->mDomain );
# Load the user, if they exist in the local database.
$this->mUser = User::newFromName( trim( $this->mName ), 'usable' );
}
/**
* Having initialised the Login object with (at least) the wpName
* and wpPassword pair, attempt to authenticate the user and log
* them into the wiki. Authentication may come from the local
* user database, or from an AuthPlugin- or ExternalUser-based
* foreign database; in the latter case, a local user record may
* or may not be created and initialised.
* @return a Login class constant representing the status.
*/
public function attemptLogin(){
global $wgUser;
$code = $this->authenticateUserData();
if( $code != self::SUCCESS ){
return $code;
}
# Log the user in and remember them if they asked for that.
if( (bool)$this->mRemember != (bool)$wgUser->getOption( 'rememberpassword' ) ) {
$wgUser->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 );
$wgUser->saveSettings();
} else {
$wgUser->invalidateCache();
}
$wgUser->setCookies();
# Reset the password throttle
$key = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
global $wgMemc;
$wgMemc->delete( $key );
wfRunHooks( 'UserLoginComplete', array( &$wgUser, &$this->mLoginResult ) );
return self::SUCCESS;
}
/**
* Check whether there is an external authentication mechanism from
* which we can automatically authenticate the user and create a
* local account for them.
* @return integer Status code. Login::SUCCESS == clear to proceed
* with user creation.
*/
protected function canAutoCreate() {
global $wgAuth, $wgUser, $wgAutocreatePolicy;
if( $wgUser->isBlockedFromCreateAccount() ) {
wfDebug( __METHOD__.": user is blocked from account creation\n" );
return self::CREATE_BLOCKED;
}
# If the external authentication plugin allows it, automatically
# create a new account for users that are externally defined but
# have not yet logged in.
if( $this->mExtUser ) {
# mExtUser is neither null nor false, so use the new
# ExternalAuth system.
if( $wgAutocreatePolicy == 'never' ) {
return self::NOT_EXISTS;
}
if( !$this->mExtUser->authenticate( $this->mPassword ) ) {
return self::WRONG_PLUGIN_PASS;
}
} else {
# Old AuthPlugin.
if( !$wgAuth->autoCreate() ) {
return self::NOT_EXISTS;
}
if( !$wgAuth->userExists( $this->mUser->getName() ) ) {
wfDebug( __METHOD__.": user does not exist\n" );
return self::NOT_EXISTS;
}
if( !$wgAuth->authenticate( $this->mUser->getName(), $this->mPassword ) ) {
wfDebug( __METHOD__.": \$wgAuth->authenticate() returned false, aborting\n" );
return self::WRONG_PLUGIN_PASS;
}
}
return self::SUCCESS;
}
/**
* Internally authenticate the login request.
*
* This may create a local account as a side effect if the
* authentication plugin allows transparent local account
* creation.
*/
protected function authenticateUserData() {
global $wgUser, $wgAuth;
if ( '' == $this->mName ) {
return self::NO_NAME;
}
global $wgPasswordAttemptThrottle;
$throttleCount = 0;
if ( is_array( $wgPasswordAttemptThrottle ) ) {
$throttleKey = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
$count = $wgPasswordAttemptThrottle['count'];
$period = $wgPasswordAttemptThrottle['seconds'];
global $wgMemc;
$throttleCount = $wgMemc->get( $throttleKey );
if ( !$throttleCount ) {
$wgMemc->add( $throttleKey, 1, $period ); # Start counter
} else if ( $throttleCount < $count ) {
$wgMemc->incr($throttleKey);
} else if ( $throttleCount >= $count ) {
return self::THROTTLED;
}
}
# Unstub $wgUser now, and check to see if we're logging in as the same
# name. As well as the obvious, unstubbing $wgUser (say by calling
# getName()) calls the UserLoadFromSession hook, which potentially
# creates the user in the database. Until we load $wgUser, checking
# for user existence using User::newFromName($name)->getId() below
# will effectively be using stale data.
if ( $wgUser->getName() === $this->mName ) {
wfDebug( __METHOD__.": already logged in as {$this->mName}\n" );
return self::SUCCESS;
}
$this->mExtUser = ExternalUser::newFromName( $this->mName );
# TODO: Allow some magic here for invalid external names, e.g., let the
# user choose a different wiki name.
if( is_null( $this->mUser ) || !User::isUsableName( $this->mUser->getName() ) ) {
return self::ILLEGAL;
}
# If the user doesn't exist in the local database, our only chance
# is for an external auth plugin to autocreate the local user.
if ( $this->mUser->getID() == 0 ) {
if ( $this->canAutoCreate() == self::SUCCESS ) {
$isAutoCreated = true;
wfDebug( __METHOD__.": creating account\n" );
$this->initUser( true );
} else {
return $this->canAutoCreate();
}
} else {
$isAutoCreated = false;
$this->mUser->load();
}
# Give general extensions, such as a captcha, a chance to abort logins
$abort = self::ABORTED;
if( !wfRunHooks( 'AbortLogin', array( $this->mUser, $this->mPassword, &$abort ) ) ) {
return $abort;
}
if( !$this->mUser->checkPassword( $this->mPassword ) ) {
if( $this->mUser->checkTemporaryPassword( $this->mPassword ) ) {
# The e-mailed temporary password should not be used for actual
# logins; that's a very sloppy habit, and insecure if an
# attacker has a few seconds to click "search" on someone's
# open mail reader.
#
# Allow it to be used only to reset the password a single time
# to a new value, which won't be in the user's e-mail archives
#
# For backwards compatibility, we'll still recognize it at the
# login form to minimize surprises for people who have been
# logging in with a temporary password for some time.
#
# As a side-effect, we can authenticate the user's e-mail ad-
# dress if it's not already done, since the temporary password
# was sent via e-mail.
if( !$this->mUser->isEmailConfirmed() ) {
$this->mUser->confirmEmail();
$this->mUser->saveSettings();
}
# At this point we just return an appropriate code/ indicating
# that the UI should show a password reset form; bot interfaces
# etc will probably just fail cleanly here.
$retval = self::RESET_PASS;
} else {
$retval = ( $this->mPassword === '' ) ? self::EMPTY_PASS : self::WRONG_PASS;
}
} else {
$wgAuth->updateUser( $this->mUser );
$wgUser = $this->mUser;
# Reset throttle after a successful login
if( $throttleCount ) {
$wgMemc->delete( $throttleKey );
}
if( $isAutoCreated ) {
# Must be run after $wgUser is set, for correct new user log
wfRunHooks( 'AuthPluginAutoCreate', array( $wgUser ) );
}
$retval = self::SUCCESS;
}
wfRunHooks( 'LoginAuthenticateAudit', array( $this->mUser, $this->mPassword, $retval ) );
return $retval;
}
/**
* Actually add a user to the database.
* Give it a User object that has been initialised with a name.
*
* @param $autocreate Bool is this is an autocreation from an external
* authentication database?
* @param $byEmail Bool is this request going to be handled by sending
* the password by email?
* @return Bool whether creation was successful (should only fail for
* Db errors etc).
*/
protected function initUser( $autocreate=false, $byEmail=false ) {
global $wgAuth;
$fields = array(
'name' => $this->mName,
'password' => $byEmail ? null : $this->mPassword,
'email' => $this->mEmail,
'options' => array(
'rememberpassword' => $this->mRemember ? 1 : 0,
),
);
$this->mUser = User::createNew( $this->mName, $fields );
if( $this->mUser === null ){
return null;
}
# Let old AuthPlugins play with the user
$wgAuth->initUser( $this->mUser, $autocreate );
# Or new ExternalUser plugins
if( $this->mExtUser ) {
$this->mExtUser->link( $this->mUser->getId() );
$email = $this->mExtUser->getPref( 'emailaddress' );
if( $email && !$this->mEmail ) {
$this->mUser->setEmail( $email );
}
}
# Update user count and newuser logs
$ssUpdate = new SiteStatsUpdate( 0, 0, 0, 0, 1 );
$ssUpdate->doUpdate();
if( $autocreate )
$this->mUser->addNewUserLogEntryAutoCreate();
else
$this->mUser->addNewUserLogEntry( $byEmail );
# Run hooks
wfRunHooks( 'AddNewAccount', array( $this->mUser ) );
return true;
}
/**
* Entry point to create a new local account from user-supplied
* data loaded from the WebRequest. We handle initialising the
* email here because it's needed for some backend things; frontend
* interfaces calling this should handle recording things like
* preference options
* @param $byEmail Bool whether to email the user their new password
* @return Status code; Login::SUCCESS == the user was successfully created
*/
public function attemptCreation( $byEmail=false ) {
global $wgUser, $wgOut;
global $wgEnableSorbs, $wgProxyWhitelist;
global $wgMemc, $wgAccountCreationThrottle;
global $wgAuth;
global $wgEmailAuthentication, $wgEmailConfirmToEdit;
if( wfReadOnly() )
return self::READ_ONLY;
# If the user passes an invalid domain, something is fishy
if( !$wgAuth->validDomain( $this->mDomain ) ) {
$this->mCreateResult = 'wrongpassword';
return self::CREATE_BADDOMAIN;
}
# If we are not allowing users to login locally, we should be checking
# to see if the user is actually able to authenticate to the authenti-
# cation server before they create an account (otherwise, they can
# create a local account and login as any domain user). We only need
# to check this for domains that aren't local.
if( !in_array( $this->mDomain, array( 'local', '' ) )
&& !$wgAuth->canCreateAccounts()
&& ( !$wgAuth->userExists( $this->mUsername )
|| !$wgAuth->authenticate( $this->mUsername, $this->mPassword )
) )
{
$this->mCreateResult = 'wrongpassword';
return self::WRONG_PLUGIN_PASS;
}
$ip = wfGetIP();
if ( $wgEnableSorbs && !in_array( $ip, $wgProxyWhitelist ) &&
$wgUser->inSorbsBlacklist( $ip ) )
{
$this->mCreateResult = 'sorbs_create_account_reason';
return self::CREATE_SORBS;
}
# Now create a dummy user ($user) and check if it is valid
$name = trim( $this->mName );
$user = User::newFromName( $name, 'creatable' );
if ( is_null( $user ) ) {
$this->mCreateResult = 'noname';
return self::CREATE_BADNAME;
}
if ( $this->mUser->idForName() != 0 ) {
$this->mCreateResult = 'userexists';
return self::CREATE_EXISTS;
}
# Check that the password is acceptable, if we're actually
# going to use it
if( !$byEmail ){
$valid = $this->mUser->isValidPassword( $this->mPassword );
if ( $valid !== true ) {
$this->mCreateResult = $valid;
return self::CREATE_BADPASS;
}
}
# if you need a confirmed email address to edit, then obviously you
# need an email address. Equally if we're going to send the password to it.
if ( $wgEmailConfirmToEdit && empty( $this->mEmail ) || $byEmail ) {
$this->mCreateResult = 'noemailcreate';
return self::CREATE_NEEDEMAIL;
}
if( !empty( $this->mEmail ) && !User::isValidEmailAddr( $this->mEmail ) ) {
$this->mCreateResult = 'invalidemailaddress';
return self::CREATE_BADEMAIL;
}
# Set some additional data so the AbortNewAccount hook can be used for
# more than just username validation
$this->mUser->setEmail( $this->mEmail );
$this->mUser->setRealName( $this->mRealName );
if( !wfRunHooks( 'AbortNewAccount', array( $this->mUser, &$this->mCreateResult ) ) ) {
# Hook point to add extra creation throttles and blocks
wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" );
return self::ABORTED;
}
if ( $wgAccountCreationThrottle && $wgUser->isPingLimitable() ) {
$key = wfMemcKey( 'acctcreate', 'ip', $ip );
$value = $wgMemc->get( $key );
if ( !$value ) {
$wgMemc->set( $key, 0, 86400 );
}
if ( $value >= $wgAccountCreationThrottle ) {
return self::THROTTLED;
}
$wgMemc->incr( $key );
}
# Since we're creating a new local user, give the external
# database a chance to synchronise.
if( !$wgAuth->addUser( $this->mUser, $this->mPassword, $this->mEmail, $this->mRealName ) ) {
$this->mCreateResult = 'externaldberror';
return self::ABORTED;
}
$result = $this->initUser( false, $byEmail );
if( $result === null )
# It's unlikely we'd get here without some exception
# being thrown, but it's probably possible...
return self::FAILED;
# Send out an email message if needed
if( $byEmail ){
$this->mailPassword( 'createaccount-title', 'createaccount-text' );
if( WikiError::isError( $this->mMailResult ) ){
# FIXME: If the password email hasn't gone out,
# then the account is inaccessible :(
return self::MAIL_ERROR;
} else {
return self::SUCCESS;
}
} else {
if( $wgEmailAuthentication && User::isValidEmailAddr( $this->mUser->getEmail() ) )
{
$this->mMailResult = $this->mUser->sendConfirmationMail();
return WikiError::isError( $this->mMailResult )
? self::MAIL_ERROR
: self::SUCCESS;
}
}
return true;
}
/**
* Email the user a new password, if appropriate to do so.
* @param $text String message key
* @param $title String message key
* @return Status code
*/
public function mailPassword( $text='passwordremindertext', $title='passwordremindertitle' ) {
global $wgUser, $wgOut, $wgAuth, $wgServer, $wgScript, $wgNewPasswordExpiry;
if( wfReadOnly() )
return self::READ_ONLY;
# If we let the email go out, it will take users to a form where
# they are forced to change their password, so don't let us go
# there if we don't want passwords changed.
if( !$wgAuth->allowPasswordChange() )
return self::MAIL_PASSCHANGE_FORBIDDEN;
# Check against blocked IPs
# FIXME: -- should we not?
if( $wgUser->isBlocked() )
return self::MAIL_BLOCKED;
# Check for hooks
if( !wfRunHooks( 'UserLoginMailPassword', array( $this->mName, &$this->mMailResult ) ) )
return self::ABORTED;
# Check against the rate limiter
if( $wgUser->pingLimiter( 'mailpassword' ) )
return self::MAIL_PING_THROTTLED;
# Check for a valid name
if ($this->mName === '' )
return self::NO_NAME;
$this->mUser = User::newFromName( $this->mName );
if( is_null( $this->mUser ) )
return self::NO_NAME;
# And that the resulting user actually exists
if ( $this->mUser->getId() === 0 )
return self::NOT_EXISTS;
# Check against password throttle
if ( $this->mUser->isPasswordReminderThrottled() )
return self::MAIL_PASS_THROTTLED;
# User doesn't have email address set
if ( $this->mUser->getEmail() === '' )
return self::MAIL_EMPTY_EMAIL;
# Don't send to people who are acting fishily by hiding their IP
$ip = wfGetIP();
if( !$ip )
return self::MAIL_BAD_IP;
# Let hooks do things with the data
wfRunHooks( 'User::mailPasswordInternal', array(&$wgUser, &$ip, &$this->mUser) );
$newpass = $this->mUser->randomPassword();
$this->mUser->setNewpassword( $newpass, true );
$this->mUser->saveSettings();
$message = wfMsgExt( $text, array( 'parsemag' ), $ip, $this->mUser->getName(), $newpass,
$wgServer . $wgScript, round( $wgNewPasswordExpiry / 86400 ) );
$this->mMailResult = $this->mUser->sendMail( wfMsg( $title ), $message );
if( WikiError::isError( $this->mMailResult ) ) {
return self::MAIL_ERROR;
} else {
return self::SUCCESS;
}
}
}
/**
* For backwards compatibility, mainly with the state constants, which
* could be referred to in old extensions with the old class name.
* @deprecated
*/
class LoginForm extends Login {}

View file

@ -112,8 +112,8 @@ class SpecialPage {
'Listredirects' => array( 'SpecialPage', 'Listredirects' ),
# Login/create account
'Userlogin' => array( 'SpecialPage', 'Userlogin' ),
'CreateAccount' => array( 'SpecialRedirectToSpecial', 'CreateAccount', 'Userlogin', 'signup', array( 'uselang' ) ),
'Userlogin' => 'SpecialUserLogin',
'CreateAccount' => 'SpecialCreateAccount',
# Users and rights
'Blockip' => array( 'SpecialPage', 'Blockip', 'block' ),

View file

@ -60,7 +60,7 @@ class ApiLogin extends ApiBase {
'wpName' => $params['name'],
'wpPassword' => $params['password'],
'wpDomain' => $params['domain'],
'wpRemember' => ''
'wpRemember' => '1'
));
// Init session if necessary
@ -68,19 +68,11 @@ class ApiLogin extends ApiBase {
wfSetupSession();
}
$loginForm = new LoginForm($req);
switch ($authRes = $loginForm->authenticateUserData()) {
case LoginForm :: SUCCESS :
$loginForm = new Login( $req );
switch ( $authRes = $loginForm->attemptLogin() ) {
case Login::SUCCESS :
global $wgUser, $wgCookiePrefix;
$wgUser->setOption('rememberpassword', 1);
$wgUser->setCookies();
// Run hooks. FIXME: split back and frontend from this hook.
// FIXME: This hook should be placed in the backend
$injected_html = '';
wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
$result['result'] = 'Success';
$result['lguserid'] = intval($wgUser->getId());
$result['lgusername'] = $wgUser->getName();
@ -89,35 +81,35 @@ class ApiLogin extends ApiBase {
$result['sessionid'] = session_id();
break;
case LoginForm :: NO_NAME :
case Login::NO_NAME :
$result['result'] = 'NoName';
break;
case LoginForm :: ILLEGAL :
case Login::ILLEGAL :
$result['result'] = 'Illegal';
break;
case LoginForm :: WRONG_PLUGIN_PASS :
case Login::WRONG_PLUGIN_PASS :
$result['result'] = 'WrongPluginPass';
break;
case LoginForm :: NOT_EXISTS :
case Login::NOT_EXISTS :
$result['result'] = 'NotExists';
break;
case LoginForm :: WRONG_PASS :
case Login::WRONG_PASS :
$result['result'] = 'WrongPass';
break;
case LoginForm :: EMPTY_PASS :
case Login::EMPTY_PASS :
$result['result'] = 'EmptyPass';
break;
case LoginForm :: CREATE_BLOCKED :
case Login::CREATE_BLOCKED :
$result['result'] = 'CreateBlocked';
$result['details'] = 'Your IP address is blocked from account creation';
break;
case LoginForm :: THROTTLED :
case Login::THROTTLED :
global $wgPasswordAttemptThrottle;
$result['result'] = 'Throttled';
$result['wait'] = intval($wgPasswordAttemptThrottle['seconds']);
$result['wait'] = intval( $wgPasswordAttemptThrottle['seconds'] );
break;
default :
ApiBase :: dieDebug(__METHOD__, "Unhandled case value: {$authRes}");
ApiBase::dieDebug( __METHOD__, "Unhandled case value: {$authRes}" );
}
$this->getResult()->addValue(null, 'login', $result);

View file

@ -0,0 +1,519 @@
<?php
/**
* Special page for creating/registering new user accounts.
* @ingroup SpecialPage
*/
class SpecialCreateAccount extends SpecialPage {
var $mUsername, $mPassword, $mRetype, $mReturnTo, $mPosted;
var $mCreateaccountMail, $mRemember, $mEmail, $mDomain, $mLanguage;
var $mReturnToQuery;
protected $mLogin;
public $mDomains = array();
public $mUseEmail = true; # Can be switched off by AuthPlugins etc
public $mUseRealname = true;
public $mUseRemember = true;
public $mFormHeader = '';
public $mFormFields = array(
'Name' => array(
'type' => 'text',
'label-message' => 'yourname',
'id' => 'wpName2',
'tabindex' => '1',
'size' => '20',
'required' => '1',
'autofocus' => '',
),
'Password' => array(
'type' => 'password',
'label-message' => 'yourpassword',
'size' => '20',
'id' => 'wpPassword2',
'required' => '',
),
'Retype' => array(
'type' => 'password',
'label-message' => 'yourpasswordagain',
'size' => '20',
'id' => 'wpRetype',
'required' => '',
),
'Email' => array(
'type' => 'email',
'label-message' => 'youremail',
'size' => '20',
'id' => 'wpEmail',
),
'RealName' => array(
'type' => 'text',
'label-message' => 'yourrealname',
'id' => 'wpRealName',
'tabindex' => '1',
'size' => '20',
),
'Remember' => array(
'type' => 'check',
'label-message' => 'remembermypassword',
'id' => 'wpRemember',
),
'Domain' => array(
'type' => 'select',
'id' => 'wpDomain',
'label-message' => 'yourdomainname',
'options' => null,
'default' => null,
),
);
public function __construct(){
parent::__construct( 'CreateAccount', 'createaccount' );
$this->mLogin = new Login();
$this->mFormFields['RealName']['label-help'] = 'prefs-help-realname';
}
public function execute( $par ){
global $wgUser, $wgOut;
$this->setHeaders();
$this->loadQuery();
# Block signup here if in readonly. Keeps user from
# going through the process (filling out data, etc)
# and being informed later.
if ( wfReadOnly() ) {
$wgOut->readOnlyPage();
return;
}
# Bail out straightaway on permissions errors
if ( !$this->userCanExecute( $wgUser ) ) {
$this->displayRestrictionError();
return;
} elseif ( $wgUser->isBlockedFromCreateAccount() ) {
$this->userBlockedMessage();
return;
} elseif ( count( $permErrors = $this->getTitle()->getUserPermissionsErrors( 'createaccount', $wgUser, true ) )>0 ) {
$wgOut->showPermissionsErrorPage( $permErrors, 'createaccount' );
return;
}
if( $this->mPosted ) {
$this->addNewAccount( $this->mCreateaccountMail );
} else {
$this->showMainForm('');
}
}
/**
* Load the member variables from the request parameters
*/
protected function loadQuery(){
global $wgRequest, $wgAuth, $wgHiddenPrefs, $wgEnableEmail, $wgRedirectOnLogin;
$this->mCreateaccountMail = $wgRequest->getCheck( 'wpCreateaccountMail' )
&& $wgEnableEmail;
$this->mUsername = $wgRequest->getText( 'wpName' );
$this->mPassword = $wgRequest->getText( 'wpPassword' );
$this->mRetype = $wgRequest->getText( 'wpRetype' );
$this->mDomain = $wgRequest->getText( 'wpDomain' );
$this->mReturnTo = $wgRequest->getVal( 'returnto' );
$this->mReturnToQuery = $wgRequest->getVal( 'returntoquery' );
$this->mPosted = $wgRequest->wasPosted();
$this->mCreateaccountMail = $wgRequest->getCheck( 'wpCreateaccountMail' )
&& $wgEnableEmail;
$this->mRemember = $wgRequest->getCheck( 'wpRemember' );
$this->mLanguage = $wgRequest->getText( 'uselang' );
if ( $wgRedirectOnLogin ) {
$this->mReturnTo = $wgRedirectOnLogin;
$this->mReturnToQuery = '';
}
if( $wgEnableEmail ) {
$this->mEmail = $wgRequest->getText( 'wpEmail' );
} else {
$this->mEmail = '';
}
if( !in_array( 'realname', $wgHiddenPrefs ) ) {
$this->mRealName = $wgRequest->getText( 'wpRealName' );
} else {
$this->mRealName = '';
}
if( !$wgAuth->validDomain( $this->mDomain ) ) {
$this->mDomain = 'invaliddomain';
}
$wgAuth->setDomain( $this->mDomain );
# When switching accounts, it sucks to get automatically logged out
$returnToTitle = Title::newFromText( $this->mReturnTo );
if( is_object( $returnToTitle ) && $returnToTitle->isSpecial( 'Userlogout' ) ) {
$this->mReturnTo = '';
$this->mReturnToQuery = '';
}
}
/**
* Create a new user account from the provided data
*/
protected function addNewAccount( $byEmail=false ) {
global $wgUser, $wgEmailAuthentication;
# Do a quick check that the user actually managed to type
# the password in the same both times
if ( 0 != strcmp( $this->mPassword, $this->mRetype ) ) {
return $this->showMainForm( wfMsgExt( 'badretype', 'parseinline' ) );
}
# Create the account and abort if there's a problem doing so
$status = $this->mLogin->attemptCreation( $byEmail );
switch( $status ){
case Login::SUCCESS:
case Login::MAIL_ERROR:
break;
case Login::CREATE_BADDOMAIN:
case Login::CREATE_EXISTS:
case Login::NO_NAME:
case Login::CREATE_NEEDEMAIL:
case Login::CREATE_BADEMAIL:
case Login::CREATE_BADNAME:
case Login::WRONG_PLUGIN_PASS:
case Login::ABORTED:
return $this->showMainForm( wfMsgExt( $this->mLogin->mCreateResult, 'parseinline' ) );
case Login::CREATE_SORBS:
return $this->showMainForm( wfMsgExt( 'sorbs_create_account_reason', 'parseinline' ) . ' (' . wfGetIP() . ')' );
case Login::CREATE_BLOCKED:
return $this->userBlockedMessage();
case Login::CREATE_BADPASS:
global $wgMinimalPasswordLength;
return $this->showMainForm( wfMsgExt( $this->mLogin->mCreateResult, array( 'parsemag' ), $wgMinimalPasswordLength ) );
case Login::THROTTLED:
global $wgAccountCreationThrottle;
return $this->showMainForm( wfMsgExt( 'acct_creation_throttle_hit', array( 'parseinline' ), $wgAccountCreationThrottle ) );
default:
throw new MWException( "Unhandled status code $status in " . __METHOD__ );
}
# If we showed up language selection links, and one was in use, be
# smart (and sensible) and save that language as the user's preference
global $wgLoginLanguageSelector;
if( $wgLoginLanguageSelector && $this->mLanguage )
$this->mLogin->mUser->setOption( 'language', $this->mLanguage );
$this->mLogin->mUser->saveSettings();
if( $byEmail ) {
if( $result == Login::MAIL_ERROR ){
# FIXME: we are totally screwed if we end up here...
$this->showMainForm( wfMsgExt( 'mailerror', 'parseinline', $this->mLogin->mMailResult->getMessage() ) );
} else {
$wgOut->setPageTitle( wfMsg( 'accmailtitle' ) );
$wgOut->addWikiMsg( 'accmailtext', $this->mLogin->mUser->getName(), $this->mLogin->mUser->getEmail() );
$wgOut->returnToMain( false );
}
} else {
# There might be a message stored from the confirmation mail
# send, which we can display.
if( $wgEmailAuthentication && $this->mLogin->mMailResult ) {
global $wgOut;
if( WikiError::isError( $this->mLogin->mMailResult ) ) {
$wgOut->addWikiMsg( 'confirmemail_sendfailed', $this->mLogin->mMailResult->getMessage() );
} else {
$wgOut->addWikiMsg( 'confirmemail_oncreate' );
}
}
# If not logged in, assume the new account as the current
# one and set session cookies then show a "welcome" message
# or a "need cookies" message as needed
if( $wgUser->isAnon() ) {
$wgUser = $this->mLogin->mUser;
$wgUser->setCookies();
if( $this->hasSessionCookie() ) {
return $this->successfulCreation();
} else {
return $this->cookieRedirectCheck();
}
} else {
# Show confirmation that the account was created
global $wgOut;
$self = SpecialPage::getTitleFor( 'Userlogin' );
$wgOut->setPageTitle( wfMsgHtml( 'accountcreated' ) );
$wgOut->addHTML( wfMsgWikiHtml( 'accountcreatedtext', $this->mLogin->mUser->getName() ) );
$wgOut->returnToMain( false, $self );
return true;
}
}
}
/**
* Run any hooks registered for logins, then
* display a message welcoming the user.
*/
protected function successfulCreation(){
global $wgUser, $wgOut;
# Run any hooks; display injected HTML
$injected_html = '';
wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
SpecialUserLogin::displaySuccessfulLogin(
'welcomecreation',
$injected_html,
$this->mReturnTo,
$this->mReturnToQuery );
}
/**
* Display a message indicating that account creation from their IP has
* been blocked by a (range)block with 'block account creation' enabled.
* It's likely that this feature will be used for blocking large numbers
* of innocent people, e.g. range blocks on schools. Don't blame it on
* the user. There's a small chance that it really is the user's fault,
* i.e. the username is blocked and they haven't bothered to log out
* before trying to create an account to evade it, but we'll leave that
* to their guilty conscience to figure out...
*/
protected function userBlockedMessage() {
global $wgOut, $wgUser;
$wgOut->setPageTitle( wfMsg( 'cantcreateaccounttitle' ) );
$wgOut->setRobotPolicy( 'noindex,nofollow' );
$wgOut->setArticleRelated( false );
$ip = wfGetIP();
$blocker = User::whoIs( $wgUser->mBlock->mBy );
$block_reason = $wgUser->mBlock->mReason;
if ( strval( $block_reason ) === '' ) {
$block_reason = wfMsgExt( 'blockednoreason', 'parseinline' );
}
$wgOut->addWikiMsg( 'cantcreateaccount-text', $ip, $block_reason, $blocker );
$wgOut->returnToMain( false );
}
/**
* Show the main input form, with an appropriate error message
* from a previous iteration, if necessary
* @param $msg String HTML of message received previously
* @param $msgtype String type of message, usually 'error'
*/
protected function showMainForm( $msg, $msgtype = 'error' ) {
global $wgUser, $wgOut, $wgHiddenPrefs, $wgEnableEmail;
global $wgCookiePrefix, $wgLoginLanguageSelector;
global $wgAuth, $wgEmailConfirmToEdit, $wgCookieExpiration;
# Parse the error message if we got one
if( $msg ){
if( $msgtype == 'error' ){
$msg = wfMsgExt( 'loginerror', 'parseinline' ) . ' ' . $msg;
}
$msg = Html::rawElement(
'div',
array( 'class' => $msgtype . 'box' ),
$msg
);
} else {
$msg = '';
}
# Make sure the returnTo strings don't get lost if the
# user changes language, etc
$linkq = array();
if ( !empty( $this->mReturnTo ) ) {
$linkq['returnto'] = wfUrlencode( $this->mReturnTo );
if ( !empty( $this->mReturnToQuery ) )
$linkq['returntoquery'] = wfUrlencode( $this->mReturnToQuery );
}
# Pass any language selection on to the mode switch link
if( $wgLoginLanguageSelector && $this->mLanguage )
$linkq['uselang'] = $this->mLanguage;
$skin = $wgUser->getSkin();
$link = $skin->link(
SpecialPage::getTitleFor( 'Userlogin' ),
wfMsgHtml( 'gotaccountlink' ),
array(),
$linkq );
$link = $wgUser->isLoggedIn()
? ''
: wfMsgWikiHtml( 'gotaccount', $link );
# Prepare language selection links as needed
$langSelector = $wgLoginLanguageSelector
? Html::rawElement(
'div',
array( 'id' => 'languagelinks' ),
SpecialUserLogin::makeLanguageSelector( $this->getTitle(), $this->mReturnTo ) )
: '';
# Add a 'send password by email' button if available
$buttons = '';
if( $wgEnableEmail && $wgUser->isLoggedIn() ){
$buttons = Html::element(
'input',
array(
'type' => 'submit',
'name' => 'wpCreateaccountMail',
'value' => wfMsg( 'createaccountmail' ),
'id' => 'wpCreateaccountMail',
)
);
}
# Give authentication and captcha plugins a chance to
# modify the form, by hook or by using $wgAuth
$wgAuth->modifyUITemplate( $this, 'new' );
wfRunHooks( 'UserCreateForm', array( &$this ) );
# The most likely use of the hook is to enable domains;
# check that now, and add fields if necessary
if( $this->mDomains ){
$this->mFormFields['Domain']['options'] = $this->mDomains;
$this->mFormFields['Domain']['default'] = $this->mDomain;
} else {
unset( $this->mFormFields['Domain'] );
}
# Or to switch email on or off
if( !$wgEnableEmail || !$this->mUseEmail ){
unset( $this->mFormFields['Email'] );
} else {
if( $wgEmailConfirmToEdit ){
$this->mFormFields['Email']['label-help'] = 'prefs-help-email-required';
$this->mFormFields['Email']['required'] = '';
} else {
$this->mFormFields['Email']['label-help'] = 'prefs-help-email';
}
}
# Or to play with realname
if( in_array( 'realname', $wgHiddenPrefs ) || !$this->mUseRealname ){
unset( $this->mFormFields['Realname'] );
}
# Or to tweak the 'remember my password' checkbox
if( !($wgCookieExpiration > 0) || !$this->mUseRemember ){
# Remove it altogether
unset( $this->mFormFields['Remember'] );
} elseif( $wgUser->getOption( 'rememberpassword' ) || $this->mRemember ){
# Or check it by default
# FIXME: this doesn't always work?
$this->mFormFields['Remember']['checked'] = '1';
}
$form = new HTMLForm( $this->mFormFields, '' );
$form->setTitle( $this->getTitle() );
$form->setSubmitText( wfMsg( 'createaccount' ) );
$form->setSubmitId( 'wpCreateaccount' );
$form->suppressReset();
$form->loadData();
$formContents = ''
. Html::rawElement( 'p', array( 'id' => 'userloginlink' ),
$link )
. $this->mFormHeader
. $langSelector
. $form->getBody()
. $form->getButtons()
. $buttons
. Xml::hidden( 'returnto', $this->mReturnTo )
. Xml::hidden( 'returntoquery', $this->mReturnToQuery )
;
$wgOut->setPageTitle( wfMsg( 'createaccount' ) );
$wgOut->setRobotPolicy( 'noindex,nofollow' );
$wgOut->setArticleRelated( false );
$wgOut->disallowUserJs(); # Stop malicious userscripts sniffing passwords
$wgOut->addHTML(
Html::rawElement(
'div',
array( 'id' => 'loginstart' ),
wfMsgExt( 'loginstart', array( 'parseinline' ) )
) .
$msg .
Html::rawElement(
'div',
array( 'id' => 'userloginForm' ),
$form->wrapForm( $formContents )
) .
Html::rawElement(
'div',
array( 'id' => 'loginend' ),
wfMsgExt( 'loginend', array( 'parseinline' ) )
)
);
}
/**
* Check if a session cookie is present.
*
* This will not pick up a cookie set during _this_ request, but is meant
* to ensure that the client is returning the cookie which was set on a
* previous pass through the system.
*
* @private
*/
protected function hasSessionCookie() {
global $wgDisableCookieCheck, $wgRequest;
return $wgDisableCookieCheck ? true : $wgRequest->checkSessionCookie();
}
/**
* Do a redirect back to the same page, so we can check any
* new session cookies.
*/
protected function cookieRedirectCheck() {
global $wgOut;
$query = array( 'wpCookieCheck' => '1' );
if ( $this->mReturnTo ) $query['returnto'] = $this->mReturnTo;
$check = $this->getTitle()->getFullURL( $query );
return $wgOut->redirect( $check );
}
/**
* Check the cookies and show errors if they're not enabled.
* @param $type String action being performed
*/
protected function onCookieRedirectCheck() {
if ( !$this->hasSessionCookie() ) {
return $this->mainLoginForm( wfMsgExt( 'nocookiesnew', array( 'parseinline' ) ) );
} else {
return SpecialUserlogin::successfulLogin(
array( 'welcomecreate' ),
$this->mReturnTo,
$this->mReturnToQuery
);
}
}
/**
* Since the UserCreateForm hook was changed to pass a SpecialPage
* instead of a QuickTemplate derivative, old extensions might
* easily try calling these methods expecing them to exist. Tempting
* though it is to let them have the fatal error, let's at least
* fail gracefully...
* @deprecated
*/
public function set(){
wfDeprecated( __METHOD__ );
}
public function addInputItem(){
wfDeprecated( __METHOD__ );
}
}

View file

@ -12,6 +12,48 @@ class SpecialResetpass extends SpecialPage {
public function __construct() {
parent::__construct( 'Resetpass' );
}
public $mFormFields = array(
'Name' => array(
'type' => 'info',
'label-message' => 'yourname',
'default' => '',
),
'Password' => array(
'type' => 'password',
'label-message' => 'oldpassword',
'size' => '20',
'id' => 'wpPassword',
'required' => '',
),
'NewPassword' => array(
'type' => 'password',
'label-message' => 'newpassword',
'size' => '20',
'id' => 'wpNewPassword',
'required' => '',
),
'Retype' => array(
'type' => 'password',
'label-message' => 'retypenew',
'size' => '20',
'id' => 'wpRetype',
'required' => '',
),
'Remember' => array(
'type' => 'check',
'label-message' => 'remembermypassword',
'id' => 'wpRemember',
),
);
public $mSubmitMsg = 'resetpass-submit-loggedin';
public $mHeaderMsg = '';
public $mHeaderMsgType = 'error';
protected $mUsername;
protected $mOldpass;
protected $mNewpass;
protected $mRetype;
/**
* Main execution point
@ -19,176 +61,142 @@ class SpecialResetpass extends SpecialPage {
function execute( $par ) {
global $wgUser, $wgAuth, $wgOut, $wgRequest;
$this->mUserName = $wgRequest->getVal( 'wpName' );
$this->mUsername = $wgRequest->getVal( 'wpName', $wgUser->getName() );
$this->mOldpass = $wgRequest->getVal( 'wpPassword' );
$this->mNewpass = $wgRequest->getVal( 'wpNewPassword' );
$this->mRetype = $wgRequest->getVal( 'wpRetype' );
$this->mRemember = $wgRequest->getVal( 'wpRemember' );
$this->mReturnTo = $wgRequest->getVal( 'returnto' );
$this->mReturnToQuery = $wgRequest->getVal( 'returntoquery' );
$this->setHeaders();
$this->outputHeader();
if( !$wgAuth->allowPasswordChange() ) {
$this->error( wfMsg( 'resetpass_forbidden' ) );
return;
$wgOut->showErrorPage( 'errorpagetitle', 'resetpass_forbidden' );
return false;
}
if( !$wgRequest->wasPosted() && !$wgUser->isLoggedIn() ) {
$this->error( wfMsg( 'resetpass-no-info' ) );
return;
$wgOut->showErrorPage( 'errorpagetitle', 'resetpass-no-info' );
return false;
}
if( $wgRequest->wasPosted() && $wgUser->matchEditToken( $wgRequest->getVal('token') ) ) {
try {
$this->attemptReset( $this->mNewpass, $this->mRetype );
$wgOut->addWikiMsg( 'resetpass_success' );
if( !$wgUser->isLoggedIn() ) {
$data = array(
'action' => 'submitlogin',
'wpName' => $this->mUserName,
'wpPassword' => $this->mNewpass,
'returnto' => $wgRequest->getVal( 'returnto' ),
);
if( $wgRequest->getCheck( 'wpRemember' ) ) {
$data['wpRemember'] = 1;
}
$login = new LoginForm( new FauxRequest( $data, true ) );
$login->execute();
if( $wgRequest->wasPosted()
&& $wgUser->matchEditToken( $wgRequest->getVal('wpEditToken') )
&& $this->attemptReset() )
{
# Log the user in if they're not already (ie we're
# coming from the e-mail-password-reset route
if( !$wgUser->isLoggedIn() ) {
$data = array(
'wpName' => $this->mUsername,
'wpPassword' => $this->mNewpass,
'returnto' => $this->mReturnTo,
);
if( $this->mRemember ) {
$data['wpRemember'] = 1;
}
$titleObj = Title::newFromText( $wgRequest->getVal( 'returnto' ) );
if ( !$titleObj instanceof Title ) {
$titleObj = Title::newMainPage();
}
$wgOut->redirect( $titleObj->getFullURL() );
} catch( PasswordError $e ) {
$this->error( $e->getMessage() );
$login = new Login( new FauxRequest( $data, true ) );
$login->attemptLogin();
# Redirect out to the appropriate target.
SpecialUserlogin::successfulLogin(
'resetpass_success',
$this->mReturnTo,
$this->mReturnToQuery,
$login->mLoginResult
);
} else {
# Redirect out to the appropriate target.
SpecialUserlogin::successfulLogin(
'resetpass_success',
$this->mReturnTo,
$this->mReturnToQuery
);
}
} else {
$this->showForm();
}
$this->showForm();
}
function error( $msg ) {
global $wgOut;
$wgOut->addHTML( Xml::element('p', array( 'class' => 'error' ), $msg ) );
}
function showForm() {
global $wgOut, $wgUser, $wgRequest;
global $wgOut, $wgUser;
$wgOut->disallowUserJs();
$self = SpecialPage::getTitleFor( 'Resetpass' );
if ( !$this->mUserName ) {
$this->mUserName = $wgUser->getName();
}
$rememberMe = '';
if ( !$wgUser->isLoggedIn() ) {
$rememberMe = '<tr>' .
'<td></td>' .
'<td class="mw-input">' .
Xml::checkLabel( wfMsg( 'remembermypassword' ),
'wpRemember', 'wpRemember',
$wgRequest->getCheck( 'wpRemember' ) ) .
'</td>' .
'</tr>';
$submitMsg = 'resetpass_submit';
$oldpassMsg = 'resetpass-temp-password';
if( $wgUser->isLoggedIn() ){
unset( $this->mFormFields['Remember'] );
} else {
$oldpassMsg = 'oldpassword';
$submitMsg = 'resetpass-submit-loggedin';
# Request is coming from Special:UserLogin after it
# authenticated someone with a temporary password.
$this->mFormFields['Password']['label-message'] = 'resetpass-temp-password';
$this->mSubmitMsg = 'resetpass_submit';
}
$this->mFormFields['Name']['default'] = $this->mUsername;
$header = $this->mHeaderMsg
? Xml::element( 'div', array( 'class' => "{$this->mHeaderMsgType}box" ), wfMsg( $this->mHeaderMsg ) )
: '';
$form = new HTMLForm( $this->mFormFields, '' );
$form->suppressReset();
$form->setSubmitText( wfMsg( $this->mSubmitMsg ) );
$form->setTitle( $this->getTitle() );
$form->loadData();
$formContents = ''
. $form->getBody()
. $form->getButtons()
. $form->getHiddenFields()
. Html::hidden( 'wpName', $this->mUsername )
. Html::hidden( 'returnto', $this->mReturnTo )
;
$formOutput = $form->wrapForm( $formContents );
$wgOut->addHTML(
Xml::fieldset( wfMsg( 'resetpass_header' ) ) .
Xml::openElement( 'form',
array(
'method' => 'post',
'action' => $self->getLocalUrl(),
'id' => 'mw-resetpass-form' ) ) . "\n" .
Xml::hidden( 'token', $wgUser->editToken() ) . "\n" .
Xml::hidden( 'wpName', $this->mUserName ) . "\n" .
Xml::hidden( 'returnto', $wgRequest->getVal( 'returnto' ) ) . "\n" .
wfMsgExt( 'resetpass_text', array( 'parse' ) ) . "\n" .
Xml::openElement( 'table', array( 'id' => 'mw-resetpass-table' ) ) . "\n" .
$this->pretty( array(
array( 'wpName', 'username', 'text', $this->mUserName ),
array( 'wpPassword', $oldpassMsg, 'password', $this->mOldpass ),
array( 'wpNewPassword', 'newpassword', 'password', null ),
array( 'wpRetype', 'retypenew', 'password', null ),
) ) . "\n" .
$rememberMe .
"<tr>\n" .
"<td></td>\n" .
'<td class="mw-input">' .
Xml::submitButton( wfMsg( $submitMsg ) ) .
"</td>\n" .
"</tr>\n" .
Xml::closeElement( 'table' ) .
Xml::closeElement( 'form' ) .
Xml::closeElement( 'fieldset' ) . "\n"
$header
. Html::rawElement( 'fieldset', array( 'class' => 'visualClear' ), ''
. Html::element( 'legend', array(), wfMsg( 'resetpass_header' ) )
. $formOutput
)
);
}
function pretty( $fields ) {
$out = '';
foreach ( $fields as $list ) {
list( $name, $label, $type, $value ) = $list;
if( $type == 'text' ) {
$field = htmlspecialchars( $value );
} else {
$attribs = array( 'id' => $name );
if ( $name == 'wpNewPassword' || $name == 'wpRetype' ) {
$attribs = array_merge( $attribs,
User::passwordChangeInputAttribs() );
}
if ( $name == 'wpPassword' ) {
$attribs[] = 'autofocus';
}
$field = Html::input( $name, $value, $type, $attribs );
}
$out .= "<tr>\n";
$out .= "\t<td class='mw-label'>";
if ( $type != 'text' )
$out .= Xml::label( wfMsg( $label ), $name );
else
$out .= wfMsgHtml( $label );
$out .= "</td>\n";
$out .= "\t<td class='mw-input'>";
$out .= $field;
$out .= "</td>\n";
$out .= "</tr>";
}
return $out;
}
/**
* @throws PasswordError when cannot set the new password because requirements not met.
* Try to reset the user's password
*/
protected function attemptReset( $newpass, $retype ) {
$user = User::newFromName( $this->mUserName );
protected function attemptReset() {
$user = User::newFromName( $this->mUsername );
if( !$user || $user->isAnon() ) {
throw new PasswordError( 'no such user' );
$this->mHeaderMsg = 'no such user';
return false;
}
if( $newpass !== $retype ) {
wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'badretype' ) );
throw new PasswordError( wfMsg( 'badretype' ) );
if( $this->mNewpass !== $this->mRetype ) {
wfRunHooks( 'PrefsPasswordAudit', array( $user, $this->mNewpass, 'badretype' ) );
$this->mHeaderMsg = 'badretype';
return false;
}
if( !$user->checkTemporaryPassword($this->mOldpass) && !$user->checkPassword($this->mOldpass) ) {
wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'wrongpassword' ) );
throw new PasswordError( wfMsg( 'resetpass-wrong-oldpass' ) );
wfRunHooks( 'PrefsPasswordAudit', array( $user, $this->mNewpass, 'wrongpassword' ) );
$this->mHeaderMsg = 'resetpass-wrong-oldpass';
return false;
}
try {
$user->setPassword( $this->mNewpass );
wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'success' ) );
wfRunHooks( 'PrefsPasswordAudit', array( $user, $this->mNewpass, 'success' ) );
$this->mNewpass = $this->mOldpass = $this->mRetypePass = '';
} catch( PasswordError $e ) {
wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'error' ) );
throw new PasswordError( $e->getMessage() );
return;
wfRunHooks( 'PrefsPasswordAudit', array( $user, $this->mNewpass, 'error' ) );
$this->mHeaderMsg = $e->getMessage();
return false;
}
$user->setCookies();
$user->saveSettings();
return true;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,323 +0,0 @@
<?php
/**
* @defgroup Templates Templates
* @file
* @ingroup Templates
*/
if( !defined( 'MEDIAWIKI' ) ) die( -1 );
/**
* HTML template for Special:Userlogin form
* @ingroup Templates
*/
class UserloginTemplate extends QuickTemplate {
function execute() {
if( $this->data['message'] ) {
?>
<div class="<?php $this->text('messagetype') ?>box">
<?php if ( $this->data['messagetype'] == 'error' ) { ?>
<h2><?php $this->msg('loginerror') ?></h2>
<?php } ?>
<?php $this->html('message') ?>
</div>
<div class="visualClear"></div>
<?php } ?>
<div id="loginstart"><?php $this->msgWiki( 'loginstart' ); ?></div>
<div id="userloginForm">
<form name="userlogin" method="post" action="<?php $this->text('action') ?>">
<h2><?php $this->msg('login') ?></h2>
<p id="userloginlink"><?php $this->html('link') ?></p>
<?php $this->html('header'); /* pre-table point for form plugins... */ ?>
<div id="userloginprompt"><?php $this->msgWiki('loginprompt') ?></div>
<?php if( @$this->haveData( 'languages' ) ) { ?><div id="languagelinks"><p><?php $this->html( 'languages' ); ?></p></div><?php } ?>
<table>
<tr>
<td class="mw-label"><label for='wpName1'><?php $this->msg('yourname') ?></label></td>
<td class="mw-input">
<?php
echo Html::input( 'wpName', $this->data['name'], 'text', array(
'class' => 'loginText',
'id' => 'wpName1',
'tabindex' => '1',
'size' => '20',
'required'
# Can't do + array( 'autofocus' ) because + for arrays in PHP
# only works right for associative arrays! Thanks, PHP.
) + ( $this->data['name'] ? array() : array( 'autofocus' => '' ) ) ); ?>
</td>
</tr>
<tr>
<td class="mw-label"><label for='wpPassword1'><?php $this->msg('yourpassword') ?></label></td>
<td class="mw-input">
<?php
echo Html::input( 'wpPassword', null, 'password', array(
'class' => 'loginPassword',
'id' => 'wpPassword1',
'tabindex' => '2',
'size' => '20'
) + ( $this->data['name'] ? array( 'autofocus' ) : array() ) ); ?>
</td>
</tr>
<?php if( $this->data['usedomain'] ) {
$doms = "";
foreach( $this->data['domainnames'] as $dom ) {
$doms .= "<option>" . htmlspecialchars( $dom ) . "</option>";
}
?>
<tr id="mw-user-domain-section">
<td class="mw-label"><?php $this->msg( 'yourdomainname' ) ?></td>
<td class="mw-input">
<select name="wpDomain" value="<?php $this->text( 'domain' ) ?>"
tabindex="3">
<?php echo $doms ?>
</select>
</td>
</tr>
<?php }
if( $this->data['canremember'] ) { ?>
<tr>
<td></td>
<td class="mw-input">
<?php
echo Html::input( 'wpRemember', '1', 'checkbox', array(
'tabindex' => '4',
'id' => 'wpRemember'
) + ( $this->data['remember'] ? array( 'checked' ) : array() ) ); ?>
<label for="wpRemember"><?php $this->msg('remembermypassword') ?></label>
</td>
</tr>
<?php } ?>
<tr>
<td></td>
<td class="mw-submit">
<?php
echo Html::input( 'wpLoginAttempt', wfMsg( 'login' ), 'submit', array(
'id' => 'wpLoginAttempt',
'tabindex' => '5'
) );
if ( $this->data['useemail'] && $this->data['canreset'] ) {
echo '&nbsp;';
echo Html::input( 'wpMailmypassword', wfMsg( 'mailmypassword' ), 'submit', array(
'id' => 'wpMailmypassword',
'tabindex' => '6'
) );
} ?>
</td>
</tr>
</table>
<?php if( @$this->haveData( 'uselang' ) ) { ?><input type="hidden" name="uselang" value="<?php $this->text( 'uselang' ); ?>" /><?php } ?>
</form>
</div>
<div id="loginend"><?php $this->msgWiki( 'loginend' ); ?></div>
<?php
}
}
/**
* @ingroup Templates
*/
class UsercreateTemplate extends QuickTemplate {
function addInputItem( $name, $value, $type, $msg, $helptext = false ) {
$this->data['extraInput'][] = array(
'name' => $name,
'value' => $value,
'type' => $type,
'msg' => $msg,
'helptext' => $helptext,
);
}
function execute() {
if( $this->data['message'] ) {
?>
<div class="<?php $this->text('messagetype') ?>box">
<?php if ( $this->data['messagetype'] == 'error' ) { ?>
<h2><?php $this->msg('loginerror') ?></h2>
<?php } ?>
<?php $this->html('message') ?>
</div>
<div class="visualClear"></div>
<?php } ?>
<div id="userlogin">
<form name="userlogin2" id="userlogin2" method="post" action="<?php $this->text('action') ?>">
<h2><?php $this->msg('createaccount') ?></h2>
<p id="userloginlink"><?php $this->html('link') ?></p>
<?php $this->html('header'); /* pre-table point for form plugins... */ ?>
<?php if( @$this->haveData( 'languages' ) ) { ?><div id="languagelinks"><p><?php $this->html( 'languages' ); ?></p></div><?php } ?>
<table>
<tr>
<td class="mw-label"><label for='wpName2'><?php $this->msg('yourname') ?></label></td>
<td class="mw-input">
<?php
echo Html::input( 'wpName', $this->data['name'], 'text', array(
'class' => 'loginText',
'id' => 'wpName2',
'tabindex' => '1',
'size' => '20',
'required',
'autofocus'
) ); ?>
</td>
</tr>
<tr>
<td class="mw-label"><label for='wpPassword2'><?php $this->msg('yourpassword') ?></label></td>
<td class="mw-input">
<?php
echo Html::input( 'wpPassword', null, 'password', array(
'class' => 'loginPassword',
'id' => 'wpPassword2',
'tabindex' => '2',
'size' => '20'
) + User::passwordChangeInputAttribs() ); ?>
</td>
</tr>
<?php if( $this->data['usedomain'] ) {
$doms = "";
foreach( $this->data['domainnames'] as $dom ) {
$doms .= "<option>" . htmlspecialchars( $dom ) . "</option>";
}
?>
<tr>
<td class="mw-label"><?php $this->msg( 'yourdomainname' ) ?></td>
<td class="mw-input">
<select name="wpDomain" value="<?php $this->text( 'domain' ) ?>"
tabindex="3">
<?php echo $doms ?>
</select>
</td>
</tr>
<?php } ?>
<tr>
<td class="mw-label"><label for='wpRetype'><?php $this->msg('yourpasswordagain') ?></label></td>
<td class="mw-input">
<?php
echo Html::input( 'wpRetype', null, 'password', array(
'class' => 'loginPassword',
'id' => 'wpRetype',
'tabindex' => '4',
'size' => '20'
) + User::passwordChangeInputAttribs() ); ?>
</td>
</tr>
<tr>
<?php if( $this->data['useemail'] ) { ?>
<td class="mw-label"><label for='wpEmail'><?php $this->msg('youremail') ?></label></td>
<td class="mw-input">
<?php
echo Html::input( 'wpEmail', $this->data['email'], 'email', array(
'class' => 'loginText',
'id' => 'wpEmail',
'tabindex' => '5',
'size' => '20'
) ); ?>
<div class="prefsectiontip">
<?php if( $this->data['emailrequired'] ) {
$this->msgWiki('prefs-help-email-required');
} else {
$this->msgWiki('prefs-help-email');
} ?>
</div>
</td>
<?php } ?>
<?php if( $this->data['userealname'] ) { ?>
</tr>
<tr>
<td class="mw-label"><label for='wpRealName'><?php $this->msg('yourrealname') ?></label></td>
<td class="mw-input">
<input type='text' class='loginText' name="wpRealName" id="wpRealName"
tabindex="6"
value="<?php $this->text('realname') ?>" size='20' />
<div class="prefsectiontip">
<?php $this->msgWiki('prefs-help-realname'); ?>
</div>
</td>
<?php } ?>
</tr>
<?php if( $this->data['canremember'] ) { ?>
<tr>
<td></td>
<td class="mw-input">
<input type='checkbox' name="wpRemember"
tabindex="7"
value="1" id="wpRemember"
<?php if( $this->data['remember'] ) { ?>checked="checked"<?php } ?>
/> <label for="wpRemember"><?php $this->msg('remembermypassword') ?></label>
</td>
</tr>
<?php }
$tabIndex = 8;
if ( isset( $this->data['extraInput'] ) && is_array( $this->data['extraInput'] ) ) {
foreach ( $this->data['extraInput'] as $inputItem ) { ?>
<tr>
<?php
if ( !empty( $inputItem['msg'] ) && $inputItem['type'] != 'checkbox' ) {
?><td class="mw-label"><label for="<?php
echo htmlspecialchars( $inputItem['name'] ); ?>"><?php
$this->msgWiki( $inputItem['msg'] ) ?></label><?php
} else {
?><td><?php
}
?></td>
<td class="mw-input">
<input type="<?php echo htmlspecialchars( $inputItem['type'] ) ?>" name="<?php
echo htmlspecialchars( $inputItem['name'] ); ?>"
tabindex="<?php echo $tabIndex++; ?>"
value="<?php
if ( $inputItem['type'] != 'checkbox' ) {
echo htmlspecialchars( $inputItem['value'] );
} else {
echo '1';
}
?>" id="<?php echo htmlspecialchars( $inputItem['name'] ); ?>"
<?php
if ( $inputItem['type'] == 'checkbox' && !empty( $inputItem['value'] ) )
echo 'checked="checked"';
?> /> <?php
if ( $inputItem['type'] == 'checkbox' && !empty( $inputItem['msg'] ) ) {
?>
<label for="<?php echo htmlspecialchars( $inputItem['name'] ); ?>"><?php
$this->msgHtml( $inputItem['msg'] ) ?></label><?php
}
if( $inputItem['helptext'] !== false ) {
?>
<div class="prefsectiontip">
<?php $this->msgWiki( $inputItem['helptext'] ); ?>
</div>
<?php } ?>
</td>
</tr>
<?php
}
}
?>
<tr>
<td></td>
<td class="mw-submit">
<input type='submit' name="wpCreateaccount" id="wpCreateaccount"
tabindex="<?php echo $tabIndex++; ?>"
value="<?php $this->msg('createaccount') ?>" />
<?php if( $this->data['createemail'] ) { ?>
<input type='submit' name="wpCreateaccountMail" id="wpCreateaccountMail"
tabindex="<?php echo $tabIndex++; ?>"
value="<?php $this->msg('createaccountmail') ?>" />
<?php } ?>
</td>
</tr>
</table>
<?php if( @$this->haveData( 'uselang' ) ) { ?><input type="hidden" name="uselang" value="<?php $this->text( 'uselang' ); ?>" /><?php } ?>
</form>
</div>
<div id="signupend"><?php $this->msgWiki( 'signupend' ); ?></div>
<?php
}
}

View file

@ -1042,7 +1042,7 @@ Do not forget to change your [[Special:Preferences|{{SITENAME}} preferences]].',
'login' => 'Log in',
'nav-login-createaccount' => 'Log in / create account',
'loginprompt' => 'You must have cookies enabled to log in to {{SITENAME}}.',
'userlogin' => 'Log in / create account',
'userlogin' => 'Log in',
'logout' => 'Log out',
'userlogout' => 'Log out',
'notloggedin' => 'Not logged in',
@ -1090,6 +1090,7 @@ If someone else made this request, or if you have remembered your password,
and you no longer wish to change it, you may ignore this message and
continue using your old password.',
'noemail' => 'There is no e-mail address recorded for user "$1".',
'noemailcreate' => 'You need to provide a valid email address',
'passwordsent' => 'A new password has been sent to the e-mail address registered for "$1".
Please log in again after you receive it.',
'blocked-mailpassword' => 'Your IP address is blocked from editing, and so is not allowed to use the password recovery function to prevent abuse.',

View file

@ -596,7 +596,7 @@ HTML markup cannot be used.",
{{Identical|Log in}}",
'nav-login-createaccount' => "Shown to anonymous users in the upper right corner of the page. When you can't create an account, the message {{msg|login}} is shown.",
'loginprompt' => 'A small notice in the log in form.',
'userlogin' => 'Name of special page [[Special:UserLogin]] where a user can log in or click to create a user account.',
'userlogin' => 'Name of special page [[Special:UserLogin]] where a user can log in.',
'logout' => '{{Identical|Log out}}',
'userlogout' => '{{Identical|Log out}}',
'notloggedin' => 'This message is displayed in the standard skin when not logged in. The message is placed above the login link in the top right corner of pages.

View file

@ -802,3 +802,5 @@ td.mw-enhanced-rc {
position: relative;
top: -16px;
}
#wpLoginAttempt, #wpCreateaccount { margin-right:0; }