r56058 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r56057‎ | r56058 | r56059 >
Date:18:40, 8 September 2009
Author:brion
Status:ok (Comments)
Tags:
Comment:
Revert broken rewrite of login forms:
r55990 "* Totally refactor includes/specials/SpecialUserlogin.php:"
r55991 "Followup to r55990 - Remove debugging hack :("
r55994 "Followup to r55990 - rename method to avoid PHP Strict warnings"
r55997 "Follow-up to r55990, per comments:"

Continued reports of breakage with the new version...
Non-vital changes of this magnitude should probably be worked up on a branch to ensure everything's consistent before pushing them to trunk.
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/img_auth.php (modified) (history)
  • /trunk/phase3/includes/AuthPlugin.php (modified) (history)
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/Login.php (deleted) (history)
  • /trunk/phase3/includes/SpecialPage.php (modified) (history)
  • /trunk/phase3/includes/api/ApiLogin.php (modified) (history)
  • /trunk/phase3/includes/specials/SpecialCreateAccount.php (deleted) (history)
  • /trunk/phase3/includes/specials/SpecialResetpass.php (modified) (history)
  • /trunk/phase3/includes/specials/SpecialUserlogin.php (modified) (history)
  • /trunk/phase3/includes/templates/Userlogin.php (added) (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/extensions/LdapAuthentication/LdapAuthentication.php
@@ -376,43 +376,38 @@
377377 /**
378378 * Modify options in the login template.
379379 *
380 - * @param $sp SpecialUserlogin or SpecialCreateAccount object
 380+ * @param UserLoginTemplate $template
381381 * @access public
382382 */
383 - public function modifyUITemplate( &$sp ) {
 383+ function modifyUITemplate( &$template ) {
384384 global $wgLDAPDomainNames, $wgLDAPUseLocal;
385385 global $wgLDAPAddLDAPUsers;
386386 global $wgLDAPAutoAuthDomain;
387387
388388 $this->printDebug( "Entering modifyUITemplate", NONSENSITIVE );
389 -
390 - if( $sp instanceof SpecialUserlogin ){
391389
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
 390+ if ( !isset( $wgLDAPAddLDAPUsers[$_SESSION['wsDomain']] ) || !$wgLDAPAddLDAPUsers[$_SESSION['wsDomain']] ) {
 391+ $template->set( 'create', false );
 392+ }
409393
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;
 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' );
416401 }
 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 );
417412 }
418413
419414 /**
Index: trunk/extensions/AntiSpoof/AntiSpoof.php
@@ -103,17 +103,15 @@
104104 /**
105105 * Set the ignore spoof thingie
106106 */
107 -function asUserCreateFormHook( &$sp ) {
 107+function asUserCreateFormHook( &$template ) {
108108 global $wgRequest, $wgAntiSpoofAccounts, $wgUser;
109109
110110 wfLoadExtensionMessages( 'AntiSpoof' );
111111
112112 if( $wgAntiSpoofAccounts && $wgUser->isAllowed( 'override-antispoof' ) )
113 - $sp->mFormFields['IgnoreAntiSpoof'] = array(
114 - 'type' => 'check',
115 - 'default' => $wgRequest->getCheck('wpIgnoreAntiSpoof'),
116 - 'label-message' => 'antispoof-ignore'
117 - );
 113+ $template->addInputItem( 'wpIgnoreAntiSpoof',
 114+ $wgRequest->getCheck('wpIgnoreAntiSpoof'),
 115+ 'checkbox', 'antispoof-ignore' );
118116 return true;
119117 }
120118
Index: trunk/extensions/ConfirmAccount/SpecialConfirmAccount.php
@@ -125,11 +125,11 @@
126126 $wgExtensionMessagesFiles['ConfirmAccount'] = $dir . 'ConfirmAccount.i18n.php';
127127 $wgExtensionAliasesFiles['ConfirmAccount'] = $dir . 'ConfirmAccount.alias.php';
128128
129 -function efAddRequestLoginText( &$sp ) {
 129+function efAddRequestLoginText( &$template ) {
130130 global $wgUser;
131131 wfLoadExtensionMessages( 'ConfirmAccount' );
132132 if ( !$wgUser->isAllowed( 'createaccount' ) ) {
133 - $sp->mFormHeader .= wfMsgExt( 'requestaccount-loginnotice', array( 'parse' ) );
 133+ $template->set( 'header', wfMsgExt( 'requestaccount-loginnotice', array( 'parse' ) ) );
134134 }
135135 return true;
136136 }
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( &$sp ) {
44 - return self::getInstance()->injectUserLogin( $sp );
 43+ static function injectUserLogin( &$template ) {
 44+ return self::getInstance()->injectUserLogin( $template );
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( &$sp ) {
 148+ function injectUserCreate( &$template ) {
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 - $sp->mFormHeader .=
 155+ $template->set( 'header',
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,17 +163,18 @@
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
167168 * @param SimpleTemplate $template
168169 * @return bool true to keep running callbacks
169170 */
170 - function injectUserLogin( &$sp ) {
 171+ function injectUserLogin( &$template ) {
171172 if ( $this->isBadLoginTriggered() ) {
172173 global $wgOut;
173 - $sp->mFormHeader .=
 174+ $template->set( 'header',
174175 "<div class='captcha'>" .
175176 $wgOut->parse( $this->getMessage( 'badlogin' ) ) .
176177 $this->getForm() .
177 - "</div>\n";
 178+ "</div>\n" );
178179 }
179180 return true;
180181 }
@@ -189,7 +190,7 @@
190191 */
191192 function triggerUserLogin( $user, $password, $retval ) {
192193 global $wgCaptchaTriggers, $wgCaptchaBadLoginExpiration, $wgMemc;
193 - if ( $retval == Login::WRONG_PASS && $wgCaptchaTriggers['badlogin'] ) {
 194+ if ( $retval == LoginForm::WRONG_PASS && $wgCaptchaTriggers['badlogin'] ) {
194195 $key = $this->badLoginKey();
195196 $count = $wgMemc->get( $key );
196197 if ( !$count ) {
@@ -556,7 +557,7 @@
557558 if ( !$this->passCaptcha() ) {
558559 $message = wfMsg( 'captcha-badlogin-fail' );
559560 // Emulate a bad-password return to confuse the shit out of attackers
560 - $retval = Login::WRONG_PASS;
 561+ $retval = LoginForm::WRONG_PASS;
561562 return false;
562563 }
563564 }
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( $sp ) {
 8+ function onUserCreateForm( $template ) {
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 - $sp->mFormHeader .= '<input type="hidden" name="testwiki-project" value="' . $projectvalue . '" />
 13+ $template->set( 'header', '<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/phase3/skins/common/shared.css
@@ -105,8 +105,6 @@
106106
107107 table.mw-htmlform-nolabel td.mw-label { width: 0 !important; }
108108
109 -#wpLoginAttempt, #wpCreateaccount { margin-right:0; }
110 -
111109 /**
112110 * Image captions
113111 */
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 Login class constant to return from authenticateUserData();
249 - default is Login::ABORTED. Note that the client may be using
 248+&$retval: a LoginForm class constant to return from authenticateUserData();
 249+ default is LoginForm::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 Login class constant with authenticateUserData() return
 948+$retval: a LoginForm class constant with authenticateUserData() return
949949 value (SUCCESS, WRONG_PASS, etc)
950950
951951 'LogLine': Processes a single log entry on Special:Log
@@ -1523,7 +1523,7 @@
15241524 determine if the password was valid
15251525
15261526 'UserCreateForm': change to manipulate the login form
1527 -$sp: SpecialCreateAccount instance
 1527+$template: SimpleTemplate instance for the form
15281528
15291529 'UserCryptPassword': called when hashing a password, return false to implement
15301530 your own hashing method
@@ -1593,7 +1593,7 @@
15941594 $inject_html: Any HTML to inject after the "logged in" message.
15951595
15961596 'UserLoginForm': change to manipulate the login form
1597 -$sp: SpecialUserLogin instance
 1597+$template: SimpleTemplate instance for the form
15981598
15991599 'UserLoginMailPassword': Block users from emailing passwords
16001600 $name: the username to email the password of.
Index: trunk/phase3/RELEASE-NOTES
@@ -82,11 +82,6 @@
8383 * (bug 20489) $wgIllegalFileChars added to override the default list of illegal characters in file names.
8484 * (bug 19646) $wgImgAuthDetails added to display reason access to uploaded file was denied to users(img_auth only)
8585 * (bug 19646) $wgImgAuthPublicTest added to test to see if img_auth set up correctly (img_auth only)
86 -* UserLoginForm and UserCreateForm hooks, and AuthPlugin::modifyUITemplate, now receive a
87 - SpecialPage subclass instead of a QuickTemplate subclass. Hence there is no
88 - $template->set(), etc. The hook has access to most of the stuff that will go into the
89 - Login/Create form; see the documentation on HTMLForm for syntax for extra fields.
90 -* LoginForm class is deprecated, its state constants are now in the Login class.
9186
9287 === New features in 1.16 ===
9388
Index: trunk/phase3/includes/Login.php
@@ -1,378 +0,0 @@
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 CREATE_BLOCKED = 9;
19 - const THROTTLED = 10;
20 -
21 - const MAIL_READ_ONLY = 11;
22 - const MAIL_PASSCHANGE_FORBIDDEN = 12;
23 - const MAIL_BLOCKED = 13;
24 - const MAIL_PING_THROTTLED = 14;
25 - const MAIL_PASS_THROTTLED = 15;
26 - const MAIL_EMPTY_EMAIL = 16;
27 - const MAIL_BAD_IP = 17;
28 - const MAIL_ERROR = 18;
29 -
30 - var $mName, $mPassword, $mPosted;
31 - var $mLoginattempt, $mRemember, $mEmail, $mDomain, $mLanguage;
32 -
33 - private $mExtUser = null;
34 -
35 - public $mUser;
36 - public $mMailResult;
37 -
38 - /**
39 - * Constructor
40 - * @param WebRequest $request A WebRequest object passed by reference.
41 - * uses $wgRequest if not given.
42 - */
43 - public function __construct( &$request=null ) {
44 - global $wgRequest, $wgAuth, $wgHiddenPrefs, $wgEnableEmail, $wgRedirectOnLogin;
45 - if( !$request ) $request = &$wgRequest;
46 -
47 - $this->mName = $request->getText( 'wpName' );
48 - $this->mPassword = $request->getText( 'wpPassword' );
49 - $this->mDomain = $request->getText( 'wpDomain' );
50 - $this->mPosted = $request->wasPosted();
51 - $this->mRemember = $request->getCheck( 'wpRemember' );
52 -
53 - if( $wgEnableEmail ) {
54 - $this->mEmail = $request->getText( 'wpEmail' );
55 - } else {
56 - $this->mEmail = '';
57 - }
58 - if( !in_array( 'realname', $wgHiddenPrefs ) ) {
59 - $this->mRealName = $request->getText( 'wpRealName' );
60 - } else {
61 - $this->mRealName = '';
62 - }
63 -
64 - if( !$wgAuth->validDomain( $this->mDomain ) ) {
65 - $this->mDomain = 'invaliddomain';
66 - }
67 - $wgAuth->setDomain( $this->mDomain );
68 -
69 - # Attempt to generate the User
70 - $this->mUser = User::newFromName( $this->mName );
71 - }
72 -
73 - /**
74 - * Actually add a user to the database.
75 - * Give it a User object that has been initialised with a name.
76 - *
77 - * @param $u User object.
78 - * @param $autocreate boolean -- true if this is an autocreation via auth plugin
79 - * @return User object.
80 - */
81 - public function initUser( $autocreate ) {
82 - global $wgAuth;
83 -
84 - $this->mUser->addToDatabase();
85 -
86 - if ( $wgAuth->allowPasswordChange() ) {
87 - $this->mUser->setPassword( $this->mPassword );
88 - }
89 -
90 - $this->mUser->setEmail( $this->mEmail );
91 - $this->mUser->setRealName( $this->mRealName );
92 - $this->mUser->setToken();
93 -
94 - $wgAuth->initUser( $this->mUser, $autocreate );
95 -
96 - if( $this->mExtUser ) {
97 - $this->mExtUser->link( $this->mUser->getId() );
98 - $email = $this->mExtUser->getPref( 'emailaddress' );
99 - if( $email && !$this->mEmail ) {
100 - $this->mUser->setEmail( $email );
101 - }
102 - }
103 -
104 - $this->mUser->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 );
105 - $this->mUser->saveSettings();
106 -
107 - # Update user count
108 - $ssUpdate = new SiteStatsUpdate( 0, 0, 0, 0, 1 );
109 - $ssUpdate->doUpdate();
110 -
111 - return $this->mUser;
112 - }
113 -
114 - public function attemptLogin(){
115 - global $wgUser;
116 - $code = $this->authenticateUserData();
117 - if( !$code == self::SUCCESS ){
118 - return $code;
119 - }
120 - if( (bool)$this->mRemember != (bool)$wgUser->getOption( 'rememberpassword' ) ) {
121 - $wgUser->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 );
122 - $wgUser->saveSettings();
123 - } else {
124 - $wgUser->invalidateCache();
125 - }
126 - $wgUser->setCookies();
127 -
128 - # Reset the throttle
129 - $key = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
130 - global $wgMemc;
131 - $wgMemc->delete( $key );
132 -
133 - $injected_html = '';
134 - wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
135 -
136 - return self::SUCCESS;
137 - }
138 -
139 - /**
140 - * Internally authenticate the login request.
141 - *
142 - * This may create a local account as a side effect if the
143 - * authentication plugin allows transparent local account
144 - * creation.
145 - */
146 - public function authenticateUserData() {
147 - global $wgUser, $wgAuth;
148 - if ( '' == $this->mName ) {
149 - return self::NO_NAME;
150 - }
151 -
152 - global $wgPasswordAttemptThrottle;
153 -
154 - $throttleCount = 0;
155 - if ( is_array( $wgPasswordAttemptThrottle ) ) {
156 - $throttleKey = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
157 - $count = $wgPasswordAttemptThrottle['count'];
158 - $period = $wgPasswordAttemptThrottle['seconds'];
159 -
160 - global $wgMemc;
161 - $throttleCount = $wgMemc->get( $throttleKey );
162 - if ( !$throttleCount ) {
163 - $wgMemc->add( $throttleKey, 1, $period ); // start counter
164 - } else if ( $throttleCount < $count ) {
165 - $wgMemc->incr($throttleKey);
166 - } else if ( $throttleCount >= $count ) {
167 - return self::THROTTLED;
168 - }
169 - }
170 -
171 - # Load $wgUser now, and check to see if we're logging in as the same
172 - # name. This is necessary because loading $wgUser (say by calling
173 - # getName()) calls the UserLoadFromSession hook, which potentially
174 - # creates the user in the database. Until we load $wgUser, checking
175 - # for user existence using User::newFromName($name)->getId() below
176 - # will effectively be using stale data.
177 - if ( $wgUser->getName() === $this->mName ) {
178 - wfDebug( __METHOD__.": already logged in as {$this->mName}\n" );
179 - return self::SUCCESS;
180 - }
181 -
182 - $this->mExtUser = ExternalUser::newFromName( $this->mName );
183 -
184 - # TODO: Allow some magic here for invalid external names, e.g., let the
185 - # user choose a different wiki name.
186 - if( is_null( $this->mUser ) || !User::isUsableName( $this->mUser->getName() ) ) {
187 - return self::ILLEGAL;
188 - }
189 -
190 - $isAutoCreated = false;
191 - if ( 0 == $this->mUser->getID() ) {
192 - $status = $this->attemptAutoCreate( $this->mUser );
193 - if ( $status !== self::SUCCESS ) {
194 - return $status;
195 - } else {
196 - $isAutoCreated = true;
197 - }
198 - } else {
199 - $this->mUser->load();
200 - }
201 -
202 - # Give general extensions, such as a captcha, a chance to abort logins
203 - $abort = self::ABORTED;
204 - if( !wfRunHooks( 'AbortLogin', array( $this->mUser, $this->mPassword, &$abort ) ) ) {
205 - return $abort;
206 - }
207 -
208 - if( !$this->mUser->checkPassword( $this->mPassword ) ) {
209 - if( $this->mUser->checkTemporaryPassword( $this->mPassword ) ) {
210 - # The e-mailed temporary password should not be used for actual
211 - # logins; that's a very sloppy habit, and insecure if an
212 - # attacker has a few seconds to click "search" on someone's
213 - # open mail reader.
214 - #
215 - # Allow it to be used only to reset the password a single time
216 - # to a new value, which won't be in the user's e-mail archives
217 - #
218 - # For backwards compatibility, we'll still recognize it at the
219 - # login form to minimize surprises for people who have been
220 - # logging in with a temporary password for some time.
221 - #
222 - # As a side-effect, we can authenticate the user's e-mail ad-
223 - # dress if it's not already done, since the temporary password
224 - # was sent via e-mail.
225 - if( !$this->mUser->isEmailConfirmed() ) {
226 - $this->mUser->confirmEmail();
227 - $this->mUser->saveSettings();
228 - }
229 -
230 - # At this point we just return an appropriate code/ indicating
231 - # that the UI should show a password reset form; bot interfaces
232 - # etc will probably just fail cleanly here.
233 - $retval = self::RESET_PASS;
234 - } else {
235 - $retval = '' == $this->mPassword ? self::EMPTY_PASS : self::WRONG_PASS;
236 - }
237 - } else {
238 - $wgAuth->updateUser( $this->mUser );
239 - $wgUser = $this->mUser;
240 -
241 - # Reset throttle after a successful login
242 - if( $throttleCount ) {
243 - $wgMemc->delete( $throttleKey );
244 - }
245 -
246 - if( $isAutoCreated ) {
247 - # Must be run after $wgUser is set, for correct new user log
248 - wfRunHooks( 'AuthPluginAutoCreate', array( $wgUser ) );
249 - }
250 -
251 - $retval = self::SUCCESS;
252 - }
253 - wfRunHooks( 'LoginAuthenticateAudit', array( $this->mUser, $this->mPassword, $retval ) );
254 - return $retval;
255 - }
256 -
257 - /**
258 - * Attempt to automatically create a user on login. Only succeeds if there
259 - * is an external authentication method which allows it.
260 - * @return integer Status code
261 - */
262 - public function attemptAutoCreate( $user ) {
263 - global $wgAuth, $wgUser, $wgAutocreatePolicy;
264 -
265 - if( $wgUser->isBlockedFromCreateAccount() ) {
266 - wfDebug( __METHOD__.": user is blocked from account creation\n" );
267 - return self::CREATE_BLOCKED;
268 - }
269 -
270 - # If the external authentication plugin allows it, automatically cre-
271 - # ate a new account for users that are externally defined but have not
272 - # yet logged in.
273 - if( $this->mExtUser ) {
274 - # mExtUser is neither null nor false, so use the new ExternalAuth
275 - # system.
276 - if( $wgAutocreatePolicy == 'never' ) {
277 - return self::NOT_EXISTS;
278 - }
279 - if( !$this->mExtUser->authenticate( $this->mPassword ) ) {
280 - return self::WRONG_PLUGIN_PASS;
281 - }
282 - } else {
283 - # Old AuthPlugin.
284 - if( !$wgAuth->autoCreate() ) {
285 - return self::NOT_EXISTS;
286 - }
287 - if( !$wgAuth->userExists( $user->getName() ) ) {
288 - wfDebug( __METHOD__.": user does not exist\n" );
289 - return self::NOT_EXISTS;
290 - }
291 - if( !$wgAuth->authenticate( $user->getName(), $this->mPassword ) ) {
292 - wfDebug( __METHOD__.": \$wgAuth->authenticate() returned false, aborting\n" );
293 - return self::WRONG_PLUGIN_PASS;
294 - }
295 - }
296 -
297 - wfDebug( __METHOD__.": creating account\n" );
298 - $this->initUser( true );
299 - return self::SUCCESS;
300 - }
301 -
302 - /**
303 - * Email the user a new password, if appropriate to do so.
304 - * @param $text String message key
305 - * @param $title String message key
306 - * @return Status code
307 - */
308 - public function mailPassword( $text='passwordremindertext', $title='passwordremindertitle' ) {
309 - global $wgUser, $wgOut, $wgAuth, $wgServer, $wgScript, $wgNewPasswordExpiry;
310 -
311 - if( wfReadOnly() )
312 - return self::MAIL_READ_ONLY;
313 -
314 - if( !$wgAuth->allowPasswordChange() )
315 - return self::MAIL_PASSCHANGE_FORBIDDEN;
316 -
317 - # Check against blocked IPs
318 - # FIXME: -- should we not?
319 - if( $wgUser->isBlocked() )
320 - return self::MAIL_BLOCKED;
321 -
322 - # Check for hooks
323 - $error = null;
324 - if ( ! wfRunHooks( 'UserLoginMailPassword', array( $this->mName, &$error ) ) )
325 - return $error;
326 -
327 - # Check against the rate limiter
328 - if( $wgUser->pingLimiter( 'mailpassword' ) )
329 - return self::MAIL_PING_THROTTLED;
330 -
331 - # Check for a valid name
332 - if ( '' == $this->mName )
333 - return self::NO_NAME;
334 - $this->mUser = User::newFromName( $this->mName );
335 - if( is_null( $this->mUser ) )
336 - return self::NO_NAME;
337 -
338 - # And that the resulting user actually exists
339 - if ( 0 == $this->mUser->getId() )
340 - return self::NOT_EXISTS;
341 -
342 - # Check against password throttle
343 - if ( $this->mUser->isPasswordReminderThrottled() )
344 - return self::MAIL_PASS_THROTTLED;
345 -
346 - # User doesn't have email address set
347 - if ( '' == $this->mUser->getEmail() )
348 - return self::MAIL_EMPTY_EMAIL;
349 -
350 - # Don't send to people who are acting fishily by hiding their IP
351 - $ip = wfGetIP();
352 - if( !$ip )
353 - return self::MAIL_BAD_IP;
354 -
355 - # Let hooks do things with the data
356 - wfRunHooks( 'User::mailPasswordInternal', array(&$wgUser, &$ip, &$this->mUser) );
357 -
358 - $newpass = $this->mUser->randomPassword();
359 - $this->mUser->setNewpassword( $newpass, true );
360 - $this->mUser->saveSettings();
361 -
362 - $message = wfMsgExt( $text, array( 'parsemag' ), $ip, $this->mUser->getName(), $newpass,
363 - $wgServer . $wgScript, round( $wgNewPasswordExpiry / 86400 ) );
364 - $this->mMailResult = $this->mUser->sendMail( wfMsg( $title ), $message );
365 -
366 - if( WikiError::isError( $this->mMailResult ) ) {
367 - return self::MAIL_ERROR;
368 - } else {
369 - return self::SUCCESS;
370 - }
371 - }
372 -}
373 -
374 -/**
375 - * For backwards compatibility, mainly with the state constants, which
376 - * could be referred to in old extensions with the old class name.
377 - * @deprecated
378 - */
379 -class LoginForm extends Login {}
\ No newline at end of file
Index: trunk/phase3/includes/SpecialPage.php
@@ -112,8 +112,8 @@
113113 'Listredirects' => array( 'SpecialPage', 'Listredirects' ),
114114
115115 # Login/create account
116 - 'Userlogin' => 'SpecialUserLogin',
117 - 'CreateAccount' => 'SpecialCreateAccount',
 116+ 'Userlogin' => array( 'SpecialPage', 'Userlogin' ),
 117+ 'CreateAccount' => array( 'SpecialRedirectToSpecial', 'CreateAccount', 'Userlogin', 'signup', array( 'uselang' ) ),
118118
119119 # Users and rights
120120 'Blockip' => array( 'SpecialPage', 'Blockip', 'block' ),
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' => '1'
 64+ 'wpRemember' => ''
6565 ));
6666
6767 // Init session if necessary
@@ -68,11 +68,19 @@
6969 wfSetupSession();
7070 }
7171
72 - $loginForm = new Login( $req );
73 - switch ( $authRes = $loginForm->attemptLogin() ) {
74 - case Login::SUCCESS :
 72+ $loginForm = new LoginForm($req);
 73+ switch ($authRes = $loginForm->authenticateUserData()) {
 74+ case LoginForm :: 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+
7785 $result['result'] = 'Success';
7886 $result['lguserid'] = intval($wgUser->getId());
7987 $result['lgusername'] = $wgUser->getName();
@@ -81,35 +89,35 @@
8290 $result['sessionid'] = session_id();
8391 break;
8492
85 - case Login::NO_NAME :
 93+ case LoginForm :: NO_NAME :
8694 $result['result'] = 'NoName';
8795 break;
88 - case Login::ILLEGAL :
 96+ case LoginForm :: ILLEGAL :
8997 $result['result'] = 'Illegal';
9098 break;
91 - case Login::WRONG_PLUGIN_PASS :
 99+ case LoginForm :: WRONG_PLUGIN_PASS :
92100 $result['result'] = 'WrongPluginPass';
93101 break;
94 - case Login::NOT_EXISTS :
 102+ case LoginForm :: NOT_EXISTS :
95103 $result['result'] = 'NotExists';
96104 break;
97 - case Login::WRONG_PASS :
 105+ case LoginForm :: WRONG_PASS :
98106 $result['result'] = 'WrongPass';
99107 break;
100 - case Login::EMPTY_PASS :
 108+ case LoginForm :: EMPTY_PASS :
101109 $result['result'] = 'EmptyPass';
102110 break;
103 - case Login::CREATE_BLOCKED :
 111+ case LoginForm :: CREATE_BLOCKED :
104112 $result['result'] = 'CreateBlocked';
105113 $result['details'] = 'Your IP address is blocked from account creation';
106114 break;
107 - case Login::THROTTLED :
 115+ case LoginForm :: THROTTLED :
108116 global $wgPasswordAttemptThrottle;
109117 $result['result'] = 'Throttled';
110118 $result['wait'] = intval($wgPasswordAttemptThrottle['seconds']);
111119 break;
112120 default :
113 - ApiBase::dieDebug(__METHOD__, "Unhandled case value: {$authRes}");
 121+ ApiBase :: dieDebug(__METHOD__, "Unhandled case value: {$authRes}");
114122 }
115123
116124 $this->getResult()->addValue(null, 'login', $result);
Index: trunk/phase3/includes/specials/SpecialCreateAccount.php
@@ -1,640 +0,0 @@
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 - public $mDomains = array();
14 -
15 - public $mUseEmail = true; # Can be switched off by AuthPlugins etc
16 - public $mUseRealname = true;
17 - public $mUseRemember = true;
18 -
19 - public $mFormHeader = '';
20 - public $mFormFields = array(
21 - 'Name' => array(
22 - 'type' => 'text',
23 - 'label-message' => 'yourname',
24 - 'id' => 'wpName2',
25 - 'tabindex' => '1',
26 - 'size' => '20',
27 - 'required' => '1',
28 - 'autofocus' => '',
29 - ),
30 - 'Password' => array(
31 - 'type' => 'password',
32 - 'label-message' => 'yourpassword',
33 - 'size' => '20',
34 - 'id' => 'wpPassword2',
35 - 'required' => '',
36 - ),
37 - 'Retype' => array(
38 - 'type' => 'password',
39 - 'label-message' => 'yourpasswordagain',
40 - 'size' => '20',
41 - 'id' => 'wpRetype',
42 - 'required' => '',
43 - ),
44 - 'Email' => array(
45 - 'type' => 'email',
46 - 'label-message' => 'youremail',
47 - 'size' => '20',
48 - 'id' => 'wpEmail',
49 - ),
50 - 'RealName' => array(
51 - 'type' => 'text',
52 - 'label-message' => 'yourrealname',
53 - 'id' => 'wpRealName',
54 - 'tabindex' => '1',
55 - 'size' => '20',
56 - 'help-message' => 'prefs-help-realname',
57 - ),
58 - 'Remember' => array(
59 - 'type' => 'check',
60 - 'label-message' => 'remembermypassword',
61 - 'id' => 'wpRemember',
62 - ),
63 - 'Domain' => array(
64 - 'type' => 'select',
65 - 'id' => 'wpDomain',
66 - 'label-message' => 'yourdomainname',
67 - 'options' => null,
68 - 'default' => null,
69 - ),
70 - );
71 -
72 - public function __construct(){
73 - parent::__construct( 'CreateAccount', 'createaccount' );
74 - $this->mLogin = new Login();
75 - }
76 -
77 - public function execute( $par ){
78 - global $wgUser, $wgOut;
79 -
80 - $this->setHeaders();
81 - $this->loadQuery();
82 -
83 - # Block signup here if in readonly. Keeps user from
84 - # going through the process (filling out data, etc)
85 - # and being informed later.
86 - if( wfReadOnly() ) {
87 - $wgOut->readOnlyPage();
88 - return;
89 - }
90 - # Bail out straightaway on permissions errors
91 - if( !$this->userCanExecute( $wgUser ) ) {
92 - $this->displayRestrictionError();
93 - return;
94 - } elseif( $wgUser->isBlockedFromCreateAccount() ) {
95 - $this->userBlockedMessage();
96 - return;
97 - } elseif( count( $permErrors = $this->getTitle()->getUserPermissionsErrors( 'createaccount', $wgUser, true ) )>0 ) {
98 - $wgOut->showPermissionsErrorPage( $permErrors, 'createaccount' );
99 - return;
100 - }
101 -
102 - if( $this->mPosted ) {
103 - if( $this->mCreateaccountMail ) {
104 - return $this->addNewAccountMailPassword();
105 - } else {
106 - return $this->addNewAccount();
107 - }
108 - } else {
109 - $this->showMainForm('');
110 - }
111 - }
112 -
113 - /**
114 - * Load the member variables from the request parameters
115 - */
116 - protected function loadQuery(){
117 - global $wgRequest, $wgAuth, $wgHiddenPrefs, $wgEnableEmail, $wgRedirectOnLogin;
118 - $this->mCreateaccountMail = $wgRequest->getCheck( 'wpCreateaccountMail' )
119 - && $wgEnableEmail;
120 -
121 - $this->mUsername = $wgRequest->getText( 'wpName' );
122 - $this->mPassword = $wgRequest->getText( 'wpPassword' );
123 - $this->mRetype = $wgRequest->getText( 'wpRetype' );
124 - $this->mDomain = $wgRequest->getText( 'wpDomain' );
125 - $this->mReturnTo = $wgRequest->getVal( 'returnto' );
126 - $this->mReturnToQuery = $wgRequest->getVal( 'returntoquery' );
127 - $this->mPosted = $wgRequest->wasPosted();
128 - $this->mCreateaccountMail = $wgRequest->getCheck( 'wpCreateaccountMail' )
129 - && $wgEnableEmail;
130 - $this->mRemember = $wgRequest->getCheck( 'wpRemember' );
131 - $this->mLanguage = $wgRequest->getText( 'uselang' );
132 -
133 - if ( $wgRedirectOnLogin ) {
134 - $this->mReturnTo = $wgRedirectOnLogin;
135 - $this->mReturnToQuery = '';
136 - }
137 -
138 - if( $wgEnableEmail ) {
139 - $this->mEmail = $wgRequest->getText( 'wpEmail' );
140 - } else {
141 - $this->mEmail = '';
142 - }
143 - if( !in_array( 'realname', $wgHiddenPrefs ) ) {
144 - $this->mRealName = $wgRequest->getText( 'wpRealName' );
145 - } else {
146 - $this->mRealName = '';
147 - }
148 -
149 - if( !$wgAuth->validDomain( $this->mDomain ) ) {
150 - $this->mDomain = 'invaliddomain';
151 - }
152 - $wgAuth->setDomain( $this->mDomain );
153 -
154 - # When switching accounts, it sucks to get automatically logged out
155 - $returnToTitle = Title::newFromText( $this->mReturnTo );
156 - if( is_object( $returnToTitle ) && $returnToTitle->isSpecial( 'Userlogout' ) ) {
157 - $this->mReturnTo = '';
158 - $this->mReturnToQuery = '';
159 - }
160 - }
161 -
162 - /**
163 - * Add a new account, and mail its password to the user
164 - */
165 - protected function addNewAccountMailPassword() {
166 - global $wgOut;
167 -
168 - if( !$this->mEmail ) {
169 - $this->showMainForm( wfMsg( 'noemail', htmlspecialchars( $this->mUsername ) ) );
170 - return;
171 - }
172 -
173 - if( !$this->addNewaccountInternal() ) {
174 - return;
175 - }
176 -
177 - # Wipe the initial password
178 - $this->mLogin->mUser->setPassword( null );
179 - $this->mLogin->mUser->saveSettings();
180 -
181 - # And mail them a temporary one
182 - $result = $this->mLogin->mailPassword( 'createaccount-title', 'createaccount-text' );
183 -
184 - wfRunHooks( 'AddNewAccount', array( $this->mLogin->mUser, true ) );
185 - $this->mLogin->mUser->addNewUserLogEntry();
186 -
187 - $wgOut->setPageTitle( wfMsg( 'accmailtitle' ) );
188 - $wgOut->setRobotPolicy( 'noindex,nofollow' );
189 - $wgOut->setArticleRelated( false );
190 -
191 - if( $result != Login::SUCCESS ) {
192 - if( $result == Login::MAIL_ERROR ){
193 - $this->showMainForm( wfMsg( 'mailerror', $this->mLogin->mMailResult->getMessage() ) );
194 - } else {
195 - $this->showMainForm( wfMsg( 'mailerror' ) );
196 - }
197 - } else {
198 - $wgOut->addWikiMsg( 'accmailtext', $this->mLogin->mUser->getName(), $this->mLogin->mUser->getEmail() );
199 - $wgOut->returnToMain( false );
200 - }
201 - }
202 -
203 - /**
204 - * Create a new user account from the provided data
205 - */
206 - protected function addNewAccount() {
207 - global $wgUser, $wgEmailAuthentication;
208 -
209 - # Create the account and abort if there's a problem doing so
210 - if( !$this->addNewAccountInternal() )
211 - return;
212 - $user = $this->mLogin->mUser;
213 -
214 - # If we showed up language selection links, and one was in use, be
215 - # smart (and sensible) and save that language as the user's preference
216 - global $wgLoginLanguageSelector;
217 - if( $wgLoginLanguageSelector && $this->mLanguage )
218 - $user->setOption( 'language', $this->mLanguage );
219 -
220 - # Send out an email authentication message if needed
221 - if( $wgEmailAuthentication && User::isValidEmailAddr( $user->getEmail() ) ) {
222 - global $wgOut;
223 - $error = $user->sendConfirmationMail();
224 - if( WikiError::isError( $error ) ) {
225 - $wgOut->addWikiMsg( 'confirmemail_sendfailed', $error->getMessage() );
226 - } else {
227 - $wgOut->addWikiMsg( 'confirmemail_oncreate' );
228 - }
229 - }
230 -
231 - # Save settings (including confirmation token)
232 - $user->saveSettings();
233 -
234 - # If not logged in, assume the new account as the current one and set
235 - # session cookies then show a "welcome" message or a "need cookies"
236 - # message as needed
237 - if( $wgUser->isAnon() ) {
238 - $wgUser = $user;
239 - $wgUser->setCookies();
240 - wfRunHooks( 'AddNewAccount', array( $wgUser ) );
241 - $wgUser->addNewUserLogEntry();
242 - if( $this->hasSessionCookie() ) {
243 - return $this->successfulCreation();
244 - } else {
245 - return $this->cookieRedirectCheck();
246 - }
247 - } else {
248 - # Confirm that the account was created
249 - global $wgOut;
250 - $self = SpecialPage::getTitleFor( 'Userlogin' );
251 - $wgOut->setPageTitle( wfMsgHtml( 'accountcreated' ) );
252 - $wgOut->setArticleRelated( false );
253 - $wgOut->setRobotPolicy( 'noindex,nofollow' );
254 - $wgOut->addWikiMsg( 'accountcreatedtext', $user->getName() );
255 - $wgOut->returnToMain( false, $self );
256 - wfRunHooks( 'AddNewAccount', array( $user ) );
257 - $user->addNewUserLogEntry();
258 - return true;
259 - }
260 - }
261 -
262 - /**
263 - * Deeper mechanics of initialising a new user and passing it
264 - * off to Login::initUser()
265 - * return Bool whether the user was successfully created
266 - */
267 - protected function addNewAccountInternal() {
268 - global $wgUser, $wgOut;
269 - global $wgEnableSorbs, $wgProxyWhitelist;
270 - global $wgMemc, $wgAccountCreationThrottle;
271 - global $wgAuth, $wgMinimalPasswordLength;
272 - global $wgEmailConfirmToEdit;
273 -
274 - # If the user passes an invalid domain, something is fishy
275 - if( !$wgAuth->validDomain( $this->mDomain ) ) {
276 - $this->showMainForm( wfMsg( 'wrongpassword' ) );
277 - return false;
278 - }
279 -
280 - # If we are not allowing users to login locally, we should be checking
281 - # to see if the user is actually able to authenticate to the authenti-
282 - # cation server before they create an account (otherwise, they can
283 - # create a local account and login as any domain user). We only need
284 - # to check this for domains that aren't local.
285 - if( !in_array( $this->mDomain, array( 'local', '' ) )
286 - && !$wgAuth->canCreateAccounts()
287 - && ( !$wgAuth->userExists( $this->mUsername )
288 - || !$wgAuth->authenticate( $this->mUsername, $this->mPassword )
289 - ) )
290 - {
291 - $this->showMainForm( wfMsg( 'wrongpassword' ) );
292 - return false;
293 - }
294 -
295 - $ip = wfGetIP();
296 - if( $wgEnableSorbs && !in_array( $ip, $wgProxyWhitelist ) &&
297 - $wgUser->inSorbsBlacklist( $ip ) )
298 - {
299 - $this->showMainForm( wfMsg( 'sorbs_create_account_reason' ) . ' (' . htmlspecialchars( $ip ) . ')' );
300 - return false;
301 - }
302 -
303 - # Now create a dummy user ($user) and check if it is valid
304 - $name = trim( $this->mUsername );
305 - $user = User::newFromName( $name, 'creatable' );
306 - if( is_null( $user ) ) {
307 - $this->showMainForm( wfMsg( 'noname' ) );
308 - return false;
309 - }
310 -
311 - if( 0 != $user->idForName() ) {
312 - $this->showMainForm( wfMsg( 'userexists' ) );
313 - return false;
314 - }
315 -
316 - if( 0 != strcmp( $this->mPassword, $this->mRetype ) ) {
317 - $this->showMainForm( wfMsg( 'badretype' ) );
318 - return false;
319 - }
320 -
321 - # check for minimal password length
322 - $valid = $user->isValidPassword( $this->mPassword );
323 - if( $valid !== true ) {
324 - if ( !$this->mCreateaccountMail ) {
325 - $this->showMainForm( wfMsgExt( $valid, array( 'parsemag' ), $wgMinimalPasswordLength ) );
326 - return false;
327 - } else {
328 - # do not force a password for account creation by email
329 - # set invalid password, it will be replaced later by a random generated password
330 - $this->mPassword = null;
331 - }
332 - }
333 -
334 - # if you need a confirmed email address to edit, then obviously you
335 - # need an email address.
336 - if( $wgEmailConfirmToEdit && empty( $this->mEmail ) ) {
337 - $this->showMainForm( wfMsg( 'noemailtitle' ) );
338 - return false;
339 - }
340 -
341 - if( !empty( $this->mEmail ) && !User::isValidEmailAddr( $this->mEmail ) ) {
342 - $this->showMainForm( wfMsg( 'invalidemailaddress' ) );
343 - return false;
344 - }
345 -
346 - # Set some additional data so the AbortNewAccount hook can be used for
347 - # more than just username validation
348 - $user->setEmail( $this->mEmail );
349 - $user->setRealName( $this->mRealName );
350 -
351 - $abortError = '';
352 - if( !wfRunHooks( 'AbortNewAccount', array( $user, &$abortError ) ) ) {
353 - # Hook point to add extra creation throttles and blocks
354 - wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" );
355 - $this->showMainForm( $abortError );
356 - return false;
357 - }
358 -
359 - if( $wgAccountCreationThrottle && $wgUser->isPingLimitable() ) {
360 - $key = wfMemcKey( 'acctcreate', 'ip', $ip );
361 - $value = $wgMemc->get( $key );
362 - if ( !$value ) {
363 - $wgMemc->set( $key, 0, 86400 );
364 - }
365 - if( $value >= $wgAccountCreationThrottle ) {
366 - $this->showMainForm( wfMsgExt( 'acct_creation_throttle_hit', array( 'parseinline' ), $wgAccountCreationThrottle ) );
367 - return false;
368 - }
369 - $wgMemc->incr( $key );
370 - }
371 -
372 - if( !$wgAuth->addUser( $user, $this->mPassword, $this->mEmail, $this->mRealName ) ) {
373 - $this->showMainForm( wfMsg( 'externaldberror' ) );
374 - return false;
375 - }
376 -
377 - $this->mLogin->mUser = $user;
378 - $this->mLogin->initUser( false );
379 - return true;
380 - }
381 -
382 - /**
383 - * Run any hooks registered for logins, then
384 - * display a message welcoming the user.
385 - */
386 - protected function successfulCreation(){
387 - global $wgUser, $wgOut;
388 -
389 - # Run any hooks; display injected HTML
390 - $injected_html = '';
391 - wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
392 -
393 - SpecialUserLogin::displaySuccessfulLogin(
394 - 'welcomecreation',
395 - $injected_html,
396 - $this->mReturnTo,
397 - $this->mReturnToQuery );
398 - }
399 -
400 - /**
401 - * Display a message indicating that account creation from their IP has
402 - * been blocked by a (range)block with 'block account creation' enabled.
403 - * It's likely that this feature will be used for blocking large numbers
404 - * of innocent people, e.g. range blocks on schools. Don't blame it on
405 - * the user. There's a small chance that it really is the user's fault,
406 - * i.e. the username is blocked and they haven't bothered to log out
407 - * before trying to create an account to evade it, but we'll leave that
408 - * to their guilty conscience to figure out...
409 - */
410 - protected function userBlockedMessage() {
411 - global $wgOut, $wgUser;
412 -
413 - $wgOut->setPageTitle( wfMsg( 'cantcreateaccounttitle' ) );
414 - $wgOut->setRobotPolicy( 'noindex,nofollow' );
415 - $wgOut->setArticleRelated( false );
416 -
417 - $ip = wfGetIP();
418 - $blocker = User::whoIs( $wgUser->mBlock->mBy );
419 - $block_reason = $wgUser->mBlock->mReason;
420 -
421 - if( strval( $block_reason ) === '' ) {
422 - $block_reason = wfMsgExt( 'blockednoreason' );
423 - }
424 - $wgOut->addWikiMsg( 'cantcreateaccount-text', $ip, $block_reason, $blocker );
425 - $wgOut->returnToMain( false );
426 - }
427 -
428 - /**
429 - * Show the main input form, with an appropriate error message
430 - * from a previous iteration, if necessary
431 - * @param $msg String HTML of message received previously
432 - * @param $msgtype String type of message, usually 'error'
433 - */
434 - protected function showMainForm( $msg, $msgtype = 'error' ) {
435 - global $wgUser, $wgOut, $wgHiddenPrefs, $wgEnableEmail;
436 - global $wgCookiePrefix, $wgLoginLanguageSelector;
437 - global $wgAuth, $wgEmailConfirmToEdit, $wgCookieExpiration;
438 -
439 - # Parse the error message if we got one
440 - if( $msg ){
441 - if( $msgtype == 'error' ){
442 - $msg = wfMsg( 'loginerror' ) . ' ' . $msg;
443 - }
444 - $msg = Html::rawElement(
445 - 'div',
446 - array( 'class' => $msgtype . 'box' ),
447 - $msg
448 - );
449 - } else {
450 - $msg = '';
451 - }
452 -
453 - # Make sure the returnTo strings don't get lost if the
454 - # user changes language, etc
455 - $linkq = array();
456 - if ( !empty( $this->mReturnTo ) ) {
457 - $linkq['returnto'] = wfUrlencode( $this->mReturnTo );
458 - if ( !empty( $this->mReturnToQuery ) )
459 - $linkq['returntoquery'] = wfUrlencode( $this->mReturnToQuery );
460 - }
461 -
462 - # Pass any language selection on to the mode switch link
463 - if( $wgLoginLanguageSelector && $this->mLanguage )
464 - $linkq['uselang'] = $this->mLanguage;
465 -
466 - $skin = $wgUser->getSkin();
467 - $link = $skin->link(
468 - SpecialPage::getTitleFor( 'Userlogin' ),
469 - wfMsgHtml( 'gotaccountlink' ),
470 - array(),
471 - $linkq );
472 - $link = $wgUser->isLoggedIn()
473 - ? ''
474 - : wfMsgWikiHtml( 'gotaccount', $link );
475 -
476 - # Prepare language selection links as needed
477 - $langSelector = $wgLoginLanguageSelector
478 - ? Html::rawElement(
479 - 'div',
480 - array( 'id' => 'languagelinks' ),
481 - SpecialUserLogin::makeLanguageSelector( $this->getTitle(), $this->mReturnTo ) )
482 - : '';
483 -
484 - # Add a 'send password by email' button if available
485 - $buttons = '';
486 - if( $wgEnableEmail && $wgUser->isLoggedIn() ){
487 - $buttons = Html::element(
488 - 'input',
489 - array(
490 - 'type' => 'submit',
491 - 'name' => 'wpCreateaccountMail',
492 - 'value' => wfMsg( 'createaccountmail' ),
493 - 'id' => 'wpCreateaccountMail',
494 - )
495 - );
496 - }
497 -
498 - # Give authentication and captcha plugins a chance to
499 - # modify the form, by hook or by using $wgAuth
500 - $wgAuth->modifyUITemplate( $this, 'new' );
501 - wfRunHooks( 'UserCreateForm', array( &$this ) );
502 -
503 - # The most likely use of the hook is to enable domains;
504 - # check that now, and add fields if necessary
505 - if( $this->mDomains ){
506 - $this->mFormFields['Domain']['options'] = $this->mDomains;
507 - $this->mFormFields['Domain']['default'] = $this->mDomain;
508 - } else {
509 - unset( $this->mFormFields['Domain'] );
510 - }
511 -
512 - # Or to switch email on or off
513 - if( !$wgEnableEmail || !$this->mUseEmail ){
514 - unset( $this->mFormFields['Email'] );
515 - } else {
516 - if( $wgEmailConfirmToEdit ){
517 - $this->mFormFields['Email']['help-message'] = 'prefs-help-email-required' ;
518 - $this->mFormFields['Email']['required'] = '';
519 - } else {
520 - $this->mFormFields['Email']['help-message'] = 'prefs-help-email';
521 - }
522 - }
523 -
524 - # Or to play with realname
525 - if( in_array( 'realname', $wgHiddenPrefs ) || !$this->mUseRealname ){
526 - unset( $this->mFormFields['Realname'] );
527 - }
528 -
529 - # Or to tweak the 'remember my password' checkbox
530 - if( !($wgCookieExpiration > 0) || !$this->mUseRemember ){
531 - # Remove it altogether
532 - unset( $this->mFormFields['Remember'] );
533 - } elseif( $wgUser->getOption( 'rememberpassword' ) || $this->mRemember ){
534 - # Or check it by default
535 - # FIXME: this doesn't always work?
536 - $this->mFormFields['Remember']['checked'] = '1';
537 - }
538 -
539 - $form = new HTMLForm( $this->mFormFields, '' );
540 - $form->setTitle( $this->getTitle() );
541 - $form->setSubmitText( wfMsg( 'createaccount' ) );
542 - $form->setSubmitId( 'wpCreateaccount' );
543 - $form->suppressReset();
544 - $form->loadData();
545 -
546 - $formContents = ''
547 - . Html::rawElement( 'p', array( 'id' => 'userloginlink' ),
548 - $link )
549 - . $this->mFormHeader
550 - . $langSelector
551 - . $form->getBody()
552 - . $form->getButtons()
553 - . $buttons
554 - . Html::hidden( 'returnto', $this->mReturnTo )
555 - . Html::hidden( 'returntoquery', $this->mReturnToQuery )
556 - ;
557 -
558 - $wgOut->setPageTitle( wfMsg( 'createaccount' ) );
559 - $wgOut->setRobotPolicy( 'noindex,nofollow' );
560 - $wgOut->setArticleRelated( false );
561 - $wgOut->disallowUserJs(); # Stop malicious userscripts sniffing passwords
562 -
563 - $wgOut->addHTML(
564 - Html::rawElement(
565 - 'div',
566 - array( 'id' => 'loginstart' ),
567 - wfMsgExt( 'loginstart', array( 'parseinline' ) )
568 - ) .
569 - $msg .
570 - Html::rawElement(
571 - 'div',
572 - array( 'id' => 'userloginForm' ),
573 - $form->wrapForm( $formContents )
574 - ) .
575 - Html::rawElement(
576 - 'div',
577 - array( 'id' => 'loginend' ),
578 - wfMsgExt( 'loginend', array( 'parseinline' ) )
579 - )
580 - );
581 -
582 - }
583 -
584 - /**
585 - * Check if a session cookie is present.
586 - *
587 - * This will not pick up a cookie set during _this_ request, but is meant
588 - * to ensure that the client is returning the cookie which was set on a
589 - * previous pass through the system.
590 - *
591 - * @private
592 - */
593 - protected function hasSessionCookie() {
594 - global $wgDisableCookieCheck, $wgRequest;
595 - return $wgDisableCookieCheck ? true : $wgRequest->checkSessionCookie();
596 - }
597 -
598 - /**
599 - * Do a redirect back to the same page, so we can check any
600 - * new session cookies.
601 - */
602 - protected function cookieRedirectCheck() {
603 - global $wgOut;
604 -
605 - $query = array( 'wpCookieCheck' => '1' );
606 - if ( $this->mReturnTo ) $query['returnto'] = $this->mReturnTo;
607 - $check = $this->getTitle()->getFullURL( $query );
608 -
609 - return $wgOut->redirect( $check );
610 - }
611 -
612 - /**
613 - * Check the cookies and show errors if they're not enabled.
614 - * @param $type String action being performed
615 - */
616 - protected function onCookieRedirectCheck() {
617 - if ( !$this->hasSessionCookie() ) {
618 - return $this->mainLoginForm( wfMsgExt( 'nocookiesnew', array( 'parseinline' ) ) );
619 - } else {
620 - return SpecialUserLogin::successfulLogin(
621 - 'welcomecreate',
622 - $this->mReturnTo,
623 - $this->mReturnToQuery );
624 - }
625 - }
626 -
627 - /**
628 - * Since the UserCreateForm hook was changed to pass a SpecialPage
629 - * instead of a QuickTemplate derivative, old extensions might
630 - * easily try calling these methods expecing them to exist. Tempting
631 - * though it is to let them have the fatal error, let's at least
632 - * fail gracefully...
633 - * @deprecated
634 - */
635 - public function set(){
636 - wfDeprecated( __METHOD__ );
637 - }
638 - public function addInputItem(){
639 - wfDeprecated( __METHOD__ );
640 - }
641 -}
Index: trunk/phase3/includes/specials/SpecialResetpass.php
@@ -43,6 +43,7 @@
4444 $wgOut->addWikiMsg( 'resetpass_success' );
4545 if( !$wgUser->isLoggedIn() ) {
4646 $data = array(
 47+ 'action' => 'submitlogin',
4748 'wpName' => $this->mUserName,
4849 'wpPassword' => $this->mNewpass,
4950 'returnto' => $wgRequest->getVal( 'returnto' ),
@@ -51,7 +52,7 @@
5253 $data['wpRemember'] = 1;
5354 }
5455 $login = new LoginForm( new FauxRequest( $data, true ) );
55 - $login->attemptLogin();
 56+ $login->execute();
5657 }
5758 $titleObj = Title::newFromText( $wgRequest->getVal( 'returnto' ) );
5859 if ( !$titleObj instanceof Title ) {
Index: trunk/phase3/includes/specials/SpecialUserlogin.php
@@ -1,108 +1,90 @@
22 <?php
33 /**
4 - * SpecialPage for logging users into the wiki
 4+ * @file
55 * @ingroup SpecialPage
66 */
77
8 -class SpecialUserLogin extends SpecialPage {
 8+/**
 9+ * constructor
 10+ */
 11+function wfSpecialUserlogin( $par = '' ) {
 12+ global $wgRequest;
 13+ if( session_id() == '' ) {
 14+ wfSetupSession();
 15+ }
916
10 - var $mUsername, $mPassword, $mReturnTo, $mCookieCheck, $mPosted;
11 - var $mCreateaccount, $mCreateaccountMail, $mMailmypassword;
12 - var $mRemember, $mDomain, $mLanguage;
13 - var $mSkipCookieCheck, $mReturnToQuery;
 17+ $form = new LoginForm( $wgRequest, $par );
 18+ $form->execute();
 19+}
1420
15 - public $mDomains = array();
 21+/**
 22+ * implements Special:Login
 23+ * @ingroup SpecialPage
 24+ */
 25+class LoginForm {
1626
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 - );
 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;
4638
47 - protected $mLogin; # Login object
 39+ var $mName, $mPassword, $mRetype, $mReturnTo, $mCookieCheck, $mPosted;
 40+ var $mAction, $mCreateaccount, $mCreateaccountMail, $mMailmypassword;
 41+ var $mLoginattempt, $mRemember, $mEmail, $mDomain, $mLanguage;
 42+ var $mSkipCookieCheck, $mReturnToQuery;
4843
49 - public function __construct(){
50 - parent::__construct( 'Userlogin' );
51 - }
 44+ private $mExtUser = null;
5245
53 - function execute( $par ) {
54 - global $wgRequest;
55 - $this->loadQuery();
56 - $this->mLogin = new Login();
57 -
58 - # Redirect out for account creation, for B/C
59 - $type = ( $par == 'signup' ) ? $par : $wgRequest->getText( 'type' );
60 - if( $type == 'signup' ){
61 - $sp = new SpecialCreateAccount();
62 - $sp->execute( $par );
63 - return;
64 - }
65 -
66 - if ( !is_null( $this->mCookieCheck ) ) {
67 - $this->onCookieRedirectCheck();
68 - return;
69 - } else if( $this->mPosted ) {
70 - if ( $this->mMailmypassword ) {
71 - return $this->showMailPage();
72 - } else {
73 - return $this->processLogin();
74 - }
75 - } else {
76 - $this->mainLoginForm( '' );
77 - }
78 - }
79 -
8046 /**
81 - * Load member variables from the HTTP request data
82 - * @param $par String the fragment passed to execute()
 47+ * Constructor
 48+ * @param WebRequest $request A WebRequest object passed by reference
8349 */
84 - protected function loadQuery(){
85 - global $wgRequest, $wgAuth, $wgHiddenPrefs, $wgEnableEmail, $wgRedirectOnLogin;
 50+ function LoginForm( &$request, $par = '' ) {
 51+ global $wgAuth, $wgHiddenPrefs, $wgEnableEmail, $wgRedirectOnLogin;
8652
87 - $this->mUsername = $wgRequest->getText( 'wpName' );
88 - $this->mPassword = $wgRequest->getText( 'wpPassword' );
89 - $this->mDomain = $wgRequest->getText( 'wpDomain' );
90 - $this->mLanguage = $wgRequest->getText( 'uselang' );
91 -
92 - $this->mReturnTo = $wgRequest->getVal( 'returnto' );
93 - $this->mReturnToQuery = $wgRequest->getVal( 'returntoquery' );
94 - $this->mCookieCheck = $wgRequest->getVal( 'wpCookieCheck' );
95 -
96 - $this->mMailmypassword = $wgRequest->getCheck( 'wpMailmypassword' )
 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' )
9766 && $wgEnableEmail;
98 - $this->mRemember = $wgRequest->getCheck( 'wpRemember' );
99 - $this->mSkipCookieCheck = $wgRequest->getCheck( 'wpSkipCookieCheck' );
100 - $this->mPosted = $wgRequest->wasPosted();
 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' );
10172
10273 if ( $wgRedirectOnLogin ) {
10374 $this->mReturnTo = $wgRedirectOnLogin;
10475 $this->mReturnToQuery = '';
10576 }
10677
 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+
10789 if( !$wgAuth->validDomain( $this->mDomain ) ) {
10890 $this->mDomain = 'invaliddomain';
10991 }
@@ -116,349 +98,519 @@
11799 }
118100 }
119101
 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+ }
 119+
120120 /**
121 - * Show the main login form
122 - * @param $msg String a message key for a warning/error message
123 - * that may have been generated on a previous iteration
 121+ * @private
124122 */
125 - protected function mainLoginForm( $msg, $msgtype = 'error' ) {
126 - global $wgUser, $wgOut, $wgEnableEmail;
127 - global $wgCookiePrefix, $wgLoginLanguageSelector;
128 - global $wgAuth, $wgCookieExpiration;
 123+ function addNewAccountMailPassword() {
 124+ global $wgOut;
129125
130 - # Preload the name field with something if we can
131 - if ( '' == $this->mUsername ) {
132 - if ( $wgUser->isLoggedIn() ) {
133 - $this->mUsername = $wgUser->getName();
134 - } elseif( isset( $_COOKIE[$wgCookiePrefix.'UserName'] ) ) {
135 - $this->mUsername = $_COOKIE[$wgCookiePrefix.'UserName'];
136 - }
 126+ if ('' == $this->mEmail) {
 127+ $this->mainLoginForm( wfMsg( 'noemail', htmlspecialchars( $this->mName ) ) );
 128+ return;
137129 }
138 - if( $this->mUsername ){
139 - $this->mFormFields['Name']['default'] = $this->mUsername;
140 - $this->mFormFields['Password']['autofocus'] = '1';
 130+
 131+ $u = $this->addNewaccountInternal();
 132+
 133+ if ($u == NULL) {
 134+ return;
 135+ }
 136+
 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() ) );
141151 } else {
142 - $this->mFormFields['Name']['autofocus'] = '1';
 152+ $wgOut->addWikiMsg( 'accmailtext', $u->getName(), $u->getEmail() );
 153+ $wgOut->returnToMain( false );
143154 }
 155+ $u = 0;
 156+ }
144157
145 - # Parse the error message if we got one
146 - if( $msg ){
147 - if( $msgtype == 'error' ){
148 - $msg = wfMsg( 'loginerror' ) . ' ' . $msg;
 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 )
 168+ 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() );
 182+ } else {
 183+ $wgOut->addWikiMsg( 'confirmemail_oncreate' );
149184 }
150 - $msg = Html::rawElement(
151 - 'div',
152 - array( 'class' => $msgtype . 'box' ),
153 - $msg
154 - );
 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+ }
155203 } else {
156 - $msg = '';
 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;
157215 }
 216+ }
158217
159 - # Make sure the returnTo strings don't get lost if the
160 - # user changes language, etc
161 - $linkq = array();
162 - if ( !empty( $this->mReturnTo ) ) {
163 - $linkq['returnto'] = wfUrlencode( $this->mReturnTo );
164 - if ( !empty( $this->mReturnToQuery ) )
165 - $linkq['returntoquery'] = wfUrlencode( $this->mReturnToQuery );
 218+ /**
 219+ * @private
 220+ */
 221+ function addNewAccountInternal() {
 222+ global $wgUser, $wgOut;
 223+ global $wgEnableSorbs, $wgProxyWhitelist;
 224+ global $wgMemc, $wgAccountCreationThrottle;
 225+ global $wgAuth, $wgMinimalPasswordLength;
 226+ global $wgEmailConfirmToEdit;
 227+
 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;
166232 }
167233
168 - # Pass any language selection on to the mode switch link
169 - if( $wgLoginLanguageSelector && $this->mLanguage )
170 - $linkq['uselang'] = $this->mLanguage;
 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+ }
171245
172 - $skin = $wgUser->getSkin();
173 - $link = $skin->link(
174 - SpecialPage::getTitleFor( 'CreateAccount' ),
175 - wfMsgHtml( 'nologinlink' ),
176 - array(),
177 - $linkq );
 246+ if ( wfReadOnly() ) {
 247+ $wgOut->readOnlyPage();
 248+ return false;
 249+ }
178250
179 - # Don't show a "create account" link if the user can't
180 - $link = $wgUser->isAllowed( 'createaccount' ) && !$wgUser->isLoggedIn()
181 - ? wfMsgWikiHtml( 'nologin', $link )
182 - : '';
 251+ # Check permissions
 252+ if ( !$wgUser->isAllowed( 'createaccount' ) ) {
 253+ $this->userNotPrivilegedMessage();
 254+ return false;
 255+ } elseif ( $wgUser->isBlockedFromCreateAccount() ) {
 256+ $this->userBlockedMessage();
 257+ return false;
 258+ }
183259
184 - # Prepare language selection links as needed
185 - $langSelector = $wgLoginLanguageSelector
186 - ? Html::rawElement(
187 - 'div',
188 - array( 'id' => 'languagelinks' ),
189 - self::makeLanguageSelector( $this->getTitle(), $this->mReturnTo ) )
190 - : '';
191 -
192 - # Add a 'mail reset' button if available
193 - $buttons = '';
194 - if( $wgEnableEmail && $wgAuth->allowPasswordChange() ){
195 - $buttons = Html::element(
196 - 'input',
197 - array(
198 - 'type' => 'submit',
199 - 'name' => 'wpMailmypassword',
200 - 'value' => wfMsg( 'mailmypassword' ),
201 - 'id' => 'wpMailmypassword',
202 - )
203 - );
 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;
204266 }
205267
206 - # Give authentication and captcha plugins a chance to
207 - # modify the form, by hook or by using $wgAuth
208 - $wgAuth->modifyUITemplate( $this, 'login' );
209 - wfRunHooks( 'UserLoginForm', array( &$this ) );
210 -
211 - # The most likely use of the hook is to enable domains;
212 - # check that now, and add fields if necessary
213 - if( $this->mDomains ){
214 - $this->mFormFields['Domain']['options'] = $this->mDomains;
215 - $this->mFormFields['Domain']['default'] = $this->mDomain;
216 - } else {
217 - unset( $this->mFormFields['Domain'] );
 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;
218274 }
219 -
220 - # Or to tweak the 'remember my password' checkbox
221 - if( !($wgCookieExpiration > 0) ){
222 - # Remove it altogether
223 - unset( $this->mFormFields['Remember'] );
224 - } elseif( $wgUser->getOption( 'rememberpassword' ) || $this->mRemember ){
225 - # Or check it by default
226 - # FIXME: this doesn't always work?
227 - $this->mFormFields['Remember']['checked'] = '1';
 275+
 276+ if ( 0 != $u->idForName() ) {
 277+ $this->mainLoginForm( wfMsg( 'userexists' ) );
 278+ return false;
228279 }
229 -
230 - $form = new HTMLForm( $this->mFormFields, '' );
231 - $form->setTitle( $this->getTitle() );
232 - $form->setSubmitText( wfMsg( 'login' ) );
233 - $form->setSubmitId( 'wpLoginAttempt' );
234 - $form->suppressReset();
235 - $form->loadData();
236 -
237 - $formContents = ''
238 - . Html::rawElement( 'p', array( 'id' => 'userloginlink' ),
239 - $link )
240 - . Html::rawElement( 'div', array( 'id' => 'userloginprompt' ),
241 - wfMsgExt( 'loginprompt', array( 'parseinline' ) ) )
242 - . $this->mFormHeader
243 - . $langSelector
244 - . $form->getBody()
245 - . $form->getButtons()
246 - . $buttons
247 - . Xml::hidden( 'returnto', $this->mReturnTo )
248 - . Xml::hidden( 'returntoquery', $this->mReturnToQuery )
249 - ;
250280
251 - $wgOut->setPageTitle( wfMsg( 'login' ) );
252 - $wgOut->setRobotPolicy( 'noindex,nofollow' );
253 - $wgOut->setArticleRelated( false );
254 - $wgOut->disallowUserJs(); # Stop malicious userscripts sniffing passwords
 281+ if ( 0 != strcmp( $this->mPassword, $this->mRetype ) ) {
 282+ $this->mainLoginForm( wfMsg( 'badretype' ) );
 283+ return false;
 284+ }
255285
256 - $wgOut->addHTML(
257 - Html::rawElement(
258 - 'div',
259 - array( 'id' => 'loginstart' ),
260 - wfMsgExt( 'loginstart', array( 'parseinline' ) )
261 - ) .
262 - $msg .
263 - Html::rawElement(
264 - 'div',
265 - array( 'id' => 'userloginForm' ),
266 - $form->wrapForm( $formContents )
267 - ) .
268 - Html::rawElement(
269 - 'div',
270 - array( 'id' => 'loginend' ),
271 - wfMsgExt( 'loginend', array( 'parseinline' ) )
272 - )
273 - );
 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+ }
274298
275 - }
 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+ }
276305
 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 );
 343+ }
 344+
277345 /**
278 - * Check if a session cookie is present.
 346+ * Actually add a user to the database.
 347+ * Give it a User object that has been initialised with a name.
279348 *
280 - * This will not pick up a cookie set during _this_ request, but is meant
281 - * to ensure that the client is returning the cookie which was set on a
282 - * previous pass through the system.
283 - *
 349+ * @param $u User object.
 350+ * @param $autocreate boolean -- true if this is an autocreation via auth plugin
 351+ * @return User object.
284352 * @private
285353 */
286 - protected function hasSessionCookie() {
287 - global $wgDisableCookieCheck, $wgRequest;
288 - return $wgDisableCookieCheck ? true : $wgRequest->checkSessionCookie();
289 - }
 354+ function initUser( $u, $autocreate ) {
 355+ global $wgAuth;
290356
291 - /**
292 - * Do a redirect back to the same page, so we can check any
293 - * new session cookies.
294 - */
295 - protected function cookieRedirectCheck() {
296 - global $wgOut;
 357+ $u->addToDatabase();
297358
298 - $query = array( 'wpCookieCheck' => '1');
299 - if ( $this->mReturnTo ) $query['returnto'] = $this->mReturnTo;
300 - $check = $this->getTitle()->getFullURL( $query );
 359+ if ( $wgAuth->allowPasswordChange() ) {
 360+ $u->setPassword( $this->mPassword );
 361+ }
301362
302 - return $wgOut->redirect( $check );
303 - }
 363+ $u->setEmail( $this->mEmail );
 364+ $u->setRealName( $this->mRealName );
 365+ $u->setToken();
304366
305 - /**
306 - * Check the cookies and show errors if they're not enabled.
307 - * @param $type String action being performed
308 - */
309 - protected function onCookieRedirectCheck() {
310 - if ( !$this->hasSessionCookie() ) {
311 - return $this->mainLoginForm( wfMsgExt( 'nocookieslogin', array( 'parseinline' ) ) );
312 - } else {
313 - return self::successfulLogin( 'loginsuccess', $this->mReturnTo, $this->mReturnToQuery );
 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 );
 374+ }
314375 }
 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;
315385 }
316386
317387 /**
318 - * Produce a bar of links which allow the user to select another language
319 - * during login/registration but retain "returnto"
320 - * @param $title Title to use in the link
321 - * @param $returnTo query string to append
322 - * @return String HTML for bar
 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
323395 */
324 - public static function makeLanguageSelector( $title, $returnTo=false ) {
325 - global $wgLang;
 396+ function authenticateUserData() {
 397+ global $wgUser, $wgAuth;
 398+ if ( '' == $this->mName ) {
 399+ return self::NO_NAME;
 400+ }
 401+
 402+ global $wgPasswordAttemptThrottle;
326403
327 - $msg = wfMsgForContent( 'loginlanguagelinks' );
328 - if( $msg != '' && !wfEmptyMsg( 'loginlanguagelinks', $msg ) ) {
329 - $langs = explode( "\n", $msg );
330 - $links = array();
331 - foreach( $langs as $lang ) {
332 - $lang = trim( $lang, '* ' );
333 - $parts = explode( '|', $lang );
334 - if (count($parts) >= 2) {
335 - $links[] = SpecialUserLogin::makeLanguageSelectorLink(
336 - $parts[0], $parts[1], $title, $returnTo );
337 - }
 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;
338418 }
339 - return count( $links ) > 0 ? wfMsgHtml( 'loginlanguagelabel', $wgLang->pipeList( $links ) ) : '';
340 - } else {
341 - return '';
342419 }
343 - }
344420
345 - /**
346 - * Create a language selector link for a particular language
347 - * Links back to this page preserving type and returnto
348 - * @param $text Link text
349 - * @param $lang Language code
350 - * @param $title Title to link to
351 - * @param $returnTo String returnto query
352 - */
353 - public static function makeLanguageSelectorLink( $text, $lang, $title, $returnTo=false ) {
354 - global $wgUser;
355 - $attr = array( 'uselang' => $lang );
356 - if( $returnTo )
357 - $attr['returnto'] = $returnTo;
358 - $skin = $wgUser->getSkin();
359 - return $skin->linkKnown(
360 - $title,
361 - htmlspecialchars( $text ),
362 - array(),
363 - $attr
364 - );
365 - }
 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+ }
366431
367 - /**
368 - * Display a "login successful" page.
369 - * @param $msgname String message key to display
370 - * @param $html String HTML to optionally add
371 - * @param $returnto Title to returnto
372 - * @param $returntoQuery String query string for returnto link
373 - */
374 - public static function displaySuccessfulLogin( $msgname, $injected_html='', $returnto=false, $returntoQuery=false ) {
375 - global $wgOut, $wgUser;
 432+ $this->mExtUser = ExternalUser::newFromName( $this->mName );
376433
377 - $wgOut->setPageTitle( wfMsg( 'loginsuccesstitle' ) );
378 - $wgOut->setRobotPolicy( 'noindex,nofollow' );
379 - $wgOut->setArticleRelated( false );
380 - $wgOut->addWikiMsg( $msgname, $wgUser->getName() );
381 - $wgOut->addHTML( $injected_html );
 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+ }
382440
383 - if ( $returnto ) {
384 - $wgOut->returnToMain( null, $returnto, $this->mReturnToQuery );
 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+ }
385449 } else {
386 - $wgOut->returnToMain( null );
 450+ $u->load();
387451 }
 452+
 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;
 488+ }
 489+ } 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;
 504+ }
 505+ wfRunHooks( 'LoginAuthenticateAudit', array( $u, $this->mPassword, $retval ) );
 506+ return $retval;
388507 }
389508
390509 /**
391 - * Run any hooks registered for logins, then HTTP redirect to
392 - * $this->mReturnTo (or Main Page if that's undefined). Formerly we had a
393 - * nice message here, but that's really not as useful as just being sent to
394 - * wherever you logged in from. It should be clear that the action was
395 - * successful, given the lack of error messages plus the appearance of your
396 - * name in the upper right.
 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
397513 */
398 - public static function successfulLogin( $message, $returnTo='', $returnToQuery='' ) {
399 - global $wgUser, $wgOut;
 514+ function attemptAutoCreate( $user ) {
 515+ global $wgAuth, $wgUser, $wgAutocreatePolicy;
400516
401 - # Run any hooks; display injected HTML if any, else redirect
402 - $injected_html = '';
403 - wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
 517+ if ( $wgUser->isBlockedFromCreateAccount() ) {
 518+ wfDebug( __METHOD__.": user is blocked from account creation\n" );
 519+ return self::CREATE_BLOCKED;
 520+ }
404521
405 - if( $injected_html !== '' ) {
406 - SpecialUserLogin::displaySuccessfulLogin( $message, $injected_html );
 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+ }
407536 } else {
408 - $titleObj = Title::newFromText( $returnTo );
409 - if ( !$titleObj instanceof Title ) {
410 - $titleObj = Title::newMainPage();
 537+ # Old AuthPlugin.
 538+ if ( !$wgAuth->autoCreate() ) {
 539+ return self::NOT_EXISTS;
411540 }
412 - $wgOut->redirect( $titleObj->getFullURL( $returnToQuery ) );
 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+ }
413549 }
 550+
 551+ wfDebug( __METHOD__.": creating account\n" );
 552+ $user = $this->initUser( $user, true );
 553+ return self::SUCCESS;
414554 }
415 -
416555
417 - protected function processLogin(){
 556+ function processLogin() {
418557 global $wgUser, $wgAuth;
419 - $result = $this->mLogin->attemptLogin();
420 - switch ( $result ) {
421 - case Login::SUCCESS:
 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+
422575 if( $this->hasSessionCookie() || $this->mSkipCookieCheck ) {
423 - # Replace the language object to provide user interface in
424 - # correct language immediately on this first page load.
 576+ /* Replace the language object to provide user interface in
 577+ * correct language immediately on this first page load.
 578+ */
425579 global $wgLang, $wgRequest;
426580 $code = $wgRequest->getVal( 'uselang', $wgUser->getOption( 'language' ) );
427581 $wgLang = Language::factory( $code );
428 - return self::successfulLogin( 'loginsuccess', $this->mReturnTo, $this->mReturnToQuery );
 582+ return $this->successfulLogin();
429583 } else {
430 - # Do a redirect check to ensure that the cookies are
431 - # being retained by the user's browser.
432 - return $this->cookieRedirectCheck();
 584+ return $this->cookieRedirectCheck( 'login' );
433585 }
434586 break;
435587
436 - case Login::NO_NAME:
437 - case Login::ILLEGAL:
 588+ case self::NO_NAME:
 589+ case self::ILLEGAL:
438590 $this->mainLoginForm( wfMsg( 'noname' ) );
439591 break;
440 - case Login::WRONG_PLUGIN_PASS:
 592+ case self::WRONG_PLUGIN_PASS:
441593 $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
442594 break;
443 - case Login::NOT_EXISTS:
 595+ case self::NOT_EXISTS:
444596 if( $wgUser->isAllowed( 'createaccount' ) ){
445597 $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $this->mName ) ) );
446598 } else {
447599 $this->mainLoginForm( wfMsg( 'nosuchusershort', htmlspecialchars( $this->mName ) ) );
448600 }
449601 break;
450 - case Login::WRONG_PASS:
 602+ case self::WRONG_PASS:
451603 $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
452604 break;
453 - case Login::EMPTY_PASS:
 605+ case self::EMPTY_PASS:
454606 $this->mainLoginForm( wfMsg( 'wrongpasswordempty' ) );
455607 break;
456 - case Login::RESET_PASS:
 608+ case self::RESET_PASS:
457609 $this->resetLoginForm( wfMsg( 'resetpass_announce' ) );
458610 break;
459 - case Login::CREATE_BLOCKED:
 611+ case self::CREATE_BLOCKED:
460612 $this->userBlockedMessage();
461613 break;
462 - case Login::THROTTLED:
 614+ case self::THROTTLED:
463615 $this->mainLoginForm( wfMsg( 'login-throttled' ) );
464616 break;
465617 default:
@@ -466,11 +618,6 @@
467619 }
468620 }
469621
470 - /**
471 - * 'Shell out' to Special:ResetPass to get the user to
472 - * set a new permanent password from a temporary one.
473 - * @param $error String message
474 - */
475622 function resetLoginForm( $error ) {
476623 global $wgOut;
477624 $wgOut->addHTML( Xml::element('p', array( 'class' => 'error' ), $error ) );
@@ -479,67 +626,438 @@
480627 }
481628
482629 /**
483 - * Attempt to send the user a password-reset mail, and display
484 - * the results (good, bad or ugly).
485 - * @return unknown_type
 630+ * @private
486631 */
487 - protected function showMailPage(){
 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+
 787+ 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) {
488796 global $wgOut;
489 - $result = $this->mLogin->mailPassword();
490797
491 - switch( $result ){
492 - case Login::MAIL_READ_ONLY :
 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() ) {
493852 $wgOut->readOnlyPage();
494853 return;
495 - case Login::MAIL_PASSCHANGE_FORBIDDEN:
496 - $this->mainLoginForm( wfMsg( 'resetpass_forbidden' ) );
 854+ } elseif ( $wgUser->isBlockedFromCreateAccount() ) {
 855+ $this->userBlockedMessage();
497856 return;
498 - case Login::MAIL_BLOCKED:
499 - $this->mainLoginForm( wfMsg( 'blocked-mailpassword' ) );
 857+ } elseif ( count( $permErrors = $titleObj->getUserPermissionsErrors( 'createaccount', $wgUser, true ) )>0 ) {
 858+ $wgOut->showPermissionsErrorPage( $permErrors, 'createaccount' );
500859 return;
501 - case Login::MAIL_PING_THROTTLED:
502 - $wgOut->rateLimited();
503 - return;
504 - case Login::MAIL_PASS_THROTTLED:
505 - global $wgPasswordReminderResendTime;
506 - # Round the time in hours to 3 d.p., in case someone
507 - # is specifying minutes or seconds.
508 - $this->mainLoginForm( wfMsgExt(
509 - 'throttled-mailpassword',
510 - array( 'parsemag' ),
511 - round( $wgPasswordReminderResendTime, 3 )
512 - ) );
513 - return;
514 - case Login::NO_NAME:
515 - $this->mainLoginForm( wfMsg( 'noname' ) );
516 - return;
517 - case Login::NOT_EXISTS:
518 - $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $this->mLogin->mUser->getName() ) ) );
519 - return;
520 - case Login::MAIL_EMPTY_EMAIL:
521 - $this->mainLoginForm( wfMsg( 'noemail', $this->mLogin->mUser->getName() ) );
522 - return;
523 - case Login::MAIL_BAD_IP:
524 - $this->mainLoginForm( wfMsg( 'badipaddress' ) );
525 - return;
526 - case Login::MAIL_ERROR:
527 - $this->mainLoginForm( wfMsg( 'mailerror', $this->mLogin->mMailResult->getMessage() ) );
528 - return;
529 - case Login::SUCCESS:
530 - $this->mainLoginForm( wfMsg( 'passwordsent', $this->mLogin->mUser->getName() ), 'success' );
531 - return;
 860+ }
532861 }
 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 );
 887+ if ( !empty( $this->mReturnToQuery ) )
 888+ $returnto .= '&returntoquery=' .
 889+ wfUrlencode( $this->mReturnToQuery );
 890+ $q .= $returnto;
 891+ $linkq .= $returnto;
 892+ }
 893+
 894+ # Pass any language selection on to the mode switch link
 895+ if( $wgLoginLanguageSelector && $this->mLanguage )
 896+ $linkq .= '&uselang=' . $this->mLanguage;
 897+
 898+ $link = '<a href="' . htmlspecialchars ( $titleObj->getLocalUrl( $linkq ) ) . '">';
 899+ $link .= wfMsgHtml( $linkmsg . 'link' ); # Calling either 'gotaccountlink' or 'nologinlink'
 900+ $link .= '</a>';
 901+
 902+ # 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', '' );
 907+
 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+
 927+ # 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 );
 932+ }
 933+
 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 ) );
 938+ } else {
 939+ wfRunHooks( 'UserLoginForm', array( &$template ) );
 940+ }
 941+
 942+ $wgOut->setPageTitle( wfMsg( 'userlogin' ) );
 943+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
 944+ $wgOut->setArticleRelated( false );
 945+ $wgOut->disallowUserJs(); // just in case...
 946+ $wgOut->addTemplate( $template );
533947 }
534948
535949 /**
536 - * Since the UserLoginForm hook was changed to pass a SpecialPage
537 - * instead of a QuickTemplate derivative, old extensions might
538 - * easily try calling this method expecing it to exist. Tempting
539 - * though it is to let them have the fatal error, let's at least
540 - * fail gracefully...
541 - * @deprecated
 950+ * @private
542951 */
543 - public function set(){
544 - wfDeprecated( __METHOD__ );
 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+ }
545960 }
 961+
 962+ /**
 963+ * Check if a session cookie is present.
 964+ *
 965+ * This will not pick up a cookie set during _this_ request, but is meant
 966+ * to ensure that the client is returning the cookie which was set on a
 967+ * previous pass through the system.
 968+ *
 969+ * @private
 970+ */
 971+ function hasSessionCookie() {
 972+ global $wgDisableCookieCheck, $wgRequest;
 973+ return $wgDisableCookieCheck ? true : $wgRequest->checkSessionCookie();
 974+ }
 975+
 976+ /**
 977+ * @private
 978+ */
 979+ function cookieRedirectCheck( $type ) {
 980+ global $wgOut;
 981+
 982+ $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
 983+ $query = array( 'wpCookieCheck' => $type );
 984+ if ( $this->mReturnTo ) $query['returnto'] = $this->mReturnTo;
 985+ $check = $titleObj->getFullURL( $query );
 986+
 987+ return $wgOut->redirect( $check );
 988+ }
 989+
 990+ /**
 991+ * @private
 992+ */
 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+ }
 1003+ } else {
 1004+ return $this->successfulLogin();
 1005+ }
 1006+ }
 1007+
 1008+ /**
 1009+ * @private
 1010+ */
 1011+ function throttleHit( $limit ) {
 1012+ $this->mainLoginForm( wfMsgExt( 'acct_creation_throttle_hit', array( 'parseinline' ), $limit ) );
 1013+ }
 1014+
 1015+ /**
 1016+ * Produce a bar of links which allow the user to select another language
 1017+ * during login/registration but retain "returnto"
 1018+ *
 1019+ * @return string
 1020+ */
 1021+ function makeLanguageSelector() {
 1022+ global $wgLang;
 1023+
 1024+ $msg = wfMsgForContent( 'loginlanguagelinks' );
 1025+ if( $msg != '' && !wfEmptyMsg( 'loginlanguagelinks', $msg ) ) {
 1026+ $langs = explode( "\n", $msg );
 1027+ $links = array();
 1028+ foreach( $langs as $lang ) {
 1029+ $lang = trim( $lang, '* ' );
 1030+ $parts = explode( '|', $lang );
 1031+ if (count($parts) >= 2) {
 1032+ $links[] = $this->makeLanguageSelectorLink( $parts[0], $parts[1] );
 1033+ }
 1034+ }
 1035+ return count( $links ) > 0 ? wfMsgHtml( 'loginlanguagelabel', $wgLang->pipeList( $links ) ) : '';
 1036+ } else {
 1037+ return '';
 1038+ }
 1039+ }
 1040+
 1041+ /**
 1042+ * Create a language selector link for a particular language
 1043+ * Links back to this page preserving type and returnto
 1044+ *
 1045+ * @param $text Link text
 1046+ * @param $lang Language code
 1047+ */
 1048+ function makeLanguageSelectorLink( $text, $lang ) {
 1049+ global $wgUser;
 1050+ $self = SpecialPage::getTitleFor( 'Userlogin' );
 1051+ $attr = array( 'uselang' => $lang );
 1052+ if( $this->mType == 'signup' )
 1053+ $attr['type'] = 'signup';
 1054+ if( $this->mReturnTo )
 1055+ $attr['returnto'] = $this->mReturnTo;
 1056+ $skin = $wgUser->getSkin();
 1057+ return $skin->linkKnown(
 1058+ $self,
 1059+ htmlspecialchars( $text ),
 1060+ array(),
 1061+ $attr
 1062+ );
 1063+ }
