MediaWiki  master
SpecialUserlogin.php
Go to the documentation of this file.
1 <?php
24 use Psr\Log\LogLevel;
26 
33  const SUCCESS = 0;
34  const NO_NAME = 1;
35  const ILLEGAL = 2;
36  const WRONG_PLUGIN_PASS = 3;
37  const NOT_EXISTS = 4;
38  const WRONG_PASS = 5;
39  const EMPTY_PASS = 6;
40  const RESET_PASS = 7;
41  const ABORTED = 8;
42  const CREATE_BLOCKED = 9;
43  const THROTTLED = 10;
44  const USER_BLOCKED = 11;
45  const NEED_TOKEN = 12;
46  const WRONG_TOKEN = 13;
47  const USER_MIGRATED = 14;
48 
49  public static $statusCodes = [
50  self::SUCCESS => 'success',
51  self::NO_NAME => 'no_name',
52  self::ILLEGAL => 'illegal',
53  self::WRONG_PLUGIN_PASS => 'wrong_plugin_pass',
54  self::NOT_EXISTS => 'not_exists',
55  self::WRONG_PASS => 'wrong_pass',
56  self::EMPTY_PASS => 'empty_pass',
57  self::RESET_PASS => 'reset_pass',
58  self::ABORTED => 'aborted',
59  self::CREATE_BLOCKED => 'create_blocked',
60  self::THROTTLED => 'throttled',
61  self::USER_BLOCKED => 'user_blocked',
62  self::NEED_TOKEN => 'need_token',
63  self::WRONG_TOKEN => 'wrong_token',
64  self::USER_MIGRATED => 'user_migrated',
65  ];
66 
80  public static $validErrorMessages = [
81  'exception-nologin-text',
82  'watchlistanontext',
83  'changeemail-no-info',
84  'resetpass-no-info',
85  'confirmemail_needlogin',
86  'prefsnologintext2',
87  ];
88 
89  public $mAbortLoginErrorMsg = null;
94  public $mThrottleWait = '?';
95 
96  protected $mUsername;
97  protected $mPassword;
98  protected $mRetype;
99  protected $mReturnTo;
100  protected $mCookieCheck;
101  protected $mPosted;
102  protected $mAction;
103  protected $mCreateaccount;
105  protected $mLoginattempt;
106  protected $mRemember;
107  protected $mEmail;
108  protected $mDomain;
109  protected $mLanguage;
110  protected $mSkipCookieCheck;
111  protected $mReturnToQuery;
112  protected $mToken;
113  protected $mStickHTTPS;
114  protected $mType;
115  protected $mReason;
116  protected $mRealName;
117  protected $mEntryError = '';
118  protected $mEntryErrorType = 'error';
119 
121  private $mLoaded = false;
123 
125  private $mOverrideRequest = null;
126 
128  private $mRequest = null;
129 
133  public function __construct( $request = null ) {
135  parent::__construct( 'Userlogin' );
136 
137  $this->mOverrideRequest = $request;
138  // Override UseMediaWikiEverywhere to true, to force login and create form to use mw ui
139  $wgUseMediaWikiUIEverywhere = true;
140  }
141 
142  public function doesWrites() {
143  return true;
144  }
145 
151  public static function getValidErrorMessages() {
152  static $messages = null;
153  if ( !$messages ) {
154  $messages = self::$validErrorMessages;
155  Hooks::run( 'LoginFormValidErrorMessages', [ &$messages ] );
156  }
157 
158  return $messages;
159  }
160 
164  function load() {
166 
167  if ( $this->mLoaded ) {
168  return;
169  }
170  $this->mLoaded = true;
171 
172  if ( $this->mOverrideRequest === null ) {
173  $request = $this->getRequest();
174  } else {
176  }
177  $this->mRequest = $request;
178 
179  $this->mType = $request->getText( 'type' );
180  $this->mUsername = $request->getText( 'wpName' );
181  $this->mPassword = $request->getText( 'wpPassword' );
182  $this->mRetype = $request->getText( 'wpRetype' );
183  $this->mDomain = $request->getText( 'wpDomain' );
184  $this->mReason = $request->getText( 'wpReason' );
185  $this->mCookieCheck = $request->getVal( 'wpCookieCheck' );
186  $this->mPosted = $request->wasPosted();
187  $this->mCreateaccountMail = $request->getCheck( 'wpCreateaccountMail' )
188  && $wgEnableEmail;
189  $this->mCreateaccount = $request->getCheck( 'wpCreateaccount' ) && !$this->mCreateaccountMail;
190  $this->mLoginattempt = $request->getCheck( 'wpLoginattempt' );
191  $this->mAction = $request->getVal( 'action' );
192  $this->mRemember = $request->getCheck( 'wpRemember' );
193  $this->mFromHTTP = $request->getBool( 'fromhttp', false )
194  || $request->getBool( 'wpFromhttp', false );
195  $this->mStickHTTPS = ( !$this->mFromHTTP && $request->getProtocol() === 'https' )
196  || $request->getBool( 'wpForceHttps', false );
197  $this->mLanguage = $request->getText( 'uselang' );
198  $this->mSkipCookieCheck = $request->getCheck( 'wpSkipCookieCheck' );
199  $this->mToken = $this->mType == 'signup'
200  ? $request->getVal( 'wpCreateaccountToken' )
201  : $request->getVal( 'wpLoginToken' );
202  $this->mReturnTo = $request->getVal( 'returnto', '' );
203  $this->mReturnToQuery = $request->getVal( 'returntoquery', '' );
204 
205  // Show an error or warning passed on from a previous page
206  $entryError = $this->msg( $request->getVal( 'error', '' ) );
207  $entryWarning = $this->msg( $request->getVal( 'warning', '' ) );
208  // bc: provide login link as a parameter for messages where the translation
209  // was not updated
210  $loginreqlink = Linker::linkKnown(
211  $this->getPageTitle(),
212  $this->msg( 'loginreqlink' )->escaped(),
213  [],
214  [
215  'returnto' => $this->mReturnTo,
216  'returntoquery' => $this->mReturnToQuery,
217  'uselang' => $this->mLanguage,
218  'fromhttp' => $this->mFromHTTP ? '1' : '0',
219  ]
220  );
221 
222  // Only show valid error or warning messages.
223  if ( $entryError->exists()
224  && in_array( $entryError->getKey(), self::getValidErrorMessages() )
225  ) {
226  $this->mEntryErrorType = 'error';
227  $this->mEntryError = $entryError->rawParams( $loginreqlink )->parse();
228 
229  } elseif ( $entryWarning->exists()
230  && in_array( $entryWarning->getKey(), self::getValidErrorMessages() )
231  ) {
232  $this->mEntryErrorType = 'warning';
233  $this->mEntryError = $entryWarning->rawParams( $loginreqlink )->parse();
234  }
235 
236  if ( $wgEnableEmail ) {
237  $this->mEmail = $request->getText( 'wpEmail' );
238  } else {
239  $this->mEmail = '';
240  }
241  if ( !in_array( 'realname', $wgHiddenPrefs ) ) {
242  $this->mRealName = $request->getText( 'wpRealName' );
243  } else {
244  $this->mRealName = '';
245  }
246 
247  if ( !$wgAuth->validDomain( $this->mDomain ) ) {
248  $this->mDomain = $wgAuth->getDomain();
249  }
250  $wgAuth->setDomain( $this->mDomain );
251 
252  # 1. When switching accounts, it sucks to get automatically logged out
253  # 2. Do not return to PasswordReset after a successful password change
254  # but goto Wiki start page (Main_Page) instead ( bug 33997 )
255  $returnToTitle = Title::newFromText( $this->mReturnTo );
256  if ( is_object( $returnToTitle )
257  && ( $returnToTitle->isSpecial( 'Userlogout' )
258  || $returnToTitle->isSpecial( 'PasswordReset' ) )
259  ) {
260  $this->mReturnTo = '';
261  $this->mReturnToQuery = '';
262  }
263  }
264 
265  function getDescription() {
266  if ( $this->mType === 'signup' ) {
267  return $this->msg( 'createaccount' )->text();
268  } else {
269  return $this->msg( 'login' )->text();
270  }
271  }
272 
276  public function execute( $subPage ) {
277  // Make sure session is persisted
278  $session = SessionManager::getGlobalSession();
279  $session->persist();
280 
281  $this->load();
282 
283  // Check for [[Special:Userlogin/signup]]. This affects form display and
284  // page title.
285  if ( $subPage == 'signup' ) {
286  $this->mType = 'signup';
287  }
288  $this->setHeaders();
289 
290  // Make sure it's possible to log in
291  if ( $this->mType !== 'signup' && !$session->canSetUser() ) {
292  throw new ErrorPageError(
293  'cannotloginnow-title',
294  'cannotloginnow-text',
295  [
296  $session->getProvider()->describe( RequestContext::getMain()->getLanguage() )
297  ]
298  );
299  }
300 
312  if (
313  $this->mType !== 'signup' &&
314  !$this->mPosted &&
315  $this->getUser()->isLoggedIn() &&
316  ( $this->mReturnTo !== '' || $this->mReturnToQuery !== '' )
317  ) {
318  $this->successfulLogin();
319  }
320 
321  // If logging in and not on HTTPS, either redirect to it or offer a link.
323  if ( $this->mRequest->getProtocol() !== 'https' ) {
324  $title = $this->getFullTitle();
325  $query = [
326  'returnto' => $this->mReturnTo !== '' ? $this->mReturnTo : null,
327  'returntoquery' => $this->mReturnToQuery !== '' ?
328  $this->mReturnToQuery : null,
329  'title' => null,
330  ( $this->mEntryErrorType === 'error' ? 'error' : 'warning' ) => $this->mEntryError,
331  ] + $this->mRequest->getQueryValues();
332  $url = $title->getFullURL( $query, false, PROTO_HTTPS );
333  if ( $wgSecureLogin
334  && wfCanIPUseHTTPS( $this->getRequest()->getIP() )
335  && !$this->mFromHTTP ) // Avoid infinite redirect
336  {
337  $url = wfAppendQuery( $url, 'fromhttp=1' );
338  $this->getOutput()->redirect( $url );
339  // Since we only do this redir to change proto, always vary
340  $this->getOutput()->addVaryHeader( 'X-Forwarded-Proto' );
341 
342  return;
343  } else {
344  // A wiki without HTTPS login support should set $wgServer to
345  // http://somehost, in which case the secure URL generated
346  // above won't actually start with https://
347  if ( substr( $url, 0, 8 ) === 'https://' ) {
348  $this->mSecureLoginUrl = $url;
349  }
350  }
351  }
352 
353  if ( !is_null( $this->mCookieCheck ) ) {
354  $this->onCookieRedirectCheck( $this->mCookieCheck );
355 
356  return;
357  } elseif ( $this->mPosted ) {
358  if ( $this->mCreateaccount ) {
359  $this->addNewAccount();
360 
361  return;
362  } elseif ( $this->mCreateaccountMail ) {
363  $this->addNewAccountMailPassword();
364 
365  return;
366  } elseif ( ( 'submitlogin' == $this->mAction ) || $this->mLoginattempt ) {
367  $this->processLogin();
368 
369  return;
370  }
371  }
372  $this->mainLoginForm( $this->mEntryError, $this->mEntryErrorType );
373  }
374 
379  if ( $this->mEmail == '' ) {
380  $this->mainLoginForm( $this->msg( 'noemailcreate' )->escaped() );
381 
382  return;
383  }
384 
385  $status = $this->addNewAccountInternal();
386  LoggerFactory::getInstance( 'authmanager' )->info(
387  'Account creation attempt with mailed password',
388  [ 'event' => 'accountcreation', 'status' => $status ]
389  );
390  if ( !$status->isGood() ) {
391  $error = $status->getMessage();
392  $this->mainLoginForm( $error->toString() );
393 
394  return;
395  }
396 
398  $u = $status->getValue();
399 
400  // Wipe the initial password and mail a temporary one
401  $u->setPassword( null );
402  $u->saveSettings();
403  $result = $this->mailPasswordInternal( $u, false, 'createaccount-title', 'createaccount-text' );
404 
405  Hooks::run( 'AddNewAccount', [ $u, true ] );
406  $u->addNewUserLogEntry( 'byemail', $this->mReason );
407 
408  $out = $this->getOutput();
409  $out->setPageTitle( $this->msg( 'accmailtitle' ) );
410 
411  if ( !$result->isGood() ) {
412  $this->mainLoginForm( $this->msg( 'mailerror', $result->getWikiText() )->text() );
413  } else {
414  $out->addWikiMsg( 'accmailtext', $u->getName(), $u->getEmail() );
415  $this->executeReturnTo( 'success' );
416  }
417  }
418 
423  function addNewAccount() {
425 
426  # Create the account and abort if there's a problem doing so
427  $status = $this->addNewAccountInternal();
428  LoggerFactory::getInstance( 'authmanager' )->info( 'Account creation attempt', [
429  'event' => 'accountcreation',
430  'status' => $status,
431  ] );
432 
433  if ( !$status->isGood() ) {
434  $error = $status->getMessage();
435  $this->mainLoginForm( $error->toString() );
436 
437  return false;
438  }
439 
440  $u = $status->getValue();
441 
442  # Only save preferences if the user is not creating an account for someone else.
443  if ( $this->getUser()->isAnon() ) {
444  # If we showed up language selection links, and one was in use, be
445  # smart (and sensible) and save that language as the user's preference
446  if ( $wgLoginLanguageSelector && $this->mLanguage ) {
447  $u->setOption( 'language', $this->mLanguage );
448  } else {
449 
450  # Otherwise the user's language preference defaults to $wgContLang,
451  # but it may be better to set it to their preferred $wgContLang variant,
452  # based on browser preferences or URL parameters.
453  $u->setOption( 'language', $wgContLang->getPreferredVariant() );
454  }
455  if ( $wgContLang->hasVariants() ) {
456  $u->setOption( 'variant', $wgContLang->getPreferredVariant() );
457  }
458  }
459 
460  $out = $this->getOutput();
461 
462  # Send out an email authentication message if needed
463  if ( $wgEmailAuthentication && Sanitizer::validateEmail( $u->getEmail() ) ) {
464  $status = $u->sendConfirmationMail();
465  if ( $status->isGood() ) {
466  $out->addWikiMsg( 'confirmemail_oncreate' );
467  } else {
468  $out->addWikiText( $status->getWikiText( 'confirmemail_sendfailed' ) );
469  }
470  }
471 
472  # Save settings (including confirmation token)
473  $u->saveSettings();
474 
475  # If not logged in, assume the new account as the current one and set
476  # session cookies then show a "welcome" message or a "need cookies"
477  # message as needed
478  if ( $this->getUser()->isAnon() ) {
479  $u->setCookies();
480  $wgUser = $u;
481  // This should set it for OutputPage and the Skin
482  // which is needed or the personal links will be
483  // wrong.
484  $this->getContext()->setUser( $u );
485  Hooks::run( 'AddNewAccount', [ $u, false ] );
486  $u->addNewUserLogEntry( 'create' );
487  if ( $this->hasSessionCookie() ) {
488  $this->successfulCreation();
489  } else {
490  $this->cookieRedirectCheck( 'new' );
491  }
492  } else {
493  # Confirm that the account was created
494  $out->setPageTitle( $this->msg( 'accountcreated' ) );
495  $out->addWikiMsg( 'accountcreatedtext', $u->getName() );
496  $out->addReturnTo( $this->getPageTitle() );
497  Hooks::run( 'AddNewAccount', [ $u, false ] );
498  $u->addNewUserLogEntry( 'create2', $this->mReason );
499  }
500 
501  return true;
502  }
503 
510  public function addNewAccountInternal() {
512 
513  // If the user passes an invalid domain, something is fishy
514  if ( !$wgAuth->validDomain( $this->mDomain ) ) {
515  return Status::newFatal( 'wrongpassword' );
516  }
517 
518  // If we are not allowing users to login locally, we should be checking
519  // to see if the user is actually able to authenticate to the authenti-
520  // cation server before they create an account (otherwise, they can
521  // create a local account and login as any domain user). We only need
522  // to check this for domains that aren't local.
523  if ( 'local' != $this->mDomain && $this->mDomain != '' ) {
524  if (
525  !$wgAuth->canCreateAccounts() &&
526  (
527  !$wgAuth->userExists( $this->mUsername ) ||
528  !$wgAuth->authenticate( $this->mUsername, $this->mPassword )
529  )
530  ) {
531  return Status::newFatal( 'wrongpassword' );
532  }
533  }
534 
535  if ( wfReadOnly() ) {
536  throw new ReadOnlyError;
537  }
538 
539  # Request forgery checks.
540  $token = self::getCreateaccountToken();
541  if ( $token->wasNew() ) {
542  return Status::newFatal( 'nocookiesfornew' );
543  }
544 
545  # The user didn't pass a createaccount token
546  if ( !$this->mToken ) {
547  return Status::newFatal( 'sessionfailure' );
548  }
549 
550  # Validate the createaccount token
551  if ( !$token->match( $this->mToken ) ) {
552  return Status::newFatal( 'sessionfailure' );
553  }
554 
555  # Check permissions
556  $currentUser = $this->getUser();
557  $creationBlock = $currentUser->isBlockedFromCreateAccount();
558  if ( !$currentUser->isAllowed( 'createaccount' ) ) {
559  throw new PermissionsError( 'createaccount' );
560  } elseif ( $creationBlock instanceof Block ) {
561  // Throws an ErrorPageError.
562  $this->userBlockedMessage( $creationBlock );
563 
564  // This should never be reached.
565  return false;
566  }
567 
568  # Include checks that will include GlobalBlocking (Bug 38333)
569  $permErrors = $this->getPageTitle()->getUserPermissionsErrors(
570  'createaccount',
571  $currentUser,
572  true
573  );
574 
575  if ( count( $permErrors ) ) {
576  throw new PermissionsError( 'createaccount', $permErrors );
577  }
578 
579  $ip = $this->getRequest()->getIP();
580  if ( $currentUser->isDnsBlacklisted( $ip, true /* check $wgProxyWhitelist */ ) ) {
581  return Status::newFatal( 'sorbs_create_account_reason' );
582  }
583 
584  # Now create a dummy user ($u) and check if it is valid
585  $u = User::newFromName( $this->mUsername, 'creatable' );
586  if ( !$u ) {
587  return Status::newFatal( 'noname' );
588  }
589 
591  # Make sure the user does not exist already
592  $lock = $cache->getScopedLock( $cache->makeGlobalKey( 'account', md5( $this->mUsername ) ) );
593  if ( !$lock ) {
594  return Status::newFatal( 'usernameinprogress' );
595  } elseif ( $u->idForName( User::READ_LOCKING ) ) {
596  return Status::newFatal( 'userexists' );
597  }
598 
599  if ( $this->mCreateaccountMail ) {
600  # do not force a password for account creation by email
601  # set invalid password, it will be replaced later by a random generated password
602  $this->mPassword = null;
603  } else {
604  if ( $this->mPassword !== $this->mRetype ) {
605  return Status::newFatal( 'badretype' );
606  }
607 
608  # check for password validity, return a fatal Status if invalid
609  $validity = $u->checkPasswordValidity( $this->mPassword, 'create' );
610  if ( !$validity->isGood() ) {
611  $validity->ok = false; // make sure this Status is fatal
612  return $validity;
613  }
614  }
615 
616  # if you need a confirmed email address to edit, then obviously you
617  # need an email address.
618  if ( $wgEmailConfirmToEdit && strval( $this->mEmail ) === '' ) {
619  return Status::newFatal( 'noemailtitle' );
620  }
621 
622  if ( strval( $this->mEmail ) !== '' && !Sanitizer::validateEmail( $this->mEmail ) ) {
623  return Status::newFatal( 'invalidemailaddress' );
624  }
625 
626  # Set some additional data so the AbortNewAccount hook can be used for
627  # more than just username validation
628  $u->setEmail( $this->mEmail );
629  $u->setRealName( $this->mRealName );
630 
631  $abortError = '';
632  $abortStatus = null;
633  if ( !Hooks::run( 'AbortNewAccount', [ $u, &$abortError, &$abortStatus ] ) ) {
634  // Hook point to add extra creation throttles and blocks
635  wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" );
636  if ( $abortStatus === null ) {
637  // Report back the old string as a raw message status.
638  // This will report the error back as 'createaccount-hook-aborted'
639  // with the given string as the message.
640  // To return a different error code, return a Status object.
641  $abortError = new Message( 'createaccount-hook-aborted', [ $abortError ] );
642  $abortError->text();
643 
644  return Status::newFatal( $abortError );
645  } else {
646  // For MediaWiki 1.23+ and updated hooks, return the Status object
647  // returned from the hook.
648  return $abortStatus;
649  }
650  }
651 
652  // Hook point to check for exempt from account creation throttle
653  if ( !Hooks::run( 'ExemptFromAccountCreationThrottle', [ $ip ] ) ) {
654  wfDebug( "LoginForm::exemptFromAccountCreationThrottle: a hook " .
655  "allowed account creation w/o throttle\n" );
656  } else {
657  if ( ( $wgAccountCreationThrottle && $currentUser->isPingLimitable() ) ) {
658  $key = wfGlobalCacheKey( 'acctcreate', 'ip', $ip );
659  $value = $cache->get( $key );
660  if ( !$value ) {
661  $cache->set( $key, 0, $cache::TTL_DAY );
662  }
663  if ( $value >= $wgAccountCreationThrottle ) {
664  return Status::newFatal( 'acct_creation_throttle_hit', $wgAccountCreationThrottle );
665  }
666  $cache->incr( $key );
667  }
668  }
669 
670  if ( !$wgAuth->addUser( $u, $this->mPassword, $this->mEmail, $this->mRealName ) ) {
671  return Status::newFatal( 'externaldberror' );
672  }
673 
674  self::clearCreateaccountToken();
675 
676  return $this->initUser( $u, false );
677  }
678 
688  function initUser( $u, $autocreate ) {
689  global $wgAuth;
690 
691  $status = $u->addToDatabase();
692  if ( !$status->isOK() ) {
693  return $status;
694  }
695 
696  if ( $wgAuth->allowPasswordChange() ) {
697  $u->setPassword( $this->mPassword );
698  }
699 
700  $u->setEmail( $this->mEmail );
701  $u->setRealName( $this->mRealName );
702  $u->setToken();
703 
704  Hooks::run( 'LocalUserCreated', [ $u, $autocreate ] );
705  $oldUser = $u;
706  $wgAuth->initUser( $u, $autocreate );
707  if ( $oldUser !== $u ) {
708  wfWarn( get_class( $wgAuth ) . '::initUser() replaced the user object' );
709  }
710 
711  $u->saveSettings();
712 
713  // Update user count
714  DeferredUpdates::addUpdate( new SiteStatsUpdate( 0, 0, 0, 0, 1 ) );
715 
716  // Watch user's userpage and talk page
717  $u->addWatch( $u->getUserPage(), User::IGNORE_USER_RIGHTS );
718 
719  return Status::newGood( $u );
720  }
721 
730  public function authenticateUserData() {
732 
733  $this->load();
734 
735  if ( $this->mUsername == '' ) {
736  return self::NO_NAME;
737  }
738 
739  // We require a login token to prevent login CSRF
740  // Handle part of this before incrementing the throttle so
741  // token-less login attempts don't count towards the throttle
742  // but wrong-token attempts do.
743 
744  // If the user doesn't have a login token yet, set one.
745  $token = self::getLoginToken();
746  if ( $token->wasNew() ) {
747  return self::NEED_TOKEN;
748  }
749  // If the user didn't pass a login token, tell them we need one
750  if ( !$this->mToken ) {
751  return self::NEED_TOKEN;
752  }
753 
754  $throttleCount = self::incrementLoginThrottle( $this->mUsername );
755  if ( $throttleCount ) {
756  $this->mThrottleWait = $throttleCount['wait'];
757  return self::THROTTLED;
758  }
759 
760  // Validate the login token
761  if ( !$token->match( $this->mToken ) ) {
762  return self::WRONG_TOKEN;
763  }
764 
765  // Load the current user now, and check to see if we're logging in as
766  // the same name. This is necessary because loading the current user
767  // (say by calling getName()) calls the UserLoadFromSession hook, which
768  // potentially creates the user in the database. Until we load $wgUser,
769  // checking for user existence using User::newFromName($name)->getId() below
770  // will effectively be using stale data.
771  if ( $this->getUser()->getName() === $this->mUsername ) {
772  wfDebug( __METHOD__ . ": already logged in as {$this->mUsername}\n" );
773 
774  return self::SUCCESS;
775  }
776 
777  $u = User::newFromName( $this->mUsername );
778  if ( $u === false ) {
779  return self::ILLEGAL;
780  }
781 
782  $msg = null;
783  // Give extensions a way to indicate the username has been updated,
784  // rather than telling the user the account doesn't exist.
785  if ( !Hooks::run( 'LoginUserMigrated', [ $u, &$msg ] ) ) {
786  $this->mAbortLoginErrorMsg = $msg;
787  return self::USER_MIGRATED;
788  }
789 
790  if ( !User::isUsableName( $u->getName() ) ) {
791  return self::ILLEGAL;
792  }
793 
794  $isAutoCreated = false;
795  if ( $u->getId() == 0 ) {
796  $status = $this->attemptAutoCreate( $u );
797  if ( $status !== self::SUCCESS ) {
798  return $status;
799  } else {
800  $isAutoCreated = true;
801  }
802  } else {
803  $u->load();
804  }
805 
806  // Give general extensions, such as a captcha, a chance to abort logins
807  $abort = self::ABORTED;
808  if ( !Hooks::run( 'AbortLogin', [ $u, $this->mPassword, &$abort, &$msg ] ) ) {
809  if ( !in_array( $abort, array_keys( self::$statusCodes ), true ) ) {
810  throw new Exception( 'Invalid status code returned from AbortLogin hook: ' . $abort );
811  }
812  $this->mAbortLoginErrorMsg = $msg;
813  return $abort;
814  }
815 
817  if ( !$u->checkPassword( $this->mPassword ) ) {
818  if ( $u->checkTemporaryPassword( $this->mPassword ) ) {
837  if ( !$u->isEmailConfirmed() && !wfReadOnly() ) {
838  $u->confirmEmail();
839  $u->saveSettings();
840  }
841 
842  // At this point we just return an appropriate code/ indicating
843  // that the UI should show a password reset form; bot inter-
844  // faces etc will probably just fail cleanly here.
845  $this->mAbortLoginErrorMsg = 'resetpass-temp-emailed';
846  $this->mTempPasswordUsed = true;
847  $retval = self::RESET_PASS;
848  } else {
849  $retval = ( $this->mPassword == '' ) ? self::EMPTY_PASS : self::WRONG_PASS;
850  }
851  } elseif ( $wgBlockDisablesLogin && $u->isBlocked() ) {
852  // If we've enabled it, make it so that a blocked user cannot login
853  $retval = self::USER_BLOCKED;
854  } elseif ( $this->checkUserPasswordExpired( $u ) == 'hard' ) {
855  // Force reset now, without logging in
856  $retval = self::RESET_PASS;
857  $this->mAbortLoginErrorMsg = 'resetpass-expired';
858  } else {
859  Hooks::run( 'UserLoggedIn', [ $u ] );
860  $oldUser = $u;
861  $wgAuth->updateUser( $u );
862  if ( $oldUser !== $u ) {
863  wfWarn( get_class( $wgAuth ) . '::updateUser() replaced the user object' );
864  }
865  $wgUser = $u;
866  // This should set it for OutputPage and the Skin
867  // which is needed or the personal links will be
868  // wrong.
869  $this->getContext()->setUser( $u );
870 
871  // Please reset throttle for successful logins, thanks!
872  self::clearLoginThrottle( $this->mUsername );
873 
874  if ( $isAutoCreated ) {
875  // Must be run after $wgUser is set, for correct new user log
876  Hooks::run( 'AuthPluginAutoCreate', [ $u ] );
877  }
878 
879  $retval = self::SUCCESS;
880  }
881  Hooks::run( 'LoginAuthenticateAudit', [ $u, $this->mPassword, $retval ] );
882 
883  return $retval;
884  }
885 
895  public static function incrementLoginThrottle( $username ) {
897  $canUsername = User::getCanonicalName( $username, 'usable' );
898  $username = $canUsername !== false ? $canUsername : $username;
899 
900  $throttleCount = 0;
901  if ( is_array( $wgPasswordAttemptThrottle ) ) {
902  $throttleConfig = $wgPasswordAttemptThrottle;
903  if ( isset( $wgPasswordAttemptThrottle['count'] ) ) {
904  // old style. Convert for backwards compat.
905  $throttleConfig = [ $wgPasswordAttemptThrottle ];
906  }
907  foreach ( $throttleConfig as $index => $specificThrottle ) {
908  if ( isset( $specificThrottle['allIPs'] ) ) {
909  $ip = 'All';
910  } else {
911  $ip = $wgRequest->getIP();
912  }
913  $throttleKey = wfGlobalCacheKey( 'password-throttle',
914  $index, $ip, md5( $username )
915  );
916  $count = $specificThrottle['count'];
917  $period = $specificThrottle['seconds'];
918 
920  $throttleCount = $cache->get( $throttleKey );
921  if ( !$throttleCount ) {
922  $cache->add( $throttleKey, 1, $period ); // start counter
923  } elseif ( $throttleCount < $count ) {
924  $cache->incr( $throttleKey );
925  } elseif ( $throttleCount >= $count ) {
926  $logMsg = 'Login attempt rejected because logins to '
927  . '{acct} from IP {ip} have been throttled for '
928  . '{period} seconds due to {count} failed attempts';
929  // If we are hitting a throttle for >= 50 attempts,
930  // it is much more likely to be an attack than someone
931  // simply forgetting their password, so log it at a
932  // higher level.
933  $level = $count >= 50 ? LogLevel::WARNING : LogLevel::INFO;
934  // It should be noted that once the throttle is hit,
935  // every attempt to login will generate the log message
936  // until the throttle expires, not just the attempt that
937  // puts the throttle over the top.
938  LoggerFactory::getInstance( 'password-throttle' )->log(
939  $level,
940  $logMsg,
941  [
942  'ip' => $ip,
943  'period' => $period,
944  'acct' => $username,
945  'count' => $count,
946  'throttleIdentifier' => $index,
947  'method' => __METHOD__
948  ]
949  );
950 
951  return [
952  'throttleIndex' => $index,
953  'wait' => $period,
954  'count' => $count
955  ];
956  }
957  }
958  }
959  return false;
960  }
961 
970  public static function incLoginThrottle( $username ) {
971  wfDeprecated( __METHOD__, "1.27" );
972  $res = self::incrementLoginThrottle( $username );
973  return is_array( $res ) ? true : 0;
974  }
975 
981  public static function clearLoginThrottle( $username ) {
983  $canUsername = User::getCanonicalName( $username, 'usable' );
984  $username = $canUsername !== false ? $canUsername : $username;
985 
986  if ( is_array( $wgPasswordAttemptThrottle ) ) {
987  $throttleConfig = $wgPasswordAttemptThrottle;
988  if ( isset( $wgPasswordAttemptThrottle['count'] ) ) {
989  // old style. Convert for backwards compat.
990  $throttleConfig = [ $wgPasswordAttemptThrottle ];
991  }
992  foreach ( $throttleConfig as $index => $specificThrottle ) {
993  if ( isset( $specificThrottle['allIPs'] ) ) {
994  $ip = 'All';
995  } else {
996  $ip = $wgRequest->getIP();
997  }
998  $throttleKey = wfGlobalCacheKey( 'password-throttle', $index,
999  $ip, md5( $username )
1000  );
1001  ObjectCache::getLocalClusterInstance()->delete( $throttleKey );
1002  }
1003  }
1004  }
1005 
1014  function attemptAutoCreate( $user ) {
1015  global $wgAuth;
1016 
1017  if ( $this->getUser()->isBlockedFromCreateAccount() ) {
1018  wfDebug( __METHOD__ . ": user is blocked from account creation\n" );
1019 
1020  return self::CREATE_BLOCKED;
1021  }
1022 
1023  if ( !$wgAuth->autoCreate() ) {
1024  return self::NOT_EXISTS;
1025  }
1026 
1027  if ( !$wgAuth->userExists( $user->getName() ) ) {
1028  wfDebug( __METHOD__ . ": user does not exist\n" );
1029 
1030  return self::NOT_EXISTS;
1031  }
1032 
1033  if ( !$wgAuth->authenticate( $user->getName(), $this->mPassword ) ) {
1034  wfDebug( __METHOD__ . ": \$wgAuth->authenticate() returned false, aborting\n" );
1035 
1036  return self::WRONG_PLUGIN_PASS;
1037  }
1038 
1039  $abortError = '';
1040  if ( !Hooks::run( 'AbortAutoAccount', [ $user, &$abortError ] ) ) {
1041  // Hook point to add extra creation throttles and blocks
1042  wfDebug( "LoginForm::attemptAutoCreate: a hook blocked creation: $abortError\n" );
1043  $this->mAbortLoginErrorMsg = $abortError;
1044 
1045  return self::ABORTED;
1046  }
1047 
1048  wfDebug( __METHOD__ . ": creating account\n" );
1049  $status = $this->initUser( $user, true );
1050 
1051  if ( !$status->isOK() ) {
1052  $errors = $status->getErrorsByType( 'error' );
1053  $this->mAbortLoginErrorMsg = $errors[0]['message'];
1054 
1055  return self::ABORTED;
1056  }
1057 
1058  return self::SUCCESS;
1059  }
1060 
1061  function processLogin() {
1063 
1064  $authRes = $this->authenticateUserData();
1065  switch ( $authRes ) {
1066  case self::SUCCESS:
1067  # We've verified now, update the real record
1068  $user = $this->getUser();
1069  $user->touch();
1070 
1071  if ( $user->requiresHTTPS() ) {
1072  $this->mStickHTTPS = true;
1073  }
1074 
1075  if ( $wgSecureLogin && !$this->mStickHTTPS ) {
1076  $user->setCookies( $this->mRequest, false, $this->mRemember );
1077  } else {
1078  $user->setCookies( $this->mRequest, null, $this->mRemember );
1079  }
1080  self::clearLoginToken();
1081 
1082  // Reset the throttle
1083  self::clearLoginThrottle( $this->mUsername );
1084 
1085  $request = $this->getRequest();
1086  if ( $this->hasSessionCookie() || $this->mSkipCookieCheck ) {
1087  /* Replace the language object to provide user interface in
1088  * correct language immediately on this first page load.
1089  */
1090  $code = $request->getVal( 'uselang', $user->getOption( 'language' ) );
1091  $userLang = Language::factory( $code );
1092  $wgLang = $userLang;
1093  RequestContext::getMain()->setLanguage( $userLang );
1094  $this->getContext()->setLanguage( $userLang );
1095  // Reset SessionID on Successful login (bug 40995)
1096  $this->renewSessionId();
1097  if ( $this->checkUserPasswordExpired( $this->getUser() ) == 'soft' ) {
1098  $this->resetLoginForm( $this->msg( 'resetpass-expired-soft' ) );
1099  } elseif ( $wgInvalidPasswordReset
1100  && !$user->isValidPassword( $this->mPassword )
1101  ) {
1102  $status = $user->checkPasswordValidity(
1103  $this->mPassword,
1104  'login'
1105  );
1106  $this->resetLoginForm(
1107  $status->getMessage( 'resetpass-validity-soft' )
1108  );
1109  } else {
1110  $this->successfulLogin();
1111  }
1112  } else {
1113  $this->cookieRedirectCheck( 'login' );
1114  }
1115  break;
1116 
1117  case self::NEED_TOKEN:
1118  $error = $this->mAbortLoginErrorMsg ?: 'nocookiesforlogin';
1119  $this->mainLoginForm( $this->msg( $error )->parse() );
1120  break;
1121  case self::WRONG_TOKEN:
1122  $error = $this->mAbortLoginErrorMsg ?: 'sessionfailure';
1123  $this->mainLoginForm( $this->msg( $error )->text() );
1124  break;
1125  case self::NO_NAME:
1126  case self::ILLEGAL:
1127  $error = $this->mAbortLoginErrorMsg ?: 'noname';
1128  $this->mainLoginForm( $this->msg( $error )->text() );
1129  break;
1130  case self::WRONG_PLUGIN_PASS:
1131  $error = $this->mAbortLoginErrorMsg ?: 'wrongpassword';
1132  $this->mainLoginForm( $this->msg( $error )->text() );
1133  break;
1134  case self::NOT_EXISTS:
1135  if ( $this->getUser()->isAllowed( 'createaccount' ) ) {
1136  $error = $this->mAbortLoginErrorMsg ?: 'nosuchuser';
1137  $this->mainLoginForm( $this->msg( $error,
1138  wfEscapeWikiText( $this->mUsername ) )->parse() );
1139  } else {
1140  $error = $this->mAbortLoginErrorMsg ?: 'nosuchusershort';
1141  $this->mainLoginForm( $this->msg( $error,
1142  wfEscapeWikiText( $this->mUsername ) )->text() );
1143  }
1144  break;
1145  case self::WRONG_PASS:
1146  $error = $this->mAbortLoginErrorMsg ?: 'wrongpassword';
1147  $this->mainLoginForm( $this->msg( $error )->text() );
1148  break;
1149  case self::EMPTY_PASS:
1150  $error = $this->mAbortLoginErrorMsg ?: 'wrongpasswordempty';
1151  $this->mainLoginForm( $this->msg( $error )->text() );
1152  break;
1153  case self::RESET_PASS:
1154  $error = $this->mAbortLoginErrorMsg ?: 'resetpass_announce';
1155  $this->resetLoginForm( $this->msg( $error ) );
1156  break;
1157  case self::CREATE_BLOCKED:
1158  $this->userBlockedMessage( $this->getUser()->isBlockedFromCreateAccount() );
1159  break;
1160  case self::THROTTLED:
1161  $error = $this->mAbortLoginErrorMsg ?: 'login-throttled';
1162  $this->mainLoginForm( $this->msg( $error )
1163  ->durationParams( $this->mThrottleWait )->text()
1164  );
1165  break;
1166  case self::USER_BLOCKED:
1167  $error = $this->mAbortLoginErrorMsg ?: 'login-userblocked';
1168  $this->mainLoginForm( $this->msg( $error, $this->mUsername )->escaped() );
1169  break;
1170  case self::ABORTED:
1171  $error = $this->mAbortLoginErrorMsg ?: 'login-abort-generic';
1172  $this->mainLoginForm( $this->msg( $error,
1173  wfEscapeWikiText( $this->mUsername ) )->text() );
1174  break;
1175  case self::USER_MIGRATED:
1176  $error = $this->mAbortLoginErrorMsg ?: 'login-migrated-generic';
1177  $params = [];
1178  if ( is_array( $error ) ) {
1179  $error = array_shift( $this->mAbortLoginErrorMsg );
1181  }
1182  $this->mainLoginForm( $this->msg( $error, $params )->text() );
1183  break;
1184  default:
1185  throw new MWException( 'Unhandled case value' );
1186  }
1187 
1188  LoggerFactory::getInstance( 'authmanager' )->info( 'Login attempt', [
1189  'event' => 'login',
1190  'successful' => $authRes === self::SUCCESS,
1191  'status' => LoginForm::$statusCodes[$authRes],
1192  ] );
1193  }
1194 
1199  protected function resetLoginForm( Message $msg ) {
1200  // Allow hooks to explain this password reset in more detail
1201  Hooks::run( 'LoginPasswordResetMessage', [ &$msg, $this->mUsername ] );
1202  $reset = new SpecialChangePasswordPreAuthManager();
1203  $derivative = new DerivativeContext( $this->getContext() );
1204  $derivative->setTitle( $reset->getPageTitle() );
1205  $reset->setContext( $derivative );
1206  if ( !$this->mTempPasswordUsed ) {
1207  $reset->setOldPasswordMessage( 'oldpassword' );
1208  }
1209  $reset->setChangeMessage( $msg );
1210  $reset->execute( null );
1211  }
1212 
1220  function mailPasswordInternal( $u, $throttle = true, $emailTitle = 'passwordremindertitle',
1221  $emailText = 'passwordremindertext'
1222  ) {
1224 
1225  if ( $u->getEmail() == '' ) {
1226  return Status::newFatal( 'noemail', $u->getName() );
1227  }
1228  $ip = $this->getRequest()->getIP();
1229  if ( !$ip ) {
1230  return Status::newFatal( 'badipaddress' );
1231  }
1232 
1233  $currentUser = $this->getUser();
1234  Hooks::run( 'User::mailPasswordInternal', [ &$currentUser, &$ip, &$u ] );
1235 
1236  $np = PasswordFactory::generateRandomPasswordString( $wgMinimalPasswordLength );
1237  $u->setNewpassword( $np, $throttle );
1238  $u->saveSettings();
1239  $userLanguage = $u->getOption( 'language' );
1240 
1241  $mainPage = Title::newMainPage();
1242  $mainPageUrl = $mainPage->getCanonicalURL();
1243 
1244  $m = $this->msg( $emailText, $ip, $u->getName(), $np, '<' . $mainPageUrl . '>',
1245  round( $wgNewPasswordExpiry / 86400 ) )->inLanguage( $userLanguage )->text();
1246  $result = $u->sendMail( $this->msg( $emailTitle )->inLanguage( $userLanguage )->text(), $m );
1247 
1248  return $result;
1249  }
1250 
1261  function successfulLogin() {
1262  # Run any hooks; display injected HTML if any, else redirect
1263  $currentUser = $this->getUser();
1264  $injected_html = '';
1265  $direct = RequestContext::getMain()->getRequest()->wasPosted();
1266  Hooks::run( 'UserLoginComplete', [ &$currentUser, &$injected_html, $direct ] );
1267 
1268  if ( $injected_html !== '' ) {
1269  $this->displaySuccessfulAction( 'success', $this->msg( 'loginsuccesstitle' ),
1270  'loginsuccess', $injected_html );
1271  } else {
1272  $this->executeReturnTo( 'successredirect' );
1273  }
1274  }
1275 
1282  function successfulCreation() {
1283  # Run any hooks; display injected HTML
1284  $currentUser = $this->getUser();
1285  $injected_html = '';
1286  $welcome_creation_msg = 'welcomecreation-msg';
1287  $direct = RequestContext::getMain()->getRequest()->wasPosted();
1288 
1289  Hooks::run( 'UserLoginComplete', [ &$currentUser, &$injected_html, $direct ] );
1290 
1296  Hooks::run( 'BeforeWelcomeCreation', [ &$welcome_creation_msg, &$injected_html ] );
1297 
1298  $this->displaySuccessfulAction(
1299  'signup',
1300  $this->msg( 'welcomeuser', $this->getUser()->getName() ),
1301  $welcome_creation_msg, $injected_html
1302  );
1303  }
1304 
1313  private function displaySuccessfulAction( $type, $title, $msgname, $injected_html ) {
1314  $out = $this->getOutput();
1315  $out->setPageTitle( $title );
1316  if ( $msgname ) {
1317  $out->addWikiMsg( $msgname, wfEscapeWikiText( $this->getUser()->getName() ) );
1318  }
1319 
1320  $out->addHTML( $injected_html );
1321 
1322  $this->executeReturnTo( $type );
1323  }
1324 
1333  function userBlockedMessage( Block $block ) {
1334  # Let's be nice about this, it's likely that this feature will be used
1335  # for blocking large numbers of innocent people, e.g. range blocks on
1336  # schools. Don't blame it on the user. There's a small chance that it
1337  # really is the user's fault, i.e. the username is blocked and they
1338  # haven't bothered to log out before trying to create an account to
1339  # evade it, but we'll leave that to their guilty conscience to figure
1340  # out.
1341  $errorParams = [
1342  $block->getTarget(),
1343  $block->mReason ? $block->mReason : $this->msg( 'blockednoreason' )->text(),
1344  $block->getByName()
1345  ];
1346 
1347  if ( $block->getType() === Block::TYPE_RANGE ) {
1348  $errorMessage = 'cantcreateaccount-range-text';
1349  $errorParams[] = $this->getRequest()->getIP();
1350  } else {
1351  $errorMessage = 'cantcreateaccount-text';
1352  }
1353 
1354  throw new ErrorPageError(
1355  'cantcreateaccounttitle',
1356  $errorMessage,
1357  $errorParams
1358  );
1359  }
1360 
1376  public function showReturnToPage(
1377  $type, $returnTo = '', $returnToQuery = '', $stickHTTPs = false
1378  ) {
1379  $this->mReturnTo = $returnTo;
1380  $this->mReturnToQuery = $returnToQuery;
1381  $this->mStickHTTPS = $stickHTTPs;
1382  $this->executeReturnTo( $type );
1383  }
1384 
1394  private function executeReturnTo( $type ) {
1396 
1397  if ( $type != 'error' && $wgRedirectOnLogin !== null ) {
1399  $returnToQuery = [];
1400  } else {
1402  $returnToQuery = wfCgiToArray( $this->mReturnToQuery );
1403  }
1404 
1405  // Allow modification of redirect behavior
1406  Hooks::run( 'PostLoginRedirect', [ &$returnTo, &$returnToQuery, &$type ] );
1407 
1408  $returnToTitle = Title::newFromText( $returnTo );
1409  if ( !$returnToTitle ) {
1410  $returnToTitle = Title::newMainPage();
1411  }
1412 
1413  if ( $wgSecureLogin && !$this->mStickHTTPS ) {
1414  $options = [ 'http' ];
1415  $proto = PROTO_HTTP;
1416  } elseif ( $wgSecureLogin ) {
1417  $options = [ 'https' ];
1418  $proto = PROTO_HTTPS;
1419  } else {
1420  $options = [];
1421  $proto = PROTO_RELATIVE;
1422  }
1423 
1424  if ( $type == 'successredirect' ) {
1425  $redirectUrl = $returnToTitle->getFullURL( $returnToQuery, false, $proto );
1426  $this->getOutput()->redirect( $redirectUrl );
1427  } else {
1428  $this->getOutput()->addReturnTo( $returnToTitle, $returnToQuery, null, $options );
1429  }
1430  }
1431 
1443  function mainLoginForm( $msg, $msgtype = 'error' ) {
1449 
1450  $titleObj = $this->getPageTitle();
1451  $user = $this->getUser();
1452  $out = $this->getOutput();
1453 
1454  if ( $this->mType == 'signup' ) {
1455  // Block signup here if in readonly. Keeps user from
1456  // going through the process (filling out data, etc)
1457  // and being informed later.
1458  $permErrors = $titleObj->getUserPermissionsErrors( 'createaccount', $user, true );
1459  if ( count( $permErrors ) ) {
1460  throw new PermissionsError( 'createaccount', $permErrors );
1461  } elseif ( $user->isBlockedFromCreateAccount() ) {
1462  $this->userBlockedMessage( $user->isBlockedFromCreateAccount() );
1463 
1464  return;
1465  } elseif ( wfReadOnly() ) {
1466  throw new ReadOnlyError;
1467  }
1468  }
1469 
1470  // Pre-fill username (if not creating an account, bug 44775).
1471  if ( $this->mUsername == '' && $this->mType != 'signup' ) {
1472  if ( $user->isLoggedIn() ) {
1473  $this->mUsername = $user->getName();
1474  } else {
1475  $this->mUsername = $this->getRequest()->getSession()->suggestLoginUsername();
1476  }
1477  }
1478 
1479  // Generic styles and scripts for both login and signup form
1480  $out->addModuleStyles( [
1481  'mediawiki.ui',
1482  'mediawiki.ui.button',
1483  'mediawiki.ui.checkbox',
1484  'mediawiki.ui.input',
1485  'mediawiki.special.userlogin.common.styles'
1486  ] );
1487 
1488  if ( $this->mType == 'signup' ) {
1489  // Additional styles and scripts for signup form
1490  $out->addModules( [
1491  'mediawiki.special.userlogin.signup.js'
1492  ] );
1493  $out->addModuleStyles( [
1494  'mediawiki.special.userlogin.signup.styles'
1495  ] );
1496 
1497  $template = new UsercreateTemplate( $this->getConfig() );
1498 
1499  // Must match number of benefits defined in messages
1500  $template->set( 'benefitCount', 3 );
1501 
1502  $q = 'action=submitlogin&type=signup';
1503  $linkq = 'type=login';
1504  } else {
1505  // Additional styles for login form
1506  $out->addModuleStyles( [
1507  'mediawiki.special.userlogin.login.styles'
1508  ] );
1509 
1510  $template = new UserloginTemplate( $this->getConfig() );
1511 
1512  $q = 'action=submitlogin&type=login';
1513  $linkq = 'type=signup';
1514  }
1515 
1516  if ( $this->mReturnTo !== '' ) {
1517  $returnto = '&returnto=' . wfUrlencode( $this->mReturnTo );
1518  if ( $this->mReturnToQuery !== '' ) {
1519  $returnto .= '&returntoquery=' .
1520  wfUrlencode( $this->mReturnToQuery );
1521  }
1522  $q .= $returnto;
1523  $linkq .= $returnto;
1524  }
1525 
1526  # Don't show a "create account" link if the user can't.
1527  if ( $this->showCreateOrLoginLink( $user ) ) {
1528  # Pass any language selection on to the mode switch link
1529  if ( $wgLoginLanguageSelector && $this->mLanguage ) {
1530  $linkq .= '&uselang=' . $this->mLanguage;
1531  }
1532  // Supply URL, login template creates the button.
1533  $template->set( 'createOrLoginHref', $titleObj->getLocalURL( $linkq ) );
1534  } else {
1535  $template->set( 'link', '' );
1536  }
1537 
1538  $resetLink = $this->mType == 'signup'
1539  ? null
1540  : is_array( $wgPasswordResetRoutes ) && in_array( true, array_values( $wgPasswordResetRoutes ) );
1541 
1542  $template->set( 'header', '' );
1543  $template->set( 'formheader', '' );
1544  $template->set( 'skin', $this->getSkin() );
1545  $template->set( 'name', $this->mUsername );
1546  $template->set( 'password', $this->mPassword );
1547  $template->set( 'retype', $this->mRetype );
1548  $template->set( 'createemailset', $this->mCreateaccountMail );
1549  $template->set( 'email', $this->mEmail );
1550  $template->set( 'realname', $this->mRealName );
1551  $template->set( 'domain', $this->mDomain );
1552  $template->set( 'reason', $this->mReason );
1553 
1554  $template->set( 'action', $titleObj->getLocalURL( $q ) );
1555  $template->set( 'message', $msg );
1556  $template->set( 'messagetype', $msgtype );
1557  $template->set( 'createemail', $wgEnableEmail && $user->isLoggedIn() );
1558  $template->set( 'userealname', !in_array( 'realname', $wgHiddenPrefs ) );
1559  $template->set( 'useemail', $wgEnableEmail );
1560  $template->set( 'emailrequired', $wgEmailConfirmToEdit );
1561  $template->set( 'emailothers', $wgEnableUserEmail );
1562  $template->set( 'canreset', $wgAuth->allowPasswordChange() );
1563  $template->set( 'resetlink', $resetLink );
1564  $template->set( 'canremember', $wgExtendedLoginCookieExpiration === null ?
1565  ( $wgCookieExpiration > 0 ) :
1566  ( $wgExtendedLoginCookieExpiration > 0 ) );
1567  $template->set( 'usereason', $user->isLoggedIn() );
1568  $template->set( 'remember', $this->mRemember );
1569  $template->set( 'cansecurelogin', ( $wgSecureLogin === true ) );
1570  $template->set( 'stickhttps', (int)$this->mStickHTTPS );
1571  $template->set( 'loggedin', $user->isLoggedIn() );
1572  $template->set( 'loggedinuser', $user->getName() );
1573 
1574  if ( $this->mType == 'signup' ) {
1575  $template->set( 'token', self::getCreateaccountToken()->toString() );
1576  } else {
1577  $template->set( 'token', self::getLoginToken()->toString() );
1578  }
1579 
1580  # Prepare language selection links as needed
1581  if ( $wgLoginLanguageSelector ) {
1582  $template->set( 'languages', $this->makeLanguageSelector() );
1583  if ( $this->mLanguage ) {
1584  $template->set( 'uselang', $this->mLanguage );
1585  }
1586  }
1587 
1588  $template->set( 'secureLoginUrl', $this->mSecureLoginUrl );
1589  // Use signupend-https for HTTPS requests if it's not blank, signupend otherwise
1590  $usingHTTPS = $this->mRequest->getProtocol() == 'https';
1591  $signupendHTTPS = $this->msg( 'signupend-https' );
1592  if ( $usingHTTPS && !$signupendHTTPS->isBlank() ) {
1593  $template->set( 'signupend', $signupendHTTPS->parse() );
1594  } else {
1595  $template->set( 'signupend', $this->msg( 'signupend' )->parse() );
1596  }
1597 
1598  // If using HTTPS coming from HTTP, then the 'fromhttp' parameter must be preserved
1599  if ( $usingHTTPS ) {
1600  $template->set( 'fromhttp', $this->mFromHTTP );
1601  }
1602 
1603  // Give authentication and captcha plugins a chance to modify the form
1604  $wgAuth->modifyUITemplate( $template, $this->mType );
1605  if ( $this->mType == 'signup' ) {
1606  Hooks::run( 'UserCreateForm', [ &$template ] );
1607  } else {
1608  Hooks::run( 'UserLoginForm', [ &$template ] );
1609  }
1610 
1611  $out->disallowUserJs(); // just in case...
1612  $out->addTemplate( $template );
1613  }
1614 
1622  private function showCreateOrLoginLink( &$user ) {
1623  if ( $this->mType == 'signup' ) {
1624  return true;
1625  } elseif ( $user->isAllowed( 'createaccount' ) ) {
1626  return true;
1627  } else {
1628  return false;
1629  }
1630  }
1631 
1642  function hasSessionCookie() {
1644 
1645  return $wgDisableCookieCheck || (
1646  $wgInitialSessionId &&
1647  $this->getRequest()->getSession()->getId() === (string)$wgInitialSessionId
1648  );
1649  }
1650 
1656  public static function getLoginToken() {
1658  return $wgRequest->getSession()->getToken( '', 'login' );
1659  }
1660 
1670  public static function setLoginToken() {
1671  wfDeprecated( __METHOD__, '1.27' );
1672  }
1673 
1677  public static function clearLoginToken() {
1679  $wgRequest->getSession()->resetToken( 'login' );
1680  }
1681 
1687  public static function getCreateaccountToken() {
1689  return $wgRequest->getSession()->getToken( '', 'createaccount' );
1690  }
1691 
1701  public static function setCreateaccountToken() {
1702  wfDeprecated( __METHOD__, '1.27' );
1703  }
1704 
1708  public static function clearCreateaccountToken() {
1710  $wgRequest->getSession()->resetToken( 'createaccount' );
1711  }
1712 
1716  private function renewSessionId() {
1718  if ( $wgSecureLogin && !$this->mStickHTTPS ) {
1719  $wgCookieSecure = false;
1720  }
1721 
1722  SessionManager::getGlobalSession()->resetId();
1723  SessionManager::getGlobalSession()->resetAllTokens();
1724  }
1725 
1731  $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
1732  $query = [ 'wpCookieCheck' => $type ];
1733  if ( $this->mReturnTo !== '' ) {
1734  $query['returnto'] = $this->mReturnTo;
1735  $query['returntoquery'] = $this->mReturnToQuery;
1736  }
1737  $check = $titleObj->getFullURL( $query );
1738 
1739  $this->getOutput()->redirect( $check );
1740  }
1741 
1747  if ( !$this->hasSessionCookie() ) {
1748  if ( $type == 'new' ) {
1749  $this->mainLoginForm( $this->msg( 'nocookiesnew' )->parse() );
1750  } elseif ( $type == 'login' ) {
1751  $this->mainLoginForm( $this->msg( 'nocookieslogin' )->parse() );
1752  } else {
1753  # shouldn't happen
1754  $this->mainLoginForm( $this->msg( 'error' )->text() );
1755  }
1756  } else {
1757  $this->successfulLogin();
1758  }
1759  }
1760 
1768  $msg = $this->msg( 'loginlanguagelinks' )->inContentLanguage();
1769  if ( $msg->isBlank() ) {
1770  return '';
1771  }
1772  $langs = explode( "\n", $msg->text() );
1773  $links = [];
1774  foreach ( $langs as $lang ) {
1775  $lang = trim( $lang, '* ' );
1776  $parts = explode( '|', $lang );
1777  if ( count( $parts ) >= 2 ) {
1778  $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) );
1779  }
1780  }
1781 
1782  return count( $links ) > 0 ? $this->msg( 'loginlanguagelabel' )->rawParams(
1783  $this->getLanguage()->pipeList( $links ) )->escaped() : '';
1784  }
1785 
1794  function makeLanguageSelectorLink( $text, $lang ) {
1795  if ( $this->getLanguage()->getCode() == $lang ) {
1796  // no link for currently used language
1797  return htmlspecialchars( $text );
1798  }
1799  $query = [ 'uselang' => $lang ];
1800  if ( $this->mType == 'signup' ) {
1801  $query['type'] = 'signup';
1802  }
1803  if ( $this->mReturnTo !== '' ) {
1804  $query['returnto'] = $this->mReturnTo;
1805  $query['returntoquery'] = $this->mReturnToQuery;
1806  }
1807 
1808  $attr = [];
1809  $targetLanguage = Language::factory( $lang );
1810  $attr['lang'] = $attr['hreflang'] = $targetLanguage->getHtmlCode();
1811 
1812  return Linker::linkKnown(
1813  $this->getPageTitle(),
1814  htmlspecialchars( $text ),
1815  $attr,
1816  $query
1817  );
1818  }
1819 
1820  protected function getGroupName() {
1821  return 'login';
1822  }
1823 
1830  private function checkUserPasswordExpired( User $user ) {
1832  $dbr = wfGetDB( DB_SLAVE );
1833  $ts = $dbr->selectField( 'user', 'user_password_expires', [ 'user_id' => $user->getId() ] );
1834 
1835  $expired = false;
1836  $now = wfTimestamp();
1837  $expUnix = wfTimestamp( TS_UNIX, $ts );
1838  if ( $ts !== null && $expUnix < $now ) {
1839  $expired = ( $expUnix + $wgPasswordExpireGrace < $now ) ? 'hard' : 'soft';
1840  }
1841  return $expired;
1842  }
1843 
1844  protected function getSubpagesForPrefixSearch() {
1845  return [ 'signup' ];
1846  }
1847 }
static newFromName($name, $validate= 'valid')
Static factory method for creation from username.
Definition: User.php:522
$wgInitialSessionId
Definition: Setup.php:737
mainLoginForm($msg, $msgtype= 'error')
authenticateUserData()
Internally authenticate the login request.
$wgPasswordAttemptThrottle
Limit password attempts to X attempts per Y seconds per IP per account.
wfGetDB($db, $groups=[], $wiki=false)
Get a Database object.
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
Definition: hooks.txt:776
null for the local wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition: hooks.txt:1435
wfCanIPUseHTTPS($ip)
Determine whether the client at a given source IP is likely to be able to access the wiki via HTTPS...
static setCreateaccountToken()
Formerly randomly generated a createaccount token that would be returned by $this->getCreateaccountTo...
getContext()
Gets the context this SpecialPage is executed in.
const TYPE_RANGE
Definition: Block.php:77
initUser($u, $autocreate)
Actually add a user to the database.
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached one of or reset my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled allows for interception of redirect as a string & $returnToQuery
Definition: hooks.txt:2376
static newMainPage()
Create a new Title for the Main Page.
Definition: Title.php:548
attemptAutoCreate($user)
Attempt to automatically create a user on login.
displaySuccessfulAction($type, $title, $msgname, $injected_html)
Display a "successful action" page.
Show an error when the wiki is locked/read-only and the user tries to do something that requires writ...
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
static getTitleFor($name, $subpage=false, $fragment= '')
Get a localised Title object for a specified special page name.
Definition: SpecialPage.php:80
static getCanonicalName($name, $validate= 'valid')
Given unvalidated user input, return a canonical username, or false if the username is invalid...
Definition: User.php:1082
The Message class provides methods which fulfil two basic services:
Definition: Message.php:159
getType()
Get the type of target for this particular block.
Definition: Block.php:1334
makeLanguageSelector()
Produce a bar of links which allow the user to select another language during login/registration but ...
$wgPasswordExpireGrace
If a user's password is expired, the number of seconds when they can still login, and cancel their pa...
if(!isset($args[0])) $lang
An IContextSource implementation which will inherit context from another source but allow individual ...
static getValidErrorMessages()
Returns an array of all valid error messages.
static generateRandomPasswordString($minLength=10)
Generate a random string suitable for a password.
static isUsableName($name)
Usernames which fail to pass this function will be blocked from user login and new account registrati...
Definition: User.php:889
$wgSecureLogin
This is to let user authenticate using https when they come from http.
This code would result in ircNotify being run twice when an article is and once for brion Hooks can return three possible true was required This is the default since MediaWiki *some string
Definition: hooks.txt:177
$value
static getLocalClusterInstance()
Get the main cluster-local cache object.
msg()
Wrapper around wfMessage that sets the current context.
$wgEmailConfirmToEdit
Should editors be required to have a validated e-mail address before being allowed to edit...
getOutput()
Get the OutputPage being used for this instance.
$wgAuth $wgAuth
Authentication plugin.
$wgHiddenPrefs
An array of preferences to not show for the user.
$wgCookieSecure
Whether the "secure" flag should be set on the cookie.
wfUrlencode($s)
We want some things to be included as literal characters in our title URLs for prettiness, which urlencode encodes by default.
static newFromText($text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:256
userBlockedMessage(Block $block)
Output a message that informs the user that they cannot create an account because there is a block on...
when a variable name is used in a it is silently declared as a new local masking the global
Definition: design.txt:93
static newFatal($message)
Factory function for fatal errors.
Definition: Status.php:89
showCreateOrLoginLink(&$user)
Whether the login/create account form should display a link to the other form (in addition to whateve...
int $mThrottleWait
How many seconds user is throttled for.
$wgEnableEmail
Set to true to enable the e-mail basic features: Password reminders, etc.
$wgPasswordResetRoutes
Whether to allow password resets ("enter some identifying data, and we'll send an email with a tempo...
wfDebug($text, $dest= 'all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as $wgLang
Definition: design.txt:56
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message.Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item.Return false to stop further processing of the tag $reader:XMLReader object $logInfo:Array of information 'ImportHandlePageXMLTag':When parsing a XML tag in a page.Return false to stop further processing of the tag $reader:XMLReader object &$pageInfo:Array of information 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision.Return false to stop further processing of the tag $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information 'ImportHandleToplevelXMLTag':When parsing a top level XML tag.Return false to stop further processing of the tag $reader:XMLReader object 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload.Return false to stop further processing of the tag $reader:XMLReader object $revisionInfo:Array of information 'ImportLogInterwikiLink':Hook to change the interwiki link used in log entries and edit summaries for transwiki imports.&$fullInterwikiPrefix:Interwiki prefix, may contain colons.&$pageTitle:String that contains page title. 'ImportSources':Called when reading from the $wgImportSources configuration variable.Can be used to lazy-load the import sources list.&$importSources:The value of $wgImportSources.Modify as necessary.See the comment in DefaultSettings.php for the detail of how to structure this array. 'InfoAction':When building information to display on the action=info page.$context:IContextSource object &$pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect.&$title:Title object for the current page &$request:WebRequest &$ignoreRedirect:boolean to skip redirect check &$target:Title/string of redirect target &$article:Article object 'InternalParseBeforeLinks':during Parser's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings.&$parser:Parser object &$text:string containing partially parsed text &$stripState:Parser's internal StripState object 'InternalParseBeforeSanitize':during Parser's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings.Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments.&$parser:Parser object &$text:string containing partially parsed text &$stripState:Parser's internal StripState object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not.Return true without providing an interwiki to continue interwiki search.$prefix:interwiki prefix we are looking for.&$iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InvalidateEmailComplete':Called after a user's email has been invalidated successfully.$user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification.Callee may modify $url and $query, URL will be constructed as $url.$query &$url:URL to index.php &$query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) &$article:article(object) being checked 'IsTrustedProxy':Override the result of IP::isTrustedProxy() &$ip:IP being check &$result:Change this value to override the result of IP::isTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from &$allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of Sanitizer::validateEmail(), for instance to return false if the domain name doesn't match your organization.$addr:The e-mail address entered by the user &$result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user &$result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we're looking for a messages file for &$file:The messages file path, you can override this to change the location. 'LanguageGetMagic':DEPRECATED!Use $magicWords in a file listed in $wgExtensionMessagesFiles instead.Use this to define synonyms of magic words depending of the language &$magicExtensions:associative array of magic words synonyms $lang:language code(string) 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces.Do not use this hook to add namespaces.Use CanonicalNamespaces for that.&$namespaces:Array of namespaces indexed by their numbers 'LanguageGetSpecialPageAliases':DEPRECATED!Use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead.Use to define aliases of special pages names depending of the language &$specialPageAliases:associative array of magic words synonyms $lang:language code(string) 'LanguageGetTranslatedLanguageNames':Provide translated language names.&$names:array of language code=> language name $code:language of the preferred translations 'LanguageLinks':Manipulate a page's language links.This is called in various places to allow extensions to define the effective language links for a page.$title:The page's Title.&$links:Associative array mapping language codes to prefixed links of the form"language:title".&$linkFlags:Associative array mapping prefixed links to arrays of flags.Currently unused, but planned to provide support for marking individual language links in the UI, e.g.for featured articles. 'LanguageSelector':Hook to change the language selector available on a page.$out:The output page.$cssClassName:CSS class name of the language selector. 'LinkBegin':DEPRECATED!Use HtmlPageLinkRendererBegin instead.Used when generating internal and interwiki links in Linker::link(), before processing starts.Return false to skip default processing and return $ret.See documentation for Linker::link() for details on the expected meanings of parameters.$skin:the Skin object $target:the Title that the link is pointing to &$html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1814
wfGlobalCacheKey()
Make a cache key with database-agnostic prefix.
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping $template
Definition: hooks.txt:776
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
Definition: User.php:47
wfTimestamp($outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
$wgLoginLanguageSelector
Show a bar of language selection links in the user login and user registration forms; edit the "login...
wfCgiToArray($query)
This is the logical opposite of wfArrayToCgi(): it accepts a query string as its argument and returns...
resetLoginForm(Message $msg)
Show the Special:ChangePassword form, with custom message.
Parent class for all special pages.
Definition: SpecialPage.php:36
mailPasswordInternal($u, $throttle=true, $emailTitle= 'passwordremindertitle', $emailText= 'passwordremindertext')
$wgExtendedLoginCookieExpiration
Default login cookie lifetime, in seconds.
const PROTO_HTTPS
Definition: Defines.php:263
wfEscapeWikiText($text)
Escapes the given text so that it may be output using addWikiText() without any linking, formatting, etc.
wfReadOnly()
Check whether the wiki is in read-only mode.
static getMain()
Static methods.
Let users recover their password.
addNewAccountInternal()
Make a new user account using the loaded data.
wfAppendQuery($url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
An error page which can definitely be safely rendered using the OutputPage.
wfWarn($msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context $options
Definition: hooks.txt:1020
$wgDisableCookieCheck
By default, MediaWiki checks if the client supports cookies during the login process, so that it can display an informative error message if cookies are disabled.
$res
Definition: database.txt:21
Class for handling updates to the site_stats table.
$wgBlockDisablesLogin
If true, blocked users will not be allowed to login.
MediaWiki exception.
Definition: MWException.php:26
makeLanguageSelectorLink($text, $lang)
Create a language selector link for a particular language Links back to this page preserving type and...
$cache
Definition: mcc.php:33
const IGNORE_USER_RIGHTS
Definition: User.php:84
$params
Implements Special:UserLogin.
getSkin()
Shortcut to get the skin being used for this instance.
wfDeprecated($function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes! ...
const DB_SLAVE
Definition: Defines.php:46
successfulLogin()
Run any hooks registered for logins, then HTTP redirect to $this->mReturnTo (or Main Page if that's un...
$wgUseMediaWikiUIEverywhere
Temporary variable that applies MediaWiki UI wherever it can be supported.
$wgNewPasswordExpiry
The time, in seconds, when an emailed temporary password expires.
hasSessionCookie()
Check if a session cookie is present.
renewSessionId()
Renew the user's session id, using strong entropy.
Allows to change the fields on the form that will be generated are created Can be used to omit specific feeds from being outputted You must not use this hook to add use OutputPage::addFeedLink() instead.&$feedLinks conditions will AND in the final query as a Content object as a Content object $title
Definition: hooks.txt:312
static linkKnown($target, $html=null, $customAttribs=[], $query=[], $options=[ 'known'])
Identical to link(), except $options defaults to 'known'.
Definition: Linker.php:255
static addUpdate(DeferrableUpdate $update, $type=self::POSTSEND)
Add an update to the deferred list.
WebRequest $mRequest
Effective request; set at the beginning of load.
static run($event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:131
const PROTO_RELATIVE
Definition: Defines.php:264
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add text
Definition: design.txt:12
$wgEnableUserEmail
Set to true to enable user-to-user e-mail.
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
static clearLoginThrottle($username)
Clear the login attempt throttle hit count for the (username,current IP) tuple.
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output modifiable & $code
Definition: hooks.txt:776
const PROTO_HTTP
Definition: Defines.php:262
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a local account $user
Definition: hooks.txt:242
$wgAccountCreationThrottle
Number of accounts each IP address may create, 0 to disable.
$wgRedirectOnLogin
Allow redirection to another page when a user logs in.
$wgEmailAuthentication
Require email authentication before sending mail to an email address.
successfulCreation()
Run any hooks registered for logins, then display a message welcoming the user.
$wgCookieExpiration
Default cookie lifetime, in seconds.
static incLoginThrottle($username)
Increment the login attempt throttle hit count for the (username,current IP) tuple unless the throttl...
static setLoginToken()
Formerly randomly generated a login token that would be returned by $this->getLoginToken().
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
$wgInvalidPasswordReset
Specifies if users should be sent to a password-reset form on login, if their password doesn't meet t...
this hook is for auditing only or null if authentication failed before getting that far $username
Definition: hooks.txt:776
error also a ContextSource you ll probably need to make sure the header is varied on $request
Definition: hooks.txt:2458
getName()
Get the name of this Special Page.
static string[] $validErrorMessages
Valid error and warning messages.
$wgMinimalPasswordLength
Specifies the minimal length of a user password.
getId()
Get the user's ID.
Definition: User.php:2114
showReturnToPage($type, $returnTo= '', $returnToQuery= '', $stickHTTPs=false)
Add a "return to" link or redirect to it.
getUser()
Shortcut to get the User executing this instance.
getConfig()
Shortcut to get main config object.
getTarget()
Get the target for this particular Block.
Definition: Block.php:1357
this hook is for auditing only WRONG_PASS
Definition: hooks.txt:1994
Show an error when a user tries to do something they do not have the necessary permissions for...
static incrementLoginThrottle($username)
Increment the login attempt throttle hit count for the (username,current IP) tuple unless the throttl...
getLanguage()
Shortcut to get user's language.
static clearLoginToken()
Remove any login token attached to the current session.
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as and the local content language as $wgContLang
Definition: design.txt:56
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set $status
Definition: hooks.txt:1020
MediaWiki Logger LoggerFactory implements a PSR[0] compatible message logging system Named Psr Log LoggerInterface instances can be obtained from the MediaWiki Logger LoggerFactory::getInstance() static method.MediaWiki\Logger\LoggerFactory expects a class implementing the MediaWiki\Logger\Spi interface to act as a factory for new Psr\Log\LoggerInterface instances.The"Spi"in MediaWiki\Logger\Spi stands for"service provider interface".An SPI is an API intended to be implemented or extended by a third party.This software design pattern is intended to enable framework extension and replaceable components.It is specifically used in the MediaWiki\Logger\LoggerFactory service to allow alternate PSR-3 logging implementations to be easily integrated with MediaWiki.The service provider interface allows the backend logging library to be implemented in multiple ways.The $wgMWLoggerDefaultSpi global provides the classname of the default MediaWiki\Logger\Spi implementation to be loaded at runtime.This can either be the name of a class implementing the MediaWiki\Logger\Spi with a zero argument const ructor or a callable that will return an MediaWiki\Logger\Spi instance.Alternately the MediaWiki\Logger\LoggerFactory MediaWiki Logger LoggerFactory
Definition: logger.txt:5
$count
executeReturnTo($type)
Add a "return to" link or redirect to it.
getFullTitle()
Return the full title, including $par.
$messages
static validateEmail($addr)
Does a string look like an e-mail address?
Definition: Sanitizer.php:1941
const TS_UNIX
Unix time - the number of seconds since 1970-01-01 00:00:00 UTC.
This serves as the entry point to the MediaWiki session handling system.
getRequest()
Get the WebRequest being used for this instance.
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached one of or reset my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled allows for interception of redirect & $returnTo
Definition: hooks.txt:2376
static factory($code)
Get a cached or new language object for a given language code.
Definition: Language.php:179
static getCreateaccountToken()
Get the createaccount token from the current session.
static clearCreateaccountToken()
Remove any createaccount token attached to the current session.
Definition: Block.php:22
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a local account incomplete not yet checked for validity & $retval
Definition: hooks.txt:242
if(is_null($wgLocalTZoffset)) if(!$wgDBerrorLogTZ) $wgRequest
Definition: Setup.php:663
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached one of or reset my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled allows for interception of redirect as a string mapping parameter names to values & $type
Definition: hooks.txt:2376
getByName()
Get the username of the blocking sysop.
Definition: Block.php:909
static newGood($value=null)
Factory function for good results.
Definition: Status.php:101
checkUserPasswordExpired(User $user)
Private function to check password expiration, until AuthManager comes along to handle that...
static getLoginToken()
Get the login token from the current session.
getPageTitle($subpage=false)
Get a self-referential title object.
$wgUser
Definition: Setup.php:801