r56684 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r56683‎ | r56684 | r56685 >
Date:20:28, 20 September 2009
Author:happy-melon
Status:reverted (Comments)
Tags:
Comment:
Merge in Login rewrite, second time lucky.
Modified paths:
  • /trunk/extensions/AntiSpoof/AntiSpoof.php (modified) (history)
  • /trunk/extensions/ConfirmAccount/SpecialConfirmAccount.php (modified) (history)
  • /trunk/extensions/ConfirmEdit/ConfirmEdit_body.php (modified) (history)
  • /trunk/extensions/LdapAuthentication/LdapAuthentication.php (modified) (history)
  • /trunk/extensions/WikimediaIncubator/CreateAccountTestWiki.php (modified) (history)
  • /trunk/phase3/RELEASE-NOTES (modified) (history)
  • /trunk/phase3/docs/hooks.txt (modified) (history)
  • /trunk/phase3/includes/AuthPlugin.php (modified) (history)
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/Login.php (added) (history)
  • /trunk/phase3/includes/SpecialPage.php (modified) (history)
  • /trunk/phase3/includes/api/ApiLogin.php (modified) (history)
  • /trunk/phase3/includes/specials/SpecialCreateAccount.php (added) (history)
  • /trunk/phase3/includes/specials/SpecialResetpass.php (modified) (history)
  • /trunk/phase3/includes/specials/SpecialUserlogin.php (modified) (history)
  • /trunk/phase3/includes/templates/Userlogin.php (deleted) (history)
  • /trunk/phase3/languages/messages/MessagesEn.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesQqq.php (modified) (history)
  • /trunk/phase3/skins/common/shared.css (modified) (history)

Diff [purge]

Index: trunk/phase3/skins/common/shared.css
@@ -802,3 +802,5 @@
803803 position: relative;
804804 top: -16px;
805805 }
 806+
 807+#wpLoginAttempt, #wpCreateaccount { margin-right:0; }
Index: trunk/phase3/docs/hooks.txt
@@ -244,8 +244,8 @@
245245 'AbortLogin': Return false to cancel account login.
246246 $user: the User object being authenticated against
247247 $password: the password being submitted, not yet checked for validity
248 -&$retval: a LoginForm class constant to return from authenticateUserData();
249 - default is LoginForm::ABORTED. Note that the client may be using
 248+&$retval: a Login class constant to return from authenticateUserData();
 249+ default is Login::ABORTED. Note that the client may be using
250250 a machine API rather than the HTML user interface.
251251
252252 'AbortMove': allows to abort moving an article (title)
@@ -944,7 +944,7 @@
945945 succeeded or failed. No return data is accepted; this hook is for auditing only.
946946 $user: the User object being authenticated against
947947 $password: the password being submitted and found wanting
948 -$retval: a LoginForm class constant with authenticateUserData() return
 948+$retval: a Login class constant with authenticateUserData() return
949949 value (SUCCESS, WRONG_PASS, etc)
950950
951951 'LogLine': Processes a single log entry on Special:Log
@@ -1526,7 +1526,7 @@
15271527 determine if the password was valid
15281528
15291529 'UserCreateForm': change to manipulate the login form
1530 -$template: SimpleTemplate instance for the form
 1530+$sp: SpecialCreateAccount instance
15311531
15321532 'UserCryptPassword': called when hashing a password, return false to implement
15331533 your own hashing method
@@ -1596,7 +1596,7 @@
15971597 $inject_html: Any HTML to inject after the "logged in" message.
15981598
15991599 'UserLoginForm': change to manipulate the login form
1600 -$template: SimpleTemplate instance for the form
 1600+$sp: SpecialCreateAccount instance
16011601
16021602 'UserLoginMailPassword': Block users from emailing passwords
16031603 $name: the username to email the password of.
Index: trunk/phase3/includes/api/ApiLogin.php
@@ -60,7 +60,7 @@
6161 'wpName' => $params['name'],
6262 'wpPassword' => $params['password'],
6363 'wpDomain' => $params['domain'],
64 - 'wpRemember' => ''
 64+ 'wpRemember' => '1'
6565 ));
6666
6767 // Init session if necessary
@@ -68,19 +68,11 @@
6969 wfSetupSession();
7070 }
7171
72 - $loginForm = new LoginForm($req);
73 - switch ($authRes = $loginForm->authenticateUserData()) {
74 - case LoginForm :: SUCCESS :
 72+ $loginForm = new Login( $req );
 73+ switch ( $authRes = $loginForm->attemptLogin() ) {
 74+ case Login::SUCCESS :
7575 global $wgUser, $wgCookiePrefix;
7676
77 - $wgUser->setOption('rememberpassword', 1);
78 - $wgUser->setCookies();
79 -
80 - // Run hooks. FIXME: split back and frontend from this hook.
81 - // FIXME: This hook should be placed in the backend
82 - $injected_html = '';
83 - wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
84 -
8577 $result['result'] = 'Success';
8678 $result['lguserid'] = intval($wgUser->getId());
8779 $result['lgusername'] = $wgUser->getName();
@@ -89,35 +81,35 @@
9082 $result['sessionid'] = session_id();
9183 break;
9284
93 - case LoginForm :: NO_NAME :
 85+ case Login::NO_NAME :
9486 $result['result'] = 'NoName';
9587 break;
96 - case LoginForm :: ILLEGAL :
 88+ case Login::ILLEGAL :
9789 $result['result'] = 'Illegal';
9890 break;
99 - case LoginForm :: WRONG_PLUGIN_PASS :
 91+ case Login::WRONG_PLUGIN_PASS :
10092 $result['result'] = 'WrongPluginPass';
10193 break;
102 - case LoginForm :: NOT_EXISTS :
 94+ case Login::NOT_EXISTS :
10395 $result['result'] = 'NotExists';
10496 break;
105 - case LoginForm :: WRONG_PASS :
 97+ case Login::WRONG_PASS :
10698 $result['result'] = 'WrongPass';
10799 break;
108 - case LoginForm :: EMPTY_PASS :
 100+ case Login::EMPTY_PASS :
109101 $result['result'] = 'EmptyPass';
110102 break;
111 - case LoginForm :: CREATE_BLOCKED :
 103+ case Login::CREATE_BLOCKED :
112104 $result['result'] = 'CreateBlocked';
113105 $result['details'] = 'Your IP address is blocked from account creation';
114106 break;
115 - case LoginForm :: THROTTLED :
 107+ case Login::THROTTLED :
116108 global $wgPasswordAttemptThrottle;
117109 $result['result'] = 'Throttled';
118 - $result['wait'] = intval($wgPasswordAttemptThrottle['seconds']);
 110+ $result['wait'] = intval( $wgPasswordAttemptThrottle['seconds'] );
119111 break;
120112 default :
121 - ApiBase :: dieDebug(__METHOD__, "Unhandled case value: {$authRes}");
 113+ ApiBase::dieDebug( __METHOD__, "Unhandled case value: {$authRes}" );
122114 }
123115
124116 $this->getResult()->addValue(null, 'login', $result);
Index: trunk/phase3/includes/AutoLoader.php
@@ -134,6 +134,8 @@
135135 'LinksUpdate' => 'includes/LinksUpdate.php',
136136 'LocalisationCache' => 'includes/LocalisationCache.php',
137137 'LocalisationCache_BulkLoad' => 'includes/LocalisationCache.php',
 138+ 'LoginForm' => 'includes/Login.php', # For B/C
 139+ 'Login' => 'includes/Login.php',
138140 'LogPage' => 'includes/LogPage.php',
139141 'LogPager' => 'includes/LogEventsList.php',
140142 'LogEventsList' => 'includes/LogEventsList.php',
@@ -493,6 +495,7 @@
494496 'AncientPagesPage' => 'includes/specials/SpecialAncientpages.php',
495497 'BrokenRedirectsPage' => 'includes/specials/SpecialBrokenRedirects.php',
496498 'ContribsPager' => 'includes/specials/SpecialContributions.php',
 499+ 'SpecialCreateAccount' => 'includes/specials/SpecialCreateAccount.php',
497500 'DBLockForm' => 'includes/specials/SpecialLockdb.php',
498501 'DBUnlockForm' => 'includes/specials/SpecialUnlockdb.php',
499502 'DeadendPagesPage' => 'includes/specials/SpecialDeadendpages.php',
@@ -513,7 +516,6 @@
514517 'ImportStringSource' => 'includes/Import.php',
515518 'LinkSearchPage' => 'includes/specials/SpecialLinkSearch.php',
516519 'ListredirectsPage' => 'includes/specials/SpecialListredirects.php',
517 - 'LoginForm' => 'includes/specials/SpecialUserlogin.php',
518520 'LonelyPagesPage' => 'includes/specials/SpecialLonelypages.php',
519521 'LongPagesPage' => 'includes/specials/SpecialLongpages.php',
520522 'MIMEsearchPage' => 'includes/specials/SpecialMIMEsearch.php',
@@ -562,6 +564,7 @@
563565 'UnwatchedpagesPage' => 'includes/specials/SpecialUnwatchedpages.php',
564566 'UploadForm' => 'includes/specials/SpecialUpload.php',
565567 'UploadFormMogile' => 'includes/specials/SpecialUploadMogile.php',
 568+ 'SpecialUserLogin' => 'includes/specials/SpecialUserlogin.php',
566569 'UserrightsPage' => 'includes/specials/SpecialUserrights.php',
567570 'UsersPager' => 'includes/specials/SpecialListusers.php',
568571 'WantedCategoriesPage' => 'includes/specials/SpecialWantedcategories.php',
Index: trunk/phase3/includes/AuthPlugin.php
@@ -62,12 +62,13 @@
6363 /**
6464 * Modify options in the login template.
6565 *
66 - * @param $template UserLoginTemplate object.
67 - * @param $type String 'signup' or 'login'.
 66+ * @param $sp SpecialUserlogin or SpecialCreateAccount object.
 67+ * @param $type String 'signup' or 'login'. Redundant because
 68+ * you can just use instanceof to tell the two cases apart.
6869 */
69 - public function modifyUITemplate( &$template, &$type ) {
 70+ public function modifyUITemplate( &$sp, $type=null ) {
7071 # Override this!
71 - $template->set( 'usedomain', false );
 72+ $sp->mDomains = false;
7273 }
7374
7475 /**
Index: trunk/phase3/includes/Login.php
@@ -0,0 +1,565 @@
 2+<?php
 3+
 4+/**
 5+ * Encapsulates the backend activities of logging a user into the wiki.
 6+ */
 7+class Login {
 8+
 9+ const SUCCESS = 0;
 10+ const NO_NAME = 1;
 11+ const ILLEGAL = 2;
 12+ const WRONG_PLUGIN_PASS = 3;
 13+ const NOT_EXISTS = 4;
 14+ const WRONG_PASS = 5;
 15+ const EMPTY_PASS = 6;
 16+ const RESET_PASS = 7;
 17+ const ABORTED = 8;
 18+ const THROTTLED = 10;
 19+ const FAILED = 11;
 20+ const READ_ONLY = 12;
 21+
 22+ const MAIL_PASSCHANGE_FORBIDDEN = 21;
 23+ const MAIL_BLOCKED = 22;
 24+ const MAIL_PING_THROTTLED = 23;
 25+ const MAIL_PASS_THROTTLED = 24;
 26+ const MAIL_EMPTY_EMAIL = 25;
 27+ const MAIL_BAD_IP = 26;
 28+ const MAIL_ERROR = 27;
 29+
 30+ const CREATE_BLOCKED = 40;
 31+ const CREATE_EXISTS = 41;
 32+ const CREATE_SORBS = 42;
 33+ const CREATE_BADDOMAIN = 43;
 34+ const CREATE_BADNAME = 44;
 35+ const CREATE_BADPASS = 45;
 36+ const CREATE_NEEDEMAIL = 46;
 37+ const CREATE_BADEMAIL = 47;
 38+
 39+ protected $mName;
 40+ protected $mPassword;
 41+ public $mRemember; # 0 or 1
 42+ public $mEmail;
 43+ public $mDomain;
 44+ public $mRealname;
 45+
 46+ private $mExtUser = null;
 47+
 48+ public $mUser;
 49+
 50+ public $mLoginResult = '';
 51+ public $mMailResult = '';
 52+ public $mCreateResult = '';
 53+
 54+ /**
 55+ * Constructor
 56+ * @param WebRequest $request A WebRequest object passed by reference.
 57+ * uses $wgRequest if not given.
 58+ */
 59+ public function __construct( &$request=null ) {
 60+ global $wgRequest, $wgAuth, $wgHiddenPrefs, $wgEnableEmail, $wgRedirectOnLogin;
 61+ if( !$request ) $request = &$wgRequest;
 62+
 63+ $this->mName = $request->getText( 'wpName' );
 64+ $this->mPassword = $request->getText( 'wpPassword' );
 65+ $this->mDomain = $request->getText( 'wpDomain' );
 66+ $this->mRemember = $request->getCheck( 'wpRemember' ) ? 1 : 0;
 67+
 68+ if( $wgEnableEmail ) {
 69+ $this->mEmail = $request->getText( 'wpEmail' );
 70+ } else {
 71+ $this->mEmail = '';
 72+ }
 73+ if( !in_array( 'realname', $wgHiddenPrefs ) ) {
 74+ $this->mRealName = $request->getText( 'wpRealName' );
 75+ } else {
 76+ $this->mRealName = '';
 77+ }
 78+
 79+ if( !$wgAuth->validDomain( $this->mDomain ) ) {
 80+ $this->mDomain = 'invaliddomain';
 81+ }
 82+ $wgAuth->setDomain( $this->mDomain );
 83+
 84+ # Load the user, if they exist in the local database.
 85+ $this->mUser = User::newFromName( trim( $this->mName ), 'usable' );
 86+ }
 87+
 88+ /**
 89+ * Having initialised the Login object with (at least) the wpName
 90+ * and wpPassword pair, attempt to authenticate the user and log
 91+ * them into the wiki. Authentication may come from the local
 92+ * user database, or from an AuthPlugin- or ExternalUser-based
 93+ * foreign database; in the latter case, a local user record may
 94+ * or may not be created and initialised.
 95+ * @return a Login class constant representing the status.
 96+ */
 97+ public function attemptLogin(){
 98+ global $wgUser;
 99+
 100+ $code = $this->authenticateUserData();
 101+ if( $code != self::SUCCESS ){
 102+ return $code;
 103+ }
 104+
 105+ # Log the user in and remember them if they asked for that.
 106+ if( (bool)$this->mRemember != (bool)$wgUser->getOption( 'rememberpassword' ) ) {
 107+ $wgUser->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 );
 108+ $wgUser->saveSettings();
 109+ } else {
 110+ $wgUser->invalidateCache();
 111+ }
 112+ $wgUser->setCookies();
 113+
 114+ # Reset the password throttle
 115+ $key = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
 116+ global $wgMemc;
 117+ $wgMemc->delete( $key );
 118+
 119+ wfRunHooks( 'UserLoginComplete', array( &$wgUser, &$this->mLoginResult ) );
 120+
 121+ return self::SUCCESS;
 122+ }
 123+
 124+ /**
 125+ * Check whether there is an external authentication mechanism from
 126+ * which we can automatically authenticate the user and create a
 127+ * local account for them.
 128+ * @return integer Status code. Login::SUCCESS == clear to proceed
 129+ * with user creation.
 130+ */
 131+ protected function canAutoCreate() {
 132+ global $wgAuth, $wgUser, $wgAutocreatePolicy;
 133+
 134+ if( $wgUser->isBlockedFromCreateAccount() ) {
 135+ wfDebug( __METHOD__.": user is blocked from account creation\n" );
 136+ return self::CREATE_BLOCKED;
 137+ }
 138+
 139+ # If the external authentication plugin allows it, automatically
 140+ # create a new account for users that are externally defined but
 141+ # have not yet logged in.
 142+ if( $this->mExtUser ) {
 143+ # mExtUser is neither null nor false, so use the new
 144+ # ExternalAuth system.
 145+ if( $wgAutocreatePolicy == 'never' ) {
 146+ return self::NOT_EXISTS;
 147+ }
 148+ if( !$this->mExtUser->authenticate( $this->mPassword ) ) {
 149+ return self::WRONG_PLUGIN_PASS;
 150+ }
 151+ } else {
 152+ # Old AuthPlugin.
 153+ if( !$wgAuth->autoCreate() ) {
 154+ return self::NOT_EXISTS;
 155+ }
 156+ if( !$wgAuth->userExists( $this->mUser->getName() ) ) {
 157+ wfDebug( __METHOD__.": user does not exist\n" );
 158+ return self::NOT_EXISTS;
 159+ }
 160+ if( !$wgAuth->authenticate( $this->mUser->getName(), $this->mPassword ) ) {
 161+ wfDebug( __METHOD__.": \$wgAuth->authenticate() returned false, aborting\n" );
 162+ return self::WRONG_PLUGIN_PASS;
 163+ }
 164+ }
 165+
 166+ return self::SUCCESS;
 167+ }
 168+
 169+ /**
 170+ * Internally authenticate the login request.
 171+ *
 172+ * This may create a local account as a side effect if the
 173+ * authentication plugin allows transparent local account
 174+ * creation.
 175+ */
 176+ protected function authenticateUserData() {
 177+ global $wgUser, $wgAuth;
 178+
 179+ if ( '' == $this->mName ) {
 180+ return self::NO_NAME;
 181+ }
 182+
 183+ global $wgPasswordAttemptThrottle;
 184+ $throttleCount = 0;
 185+ if ( is_array( $wgPasswordAttemptThrottle ) ) {
 186+ $throttleKey = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
 187+ $count = $wgPasswordAttemptThrottle['count'];
 188+ $period = $wgPasswordAttemptThrottle['seconds'];
 189+
 190+ global $wgMemc;
 191+ $throttleCount = $wgMemc->get( $throttleKey );
 192+ if ( !$throttleCount ) {
 193+ $wgMemc->add( $throttleKey, 1, $period ); # Start counter
 194+ } else if ( $throttleCount < $count ) {
 195+ $wgMemc->incr($throttleKey);
 196+ } else if ( $throttleCount >= $count ) {
 197+ return self::THROTTLED;
 198+ }
 199+ }
 200+
 201+ # Unstub $wgUser now, and check to see if we're logging in as the same
 202+ # name. As well as the obvious, unstubbing $wgUser (say by calling
 203+ # getName()) calls the UserLoadFromSession hook, which potentially
 204+ # creates the user in the database. Until we load $wgUser, checking
 205+ # for user existence using User::newFromName($name)->getId() below
 206+ # will effectively be using stale data.
 207+ if ( $wgUser->getName() === $this->mName ) {
 208+ wfDebug( __METHOD__.": already logged in as {$this->mName}\n" );
 209+ return self::SUCCESS;
 210+ }
 211+
 212+ $this->mExtUser = ExternalUser::newFromName( $this->mName );
 213+
 214+ # TODO: Allow some magic here for invalid external names, e.g., let the
 215+ # user choose a different wiki name.
 216+ if( is_null( $this->mUser ) || !User::isUsableName( $this->mUser->getName() ) ) {
 217+ return self::ILLEGAL;
 218+ }
 219+
 220+ # If the user doesn't exist in the local database, our only chance
 221+ # is for an external auth plugin to autocreate the local user.
 222+ if ( $this->mUser->getID() == 0 ) {
 223+ if ( $this->canAutoCreate() == self::SUCCESS ) {
 224+ $isAutoCreated = true;
 225+ wfDebug( __METHOD__.": creating account\n" );
 226+ $this->initUser( true );
 227+ } else {
 228+ return $this->canAutoCreate();
 229+ }
 230+ } else {
 231+ $isAutoCreated = false;
 232+ $this->mUser->load();
 233+ }
 234+
 235+ # Give general extensions, such as a captcha, a chance to abort logins
 236+ $abort = self::ABORTED;
 237+ if( !wfRunHooks( 'AbortLogin', array( $this->mUser, $this->mPassword, &$abort ) ) ) {
 238+ return $abort;
 239+ }
 240+
 241+ if( !$this->mUser->checkPassword( $this->mPassword ) ) {
 242+ if( $this->mUser->checkTemporaryPassword( $this->mPassword ) ) {
 243+ # The e-mailed temporary password should not be used for actual
 244+ # logins; that's a very sloppy habit, and insecure if an
 245+ # attacker has a few seconds to click "search" on someone's
 246+ # open mail reader.
 247+ #
 248+ # Allow it to be used only to reset the password a single time
 249+ # to a new value, which won't be in the user's e-mail archives
 250+ #
 251+ # For backwards compatibility, we'll still recognize it at the
 252+ # login form to minimize surprises for people who have been
 253+ # logging in with a temporary password for some time.
 254+ #
 255+ # As a side-effect, we can authenticate the user's e-mail ad-
 256+ # dress if it's not already done, since the temporary password
 257+ # was sent via e-mail.
 258+ if( !$this->mUser->isEmailConfirmed() ) {
 259+ $this->mUser->confirmEmail();
 260+ $this->mUser->saveSettings();
 261+ }
 262+
 263+ # At this point we just return an appropriate code/ indicating
 264+ # that the UI should show a password reset form; bot interfaces
 265+ # etc will probably just fail cleanly here.
 266+ $retval = self::RESET_PASS;
 267+ } else {
 268+ $retval = ( $this->mPassword === '' ) ? self::EMPTY_PASS : self::WRONG_PASS;
 269+ }
 270+ } else {
 271+ $wgAuth->updateUser( $this->mUser );
 272+ $wgUser = $this->mUser;
 273+
 274+ # Reset throttle after a successful login
 275+ if( $throttleCount ) {
 276+ $wgMemc->delete( $throttleKey );
 277+ }
 278+
 279+ if( $isAutoCreated ) {
 280+ # Must be run after $wgUser is set, for correct new user log
 281+ wfRunHooks( 'AuthPluginAutoCreate', array( $wgUser ) );
 282+ }
 283+
 284+ $retval = self::SUCCESS;
 285+ }
 286+ wfRunHooks( 'LoginAuthenticateAudit', array( $this->mUser, $this->mPassword, $retval ) );
 287+ return $retval;
 288+ }
 289+
 290+ /**
 291+ * Actually add a user to the database.
 292+ * Give it a User object that has been initialised with a name.
 293+ *
 294+ * @param $autocreate Bool is this is an autocreation from an external
 295+ * authentication database?
 296+ * @param $byEmail Bool is this request going to be handled by sending
 297+ * the password by email?
 298+ * @return Bool whether creation was successful (should only fail for
 299+ * Db errors etc).
 300+ */
 301+ protected function initUser( $autocreate=false, $byEmail=false ) {
 302+ global $wgAuth;
 303+
 304+ $fields = array(
 305+ 'name' => $this->mName,
 306+ 'password' => $byEmail ? null : $this->mPassword,
 307+ 'email' => $this->mEmail,
 308+ 'options' => array(
 309+ 'rememberpassword' => $this->mRemember ? 1 : 0,
 310+ ),
 311+ );
 312+
 313+ $this->mUser = User::createNew( $this->mName, $fields );
 314+
 315+ if( $this->mUser === null ){
 316+ return null;
 317+ }
 318+
 319+ # Let old AuthPlugins play with the user
 320+ $wgAuth->initUser( $this->mUser, $autocreate );
 321+
 322+ # Or new ExternalUser plugins
 323+ if( $this->mExtUser ) {
 324+ $this->mExtUser->link( $this->mUser->getId() );
 325+ $email = $this->mExtUser->getPref( 'emailaddress' );
 326+ if( $email && !$this->mEmail ) {
 327+ $this->mUser->setEmail( $email );
 328+ }
 329+ }
 330+
 331+ # Update user count and newuser logs
 332+ $ssUpdate = new SiteStatsUpdate( 0, 0, 0, 0, 1 );
 333+ $ssUpdate->doUpdate();
 334+ if( $autocreate )
 335+ $this->mUser->addNewUserLogEntryAutoCreate();
 336+ else
 337+ $this->mUser->addNewUserLogEntry( $byEmail );
 338+
 339+ # Run hooks
 340+ wfRunHooks( 'AddNewAccount', array( $this->mUser ) );
 341+
 342+ return true;
 343+ }
 344+
 345+ /**
 346+ * Entry point to create a new local account from user-supplied
 347+ * data loaded from the WebRequest. We handle initialising the
 348+ * email here because it's needed for some backend things; frontend
 349+ * interfaces calling this should handle recording things like
 350+ * preference options
 351+ * @param $byEmail Bool whether to email the user their new password
 352+ * @return Status code; Login::SUCCESS == the user was successfully created
 353+ */
 354+ public function attemptCreation( $byEmail=false ) {
 355+ global $wgUser, $wgOut;
 356+ global $wgEnableSorbs, $wgProxyWhitelist;
 357+ global $wgMemc, $wgAccountCreationThrottle;
 358+ global $wgAuth;
 359+ global $wgEmailAuthentication, $wgEmailConfirmToEdit;
 360+
 361+ if( wfReadOnly() )
 362+ return self::READ_ONLY;
 363+
 364+ # If the user passes an invalid domain, something is fishy
 365+ if( !$wgAuth->validDomain( $this->mDomain ) ) {
 366+ $this->mCreateResult = 'wrongpassword';
 367+ return self::CREATE_BADDOMAIN;
 368+ }
 369+
 370+ # If we are not allowing users to login locally, we should be checking
 371+ # to see if the user is actually able to authenticate to the authenti-
 372+ # cation server before they create an account (otherwise, they can
 373+ # create a local account and login as any domain user). We only need
 374+ # to check this for domains that aren't local.
 375+ if( !in_array( $this->mDomain, array( 'local', '' ) )
 376+ && !$wgAuth->canCreateAccounts()
 377+ && ( !$wgAuth->userExists( $this->mUsername )
 378+ || !$wgAuth->authenticate( $this->mUsername, $this->mPassword )
 379+ ) )
 380+ {
 381+ $this->mCreateResult = 'wrongpassword';
 382+ return self::WRONG_PLUGIN_PASS;
 383+ }
 384+
 385+ $ip = wfGetIP();
 386+ if ( $wgEnableSorbs && !in_array( $ip, $wgProxyWhitelist ) &&
 387+ $wgUser->inSorbsBlacklist( $ip ) )
 388+ {
 389+ $this->mCreateResult = 'sorbs_create_account_reason';
 390+ return self::CREATE_SORBS;
 391+ }
 392+
 393+ # Now create a dummy user ($user) and check if it is valid
 394+ $name = trim( $this->mName );
 395+ $user = User::newFromName( $name, 'creatable' );
 396+ if ( is_null( $user ) ) {
 397+ $this->mCreateResult = 'noname';
 398+ return self::CREATE_BADNAME;
 399+ }
 400+
 401+ if ( $this->mUser->idForName() != 0 ) {
 402+ $this->mCreateResult = 'userexists';
 403+ return self::CREATE_EXISTS;
 404+ }
 405+
 406+ # Check that the password is acceptable, if we're actually
 407+ # going to use it
 408+ if( !$byEmail ){
 409+ $valid = $this->mUser->isValidPassword( $this->mPassword );
 410+ if ( $valid !== true ) {
 411+ $this->mCreateResult = $valid;
 412+ return self::CREATE_BADPASS;
 413+ }
 414+ }
 415+
 416+ # if you need a confirmed email address to edit, then obviously you
 417+ # need an email address. Equally if we're going to send the password to it.
 418+ if ( $wgEmailConfirmToEdit && empty( $this->mEmail ) || $byEmail ) {
 419+ $this->mCreateResult = 'noemailcreate';
 420+ return self::CREATE_NEEDEMAIL;
 421+ }
 422+
 423+ if( !empty( $this->mEmail ) && !User::isValidEmailAddr( $this->mEmail ) ) {
 424+ $this->mCreateResult = 'invalidemailaddress';
 425+ return self::CREATE_BADEMAIL;
 426+ }
 427+
 428+ # Set some additional data so the AbortNewAccount hook can be used for
 429+ # more than just username validation
 430+ $this->mUser->setEmail( $this->mEmail );
 431+ $this->mUser->setRealName( $this->mRealName );
 432+
 433+ if( !wfRunHooks( 'AbortNewAccount', array( $this->mUser, &$this->mCreateResult ) ) ) {
 434+ # Hook point to add extra creation throttles and blocks
 435+ wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" );
 436+ return self::ABORTED;
 437+ }
 438+
 439+ if ( $wgAccountCreationThrottle && $wgUser->isPingLimitable() ) {
 440+ $key = wfMemcKey( 'acctcreate', 'ip', $ip );
 441+ $value = $wgMemc->get( $key );
 442+ if ( !$value ) {
 443+ $wgMemc->set( $key, 0, 86400 );
 444+ }
 445+ if ( $value >= $wgAccountCreationThrottle ) {
 446+ return self::THROTTLED;
 447+ }
 448+ $wgMemc->incr( $key );
 449+ }
 450+
 451+ # Since we're creating a new local user, give the external
 452+ # database a chance to synchronise.
 453+ if( !$wgAuth->addUser( $this->mUser, $this->mPassword, $this->mEmail, $this->mRealName ) ) {
 454+ $this->mCreateResult = 'externaldberror';
 455+ return self::ABORTED;
 456+ }
 457+
 458+ $result = $this->initUser( false, $byEmail );
 459+ if( $result === null )
 460+ # It's unlikely we'd get here without some exception
 461+ # being thrown, but it's probably possible...
 462+ return self::FAILED;
 463+
 464+
 465+ # Send out an email message if needed
 466+ if( $byEmail ){
 467+ $this->mailPassword( 'createaccount-title', 'createaccount-text' );
 468+ if( WikiError::isError( $this->mMailResult ) ){
 469+ # FIXME: If the password email hasn't gone out,
 470+ # then the account is inaccessible :(
 471+ return self::MAIL_ERROR;
 472+ } else {
 473+ return self::SUCCESS;
 474+ }
 475+ } else {
 476+ if( $wgEmailAuthentication && User::isValidEmailAddr( $this->mUser->getEmail() ) )
 477+ {
 478+ $this->mMailResult = $this->mUser->sendConfirmationMail();
 479+ return WikiError::isError( $this->mMailResult )
 480+ ? self::MAIL_ERROR
 481+ : self::SUCCESS;
 482+ }
 483+ }
 484+ return true;
 485+ }
 486+
 487+ /**
 488+ * Email the user a new password, if appropriate to do so.
 489+ * @param $text String message key
 490+ * @param $title String message key
 491+ * @return Status code
 492+ */
 493+ public function mailPassword( $text='passwordremindertext', $title='passwordremindertitle' ) {
 494+ global $wgUser, $wgOut, $wgAuth, $wgServer, $wgScript, $wgNewPasswordExpiry;
 495+
 496+ if( wfReadOnly() )
 497+ return self::READ_ONLY;
 498+
 499+ # If we let the email go out, it will take users to a form where
 500+ # they are forced to change their password, so don't let us go
 501+ # there if we don't want passwords changed.
 502+ if( !$wgAuth->allowPasswordChange() )
 503+ return self::MAIL_PASSCHANGE_FORBIDDEN;
 504+
 505+ # Check against blocked IPs
 506+ # FIXME: -- should we not?
 507+ if( $wgUser->isBlocked() )
 508+ return self::MAIL_BLOCKED;
 509+
 510+ # Check for hooks
 511+ if( !wfRunHooks( 'UserLoginMailPassword', array( $this->mName, &$this->mMailResult ) ) )
 512+ return self::ABORTED;
 513+
 514+ # Check against the rate limiter
 515+ if( $wgUser->pingLimiter( 'mailpassword' ) )
 516+ return self::MAIL_PING_THROTTLED;
 517+
 518+ # Check for a valid name
 519+ if ($this->mName === '' )
 520+ return self::NO_NAME;
 521+ $this->mUser = User::newFromName( $this->mName );
 522+ if( is_null( $this->mUser ) )
 523+ return self::NO_NAME;
 524+
 525+ # And that the resulting user actually exists
 526+ if ( $this->mUser->getId() === 0 )
 527+ return self::NOT_EXISTS;
 528+
 529+ # Check against password throttle
 530+ if ( $this->mUser->isPasswordReminderThrottled() )
 531+ return self::MAIL_PASS_THROTTLED;
 532+
 533+ # User doesn't have email address set
 534+ if ( $this->mUser->getEmail() === '' )
 535+ return self::MAIL_EMPTY_EMAIL;
 536+
 537+ # Don't send to people who are acting fishily by hiding their IP
 538+ $ip = wfGetIP();
 539+ if( !$ip )
 540+ return self::MAIL_BAD_IP;
 541+
 542+ # Let hooks do things with the data
 543+ wfRunHooks( 'User::mailPasswordInternal', array(&$wgUser, &$ip, &$this->mUser) );
 544+
 545+ $newpass = $this->mUser->randomPassword();
 546+ $this->mUser->setNewpassword( $newpass, true );
 547+ $this->mUser->saveSettings();
 548+
 549+ $message = wfMsgExt( $text, array( 'parsemag' ), $ip, $this->mUser->getName(), $newpass,
 550+ $wgServer . $wgScript, round( $wgNewPasswordExpiry / 86400 ) );
 551+ $this->mMailResult = $this->mUser->sendMail( wfMsg( $title ), $message );
 552+
 553+ if( WikiError::isError( $this->mMailResult ) ) {
 554+ return self::MAIL_ERROR;
 555+ } else {
 556+ return self::SUCCESS;
 557+ }
 558+ }
 559+}
 560+
 561+/**
 562+ * For backwards compatibility, mainly with the state constants, which
 563+ * could be referred to in old extensions with the old class name.
 564+ * @deprecated
 565+ */
 566+class LoginForm extends Login {}
\ No newline at end of file
Property changes on: trunk/phase3/includes/Login.php
___________________________________________________________________
Added: svn:eol-style
1567 + native
Index: trunk/phase3/includes/specials/SpecialUserlogin.php
@@ -1,962 +1,281 @@
22 <?php
33 /**
4 - * @file
 4+ * SpecialPage for logging users into the wiki
55 * @ingroup SpecialPage
66 */
77
8 -/**
9 - * constructor
10 - */
11 -function wfSpecialUserlogin( $par = '' ) {
12 - global $wgRequest;
13 - if( session_id() == '' ) {
14 - wfSetupSession();
15 - }
 8+class SpecialUserLogin extends SpecialPage {
169
17 - $form = new LoginForm( $wgRequest, $par );
18 - $form->execute();
19 -}
20 -
21 -/**
22 - * implements Special:Login
23 - * @ingroup SpecialPage
24 - */
25 -class LoginForm {
26 -
27 - const SUCCESS = 0;
28 - const NO_NAME = 1;
29 - const ILLEGAL = 2;
30 - const WRONG_PLUGIN_PASS = 3;
31 - const NOT_EXISTS = 4;
32 - const WRONG_PASS = 5;
33 - const EMPTY_PASS = 6;
34 - const RESET_PASS = 7;
35 - const ABORTED = 8;
36 - const CREATE_BLOCKED = 9;
37 - const THROTTLED = 10;
38 -
39 - var $mName, $mPassword, $mRetype, $mReturnTo, $mCookieCheck, $mPosted;
40 - var $mAction, $mCreateaccount, $mCreateaccountMail, $mMailmypassword;
41 - var $mLoginattempt, $mRemember, $mEmail, $mDomain, $mLanguage;
 10+ var $mUsername, $mPassword, $mReturnTo, $mCookieCheck, $mPosted;
 11+ var $mCreateaccount, $mCreateaccountMail, $mMailmypassword;
 12+ var $mRemember, $mDomain, $mLanguage;
4213 var $mSkipCookieCheck, $mReturnToQuery;
4314
44 - private $mExtUser = null;
 15+ public $mDomains = array();
4516
46 - /**
47 - * Constructor
48 - * @param WebRequest $request A WebRequest object passed by reference
49 - */
50 - function LoginForm( &$request, $par = '' ) {
51 - global $wgAuth, $wgHiddenPrefs, $wgEnableEmail, $wgRedirectOnLogin;
 17+ public $mFormHeader = ''; # Can be filled by hooks etc
 18+ public $mFormFields = array(
 19+ 'Name' => array(
 20+ 'type' => 'text',
 21+ 'label-message' => 'yourname',
 22+ 'id' => 'wpName1',
 23+ 'tabindex' => '1',
 24+ 'size' => '20',
 25+ 'required' => '1',
 26+ ),
 27+ 'Password' => array(
 28+ 'type' => 'password',
 29+ 'label-message' => 'yourpassword',
 30+ 'size' => '20',
 31+ 'id' => 'wpPassword1',
 32+ ),
 33+ 'Domain' => array(
 34+ 'type' => 'select',
 35+ 'id' => 'wpDomain',
 36+ 'label-message' => 'yourdomainname',
 37+ 'options' => null,
 38+ 'default' => null,
 39+ ),
 40+ 'Remember' => array(
 41+ 'type' => 'check',
 42+ 'label-message' => 'remembermypassword',
 43+ 'id' => 'wpRemember',
 44+ )
 45+ );
5246
53 - $this->mType = ( $par == 'signup' ) ? $par : $request->getText( 'type' ); # Check for [[Special:Userlogin/signup]]
54 - $this->mName = $request->getText( 'wpName' );
55 - $this->mPassword = $request->getText( 'wpPassword' );
56 - $this->mRetype = $request->getText( 'wpRetype' );
57 - $this->mDomain = $request->getText( 'wpDomain' );
58 - $this->mReturnTo = $request->getVal( 'returnto' );
59 - $this->mReturnToQuery = $request->getVal( 'returntoquery' );
60 - $this->mCookieCheck = $request->getVal( 'wpCookieCheck' );
61 - $this->mPosted = $request->wasPosted();
62 - $this->mCreateaccount = $request->getCheck( 'wpCreateaccount' );
63 - $this->mCreateaccountMail = $request->getCheck( 'wpCreateaccountMail' )
64 - && $wgEnableEmail;
65 - $this->mMailmypassword = $request->getCheck( 'wpMailmypassword' )
66 - && $wgEnableEmail;
67 - $this->mLoginattempt = $request->getCheck( 'wpLoginattempt' );
68 - $this->mAction = $request->getVal( 'action' );
69 - $this->mRemember = $request->getCheck( 'wpRemember' );
70 - $this->mLanguage = $request->getText( 'uselang' );
71 - $this->mSkipCookieCheck = $request->getCheck( 'wpSkipCookieCheck' );
 47+ protected $mLogin; # Login object
7248
73 - if ( $wgRedirectOnLogin ) {
74 - $this->mReturnTo = $wgRedirectOnLogin;
75 - $this->mReturnToQuery = '';
76 - }
77 -
78 - if( $wgEnableEmail ) {
79 - $this->mEmail = $request->getText( 'wpEmail' );
80 - } else {
81 - $this->mEmail = '';
82 - }
83 - if( !in_array( 'realname', $wgHiddenPrefs ) ) {
84 - $this->mRealName = $request->getText( 'wpRealName' );
85 - } else {
86 - $this->mRealName = '';
87 - }
88 -
89 - if( !$wgAuth->validDomain( $this->mDomain ) ) {
90 - $this->mDomain = 'invaliddomain';
91 - }
92 - $wgAuth->setDomain( $this->mDomain );
93 -
94 - # When switching accounts, it sucks to get automatically logged out
95 - $returnToTitle = Title::newFromText( $this->mReturnTo );
96 - if( is_object( $returnToTitle ) && $returnToTitle->isSpecial( 'Userlogout' ) ) {
97 - $this->mReturnTo = '';
98 - $this->mReturnToQuery = '';
99 - }
 49+ public function __construct(){
 50+ parent::__construct( 'Userlogin' );
10051 }
10152
102 - function execute() {
103 - if ( !is_null( $this->mCookieCheck ) ) {
104 - $this->onCookieRedirectCheck( $this->mCookieCheck );
105 - return;
106 - } else if( $this->mPosted ) {
107 - if( $this->mCreateaccount ) {
108 - return $this->addNewAccount();
109 - } else if ( $this->mCreateaccountMail ) {
110 - return $this->addNewAccountMailPassword();
111 - } else if ( $this->mMailmypassword ) {
112 - return $this->mailPassword();
113 - } else if ( ( 'submitlogin' == $this->mAction ) || $this->mLoginattempt ) {
114 - return $this->processLogin();
115 - }
116 - }
117 - $this->mainLoginForm( '' );
118 - }
 53+ function execute( $par ) {
 54+ global $wgRequest;
11955
120 - /**
121 - * @private
122 - */
123 - function addNewAccountMailPassword() {
124 - global $wgOut;
125 -
126 - if ('' == $this->mEmail) {
127 - $this->mainLoginForm( wfMsg( 'noemail', htmlspecialchars( $this->mName ) ) );
 56+ # Redirect out for account creation, for B/C
 57+ $type = ( $par == 'signup' ) ? $par : $wgRequest->getText( 'type' );
 58+ if( $type == 'signup' ){
 59+ $sp = new SpecialCreateAccount();
 60+ $sp->execute( $par );
12861 return;
12962 }
130 -
131 - $u = $this->addNewaccountInternal();
132 -
133 - if ($u == NULL) {
134 - return;
 63+
 64+ # Because we're transitioning from logged-out, who might not
 65+ # have a session, to logged-in, who always do, we need to make
 66+ # sure that we *always* have a session...
 67+ if( session_id() == '' ) {
 68+ wfSetupSession();
13569 }
 70+
 71+ $this->loadQuery();
 72+ $this->mLogin = new Login();
13673
137 - // Wipe the initial password and mail a temporary one
138 - $u->setPassword( null );
139 - $u->saveSettings();
140 - $result = $this->mailPasswordInternal( $u, false, 'createaccount-title', 'createaccount-text' );
141 -
142 - wfRunHooks( 'AddNewAccount', array( $u, true ) );
143 - $u->addNewUserLogEntry();
144 -
145 - $wgOut->setPageTitle( wfMsg( 'accmailtitle' ) );
146 - $wgOut->setRobotPolicy( 'noindex,nofollow' );
147 - $wgOut->setArticleRelated( false );
148 -
149 - if( WikiError::isError( $result ) ) {
150 - $this->mainLoginForm( wfMsg( 'mailerror', $result->getMessage() ) );
151 - } else {
152 - $wgOut->addWikiMsg( 'accmailtext', $u->getName(), $u->getEmail() );
153 - $wgOut->returnToMain( false );
154 - }
155 - $u = 0;
156 - }
157 -
158 -
159 - /**
160 - * @private
161 - */
162 - function addNewAccount() {
163 - global $wgUser, $wgEmailAuthentication;
164 -
165 - # Create the account and abort if there's a problem doing so
166 - $u = $this->addNewAccountInternal();
167 - if( $u == NULL )
 74+ if ( $wgRequest->getCheck( 'wpCookieCheck' ) ) {
 75+ $this->onCookieRedirectCheck();
16876 return;
169 -
170 - # If we showed up language selection links, and one was in use, be
171 - # smart (and sensible) and save that language as the user's preference
172 - global $wgLoginLanguageSelector;
173 - if( $wgLoginLanguageSelector && $this->mLanguage )
174 - $u->setOption( 'language', $this->mLanguage );
175 -
176 - # Send out an email authentication message if needed
177 - if( $wgEmailAuthentication && User::isValidEmailAddr( $u->getEmail() ) ) {
178 - global $wgOut;
179 - $error = $u->sendConfirmationMail();
180 - if( WikiError::isError( $error ) ) {
181 - $wgOut->addWikiMsg( 'confirmemail_sendfailed', $error->getMessage() );
 77+ } else if( $wgRequest->wasPosted() ) {
 78+ if ( $this->mMailmypassword ) {
 79+ return $this->showMailPage();
18280 } else {
183 - $wgOut->addWikiMsg( 'confirmemail_oncreate' );
 81+ return $this->processLogin();
18482 }
185 - }
186 -
187 - # Save settings (including confirmation token)
188 - $u->saveSettings();
189 -
190 - # If not logged in, assume the new account as the current one and set
191 - # session cookies then show a "welcome" message or a "need cookies"
192 - # message as needed
193 - if( $wgUser->isAnon() ) {
194 - $wgUser = $u;
195 - $wgUser->setCookies();
196 - wfRunHooks( 'AddNewAccount', array( $wgUser ) );
197 - $wgUser->addNewUserLogEntry();
198 - if( $this->hasSessionCookie() ) {
199 - return $this->successfulCreation();
200 - } else {
201 - return $this->cookieRedirectCheck( 'new' );
202 - }
20383 } else {
204 - # Confirm that the account was created
205 - global $wgOut;
206 - $self = SpecialPage::getTitleFor( 'Userlogin' );
207 - $wgOut->setPageTitle( wfMsgHtml( 'accountcreated' ) );
208 - $wgOut->setArticleRelated( false );
209 - $wgOut->setRobotPolicy( 'noindex,nofollow' );
210 - $wgOut->addHTML( wfMsgWikiHtml( 'accountcreatedtext', $u->getName() ) );
211 - $wgOut->returnToMain( false, $self );
212 - wfRunHooks( 'AddNewAccount', array( $u ) );
213 - $u->addNewUserLogEntry();
214 - return true;
 84+ $this->mainLoginForm( '' );
21585 }
21686 }
21787
21888 /**
219 - * @private
 89+ * Load member variables from the HTTP request data
 90+ * @param $par String the fragment passed to execute()
22091 */
221 - function addNewAccountInternal() {
222 - global $wgUser, $wgOut;
223 - global $wgEnableSorbs, $wgProxyWhitelist;
224 - global $wgMemc, $wgAccountCreationThrottle;
225 - global $wgAuth, $wgMinimalPasswordLength;
226 - global $wgEmailConfirmToEdit;
 92+ protected function loadQuery(){
 93+ global $wgRequest, $wgAuth, $wgHiddenPrefs, $wgEnableEmail, $wgRedirectOnLogin;
22794
228 - // If the user passes an invalid domain, something is fishy
229 - if( !$wgAuth->validDomain( $this->mDomain ) ) {
230 - $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
231 - return false;
232 - }
 95+ $this->mUsername = $wgRequest->getText( 'wpName' );
 96+ $this->mPassword = $wgRequest->getText( 'wpPassword' );
 97+ $this->mDomain = $wgRequest->getText( 'wpDomain' );
 98+ $this->mLanguage = $wgRequest->getText( 'uselang' );
23399
234 - // If we are not allowing users to login locally, we should be checking
235 - // to see if the user is actually able to authenticate to the authenti-
236 - // cation server before they create an account (otherwise, they can
237 - // create a local account and login as any domain user). We only need
238 - // to check this for domains that aren't local.
239 - if( 'local' != $this->mDomain && '' != $this->mDomain ) {
240 - if( !$wgAuth->canCreateAccounts() && ( !$wgAuth->userExists( $this->mName ) || !$wgAuth->authenticate( $this->mName, $this->mPassword ) ) ) {
241 - $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
242 - return false;
243 - }
244 - }
 100+ $this->mReturnTo = $wgRequest->getVal( 'returnto' );
 101+ $this->mReturnToQuery = $wgRequest->getVal( 'returntoquery' );
245102
246 - if ( wfReadOnly() ) {
247 - $wgOut->readOnlyPage();
248 - return false;
249 - }
 103+ $this->mMailmypassword = $wgRequest->getCheck( 'wpMailmypassword' )
 104+ && $wgEnableEmail;
 105+ $this->mRemember = $wgRequest->getCheck( 'wpRemember' );
 106+ $this->mSkipCookieCheck = $wgRequest->getCheck( 'wpSkipCookieCheck' );
250107
251 - # Check permissions
252 - if ( !$wgUser->isAllowed( 'createaccount' ) ) {
253 - $this->userNotPrivilegedMessage();
254 - return false;
255 - } elseif ( $wgUser->isBlockedFromCreateAccount() ) {
256 - $this->userBlockedMessage();
257 - return false;
 108+ if( !$wgAuth->validDomain( $this->mDomain ) ) {
 109+ $this->mDomain = 'invaliddomain';
258110 }
259 -
260 - $ip = wfGetIP();
261 - if ( $wgEnableSorbs && !in_array( $ip, $wgProxyWhitelist ) &&
262 - $wgUser->inSorbsBlacklist( $ip ) )
263 - {
264 - $this->mainLoginForm( wfMsg( 'sorbs_create_account_reason' ) . ' (' . htmlspecialchars( $ip ) . ')' );
265 - return;
 111+ $wgAuth->setDomain( $this->mDomain );
 112+
 113+ if ( $wgRedirectOnLogin ) {
 114+ $this->mReturnTo = $wgRedirectOnLogin;
 115+ $this->mReturnToQuery = '';
266116 }
267 -
268 - # Now create a dummy user ($u) and check if it is valid
269 - $name = trim( $this->mName );
270 - $u = User::newFromName( $name, 'creatable' );
271 - if ( is_null( $u ) ) {
272 - $this->mainLoginForm( wfMsg( 'noname' ) );
273 - return false;
 117+ # When switching accounts, it sucks to get automatically logged out
 118+ $returnToTitle = Title::newFromText( $this->mReturnTo );
 119+ if( is_object( $returnToTitle ) && $returnToTitle->isSpecial( 'Userlogout' ) ) {
 120+ $this->mReturnTo = '';
 121+ $this->mReturnToQuery = '';
274122 }
275 -
276 - if ( 0 != $u->idForName() ) {
277 - $this->mainLoginForm( wfMsg( 'userexists' ) );
278 - return false;
279 - }
280 -
281 - if ( 0 != strcmp( $this->mPassword, $this->mRetype ) ) {
282 - $this->mainLoginForm( wfMsg( 'badretype' ) );
283 - return false;
284 - }
285 -
286 - # check for minimal password length
287 - $valid = $u->isValidPassword( $this->mPassword );
288 - if ( $valid !== true ) {
289 - if ( !$this->mCreateaccountMail ) {
290 - $this->mainLoginForm( wfMsgExt( $valid, array( 'parsemag' ), $wgMinimalPasswordLength ) );
291 - return false;
292 - } else {
293 - # do not force a password for account creation by email
294 - # set invalid password, it will be replaced later by a random generated password
295 - $this->mPassword = null;
296 - }
297 - }
298 -
299 - # if you need a confirmed email address to edit, then obviously you
300 - # need an email address.
301 - if ( $wgEmailConfirmToEdit && empty( $this->mEmail ) ) {
302 - $this->mainLoginForm( wfMsg( 'noemailtitle' ) );
303 - return false;
304 - }
305 -
306 - if( !empty( $this->mEmail ) && !User::isValidEmailAddr( $this->mEmail ) ) {
307 - $this->mainLoginForm( wfMsg( 'invalidemailaddress' ) );
308 - return false;
309 - }
310 -
311 - # Set some additional data so the AbortNewAccount hook can be used for
312 - # more than just username validation
313 - $u->setEmail( $this->mEmail );
314 - $u->setRealName( $this->mRealName );
315 -
316 - $abortError = '';
317 - if( !wfRunHooks( 'AbortNewAccount', array( $u, &$abortError ) ) ) {
318 - // Hook point to add extra creation throttles and blocks
319 - wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" );
320 - $this->mainLoginForm( $abortError );
321 - return false;
322 - }
323 -
324 - if ( $wgAccountCreationThrottle && $wgUser->isPingLimitable() ) {
325 - $key = wfMemcKey( 'acctcreate', 'ip', $ip );
326 - $value = $wgMemc->get( $key );
327 - if ( !$value ) {
328 - $wgMemc->set( $key, 0, 86400 );
329 - }
330 - if ( $value >= $wgAccountCreationThrottle ) {
331 - $this->throttleHit( $wgAccountCreationThrottle );
332 - return false;
333 - }
334 - $wgMemc->incr( $key );
335 - }
336 -
337 - if( !$wgAuth->addUser( $u, $this->mPassword, $this->mEmail, $this->mRealName ) ) {
338 - $this->mainLoginForm( wfMsg( 'externaldberror' ) );
339 - return false;
340 - }
341 -
342 - return $this->initUser( $u, false );
343123 }
344124
345125 /**
346 - * Actually add a user to the database.
347 - * Give it a User object that has been initialised with a name.
348 - *
349 - * @param $u User object.
350 - * @param $autocreate boolean -- true if this is an autocreation via auth plugin
351 - * @return User object.
352 - * @private
 126+ * Show the main login form
 127+ * @param $msg String a message key for a warning/error message
 128+ * that may have been generated on a previous iteration
353129 */
354 - function initUser( $u, $autocreate ) {
355 - global $wgAuth;
 130+ protected function mainLoginForm( $msg, $msgtype = 'error' ) {
 131+ global $wgUser, $wgOut, $wgEnableEmail;
 132+ global $wgCookiePrefix, $wgLoginLanguageSelector;
 133+ global $wgAuth, $wgCookieExpiration;
356134
357 - $u->addToDatabase();
358 -
359 - if ( $wgAuth->allowPasswordChange() ) {
360 - $u->setPassword( $this->mPassword );
361 - }
362 -
363 - $u->setEmail( $this->mEmail );
364 - $u->setRealName( $this->mRealName );
365 - $u->setToken();
366 -
367 - $wgAuth->initUser( $u, $autocreate );
368 -
369 - if ( $this->mExtUser ) {
370 - $this->mExtUser->link( $u->getId() );
371 - $email = $this->mExtUser->getPref( 'emailaddress' );
372 - if ( $email && !$this->mEmail ) {
373 - $u->setEmail( $email );
 135+ # Preload the name field with something if we can
 136+ if ( '' == $this->mUsername ) {
 137+ if ( $wgUser->isLoggedIn() ) {
 138+ $this->mUsername = $wgUser->getName();
 139+ } elseif( isset( $_COOKIE[$wgCookiePrefix.'UserName'] ) ) {
 140+ $this->mUsername = $_COOKIE[$wgCookiePrefix.'UserName'];
374141 }
375142 }
376 -
377 - $u->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 );
378 - $u->saveSettings();
379 -
380 - # Update user count
381 - $ssUpdate = new SiteStatsUpdate( 0, 0, 0, 0, 1 );
382 - $ssUpdate->doUpdate();
383 -
384 - return $u;
385 - }
386 -
387 - /**
388 - * Internally authenticate the login request.
389 - *
390 - * This may create a local account as a side effect if the
391 - * authentication plugin allows transparent local account
392 - * creation.
393 - *
394 - * @public
395 - */
396 - function authenticateUserData() {
397 - global $wgUser, $wgAuth;
398 - if ( '' == $this->mName ) {
399 - return self::NO_NAME;
400 - }
401 -
402 - global $wgPasswordAttemptThrottle;
403 -
404 - $throttleCount = 0;
405 - if ( is_array( $wgPasswordAttemptThrottle ) ) {
406 - $throttleKey = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
407 - $count = $wgPasswordAttemptThrottle['count'];
408 - $period = $wgPasswordAttemptThrottle['seconds'];
409 -
410 - global $wgMemc;
411 - $throttleCount = $wgMemc->get( $throttleKey );
412 - if ( !$throttleCount ) {
413 - $wgMemc->add( $throttleKey, 1, $period ); // start counter
414 - } else if ( $throttleCount < $count ) {
415 - $wgMemc->incr($throttleKey);
416 - } else if ( $throttleCount >= $count ) {
417 - return self::THROTTLED;
418 - }
419 - }
420 -
421 - // Load $wgUser now, and check to see if we're logging in as the same
422 - // name. This is necessary because loading $wgUser (say by calling
423 - // getName()) calls the UserLoadFromSession hook, which potentially
424 - // creates the user in the database. Until we load $wgUser, checking
425 - // for user existence using User::newFromName($name)->getId() below
426 - // will effectively be using stale data.
427 - if ( $wgUser->getName() === $this->mName ) {
428 - wfDebug( __METHOD__.": already logged in as {$this->mName}\n" );
429 - return self::SUCCESS;
430 - }
431 -
432 - $this->mExtUser = ExternalUser::newFromName( $this->mName );
433 -
434 - # TODO: Allow some magic here for invalid external names, e.g., let the
435 - # user choose a different wiki name.
436 - $u = User::newFromName( $this->mName );
437 - if( is_null( $u ) || !User::isUsableName( $u->getName() ) ) {
438 - return self::ILLEGAL;
439 - }
440 -
441 - $isAutoCreated = false;
442 - if ( 0 == $u->getID() ) {
443 - $status = $this->attemptAutoCreate( $u );
444 - if ( $status !== self::SUCCESS ) {
445 - return $status;
446 - } else {
447 - $isAutoCreated = true;
448 - }
 143+ if( $this->mUsername ){
 144+ $this->mFormFields['Name']['default'] = $this->mUsername;
 145+ $this->mFormFields['Password']['autofocus'] = '1';
449146 } else {
450 - $u->load();
 147+ $this->mFormFields['Name']['autofocus'] = '1';
451148 }
452149
453 - // Give general extensions, such as a captcha, a chance to abort logins
454 - $abort = self::ABORTED;
455 - if( !wfRunHooks( 'AbortLogin', array( $u, $this->mPassword, &$abort ) ) ) {
456 - return $abort;
457 - }
458 -
459 - if (!$u->checkPassword( $this->mPassword )) {
460 - if( $u->checkTemporaryPassword( $this->mPassword ) ) {
461 - // The e-mailed temporary password should not be used for actu-
462 - // al logins; that's a very sloppy habit, and insecure if an
463 - // attacker has a few seconds to click "search" on someone's o-
464 - // pen mail reader.
465 - //
466 - // Allow it to be used only to reset the password a single time
467 - // to a new value, which won't be in the user's e-mail ar-
468 - // chives.
469 - //
470 - // For backwards compatibility, we'll still recognize it at the
471 - // login form to minimize surprises for people who have been
472 - // logging in with a temporary password for some time.
473 - //
474 - // As a side-effect, we can authenticate the user's e-mail ad-
475 - // dress if it's not already done, since the temporary password
476 - // was sent via e-mail.
477 - if( !$u->isEmailConfirmed() ) {
478 - $u->confirmEmail();
479 - $u->saveSettings();
480 - }
481 -
482 - // At this point we just return an appropriate code/ indicating
483 - // that the UI should show a password reset form; bot inter-
484 - // faces etc will probably just fail cleanly here.
485 - $retval = self::RESET_PASS;
486 - } else {
487 - $retval = '' == $this->mPassword ? self::EMPTY_PASS : self::WRONG_PASS;
 150+ # Parse the error message if we got one
 151+ if( $msg ){
 152+ if( $msgtype == 'error' ){
 153+ $msg = wfMsgExt( 'loginerror', 'parseinline' ) . ' ' . $msg;
488154 }
 155+ $msg = Html::rawElement(
 156+ 'div',
 157+ array( 'class' => $msgtype . 'box' ),
 158+ $msg
 159+ );
489160 } else {
490 - $wgAuth->updateUser( $u );
491 - $wgUser = $u;
492 -
493 - // Please reset throttle for successful logins, thanks!
494 - if($throttleCount) {
495 - $wgMemc->delete($throttleKey);
496 - }
497 -
498 - if ( $isAutoCreated ) {
499 - // Must be run after $wgUser is set, for correct new user log
500 - wfRunHooks( 'AuthPluginAutoCreate', array( $wgUser ) );
501 - }
502 -
503 - $retval = self::SUCCESS;
 161+ $msg = '';
504162 }
505 - wfRunHooks( 'LoginAuthenticateAudit', array( $u, $this->mPassword, $retval ) );
506 - return $retval;
507 - }
508163
509 - /**
510 - * Attempt to automatically create a user on login. Only succeeds if there
511 - * is an external authentication method which allows it.
512 - * @return integer Status code
513 - */
514 - function attemptAutoCreate( $user ) {
515 - global $wgAuth, $wgUser, $wgAutocreatePolicy;
516 -
517 - if ( $wgUser->isBlockedFromCreateAccount() ) {
518 - wfDebug( __METHOD__.": user is blocked from account creation\n" );
519 - return self::CREATE_BLOCKED;
520 - }
521 -
522 - /**
523 - * If the external authentication plugin allows it, automatically cre-
524 - * ate a new account for users that are externally defined but have not
525 - * yet logged in.
526 - */
527 - if ( $this->mExtUser ) {
528 - # mExtUser is neither null nor false, so use the new ExternalAuth
529 - # system.
530 - if ( $wgAutocreatePolicy == 'never' ) {
531 - return self::NOT_EXISTS;
532 - }
533 - if ( !$this->mExtUser->authenticate( $this->mPassword ) ) {
534 - return self::WRONG_PLUGIN_PASS;
535 - }
536 - } else {
537 - # Old AuthPlugin.
538 - if ( !$wgAuth->autoCreate() ) {
539 - return self::NOT_EXISTS;
540 - }
541 - if ( !$wgAuth->userExists( $user->getName() ) ) {
542 - wfDebug( __METHOD__.": user does not exist\n" );
543 - return self::NOT_EXISTS;
544 - }
545 - if ( !$wgAuth->authenticate( $user->getName(), $this->mPassword ) ) {
546 - wfDebug( __METHOD__.": \$wgAuth->authenticate() returned false, aborting\n" );
547 - return self::WRONG_PLUGIN_PASS;
548 - }
549 - }
550 -
551 - wfDebug( __METHOD__.": creating account\n" );
552 - $user = $this->initUser( $user, true );
553 - return self::SUCCESS;
554 - }
555 -
556 - function processLogin() {
557 - global $wgUser, $wgAuth;
558 -
559 - switch ( $this->authenticateUserData() ) {
560 - case self::SUCCESS:
561 - # We've verified now, update the real record
562 - if( (bool)$this->mRemember != (bool)$wgUser->getOption( 'rememberpassword' ) ) {
563 - $wgUser->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 );
564 - $wgUser->saveSettings();
565 - } else {
566 - $wgUser->invalidateCache();
567 - }
568 - $wgUser->setCookies();
569 -
570 - // Reset the throttle
571 - $key = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
572 - global $wgMemc;
573 - $wgMemc->delete( $key );
574 -
575 - if( $this->hasSessionCookie() || $this->mSkipCookieCheck ) {
576 - /* Replace the language object to provide user interface in
577 - * correct language immediately on this first page load.
578 - */
579 - global $wgLang, $wgRequest;
580 - $code = $wgRequest->getVal( 'uselang', $wgUser->getOption( 'language' ) );
581 - $wgLang = Language::factory( $code );
582 - return $this->successfulLogin();
583 - } else {
584 - return $this->cookieRedirectCheck( 'login' );
585 - }
586 - break;
587 -
588 - case self::NO_NAME:
589 - case self::ILLEGAL:
590 - $this->mainLoginForm( wfMsg( 'noname' ) );
591 - break;
592 - case self::WRONG_PLUGIN_PASS:
593 - $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
594 - break;
595 - case self::NOT_EXISTS:
596 - if( $wgUser->isAllowed( 'createaccount' ) ){
597 - $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $this->mName ) ) );
598 - } else {
599 - $this->mainLoginForm( wfMsg( 'nosuchusershort', htmlspecialchars( $this->mName ) ) );
600 - }
601 - break;
602 - case self::WRONG_PASS:
603 - $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
604 - break;
605 - case self::EMPTY_PASS:
606 - $this->mainLoginForm( wfMsg( 'wrongpasswordempty' ) );
607 - break;
608 - case self::RESET_PASS:
609 - $this->resetLoginForm( wfMsg( 'resetpass_announce' ) );
610 - break;
611 - case self::CREATE_BLOCKED:
612 - $this->userBlockedMessage();
613 - break;
614 - case self::THROTTLED:
615 - $this->mainLoginForm( wfMsg( 'login-throttled' ) );
616 - break;
617 - default:
618 - throw new MWException( "Unhandled case value" );
619 - }
620 - }
621 -
622 - function resetLoginForm( $error ) {
623 - global $wgOut;
624 - $wgOut->addHTML( Xml::element('p', array( 'class' => 'error' ), $error ) );
625 - $reset = new SpecialResetpass();
626 - $reset->execute( null );
627 - }
628 -
629 - /**
630 - * @private
631 - */
632 - function mailPassword() {
633 - global $wgUser, $wgOut, $wgAuth;
634 -
635 - if ( wfReadOnly() ) {
636 - $wgOut->readOnlyPage();
637 - return false;
638 - }
639 -
640 - if( !$wgAuth->allowPasswordChange() ) {
641 - $this->mainLoginForm( wfMsg( 'resetpass_forbidden' ) );
642 - return;
643 - }
644 -
645 - # Check against blocked IPs
646 - # fixme -- should we not?
647 - if( $wgUser->isBlocked() ) {
648 - $this->mainLoginForm( wfMsg( 'blocked-mailpassword' ) );
649 - return;
650 - }
651 -
652 - // Check for hooks
653 - $error = null;
654 - if ( ! wfRunHooks( 'UserLoginMailPassword', array( $this->mName, &$error ) ) ) {
655 - $this->mainLoginForm( $error );
656 - return;
657 - }
658 -
659 - # Check against the rate limiter
660 - if( $wgUser->pingLimiter( 'mailpassword' ) ) {
661 - $wgOut->rateLimited();
662 - return;
663 - }
664 -
665 - if ( '' == $this->mName ) {
666 - $this->mainLoginForm( wfMsg( 'noname' ) );
667 - return;
668 - }
669 - $u = User::newFromName( $this->mName );
670 - if( is_null( $u ) ) {
671 - $this->mainLoginForm( wfMsg( 'noname' ) );
672 - return;
673 - }
674 - if ( 0 == $u->getID() ) {
675 - $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $u->getName() ) ) );
676 - return;
677 - }
678 -
679 - # Check against password throttle
680 - if ( $u->isPasswordReminderThrottled() ) {
681 - global $wgPasswordReminderResendTime;
682 - # Round the time in hours to 3 d.p., in case someone is specifying
683 - # minutes or seconds.
684 - $this->mainLoginForm( wfMsgExt( 'throttled-mailpassword', array( 'parsemag' ),
685 - round( $wgPasswordReminderResendTime, 3 ) ) );
686 - return;
687 - }
688 -
689 - $result = $this->mailPasswordInternal( $u, true, 'passwordremindertitle', 'passwordremindertext' );
690 - if( WikiError::isError( $result ) ) {
691 - $this->mainLoginForm( wfMsg( 'mailerror', $result->getMessage() ) );
692 - } else {
693 - $this->mainLoginForm( wfMsg( 'passwordsent', $u->getName() ), 'success' );
694 - }
695 - }
696 -
697 -
698 - /**
699 - * @param object user
700 - * @param bool throttle
701 - * @param string message name of email title
702 - * @param string message name of email text
703 - * @return mixed true on success, WikiError on failure
704 - * @private
705 - */
706 - function mailPasswordInternal( $u, $throttle = true, $emailTitle = 'passwordremindertitle', $emailText = 'passwordremindertext' ) {
707 - global $wgServer, $wgScript, $wgUser, $wgNewPasswordExpiry;
708 -
709 - if ( '' == $u->getEmail() ) {
710 - return new WikiError( wfMsg( 'noemail', $u->getName() ) );
711 - }
712 - $ip = wfGetIP();
713 - if( !$ip ) {
714 - return new WikiError( wfMsg( 'badipaddress' ) );
715 - }
716 -
717 - wfRunHooks( 'User::mailPasswordInternal', array(&$wgUser, &$ip, &$u) );
718 -
719 - $np = $u->randomPassword();
720 - $u->setNewpassword( $np, $throttle );
721 - $u->saveSettings();
722 -
723 - $m = wfMsgExt( $emailText, array( 'parsemag' ), $ip, $u->getName(), $np,
724 - $wgServer . $wgScript, round( $wgNewPasswordExpiry / 86400 ) );
725 - $result = $u->sendMail( wfMsg( $emailTitle ), $m );
726 -
727 - return $result;
728 - }
729 -
730 -
731 - /**
732 - * Run any hooks registered for logins, then HTTP redirect to
733 - * $this->mReturnTo (or Main Page if that's undefined). Formerly we had a
734 - * nice message here, but that's really not as useful as just being sent to
735 - * wherever you logged in from. It should be clear that the action was
736 - * successful, given the lack of error messages plus the appearance of your
737 - * name in the upper right.
738 - *
739 - * @private
740 - */
741 - function successfulLogin() {
742 - global $wgUser, $wgOut;
743 -
744 - # Run any hooks; display injected HTML if any, else redirect
745 - $injected_html = '';
746 - wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
747 -
748 - if( $injected_html !== '' ) {
749 - $this->displaySuccessfulLogin( 'loginsuccess', $injected_html );
750 - } else {
751 - $titleObj = Title::newFromText( $this->mReturnTo );
752 - if ( !$titleObj instanceof Title ) {
753 - $titleObj = Title::newMainPage();
754 - }
755 - $wgOut->redirect( $titleObj->getFullURL( $this->mReturnToQuery ) );
756 - }
757 - }
758 -
759 - /**
760 - * Run any hooks registered for logins, then display a message welcoming
761 - * the user.
762 - *
763 - * @private
764 - */
765 - function successfulCreation() {
766 - global $wgUser, $wgOut;
767 -
768 - # Run any hooks; display injected HTML
769 - $injected_html = '';
770 - wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
771 -
772 - $this->displaySuccessfulLogin( 'welcomecreation', $injected_html );
773 - }
774 -
775 - /**
776 - * Display a "login successful" page.
777 - */
778 - private function displaySuccessfulLogin( $msgname, $injected_html ) {
779 - global $wgOut, $wgUser;
780 -
781 - $wgOut->setPageTitle( wfMsg( 'loginsuccesstitle' ) );
782 - $wgOut->setRobotPolicy( 'noindex,nofollow' );
783 - $wgOut->setArticleRelated( false );
784 - $wgOut->addWikiMsg( $msgname, $wgUser->getName() );
785 - $wgOut->addHTML( $injected_html );
786 -
 164+ # Make sure the returnTo strings don't get lost if the
 165+ # user changes language, etc
 166+ $linkq = array();
787167 if ( !empty( $this->mReturnTo ) ) {
788 - $wgOut->returnToMain( null, $this->mReturnTo, $this->mReturnToQuery );
789 - } else {
790 - $wgOut->returnToMain( null );
791 - }
792 - }
793 -
794 - /** */
795 - function userNotPrivilegedMessage($errors) {
796 - global $wgOut;
797 -
798 - $wgOut->setPageTitle( wfMsg( 'permissionserrors' ) );
799 - $wgOut->setRobotPolicy( 'noindex,nofollow' );
800 - $wgOut->setArticleRelated( false );
801 -
802 - $wgOut->addWikitext( $wgOut->formatPermissionsErrorMessage( $errors, 'createaccount' ) );
803 - // Stuff that might want to be added at the end. For example, instruc-
804 - // tions if blocked.
805 - $wgOut->addWikiMsg( 'cantcreateaccount-nonblock-text' );
806 -
807 - $wgOut->returnToMain( false );
808 - }
809 -
810 - /** */
811 - function userBlockedMessage() {
812 - global $wgOut, $wgUser;
813 -
814 - # Let's be nice about this, it's likely that this feature will be used
815 - # for blocking large numbers of innocent people, e.g. range blocks on
816 - # schools. Don't blame it on the user. There's a small chance that it
817 - # really is the user's fault, i.e. the username is blocked and they
818 - # haven't bothered to log out before trying to create an account to
819 - # evade it, but we'll leave that to their guilty conscience to figure
820 - # out.
821 -
822 - $wgOut->setPageTitle( wfMsg( 'cantcreateaccounttitle' ) );
823 - $wgOut->setRobotPolicy( 'noindex,nofollow' );
824 - $wgOut->setArticleRelated( false );
825 -
826 - $ip = wfGetIP();
827 - $blocker = User::whoIs( $wgUser->mBlock->mBy );
828 - $block_reason = $wgUser->mBlock->mReason;
829 -
830 - if ( strval( $block_reason ) === '' ) {
831 - $block_reason = wfMsg( 'blockednoreason' );
832 - }
833 - $wgOut->addWikiMsg( 'cantcreateaccount-text', $ip, $block_reason, $blocker );
834 - $wgOut->returnToMain( false );
835 - }
836 -
837 - /**
838 - * @private
839 - */
840 - function mainLoginForm( $msg, $msgtype = 'error' ) {
841 - global $wgUser, $wgOut, $wgHiddenPrefs, $wgEnableEmail;
842 - global $wgCookiePrefix, $wgLoginLanguageSelector;
843 - global $wgAuth, $wgEmailConfirmToEdit, $wgCookieExpiration;
844 -
845 - $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
846 -
847 - if ( $this->mType == 'signup' ) {
848 - // Block signup here if in readonly. Keeps user from
849 - // going through the process (filling out data, etc)
850 - // and being informed later.
851 - if ( wfReadOnly() ) {
852 - $wgOut->readOnlyPage();
853 - return;
854 - } elseif ( $wgUser->isBlockedFromCreateAccount() ) {
855 - $this->userBlockedMessage();
856 - return;
857 - } elseif ( count( $permErrors = $titleObj->getUserPermissionsErrors( 'createaccount', $wgUser, true ) )>0 ) {
858 - $wgOut->showPermissionsErrorPage( $permErrors, 'createaccount' );
859 - return;
860 - }
861 - }
862 -
863 - if ( '' == $this->mName ) {
864 - if ( $wgUser->isLoggedIn() ) {
865 - $this->mName = $wgUser->getName();
866 - } else {
867 - $this->mName = isset( $_COOKIE[$wgCookiePrefix.'UserName'] ) ? $_COOKIE[$wgCookiePrefix.'UserName'] : null;
868 - }
869 - }
870 -
871 - $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
872 -
873 - if ( $this->mType == 'signup' ) {
874 - $template = new UsercreateTemplate();
875 - $q = 'action=submitlogin&type=signup';
876 - $linkq = 'type=login';
877 - $linkmsg = 'gotaccount';
878 - } else {
879 - $template = new UserloginTemplate();
880 - $q = 'action=submitlogin&type=login';
881 - $linkq = 'type=signup';
882 - $linkmsg = 'nologin';
883 - }
884 -
885 - if ( !empty( $this->mReturnTo ) ) {
886 - $returnto = '&returnto=' . wfUrlencode( $this->mReturnTo );
 168+ $linkq['returnto'] = wfUrlencode( $this->mReturnTo );
887169 if ( !empty( $this->mReturnToQuery ) )
888 - $returnto .= '&returntoquery=' .
889 - wfUrlencode( $this->mReturnToQuery );
890 - $q .= $returnto;
891 - $linkq .= $returnto;
 170+ $linkq['returntoquery'] = wfUrlencode( $this->mReturnToQuery );
892171 }
893172
894173 # Pass any language selection on to the mode switch link
895174 if( $wgLoginLanguageSelector && $this->mLanguage )
896 - $linkq .= '&uselang=' . $this->mLanguage;
 175+ $linkq['uselang'] = $this->mLanguage;
897176
898 - $link = '<a href="' . htmlspecialchars ( $titleObj->getLocalUrl( $linkq ) ) . '">';
899 - $link .= wfMsgHtml( $linkmsg . 'link' ); # Calling either 'gotaccountlink' or 'nologinlink'
900 - $link .= '</a>';
 177+ $skin = $wgUser->getSkin();
 178+ $link = $skin->link(
 179+ SpecialPage::getTitleFor( 'CreateAccount' ),
 180+ wfMsgHtml( 'nologinlink' ),
 181+ array(),
 182+ $linkq );
901183
902184 # Don't show a "create account" link if the user can't
903 - if( $this->showCreateOrLoginLink( $wgUser ) )
904 - $template->set( 'link', wfMsgWikiHtml( $linkmsg, $link ) );
905 - else
906 - $template->set( 'link', '' );
 185+ $link = $wgUser->isAllowed( 'createaccount' ) && !$wgUser->isLoggedIn()
 186+ ? wfMsgWikiHtml( 'nologin', $link )
 187+ : '';
907188
908 - $template->set( 'header', '' );
909 - $template->set( 'name', $this->mName );
910 - $template->set( 'password', $this->mPassword );
911 - $template->set( 'retype', $this->mRetype );
912 - $template->set( 'email', $this->mEmail );
913 - $template->set( 'realname', $this->mRealName );
914 - $template->set( 'domain', $this->mDomain );
915 -
916 - $template->set( 'action', $titleObj->getLocalUrl( $q ) );
917 - $template->set( 'message', $msg );
918 - $template->set( 'messagetype', $msgtype );
919 - $template->set( 'createemail', $wgEnableEmail && $wgUser->isLoggedIn() );
920 - $template->set( 'userealname', !in_array( 'realname', $wgHiddenPrefs ) );
921 - $template->set( 'useemail', $wgEnableEmail );
922 - $template->set( 'emailrequired', $wgEmailConfirmToEdit );
923 - $template->set( 'canreset', $wgAuth->allowPasswordChange() );
924 - $template->set( 'canremember', ( $wgCookieExpiration > 0 ) );
925 - $template->set( 'remember', $wgUser->getOption( 'rememberpassword' ) or $this->mRemember );
926 -
927189 # Prepare language selection links as needed
928 - if( $wgLoginLanguageSelector ) {
929 - $template->set( 'languages', $this->makeLanguageSelector() );
930 - if( $this->mLanguage )
931 - $template->set( 'uselang', $this->mLanguage );
 190+ $langSelector = $wgLoginLanguageSelector
 191+ ? Html::rawElement(
 192+ 'div',
 193+ array( 'id' => 'languagelinks' ),
 194+ self::makeLanguageSelector( $this->getTitle(), $this->mReturnTo ) )
 195+ : '';
 196+
 197+ # Add a 'mail reset' button if available
 198+ $buttons = '';
 199+ if( $wgEnableEmail && $wgAuth->allowPasswordChange() ){
 200+ $buttons = Html::element(
 201+ 'input',
 202+ array(
 203+ 'type' => 'submit',
 204+ 'name' => 'wpMailmypassword',
 205+ 'value' => wfMsg( 'mailmypassword' ),
 206+ 'id' => 'wpMailmypassword',
 207+ )
 208+ );
932209 }
933210
934 - // Give authentication and captcha plugins a chance to modify the form
935 - $wgAuth->modifyUITemplate( $template, $this->mType );
936 - if ( $this->mType == 'signup' ) {
937 - wfRunHooks( 'UserCreateForm', array( &$template ) );
 211+ # Give authentication and captcha plugins a chance to
 212+ # modify the form, by hook or by using $wgAuth
 213+ $wgAuth->modifyUITemplate( $this, 'login' );
 214+ wfRunHooks( 'UserLoginForm', array( &$this ) );
 215+
 216+ # The most likely use of the hook is to enable domains;
 217+ # check that now, and add fields if necessary
 218+ if( $this->mDomains ){
 219+ $this->mFormFields['Domain']['options'] = $this->mDomains;
 220+ $this->mFormFields['Domain']['default'] = $this->mDomain;
938221 } else {
939 - wfRunHooks( 'UserLoginForm', array( &$template ) );
 222+ unset( $this->mFormFields['Domain'] );
940223 }
 224+
 225+ # Or to tweak the 'remember my password' checkbox
 226+ if( !($wgCookieExpiration > 0) ){
 227+ # Remove it altogether
 228+ unset( $this->mFormFields['Remember'] );
 229+ } elseif( $wgUser->getOption( 'rememberpassword' ) || $this->mRemember ){
 230+ # Or check it by default
 231+ # FIXME: this doesn't always work?
 232+ $this->mFormFields['Remember']['checked'] = '1';
 233+ }
 234+
 235+ $form = new HTMLForm( $this->mFormFields, '' );
 236+ $form->setTitle( $this->getTitle() );
 237+ $form->setSubmitText( wfMsg( 'login' ) );
 238+ $form->setSubmitId( 'wpLoginAttempt' );
 239+ $form->suppressReset();
 240+ $form->loadData();
 241+
 242+ $formContents = ''
 243+ . Html::rawElement( 'p', array( 'id' => 'userloginlink' ),
 244+ $link )
 245+ . Html::rawElement( 'div', array( 'id' => 'userloginprompt' ),
 246+ wfMsgExt( 'loginprompt', array( 'parseinline' ) ) )
 247+ . $this->mFormHeader
 248+ . $langSelector
 249+ . $form->getBody()
 250+ . $form->getButtons()
 251+ . $buttons
 252+ . Xml::hidden( 'returnto', $this->mReturnTo )
 253+ . Xml::hidden( 'returntoquery', $this->mReturnToQuery )
 254+ ;
941255
942 - $wgOut->setPageTitle( wfMsg( 'userlogin' ) );
 256+ $wgOut->setPageTitle( wfMsg( 'login' ) );
943257 $wgOut->setRobotPolicy( 'noindex,nofollow' );
944258 $wgOut->setArticleRelated( false );
945 - $wgOut->disallowUserJs(); // just in case...
946 - $wgOut->addTemplate( $template );
947 - }
 259+ $wgOut->disallowUserJs(); # Stop malicious userscripts sniffing passwords
948260
949 - /**
950 - * @private
951 - */
952 - function showCreateOrLoginLink( &$user ) {
953 - if( $this->mType == 'signup' ) {
954 - return( true );
955 - } elseif( $user->isAllowed( 'createaccount' ) ) {
956 - return( true );
957 - } else {
958 - return( false );
959 - }
960 - }
 261+ $wgOut->addHTML(
 262+ Html::rawElement(
 263+ 'div',
 264+ array( 'id' => 'loginstart' ),
 265+ wfMsgExt( 'loginstart', array( 'parseinline' ) )
 266+ ) .
 267+ $msg .
 268+ Html::rawElement(
 269+ 'div',
 270+ array( 'id' => 'userloginForm' ),
 271+ $form->wrapForm( $formContents )
 272+ ) .
 273+ Html::rawElement(
 274+ 'div',
 275+ array( 'id' => 'loginend' ),
 276+ wfMsgExt( 'loginend', array( 'parseinline' ) )
 277+ )
 278+ );
 279+ }
961280
962281 /**
963282 * Check if a session cookie is present.
@@ -967,57 +286,49 @@
968287 *
969288 * @private
970289 */
971 - function hasSessionCookie() {
 290+ protected function hasSessionCookie() {
972291 global $wgDisableCookieCheck, $wgRequest;
973 - return $wgDisableCookieCheck ? true : $wgRequest->checkSessionCookie();
 292+ return $wgDisableCookieCheck || $wgRequest->checkSessionCookie();
974293 }
975294
976295 /**
977 - * @private
 296+ * Do a redirect back to the same page, so we can check any
 297+ * new session cookies.
978298 */
979 - function cookieRedirectCheck( $type ) {
 299+ protected function cookieRedirectCheck() {
980300 global $wgOut;
981301
982 - $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
983 - $query = array( 'wpCookieCheck' => $type );
 302+ $query = array( 'wpCookieCheck' => '1');
984303 if ( $this->mReturnTo ) $query['returnto'] = $this->mReturnTo;
985 - $check = $titleObj->getFullURL( $query );
 304+ $check = $this->getTitle()->getFullURL( $query );
986305
987306 return $wgOut->redirect( $check );
988307 }
989308
990309 /**
991 - * @private
 310+ * Check the cookies and show errors if they're not enabled.
 311+ * @param $type String action being performed
992312 */
993 - function onCookieRedirectCheck( $type ) {
994 - if ( !$this->hasSessionCookie() ) {
995 - if ( $type == 'new' ) {
996 - return $this->mainLoginForm( wfMsgExt( 'nocookiesnew', array( 'parseinline' ) ) );
997 - } else if ( $type == 'login' ) {
998 - return $this->mainLoginForm( wfMsgExt( 'nocookieslogin', array( 'parseinline' ) ) );
999 - } else {
1000 - # shouldn't happen
1001 - return $this->mainLoginForm( wfMsg( 'error' ) );
1002 - }
 313+ protected function onCookieRedirectCheck() {
 314+ if ( $this->hasSessionCookie() ) {
 315+ return self::successfulLogin(
 316+ 'loginsuccess',
 317+ $this->mReturnTo,
 318+ $this->mReturnToQuery
 319+ );
1003320 } else {
1004 - return $this->successfulLogin();
 321+ return $this->mainLoginForm( wfMsgExt( 'nocookieslogin', array( 'parseinline' ) ) );
1005322 }
1006323 }
1007324
1008325 /**
1009 - * @private
1010 - */
1011 - function throttleHit( $limit ) {
1012 - $this->mainLoginForm( wfMsgExt( 'acct_creation_throttle_hit', array( 'parseinline' ), $limit ) );
1013 - }
1014 -
1015 - /**
1016326 * Produce a bar of links which allow the user to select another language
1017327 * during login/registration but retain "returnto"
1018 - *
1019 - * @return string
 328+ * @param $title Title to use in the link
 329+ * @param $returnTo query string to append
 330+ * @return String HTML for bar
1020331 */
1021 - function makeLanguageSelector() {
 332+ public static function makeLanguageSelector( $title, $returnTo=false ) {
1022333 global $wgLang;
1023334
1024335 $msg = wfMsgForContent( 'loginlanguagelinks' );
@@ -1028,7 +339,8 @@
1029340 $lang = trim( $lang, '* ' );
1030341 $parts = explode( '|', $lang );
1031342 if (count($parts) >= 2) {
1032 - $links[] = $this->makeLanguageSelectorLink( $parts[0], $parts[1] );
 343+ $links[] = SpecialUserLogin::makeLanguageSelectorLink(
 344+ $parts[0], $parts[1], $title, $returnTo );
1033345 }
1034346 }
1035347 return count( $links ) > 0 ? wfMsgHtml( 'loginlanguagelabel', $wgLang->pipeList( $links ) ) : '';
@@ -1040,24 +352,204 @@
1041353 /**
1042354 * Create a language selector link for a particular language
1043355 * Links back to this page preserving type and returnto
1044 - *
1045356 * @param $text Link text
1046357 * @param $lang Language code
 358+ * @param $title Title to link to
 359+ * @param $returnTo String returnto query
1047360 */
1048 - function makeLanguageSelectorLink( $text, $lang ) {
 361+ public static function makeLanguageSelectorLink( $text, $lang, $title, $returnTo=false ) {
1049362 global $wgUser;
1050 - $self = SpecialPage::getTitleFor( 'Userlogin' );
1051363 $attr = array( 'uselang' => $lang );
1052 - if( $this->mType == 'signup' )
1053 - $attr['type'] = 'signup';
1054 - if( $this->mReturnTo )
1055 - $attr['returnto'] = $this->mReturnTo;
 364+ if( $returnTo )
 365+ $attr['returnto'] = $returnTo;
1056366 $skin = $wgUser->getSkin();
1057367 return $skin->linkKnown(
1058 - $self,
 368+ $title,
1059369 htmlspecialchars( $text ),
1060370 array(),
1061371 $attr
1062372 );
1063373 }
 374+
 375+ /**
 376+ * Display a "login successful" page.
 377+ * @param $message String message key of main message to display
 378+ * @param $html String HTML to optionally add
 379+ * @param $returnto Title to returnto
 380+ * @param $returntoQuery String query string for returnto link
 381+ */
 382+ public static function displaySuccessfulLogin( $message, $html='', $returnTo=false, $returnToQuery=false ) {
 383+ global $wgOut, $wgUser;
 384+
 385+ $wgOut->setPageTitle( wfMsg( 'loginsuccesstitle' ) );
 386+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
 387+ $wgOut->setArticleRelated( false );
 388+ $wgOut->addWikiMsg( $message, $wgUser->getName() );
 389+ $wgOut->addHTML( $html );
 390+
 391+ if ( $returnTo ) {
 392+ $wgOut->returnToMain( null, $returnTo, $returnToQuery );
 393+ } else {
 394+ $wgOut->returnToMain( null );
 395+ }
 396+ }
 397+
 398+ /**
 399+ * Display any messages generated by hooks, or HTTP redirect to
 400+ * $this->mReturnTo (or Main Page if that's undefined). Formerly we had a
 401+ * nice message here, but that's not as useful as just being sent to
 402+ * wherever you logged in from. It should be clear that the action was
 403+ * successful, given the lack of error messages plus the appearance of your
 404+ * name in the upper right.
 405+ *
 406+ * Remember that this function can be accessed from a variety of
 407+ * places, such as Special:ResetPass, or Special:CreateAccount.
 408+ * @param $message String message key of a message to display if
 409+ * we don't redirect
 410+ * @param $returnTo String title of page to redirect to
 411+ * @param $returnToQuery String query string to add to the redirect.
 412+ * @param $html String empty string to go straight
 413+ * to the redirect, or valid HTML to add underneath the text.
 414+ */
 415+ public static function successfulLogin( $message, $returnTo='', $returnToQuery='', $html='' ) {
 416+ global $wgUser, $wgOut;
 417+
 418+ if( $html === '' ) {
 419+ $titleObj = Title::newFromText( $returnTo );
 420+ if ( !$titleObj instanceof Title ) {
 421+ $titleObj = Title::newMainPage();
 422+ }
 423+ $wgOut->redirect( $titleObj->getFullURL( $returnToQuery ) );
 424+ } else {
 425+ SpecialUserLogin::displaySuccessfulLogin( $message, $html, $returnTo, $returnToQuery );
 426+ }
 427+ }
 428+
 429+
 430+ protected function processLogin(){
 431+ global $wgUser, $wgAuth;
 432+ $result = $this->mLogin->attemptLogin();
 433+ switch ( $result ) {
 434+ case Login::SUCCESS:
 435+ if( $this->hasSessionCookie() || $this->mSkipCookieCheck ) {
 436+ # Replace the language object to provide user interface in
 437+ # correct language immediately on this first page load.
 438+ global $wgLang, $wgRequest;
 439+ $code = $wgRequest->getVal( 'uselang', $wgUser->getOption( 'language' ) );
 440+ $wgLang = Language::factory( $code );
 441+ return self::successfulLogin(
 442+ 'loginsuccess',
 443+ $this->mReturnTo,
 444+ $this->mReturnToQuery,
 445+ $this->mLogin->mLoginResult );
 446+ } else {
 447+ # Do a redirect check to ensure that the cookies are
 448+ # being retained by the user's browser.
 449+ return $this->cookieRedirectCheck();
 450+ }
 451+ break;
 452+
 453+ case Login::NO_NAME:
 454+ case Login::ILLEGAL:
 455+ case Login::WRONG_PLUGIN_PASS:
 456+ case Login::WRONG_PASS:
 457+ case Login::EMPTY_PASS:
 458+ case Login::THROTTLED:
 459+ $this->mainLoginForm( wfMsgExt( $this->mLogin->mLoginResult, 'parseinline' ) );
 460+ break;
 461+
 462+ case Login::NOT_EXISTS:
 463+ if( $wgUser->isAllowed( 'createaccount' ) ){
 464+ $this->mainLoginForm( wfMsgExt( 'nosuchuser', 'parseinline', htmlspecialchars( $this->mName ) ) );
 465+ } else {
 466+ $this->mainLoginForm( wfMsgExt( 'nosuchusershort', 'parseinline', htmlspecialchars( $this->mName ) ) );
 467+ }
 468+ break;
 469+
 470+ case Login::RESET_PASS:
 471+ # 'Shell out' to Special:ResetPass to get the user to
 472+ # set a new permanent password from a temporary one.
 473+ $reset = new SpecialResetpass();
 474+ $reset->mHeaderMsg = 'resetpass_announce';
 475+ $reset->mHeaderMsgType = 'success';
 476+ $reset->execute( null );
 477+ break;
 478+
 479+ case Login::CREATE_BLOCKED:
 480+ $this->userBlockedMessage();
 481+ break;
 482+
 483+ case Login::ABORTED:
 484+ $msg = $this->mLogin->mLoginResult ? $this->mLogin->mLoginResult : $this->mLogin->mCreateResult;
 485+ $this->mainLoginForm( wfMsgExt( $msg, 'parseinline' ) );
 486+ break;
 487+
 488+ default:
 489+ throw new MWException( "Unhandled case value: $result" );
 490+ }
 491+ }
 492+
 493+ /**
 494+ * Attempt to send the user a password-reset mail, and display
 495+ * the results (good, bad or ugly).
 496+ */
 497+ protected function showMailPage(){
 498+ global $wgOut;
 499+ $result = $this->mLogin->mailPassword();
 500+
 501+ switch( $result ){
 502+ case Login::READ_ONLY :
 503+ $wgOut->readOnlyPage();
 504+ return;
 505+ case Login::MAIL_PASSCHANGE_FORBIDDEN:
 506+ $this->mainLoginForm( wfMsgExt( 'resetpass_forbidden', 'parseinline' ) );
 507+ return;
 508+ case Login::MAIL_BLOCKED:
 509+ $this->mainLoginForm( wfMsgExt( 'blocked-mailpassword', 'parseinline' ) );
 510+ return;
 511+ case Login::MAIL_PING_THROTTLED:
 512+ $wgOut->rateLimited();
 513+ return;
 514+ case Login::MAIL_PASS_THROTTLED:
 515+ global $wgPasswordReminderResendTime;
 516+ # Round the time in hours to 3 d.p., in case someone
 517+ # is specifying minutes or seconds.
 518+ $this->mainLoginForm( wfMsgExt(
 519+ 'throttled-mailpassword',
 520+ array( 'parsemag' ),
 521+ round( $wgPasswordReminderResendTime, 3 )
 522+ ) );
 523+ return;
 524+ case Login::NO_NAME:
 525+ $this->mainLoginForm( wfMsgExt( 'noname', 'parseinline' ) );
 526+ return;
 527+ case Login::NOT_EXISTS:
 528+ $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $this->mLogin->mUser->getName() ) ) );
 529+ return;
 530+ case Login::MAIL_EMPTY_EMAIL:
 531+ $this->mainLoginForm( wfMsgExt( 'noemail', 'parseinline', $this->mLogin->mUser->getName() ) );
 532+ return;
 533+ case Login::MAIL_BAD_IP:
 534+ $this->mainLoginForm( wfMsgExt( 'badipaddress', 'parseinline' ) );
 535+ return;
 536+ case Login::MAIL_ERROR:
 537+ $this->mainLoginForm( wfMsgExt( 'mailerror', 'parseinline', $this->mLogin->mMailResult->getMessage() ) );
 538+ return;
 539+ case Login::SUCCESS:
 540+ $this->mainLoginForm( wfMsgExt( 'passwordsent', 'parseinline', $this->mLogin->mUser->getName() ), 'success' );
 541+ return;
 542+ }
 543+ }
 544+
 545+ /**
 546+ * Since the UserLoginForm hook was changed to pass a SpecialPage
 547+ * instead of a QuickTemplate derivative, old extensions might
 548+ * easily try calling this method expecing it to exist. Tempting
 549+ * though it is to let them have the fatal error, let's at least
 550+ * fail gracefully...
 551+ * @deprecated
 552+ */
 553+ public function set(){
 554+ wfDeprecated( __METHOD__ );
 555+ }
1064556 }
Index: trunk/phase3/includes/specials/SpecialCreateAccount.php
@@ -0,0 +1,519 @@
 2+<?php
 3+/**
 4+ * Special page for creating/registering new user accounts.
 5+ * @ingroup SpecialPage
 6+ */
 7+class SpecialCreateAccount extends SpecialPage {
 8+
 9+ var $mUsername, $mPassword, $mRetype, $mReturnTo, $mPosted;
 10+ var $mCreateaccountMail, $mRemember, $mEmail, $mDomain, $mLanguage;
 11+ var $mReturnToQuery;
 12+
 13+ protected $mLogin;
 14+
 15+ public $mDomains = array();
 16+
 17+ public $mUseEmail = true; # Can be switched off by AuthPlugins etc
 18+ public $mUseRealname = true;
 19+ public $mUseRemember = true;
 20+
 21+ public $mFormHeader = '';
 22+ public $mFormFields = array(
 23+ 'Name' => array(
 24+ 'type' => 'text',
 25+ 'label-message' => 'yourname',
 26+ 'id' => 'wpName2',
 27+ 'tabindex' => '1',
 28+ 'size' => '20',
 29+ 'required' => '1',
 30+ 'autofocus' => '',
 31+ ),
 32+ 'Password' => array(
 33+ 'type' => 'password',
 34+ 'label-message' => 'yourpassword',
 35+ 'size' => '20',
 36+ 'id' => 'wpPassword2',
 37+ 'required' => '',
 38+ ),
 39+ 'Retype' => array(
 40+ 'type' => 'password',
 41+ 'label-message' => 'yourpasswordagain',
 42+ 'size' => '20',
 43+ 'id' => 'wpRetype',
 44+ 'required' => '',
 45+ ),
 46+ 'Email' => array(
 47+ 'type' => 'email',
 48+ 'label-message' => 'youremail',
 49+ 'size' => '20',
 50+ 'id' => 'wpEmail',
 51+ ),
 52+ 'RealName' => array(
 53+ 'type' => 'text',
 54+ 'label-message' => 'yourrealname',
 55+ 'id' => 'wpRealName',
 56+ 'tabindex' => '1',
 57+ 'size' => '20',
 58+ ),
 59+ 'Remember' => array(
 60+ 'type' => 'check',
 61+ 'label-message' => 'remembermypassword',
 62+ 'id' => 'wpRemember',
 63+ ),
 64+ 'Domain' => array(
 65+ 'type' => 'select',
 66+ 'id' => 'wpDomain',
 67+ 'label-message' => 'yourdomainname',
 68+ 'options' => null,
 69+ 'default' => null,
 70+ ),
 71+ );
 72+
 73+ public function __construct(){
 74+ parent::__construct( 'CreateAccount', 'createaccount' );
 75+ $this->mLogin = new Login();
 76+ $this->mFormFields['RealName']['label-help'] = 'prefs-help-realname';
 77+ }
 78+
 79+ public function execute( $par ){
 80+ global $wgUser, $wgOut;
 81+
 82+ $this->setHeaders();
 83+ $this->loadQuery();
 84+
 85+ # Block signup here if in readonly. Keeps user from
 86+ # going through the process (filling out data, etc)
 87+ # and being informed later.
 88+ if ( wfReadOnly() ) {
 89+ $wgOut->readOnlyPage();
 90+ return;
 91+ }
 92+ # Bail out straightaway on permissions errors
 93+ if ( !$this->userCanExecute( $wgUser ) ) {
 94+ $this->displayRestrictionError();
 95+ return;
 96+ } elseif ( $wgUser->isBlockedFromCreateAccount() ) {
 97+ $this->userBlockedMessage();
 98+ return;
 99+ } elseif ( count( $permErrors = $this->getTitle()->getUserPermissionsErrors( 'createaccount', $wgUser, true ) )>0 ) {
 100+ $wgOut->showPermissionsErrorPage( $permErrors, 'createaccount' );
 101+ return;
 102+ }
 103+
 104+ if( $this->mPosted ) {
 105+ $this->addNewAccount( $this->mCreateaccountMail );
 106+ } else {
 107+ $this->showMainForm('');
 108+ }
 109+ }
 110+
 111+ /**
 112+ * Load the member variables from the request parameters
 113+ */
 114+ protected function loadQuery(){
 115+ global $wgRequest, $wgAuth, $wgHiddenPrefs, $wgEnableEmail, $wgRedirectOnLogin;
 116+ $this->mCreateaccountMail = $wgRequest->getCheck( 'wpCreateaccountMail' )
 117+ && $wgEnableEmail;
 118+
 119+ $this->mUsername = $wgRequest->getText( 'wpName' );
 120+ $this->mPassword = $wgRequest->getText( 'wpPassword' );
 121+ $this->mRetype = $wgRequest->getText( 'wpRetype' );
 122+ $this->mDomain = $wgRequest->getText( 'wpDomain' );
 123+ $this->mReturnTo = $wgRequest->getVal( 'returnto' );
 124+ $this->mReturnToQuery = $wgRequest->getVal( 'returntoquery' );
 125+ $this->mPosted = $wgRequest->wasPosted();
 126+ $this->mCreateaccountMail = $wgRequest->getCheck( 'wpCreateaccountMail' )
 127+ && $wgEnableEmail;
 128+ $this->mRemember = $wgRequest->getCheck( 'wpRemember' );
 129+ $this->mLanguage = $wgRequest->getText( 'uselang' );
 130+
 131+ if ( $wgRedirectOnLogin ) {
 132+ $this->mReturnTo = $wgRedirectOnLogin;
 133+ $this->mReturnToQuery = '';
 134+ }
 135+
 136+ if( $wgEnableEmail ) {
 137+ $this->mEmail = $wgRequest->getText( 'wpEmail' );
 138+ } else {
 139+ $this->mEmail = '';
 140+ }
 141+ if( !in_array( 'realname', $wgHiddenPrefs ) ) {
 142+ $this->mRealName = $wgRequest->getText( 'wpRealName' );
 143+ } else {
 144+ $this->mRealName = '';
 145+ }
 146+
 147+ if( !$wgAuth->validDomain( $this->mDomain ) ) {
 148+ $this->mDomain = 'invaliddomain';
 149+ }
 150+ $wgAuth->setDomain( $this->mDomain );
 151+
 152+ # When switching accounts, it sucks to get automatically logged out
 153+ $returnToTitle = Title::newFromText( $this->mReturnTo );
 154+ if( is_object( $returnToTitle ) && $returnToTitle->isSpecial( 'Userlogout' ) ) {
 155+ $this->mReturnTo = '';
 156+ $this->mReturnToQuery = '';
 157+ }
 158+ }
 159+
 160+ /**
 161+ * Create a new user account from the provided data
 162+ */
 163+ protected function addNewAccount( $byEmail=false ) {
 164+ global $wgUser, $wgEmailAuthentication;
 165+
 166+ # Do a quick check that the user actually managed to type
 167+ # the password in the same both times
 168+ if ( 0 != strcmp( $this->mPassword, $this->mRetype ) ) {
 169+ return $this->showMainForm( wfMsgExt( 'badretype', 'parseinline' ) );
 170+ }
 171+
 172+ # Create the account and abort if there's a problem doing so
 173+ $status = $this->mLogin->attemptCreation( $byEmail );
 174+ switch( $status ){
 175+ case Login::SUCCESS:
 176+ case Login::MAIL_ERROR:
 177+ break;
 178+
 179+ case Login::CREATE_BADDOMAIN:
 180+ case Login::CREATE_EXISTS:
 181+ case Login::NO_NAME:
 182+ case Login::CREATE_NEEDEMAIL:
 183+ case Login::CREATE_BADEMAIL:
 184+ case Login::CREATE_BADNAME:
 185+ case Login::WRONG_PLUGIN_PASS:
 186+ case Login::ABORTED:
 187+ return $this->showMainForm( wfMsgExt( $this->mLogin->mCreateResult, 'parseinline' ) );
 188+
 189+ case Login::CREATE_SORBS:
 190+ return $this->showMainForm( wfMsgExt( 'sorbs_create_account_reason', 'parseinline' ) . ' (' . wfGetIP() . ')' );
 191+
 192+ case Login::CREATE_BLOCKED:
 193+ return $this->userBlockedMessage();
 194+
 195+ case Login::CREATE_BADPASS:
 196+ global $wgMinimalPasswordLength;
 197+ return $this->showMainForm( wfMsgExt( $this->mLogin->mCreateResult, array( 'parsemag' ), $wgMinimalPasswordLength ) );
 198+
 199+ case Login::THROTTLED:
 200+ global $wgAccountCreationThrottle;
 201+ return $this->showMainForm( wfMsgExt( 'acct_creation_throttle_hit', array( 'parseinline' ), $wgAccountCreationThrottle ) );
 202+
 203+ default:
 204+ throw new MWException( "Unhandled status code $status in " . __METHOD__ );
 205+ }
 206+
 207+ # If we showed up language selection links, and one was in use, be
 208+ # smart (and sensible) and save that language as the user's preference
 209+ global $wgLoginLanguageSelector;
 210+ if( $wgLoginLanguageSelector && $this->mLanguage )
 211+ $this->mLogin->mUser->setOption( 'language', $this->mLanguage );
 212+ $this->mLogin->mUser->saveSettings();
 213+
 214+ if( $byEmail ) {
 215+ if( $result == Login::MAIL_ERROR ){
 216+ # FIXME: we are totally screwed if we end up here...
 217+ $this->showMainForm( wfMsgExt( 'mailerror', 'parseinline', $this->mLogin->mMailResult->getMessage() ) );
 218+ } else {
 219+ $wgOut->setPageTitle( wfMsg( 'accmailtitle' ) );
 220+ $wgOut->addWikiMsg( 'accmailtext', $this->mLogin->mUser->getName(), $this->mLogin->mUser->getEmail() );
 221+ $wgOut->returnToMain( false );
 222+ }
 223+
 224+ } else {
 225+
 226+ # There might be a message stored from the confirmation mail
 227+ # send, which we can display.
 228+ if( $wgEmailAuthentication && $this->mLogin->mMailResult ) {
 229+ global $wgOut;
 230+ if( WikiError::isError( $this->mLogin->mMailResult ) ) {
 231+ $wgOut->addWikiMsg( 'confirmemail_sendfailed', $this->mLogin->mMailResult->getMessage() );
 232+ } else {
 233+ $wgOut->addWikiMsg( 'confirmemail_oncreate' );
 234+ }
 235+ }
 236+
 237+ # If not logged in, assume the new account as the current
 238+ # one and set session cookies then show a "welcome" message
 239+ # or a "need cookies" message as needed
 240+ if( $wgUser->isAnon() ) {
 241+ $wgUser = $this->mLogin->mUser;
 242+ $wgUser->setCookies();
 243+ if( $this->hasSessionCookie() ) {
 244+ return $this->successfulCreation();
 245+ } else {
 246+ return $this->cookieRedirectCheck();
 247+ }
 248+ } else {
 249+ # Show confirmation that the account was created
 250+ global $wgOut;
 251+ $self = SpecialPage::getTitleFor( 'Userlogin' );
 252+ $wgOut->setPageTitle( wfMsgHtml( 'accountcreated' ) );
 253+ $wgOut->addHTML( wfMsgWikiHtml( 'accountcreatedtext', $this->mLogin->mUser->getName() ) );
 254+ $wgOut->returnToMain( false, $self );
 255+ return true;
 256+ }
 257+ }
 258+ }
 259+
 260+ /**
 261+ * Run any hooks registered for logins, then
 262+ * display a message welcoming the user.
 263+ */
 264+ protected function successfulCreation(){
 265+ global $wgUser, $wgOut;
 266+
 267+ # Run any hooks; display injected HTML
 268+ $injected_html = '';
 269+ wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
 270+
 271+ SpecialUserLogin::displaySuccessfulLogin(
 272+ 'welcomecreation',
 273+ $injected_html,
 274+ $this->mReturnTo,
 275+ $this->mReturnToQuery );
 276+ }
 277+
 278+ /**
 279+ * Display a message indicating that account creation from their IP has
 280+ * been blocked by a (range)block with 'block account creation' enabled.
 281+ * It's likely that this feature will be used for blocking large numbers
 282+ * of innocent people, e.g. range blocks on schools. Don't blame it on
 283+ * the user. There's a small chance that it really is the user's fault,
 284+ * i.e. the username is blocked and they haven't bothered to log out
 285+ * before trying to create an account to evade it, but we'll leave that
 286+ * to their guilty conscience to figure out...
 287+ */
 288+ protected function userBlockedMessage() {
 289+ global $wgOut, $wgUser;
 290+
 291+ $wgOut->setPageTitle( wfMsg( 'cantcreateaccounttitle' ) );
 292+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
 293+ $wgOut->setArticleRelated( false );
 294+
 295+ $ip = wfGetIP();
 296+ $blocker = User::whoIs( $wgUser->mBlock->mBy );
 297+ $block_reason = $wgUser->mBlock->mReason;
 298+
 299+ if ( strval( $block_reason ) === '' ) {
 300+ $block_reason = wfMsgExt( 'blockednoreason', 'parseinline' );
 301+ }
 302+ $wgOut->addWikiMsg( 'cantcreateaccount-text', $ip, $block_reason, $blocker );
 303+ $wgOut->returnToMain( false );
 304+ }
 305+
 306+ /**
 307+ * Show the main input form, with an appropriate error message
 308+ * from a previous iteration, if necessary
 309+ * @param $msg String HTML of message received previously
 310+ * @param $msgtype String type of message, usually 'error'
 311+ */
 312+ protected function showMainForm( $msg, $msgtype = 'error' ) {
 313+ global $wgUser, $wgOut, $wgHiddenPrefs, $wgEnableEmail;
 314+ global $wgCookiePrefix, $wgLoginLanguageSelector;
 315+ global $wgAuth, $wgEmailConfirmToEdit, $wgCookieExpiration;
 316+
 317+ # Parse the error message if we got one
 318+ if( $msg ){
 319+ if( $msgtype == 'error' ){
 320+ $msg = wfMsgExt( 'loginerror', 'parseinline' ) . ' ' . $msg;
 321+ }
 322+ $msg = Html::rawElement(
 323+ 'div',
 324+ array( 'class' => $msgtype . 'box' ),
 325+ $msg
 326+ );
 327+ } else {
 328+ $msg = '';
 329+ }
 330+
 331+ # Make sure the returnTo strings don't get lost if the
 332+ # user changes language, etc
 333+ $linkq = array();
 334+ if ( !empty( $this->mReturnTo ) ) {
 335+ $linkq['returnto'] = wfUrlencode( $this->mReturnTo );
 336+ if ( !empty( $this->mReturnToQuery ) )
 337+ $linkq['returntoquery'] = wfUrlencode( $this->mReturnToQuery );
 338+ }
 339+
 340+ # Pass any language selection on to the mode switch link
 341+ if( $wgLoginLanguageSelector && $this->mLanguage )
 342+ $linkq['uselang'] = $this->mLanguage;
 343+
 344+ $skin = $wgUser->getSkin();
 345+ $link = $skin->link(
 346+ SpecialPage::getTitleFor( 'Userlogin' ),
 347+ wfMsgHtml( 'gotaccountlink' ),
 348+ array(),
 349+ $linkq );
 350+ $link = $wgUser->isLoggedIn()
 351+ ? ''
 352+ : wfMsgWikiHtml( 'gotaccount', $link );
 353+
 354+ # Prepare language selection links as needed
 355+ $langSelector = $wgLoginLanguageSelector
 356+ ? Html::rawElement(
 357+ 'div',
 358+ array( 'id' => 'languagelinks' ),
 359+ SpecialUserLogin::makeLanguageSelector( $this->getTitle(), $this->mReturnTo ) )
 360+ : '';
 361+
 362+ # Add a 'send password by email' button if available
 363+ $buttons = '';
 364+ if( $wgEnableEmail && $wgUser->isLoggedIn() ){
 365+ $buttons = Html::element(
 366+ 'input',
 367+ array(
 368+ 'type' => 'submit',
 369+ 'name' => 'wpCreateaccountMail',
 370+ 'value' => wfMsg( 'createaccountmail' ),
 371+ 'id' => 'wpCreateaccountMail',
 372+ )
 373+ );
 374+ }
 375+
 376+ # Give authentication and captcha plugins a chance to
 377+ # modify the form, by hook or by using $wgAuth
 378+ $wgAuth->modifyUITemplate( $this, 'new' );
 379+ wfRunHooks( 'UserCreateForm', array( &$this ) );
 380+
 381+ # The most likely use of the hook is to enable domains;
 382+ # check that now, and add fields if necessary
 383+ if( $this->mDomains ){
 384+ $this->mFormFields['Domain']['options'] = $this->mDomains;
 385+ $this->mFormFields['Domain']['default'] = $this->mDomain;
 386+ } else {
 387+ unset( $this->mFormFields['Domain'] );
 388+ }
 389+
 390+ # Or to switch email on or off
 391+ if( !$wgEnableEmail || !$this->mUseEmail ){
 392+ unset( $this->mFormFields['Email'] );
 393+ } else {
 394+ if( $wgEmailConfirmToEdit ){
 395+ $this->mFormFields['Email']['label-help'] = 'prefs-help-email-required';
 396+ $this->mFormFields['Email']['required'] = '';
 397+ } else {
 398+ $this->mFormFields['Email']['label-help'] = 'prefs-help-email';
 399+ }
 400+ }
 401+
 402+ # Or to play with realname
 403+ if( in_array( 'realname', $wgHiddenPrefs ) || !$this->mUseRealname ){
 404+ unset( $this->mFormFields['Realname'] );
 405+ }
 406+
 407+ # Or to tweak the 'remember my password' checkbox
 408+ if( !($wgCookieExpiration > 0) || !$this->mUseRemember ){
 409+ # Remove it altogether
 410+ unset( $this->mFormFields['Remember'] );
 411+ } elseif( $wgUser->getOption( 'rememberpassword' ) || $this->mRemember ){
 412+ # Or check it by default
 413+ # FIXME: this doesn't always work?
 414+ $this->mFormFields['Remember']['checked'] = '1';
 415+ }
 416+
 417+ $form = new HTMLForm( $this->mFormFields, '' );
 418+ $form->setTitle( $this->getTitle() );
 419+ $form->setSubmitText( wfMsg( 'createaccount' ) );
 420+ $form->setSubmitId( 'wpCreateaccount' );
 421+ $form->suppressReset();
 422+ $form->loadData();
 423+
 424+ $formContents = ''
 425+ . Html::rawElement( 'p', array( 'id' => 'userloginlink' ),
 426+ $link )
 427+ . $this->mFormHeader
 428+ . $langSelector
 429+ . $form->getBody()
 430+ . $form->getButtons()
 431+ . $buttons
 432+ . Xml::hidden( 'returnto', $this->mReturnTo )
 433+ . Xml::hidden( 'returntoquery', $this->mReturnToQuery )
 434+ ;
 435+
 436+ $wgOut->setPageTitle( wfMsg( 'createaccount' ) );
 437+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
 438+ $wgOut->setArticleRelated( false );
 439+ $wgOut->disallowUserJs(); # Stop malicious userscripts sniffing passwords
 440+
 441+ $wgOut->addHTML(
 442+ Html::rawElement(
 443+ 'div',
 444+ array( 'id' => 'loginstart' ),
 445+ wfMsgExt( 'loginstart', array( 'parseinline' ) )
 446+ ) .
 447+ $msg .
 448+ Html::rawElement(
 449+ 'div',
 450+ array( 'id' => 'userloginForm' ),
 451+ $form->wrapForm( $formContents )
 452+ ) .
 453+ Html::rawElement(
 454+ 'div',
 455+ array( 'id' => 'loginend' ),
 456+ wfMsgExt( 'loginend', array( 'parseinline' ) )
 457+ )
 458+ );
 459+
 460+ }
 461+
 462+ /**
 463+ * Check if a session cookie is present.
 464+ *
 465+ * This will not pick up a cookie set during _this_ request, but is meant
 466+ * to ensure that the client is returning the cookie which was set on a
 467+ * previous pass through the system.
 468+ *
 469+ * @private
 470+ */
 471+ protected function hasSessionCookie() {
 472+ global $wgDisableCookieCheck, $wgRequest;
 473+ return $wgDisableCookieCheck ? true : $wgRequest->checkSessionCookie();
 474+ }
 475+
 476+ /**
 477+ * Do a redirect back to the same page, so we can check any
 478+ * new session cookies.
 479+ */
 480+ protected function cookieRedirectCheck() {
 481+ global $wgOut;
 482+
 483+ $query = array( 'wpCookieCheck' => '1' );
 484+ if ( $this->mReturnTo ) $query['returnto'] = $this->mReturnTo;
 485+ $check = $this->getTitle()->getFullURL( $query );
 486+
 487+ return $wgOut->redirect( $check );
 488+ }
 489+
 490+ /**
 491+ * Check the cookies and show errors if they're not enabled.
 492+ * @param $type String action being performed
 493+ */
 494+ protected function onCookieRedirectCheck() {
 495+ if ( !$this->hasSessionCookie() ) {
 496+ return $this->mainLoginForm( wfMsgExt( 'nocookiesnew', array( 'parseinline' ) ) );
 497+ } else {
 498+ return SpecialUserlogin::successfulLogin(
 499+ array( 'welcomecreate' ),
 500+ $this->mReturnTo,
 501+ $this->mReturnToQuery
 502+ );
 503+ }
 504+ }
 505+
 506+ /**
 507+ * Since the UserCreateForm hook was changed to pass a SpecialPage
 508+ * instead of a QuickTemplate derivative, old extensions might
 509+ * easily try calling these methods expecing them to exist. Tempting
 510+ * though it is to let them have the fatal error, let's at least
 511+ * fail gracefully...
 512+ * @deprecated
 513+ */
 514+ public function set(){
 515+ wfDeprecated( __METHOD__ );
 516+ }
 517+ public function addInputItem(){
 518+ wfDeprecated( __METHOD__ );
 519+ }
 520+}
Property changes on: trunk/phase3/includes/specials/SpecialCreateAccount.php
___________________________________________________________________
Added: svn:eol-style
1521 + native
Index: trunk/phase3/includes/specials/SpecialResetpass.php
@@ -12,6 +12,48 @@
1313 public function __construct() {
1414 parent::__construct( 'Resetpass' );
1515 }
 16+
 17+ public $mFormFields = array(
 18+ 'Name' => array(
 19+ 'type' => 'info',
 20+ 'label-message' => 'yourname',
 21+ 'default' => '',
 22+ ),
 23+ 'Password' => array(
 24+ 'type' => 'password',
 25+ 'label-message' => 'oldpassword',
 26+ 'size' => '20',
 27+ 'id' => 'wpPassword',
 28+ 'required' => '',
 29+ ),
 30+ 'NewPassword' => array(
 31+ 'type' => 'password',
 32+ 'label-message' => 'newpassword',
 33+ 'size' => '20',
 34+ 'id' => 'wpNewPassword',
 35+ 'required' => '',
 36+ ),
 37+ 'Retype' => array(
 38+ 'type' => 'password',
 39+ 'label-message' => 'retypenew',
 40+ 'size' => '20',
 41+ 'id' => 'wpRetype',
 42+ 'required' => '',
 43+ ),
 44+ 'Remember' => array(
 45+ 'type' => 'check',
 46+ 'label-message' => 'remembermypassword',
 47+ 'id' => 'wpRemember',
 48+ ),
 49+ );
 50+ public $mSubmitMsg = 'resetpass-submit-loggedin';
 51+ public $mHeaderMsg = '';
 52+ public $mHeaderMsgType = 'error';
 53+
 54+ protected $mUsername;
 55+ protected $mOldpass;
 56+ protected $mNewpass;
 57+ protected $mRetype;
1658
1759 /**
1860 * Main execution point
@@ -19,176 +61,142 @@
2062 function execute( $par ) {
2163 global $wgUser, $wgAuth, $wgOut, $wgRequest;
2264
23 - $this->mUserName = $wgRequest->getVal( 'wpName' );
 65+ $this->mUsername = $wgRequest->getVal( 'wpName', $wgUser->getName() );
2466 $this->mOldpass = $wgRequest->getVal( 'wpPassword' );
2567 $this->mNewpass = $wgRequest->getVal( 'wpNewPassword' );
2668 $this->mRetype = $wgRequest->getVal( 'wpRetype' );
 69+ $this->mRemember = $wgRequest->getVal( 'wpRemember' );
 70+ $this->mReturnTo = $wgRequest->getVal( 'returnto' );
 71+ $this->mReturnToQuery = $wgRequest->getVal( 'returntoquery' );
2772
2873 $this->setHeaders();
2974 $this->outputHeader();
3075
3176 if( !$wgAuth->allowPasswordChange() ) {
32 - $this->error( wfMsg( 'resetpass_forbidden' ) );
33 - return;
 77+ $wgOut->showErrorPage( 'errorpagetitle', 'resetpass_forbidden' );
 78+ return false;
3479 }
3580
3681 if( !$wgRequest->wasPosted() && !$wgUser->isLoggedIn() ) {
37 - $this->error( wfMsg( 'resetpass-no-info' ) );
38 - return;
 82+ $wgOut->showErrorPage( 'errorpagetitle', 'resetpass-no-info' );
 83+ return false;
3984 }
4085
41 - if( $wgRequest->wasPosted() && $wgUser->matchEditToken( $wgRequest->getVal('token') ) ) {
42 - try {
43 - $this->attemptReset( $this->mNewpass, $this->mRetype );
44 - $wgOut->addWikiMsg( 'resetpass_success' );
45 - if( !$wgUser->isLoggedIn() ) {
46 - $data = array(
47 - 'action' => 'submitlogin',
48 - 'wpName' => $this->mUserName,
49 - 'wpPassword' => $this->mNewpass,
50 - 'returnto' => $wgRequest->getVal( 'returnto' ),
51 - );
52 - if( $wgRequest->getCheck( 'wpRemember' ) ) {
53 - $data['wpRemember'] = 1;
54 - }
55 - $login = new LoginForm( new FauxRequest( $data, true ) );
56 - $login->execute();
 86+ if( $wgRequest->wasPosted()
 87+ && $wgUser->matchEditToken( $wgRequest->getVal('wpEditToken') )
 88+ && $this->attemptReset() )
 89+ {
 90+ # Log the user in if they're not already (ie we're
 91+ # coming from the e-mail-password-reset route
 92+ if( !$wgUser->isLoggedIn() ) {
 93+ $data = array(
 94+ 'wpName' => $this->mUsername,
 95+ 'wpPassword' => $this->mNewpass,
 96+ 'returnto' => $this->mReturnTo,
 97+ );
 98+ if( $this->mRemember ) {
 99+ $data['wpRemember'] = 1;
57100 }
58 - $titleObj = Title::newFromText( $wgRequest->getVal( 'returnto' ) );
59 - if ( !$titleObj instanceof Title ) {
60 - $titleObj = Title::newMainPage();
61 - }
62 - $wgOut->redirect( $titleObj->getFullURL() );
63 - } catch( PasswordError $e ) {
64 - $this->error( $e->getMessage() );
 101+ $login = new Login( new FauxRequest( $data, true ) );
 102+ $login->attemptLogin();
 103+
 104+ # Redirect out to the appropriate target.
 105+ SpecialUserlogin::successfulLogin(
 106+ 'resetpass_success',
 107+ $this->mReturnTo,
 108+ $this->mReturnToQuery,
 109+ $login->mLoginResult
 110+ );
 111+ } else {
 112+ # Redirect out to the appropriate target.
 113+ SpecialUserlogin::successfulLogin(
 114+ 'resetpass_success',
 115+ $this->mReturnTo,
 116+ $this->mReturnToQuery
 117+ );
65118 }
 119+ } else {
 120+ $this->showForm();
66121 }
67 - $this->showForm();
68122 }
69123
70 - function error( $msg ) {
71 - global $wgOut;
72 - $wgOut->addHTML( Xml::element('p', array( 'class' => 'error' ), $msg ) );
73 - }
74 -
75124 function showForm() {
76 - global $wgOut, $wgUser, $wgRequest;
 125+ global $wgOut, $wgUser;
77126
78127 $wgOut->disallowUserJs();
79 -
80 - $self = SpecialPage::getTitleFor( 'Resetpass' );
81 - if ( !$this->mUserName ) {
82 - $this->mUserName = $wgUser->getName();
83 - }
84 - $rememberMe = '';
85 - if ( !$wgUser->isLoggedIn() ) {
86 - $rememberMe = '<tr>' .
87 - '<td></td>' .
88 - '<td class="mw-input">' .
89 - Xml::checkLabel( wfMsg( 'remembermypassword' ),
90 - 'wpRemember', 'wpRemember',
91 - $wgRequest->getCheck( 'wpRemember' ) ) .
92 - '</td>' .
93 - '</tr>';
94 - $submitMsg = 'resetpass_submit';
95 - $oldpassMsg = 'resetpass-temp-password';
 128+
 129+ if( $wgUser->isLoggedIn() ){
 130+ unset( $this->mFormFields['Remember'] );
96131 } else {
97 - $oldpassMsg = 'oldpassword';
98 - $submitMsg = 'resetpass-submit-loggedin';
 132+ # Request is coming from Special:UserLogin after it
 133+ # authenticated someone with a temporary password.
 134+ $this->mFormFields['Password']['label-message'] = 'resetpass-temp-password';
 135+ $this->mSubmitMsg = 'resetpass_submit';
99136 }
 137+ $this->mFormFields['Name']['default'] = $this->mUsername;
 138+
 139+ $header = $this->mHeaderMsg
 140+ ? Xml::element( 'div', array( 'class' => "{$this->mHeaderMsgType}box" ), wfMsg( $this->mHeaderMsg ) )
 141+ : '';
 142+
 143+ $form = new HTMLForm( $this->mFormFields, '' );
 144+ $form->suppressReset();
 145+ $form->setSubmitText( wfMsg( $this->mSubmitMsg ) );
 146+ $form->setTitle( $this->getTitle() );
 147+ $form->loadData();
 148+
 149+ $formContents = ''
 150+ . $form->getBody()
 151+ . $form->getButtons()
 152+ . $form->getHiddenFields()
 153+ . Html::hidden( 'wpName', $this->mUsername )
 154+ . Html::hidden( 'returnto', $this->mReturnTo )
 155+ ;
 156+ $formOutput = $form->wrapForm( $formContents );
 157+
100158 $wgOut->addHTML(
101 - Xml::fieldset( wfMsg( 'resetpass_header' ) ) .
102 - Xml::openElement( 'form',
103 - array(
104 - 'method' => 'post',
105 - 'action' => $self->getLocalUrl(),
106 - 'id' => 'mw-resetpass-form' ) ) . "\n" .
107 - Xml::hidden( 'token', $wgUser->editToken() ) . "\n" .
108 - Xml::hidden( 'wpName', $this->mUserName ) . "\n" .
109 - Xml::hidden( 'returnto', $wgRequest->getVal( 'returnto' ) ) . "\n" .
110 - wfMsgExt( 'resetpass_text', array( 'parse' ) ) . "\n" .
111 - Xml::openElement( 'table', array( 'id' => 'mw-resetpass-table' ) ) . "\n" .
112 - $this->pretty( array(
113 - array( 'wpName', 'username', 'text', $this->mUserName ),
114 - array( 'wpPassword', $oldpassMsg, 'password', $this->mOldpass ),
115 - array( 'wpNewPassword', 'newpassword', 'password', null ),
116 - array( 'wpRetype', 'retypenew', 'password', null ),
117 - ) ) . "\n" .
118 - $rememberMe .
119 - "<tr>\n" .
120 - "<td></td>\n" .
121 - '<td class="mw-input">' .
122 - Xml::submitButton( wfMsg( $submitMsg ) ) .
123 - "</td>\n" .
124 - "</tr>\n" .
125 - Xml::closeElement( 'table' ) .
126 - Xml::closeElement( 'form' ) .
127 - Xml::closeElement( 'fieldset' ) . "\n"
 159+ $header
 160+ . Html::rawElement( 'fieldset', array( 'class' => 'visualClear' ), ''
 161+ . Html::element( 'legend', array(), wfMsg( 'resetpass_header' ) )
 162+ . $formOutput
 163+ )
128164 );
129165 }
130166
131 - function pretty( $fields ) {
132 - $out = '';
133 - foreach ( $fields as $list ) {
134 - list( $name, $label, $type, $value ) = $list;
135 - if( $type == 'text' ) {
136 - $field = htmlspecialchars( $value );
137 - } else {
138 - $attribs = array( 'id' => $name );
139 - if ( $name == 'wpNewPassword' || $name == 'wpRetype' ) {
140 - $attribs = array_merge( $attribs,
141 - User::passwordChangeInputAttribs() );
142 - }
143 - if ( $name == 'wpPassword' ) {
144 - $attribs[] = 'autofocus';
145 - }
146 - $field = Html::input( $name, $value, $type, $attribs );
147 - }
148 - $out .= "<tr>\n";
149 - $out .= "\t<td class='mw-label'>";
150 - if ( $type != 'text' )
151 - $out .= Xml::label( wfMsg( $label ), $name );
152 - else
153 - $out .= wfMsgHtml( $label );
154 - $out .= "</td>\n";
155 - $out .= "\t<td class='mw-input'>";
156 - $out .= $field;
157 - $out .= "</td>\n";
158 - $out .= "</tr>";
159 - }
160 - return $out;
161 - }
162 -
163167 /**
164 - * @throws PasswordError when cannot set the new password because requirements not met.
 168+ * Try to reset the user's password
165169 */
166 - protected function attemptReset( $newpass, $retype ) {
167 - $user = User::newFromName( $this->mUserName );
 170+ protected function attemptReset() {
 171+ $user = User::newFromName( $this->mUsername );
168172 if( !$user || $user->isAnon() ) {
169 - throw new PasswordError( 'no such user' );
 173+ $this->mHeaderMsg = 'no such user';
 174+ return false;
170175 }
171176
172 - if( $newpass !== $retype ) {
173 - wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'badretype' ) );
174 - throw new PasswordError( wfMsg( 'badretype' ) );
 177+ if( $this->mNewpass !== $this->mRetype ) {
 178+ wfRunHooks( 'PrefsPasswordAudit', array( $user, $this->mNewpass, 'badretype' ) );
 179+ $this->mHeaderMsg = 'badretype';
 180+ return false;
175181 }
176182
177183 if( !$user->checkTemporaryPassword($this->mOldpass) && !$user->checkPassword($this->mOldpass) ) {
178 - wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'wrongpassword' ) );
179 - throw new PasswordError( wfMsg( 'resetpass-wrong-oldpass' ) );
 184+ wfRunHooks( 'PrefsPasswordAudit', array( $user, $this->mNewpass, 'wrongpassword' ) );
 185+ $this->mHeaderMsg = 'resetpass-wrong-oldpass';
 186+ return false;
180187 }
181188
182189 try {
183190 $user->setPassword( $this->mNewpass );
184 - wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'success' ) );
 191+ wfRunHooks( 'PrefsPasswordAudit', array( $user, $this->mNewpass, 'success' ) );
185192 $this->mNewpass = $this->mOldpass = $this->mRetypePass = '';
186193 } catch( PasswordError $e ) {
187 - wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'error' ) );
188 - throw new PasswordError( $e->getMessage() );
189 - return;
 194+ wfRunHooks( 'PrefsPasswordAudit', array( $user, $this->mNewpass, 'error' ) );
 195+ $this->mHeaderMsg = $e->getMessage();
 196+ return false;
190197 }
191198
192199 $user->setCookies();
193200 $user->saveSettings();
 201+ return true;
194202 }
195203 }
Index: trunk/phase3/includes/SpecialPage.php
@@ -112,8 +112,8 @@
113113 'Listredirects' => array( 'SpecialPage', 'Listredirects' ),
114114
115115 # Login/create account
116 - 'Userlogin' => array( 'SpecialPage', 'Userlogin' ),
117 - 'CreateAccount' => array( 'SpecialRedirectToSpecial', 'CreateAccount', 'Userlogin', 'signup', array( 'uselang' ) ),
 116+ 'Userlogin' => 'SpecialUserLogin',
 117+ 'CreateAccount' => 'SpecialCreateAccount',
118118
119119 # Users and rights
120120 'Blockip' => array( 'SpecialPage', 'Blockip', 'block' ),
Index: trunk/phase3/includes/templates/Userlogin.php
@@ -1,323 +0,0 @@
2 -<?php
3 -/**
4 - * @defgroup Templates Templates
5 - * @file
6 - * @ingroup Templates
7 - */
8 -if( !defined( 'MEDIAWIKI' ) ) die( -1 );
9 -
10 -/**
11 - * HTML template for Special:Userlogin form
12 - * @ingroup Templates
13 - */
14 -class UserloginTemplate extends QuickTemplate {
15 - function execute() {
16 - if( $this->data['message'] ) {
17 -?>
18 - <div class="<?php $this->text('messagetype') ?>box">
19 - <?php if ( $this->data['messagetype'] == 'error' ) { ?>
20 - <h2><?php $this->msg('loginerror') ?></h2>
21 - <?php } ?>
22 - <?php $this->html('message') ?>
23 - </div>
24 - <div class="visualClear"></div>
25 -<?php } ?>
26 -
27 -<div id="loginstart"><?php $this->msgWiki( 'loginstart' ); ?></div>
28 -<div id="userloginForm">
29 -<form name="userlogin" method="post" action="<?php $this->text('action') ?>">
30 - <h2><?php $this->msg('login') ?></h2>
31 - <p id="userloginlink"><?php $this->html('link') ?></p>
32 - <?php $this->html('header'); /* pre-table point for form plugins... */ ?>
33 - <div id="userloginprompt"><?php $this->msgWiki('loginprompt') ?></div>
34 - <?php if( @$this->haveData( 'languages' ) ) { ?><div id="languagelinks"><p><?php $this->html( 'languages' ); ?></p></div><?php } ?>
35 - <table>
36 - <tr>
37 - <td class="mw-label"><label for='wpName1'><?php $this->msg('yourname') ?></label></td>
38 - <td class="mw-input">
39 - <?php
40 - echo Html::input( 'wpName', $this->data['name'], 'text', array(
41 - 'class' => 'loginText',
42 - 'id' => 'wpName1',
43 - 'tabindex' => '1',
44 - 'size' => '20',
45 - 'required'
46 - # Can't do + array( 'autofocus' ) because + for arrays in PHP
47 - # only works right for associative arrays! Thanks, PHP.
48 - ) + ( $this->data['name'] ? array() : array( 'autofocus' => '' ) ) ); ?>
49 -
50 - </td>
51 - </tr>
52 - <tr>
53 - <td class="mw-label"><label for='wpPassword1'><?php $this->msg('yourpassword') ?></label></td>
54 - <td class="mw-input">
55 - <?php
56 - echo Html::input( 'wpPassword', null, 'password', array(
57 - 'class' => 'loginPassword',
58 - 'id' => 'wpPassword1',
59 - 'tabindex' => '2',
60 - 'size' => '20'
61 - ) + ( $this->data['name'] ? array( 'autofocus' ) : array() ) ); ?>
62 -
63 - </td>
64 - </tr>
65 - <?php if( $this->data['usedomain'] ) {
66 - $doms = "";
67 - foreach( $this->data['domainnames'] as $dom ) {
68 - $doms .= "<option>" . htmlspecialchars( $dom ) . "</option>";
69 - }
70 - ?>
71 - <tr id="mw-user-domain-section">
72 - <td class="mw-label"><?php $this->msg( 'yourdomainname' ) ?></td>
73 - <td class="mw-input">
74 - <select name="wpDomain" value="<?php $this->text( 'domain' ) ?>"
75 - tabindex="3">
76 - <?php echo $doms ?>
77 - </select>
78 - </td>
79 - </tr>
80 - <?php }
81 - if( $this->data['canremember'] ) { ?>
82 - <tr>
83 - <td></td>
84 - <td class="mw-input">
85 - <?php
86 - echo Html::input( 'wpRemember', '1', 'checkbox', array(
87 - 'tabindex' => '4',
88 - 'id' => 'wpRemember'
89 - ) + ( $this->data['remember'] ? array( 'checked' ) : array() ) ); ?>
90 -
91 - <label for="wpRemember"><?php $this->msg('remembermypassword') ?></label>
92 - </td>
93 - </tr>
94 -<?php } ?>
95 - <tr>
96 - <td></td>
97 - <td class="mw-submit">
98 - <?php
99 - echo Html::input( 'wpLoginAttempt', wfMsg( 'login' ), 'submit', array(
100 - 'id' => 'wpLoginAttempt',
101 - 'tabindex' => '5'
102 - ) );
103 - if ( $this->data['useemail'] && $this->data['canreset'] ) {
104 - echo '&nbsp;';
105 - echo Html::input( 'wpMailmypassword', wfMsg( 'mailmypassword' ), 'submit', array(
106 - 'id' => 'wpMailmypassword',
107 - 'tabindex' => '6'
108 - ) );
109 - } ?>
110 -
111 - </td>
112 - </tr>
113 - </table>
114 -<?php if( @$this->haveData( 'uselang' ) ) { ?><input type="hidden" name="uselang" value="<?php $this->text( 'uselang' ); ?>" /><?php } ?>
115 -</form>
116 -</div>
117 -<div id="loginend"><?php $this->msgWiki( 'loginend' ); ?></div>
118 -<?php
119 -
120 - }
121 -}
122 -
123 -/**
124 - * @ingroup Templates
125 - */
126 -class UsercreateTemplate extends QuickTemplate {
127 - function addInputItem( $name, $value, $type, $msg, $helptext = false ) {
128 - $this->data['extraInput'][] = array(
129 - 'name' => $name,
130 - 'value' => $value,
131 - 'type' => $type,
132 - 'msg' => $msg,
133 - 'helptext' => $helptext,
134 - );
135 - }
136 -
137 - function execute() {
138 - if( $this->data['message'] ) {
139 -?>
140 - <div class="<?php $this->text('messagetype') ?>box">
141 - <?php if ( $this->data['messagetype'] == 'error' ) { ?>
142 - <h2><?php $this->msg('loginerror') ?></h2>
143 - <?php } ?>
144 - <?php $this->html('message') ?>
145 - </div>
146 - <div class="visualClear"></div>
147 -<?php } ?>
148 -<div id="userlogin">
149 -
150 -<form name="userlogin2" id="userlogin2" method="post" action="<?php $this->text('action') ?>">
151 - <h2><?php $this->msg('createaccount') ?></h2>
152 - <p id="userloginlink"><?php $this->html('link') ?></p>
153 - <?php $this->html('header'); /* pre-table point for form plugins... */ ?>
154 - <?php if( @$this->haveData( 'languages' ) ) { ?><div id="languagelinks"><p><?php $this->html( 'languages' ); ?></p></div><?php } ?>
155 - <table>
156 - <tr>
157 - <td class="mw-label"><label for='wpName2'><?php $this->msg('yourname') ?></label></td>
158 - <td class="mw-input">
159 - <?php
160 - echo Html::input( 'wpName', $this->data['name'], 'text', array(
161 - 'class' => 'loginText',
162 - 'id' => 'wpName2',
163 - 'tabindex' => '1',
164 - 'size' => '20',
165 - 'required',
166 - 'autofocus'
167 - ) ); ?>
168 - </td>
169 - </tr>
170 - <tr>
171 - <td class="mw-label"><label for='wpPassword2'><?php $this->msg('yourpassword') ?></label></td>
172 - <td class="mw-input">
173 -<?php
174 - echo Html::input( 'wpPassword', null, 'password', array(
175 - 'class' => 'loginPassword',
176 - 'id' => 'wpPassword2',
177 - 'tabindex' => '2',
178 - 'size' => '20'
179 - ) + User::passwordChangeInputAttribs() ); ?>
180 - </td>
181 - </tr>
182 - <?php if( $this->data['usedomain'] ) {
183 - $doms = "";
184 - foreach( $this->data['domainnames'] as $dom ) {
185 - $doms .= "<option>" . htmlspecialchars( $dom ) . "</option>";
186 - }
187 - ?>
188 - <tr>
189 - <td class="mw-label"><?php $this->msg( 'yourdomainname' ) ?></td>
190 - <td class="mw-input">
191 - <select name="wpDomain" value="<?php $this->text( 'domain' ) ?>"
192 - tabindex="3">
193 - <?php echo $doms ?>
194 - </select>
195 - </td>
196 - </tr>
197 - <?php } ?>
198 - <tr>
199 - <td class="mw-label"><label for='wpRetype'><?php $this->msg('yourpasswordagain') ?></label></td>
200 - <td class="mw-input">
201 - <?php
202 - echo Html::input( 'wpRetype', null, 'password', array(
203 - 'class' => 'loginPassword',
204 - 'id' => 'wpRetype',
205 - 'tabindex' => '4',
206 - 'size' => '20'
207 - ) + User::passwordChangeInputAttribs() ); ?>
208 - </td>
209 - </tr>
210 - <tr>
211 - <?php if( $this->data['useemail'] ) { ?>
212 - <td class="mw-label"><label for='wpEmail'><?php $this->msg('youremail') ?></label></td>
213 - <td class="mw-input">
214 - <?php
215 - echo Html::input( 'wpEmail', $this->data['email'], 'email', array(
216 - 'class' => 'loginText',
217 - 'id' => 'wpEmail',
218 - 'tabindex' => '5',
219 - 'size' => '20'
220 - ) ); ?>
221 - <div class="prefsectiontip">
222 - <?php if( $this->data['emailrequired'] ) {
223 - $this->msgWiki('prefs-help-email-required');
224 - } else {
225 - $this->msgWiki('prefs-help-email');
226 - } ?>
227 - </div>
228 - </td>
229 - <?php } ?>
230 - <?php if( $this->data['userealname'] ) { ?>
231 - </tr>
232 - <tr>
233 - <td class="mw-label"><label for='wpRealName'><?php $this->msg('yourrealname') ?></label></td>
234 - <td class="mw-input">
235 - <input type='text' class='loginText' name="wpRealName" id="wpRealName"
236 - tabindex="6"
237 - value="<?php $this->text('realname') ?>" size='20' />
238 - <div class="prefsectiontip">
239 - <?php $this->msgWiki('prefs-help-realname'); ?>
240 - </div>
241 - </td>
242 - <?php } ?>
243 - </tr>
244 - <?php if( $this->data['canremember'] ) { ?>
245 - <tr>
246 - <td></td>
247 - <td class="mw-input">
248 - <input type='checkbox' name="wpRemember"
249 - tabindex="7"
250 - value="1" id="wpRemember"
251 - <?php if( $this->data['remember'] ) { ?>checked="checked"<?php } ?>
252 - /> <label for="wpRemember"><?php $this->msg('remembermypassword') ?></label>
253 - </td>
254 - </tr>
255 -<?php }
256 -
257 - $tabIndex = 8;
258 - if ( isset( $this->data['extraInput'] ) && is_array( $this->data['extraInput'] ) ) {
259 - foreach ( $this->data['extraInput'] as $inputItem ) { ?>
260 - <tr>
261 - <?php
262 - if ( !empty( $inputItem['msg'] ) && $inputItem['type'] != 'checkbox' ) {
263 - ?><td class="mw-label"><label for="<?php
264 - echo htmlspecialchars( $inputItem['name'] ); ?>"><?php
265 - $this->msgWiki( $inputItem['msg'] ) ?></label><?php
266 - } else {
267 - ?><td><?php
268 - }
269 - ?></td>
270 - <td class="mw-input">
271 - <input type="<?php echo htmlspecialchars( $inputItem['type'] ) ?>" name="<?php
272 - echo htmlspecialchars( $inputItem['name'] ); ?>"
273 - tabindex="<?php echo $tabIndex++; ?>"
274 - value="<?php
275 - if ( $inputItem['type'] != 'checkbox' ) {
276 - echo htmlspecialchars( $inputItem['value'] );
277 - } else {
278 - echo '1';
279 - }
280 - ?>" id="<?php echo htmlspecialchars( $inputItem['name'] ); ?>"
281 - <?php
282 - if ( $inputItem['type'] == 'checkbox' && !empty( $inputItem['value'] ) )
283 - echo 'checked="checked"';
284 - ?> /> <?php
285 - if ( $inputItem['type'] == 'checkbox' && !empty( $inputItem['msg'] ) ) {
286 - ?>
287 - <label for="<?php echo htmlspecialchars( $inputItem['name'] ); ?>"><?php
288 - $this->msgHtml( $inputItem['msg'] ) ?></label><?php
289 - }
290 - if( $inputItem['helptext'] !== false ) {
291 - ?>
292 - <div class="prefsectiontip">
293 - <?php $this->msgWiki( $inputItem['helptext'] ); ?>
294 - </div>
295 - <?php } ?>
296 - </td>
297 - </tr>
298 -<?php
299 -
300 - }
301 - }
302 -?>
303 - <tr>
304 - <td></td>
305 - <td class="mw-submit">
306 - <input type='submit' name="wpCreateaccount" id="wpCreateaccount"
307 - tabindex="<?php echo $tabIndex++; ?>"
308 - value="<?php $this->msg('createaccount') ?>" />
309 - <?php if( $this->data['createemail'] ) { ?>
310 - <input type='submit' name="wpCreateaccountMail" id="wpCreateaccountMail"
311 - tabindex="<?php echo $tabIndex++; ?>"
312 - value="<?php $this->msg('createaccountmail') ?>" />
313 - <?php } ?>
314 - </td>
315 - </tr>
316 - </table>
317 -<?php if( @$this->haveData( 'uselang' ) ) { ?><input type="hidden" name="uselang" value="<?php $this->text( 'uselang' ); ?>" /><?php } ?>
318 -</form>
319 -</div>
320 -<div id="signupend"><?php $this->msgWiki( 'signupend' ); ?></div>
321 -<?php
322 -
323 - }
324 -}
Index: trunk/phase3/languages/messages/MessagesQqq.php
@@ -596,7 +596,7 @@
597597 {{Identical|Log in}}",
598598 '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.",
599599 'loginprompt' => 'A small notice in the log in form.',
600 -'userlogin' => 'Name of special page [[Special:UserLogin]] where a user can log in or click to create a user account.',
 600+'userlogin' => 'Name of special page [[Special:UserLogin]] where a user can log in.',
601601 'logout' => '{{Identical|Log out}}',
602602 'userlogout' => '{{Identical|Log out}}',
603603 '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.
Index: trunk/phase3/languages/messages/MessagesEn.php
@@ -1042,7 +1042,7 @@
10431043 'login' => 'Log in',
10441044 'nav-login-createaccount' => 'Log in / create account',
10451045 'loginprompt' => 'You must have cookies enabled to log in to {{SITENAME}}.',
1046 -'userlogin' => 'Log in / create account',
 1046+'userlogin' => 'Log in',
10471047 'logout' => 'Log out',
10481048 'userlogout' => 'Log out',
10491049 'notloggedin' => 'Not logged in',
@@ -1090,6 +1090,7 @@
10911091 and you no longer wish to change it, you may ignore this message and
10921092 continue using your old password.',
10931093 'noemail' => 'There is no e-mail address recorded for user "$1".',
 1094+'noemailcreate' => 'You need to provide a valid email address',
10941095 'passwordsent' => 'A new password has been sent to the e-mail address registered for "$1".
10951096 Please log in again after you receive it.',
10961097 'blocked-mailpassword' => 'Your IP address is blocked from editing, and so is not allowed to use the password recovery function to prevent abuse.',
Index: trunk/phase3/RELEASE-NOTES
@@ -87,6 +87,11 @@
8888 correctly (img_auth only)
8989 * $wgUploadMaintenance added to disable file deletions and restorations during
9090 maintenance
 91+* UserLoginForm and UserCreateForm hooks, and AuthPlugin::modifyUITemplate, now receive a
 92+ SpecialPage subclass instead of a QuickTemplate subclass. Hence there is no
 93+ $template->set(), etc. The hook has access to most of the stuff that will go into the
 94+ Login/Create form; see the documentation on HTMLForm for syntax for extra fields.
 95+ LoginForm class is deprecated, its state constants are now in the Login class.
9196
9297 === New features in 1.16 ===
9398
Index: trunk/extensions/AntiSpoof/AntiSpoof.php
@@ -103,15 +103,17 @@
104104 /**
105105 * Set the ignore spoof thingie
106106 */
107 -function asUserCreateFormHook( &$template ) {
 107+function asUserCreateFormHook( &$sp ) {
108108 global $wgRequest, $wgAntiSpoofAccounts, $wgUser;
109109
110110 wfLoadExtensionMessages( 'AntiSpoof' );
111111
112112 if( $wgAntiSpoofAccounts && $wgUser->isAllowed( 'override-antispoof' ) )
113 - $template->addInputItem( 'wpIgnoreAntiSpoof',
114 - $wgRequest->getCheck('wpIgnoreAntiSpoof'),
115 - 'checkbox', 'antispoof-ignore' );
 113+ $sp->mFormFields['IgnoreAntiSpoof'] = array(
 114+ 'type' => 'check',
 115+ 'default' => $wgRequest->getCheck('wpIgnoreAntiSpoof'),
 116+ 'label-message' => 'antispoof-ignore'
 117+ );
116118 return true;
117119 }
118120
Index: trunk/extensions/ConfirmEdit/ConfirmEdit_body.php
@@ -39,8 +39,8 @@
4040 return self::getInstance()->triggerUserLogin( $user, $password, $retval );
4141 }
4242
43 - static function injectUserLogin( &$template ) {
44 - return self::getInstance()->injectUserLogin( $template );
 43+ static function injectUserLogin( &$sp ) {
 44+ return self::getInstance()->injectUserLogin( $sp );
4545 }
4646
4747 static function confirmUserLogin( $u, $pass, &$retval ) {
@@ -144,18 +144,18 @@
145145 * @param SimpleTemplate $template
146146 * @return bool true to keep running callbacks
147147 */
148 - function injectUserCreate( &$template ) {
 148+ function injectUserCreate( &$sp ) {
149149 global $wgCaptchaTriggers, $wgOut, $wgUser;
150150 if ( $wgCaptchaTriggers['createaccount'] ) {
151151 if ( $wgUser->isAllowed( 'skipcaptcha' ) ) {
152152 wfDebug( "ConfirmEdit: user group allows skipping captcha on account creation\n" );
153153 return true;
154154 }
155 - $template->set( 'header',
 155+ $sp->mFormHeader .=
156156 "<div class='captcha'>" .
157157 $wgOut->parse( $this->getMessage( 'createaccount' ) ) .
158158 $this->getForm() .
159 - "</div>\n" );
 159+ "</div>\n";
160160 }
161161 return true;
162162 }
@@ -163,18 +163,17 @@
164164 /**
165165 * Inject a captcha into the user login form after a failed
166166 * password attempt as a speedbump for mass attacks.
167 - * @fixme if multiple thingies insert a header, could break
168167 * @param SimpleTemplate $template
169168 * @return bool true to keep running callbacks
170169 */
171 - function injectUserLogin( &$template ) {
 170+ function injectUserLogin( &$sp ) {
172171 if ( $this->isBadLoginTriggered() ) {
173172 global $wgOut;
174 - $template->set( 'header',
 173+ $sp->mFormHeader .=
175174 "<div class='captcha'>" .
176175 $wgOut->parse( $this->getMessage( 'badlogin' ) ) .
177176 $this->getForm() .
178 - "</div>\n" );
 177+ "</div>\n";
179178 }
180179 return true;
181180 }
@@ -190,7 +189,7 @@
191190 */
192191 function triggerUserLogin( $user, $password, $retval ) {
193192 global $wgCaptchaTriggers, $wgCaptchaBadLoginExpiration, $wgMemc;
194 - if ( $retval == LoginForm::WRONG_PASS && $wgCaptchaTriggers['badlogin'] ) {
 193+ if ( $retval == Login::WRONG_PASS && $wgCaptchaTriggers['badlogin'] ) {
195194 $key = $this->badLoginKey();
196195 $count = $wgMemc->get( $key );
197196 if ( !$count ) {
@@ -557,7 +556,7 @@
558557 if ( !$this->passCaptcha() ) {
559558 $message = wfMsg( 'captcha-badlogin-fail' );
560559 // Emulate a bad-password return to confuse the shit out of attackers
561 - $retval = LoginForm::WRONG_PASS;
 560+ $retval = Login::WRONG_PASS;
562561 return false;
563562 }
564563 }
Index: trunk/extensions/LdapAuthentication/LdapAuthentication.php
@@ -376,38 +376,43 @@
377377 /**
378378 * Modify options in the login template.
379379 *
380 - * @param UserLoginTemplate $template
 380+ * @param $sp SpecialUserlogin or SpecialCreateAccount object
381381 * @access public
382382 */
383 - function modifyUITemplate( &$template ) {
 383+ public function modifyUITemplate( &$sp ) {
384384 global $wgLDAPDomainNames, $wgLDAPUseLocal;
385385 global $wgLDAPAddLDAPUsers;
386386 global $wgLDAPAutoAuthDomain;
387387
388388 $this->printDebug( "Entering modifyUITemplate", NONSENSITIVE );
 389+
 390+ if( $sp instanceof SpecialUserlogin ){
389391
390 - if ( !isset( $wgLDAPAddLDAPUsers[$_SESSION['wsDomain']] ) || !$wgLDAPAddLDAPUsers[$_SESSION['wsDomain']] ) {
391 - $template->set( 'create', false );
392 - }
 392+ $tempDomArr = $wgLDAPDomainNames;
 393+ if( $wgLDAPUseLocal ) {
 394+ $this->printDebug( "Allowing the local domain, adding it to the list.", NONSENSITIVE );
 395+ array_push( $tempDomArr, 'local' );
 396+ }
 397+
 398+ if( isset( $wgLDAPAutoAuthDomain ) ) {
 399+ $this->printDebug( "Allowing auto-authentication login, removing the domain from the list.", NONSENSITIVE );
 400+
 401+ //There is no reason for people to log in directly to the wiki if the are using an
 402+ //auto-authentication domain. If they try to, they are probably up to something fishy.
 403+ unset( $tempDomArr[array_search( $wgLDAPAutoAuthDomain, $tempDomArr )] );
 404+ }
 405+
 406+ $sp->mDomains = $tempDomArr;
 407+
 408+ } else { # SpecialCreateAccount
393409
394 - $template->set( 'usedomain', true );
395 - $template->set( 'useemail', false );
396 -
397 - $tempDomArr = $wgLDAPDomainNames;
398 - if ( $wgLDAPUseLocal ) {
399 - $this->printDebug( "Allowing the local domain, adding it to the list.", NONSENSITIVE );
400 - array_push( $tempDomArr, 'local' );
 410+ # FIXME: This achieves nothing; what is the purpose?
 411+ if( !isset( $wgLDAPAddLDAPUsers[$_SESSION['wsDomain']] ) || !$wgLDAPAddLDAPUsers[$_SESSION['wsDomain']] ) {
 412+ $sp->set( 'create', false );
 413+ }
 414+
 415+ $sp->mUseEmail = false;
401416 }
402 -
403 - if ( isset( $wgLDAPAutoAuthDomain ) ) {
404 - $this->printDebug( "Allowing auto-authentication login, removing the domain from the list.", NONSENSITIVE );
405 -
406 - //There is no reason for people to log in directly to the wiki if the are using an
407 - //auto-authentication domain. If they try to, they are probably up to something fishy.
408 - unset( $tempDomArr[array_search( $wgLDAPAutoAuthDomain, $tempDomArr )] );
409 - }
410 -
411 - $template->set( 'domainnames', $tempDomArr );
412417 }
413418
414419 /**
Index: trunk/extensions/WikimediaIncubator/CreateAccountTestWiki.php
@@ -4,14 +4,14 @@
55 * This can be used to work with my toolserver project (http://toolserver.org/~robin/?tool=proposewiki), so users don't *have* to change their preferences (automatically is always better :p)
66 */
77 class AutoTestWiki {
8 - function onUserCreateForm( $template ) {
 8+ function onUserCreateForm( $sp ) {
99 global $wgRequest;
1010 $projectvalue = strtolower( $wgRequest->getVal( 'testwikiproject', '' ) );
1111 $codevalue = strtolower( $wgRequest->getVal( 'testwikicode', '' ) );
1212 if ( preg_match( '/[a-z][a-z][a-z]?/', $codevalue ) && in_array( $projectvalue, array( 'p', 'b', 't', 'q', 'n' ) ) ) {
13 - $template->set( 'header', '<input type="hidden" name="testwiki-project" value="' . $projectvalue . '" />
 13+ $sp->mFormHeader .= '<input type="hidden" name="testwiki-project" value="' . $projectvalue . '" />
1414 <input type="hidden" name="testwiki-code" value="' . $codevalue . '" />
15 - ' );
 15+ ';
1616 }
1717 return true;
1818 }
Index: trunk/extensions/ConfirmAccount/SpecialConfirmAccount.php
@@ -132,12 +132,12 @@
133133 }
134134 }
135135
136 -function efAddRequestLoginText( &$template ) {
 136+function efAddRequestLoginText( &$sp ) {
137137 global $wgUser;
138138 wfLoadExtensionMessages( 'ConfirmAccount' );
139139 # Add a link to RequestAccount from UserLogin
140140 if ( !$wgUser->isAllowed( 'createaccount' ) ) {
141 - $template->set( 'header', wfMsgExt( 'requestaccount-loginnotice', array( 'parse' ) ) );
 141+ $sp->mFormHeader = wfMsgExt( 'requestaccount-loginnotice', array( 'parse' ) );
142142 }
143143 return true;
144144 }

Follow-up revisions

RevisionCommit summaryAuthorDate
r56686Follow-ups to r56684: add a member function for extensions to add header text...happy-melon21:24, 20 September 2009
r56696Follow-up to r56684; fix newuser log.happy-melon10:57, 21 September 2009
r56697Followup r56684: Add new message 'createaccounterror' for errors on account c...demon11:37, 21 September 2009
r56699Follow-up to r56684 - stop people registering invalid usernames.happy-melon11:58, 21 September 2009
r56702Follow-up to r56684 - set message keys in Login.php, and readd the ExternalUs...happy-melon13:53, 21 September 2009
r56704Follow-up to r56684 - fix message parameters for Login::ILLEGALhappy-melon14:19, 21 September 2009
r56937Revert broken rewrite of login system; totally broken....brion00:49, 26 September 2009

Comments

#Comment by Bryan (talk | contribs)   20:38, 20 September 2009
+       /**
+        * 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;
+

Why not give name, password, domain and remember as separate parameters and possibly add a helper method createFromRequest? That would eliminate FauxRequest hacks.

-               $loginForm = new LoginForm($req);
-               switch ($authRes = $loginForm->authenticateUserData()) {
-                       case LoginForm :: SUCCESS :
+               $loginForm = new Login( $req );

That variable should be renamed.


#Comment by Happy-melon (talk | contribs)   21:27, 20 September 2009

I'm not convinced that passing large numbers of parameters is better than using FauxRequest; it doesn't seem that hackish to me.

$loginForm → $login in rev:56686

#Comment by Nikerabbit (talk | contribs)   05:18, 21 September 2009

Seems to create incorrect log entries:

04:25     60.xx.xx.xx created new account User:NK45
#Comment by Nikerabbit (talk | contribs)   05:24, 21 September 2009

+ Doesn't seem to add an entry to the actual new users log, just recent changes.

#Comment by Nikerabbit (talk | contribs)   05:35, 21 September 2009

Actually it does, but it is create2 entry with ip as log_user_text and 0 as log_user, and thus not shown in there.

Status & tagging log