Advertisement
Guest User

Untitled

a guest
May 24th, 2017
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 32.93 KB | None | 0 0
  1. <?php
  2. /**
  3. * @file
  4. * @ingroup SpecialPage
  5. */
  6.  
  7. /**
  8. * constructor
  9. */
  10. function wfSpecialUserlogin( $par = '' ) {
  11. global $wgRequest;
  12. if( session_id() == '' ) {
  13. wfSetupSession();
  14. }
  15.  
  16. $form = new LoginForm( $wgRequest, $par );
  17. $form->execute();
  18. }
  19.  
  20. /**
  21. * implements Special:Login
  22. * @ingroup SpecialPage
  23. */
  24. class LoginForm {
  25.  
  26. const SUCCESS = 0;
  27. const NO_NAME = 1;
  28. const ILLEGAL = 2;
  29. const WRONG_PLUGIN_PASS = 3;
  30. const NOT_EXISTS = 4;
  31. const WRONG_PASS = 5;
  32. const EMPTY_PASS = 6;
  33. const RESET_PASS = 7;
  34. const ABORTED = 8;
  35. const CREATE_BLOCKED = 9;
  36. const THROTTLED = 10;
  37. const USER_BLOCKED = 11;
  38. const NEED_TOKEN = 12;
  39. const WRONG_TOKEN = 13;
  40.  
  41. var $mName, $mPassword, $mRetype, $mReturnTo, $mCookieCheck, $mPosted;
  42. var $mAction, $mCreateaccount, $mCreateaccountMail, $mMailmypassword;
  43. var $mLoginattempt, $mRemember, $mEmail, $mDomain, $mLanguage, $mSkipCookieCheck;
  44. var $mToken;
  45.  
  46. /**
  47. * Constructor
  48. * @param WebRequest $request A WebRequest object passed by reference
  49. */
  50. function LoginForm( &$request, $par = '' ) {
  51. global $wgLang, $wgAllowRealName, $wgEnableEmail;
  52. global $wgAuth, $wgRedirectOnLogin;
  53.  
  54. $this->mType = ( $par == 'signup' ) ? $par : $request->getText( 'type' ); # Check for [[Special:Userlogin/signup]]
  55. $this->mName = $request->getText( 'wpName' );
  56. $this->mPassword = $request->getText( 'wpPassword' );
  57. $this->mRetype = $request->getText( 'wpRetype' );
  58. $this->mDomain = $request->getText( 'wpDomain' );
  59. $this->mReturnTo = $request->getVal( 'returnto' );
  60. $this->mCookieCheck = $request->getVal( 'wpCookieCheck' );
  61. $this->mPosted = $request->wasPosted();
  62. $this->mCreateaccount = $request->getCheck( 'wpCreateaccount' );
  63. $this->mCreateaccountMail = $request->getCheck( 'wpCreateaccountMail' )
  64. && $wgEnableEmail;
  65. $this->mMailmypassword = $request->getCheck( 'wpMailmypassword' )
  66. && $wgEnableEmail;
  67. $this->mLoginattempt = $request->getCheck( 'wpLoginattempt' );
  68. $this->mAction = $request->getVal( 'action' );
  69. $this->mRemember = $request->getCheck( 'wpRemember' );
  70. $this->mLanguage = $request->getText( 'uselang' );
  71. $this->mSkipCookieCheck = $request->getCheck( 'wpSkipCookieCheck' );
  72. $this->mToken = $request->getVal( 'wpLoginToken' );
  73.  
  74. if ( $wgRedirectOnLogin ) {
  75. $this->mReturnTo = $wgRedirectOnLogin;
  76. }
  77.  
  78. if( $wgEnableEmail ) {
  79. $this->mEmail = $request->getText( 'wpEmail' );
  80. } else {
  81. $this->mEmail = '';
  82. }
  83. if( $wgAllowRealName ) {
  84. $this->mRealName = $request->getText( 'wpRealName' );
  85. } else {
  86. $this->mRealName = '';
  87. }
  88.  
  89. if( !$wgAuth->validDomain( $this->mDomain ) ) {
  90. $this->mDomain = 'invaliddomain';
  91. }
  92. $wgAuth->setDomain( $this->mDomain );
  93.  
  94. # When switching accounts, it sucks to get automatically logged out
  95. if( $this->mReturnTo == $wgLang->specialPage( 'Userlogout' ) ) {
  96. $this->mReturnTo = '';
  97. }
  98. }
  99.  
  100. function execute() {
  101. if ( !is_null( $this->mCookieCheck ) ) {
  102. $this->onCookieRedirectCheck( $this->mCookieCheck );
  103. return;
  104. } else if( $this->mPosted ) {
  105. if( $this->mCreateaccount ) {
  106. return $this->addNewAccount();
  107. } else if ( $this->mCreateaccountMail ) {
  108. return $this->addNewAccountMailPassword();
  109. } else if ( $this->mMailmypassword ) {
  110. return $this->mailPassword();
  111. } else if ( ( 'submitlogin' == $this->mAction ) || $this->mLoginattempt ) {
  112. return $this->processLogin();
  113. }
  114. }
  115. $this->mainLoginForm( '' );
  116. }
  117.  
  118. /**
  119. * @private
  120. */
  121. function addNewAccountMailPassword() {
  122. global $wgOut;
  123.  
  124. if ('' == $this->mEmail) {
  125. $this->mainLoginForm( wfMsg( 'noemail', htmlspecialchars( $this->mName ) ) );
  126. return;
  127. }
  128.  
  129. $u = $this->addNewaccountInternal();
  130.  
  131. if ($u == NULL) {
  132. return;
  133. }
  134.  
  135. // Wipe the initial password and mail a temporary one
  136. $u->setPassword( null );
  137. $u->saveSettings();
  138. $result = $this->mailPasswordInternal( $u, false, 'createaccount-title', 'createaccount-text' );
  139.  
  140. wfRunHooks( 'AddNewAccount', array( $u, true ) );
  141. $u->addNewUserLogEntry();
  142.  
  143. $wgOut->setPageTitle( wfMsg( 'accmailtitle' ) );
  144. $wgOut->setRobotPolicy( 'noindex,nofollow' );
  145. $wgOut->setArticleRelated( false );
  146.  
  147. if( WikiError::isError( $result ) ) {
  148. $this->mainLoginForm( wfMsg( 'mailerror', $result->getMessage() ) );
  149. } else {
  150. $wgOut->addWikiMsg( 'accmailtext', $u->getName(), $u->getEmail() );
  151. $wgOut->returnToMain( false );
  152. }
  153. $u = 0;
  154. }
  155.  
  156.  
  157. /**
  158. * @private
  159. */
  160. function addNewAccount() {
  161. global $wgUser, $wgEmailAuthentication;
  162.  
  163. # Create the account and abort if there's a problem doing so
  164. $u = $this->addNewAccountInternal();
  165. if( $u == NULL )
  166. return;
  167.  
  168. # If we showed up language selection links, and one was in use, be
  169. # smart (and sensible) and save that language as the user's preference
  170. global $wgLoginLanguageSelector;
  171. if( $wgLoginLanguageSelector && $this->mLanguage )
  172. $u->setOption( 'language', $this->mLanguage );
  173.  
  174. # Send out an email authentication message if needed
  175. if( $wgEmailAuthentication && User::isValidEmailAddr( $u->getEmail() ) ) {
  176. global $wgOut;
  177. $error = $u->sendConfirmationMail();
  178. if( WikiError::isError( $error ) ) {
  179. $wgOut->addWikiMsg( 'confirmemail_sendfailed', $error->getMessage() );
  180. } else {
  181. $wgOut->addWikiMsg( 'confirmemail_oncreate' );
  182. }
  183. }
  184.  
  185. # Save settings (including confirmation token)
  186. $u->saveSettings();
  187.  
  188. # If not logged in, assume the new account as the current one and set
  189. # session cookies then show a "welcome" message or a "need cookies"
  190. # message as needed
  191. if( $wgUser->isAnon() ) {
  192. $wgUser = $u;
  193. $wgUser->setCookies();
  194. wfRunHooks( 'AddNewAccount', array( $wgUser ) );
  195. $wgUser->addNewUserLogEntry();
  196. if( $this->hasSessionCookie() ) {
  197. return $this->successfulCreation();
  198. } else {
  199. return $this->cookieRedirectCheck( 'new' );
  200. }
  201. } else {
  202. # Confirm that the account was created
  203. global $wgOut;
  204. $self = SpecialPage::getTitleFor( 'Userlogin' );
  205. $wgOut->setPageTitle( wfMsgHtml( 'accountcreated' ) );
  206. $wgOut->setArticleRelated( false );
  207. $wgOut->setRobotPolicy( 'noindex,nofollow' );
  208. $wgOut->addHTML( wfMsgWikiHtml( 'accountcreatedtext', $u->getName() ) );
  209. $wgOut->returnToMain( false, $self );
  210. wfRunHooks( 'AddNewAccount', array( $u ) );
  211. $u->addNewUserLogEntry();
  212. return true;
  213. }
  214. }
  215.  
  216. /**
  217. * @private
  218. */
  219. function addNewAccountInternal() {
  220. global $wgUser, $wgOut;
  221. global $wgEnableSorbs, $wgProxyWhitelist;
  222. global $wgMemc, $wgAccountCreationThrottle;
  223. global $wgAuth, $wgMinimalPasswordLength;
  224. global $wgEmailConfirmToEdit;
  225.  
  226. // If the user passes an invalid domain, something is fishy
  227. if( !$wgAuth->validDomain( $this->mDomain ) ) {
  228. $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
  229. return false;
  230. }
  231.  
  232. // If we are not allowing users to login locally, we should be checking
  233. // to see if the user is actually able to authenticate to the authenti-
  234. // cation server before they create an account (otherwise, they can
  235. // create a local account and login as any domain user). We only need
  236. // to check this for domains that aren't local.
  237. if( 'local' != $this->mDomain && '' != $this->mDomain ) {
  238. if( !$wgAuth->canCreateAccounts() && ( !$wgAuth->userExists( $this->mName ) || !$wgAuth->authenticate( $this->mName, $this->mPassword ) ) ) {
  239. $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
  240. return false;
  241. }
  242. }
  243.  
  244. if ( wfReadOnly() ) {
  245. $wgOut->readOnlyPage();
  246. return false;
  247. }
  248.  
  249. # Check permissions
  250. if ( !$wgUser->isAllowed( 'createaccount' ) ) {
  251. $this->userNotPrivilegedMessage();
  252. return false;
  253. } elseif ( $wgUser->isBlockedFromCreateAccount() ) {
  254. $this->userBlockedMessage();
  255. return false;
  256. }
  257.  
  258. $ip = wfGetIP();
  259. if ( $wgEnableSorbs && !in_array( $ip, $wgProxyWhitelist ) &&
  260. $wgUser->inSorbsBlacklist( $ip ) )
  261. {
  262. $this->mainLoginForm( wfMsg( 'sorbs_create_account_reason' ) . ' (' . htmlspecialchars( $ip ) . ')' );
  263. return;
  264. }
  265.  
  266. # Now create a dummy user ($u) and check if it is valid
  267. $name = trim( $this->mName );
  268. $u = User::newFromName( $name, 'creatable' );
  269. if ( is_null( $u ) ) {
  270. $this->mainLoginForm( wfMsg( 'noname' ) );
  271. return false;
  272. }
  273.  
  274. if ( 0 != $u->idForName() ) {
  275. $this->mainLoginForm( wfMsg( 'userexists' ) );
  276. return false;
  277. }
  278.  
  279. if ( 0 != strcmp( $this->mPassword, $this->mRetype ) ) {
  280. $this->mainLoginForm( wfMsg( 'badretype' ) );
  281. return false;
  282. }
  283.  
  284. # check for minimal password length
  285. if ( !$u->isValidPassword( $this->mPassword ) ) {
  286. if ( !$this->mCreateaccountMail ) {
  287. $this->mainLoginForm( wfMsgExt( 'passwordtooshort', array( 'parsemag' ), $wgMinimalPasswordLength ) );
  288. return false;
  289. } else {
  290. # do not force a password for account creation by email
  291. # set invalid password, it will be replaced later by a random generated password
  292. $this->mPassword = null;
  293. }
  294. }
  295.  
  296. # if you need a confirmed email address to edit, then obviously you
  297. # need an email address.
  298. if ( $wgEmailConfirmToEdit && empty( $this->mEmail ) ) {
  299. $this->mainLoginForm( wfMsg( 'noemailtitle' ) );
  300. return false;
  301. }
  302.  
  303. if( !empty( $this->mEmail ) && !User::isValidEmailAddr( $this->mEmail ) ) {
  304. $this->mainLoginForm( wfMsg( 'invalidemailaddress' ) );
  305. return false;
  306. }
  307.  
  308. # Set some additional data so the AbortNewAccount hook can be used for
  309. # more than just username validation
  310. $u->setEmail( $this->mEmail );
  311. $u->setRealName( $this->mRealName );
  312.  
  313. $abortError = '';
  314. if( !wfRunHooks( 'AbortNewAccount', array( $u, &$abortError ) ) ) {
  315. // Hook point to add extra creation throttles and blocks
  316. wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" );
  317. $this->mainLoginForm( $abortError );
  318. return false;
  319. }
  320.  
  321. if ( $wgAccountCreationThrottle && $wgUser->isPingLimitable() ) {
  322. $key = wfMemcKey( 'acctcreate', 'ip', $ip );
  323. $value = $wgMemc->get( $key );
  324. if ( !$value ) {
  325. $wgMemc->set( $key, 0, 86400 );
  326. }
  327. if ( $value >= $wgAccountCreationThrottle ) {
  328. $this->throttleHit( $wgAccountCreationThrottle );
  329. return false;
  330. }
  331. $wgMemc->incr( $key );
  332. }
  333.  
  334. if( !$wgAuth->addUser( $u, $this->mPassword, $this->mEmail, $this->mRealName ) ) {
  335. $this->mainLoginForm( wfMsg( 'externaldberror' ) );
  336. return false;
  337. }
  338.  
  339. return $this->initUser( $u, false );
  340. }
  341.  
  342. /**
  343. * Actually add a user to the database.
  344. * Give it a User object that has been initialised with a name.
  345. *
  346. * @param $u User object.
  347. * @param $autocreate boolean -- true if this is an autocreation via auth plugin
  348. * @return User object.
  349. * @private
  350. */
  351. function initUser( $u, $autocreate ) {
  352. global $wgAuth;
  353.  
  354. $u->addToDatabase();
  355.  
  356. if ( $wgAuth->allowPasswordChange() ) {
  357. $u->setPassword( $this->mPassword );
  358. }
  359.  
  360. $u->setEmail( $this->mEmail );
  361. $u->setRealName( $this->mRealName );
  362. $u->setToken();
  363.  
  364. $wgAuth->initUser( $u, $autocreate );
  365.  
  366. $u->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 );
  367. $u->saveSettings();
  368.  
  369. # Update user count
  370. $ssUpdate = new SiteStatsUpdate( 0, 0, 0, 0, 1 );
  371. $ssUpdate->doUpdate();
  372.  
  373. return $u;
  374. }
  375.  
  376. /**
  377. * Internally authenticate the login request.
  378. *
  379. * This may create a local account as a side effect if the
  380. * authentication plugin allows transparent local account
  381. * creation.
  382. *
  383. * @public
  384. */
  385. function authenticateUserData() {
  386. global $wgUser, $wgAuth;
  387. if ( '' == $this->mName ) {
  388. return self::NO_NAME;
  389. }
  390.  
  391. // We require a login token to prevent login CSRF
  392. // Handle part of this before incrementing the throttle so
  393. // token-less login attempts don't count towards the throttle
  394. // but wrong-token attempts do.
  395.  
  396. // If the user doesn't have a login token yet, set one.
  397. if ( !self::getLoginToken() ) {
  398. self::setLoginToken();
  399. return self::NEED_TOKEN;
  400. }
  401. // If the user didn't pass a login token, tell them we need one
  402. if ( !$this->mToken ) {
  403. return self::NEED_TOKEN;
  404. }
  405.  
  406. global $wgPasswordAttemptThrottle;
  407.  
  408. $throttleCount=0;
  409. if ( is_array($wgPasswordAttemptThrottle) ) {
  410. $throttleKey = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
  411. $count = $wgPasswordAttemptThrottle['count'];
  412. $period = $wgPasswordAttemptThrottle['seconds'];
  413.  
  414. global $wgMemc;
  415. $throttleCount = $wgMemc->get($throttleKey);
  416. if ( !$throttleCount ) {
  417. $wgMemc->add( $throttleKey, 1, $period ); // start counter
  418. } else if ( $throttleCount < $count ) {
  419. $wgMemc->incr($throttleKey);
  420. } else if ( $throttleCount >= $count ) {
  421. return self::THROTTLED;
  422. }
  423. }
  424.  
  425. // Validate the login token
  426. if ( $this->mToken !== self::getLoginToken() ) {
  427. return self::WRONG_TOKEN;
  428. }
  429.  
  430. // Load $wgUser now, and check to see if we're logging in as the same
  431. // name. This is necessary because loading $wgUser (say by calling
  432. // getName()) calls the UserLoadFromSession hook, which potentially
  433. // creates the user in the database. Until we load $wgUser, checking
  434. // for user existence using User::newFromName($name)->getId() below
  435. // will effectively be using stale data.
  436. if ( $wgUser->getName() === $this->mName ) {
  437. wfDebug( __METHOD__.": already logged in as {$this->mName}\n" );
  438. return self::SUCCESS;
  439. }
  440. $u = User::newFromName( $this->mName );
  441. if( is_null( $u ) || !User::isUsableName( $u->getName() ) ) {
  442. return self::ILLEGAL;
  443. }
  444.  
  445. $isAutoCreated = false;
  446. if ( 0 == $u->getID() ) {
  447. $status = $this->attemptAutoCreate( $u );
  448. if ( $status !== self::SUCCESS ) {
  449. return $status;
  450. } else {
  451. $isAutoCreated = true;
  452. }
  453. } else {
  454. $u->load();
  455. }
  456.  
  457. // Give general extensions, such as a captcha, a chance to abort logins
  458. $abort = self::ABORTED;
  459. if( !wfRunHooks( 'AbortLogin', array( $u, $this->mPassword, &$abort ) ) ) {
  460. return $abort;
  461. }
  462.  
  463. if (!$u->checkPassword( $this->mPassword )) {
  464. if( $u->checkTemporaryPassword( $this->mPassword ) ) {
  465. // The e-mailed temporary password should not be used for actu-
  466. // al logins; that's a very sloppy habit, and insecure if an
  467. // attacker has a few seconds to click "search" on someone's o-
  468. // pen mail reader.
  469. //
  470. // Allow it to be used only to reset the password a single time
  471. // to a new value, which won't be in the user's e-mail ar-
  472. // chives.
  473. //
  474. // For backwards compatibility, we'll still recognize it at the
  475. // login form to minimize surprises for people who have been
  476. // logging in with a temporary password for some time.
  477. //
  478. // As a side-effect, we can authenticate the user's e-mail ad-
  479. // dress if it's not already done, since the temporary password
  480. // was sent via e-mail.
  481. if( !$u->isEmailConfirmed() ) {
  482. $u->confirmEmail();
  483. $u->saveSettings();
  484. }
  485.  
  486. // At this point we just return an appropriate code/ indicating
  487. // that the UI should show a password reset form; bot inter-
  488. // faces etc will probably just fail cleanly here.
  489. $retval = self::RESET_PASS;
  490. } else {
  491. $retval = '' == $this->mPassword ? self::EMPTY_PASS : self::WRONG_PASS;
  492. }
  493. } else {
  494. $wgAuth->updateUser( $u );
  495. $wgUser = $u;
  496.  
  497. // Please reset throttle for successful logins, thanks!
  498. if($throttleCount) {
  499. $wgMemc->delete($throttleKey);
  500. }
  501.  
  502. if ( $isAutoCreated ) {
  503. // Must be run after $wgUser is set, for correct new user log
  504. wfRunHooks( 'AuthPluginAutoCreate', array( $wgUser ) );
  505. }
  506.  
  507. $retval = self::SUCCESS;
  508. }
  509. wfRunHooks( 'LoginAuthenticateAudit', array( $u, $this->mPassword, $retval ) );
  510. return $retval;
  511. }
  512.  
  513. /**
  514. * Attempt to automatically create a user on login. Only succeeds if there
  515. * is an external authentication method which allows it.
  516. * @return integer Status code
  517. */
  518. function attemptAutoCreate( $user ) {
  519. global $wgAuth, $wgUser;
  520. /**
  521. * If the external authentication plugin allows it, automatically cre-
  522. * ate a new account for users that are externally defined but have not
  523. * yet logged in.
  524. */
  525. if ( !$wgAuth->autoCreate() ) {
  526. return self::NOT_EXISTS;
  527. }
  528. if ( !$wgAuth->userExists( $user->getName() ) ) {
  529. wfDebug( __METHOD__.": user does not exist\n" );
  530. return self::NOT_EXISTS;
  531. }
  532. if ( !$wgAuth->authenticate( $user->getName(), $this->mPassword ) ) {
  533. wfDebug( __METHOD__.": \$wgAuth->authenticate() returned false, aborting\n" );
  534. return self::WRONG_PLUGIN_PASS;
  535. }
  536. if ( $wgUser->isBlockedFromCreateAccount() ) {
  537. wfDebug( __METHOD__.": user is blocked from account creation\n" );
  538. return self::CREATE_BLOCKED;
  539. }
  540.  
  541. wfDebug( __METHOD__.": creating account\n" );
  542. $user = $this->initUser( $user, true );
  543. return self::SUCCESS;
  544. }
  545.  
  546. function processLogin() {
  547. global $wgUser, $wgAuth;
  548.  
  549. switch ($this->authenticateUserData())
  550. {
  551. case self::SUCCESS:
  552. # We've verified now, update the real record
  553. if( (bool)$this->mRemember != (bool)$wgUser->getOption( 'rememberpassword' ) ) {
  554. $wgUser->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 );
  555. $wgUser->saveSettings();
  556. } else {
  557. $wgUser->invalidateCache();
  558. }
  559. $wgUser->setCookies();
  560. self::clearLoginToken();
  561.  
  562. // Reset the throttle
  563. $key = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
  564. global $wgMemc;
  565. $wgMemc->delete( $key );
  566.  
  567. if( $this->hasSessionCookie() || $this->mSkipCookieCheck ) {
  568. /* Replace the language object to provide user interface in
  569. * correct language immediately on this first page load.
  570. */
  571. global $wgLang, $wgRequest;
  572. $code = $wgRequest->getVal( 'uselang', $wgUser->getOption( 'language' ) );
  573. $wgLang = Language::factory( $code );
  574. return $this->successfulLogin();
  575. } else {
  576. return $this->cookieRedirectCheck( 'login' );
  577. }
  578. break;
  579.  
  580. case self::NEED_TOKEN:
  581. $this->mainLoginForm( wfMsg( 'sessionfailure' ) . "NEED TOKEN" );
  582. case self::WRONG_TOKEN:
  583. $this->mainLoginForm( wfMsg( 'sessionfailure' ) . "WRONG TOKEN" );
  584. break;
  585. case self::NO_NAME:
  586. case self::ILLEGAL:
  587. $this->mainLoginForm( wfMsg( 'noname' ) );
  588. break;
  589. case self::WRONG_PLUGIN_PASS:
  590. $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
  591. break;
  592. case self::NOT_EXISTS:
  593. if( $wgUser->isAllowed( 'createaccount' ) ){
  594. $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $this->mName ) ) );
  595. } else {
  596. $this->mainLoginForm( wfMsg( 'nosuchusershort', htmlspecialchars( $this->mName ) ) );
  597. }
  598. break;
  599. case self::WRONG_PASS:
  600. $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
  601. break;
  602. case self::EMPTY_PASS:
  603. $this->mainLoginForm( wfMsg( 'wrongpasswordempty' ) );
  604. break;
  605. case self::RESET_PASS:
  606. $this->resetLoginForm( wfMsg( 'resetpass_announce' ) );
  607. break;
  608. case self::CREATE_BLOCKED:
  609. $this->userBlockedMessage();
  610. break;
  611. case self::THROTTLED:
  612. $this->mainLoginForm( wfMsg( 'login-throttled' ) );
  613. break;
  614. default:
  615. throw new MWException( "Unhandled case value" );
  616. }
  617. }
  618.  
  619. function resetLoginForm( $error ) {
  620. global $wgOut;
  621. $wgOut->addHTML( Xml::element('p', array( 'class' => 'error' ), $error ) );
  622. $reset = new SpecialResetpass();
  623. $reset->execute( null );
  624. }
  625.  
  626. /**
  627. * @private
  628. */
  629. function mailPassword() {
  630. global $wgUser, $wgOut, $wgAuth;
  631.  
  632. if ( wfReadOnly() ) {
  633. $wgOut->readOnlyPage();
  634. return false;
  635. }
  636.  
  637. if( !$wgAuth->allowPasswordChange() ) {
  638. $this->mainLoginForm( wfMsg( 'resetpass_forbidden' ) );
  639. return;
  640. }
  641.  
  642. # Check against blocked IPs
  643. # fixme -- should we not?
  644. if( $wgUser->isBlocked() ) {
  645. $this->mainLoginForm( wfMsg( 'blocked-mailpassword' ) );
  646. return;
  647. }
  648.  
  649. # Check against the rate limiter
  650. if( $wgUser->pingLimiter( 'mailpassword' ) ) {
  651. $wgOut->rateLimited();
  652. return;
  653. }
  654.  
  655. if ( '' == $this->mName ) {
  656. $this->mainLoginForm( wfMsg( 'noname' ) );
  657. return;
  658. }
  659. $u = User::newFromName( $this->mName );
  660. if( is_null( $u ) ) {
  661. $this->mainLoginForm( wfMsg( 'noname' ) );
  662. return;
  663. }
  664. if ( 0 == $u->getID() ) {
  665. $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $u->getName() ) ) );
  666. return;
  667. }
  668.  
  669. # Check against password throttle
  670. if ( $u->isPasswordReminderThrottled() ) {
  671. global $wgPasswordReminderResendTime;
  672. # Round the time in hours to 3 d.p., in case someone is specifying
  673. # minutes or seconds.
  674. $this->mainLoginForm( wfMsgExt( 'throttled-mailpassword', array( 'parsemag' ),
  675. round( $wgPasswordReminderResendTime, 3 ) ) );
  676. return;
  677. }
  678.  
  679. $result = $this->mailPasswordInternal( $u, true, 'passwordremindertitle', 'passwordremindertext' );
  680. if( WikiError::isError( $result ) ) {
  681. $this->mainLoginForm( wfMsg( 'mailerror', $result->getMessage() ) );
  682. } else {
  683. $this->mainLoginForm( wfMsg( 'passwordsent', $u->getName() ), 'success' );
  684. }
  685. }
  686.  
  687.  
  688. /**
  689. * @param object user
  690. * @param bool throttle
  691. * @param string message name of email title
  692. * @param string message name of email text
  693. * @return mixed true on success, WikiError on failure
  694. * @private
  695. */
  696. function mailPasswordInternal( $u, $throttle = true, $emailTitle = 'passwordremindertitle', $emailText = 'passwordremindertext' ) {
  697. global $wgServer, $wgScript, $wgUser, $wgNewPasswordExpiry;
  698.  
  699. if ( '' == $u->getEmail() ) {
  700. return new WikiError( wfMsg( 'noemail', $u->getName() ) );
  701. }
  702. $ip = wfGetIP();
  703. if( !$ip ) {
  704. return new WikiError( wfMsg( 'badipaddress' ) );
  705. }
  706.  
  707. wfRunHooks( 'User::mailPasswordInternal', array(&$wgUser, &$ip, &$u) );
  708.  
  709. $np = $u->randomPassword();
  710. $u->setNewpassword( $np, $throttle );
  711. $u->saveSettings();
  712.  
  713. $m = wfMsgExt( $emailText, array( 'parsemag' ), $ip, $u->getName(), $np,
  714. $wgServer . $wgScript, round( $wgNewPasswordExpiry / 86400 ) );
  715. $result = $u->sendMail( wfMsg( $emailTitle ), $m );
  716.  
  717. return $result;
  718. }
  719.  
  720.  
  721. /**
  722. * Run any hooks registered for logins, then HTTP redirect to
  723. * $this->mReturnTo (or Main Page if that's undefined). Formerly we had a
  724. * nice message here, but that's really not as useful as just being sent to
  725. * wherever you logged in from. It should be clear that the action was
  726. * successful, given the lack of error messages plus the appearance of your
  727. * name in the upper right.
  728. *
  729. * @private
  730. */
  731. function successfulLogin() {
  732. global $wgUser, $wgOut;
  733.  
  734. # Run any hooks; display injected HTML if any, else redirect
  735. $injected_html = '';
  736. wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
  737.  
  738. if( $injected_html !== '' ) {
  739. $this->displaySuccessfulLogin( 'loginsuccess', $injected_html );
  740. } else {
  741. $titleObj = Title::newFromText( $this->mReturnTo );
  742. if ( !$titleObj instanceof Title ) {
  743. $titleObj = Title::newMainPage();
  744. }
  745.  
  746. $wgOut->redirect( $titleObj->getFullURL() );
  747. }
  748. }
  749.  
  750. /**
  751. * Run any hooks registered for logins, then display a message welcoming
  752. * the user.
  753. *
  754. * @private
  755. */
  756. function successfulCreation() {
  757. global $wgUser, $wgOut;
  758.  
  759. # Run any hooks; display injected HTML
  760. $injected_html = '';
  761. wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
  762.  
  763. $this->displaySuccessfulLogin( 'welcomecreation', $injected_html );
  764. }
  765.  
  766. /**
  767. * Display a "login successful" page.
  768. */
  769. private function displaySuccessfulLogin( $msgname, $injected_html ) {
  770. global $wgOut, $wgUser;
  771.  
  772. $wgOut->setPageTitle( wfMsg( 'loginsuccesstitle' ) );
  773. $wgOut->setRobotPolicy( 'noindex,nofollow' );
  774. $wgOut->setArticleRelated( false );
  775. $wgOut->addWikiMsg( $msgname, $wgUser->getName() );
  776. $wgOut->addHTML( $injected_html );
  777.  
  778. if ( !empty( $this->mReturnTo ) ) {
  779. $wgOut->returnToMain( null, $this->mReturnTo );
  780. } else {
  781. $wgOut->returnToMain( null );
  782. }
  783. }
  784.  
  785. /** */
  786. function userNotPrivilegedMessage($errors) {
  787. global $wgOut;
  788.  
  789. $wgOut->setPageTitle( wfMsg( 'permissionserrors' ) );
  790. $wgOut->setRobotPolicy( 'noindex,nofollow' );
  791. $wgOut->setArticleRelated( false );
  792.  
  793. $wgOut->addWikitext( $wgOut->formatPermissionsErrorMessage( $errors, 'createaccount' ) );
  794. // Stuff that might want to be added at the end. For example, instruc-
  795. // tions if blocked.
  796. $wgOut->addWikiMsg( 'cantcreateaccount-nonblock-text' );
  797.  
  798. $wgOut->returnToMain( false );
  799. }
  800.  
  801. /** */
  802. function userBlockedMessage() {
  803. global $wgOut, $wgUser;
  804.  
  805. # Let's be nice about this, it's likely that this feature will be used
  806. # for blocking large numbers of innocent people, e.g. range blocks on
  807. # schools. Don't blame it on the user. There's a small chance that it
  808. # really is the user's fault, i.e. the username is blocked and they
  809. # haven't bothered to log out before trying to create an account to
  810. # evade it, but we'll leave that to their guilty conscience to figure
  811. # out.
  812.  
  813. $wgOut->setPageTitle( wfMsg( 'cantcreateaccounttitle' ) );
  814. $wgOut->setRobotPolicy( 'noindex,nofollow' );
  815. $wgOut->setArticleRelated( false );
  816.  
  817. $ip = wfGetIP();
  818. $blocker = User::whoIs( $wgUser->mBlock->mBy );
  819. $block_reason = $wgUser->mBlock->mReason;
  820.  
  821. if ( strval( $block_reason ) === '' ) {
  822. $block_reason = wfMsg( 'blockednoreason' );
  823. }
  824. $wgOut->addWikiMsg( 'cantcreateaccount-text', $ip, $block_reason, $blocker );
  825. $wgOut->returnToMain( false );
  826. }
  827.  
  828. /**
  829. * @private
  830. */
  831. function mainLoginForm( $msg, $msgtype = 'error' ) {
  832. global $wgUser, $wgOut, $wgAllowRealName, $wgEnableEmail;
  833. global $wgCookiePrefix, $wgLoginLanguageSelector;
  834. global $wgAuth, $wgEmailConfirmToEdit, $wgCookieExpiration;
  835.  
  836. $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
  837.  
  838. if ( $this->mType == 'signup' ) {
  839. // Block signup here if in readonly. Keeps user from
  840. // going through the process (filling out data, etc)
  841. // and being informed later.
  842. if ( wfReadOnly() ) {
  843. $wgOut->readOnlyPage();
  844. return;
  845. } elseif ( $wgUser->isBlockedFromCreateAccount() ) {
  846. $this->userBlockedMessage();
  847. return;
  848. } elseif ( count( $permErrors = $titleObj->getUserPermissionsErrors( 'createaccount', $wgUser, true ) )>0 ) {
  849. $wgOut->showPermissionsErrorPage( $permErrors, 'createaccount' );
  850. return;
  851. }
  852. }
  853.  
  854. if ( '' == $this->mName ) {
  855. if ( $wgUser->isLoggedIn() ) {
  856. $this->mName = $wgUser->getName();
  857. } else {
  858. $this->mName = isset( $_COOKIE[$wgCookiePrefix.'UserName'] ) ? $_COOKIE[$wgCookiePrefix.'UserName'] : null;
  859. }
  860. }
  861.  
  862. $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
  863.  
  864. if ( $this->mType == 'signup' ) {
  865. $template = new UsercreateTemplate();
  866. $q = 'action=submitlogin&type=signup';
  867. $linkq = 'type=login';
  868. $linkmsg = 'gotaccount';
  869. } else {
  870. $template = new UserloginTemplate();
  871. $q = 'action=submitlogin&type=login';
  872. $linkq = 'type=signup';
  873. $linkmsg = 'nologin';
  874. }
  875.  
  876. if ( !empty( $this->mReturnTo ) ) {
  877. $returnto = '&returnto=' . wfUrlencode( $this->mReturnTo );
  878. $q .= $returnto;
  879. $linkq .= $returnto;
  880. }
  881.  
  882. # Pass any language selection on to the mode switch link
  883. if( $wgLoginLanguageSelector && $this->mLanguage )
  884. $linkq .= '&uselang=' . $this->mLanguage;
  885.  
  886. $link = '<a href="' . htmlspecialchars ( $titleObj->getLocalUrl( $linkq ) ) . '">';
  887. $link .= wfMsgHtml( $linkmsg . 'link' ); # Calling either 'gotaccountlink' or 'nologinlink'
  888. $link .= '</a>';
  889.  
  890. # Don't show a "create account" link if the user can't
  891. if( $this->showCreateOrLoginLink( $wgUser ) )
  892. $template->set( 'link', wfMsgHtml( $linkmsg, $link ) );
  893. else
  894. $template->set( 'link', '' );
  895.  
  896. $template->set( 'header', '' );
  897. $template->set( 'name', $this->mName );
  898. $template->set( 'password', $this->mPassword );
  899. $template->set( 'retype', $this->mRetype );
  900. $template->set( 'email', $this->mEmail );
  901. $template->set( 'realname', $this->mRealName );
  902. $template->set( 'domain', $this->mDomain );
  903.  
  904. $template->set( 'action', $titleObj->getLocalUrl( $q ) );
  905. $template->set( 'message', $msg );
  906. $template->set( 'messagetype', $msgtype );
  907. $template->set( 'createemail', $wgEnableEmail && $wgUser->isLoggedIn() );
  908. $template->set( 'userealname', $wgAllowRealName );
  909. $template->set( 'useemail', $wgEnableEmail );
  910. $template->set( 'emailrequired', $wgEmailConfirmToEdit );
  911. $template->set( 'canreset', $wgAuth->allowPasswordChange() );
  912. $template->set( 'canremember', ( $wgCookieExpiration > 0 ) );
  913. $template->set( 'remember', $wgUser->getOption( 'rememberpassword' ) or $this->mRemember );
  914.  
  915. if ( !self::getLoginToken() ) {
  916. self::setLoginToken();
  917. }
  918. $template->set( 'token', self::getLoginToken() );
  919.  
  920. # Prepare language selection links as needed
  921. if( $wgLoginLanguageSelector ) {
  922. $template->set( 'languages', $this->makeLanguageSelector() );
  923. if( $this->mLanguage )
  924. $template->set( 'uselang', $this->mLanguage );
  925. }
  926.  
  927. // Give authentication and captcha plugins a chance to modify the form
  928. $wgAuth->modifyUITemplate( $template );
  929. if ( $this->mType == 'signup' ) {
  930. wfRunHooks( 'UserCreateForm', array( &$template ) );
  931. } else {
  932. wfRunHooks( 'UserLoginForm', array( &$template ) );
  933. }
  934.  
  935. $wgOut->setPageTitle( wfMsg( 'userlogin' ) );
  936. $wgOut->setRobotPolicy( 'noindex,nofollow' );
  937. $wgOut->setArticleRelated( false );
  938. $wgOut->disallowUserJs(); // just in case...
  939. $wgOut->addTemplate( $template );
  940. }
  941.  
  942. /**
  943. * @private
  944. */
  945. function showCreateOrLoginLink( &$user ) {
  946. if( $this->mType == 'signup' ) {
  947. return( true );
  948. } elseif( $user->isAllowed( 'createaccount' ) ) {
  949. return( true );
  950. } else {
  951. return( false );
  952. }
  953. }
  954.  
  955. /**
  956. * Check if a session cookie is present.
  957. *
  958. * This will not pick up a cookie set during _this_ request, but is meant
  959. * to ensure that the client is returning the cookie which was set on a
  960. * previous pass through the system.
  961. *
  962. * @private
  963. */
  964. function hasSessionCookie() {
  965. global $wgDisableCookieCheck, $wgRequest;
  966. return $wgDisableCookieCheck ? true : $wgRequest->checkSessionCookie();
  967. }
  968.  
  969. /**
  970. * Get the login token from the current session
  971. */
  972. public static function getLoginToken() {
  973. global $wgRequest;
  974. return $wgRequest->getSessionData( 'wsLoginToken' );
  975. }
  976.  
  977. /**
  978. * Generate a new login token and attach it to the current session
  979. */
  980. public static function setLoginToken() {
  981. global $wgRequest;
  982. // Use User::generateToken() instead of $user->editToken()
  983. // because the latter reuses $_SESSION['wsEditToken']
  984. $wgRequest->setSessionData( 'wsLoginToken', User::generateToken() );
  985. }
  986.  
  987. /**
  988. * Remove any login token attached to the current session
  989. */
  990. public static function clearLoginToken() {
  991. global $wgRequest;
  992. $wgRequest->setSessionData( 'wsLoginToken', null );
  993. }
  994.  
  995. /**
  996. * @private
  997. */
  998. function cookieRedirectCheck( $type ) {
  999. global $wgOut;
  1000.  
  1001. $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
  1002. $query = array( 'wpCookieCheck' => $type );
  1003. if ( $this->mReturnTo ) $query['returnto'] = $this->mReturnTo;
  1004. $check = $titleObj->getFullURL( $query );
  1005.  
  1006. return $wgOut->redirect( $check );
  1007. }
  1008.  
  1009. /**
  1010. * @private
  1011. */
  1012. function onCookieRedirectCheck( $type ) {
  1013. global $wgUser;
  1014.  
  1015. if ( !$this->hasSessionCookie() ) {
  1016. if ( $type == 'new' ) {
  1017. return $this->mainLoginForm( wfMsgExt( 'nocookiesnew', array( 'parseinline' ) ) );
  1018. } else if ( $type == 'login' ) {
  1019. return $this->mainLoginForm( wfMsgExt( 'nocookieslogin', array( 'parseinline' ) ) );
  1020. } else {
  1021. # shouldn't happen
  1022. return $this->mainLoginForm( wfMsg( 'error' ) );
  1023. }
  1024. } else {
  1025. return $this->successfulLogin();
  1026. }
  1027. }
  1028.  
  1029. /**
  1030. * @private
  1031. */
  1032. function throttleHit( $limit ) {
  1033. $this->mainLoginForm( wfMsgExt( 'acct_creation_throttle_hit', array( 'parseinline' ), $limit ) );
  1034. }
  1035.  
  1036. /**
  1037. * Produce a bar of links which allow the user to select another language
  1038. * during login/registration but retain "returnto"
  1039. *
  1040. * @return string
  1041. */
  1042. function makeLanguageSelector() {
  1043. global $wgLang;
  1044.  
  1045. $msg = wfMsgForContent( 'loginlanguagelinks' );
  1046. if( $msg != '' && !wfEmptyMsg( 'loginlanguagelinks', $msg ) ) {
  1047. $langs = explode( "\n", $msg );
  1048. $links = array();
  1049. foreach( $langs as $lang ) {
  1050. $lang = trim( $lang, '* ' );
  1051. $parts = explode( '|', $lang );
  1052. if (count($parts) >= 2) {
  1053. $links[] = $this->makeLanguageSelectorLink( $parts[0], $parts[1] );
  1054. }
  1055. }
  1056. return count( $links ) > 0 ? wfMsgHtml( 'loginlanguagelabel', $wgLang->pipeList( $links ) ) : '';
  1057. } else {
  1058. return '';
  1059. }
  1060. }
  1061.  
  1062. /**
  1063. * Create a language selector link for a particular language
  1064. * Links back to this page preserving type and returnto
  1065. *
  1066. * @param $text Link text
  1067. * @param $lang Language code
  1068. */
  1069. function makeLanguageSelectorLink( $text, $lang ) {
  1070. global $wgUser;
  1071. $self = SpecialPage::getTitleFor( 'Userlogin' );
  1072. $attr[] = 'uselang=' . $lang;
  1073. if( $this->mType == 'signup' )
  1074. $attr[] = 'type=signup';
  1075. if( $this->mReturnTo )
  1076. $attr[] = 'returnto=' . $this->mReturnTo;
  1077. $skin = $wgUser->getSkin();
  1078. return $skin->makeKnownLinkObj( $self, htmlspecialchars( $text ), implode( '&', $attr ) );
  1079. }
  1080. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement