55use Wikimedia\ScopedCallback;
111 private $reasonValidatorResult =
null;
144 protected function setRequest( array $data, $wasPosted =
null ) {
145 parent::setRequest( $data, $wasPosted );
146 $this->mLoadedRequest =
false;
152 private function loadRequestParameters() {
153 if ( $this->mLoadedRequest ) {
156 $this->mLoadedRequest =
true;
159 $this->mPosted = $request->wasPosted();
160 $this->mAction = $request->getRawVal(
'action' );
161 $this->mFromHTTP = $request->getBool(
'fromhttp',
false )
162 || $request->getBool(
'wpFromhttp',
false );
164 || ( !$this->mFromHTTP && $request->getProtocol() ===
'https' )
165 || $request->getBool(
'wpForceHttps',
false );
166 $this->mReturnTo = $request->getVal(
'returnto',
'' );
167 $this->mReturnToQuery = $request->getVal(
'returntoquery',
'' );
168 $this->mReturnToAnchor = $request->getVal(
'returntoanchor',
'' );
169 if ( $request->getRawVal(
'display' ) ===
'popup' ) {
170 $this->mDisplay =
'popup';
180 $this->loadRequestParameters();
181 if ( $this->mLoaded ) {
184 $this->mLoaded =
true;
187 $securityLevel = $this->
getRequest()->getText(
'force' );
198 $this->mToken = $request->getVal( $this->
getTokenName() );
201 $entryError = $this->
msg( $request->getVal(
'error',
'' ) );
202 $entryWarning = $this->
msg( $request->getVal(
'warning',
'' ) );
203 $entryNotice = $this->
msg( $request->getVal(
'notice',
'' ) );
208 $this->
msg(
'loginreqlink' )->text(),
215 if ( $entryError->exists()
216 && in_array( $entryError->getKey(), $validErrorMessages,
true )
218 $this->mEntryErrorType =
'error';
219 $this->mEntryError = $entryError->rawParams( $loginreqlink )->parse();
221 } elseif ( $entryWarning->exists()
222 && in_array( $entryWarning->getKey(), $validErrorMessages,
true )
224 $this->mEntryErrorType =
'warning';
225 $this->mEntryError = $entryWarning->rawParams( $loginreqlink )->parse();
226 } elseif ( $entryNotice->exists()
227 && in_array( $entryNotice->getKey(), $validErrorMessages,
true )
229 $this->mEntryErrorType =
'notice';
230 $this->mEntryError = $entryNotice->parse();
233 # 1. When switching accounts, it sucks to get automatically logged out
234 # 2. Do not return to PasswordReset after a successful password change
235 # but goto Wiki start page (Main_Page) instead ( T35997 )
236 $returnToTitle = Title::newFromText( $this->mReturnTo );
237 if ( is_object( $returnToTitle )
238 && ( $returnToTitle->isSpecial(
'Userlogout' )
239 || $returnToTitle->isSpecial(
'PasswordReset' ) )
241 $this->mReturnTo =
'';
242 $this->mReturnToQuery =
'';
248 $params = parent::getPreservedParams( $options );
252 $this->loadRequestParameters();
254 'returnto' =>
'mReturnTo',
255 'returntoquery' =>
'mReturnToQuery',
256 'returntoanchor' =>
'mReturnToAnchor',
258 foreach ( $properties as $key => $prop ) {
259 $value = $this->$prop;
260 if ( $value !==
'' ) {
268 $params[
'fromhttp'] = $this->mFromHTTP ?
'1' :
null;
270 if ( $this->mDisplay !==
'page' ) {
274 return array_filter(
$params,
static fn ( $val ) => $val !==
null );
279 $this->loadRequestParameters();
280 return parent::beforeExecute(
$subPage );
287 if ( $this->mPosted ) {
288 $time = microtime(
true );
289 $profilingScope =
new ScopedCallback(
function () use ( $time ) {
290 $time = microtime(
true ) - $time;
292 $stats->getTiming(
'auth_specialpage_executeTiming_seconds' )
293 ->setLabel(
'action', $this->authAction )
294 ->copyToStatsdAt(
"timing.login.ui.{$this->authAction}" )
295 ->observe( $time * 1000 );
300 $session = SessionManager::getGlobalSession();
307 $this->
getOutput()->disableClientCache();
312 if ( $this->mDisplay ===
'popup' ) {
317 $this->
getContext()->setSkin( $skinFactory->makeSkin(
'authentication-popup' ) );
324 if ( !$this->
isSignup() && !$authManager->canAuthenticateNow() ) {
325 if ( !$session->canSetUser() ) {
326 throw new ErrorPageError(
'cannotloginnow-title',
'cannotloginnow-text', [
327 $session->getProvider()->describe( $this->getLanguage() )
330 throw new ErrorPageError(
'cannotlogin-title',
'cannotlogin-text' );
331 } elseif ( $this->
isSignup() && !$authManager->canCreateAccounts() ) {
332 throw new ErrorPageError(
'cannotcreateaccount-title',
'cannotcreateaccount-text' );
353 if ( !$this->
isSignup() && !$this->mPosted && !$this->securityLevel &&
354 ( $this->mReturnTo !==
'' || $this->mReturnToQuery !==
'' ) &&
362 if ( $this->
getRequest()->getProtocol() !==
'https' ) {
366 ( $this->mEntryErrorType ===
'error' ?
'error'
367 :
'warning' ) => $this->mEntryError,
375 $this->
getOutput()->addVaryHeader(
'X-Forwarded-Proto' );
382 if ( str_starts_with(
$url,
'https://' ) ) {
383 $this->mSecureLoginUrl =
$url;
392 $this->
mainLoginForm( [],
'authpage-cannot-' . $this->authAction );
396 if ( $this->canBypassForm( $button_name ) ) {
399 if ( $button_name ) {
400 $this->
getRequest()->setVal( $button_name,
true );
406 if ( !$status || !$status->isGood() ) {
407 $this->
mainLoginForm( $this->authRequests, $status ? $status->getMessage() :
'',
'error' );
412 $response = $status->getValue();
416 switch ( $response->status ) {
417 case AuthenticationResponse::PASS:
419 $this->proxyAccountCreation = $this->
isSignup() && $this->
getUser()->isNamed();
420 $this->targetUser = User::newFromName( $response->username );
423 !$this->proxyAccountCreation
424 && $response->loginRequest
425 && $authManager->canAuthenticateNow()
428 $response2 = $authManager->beginAuthentication( [ $response->loginRequest ],
430 if ( $response2->status !== AuthenticationResponse::PASS ) {
431 LoggerFactory::getInstance(
'login' )
432 ->error(
'Could not log in after account creation' );
433 $this->
successfulAction(
true, Status::newFatal(
'createacct-loginerror' ) );
438 if ( !$this->proxyAccountCreation ) {
439 $context = RequestContext::getMain();
441 if ( $context !== $localContext ) {
451 case AuthenticationResponse::FAIL:
453 case AuthenticationResponse::RESTART:
454 $this->authForm =
null;
455 if ( $response->status === AuthenticationResponse::FAIL ) {
457 $messageType =
'error';
460 $messageType =
'warning';
462 $this->
logAuthResult(
false, $performer, $response->message ? $response->message->getKey() :
'-' );
464 $this->
mainLoginForm( $this->authRequests, $response->message, $messageType );
466 case AuthenticationResponse::REDIRECT:
467 $this->authForm =
null;
468 $this->
getOutput()->redirect( $response->redirectTarget );
470 case AuthenticationResponse::UI:
471 $this->authForm =
null;
472 $this->authAction = $this->
isSignup() ? AuthManager::ACTION_CREATE_CONTINUE
473 : AuthManager::ACTION_LOGIN_CONTINUE;
474 $this->authRequests = $response->neededRequests;
475 $this->
mainLoginForm( $response->neededRequests, $response->message, $response->messageType );
478 throw new LogicException(
'invalid AuthenticationResponse' );
495 private function canBypassForm( &$button_name ) {
500 $fields = AuthenticationRequest::mergeFieldInfo( $this->authRequests );
501 foreach ( $fields as $fieldname => $field ) {
502 if ( !isset( $field[
'type'] ) ) {
505 if ( !empty( $field[
'skippable'] ) ) {
508 if ( $field[
'type'] ===
'button' ) {
509 if ( $button_name !==
null ) {
513 $button_name = $fieldname;
515 } elseif ( $field[
'type'] !==
'null' ) {
532 $type, $title, $msgname, $injected_html, $extraMessages
535 if ( is_string( $title ) ) {
536 wfDeprecated( __METHOD__ .
' with string title',
'1.41' );
537 $title = (
new RawMessage(
'$1' ) )->rawParams( $title );
539 $out->setPageTitleMsg( $title );
543 if ( $extraMessages ) {
544 $extraMessages = Status::wrap( $extraMessages );
545 $out->addWikiTextAsInterface(
546 $extraMessages->getWikiText(
false,
false, $this->getLanguage() )
550 $out->addHTML( $injected_html );
553 $helper->showReturnToPage( $type, $this->mReturnTo, $this->mReturnToQuery,
554 $this->mStickHTTPS, $this->mReturnToAnchor );
570 protected function mainLoginForm( array $requests, $msg =
'', $msgtype =
'error' ) {
578 $this->authForm =
null;
580 ->getAuthenticationRequests( $this->authAction, $user );
584 $out->addModuleStyles( [
585 'mediawiki.special.userlogin.common.styles',
586 'mediawiki.codex.messagebox.styles'
590 $out->addModules(
'mediawiki.special.createaccount' );
591 $out->addModuleStyles( [
592 'mediawiki.special.userlogin.signup.styles'
596 $out->addModuleStyles( [
597 'mediawiki.special.userlogin.login.styles'
600 $out->disallowUserJs();
602 $form = $this->
getAuthForm( $requests, $this->authAction );
603 $form->prepareForm();
605 $submitStatus = Status::newGood();
606 if ( $msg && $msgtype ===
'warning' ) {
607 $submitStatus->warning( $msg );
608 } elseif ( $msg && $msgtype ===
'error' ) {
609 $submitStatus->fatal( $msg );
615 $this->
getUser()->isRegistered() &&
617 $this->authAction !== AuthManager::ACTION_LOGIN_CONTINUE
619 $reauthMessage = $this->securityLevel ?
'userlogin-reauth' :
'userlogin-loggedin';
620 $submitStatus->warning( $reauthMessage, $this->
getUser()->
getName() );
623 $formHtml = $form->getHTML( $submitStatus );
635 $loginPrompt = $this->
isSignup() ?
'' : Html::rawElement(
'div',
636 [
'id' =>
'userloginprompt' ], $this->
msg(
'loginprompt' )->parseAsBlock() );
639 $signupStartMsg = $this->
msg(
'signupstart' );
640 $signupStart = ( $this->
isSignup() && !$signupStartMsg->isDisabled() )
641 ? Html::rawElement(
'div', [
'id' =>
'signupstart' ], $signupStartMsg->parseAsBlock() ) :
'';
642 if ( $languageLinks ) {
643 $languageLinks = Html::rawElement(
'div', [
'id' =>
'languagelinks' ],
644 Html::rawElement(
'p', [], $languageLinks )
647 if ( $this->
getUser()->isTemp() ) {
652 $formBlock = Html::rawElement(
'div', [
'id' =>
'userloginForm' ], $formHtml );
653 $formAndBenefits = $formBlock;
655 $benefitsContainerHtml =
null;
661 'beforeForm' =>
false,
664 $benefitsContainerHtml, $info, $options
667 $formAndBenefits = $options[
'beforeForm']
668 ? ( $benefitsContainerHtml . $formBlock )
669 : ( $formBlock . $benefitsContainerHtml );
676 . Html::rawElement(
'div', [
'class' =>
'mw-ui-container' ],
689 $benefitsContainer =
'';
690 $this->
getOutput()->addModuleStyles( [
'oojs-ui.styles.icons-user' ] );
692 if ( !$this->
getUser()->isTemp() ) {
699 for ( $benefitIdx = 1; $benefitIdx <= $benefitCount; $benefitIdx++ ) {
700 $headUnescaped = $this->
msg(
"createacct-benefit-head$benefitIdx" )->text();
701 $iconClass = $this->
msg(
"createacct-benefit-icon$benefitIdx" )->text();
702 $benefitList .= Html::rawElement(
'div', [
'class' =>
"mw-number-text $iconClass" ],
703 Html::rawElement(
'span', [],
704 $this->
msg(
"createacct-benefit-head$benefitIdx" )->escaped()
706 . Html::rawElement(
'p', [],
707 $this->
msg(
"createacct-benefit-body$benefitIdx" )->params( $headUnescaped )->escaped()
711 $benefitsContainer = Html::rawElement(
'div', [
'class' =>
'mw-createacct-benefits-container' ],
712 Html::rawElement(
'div', [
'class' =>
'mw-createacct-benefits-heading' ],
713 $this->
msg(
'createacct-benefit-heading' )->escaped()
715 . Html::rawElement(
'div', [
'class' =>
'mw-createacct-benefits-list' ], $benefitList )
721 'oojs-ui.styles.icons-moderation',
722 'oojs-ui.styles.icons-interactions',
727 'icon' =>
'oo-ui-icon-unStar',
728 'description' => $this->
msg(
"benefit-1-description" )->escaped()
731 'icon' =>
'oo-ui-icon-userContributions',
732 'description' => $this->
msg(
"benefit-2-description" )->escaped()
735 'icon' =>
'oo-ui-icon-settings',
736 'description' => $this->
msg(
"benefit-3-description" )->escaped()
739 foreach ( $benefits as $benefit ) {
740 $benefitContent = Html::rawElement(
'div', [
'class' =>
'mw-benefit-item' ],
741 Html::rawElement(
'span', [
'class' => $benefit[
'icon' ] ] )
742 . Html::rawElement(
'p', [], $benefit[
'description'] )
745 $benefitList .= Html::rawElement(
746 'div', [
'class' =>
'mw-benefit-item-wrapper' ], $benefitContent );
749 $benefitsListWrapper = Html::rawElement(
750 'div', [
'class' =>
'mw-benefit-list-wrapper' ], $benefitList );
752 $headingSubheadingWrapper = Html::rawElement(
'div', [
'class' =>
'mw-heading-subheading-wrapper' ],
753 Html::rawElement(
'h2', [], $this->
msg(
'createacct-benefit-heading-temp-user' )->escaped() )
754 . Html::rawElement(
'p', [
'class' =>
'mw-benefit-subheading' ], $this->
msg(
755 'createacct-benefit-subheading-temp-user' )->escaped() )
758 $benefitsContainer = Html::rawElement(
759 'div', [
'class' =>
'mw-createacct-benefits-container' ],
760 $headingSubheadingWrapper
761 . $benefitsListWrapper
765 return $benefitsContainer;
777 if ( $this->authForm ) {
778 return $this->authForm;
781 $usingHTTPS = $this->getRequest()->getProtocol() ===
'https';
784 $fieldInfo = AuthenticationRequest::mergeFieldInfo( $requests );
786 $formDescriptor = $this->fieldInfoToFormDescriptor( $requests, $fieldInfo, $this->authAction );
787 $this->postProcessFormDescriptor( $formDescriptor, $requests );
789 $context = $this->getContext();
790 if ( $context->getRequest() !== $this->getRequest() ) {
793 $context->setRequest( $this->getRequest() );
795 $form = HTMLForm::factory(
'codex', $formDescriptor, $context );
797 $form->addHiddenField(
'authAction', $this->authAction );
798 $form->addHiddenField(
'force', $this->securityLevel );
799 $form->addHiddenField( $this->getTokenName(), $this->getToken()->toString() );
800 $config = $this->getConfig();
804 if ( !$this->isSignup() ) {
805 $form->addHiddenField(
'wpForceHttps', (
int)$this->mStickHTTPS );
806 $form->addHiddenField(
'wpFromhttp', $usingHTTPS );
810 $form->setAction( $this->getPageTitle()->getLocalURL( $this->getPreservedParams(
814 $form->setName(
'userlogin' . ( $this->isSignup() ?
'2' :
'' ) );
815 if ( $this->isSignup() ) {
816 $form->setId(
'userlogin2' );
819 $form->suppressDefaultSubmit();
821 $this->authForm = $form;
828 array $requests, array $fieldInfo, array &$formDescriptor, $action
830 $formDescriptor = self::mergeDefaultFormDescriptor( $fieldInfo, $formDescriptor,
831 $this->getFieldDefinitions( $fieldInfo, $requests ) );
841 return $this->authAction !== $this->getContinueAction( $this->authAction )
842 && !$this->securityLevel;
854 $isLoggedIn = $this->getUser()->isRegistered();
855 $continuePart = $this->isContinued() ?
'continue-' :
'';
856 $anotherPart = $isLoggedIn ?
'another-' :
'';
858 $expiration = $this->getRequest()->getSession()->getProvider()->getRememberUserDuration();
859 $expirationDays = ceil( $expiration / ( 3600 * 24 ) );
860 $secureLoginLink =
'';
861 if ( $this->mSecureLoginUrl ) {
862 $secureLoginLink = Html::rawElement(
'a', [
863 'href' => $this->mSecureLoginUrl,
864 'class' =>
'mw-login-flush-right mw-secure',
865 ],
Html::element(
'span', [
'class' =>
'mw-secure--icon' ] ) .
866 $this->msg(
'userlogin-signwithsecure' )->parse() );
868 $usernameHelpLink =
'';
869 if ( !$this->msg(
'createacct-helpusername' )->isDisabled() ) {
870 $usernameHelpLink = Html::rawElement(
'span', [
871 'class' =>
'mw-login-flush-right',
872 ], $this->msg(
'createacct-helpusername' )->parse() );
875 if ( $this->isSignup() ) {
876 $config = $this->getConfig();
877 $hideIf = isset( $fieldInfo[
'mailpassword'] ) ? [
'hide-if' => [
'===',
'mailpassword',
'1' ] ] : [];
878 $fieldDefinitions = [
880 'label-raw' => $this->msg(
'userlogin-yourname' )->escaped() . $usernameHelpLink,
882 'placeholder-message' => $isLoggedIn ?
'createacct-another-username-ph'
883 :
'userlogin-yourname-ph',
888 'label-message' =>
'createaccountmail',
889 'name' =>
'wpCreateaccountMail',
890 'id' =>
'wpCreateaccountMail',
893 'id' =>
'wpPassword2',
894 'autocomplete' =>
'new-password',
895 'placeholder-message' =>
'createacct-yourpassword-ph',
896 'help-message' =>
'createacct-useuniquepass',
900 'type' =>
'password',
901 'label-message' =>
'createacct-yourpasswordagain',
903 'cssclass' =>
'loginPassword',
905 'autocomplete' =>
'new-password',
906 'validation-callback' =>
function ( $value, $alldata ) {
907 if ( empty( $alldata[
'mailpassword'] ) && !empty( $alldata[
'password'] ) ) {
909 return $this->msg(
'htmlform-required' );
910 } elseif ( $value !== $alldata[
'password'] ) {
911 return $this->msg(
'badretype' );
916 'placeholder-message' =>
'createacct-yourpasswordagain-ph',
921 ?
'createacct-emailrequired' :
'createacct-emailoptional',
923 'cssclass' =>
'loginText',
926 'autocomplete' =>
'email',
929 'validation-callback' =>
function ( $value, $alldata ) {
937 return $this->msg(
'noemailtitle' );
938 } elseif ( !$value && !empty( $alldata[
'mailpassword'] ) ) {
940 return $this->msg(
'noemailcreate' );
941 } elseif ( $value && !Sanitizer::validateEmail( $value ) ) {
942 return $this->msg(
'invalidemailaddress' );
943 } elseif ( is_string( $value ) && strlen( $value ) > 255 ) {
944 return $this->msg(
'changeemail-maxlength' );
951 'placeholder-message' =>
'createacct-' . $anotherPart .
'email-ph',
955 'help-message' => $isLoggedIn ?
'createacct-another-realname-tip'
956 :
'prefs-help-realname',
957 'label-message' =>
'createacct-realname',
958 'cssclass' =>
'loginText',
960 'placeholder-message' =>
'createacct-realname',
961 'id' =>
'wpRealName',
962 'autocomplete' =>
'name',
967 'label-message' =>
'createacct-reason',
968 'cssclass' =>
'loginText',
971 'validation-callback' =>
function ( $value, $alldata ) {
974 if ( $value && Sanitizer::validateEmail( $value ) ) {
975 if ( $this->reasonValidatorResult !==
null ) {
976 return $this->reasonValidatorResult;
978 $this->reasonValidatorResult =
true;
980 if ( !$authManager->getAuthenticationSessionData(
'reason-retry',
false ) ) {
981 $authManager->setAuthenticationSessionData(
'reason-retry',
true );
982 $this->reasonValidatorResult = $this->msg(
'createacct-reason-confirm' );
984 return $this->reasonValidatorResult;
988 'placeholder-message' =>
'createacct-reason-ph',
998 'default' => $this->msg(
'createacct-' . $anotherPart . $continuePart .
1000 'name' =>
'wpCreateaccount',
1001 'id' =>
'wpCreateaccount',
1005 if ( !$this->msg(
'createacct-username-help' )->isDisabled() ) {
1006 $fieldDefinitions[
'username'][
'help-message'] =
'createacct-username-help';
1012 $passwordRequest = AuthenticationRequest::getRequestByClass( $this->authRequests,
1013 PasswordAuthenticationRequest::class );
1014 $changePassword = $passwordRequest && $passwordRequest->action == AuthManager::ACTION_CHANGE;
1015 $fieldDefinitions = [
1018 'label-raw' => $this->msg(
'userlogin-yourname' )->escaped() . $secureLoginLink,
1020 'placeholder-message' =>
'userlogin-yourname-ph',
1021 ] + ( $changePassword ? [
1024 'baseField' =>
'password',
1027 'cssclass' =>
'mw-htmlform-hidden-field',
1032 'autocomplete' =>
'new-password',
1033 'placeholder-message' =>
'createacct-yourpassword-ph',
1034 'help-message' =>
'createacct-useuniquepass',
1036 'id' =>
'wpPassword1',
1037 'autocomplete' =>
'current-password',
1038 'placeholder-message' =>
'userlogin-yourpassword-ph',
1042 'type' =>
'password',
1043 'autocomplete' =>
'new-password',
1044 'placeholder-message' =>
'createacct-yourpasswordagain-ph',
1050 'cssclass' =>
'mw-userlogin-rememberme',
1051 'name' =>
'wpRemember',
1052 'label-message' => $this->msg(
'userlogin-remembermypassword' )
1053 ->numParams( $expirationDays ),
1054 'id' =>
'wpRemember',
1062 'default' => $this->msg(
'pt-login-' . $continuePart .
'button' )->text(),
1063 'id' =>
'wpLoginAttempt',
1066 'linkcontainer' => [
1069 'cssclass' =>
'mw-form-related-link-container mw-userlogin-help',
1074 ->inContentLanguage()
1076 ], $this->msg(
'userlogin-helplink2' )->text() ),
1090 $isUsernameOrPasswordRequest =
1091 AuthenticationRequest::getRequestByClass( $requests, UsernameAuthenticationRequest::class ) ||
1092 AuthenticationRequest::getRequestByClass( $requests, PasswordAuthenticationRequest::class );
1094 if ( $isUsernameOrPasswordRequest ) {
1095 $fieldDefinitions[
'username'] += [
1098 'cssclass' =>
'loginText mw-userlogin-username',
1100 'autocomplete' =>
'username',
1103 $fieldDefinitions[
'password'] += [
1104 'type' =>
'password',
1106 'name' =>
'wpPassword',
1107 'cssclass' =>
'loginPassword mw-userlogin-password',
1113 if ( $this->mEntryError ) {
1115 if ( $this->mEntryErrorType ===
'error' ) {
1116 $defaultHtml = Html::errorBox( $this->mEntryError );
1117 } elseif ( $this->mEntryErrorType ===
'warning' ) {
1118 $defaultHtml = Html::warningBox( $this->mEntryError );
1119 } elseif ( $this->mEntryErrorType ===
'notice' ) {
1120 $defaultHtml = Html::noticeBox( $this->mEntryError,
'' );
1122 $fieldDefinitions[
'entryError'] = [
1124 'default' => $defaultHtml,
1130 if ( !$this->showExtraInformation() ) {
1131 unset( $fieldDefinitions[
'linkcontainer'], $fieldDefinitions[
'signupend'] );
1133 if ( $this->isSignup() && $this->showExtraInformation() ) {
1136 $signupendMsg = $this->msg(
'signupend' );
1137 $signupendHttpsMsg = $this->msg(
'signupend-https' );
1138 if ( !$signupendMsg->isDisabled() ) {
1139 $usingHTTPS = $this->getRequest()->getProtocol() ===
'https';
1140 $signupendText = ( $usingHTTPS && !$signupendHttpsMsg->isBlank() )
1141 ? $signupendHttpsMsg->parse() : $signupendMsg->parse();
1142 $fieldDefinitions[
'signupend'] = [
1145 'default' => Html::rawElement(
'div', [
'id' =>
'signupend' ], $signupendText ),
1150 if ( !$this->isSignup() && $this->showExtraInformation() ) {
1152 if ( $passwordReset->isAllowed( $this->getUser() )->isGood() ) {
1153 $fieldDefinitions[
'passwordReset'] = [
1156 'cssclass' =>
'mw-form-related-link-container',
1157 'default' => $this->getLinkRenderer()->makeLink(
1159 $this->msg(
'userlogin-resetpassword-link' )->text()
1166 if ( $this->showCreateAccountLink() ) {
1168 $linkTitle = $this->getTitleFor( $this->isSignup() ?
'Userlogin' :
'CreateAccount' );
1169 $linkq =
wfArrayToCgi( $this->getPreservedParams( [
'reset' =>
true ] ) );
1170 $isLoggedIn = $this->getUser()->isRegistered()
1171 && !$this->getUser()->isTemp();
1173 $fieldDefinitions[
'createOrLogin'] = [
1176 'linkQuery' => $linkq,
1177 'default' =>
function (
$params ) use ( $isLoggedIn, $linkTitle ) {
1178 $buttonClasses =
'cdx-button cdx-button--action-progressive '
1179 .
'cdx-button--fake-button cdx-button--fake-button--enabled';
1181 return Html::rawElement(
'div',
1184 [
'id' =>
'mw-createaccount' . ( !$isLoggedIn ?
'-cta' :
'' ),
1185 'class' => ( $isLoggedIn ?
'mw-form-related-link-container' :
'mw-ui-vform-field' ) ],
1186 ( $isLoggedIn ?
'' : $this->msg(
'userlogin-noaccount' )->escaped() )
1191 'id' =>
'mw-createaccount-join' . ( $isLoggedIn ?
'-loggedin' :
'' ),
1192 'href' => $linkTitle->getLocalURL(
$params[
'linkQuery'] ),
1193 'class' => [
'mw-authentication-popup-link', $buttonClasses => !$isLoggedIn ],
1194 'target' =>
'_self',
1198 $isLoggedIn ?
'userlogin-createanother' :
'userlogin-joinproject'
1208 return $fieldDefinitions;
1232 private function showCreateAccountLink() {
1233 return $this->isSignup() ||
1234 $this->getContext()->getAuthority()->isAllowed(
'createaccount' );
1238 return $this->isSignup() ?
'wpCreateaccountToken' :
'wpLoginToken';
1248 $msg = $this->msg(
'loginlanguagelinks' )->inContentLanguage();
1249 if ( $msg->isBlank() ) {
1252 $langs = explode(
"\n", $msg->text() );
1254 foreach ( $langs as $lang ) {
1255 $lang = trim( $lang,
'* ' );
1256 $parts = explode(
'|', $lang );
1257 if ( count( $parts ) >= 2 ) {
1258 $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) );
1262 return count( $links ) > 0 ? $this->msg(
'loginlanguagelabel' )->rawParams(
1263 $this->getLanguage()->pipeList( $links ) )->escaped() :
'';
1277 if ( $this->getLanguage()->getCode() == $lang
1278 || !$services->getLanguageNameUtils()->isValidCode( $lang )
1282 return htmlspecialchars( $text );
1285 $query = $this->getPreservedParams();
1286 $query[
'uselang'] = $lang;
1289 $targetLanguage = $services->getLanguageFactory()->getLanguage( $lang );
1290 $attr[
'lang'] = $attr[
'hreflang'] = $targetLanguage->getHtmlCode();
1291 $attr[
'class'] =
'mw-authentication-popup-link';
1292 $attr[
'title'] =
false;
1294 return $this->getLinkRenderer()->makeKnownLink(
1295 $this->getPageTitle(),
1313 isset( $formDescriptor[
'username'] ) &&
1314 !isset( $formDescriptor[
'username'][
'default'] ) &&
1317 $user = $this->getUser();
1318 if ( $user->isRegistered() && !$user->isTemp() ) {
1319 $formDescriptor[
'username'][
'default'] = $user->getName();
1321 $formDescriptor[
'username'][
'default'] =
1322 $this->getRequest()->getSession()->suggestLoginUsername();
1328 if ( !$this->needsSubmitButton( $requests ) ) {
1329 unset( $formDescriptor[
'createaccount'], $formDescriptor[
'loginattempt'] );
1332 if ( !$this->isSignup() ) {
1336 isset( $formDescriptor[
'username'] )
1337 && empty( $formDescriptor[
'username'][
'default'] )
1338 && !$this->getRequest()->getCheck(
'wpName' )
1340 $formDescriptor[
'username'][
'autofocus'] =
true;
1341 } elseif ( isset( $formDescriptor[
'password'] ) ) {
1342 $formDescriptor[
'password'][
'autofocus'] =
true;
1346 $this->addTabIndex( $formDescriptor );
1355 $noticeContent = $this->msg(
'createacct-temp-warning', $this->getUser()->getName() )->parse();
1356 return Html::noticeBox(
1358 'mw-createaccount-temp-warning',
1360 'mw-userLogin-icon--user-temporary'
1367class_alias( LoginSignupSpecialPage::class,
'LoginSignupSpecialPage' );
wfEscapeWikiText( $input)
Escapes the given text so that it may be output using addWikiText() without any linking,...
wfAppendQuery( $url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
global $wgInitialSessionId
array $params
The job parameters.
An error page which can definitely be safely rendered using the OutputPage.
Abort the web request with a custom HTML string that will represent the entire response.
Helper functions for the login form that need to be shared with other special pages (such as CentralA...
static getValidErrorMessages()
Returns an array of all valid error messages.
An IContextSource implementation which will inherit context from another source but allow individual ...
Group all the pieces relevant to the context of a request into one instance.
A class containing constants representing the names of configuration variables.
const LoginLanguageSelector
Name constant for the LoginLanguageSelector setting, for use with Config::get()
const ForceHTTPS
Name constant for the ForceHTTPS setting, for use with Config::get()
const EmailConfirmToEdit
Name constant for the EmailConfirmToEdit setting, for use with Config::get()
const SecureLogin
Name constant for the SecureLogin setting, for use with Config::get()
A special page subclass for authentication-related special pages.
string $subPage
Subpage of the special page.
getToken()
Returns the CSRF token.
getContinueAction( $action)
Gets the _CONTINUE version of an action.
isContinued()
Returns true if this is not the first step of the authentication.
isActionAllowed( $action)
Checks whether AuthManager is ready to perform the action.
trySubmit()
Attempts to do an authentication step with the submitted data.
loadAuth( $subPage, $authAction=null, $reset=false)
Load or initialize $authAction, $authRequests and $subPage.
getDefaultAction( $subPage)
Get the default action for this special page if none is given via URL/POST data.
getRequest()
Get the WebRequest being used for this instance.
Holds shared logic for login and account creation pages.
setRequest(array $data, $wasPosted=null)
Override the POST data, GET data from the real request is preserved.
postProcessFormDescriptor(&$formDescriptor, $requests)
makeLanguageSelectorLink( $text, $lang)
Create a language selector link for a particular language Links back to this page preserving type and...
string string $mReturnToAnchor
The fragment part of the URL to return to after authentication finishes.
beforeExecute( $subPage)
Gets called before.SpecialPage::execute. Return false to prevent calling execute() (since 1....
string null $mSecureLoginUrl
showSuccessPage( $type, $title, $msgname, $injected_html, $extraMessages)
Show the success page.
getAuthForm(array $requests, $action)
Generates a form from the given request.
getTokenName()
Returns the name of the CSRF token (under which it should be found in the POST or GET data).
getBenefitsContainerHtml()
The HTML to be shown in the "benefits to signing in / creating an account" section of the signup/logi...
mainLoginForm(array $requests, $msg='', $msgtype='error')
getPreservedParams( $options=[])
Returns URL query parameters which should be preserved between authentication requests....
logAuthResult( $success, UserIdentity $performer, $status=null)
Logs to the authmanager-stats channel.
bool $proxyAccountCreation
True if the user if creating an account for someone else.
showExtraInformation()
Show extra information such as password recovery information, link from login to signup,...
string string $mReturnToQuery
The query string part of the URL to return to after authentication finishes.
onAuthChangeFormFields(array $requests, array $fieldInfo, array &$formDescriptor, $action)
Change the form descriptor that determines how a field will look in the authentication form....
makeLanguageSelector()
Produce a bar of links which allow the user to select another language during login/registration but ...
successfulAction( $direct=false, $extraMessages=null)
string string $mReturnTo
The title of the page to return to after authentication finishes, or the empty string when there is n...
getNoticeHtml()
Generates the HTML for a notice box to be displayed to a temporary user.
hasSessionCookie()
Check if a session cookie is present.
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
getFieldDefinitions(array $fieldInfo, array $requests)
Create a HTMLForm descriptor for the core login fields.
getPageHtml( $formHtml)
Add page elements which are outside the form.
User $targetUser
FIXME another flag for passing data.
load( $subPage)
Load data from request.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
getUser()
Shortcut to get the User executing this instance.
getPageTitle( $subpage=false)
Get a self-referential title object.
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
getConfig()
Shortcut to get main config object.
getContext()
Gets the context this SpecialPage is executed in.
setContext( $context)
Sets the context this SpecialPage is executed in.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getOutput()
Get the OutputPage being used for this instance.
getName()
Get the canonical, unlocalized name of this special page without namespace.
getFullTitle()
Return the full title, including $par.
Show an error when a user tries to do something they do not have the necessary permissions for.
Show an error when the wiki is locked/read-only and the user tries to do something that requires writ...
The base class for all skins.
static makeInternalOrExternalUrl( $name)
If url string starts with http, consider as external URL, else internal.
Generic operation result class Has warning/error list, boolean status and arbitrary value.