5461064 }
Index: trunk/phase3/includes/AutoLoader.php
@@ -136,8 +136,6 @@
137137 'LinksUpdate' => 'includes/LinksUpdate.php',
138138 'LocalisationCache' => 'includes/LocalisationCache.php',
139139 'LocalisationCache_BulkLoad' => 'includes/LocalisationCache.php',
140 - 'LoginForm' => 'includes/Login.php', # For B/C
141 - 'Login' => 'includes/Login.php',
142140 'LogPage' => 'includes/LogPage.php',
143141 'LogPager' => 'includes/LogEventsList.php',
144142 'LogEventsList' => 'includes/LogEventsList.php',
@@ -493,7 +491,6 @@
494492 'AncientPagesPage' => 'includes/specials/SpecialAncientpages.php',
495493 'BrokenRedirectsPage' => 'includes/specials/SpecialBrokenRedirects.php',
496494 'ContribsPager' => 'includes/specials/SpecialContributions.php',
497 - 'SpecialCreateAccount' => 'includes/specials/SpecialCreateAccount.php',
498495 'DBLockForm' => 'includes/specials/SpecialLockdb.php',
499496 'DBUnlockForm' => 'includes/specials/SpecialUnlockdb.php',
500497 'DeadendPagesPage' => 'includes/specials/SpecialDeadendpages.php',
@@ -514,6 +511,7 @@
515512 'ImportStringSource' => 'includes/Import.php',
516513 'LinkSearchPage' => 'includes/specials/SpecialLinkSearch.php',
517514 'ListredirectsPage' => 'includes/specials/SpecialListredirects.php',
 515+ 'LoginForm' => 'includes/specials/SpecialUserlogin.php',
