00001 <?php
00010 function wfSpecialUserlogin( $par = '' ) {
00011 global $wgRequest;
00012 if( session_id() == '' ) {
00013 wfSetupSession();
00014 }
00015
00016 $form = new LoginForm( $wgRequest, $par );
00017 $form->execute();
00018 }
00019
00024 class LoginForm {
00025
00026 const SUCCESS = 0;
00027 const NO_NAME = 1;
00028 const ILLEGAL = 2;
00029 const WRONG_PLUGIN_PASS = 3;
00030 const NOT_EXISTS = 4;
00031 const WRONG_PASS = 5;
00032 const EMPTY_PASS = 6;
00033 const RESET_PASS = 7;
00034 const ABORTED = 8;
00035 const CREATE_BLOCKED = 9;
00036 const THROTTLED = 10;
00037 const USER_BLOCKED = 11;
00038 const NEED_TOKEN = 12;
00039 const WRONG_TOKEN = 13;
00040
00041 var $mName, $mPassword, $mRetype, $mReturnTo, $mCookieCheck, $mPosted;
00042 var $mAction, $mCreateaccount, $mCreateaccountMail, $mMailmypassword;
00043 var $mLoginattempt, $mRemember, $mEmail, $mDomain, $mLanguage;
00044 var $mSkipCookieCheck, $mReturnToQuery, $mToken;
00045
00046 private $mExtUser = null;
00047
00053 function LoginForm( &$request, $par = '' ) {
00054 global $wgAuth, $wgHiddenPrefs, $wgEnableEmail, $wgRedirectOnLogin;
00055
00056 $this->mType = ( $par == 'signup' ) ? $par : $request->getText( 'type' ); # Check for [[Special:Userlogin/signup]]
00057 $this->mName = $request->getText( 'wpName' );
00058 $this->mPassword = $request->getText( 'wpPassword' );
00059 $this->mRetype = $request->getText( 'wpRetype' );
00060 $this->mDomain = $request->getText( 'wpDomain' );
00061 $this->mReturnTo = $request->getVal( 'returnto' );
00062 $this->mReturnToQuery = $request->getVal( 'returntoquery' );
00063 $this->mCookieCheck = $request->getVal( 'wpCookieCheck' );
00064 $this->mPosted = $request->wasPosted();
00065 $this->mCreateaccount = $request->getCheck( 'wpCreateaccount' );
00066 $this->mCreateaccountMail = $request->getCheck( 'wpCreateaccountMail' )
00067 && $wgEnableEmail;
00068 $this->mMailmypassword = $request->getCheck( 'wpMailmypassword' )
00069 && $wgEnableEmail;
00070 $this->mLoginattempt = $request->getCheck( 'wpLoginattempt' );
00071 $this->mAction = $request->getVal( 'action' );
00072 $this->mRemember = $request->getCheck( 'wpRemember' );
00073 $this->mLanguage = $request->getText( 'uselang' );
00074 $this->mSkipCookieCheck = $request->getCheck( 'wpSkipCookieCheck' );
00075 $this->mToken = ($this->mType == 'signup' ) ? $request->getVal( 'wpCreateaccountToken' ) : $request->getVal( 'wpLoginToken' );
00076
00077 if ( $wgRedirectOnLogin ) {
00078 $this->mReturnTo = $wgRedirectOnLogin;
00079 $this->mReturnToQuery = '';
00080 }
00081
00082 if( $wgEnableEmail ) {
00083 $this->mEmail = $request->getText( 'wpEmail' );
00084 } else {
00085 $this->mEmail = '';
00086 }
00087 if( !in_array( 'realname', $wgHiddenPrefs ) ) {
00088 $this->mRealName = $request->getText( 'wpRealName' );
00089 } else {
00090 $this->mRealName = '';
00091 }
00092
00093 if( !$wgAuth->validDomain( $this->mDomain ) ) {
00094 $this->mDomain = 'invaliddomain';
00095 }
00096 $wgAuth->setDomain( $this->mDomain );
00097
00098 # When switching accounts, it sucks to get automatically logged out
00099 $returnToTitle = Title::newFromText( $this->mReturnTo );
00100 if( is_object( $returnToTitle ) && $returnToTitle->isSpecial( 'Userlogout' ) ) {
00101 $this->mReturnTo = '';
00102 $this->mReturnToQuery = '';
00103 }
00104 }
00105
00106 function execute() {
00107 if ( !is_null( $this->mCookieCheck ) ) {
00108 $this->onCookieRedirectCheck( $this->mCookieCheck );
00109 return;
00110 } else if( $this->mPosted ) {
00111 if( $this->mCreateaccount ) {
00112 return $this->addNewAccount();
00113 } else if ( $this->mCreateaccountMail ) {
00114 return $this->addNewAccountMailPassword();
00115 } else if ( $this->mMailmypassword ) {
00116 return $this->mailPassword();
00117 } else if ( ( 'submitlogin' == $this->mAction ) || $this->mLoginattempt ) {
00118 return $this->processLogin();
00119 }
00120 }
00121 $this->mainLoginForm( '' );
00122 }
00123
00127 function addNewAccountMailPassword() {
00128 global $wgOut;
00129
00130 if ( $this->mEmail == '' ) {
00131 $this->mainLoginForm( wfMsg( 'noemail', htmlspecialchars( $this->mName ) ) );
00132 return;
00133 }
00134
00135 $u = $this->addNewaccountInternal();
00136
00137 if ($u == null) {
00138 return;
00139 }
00140
00141
00142 $u->setPassword( null );
00143 $u->saveSettings();
00144 $result = $this->mailPasswordInternal( $u, false, 'createaccount-title', 'createaccount-text' );
00145
00146 wfRunHooks( 'AddNewAccount', array( $u, true ) );
00147 $u->addNewUserLogEntry();
00148
00149 $wgOut->setPageTitle( wfMsg( 'accmailtitle' ) );
00150 $wgOut->setRobotPolicy( 'noindex,nofollow' );
00151 $wgOut->setArticleRelated( false );
00152
00153 if( WikiError::isError( $result ) ) {
00154 $this->mainLoginForm( wfMsg( 'mailerror', $result->getMessage() ) );
00155 } else {
00156 $wgOut->addWikiMsg( 'accmailtext', $u->getName(), $u->getEmail() );
00157 $wgOut->returnToMain( false );
00158 }
00159 $u = 0;
00160 }
00161
00162
00166 function addNewAccount() {
00167 global $wgUser, $wgEmailAuthentication;
00168
00169 # Create the account and abort if there's a problem doing so
00170 $u = $this->addNewAccountInternal();
00171 if( $u == null )
00172 return;
00173
00174 # If we showed up language selection links, and one was in use, be
00175 # smart (and sensible) and save that language as the user's preference
00176 global $wgLoginLanguageSelector;
00177 if( $wgLoginLanguageSelector && $this->mLanguage )
00178 $u->setOption( 'language', $this->mLanguage );
00179
00180 # Send out an email authentication message if needed
00181 if( $wgEmailAuthentication && User::isValidEmailAddr( $u->getEmail() ) ) {
00182 global $wgOut;
00183 $error = $u->sendConfirmationMail();
00184 if( WikiError::isError( $error ) ) {
00185 $wgOut->addWikiMsg( 'confirmemail_sendfailed', $error->getMessage() );
00186 } else {
00187 $wgOut->addWikiMsg( 'confirmemail_oncreate' );
00188 }
00189 }
00190
00191 # Save settings (including confirmation token)
00192 $u->saveSettings();
00193
00194 # If not logged in, assume the new account as the current one and set
00195 # session cookies then show a "welcome" message or a "need cookies"
00196 # message as needed
00197 if( $wgUser->isAnon() ) {
00198 $wgUser = $u;
00199 $wgUser->setCookies();
00200 wfRunHooks( 'AddNewAccount', array( $wgUser, false ) );
00201 $wgUser->addNewUserLogEntry();
00202 if( $this->hasSessionCookie() ) {
00203 return $this->successfulCreation();
00204 } else {
00205 return $this->cookieRedirectCheck( 'new' );
00206 }
00207 } else {
00208 # Confirm that the account was created
00209 global $wgOut;
00210 $self = SpecialPage::getTitleFor( 'Userlogin' );
00211 $wgOut->setPageTitle( wfMsgHtml( 'accountcreated' ) );
00212 $wgOut->setArticleRelated( false );
00213 $wgOut->setRobotPolicy( 'noindex,nofollow' );
00214 $wgOut->addHTML( wfMsgWikiHtml( 'accountcreatedtext', $u->getName() ) );
00215 $wgOut->returnToMain( false, $self );
00216 wfRunHooks( 'AddNewAccount', array( $u, false ) );
00217 $u->addNewUserLogEntry();
00218 return true;
00219 }
00220 }
00221
00225 function addNewAccountInternal() {
00226 global $wgUser, $wgOut;
00227 global $wgMemc, $wgAccountCreationThrottle;
00228 global $wgAuth, $wgMinimalPasswordLength;
00229 global $wgEmailConfirmToEdit;
00230
00231
00232 if( !$wgAuth->validDomain( $this->mDomain ) ) {
00233 $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
00234 return false;
00235 }
00236
00237
00238
00239
00240
00241
00242 if( 'local' != $this->mDomain && $this->mDomain != '' ) {
00243 if( !$wgAuth->canCreateAccounts() && ( !$wgAuth->userExists( $this->mName ) || !$wgAuth->authenticate( $this->mName, $this->mPassword ) ) ) {
00244 $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
00245 return false;
00246 }
00247 }
00248
00249 if ( wfReadOnly() ) {
00250 $wgOut->readOnlyPage();
00251 return false;
00252 }
00253
00254 # Request forgery checks.
00255 if ( !self::getCreateaccountToken() ) {
00256 self::setCreateaccountToken();
00257 $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
00258 return false;
00259 }
00260
00261 # The user didn't pass a createaccount token
00262 if ( !$this->mToken ) {
00263 $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
00264 return false;
00265 }
00266
00267 # Validate the createaccount token
00268 if ( $this->mToken !== self::getCreateaccountToken() ) {
00269 $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
00270 return false;
00271 }
00272
00273 # Check permissions
00274 if ( !$wgUser->isAllowed( 'createaccount' ) ) {
00275 $this->userNotPrivilegedMessage();
00276 return false;
00277 } elseif ( $wgUser->isBlockedFromCreateAccount() ) {
00278 $this->userBlockedMessage();
00279 return false;
00280 }
00281
00282 $ip = wfGetIP();
00283 if ( $wgUser->isDnsBlacklisted( $ip, true ) ) {
00284 $this->mainLoginForm( wfMsg( 'sorbs_create_account_reason' ) . ' (' . htmlspecialchars( $ip ) . ')' );
00285 return false;
00286 }
00287
00288 # Now create a dummy user ($u) and check if it is valid
00289 $name = trim( $this->mName );
00290 $u = User::newFromName( $name, 'creatable' );
00291 if ( !is_object( $u ) ) {
00292 $this->mainLoginForm( wfMsg( 'noname' ) );
00293 return false;
00294 }
00295
00296 if ( 0 != $u->idForName() ) {
00297 $this->mainLoginForm( wfMsg( 'userexists' ) );
00298 return false;
00299 }
00300
00301 if ( 0 != strcmp( $this->mPassword, $this->mRetype ) ) {
00302 $this->mainLoginForm( wfMsg( 'badretype' ) );
00303 return false;
00304 }
00305
00306 # check for minimal password length
00307 $valid = $u->getPasswordValidity( $this->mPassword );
00308 if ( $valid !== true ) {
00309 if ( !$this->mCreateaccountMail ) {
00310 $this->mainLoginForm( wfMsgExt( $valid, array( 'parsemag' ), $wgMinimalPasswordLength ) );
00311 return false;
00312 } else {
00313 # do not force a password for account creation by email
00314 # set invalid password, it will be replaced later by a random generated password
00315 $this->mPassword = null;
00316 }
00317 }
00318
00319 # if you need a confirmed email address to edit, then obviously you
00320 # need an email address.
00321 if ( $wgEmailConfirmToEdit && empty( $this->mEmail ) ) {
00322 $this->mainLoginForm( wfMsg( 'noemailtitle' ) );
00323 return false;
00324 }
00325
00326 if( !empty( $this->mEmail ) && !User::isValidEmailAddr( $this->mEmail ) ) {
00327 $this->mainLoginForm( wfMsg( 'invalidemailaddress' ) );
00328 return false;
00329 }
00330
00331 # Set some additional data so the AbortNewAccount hook can be used for
00332 # more than just username validation
00333 $u->setEmail( $this->mEmail );
00334 $u->setRealName( $this->mRealName );
00335
00336 $abortError = '';
00337 if( !wfRunHooks( 'AbortNewAccount', array( $u, &$abortError ) ) ) {
00338
00339 wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" );
00340 $this->mainLoginForm( $abortError );
00341 return false;
00342 }
00343
00344 if ( $wgAccountCreationThrottle && $wgUser->isPingLimitable() ) {
00345 $key = wfMemcKey( 'acctcreate', 'ip', $ip );
00346 $value = $wgMemc->get( $key );
00347 if ( !$value ) {
00348 $wgMemc->set( $key, 0, 86400 );
00349 }
00350 if ( $value >= $wgAccountCreationThrottle ) {
00351 $this->throttleHit( $wgAccountCreationThrottle );
00352 return false;
00353 }
00354 $wgMemc->incr( $key );
00355 }
00356
00357 if( !$wgAuth->addUser( $u, $this->mPassword, $this->mEmail, $this->mRealName ) ) {
00358 $this->mainLoginForm( wfMsg( 'externaldberror' ) );
00359 return false;
00360 }
00361
00362 self::clearCreateaccountToken();
00363 return $this->initUser( $u, false );
00364 }
00365
00375 function initUser( $u, $autocreate ) {
00376 global $wgAuth;
00377
00378 $u->addToDatabase();
00379
00380 if ( $wgAuth->allowPasswordChange() ) {
00381 $u->setPassword( $this->mPassword );
00382 }
00383
00384 $u->setEmail( $this->mEmail );
00385 $u->setRealName( $this->mRealName );
00386 $u->setToken();
00387
00388 $wgAuth->initUser( $u, $autocreate );
00389
00390 if ( $this->mExtUser ) {
00391 $this->mExtUser->linkToLocal( $u->getId() );
00392 $email = $this->mExtUser->getPref( 'emailaddress' );
00393 if ( $email && !$this->mEmail ) {
00394 $u->setEmail( $email );
00395 }
00396 }
00397
00398 $u->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 );
00399 $u->saveSettings();
00400
00401 # Update user count
00402 $ssUpdate = new SiteStatsUpdate( 0, 0, 0, 0, 1 );
00403 $ssUpdate->doUpdate();
00404
00405 return $u;
00406 }
00407
00415 public function authenticateUserData() {
00416 global $wgUser, $wgAuth;
00417 if ( $this->mName == '' ) {
00418 return self::NO_NAME;
00419 }
00420
00421
00422
00423
00424
00425
00426
00427 if ( !self::getLoginToken() ) {
00428 self::setLoginToken();
00429 return self::NEED_TOKEN;
00430 }
00431
00432 if ( !$this->mToken ) {
00433 return self::NEED_TOKEN;
00434 }
00435
00436 global $wgPasswordAttemptThrottle;
00437
00438 $throttleCount = 0;
00439 if ( is_array( $wgPasswordAttemptThrottle ) ) {
00440 $throttleKey = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
00441 $count = $wgPasswordAttemptThrottle['count'];
00442 $period = $wgPasswordAttemptThrottle['seconds'];
00443
00444 global $wgMemc;
00445 $throttleCount = $wgMemc->get( $throttleKey );
00446 if ( !$throttleCount ) {
00447 $wgMemc->add( $throttleKey, 1, $period );
00448 } else if ( $throttleCount < $count ) {
00449 $wgMemc->incr($throttleKey);
00450 } else if ( $throttleCount >= $count ) {
00451 return self::THROTTLED;
00452 }
00453 }
00454
00455
00456 if ( $this->mToken !== self::getLoginToken() ) {
00457 return self::WRONG_TOKEN;
00458 }
00459
00460
00461
00462
00463
00464
00465
00466 if ( $wgUser->getName() === $this->mName ) {
00467 wfDebug( __METHOD__.": already logged in as {$this->mName}\n" );
00468 return self::SUCCESS;
00469 }
00470
00471 $this->mExtUser = ExternalUser::newFromName( $this->mName );
00472
00473 # TODO: Allow some magic here for invalid external names, e.g., let the
00474 # user choose a different wiki name.
00475 $u = User::newFromName( $this->mName );
00476 if( !( $u instanceof User ) || !User::isUsableName( $u->getName() ) ) {
00477 return self::ILLEGAL;
00478 }
00479
00480 $isAutoCreated = false;
00481 if ( 0 == $u->getID() ) {
00482 $status = $this->attemptAutoCreate( $u );
00483 if ( $status !== self::SUCCESS ) {
00484 return $status;
00485 } else {
00486 $isAutoCreated = true;
00487 }
00488 } else {
00489 global $wgExternalAuthType, $wgAutocreatePolicy;
00490 if ( $wgExternalAuthType && $wgAutocreatePolicy != 'never'
00491 && is_object( $this->mExtUser )
00492 && $this->mExtUser->authenticate( $this->mPassword ) ) {
00493 # The external user and local user have the same name and
00494 # password, so we assume they're the same.
00495 $this->mExtUser->linkToLocal( $u->getID() );
00496 }
00497
00498 $u->load();
00499 }
00500
00501
00502 $abort = self::ABORTED;
00503 if( !wfRunHooks( 'AbortLogin', array( $u, $this->mPassword, &$abort ) ) ) {
00504 return $abort;
00505 }
00506
00507 global $wgBlockDisablesLogin;
00508 if (!$u->checkPassword( $this->mPassword )) {
00509 if( $u->checkTemporaryPassword( $this->mPassword ) ) {
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526 if( !$u->isEmailConfirmed() ) {
00527 $u->confirmEmail();
00528 $u->saveSettings();
00529 }
00530
00531
00532
00533
00534 $retval = self::RESET_PASS;
00535 } else {
00536 $retval = ($this->mPassword == '') ? self::EMPTY_PASS : self::WRONG_PASS;
00537 }
00538 } elseif ( $wgBlockDisablesLogin && $u->isBlocked() ) {
00539
00540 $retval = self::USER_BLOCKED;
00541 } else {
00542 $wgAuth->updateUser( $u );
00543 $wgUser = $u;
00544
00545
00546 if($throttleCount) {
00547 $wgMemc->delete($throttleKey);
00548 }
00549
00550 if ( $isAutoCreated ) {
00551
00552 wfRunHooks( 'AuthPluginAutoCreate', array( $wgUser ) );
00553 }
00554
00555 $retval = self::SUCCESS;
00556 }
00557 wfRunHooks( 'LoginAuthenticateAudit', array( $u, $this->mPassword, $retval ) );
00558 return $retval;
00559 }
00560
00566 function attemptAutoCreate( $user ) {
00567 global $wgAuth, $wgUser, $wgAutocreatePolicy;
00568
00569 if ( $wgUser->isBlockedFromCreateAccount() ) {
00570 wfDebug( __METHOD__.": user is blocked from account creation\n" );
00571 return self::CREATE_BLOCKED;
00572 }
00573
00579 if ( $this->mExtUser ) {
00580 # mExtUser is neither null nor false, so use the new ExternalAuth
00581 # system.
00582 if ( $wgAutocreatePolicy == 'never' ) {
00583 return self::NOT_EXISTS;
00584 }
00585 if ( !$this->mExtUser->authenticate( $this->mPassword ) ) {
00586 return self::WRONG_PLUGIN_PASS;
00587 }
00588 } else {
00589 # Old AuthPlugin.
00590 if ( !$wgAuth->autoCreate() ) {
00591 return self::NOT_EXISTS;
00592 }
00593 if ( !$wgAuth->userExists( $user->getName() ) ) {
00594 wfDebug( __METHOD__.": user does not exist\n" );
00595 return self::NOT_EXISTS;
00596 }
00597 if ( !$wgAuth->authenticate( $user->getName(), $this->mPassword ) ) {
00598 wfDebug( __METHOD__.": \$wgAuth->authenticate() returned false, aborting\n" );
00599 return self::WRONG_PLUGIN_PASS;
00600 }
00601 }
00602
00603 wfDebug( __METHOD__.": creating account\n" );
00604 $user = $this->initUser( $user, true );
00605 return self::SUCCESS;
00606 }
00607
00608 function processLogin() {
00609 global $wgUser, $wgAuth;
00610
00611 switch ( $this->authenticateUserData() ) {
00612 case self::SUCCESS:
00613 # We've verified now, update the real record
00614 if( (bool)$this->mRemember != (bool)$wgUser->getOption( 'rememberpassword' ) ) {
00615 $wgUser->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 );
00616 $wgUser->saveSettings();
00617 } else {
00618 $wgUser->invalidateCache();
00619 }
00620 $wgUser->setCookies();
00621 self::clearLoginToken();
00622
00623
00624 $key = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
00625 global $wgMemc;
00626 $wgMemc->delete( $key );
00627
00628 if( $this->hasSessionCookie() || $this->mSkipCookieCheck ) {
00629
00630
00631
00632 global $wgLang, $wgRequest;
00633 $code = $wgRequest->getVal( 'uselang', $wgUser->getOption( 'language' ) );
00634 $wgLang = Language::factory( $code );
00635 return $this->successfulLogin();
00636 } else {
00637 return $this->cookieRedirectCheck( 'login' );
00638 }
00639 break;
00640
00641 case self::NEED_TOKEN:
00642 case self::WRONG_TOKEN:
00643 $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
00644 break;
00645 case self::NO_NAME:
00646 case self::ILLEGAL:
00647 $this->mainLoginForm( wfMsg( 'noname' ) );
00648 break;
00649 case self::WRONG_PLUGIN_PASS:
00650 $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
00651 break;
00652 case self::NOT_EXISTS:
00653 if( $wgUser->isAllowed( 'createaccount' ) ){
00654 $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $this->mName ) ) );
00655 } else {
00656 $this->mainLoginForm( wfMsg( 'nosuchusershort', htmlspecialchars( $this->mName ) ) );
00657 }
00658 break;
00659 case self::WRONG_PASS:
00660 $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
00661 break;
00662 case self::EMPTY_PASS:
00663 $this->mainLoginForm( wfMsg( 'wrongpasswordempty' ) );
00664 break;
00665 case self::RESET_PASS:
00666 $this->resetLoginForm( wfMsg( 'resetpass_announce' ) );
00667 break;
00668 case self::CREATE_BLOCKED:
00669 $this->userBlockedMessage();
00670 break;
00671 case self::THROTTLED:
00672 $this->mainLoginForm( wfMsg( 'login-throttled' ) );
00673 break;
00674 case self::USER_BLOCKED:
00675 $this->mainLoginForm( wfMsgExt( 'login-userblocked',
00676 array( 'parsemag', 'escape' ), $this->mName ) );
00677 break;
00678 default:
00679 throw new MWException( "Unhandled case value" );
00680 }
00681 }
00682
00683 function resetLoginForm( $error ) {
00684 global $wgOut;
00685 $wgOut->addHTML( Xml::element('p', array( 'class' => 'error' ), $error ) );
00686 $reset = new SpecialResetpass();
00687 $reset->execute( null );
00688 }
00689
00693 function mailPassword() {
00694 global $wgUser, $wgOut, $wgAuth;
00695
00696 if ( wfReadOnly() ) {
00697 $wgOut->readOnlyPage();
00698 return false;
00699 }
00700
00701 if( !$wgAuth->allowPasswordChange() ) {
00702 $this->mainLoginForm( wfMsg( 'resetpass_forbidden' ) );
00703 return;
00704 }
00705
00706 # Check against blocked IPs so blocked users can't flood admins
00707 # with password resets
00708 if( $wgUser->isBlocked() ) {
00709 $this->mainLoginForm( wfMsg( 'blocked-mailpassword' ) );
00710 return;
00711 }
00712
00713 # Check for hooks
00714 $error = null;
00715 if ( ! wfRunHooks( 'UserLoginMailPassword', array( $this->mName, &$error ) ) ) {
00716 $this->mainLoginForm( $error );
00717 return;
00718 }
00719
00720 # If the user doesn't have a login token yet, set one.
00721 if ( !self::getLoginToken() ) {
00722 self::setLoginToken();
00723 $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
00724 return;
00725 }
00726
00727 # If the user didn't pass a login token, tell them we need one
00728 if ( !$this->mToken ) {
00729 $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
00730 return;
00731 }
00732
00733 # Check against the rate limiter
00734 if( $wgUser->pingLimiter( 'mailpassword' ) ) {
00735 $wgOut->rateLimited();
00736 return;
00737 }
00738
00739 if ( $this->mName == '' ) {
00740 $this->mainLoginForm( wfMsg( 'noname' ) );
00741 return;
00742 }
00743 $u = User::newFromName( $this->mName );
00744 if( !$u instanceof User ) {
00745 $this->mainLoginForm( wfMsg( 'noname' ) );
00746 return;
00747 }
00748 if ( 0 == $u->getID() ) {
00749 $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $u->getName() ) ) );
00750 return;
00751 }
00752
00753 # Validate the login token
00754 if ( $this->mToken !== self::getLoginToken() ) {
00755 $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
00756 return;
00757 }
00758
00759 # Check against password throttle
00760 if ( $u->isPasswordReminderThrottled() ) {
00761 global $wgPasswordReminderResendTime;
00762 # Round the time in hours to 3 d.p., in case someone is specifying
00763 # minutes or seconds.
00764 $this->mainLoginForm( wfMsgExt( 'throttled-mailpassword', array( 'parsemag' ),
00765 round( $wgPasswordReminderResendTime, 3 ) ) );
00766 return;
00767 }
00768
00769 $result = $this->mailPasswordInternal( $u, true, 'passwordremindertitle', 'passwordremindertext' );
00770 if( WikiError::isError( $result ) ) {
00771 $this->mainLoginForm( wfMsg( 'mailerror', $result->getMessage() ) );
00772 } else {
00773 $this->mainLoginForm( wfMsg( 'passwordsent', $u->getName() ), 'success' );
00774 self::clearLoginToken();
00775 }
00776 }
00777
00778
00787 function mailPasswordInternal( $u, $throttle = true, $emailTitle = 'passwordremindertitle', $emailText = 'passwordremindertext' ) {
00788 global $wgServer, $wgScript, $wgUser, $wgNewPasswordExpiry;
00789
00790 if ( $u->getEmail() == '' ) {
00791 return new WikiError( wfMsg( 'noemail', $u->getName() ) );
00792 }
00793 $ip = wfGetIP();
00794 if( !$ip ) {
00795 return new WikiError( wfMsg( 'badipaddress' ) );
00796 }
00797
00798 wfRunHooks( 'User::mailPasswordInternal', array(&$wgUser, &$ip, &$u) );
00799
00800 $np = $u->randomPassword();
00801 $u->setNewpassword( $np, $throttle );
00802 $u->saveSettings();
00803 $userLanguage = $u->getOption( 'language' );
00804 $m = wfMsgExt( $emailText, array( 'parsemag', 'language' => $userLanguage ), $ip, $u->getName(), $np,
00805 $wgServer . $wgScript, round( $wgNewPasswordExpiry / 86400 ) );
00806 $result = $u->sendMail( wfMsgExt( $emailTitle, array( 'parsemag', 'language' => $userLanguage ) ), $m );
00807
00808 return $result;
00809 }
00810
00811
00822 function successfulLogin() {
00823 global $wgUser, $wgOut;
00824
00825 # Run any hooks; display injected HTML if any, else redirect
00826 $injected_html = '';
00827 wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
00828
00829 if( $injected_html !== '' ) {
00830 $this->displaySuccessfulLogin( 'loginsuccess', $injected_html );
00831 } else {
00832 $titleObj = Title::newFromText( $this->mReturnTo );
00833 if ( !$titleObj instanceof Title ) {
00834 $titleObj = Title::newMainPage();
00835 }
00836 $wgOut->redirect( $titleObj->getFullURL( $this->mReturnToQuery ) );
00837 }
00838 }
00839
00846 function successfulCreation() {
00847 global $wgUser, $wgOut;
00848
00849 # Run any hooks; display injected HTML
00850 $injected_html = '';
00851 wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
00852
00853 $this->displaySuccessfulLogin( 'welcomecreation', $injected_html );
00854 }
00855
00859 private function displaySuccessfulLogin( $msgname, $injected_html ) {
00860 global $wgOut, $wgUser;
00861
00862 $wgOut->setPageTitle( wfMsg( 'loginsuccesstitle' ) );
00863 $wgOut->setRobotPolicy( 'noindex,nofollow' );
00864 $wgOut->setArticleRelated( false );
00865 $wgOut->addWikiMsg( $msgname, $wgUser->getName() );
00866 $wgOut->addHTML( $injected_html );
00867
00868 if ( !empty( $this->mReturnTo ) ) {
00869 $wgOut->returnToMain( null, $this->mReturnTo, $this->mReturnToQuery );
00870 } else {
00871 $wgOut->returnToMain( null );
00872 }
00873 }
00874
00876 function userNotPrivilegedMessage($errors) {
00877 global $wgOut;
00878
00879 $wgOut->setPageTitle( wfMsg( 'permissionserrors' ) );
00880 $wgOut->setRobotPolicy( 'noindex,nofollow' );
00881 $wgOut->setArticleRelated( false );
00882
00883 $wgOut->addWikitext( $wgOut->formatPermissionsErrorMessage( $errors, 'createaccount' ) );
00884
00885
00886 $wgOut->addWikiMsg( 'cantcreateaccount-nonblock-text' );
00887
00888 $wgOut->returnToMain( false );
00889 }
00890
00892 function userBlockedMessage() {
00893 global $wgOut, $wgUser;
00894
00895 # Let's be nice about this, it's likely that this feature will be used
00896 # for blocking large numbers of innocent people, e.g. range blocks on
00897 # schools. Don't blame it on the user. There's a small chance that it
00898 # really is the user's fault, i.e. the username is blocked and they
00899 # haven't bothered to log out before trying to create an account to
00900 # evade it, but we'll leave that to their guilty conscience to figure
00901 # out.
00902
00903 $wgOut->setPageTitle( wfMsg( 'cantcreateaccounttitle' ) );
00904 $wgOut->setRobotPolicy( 'noindex,nofollow' );
00905 $wgOut->setArticleRelated( false );
00906
00907 $ip = wfGetIP();
00908 $blocker = User::whoIs( $wgUser->mBlock->mBy );
00909 $block_reason = $wgUser->mBlock->mReason;
00910
00911 if ( strval( $block_reason ) === '' ) {
00912 $block_reason = wfMsg( 'blockednoreason' );
00913 }
00914 $wgOut->addWikiMsg( 'cantcreateaccount-text', $ip, $block_reason, $blocker );
00915 $wgOut->returnToMain( false );
00916 }
00917
00921 function mainLoginForm( $msg, $msgtype = 'error' ) {
00922 global $wgUser, $wgOut, $wgHiddenPrefs, $wgEnableEmail;
00923 global $wgCookiePrefix, $wgLoginLanguageSelector;
00924 global $wgAuth, $wgEmailConfirmToEdit, $wgCookieExpiration;
00925
00926 $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
00927
00928 if ( $this->mType == 'signup' ) {
00929
00930
00931
00932 if ( wfReadOnly() ) {
00933 $wgOut->readOnlyPage();
00934 return;
00935 } elseif ( $wgUser->isBlockedFromCreateAccount() ) {
00936 $this->userBlockedMessage();
00937 return;
00938 } elseif ( count( $permErrors = $titleObj->getUserPermissionsErrors( 'createaccount', $wgUser, true ) )>0 ) {
00939 $wgOut->showPermissionsErrorPage( $permErrors, 'createaccount' );
00940 return;
00941 }
00942 }
00943
00944 if ( $this->mName == '' ) {
00945 if ( $wgUser->isLoggedIn() ) {
00946 $this->mName = $wgUser->getName();
00947 } else {
00948 $this->mName = isset( $_COOKIE[$wgCookiePrefix.'UserName'] ) ? $_COOKIE[$wgCookiePrefix.'UserName'] : null;
00949 }
00950 }
00951
00952 $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
00953
00954 if ( $this->mType == 'signup' ) {
00955 $template = new UsercreateTemplate();
00956 $q = 'action=submitlogin&type=signup';
00957 $linkq = 'type=login';
00958 $linkmsg = 'gotaccount';
00959 } else {
00960 $template = new UserloginTemplate();
00961 $q = 'action=submitlogin&type=login';
00962 $linkq = 'type=signup';
00963 $linkmsg = 'nologin';
00964 }
00965
00966 if ( !empty( $this->mReturnTo ) ) {
00967 $returnto = '&returnto=' . wfUrlencode( $this->mReturnTo );
00968 if ( !empty( $this->mReturnToQuery ) )
00969 $returnto .= '&returntoquery=' .
00970 wfUrlencode( $this->mReturnToQuery );
00971 $q .= $returnto;
00972 $linkq .= $returnto;
00973 }
00974
00975 # Pass any language selection on to the mode switch link
00976 if( $wgLoginLanguageSelector && $this->mLanguage )
00977 $linkq .= '&uselang=' . $this->mLanguage;
00978
00979 $link = '<a href="' . htmlspecialchars ( $titleObj->getLocalUrl( $linkq ) ) . '">';
00980 $link .= wfMsgHtml( $linkmsg . 'link' ); # Calling either 'gotaccountlink' or 'nologinlink'
00981 $link .= '</a>';
00982
00983 # Don't show a "create account" link if the user can't
00984 if( $this->showCreateOrLoginLink( $wgUser ) )
00985 $template->set( 'link', wfMsgWikiHtml( $linkmsg, $link ) );
00986 else
00987 $template->set( 'link', '' );
00988
00989 $template->set( 'header', '' );
00990 $template->set( 'name', $this->mName );
00991 $template->set( 'password', $this->mPassword );
00992 $template->set( 'retype', $this->mRetype );
00993 $template->set( 'email', $this->mEmail );
00994 $template->set( 'realname', $this->mRealName );
00995 $template->set( 'domain', $this->mDomain );
00996
00997 $template->set( 'action', $titleObj->getLocalUrl( $q ) );
00998 $template->set( 'message', $msg );
00999 $template->set( 'messagetype', $msgtype );
01000 $template->set( 'createemail', $wgEnableEmail && $wgUser->isLoggedIn() );
01001 $template->set( 'userealname', !in_array( 'realname', $wgHiddenPrefs ) );
01002 $template->set( 'useemail', $wgEnableEmail );
01003 $template->set( 'emailrequired', $wgEmailConfirmToEdit );
01004 $template->set( 'canreset', $wgAuth->allowPasswordChange() );
01005 $template->set( 'canremember', ( $wgCookieExpiration > 0 ) );
01006 $template->set( 'remember', $wgUser->getOption( 'rememberpassword' ) or $this->mRemember );
01007
01008 if ( $this->mType == 'signup' ) {
01009 if ( !self::getCreateaccountToken() ) {
01010 self::setCreateaccountToken();
01011 }
01012 $template->set( 'token', self::getCreateaccountToken() );
01013 } else {
01014 if ( !self::getLoginToken() ) {
01015 self::setLoginToken();
01016 }
01017 $template->set( 'token', self::getLoginToken() );
01018 }
01019
01020 # Prepare language selection links as needed
01021 if( $wgLoginLanguageSelector ) {
01022 $template->set( 'languages', $this->makeLanguageSelector() );
01023 if( $this->mLanguage )
01024 $template->set( 'uselang', $this->mLanguage );
01025 }
01026
01027
01028 $wgAuth->modifyUITemplate( $template, $this->mType );
01029 if ( $this->mType == 'signup' ) {
01030 wfRunHooks( 'UserCreateForm', array( &$template ) );
01031 } else {
01032 wfRunHooks( 'UserLoginForm', array( &$template ) );
01033 }
01034
01035
01036 if ( $wgUser->isAllowed( 'createaccount' ) ) {
01037 $wgOut->setPageTitle( wfMsg( 'userlogin' ) );
01038 } else {
01039 $wgOut->setPageTitle( wfMsg( 'userloginnocreate' ) );
01040 }
01041
01042 $wgOut->setRobotPolicy( 'noindex,nofollow' );
01043 $wgOut->setArticleRelated( false );
01044 $wgOut->disallowUserJs();
01045 $wgOut->addTemplate( $template );
01046 }
01047
01051 function showCreateOrLoginLink( &$user ) {
01052 if( $this->mType == 'signup' ) {
01053 return( true );
01054 } elseif( $user->isAllowed( 'createaccount' ) ) {
01055 return( true );
01056 } else {
01057 return( false );
01058 }
01059 }
01060
01070 function hasSessionCookie() {
01071 global $wgDisableCookieCheck, $wgRequest;
01072 return $wgDisableCookieCheck ? true : $wgRequest->checkSessionCookie();
01073 }
01074
01078 public static function getLoginToken() {
01079 global $wgRequest;
01080 return $wgRequest->getSessionData( 'wsLoginToken' );
01081 }
01082
01086 public static function setLoginToken() {
01087 global $wgRequest;
01088
01089
01090 $wgRequest->setSessionData( 'wsLoginToken', User::generateToken() );
01091 }
01092
01096 public static function clearLoginToken() {
01097 global $wgRequest;
01098 $wgRequest->setSessionData( 'wsLoginToken', null );
01099 }
01100
01104 public static function getCreateaccountToken() {
01105 global $wgRequest;
01106 return $wgRequest->getSessionData( 'wsCreateaccountToken' );
01107 }
01108
01112 public static function setCreateaccountToken() {
01113 global $wgRequest;
01114 $wgRequest->setSessionData( 'wsCreateaccountToken', User::generateToken() );
01115 }
01116
01120 public static function clearCreateaccountToken() {
01121 global $wgRequest;
01122 $wgRequest->setSessionData( 'wsCreateaccountToken', null );
01123 }
01124
01128 function cookieRedirectCheck( $type ) {
01129 global $wgOut;
01130
01131 $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
01132 $query = array( 'wpCookieCheck' => $type );
01133 if ( $this->mReturnTo ) $query['returnto'] = $this->mReturnTo;
01134 $check = $titleObj->getFullURL( $query );
01135
01136 return $wgOut->redirect( $check );
01137 }
01138
01142 function onCookieRedirectCheck( $type ) {
01143 if ( !$this->hasSessionCookie() ) {
01144 if ( $type == 'new' ) {
01145 return $this->mainLoginForm( wfMsgExt( 'nocookiesnew', array( 'parseinline' ) ) );
01146 } else if ( $type == 'login' ) {
01147 return $this->mainLoginForm( wfMsgExt( 'nocookieslogin', array( 'parseinline' ) ) );
01148 } else {
01149 # shouldn't happen
01150 return $this->mainLoginForm( wfMsg( 'error' ) );
01151 }
01152 } else {
01153 return $this->successfulLogin();
01154 }
01155 }
01156
01160 function throttleHit( $limit ) {
01161 $this->mainLoginForm( wfMsgExt( 'acct_creation_throttle_hit', array( 'parseinline' ), $limit ) );
01162 }
01163
01170 function makeLanguageSelector() {
01171 global $wgLang;
01172
01173 $msg = wfMsgForContent( 'loginlanguagelinks' );
01174 if( $msg != '' && !wfEmptyMsg( 'loginlanguagelinks', $msg ) ) {
01175 $langs = explode( "\n", $msg );
01176 $links = array();
01177 foreach( $langs as $lang ) {
01178 $lang = trim( $lang, '* ' );
01179 $parts = explode( '|', $lang );
01180 if (count($parts) >= 2) {
01181 $links[] = $this->makeLanguageSelectorLink( $parts[0], $parts[1] );
01182 }
01183 }
01184 return count( $links ) > 0 ? wfMsgHtml( 'loginlanguagelabel', $wgLang->pipeList( $links ) ) : '';
01185 } else {
01186 return '';
01187 }
01188 }
01189
01197 function makeLanguageSelectorLink( $text, $lang ) {
01198 global $wgUser;
01199 $self = SpecialPage::getTitleFor( 'Userlogin' );
01200 $attr = array( 'uselang' => $lang );
01201 if( $this->mType == 'signup' )
01202 $attr['type'] = 'signup';
01203 if( $this->mReturnTo )
01204 $attr['returnto'] = $this->mReturnTo;
01205 $skin = $wgUser->getSkin();
01206 return $skin->linkKnown(
01207 $self,
01208 htmlspecialchars( $text ),
01209 array(),
01210 $attr
01211 );
01212 }
01213 }