518516 'LonelyPagesPage' => 'includes/specials/SpecialLonelypages.php',
519517 'LongPagesPage' => 'includes/specials/SpecialLongpages.php',
520518 'MIMEsearchPage' => 'includes/specials/SpecialMIMEsearch.php',
@@ -562,7 +560,6 @@
563561 'UnwatchedpagesPage' => 'includes/specials/SpecialUnwatchedpages.php',
564562 'UploadForm' => 'includes/specials/SpecialUpload.php',
565563 'UploadFormMogile' => 'includes/specials/SpecialUploadMogile.php',
566 - 'SpecialUserLogin' => 'includes/specials/SpecialUserlogin.php',
567564 'UserrightsPage' => 'includes/specials/SpecialUserrights.php',
568565 'UsersPager' => 'includes/specials/SpecialListusers.php',
569566 'WantedCategoriesPage' => 'includes/specials/SpecialWantedcategories.php',
Index: trunk/phase3/includes/templates/Userlogin.php
@@ -0,0 +1,323 @@
 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', null, '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+}
Property changes on: trunk/phase3/includes/templates/Userlogin.php
___________________________________________________________________
Added: svn:eol-style
1325 + native
Added: svn:keywords
2326 + Author Date Id Revision
Index: trunk/phase3/includes/AuthPlugin.php
@@ -62,13 +62,12 @@
6363 /**
6464 * Modify options in the login template.
6565 *
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.
 66+ * @param $template UserLoginTemplate object.
 67+ * @param $type String 'signup' or 'login'.
6968 */
70 - public function modifyUITemplate( &$sp, $type=null ) {
 69+ public function modifyUITemplate( &$template, &$type ) {
7170 # Override this!
72 - $sp->mDomains = false;
 71+ $template->set( 'usedomain', false );
7372 }
7473
7574 /**
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',
 1046+'userlogin' => 'Log in / create account',
10471047 'logout' => 'Log out',
10481048 'userlogout' => 'Log out',
10491049 'notloggedin' => 'Not logged in',
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.',
 600+'userlogin' => 'Name of special page [[Special:UserLogin]] where a user can log in or click to create a user account.',
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.
@@ -604,7 +604,7 @@
605605 {{Identical|Not logged in}}',
606606 'nologin' => 'A message shown in the log in form. $1 is a link to the account creation form, and the text of it is "[[MediaWiki:Nologinlink/{{SUBPAGENAME}}|{{int:nologinlink}}]]".',
607607 'nologinlink' => 'Text of the link to the account creation form. Before that link, the message [[MediaWiki:Nologin/{{SUBPAGENAME}}]] appears.',
608 -'createaccount' => 'The title of Special:CreateAccount, where users can register a new account. Used on Special:SpecialPages, and also on the submit button in the form where you register a new account.',
 608+'createaccount' => 'Used on the submit button in the form where you register a new account.',
609609 'gotaccount' => 'A message shown in the account creation form. $1 is a link to the log in form, and the text of it is "[[MediaWiki:Gotaccountlink/{{SUBPAGENAME}}|{{int:gotaccountlink}}]]".',
610610 'gotaccountlink' => 'Text of the link to the log in form. Before that link, the message [[MediaWiki:Gotaccount/{{SUBPAGENAME}}]] appears.
611611
Property changes on: trunk/phase3/img_auth.php
___________________________________________________________________
Added: svn:mergeinfo
612612 Merged /branches/REL1_15/phase3/img_auth.php:r51646

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r55990* Totally refactor includes/specials/SpecialUserlogin.php:...happy-melon19:00, 7 September 2009
r55991Followup to r55990 - Remove debugging hack :(happy-melon19:07, 7 September 2009
r55994Followup to r55990 - rename method to avoid PHP Strict warningshappy-melon19:20, 7 September 2009
r55997Follow-up to r55990, per comments:...happy-melon19:52, 7 September 2009

Comments

#Comment by Simetrical (talk | contribs)   22:56, 8 September 2009

I don't think there's much point in a branch. maintenance and upload have both shown branch merges can be just as messy to merge. And nobody actually tests branches, so the bugs won't be fixed until it gets merged anyway. And branches are a PITA to maintain.

Status & tagging log