53use Wikimedia\ScopedCallback;
76 private $reasonValidatorResult =
null;
99 abstract protected function successfulAction( $direct =
false, $extraMessages =
null );
108 protected function setRequest( array $data, $wasPosted =
null ) {
109 parent::setRequest( $data, $wasPosted );
110 $this->mLoadedRequest =
false;
116 private function loadRequestParameters() {
117 if ( $this->mLoadedRequest ) {
120 $this->mLoadedRequest =
true;
123 $this->mPosted = $request->wasPosted();
124 $this->mAction = $request->getRawVal(
'action' );
125 $this->mFromHTTP = $request->getBool(
'fromhttp',
false )
126 || $request->getBool(
'wpFromhttp',
false );
128 || ( !$this->mFromHTTP && $request->getProtocol() ===
'https' )
129 || $request->getBool(
'wpForceHttps',
false );
130 $this->mLanguage = $request->getText(
'uselang' );
131 $this->mVariant = $request->getText(
'variant' );
132 $this->mReturnTo = $request->getVal(
'returnto',
'' );
133 $this->mReturnToQuery = $request->getVal(
'returntoquery',
'' );
142 $this->loadRequestParameters();
143 if ( $this->mLoaded ) {
146 $this->mLoaded =
true;
149 $securityLevel = $this->
getRequest()->getText(
'force' );
160 $this->mToken = $request->getVal( $this->
getTokenName() );
163 $entryError = $this->
msg( $request->getVal(
'error',
'' ) );
164 $entryWarning = $this->
msg( $request->getVal(
'warning',
'' ) );
169 $this->
msg(
'loginreqlink' )->text(),
172 'returnto' => $this->mReturnTo,
173 'returntoquery' => $this->mReturnToQuery,
174 'uselang' => $this->mLanguage ?:
null,
175 'variant' => $this->mVariant ?:
null,
177 $this->mFromHTTP ?
'1' :
null,
182 if ( $entryError->exists()
185 $this->mEntryErrorType =
'error';
186 $this->mEntryError = $entryError->rawParams( $loginreqlink )->parse();
188 } elseif ( $entryWarning->exists()
191 $this->mEntryErrorType =
'warning';
192 $this->mEntryError = $entryWarning->rawParams( $loginreqlink )->parse();
195 # 1. When switching accounts, it sucks to get automatically logged out
196 # 2. Do not return to PasswordReset after a successful password change
197 # but goto Wiki start page (Main_Page) instead ( T35997 )
198 $returnToTitle = Title::newFromText( $this->mReturnTo );
199 if ( is_object( $returnToTitle )
200 && ( $returnToTitle->isSpecial(
'Userlogout' )
201 || $returnToTitle->isSpecial(
'PasswordReset' ) )
203 $this->mReturnTo =
'';
204 $this->mReturnToQuery =
'';
209 $params = parent::getPreservedParams( $withToken );
211 'returnto' => $this->mReturnTo ?:
null,
212 'returntoquery' => $this->mReturnToQuery ?:
null,
215 $params[
'fromhttp'] = $this->mFromHTTP ?
'1' :
null;
222 $this->loadRequestParameters();
223 return parent::beforeExecute(
$subPage );
231 if ( $this->mPosted ) {
232 $time = microtime(
true );
233 $profilingScope =
new ScopedCallback(
function () use ( $time ) {
234 $time = microtime(
true ) - $time;
236 $stats->getTiming(
'auth_specialpage_executeTiming_seconds' )
237 ->setLabel(
'action', $this->authAction )
238 ->copyToStatsdAt(
"timing.login.ui.{$this->authAction}" )
239 ->observe( $time * 1000 );
244 $session = SessionManager::getGlobalSession();
251 $this->
getOutput()->disableClientCache();
258 if ( !$this->
isSignup() && !$authManager->canAuthenticateNow() ) {
259 if ( !$session->canSetUser() ) {
260 throw new ErrorPageError(
'cannotloginnow-title',
'cannotloginnow-text', [
261 $session->getProvider()->describe( $this->getLanguage() )
264 throw new ErrorPageError(
'cannotlogin-title',
'cannotlogin-text' );
265 } elseif ( $this->
isSignup() && !$authManager->canCreateAccounts() ) {
266 throw new ErrorPageError(
'cannotcreateaccount-title',
'cannotcreateaccount-text' );
287 if ( !$this->
isSignup() && !$this->mPosted && !$this->securityLevel &&
288 ( $this->mReturnTo !==
'' || $this->mReturnToQuery !==
'' ) &&
296 if ( $this->
getRequest()->getProtocol() !==
'https' ) {
300 ( $this->mEntryErrorType ===
'error' ?
'error'
301 :
'warning' ) => $this->mEntryError,
303 $url = $title->getFullURL( $query,
false,
PROTO_HTTPS );
309 $this->
getOutput()->addVaryHeader(
'X-Forwarded-Proto' );
316 if ( str_starts_with( $url,
'https://' ) ) {
317 $this->mSecureLoginUrl = $url;
326 $this->
mainLoginForm( [],
'authpage-cannot-' . $this->authAction );
330 if ( $this->canBypassForm( $button_name ) ) {
333 if ( $button_name ) {
334 $this->
getRequest()->setVal( $button_name,
true );
340 if ( !$status || !$status->isGood() ) {
341 $this->
mainLoginForm( $this->authRequests, $status ? $status->getMessage() :
'',
'error' );
346 $response = $status->getValue();
350 switch ( $response->status ) {
351 case AuthenticationResponse::PASS:
353 $this->proxyAccountCreation = $this->
isSignup() && $this->
getUser()->isNamed();
354 $this->targetUser = User::newFromName( $response->username );
357 !$this->proxyAccountCreation
358 && $response->loginRequest
359 && $authManager->canAuthenticateNow()
362 $response2 = $authManager->beginAuthentication( [ $response->loginRequest ],
364 if ( $response2->status !== AuthenticationResponse::PASS ) {
365 LoggerFactory::getInstance(
'login' )
366 ->error(
'Could not log in after account creation' );
367 $this->
successfulAction(
true, Status::newFatal(
'createacct-loginerror' ) );
372 if ( !$this->proxyAccountCreation ) {
373 $context = RequestContext::getMain();
375 if ( $context !== $localContext ) {
385 case AuthenticationResponse::FAIL:
387 case AuthenticationResponse::RESTART:
388 unset( $this->authForm );
389 if ( $response->status === AuthenticationResponse::FAIL ) {
391 $messageType =
'error';
394 $messageType =
'warning';
396 $this->
logAuthResult(
false, $response->message ? $response->message->getKey() :
'-' );
398 $this->
mainLoginForm( $this->authRequests, $response->message, $messageType );
400 case AuthenticationResponse::REDIRECT:
401 unset( $this->authForm );
402 $this->
getOutput()->redirect( $response->redirectTarget );
404 case AuthenticationResponse::UI:
405 unset( $this->authForm );
406 $this->authAction = $this->
isSignup() ? AuthManager::ACTION_CREATE_CONTINUE
407 : AuthManager::ACTION_LOGIN_CONTINUE;
408 $this->authRequests = $response->neededRequests;
409 $this->
mainLoginForm( $response->neededRequests, $response->message, $response->messageType );
412 throw new LogicException(
'invalid AuthenticationResponse' );
429 private function canBypassForm( &$button_name ) {
434 $fields = AuthenticationRequest::mergeFieldInfo( $this->authRequests );
435 foreach ( $fields as $fieldname => $field ) {
436 if ( !isset( $field[
'type'] ) ) {
439 if ( !empty( $field[
'skippable'] ) ) {
442 if ( $field[
'type'] ===
'button' ) {
443 if ( $button_name !==
null ) {
447 $button_name = $fieldname;
449 } elseif ( $field[
'type'] !==
'null' ) {
466 $type, $title, $msgname, $injected_html, $extraMessages
469 if ( is_string( $title ) ) {
470 wfDeprecated( __METHOD__ .
' with string title',
'1.41' );
471 $title = (
new RawMessage(
'$1' ) )->rawParams( $title );
473 $out->setPageTitleMsg( $title );
477 if ( $extraMessages ) {
478 $extraMessages = Status::wrap( $extraMessages );
479 $out->addWikiTextAsInterface(
480 $extraMessages->getWikiText(
false,
false, $this->getLanguage() )
484 $out->addHTML( $injected_html );
487 $helper->showReturnToPage( $type, $this->mReturnTo, $this->mReturnToQuery, $this->mStickHTTPS );
506 $type, $returnTo =
'', $returnToQuery =
'', $stickHTTPS =
false
509 $helper->showReturnToPage( $type, $returnTo, $returnToQuery, $stickHTTPS );
525 protected function mainLoginForm( array $requests, $msg =
'', $msgtype =
'error' ) {
533 $this->authForm =
null;
535 ->getAuthenticationRequests( $this->authAction, $user );
539 $out->addModuleStyles( [
540 'mediawiki.special.userlogin.common.styles'
544 $out->addModules(
'mediawiki.special.createaccount' );
545 $out->addModuleStyles( [
546 'mediawiki.special.userlogin.signup.styles'
550 $out->addModuleStyles( [
551 'mediawiki.special.userlogin.login.styles'
554 $out->disallowUserJs();
556 $form = $this->
getAuthForm( $requests, $this->authAction );
557 $form->prepareForm();
559 $submitStatus = Status::newGood();
560 if ( $msg && $msgtype ===
'warning' ) {
561 $submitStatus->warning( $msg );
562 } elseif ( $msg && $msgtype ===
'error' ) {
563 $submitStatus->fatal( $msg );
569 $this->
getUser()->isRegistered() &&
571 $this->authAction !== AuthManager::ACTION_LOGIN_CONTINUE
573 $reauthMessage = $this->securityLevel ?
'userlogin-reauth' :
'userlogin-loggedin';
574 $submitStatus->warning( $reauthMessage, $this->
getUser()->
getName() );
577 $formHtml = $form->getHTML( $submitStatus );
589 $loginPrompt = $this->
isSignup() ?
'' : Html::rawElement(
'div',
590 [
'id' =>
'userloginprompt' ], $this->
msg(
'loginprompt' )->parseAsBlock() );
593 $signupStartMsg = $this->
msg(
'signupstart' );
594 $signupStart = ( $this->
isSignup() && !$signupStartMsg->isDisabled() )
595 ? Html::rawElement(
'div', [
'id' =>
'signupstart' ], $signupStartMsg->parseAsBlock() ) :
'';
596 if ( $languageLinks ) {
597 $languageLinks = Html::rawElement(
'div', [
'id' =>
'languagelinks' ],
598 Html::rawElement(
'p', [], $languageLinks )
601 if ( $this->
getUser()->isTemp() ) {
606 $formBlock = Html::rawElement(
'div', [
'id' =>
'userloginForm' ], $formHtml );
607 $formAndBenefits = $formBlock;
609 $benefitsContainerHtml =
null;
615 'beforeForm' =>
false,
618 $benefitsContainerHtml, $info, $options
620 if ( $benefitsContainerHtml ===
null ) {
623 $formAndBenefits = $options[
'beforeForm']
624 ? ( $benefitsContainerHtml . $formBlock )
625 : ( $formBlock . $benefitsContainerHtml );
628 return Html::rawElement(
'div', [
'class' =>
'mw-ui-container' ],
645 $benefitsContainer =
'';
646 $this->
getOutput()->addModuleStyles( [
'oojs-ui.styles.icons-user' ] );
648 if ( !$this->
getUser()->isTemp() ) {
655 for ( $benefitIdx = 1; $benefitIdx <= $benefitCount; $benefitIdx++ ) {
656 $headUnescaped = $this->
msg(
"createacct-benefit-head$benefitIdx" )->text();
657 $iconClass = $this->
msg(
"createacct-benefit-icon$benefitIdx" )->text();
658 $benefitList .= Html::rawElement(
'div', [
'class' =>
"mw-number-text $iconClass" ],
659 Html::rawElement(
'span', [],
660 $this->
msg(
"createacct-benefit-head$benefitIdx" )->escaped()
662 . Html::rawElement(
'p', [],
663 $this->
msg(
"createacct-benefit-body$benefitIdx" )->params( $headUnescaped )->escaped()
667 $benefitsContainer = Html::rawElement(
'div', [
'class' =>
'mw-createacct-benefits-container' ],
668 Html::rawElement(
'div', [
'class' =>
'mw-createacct-benefits-heading' ],
669 $this->
msg(
'createacct-benefit-heading' )->escaped()
671 . Html::rawElement(
'div', [
'class' =>
'mw-createacct-benefits-list' ], $benefitList )
677 'oojs-ui.styles.icons-moderation',
678 'oojs-ui.styles.icons-interactions',
683 'icon' =>
'oo-ui-icon-unStar',
684 'description' => $this->
msg(
"benefit-1-description" )->escaped()
687 'icon' =>
'oo-ui-icon-userContributions',
688 'description' => $this->
msg(
"benefit-2-description" )->escaped()
691 'icon' =>
'oo-ui-icon-settings',
692 'description' => $this->
msg(
"benefit-3-description" )->escaped()
695 foreach ( $benefits as $benefit ) {
696 $benefitContent = Html::rawElement(
'div', [
'class' =>
'mw-benefit-item' ],
697 Html::rawElement(
'span', [
'class' => $benefit[
'icon' ] ] )
698 . Html::rawElement(
'p', [], $benefit[
'description'] )
701 $benefitList .= Html::rawElement(
702 'div', [
'class' =>
'mw-benefit-item-wrapper' ], $benefitContent );
705 $benefitsListWrapper = Html::rawElement(
706 'div', [
'class' =>
'mw-benefit-list-wrapper' ], $benefitList );
708 $headingSubheadingWrapper = Html::rawElement(
'div', [
'class' =>
'mw-heading-subheading-wrapper' ],
709 Html::rawElement(
'h2', [], $this->
msg(
'createacct-benefit-heading-temp-user' )->escaped() )
710 . Html::rawElement(
'p', [
'class' =>
'mw-benefit-subheading' ], $this->
msg(
711 'createacct-benefit-subheading-temp-user' )->escaped() )
714 $benefitsContainer = Html::rawElement(
715 'div', [
'class' =>
'mw-createacct-benefits-container' ],
716 $headingSubheadingWrapper
717 . $benefitsListWrapper
721 return $benefitsContainer;
733 if ( isset( $this->authForm ) ) {
734 return $this->authForm;
737 $usingHTTPS = $this->
getRequest()->getProtocol() ===
'https';
740 $fieldInfo = AuthenticationRequest::mergeFieldInfo( $requests );
742 $formDescriptor = $this->fieldInfoToFormDescriptor( $requests, $fieldInfo, $this->authAction );
743 $this->postProcessFormDescriptor( $formDescriptor, $requests );
746 if ( $context->getRequest() !== $this->getRequest() ) {
751 $form = HTMLForm::factory(
'codex', $formDescriptor, $context );
753 $form->addHiddenField(
'authAction', $this->authAction );
754 if ( $this->mLanguage ) {
755 $form->addHiddenField(
'uselang', $this->mLanguage );
757 if ( $this->mVariant ) {
758 $form->addHiddenField(
'variant', $this->mVariant );
760 $form->addHiddenField(
'force', $this->securityLevel );
761 $form->addHiddenField( $this->getTokenName(), $this->getToken()->toString() );
762 $config = $this->getConfig();
766 if ( !$this->isSignup() ) {
767 $form->addHiddenField(
'wpForceHttps', (
int)$this->mStickHTTPS );
768 $form->addHiddenField(
'wpFromhttp', $usingHTTPS );
773 $form->setAction( $this->getPageTitle()->getLocalURL( $this->getReturnToQueryStringFragment() ) );
774 $form->setName(
'userlogin' . ( $this->isSignup() ?
'2' :
'' ) );
775 if ( $this->isSignup() ) {
776 $form->setId(
'userlogin2' );
779 $form->suppressDefaultSubmit();
781 $this->authForm = $form;
788 array $requests, array $fieldInfo, array &$formDescriptor, $action
790 $formDescriptor = self::mergeDefaultFormDescriptor( $fieldInfo, $formDescriptor,
791 $this->getFieldDefinitions( $fieldInfo ) );
801 return $this->authAction !== $this->getContinueAction( $this->authAction )
802 && !$this->securityLevel;
811 $isLoggedIn = $this->
getUser()->isRegistered();
812 $continuePart = $this->isContinued() ?
'continue-' :
'';
813 $anotherPart = $isLoggedIn ?
'another-' :
'';
815 $expiration = $this->
getRequest()->getSession()->getProvider()->getRememberUserDuration();
816 $expirationDays = ceil( $expiration / ( 3600 * 24 ) );
817 $secureLoginLink =
'';
818 if ( $this->mSecureLoginUrl ) {
820 'href' => $this->mSecureLoginUrl,
821 'class' =>
'mw-login-flush-right mw-secure',
822 ], $this->msg(
'userlogin-signwithsecure' )->text() );
824 $usernameHelpLink =
'';
825 if ( !$this->msg(
'createacct-helpusername' )->isDisabled() ) {
826 $usernameHelpLink = Html::rawElement(
'span', [
827 'class' =>
'mw-login-flush-right',
828 ], $this->msg(
'createacct-helpusername' )->parse() );
831 if ( $this->isSignup() ) {
832 $config = $this->getConfig();
833 $hideIf = isset( $fieldInfo[
'mailpassword'] ) ? [
'hide-if' => [
'===',
'mailpassword',
'1' ] ] : [];
834 $fieldDefinitions = [
836 'label-raw' => $this->msg(
'userlogin-yourname' )->escaped() . $usernameHelpLink,
838 'placeholder-message' => $isLoggedIn ?
'createacct-another-username-ph'
839 :
'userlogin-yourname-ph',
844 'label-message' =>
'createaccountmail',
845 'name' =>
'wpCreateaccountMail',
846 'id' =>
'wpCreateaccountMail',
849 'id' =>
'wpPassword2',
850 'autocomplete' =>
'new-password',
851 'placeholder-message' =>
'createacct-yourpassword-ph',
852 'help-message' =>
'createacct-useuniquepass',
856 'type' =>
'password',
857 'label-message' =>
'createacct-yourpasswordagain',
859 'cssclass' =>
'loginPassword',
861 'autocomplete' =>
'new-password',
862 'validation-callback' =>
function ( $value, $alldata ) {
863 if ( empty( $alldata[
'mailpassword'] ) && !empty( $alldata[
'password'] ) ) {
865 return $this->msg(
'htmlform-required' );
866 } elseif ( $value !== $alldata[
'password'] ) {
867 return $this->msg(
'badretype' );
872 'placeholder-message' =>
'createacct-yourpasswordagain-ph',
877 ?
'createacct-emailrequired' :
'createacct-emailoptional',
879 'cssclass' =>
'loginText',
882 'autocomplete' =>
'email',
885 'validation-callback' =>
function ( $value, $alldata ) {
893 return $this->msg(
'noemailtitle' );
894 } elseif ( !$value && !empty( $alldata[
'mailpassword'] ) ) {
896 return $this->msg(
'noemailcreate' );
897 } elseif ( $value && !Sanitizer::validateEmail( $value ) ) {
898 return $this->msg(
'invalidemailaddress' );
899 } elseif ( is_string( $value ) && strlen( $value ) > 255 ) {
900 return $this->msg(
'changeemail-maxlength' );
907 'placeholder-message' =>
'createacct-' . $anotherPart .
'email-ph',
911 'help-message' => $isLoggedIn ?
'createacct-another-realname-tip'
912 :
'prefs-help-realname',
913 'label-message' =>
'createacct-realname',
914 'cssclass' =>
'loginText',
916 'placeholder-message' =>
'createacct-realname',
917 'id' =>
'wpRealName',
918 'autocomplete' =>
'name',
923 'label-message' =>
'createacct-reason',
924 'cssclass' =>
'loginText',
927 'validation-callback' =>
function ( $value, $alldata ) {
930 if ( $value && Sanitizer::validateEmail( $value ) ) {
931 if ( $this->reasonValidatorResult !==
null ) {
932 return $this->reasonValidatorResult;
934 $this->reasonValidatorResult =
true;
936 if ( !$authManager->getAuthenticationSessionData(
'reason-retry',
false ) ) {
937 $authManager->setAuthenticationSessionData(
'reason-retry',
true );
938 $this->reasonValidatorResult = $this->msg(
'createacct-reason-confirm' );
940 return $this->reasonValidatorResult;
944 'placeholder-message' =>
'createacct-reason-ph',
954 'default' => $this->msg(
'createacct-' . $anotherPart . $continuePart .
956 'name' =>
'wpCreateaccount',
957 'id' =>
'wpCreateaccount',
961 if ( !$this->msg(
'createacct-username-help' )->isDisabled() ) {
962 $fieldDefinitions[
'username'][
'help-message'] =
'createacct-username-help';
968 $passwordRequest = AuthenticationRequest::getRequestByClass( $this->authRequests,
969 PasswordAuthenticationRequest::class );
970 $changePassword = $passwordRequest && $passwordRequest->action == AuthManager::ACTION_CHANGE;
971 $fieldDefinitions = [
974 'label-raw' => $this->msg(
'userlogin-yourname' )->escaped() . $secureLoginLink,
976 'placeholder-message' =>
'userlogin-yourname-ph',
977 ] + ( $changePassword ? [
980 'baseField' =>
'password',
983 'cssclass' =>
'mw-htmlform-hidden-field',
988 'autocomplete' =>
'new-password',
989 'placeholder-message' =>
'createacct-yourpassword-ph',
990 'help-message' =>
'createacct-useuniquepass',
992 'id' =>
'wpPassword1',
993 'autocomplete' =>
'current-password',
994 'placeholder-message' =>
'userlogin-yourpassword-ph',
998 'type' =>
'password',
999 'autocomplete' =>
'new-password',
1000 'placeholder-message' =>
'createacct-yourpasswordagain-ph',
1006 'cssclass' =>
'mw-userlogin-rememberme',
1007 'name' =>
'wpRemember',
1008 'label-message' => $this->msg(
'userlogin-remembermypassword' )
1009 ->numParams( $expirationDays ),
1010 'id' =>
'wpRemember',
1018 'default' => $this->msg(
'pt-login-' . $continuePart .
'button' )->text(),
1019 'id' =>
'wpLoginAttempt',
1022 'linkcontainer' => [
1025 'cssclass' =>
'mw-form-related-link-container mw-userlogin-help',
1030 ->inContentLanguage()
1032 ], $this->msg(
'userlogin-helplink2' )->text() ),
1043 $fieldDefinitions[
'username'] += [
1046 'cssclass' =>
'loginText mw-userlogin-username',
1048 'autocomplete' =>
'username',
1051 $fieldDefinitions[
'password'] += [
1052 'type' =>
'password',
1054 'name' =>
'wpPassword',
1055 'cssclass' =>
'loginPassword mw-userlogin-password',
1060 if ( $this->mEntryError ) {
1062 if ( $this->mEntryErrorType ===
'error' ) {
1063 $defaultHtml = Html::errorBox( $this->mEntryError );
1064 } elseif ( $this->mEntryErrorType ===
'warning' ) {
1065 $defaultHtml = Html::warningBox( $this->mEntryError );
1067 $fieldDefinitions[
'entryError'] = [
1069 'default' => $defaultHtml,
1075 if ( !$this->showExtraInformation() ) {
1076 unset( $fieldDefinitions[
'linkcontainer'], $fieldDefinitions[
'signupend'] );
1078 if ( $this->isSignup() && $this->showExtraInformation() ) {
1081 $signupendMsg = $this->msg(
'signupend' );
1082 $signupendHttpsMsg = $this->msg(
'signupend-https' );
1083 if ( !$signupendMsg->isDisabled() ) {
1084 $usingHTTPS = $this->
getRequest()->getProtocol() ===
'https';
1085 $signupendText = ( $usingHTTPS && !$signupendHttpsMsg->isBlank() )
1086 ? $signupendHttpsMsg->parse() : $signupendMsg->parse();
1087 $fieldDefinitions[
'signupend'] = [
1090 'default' => Html::rawElement(
'div', [
'id' =>
'signupend' ], $signupendText ),
1095 if ( !$this->isSignup() && $this->showExtraInformation() ) {
1097 if ( $passwordReset->isAllowed( $this->getUser() )->isGood() ) {
1098 $fieldDefinitions[
'passwordReset'] = [
1101 'cssclass' =>
'mw-form-related-link-container',
1102 'default' => $this->getLinkRenderer()->makeLink(
1104 $this->msg(
'userlogin-resetpassword-link' )->text()
1111 if ( $this->showCreateAccountLink() ) {
1113 $linkTitle = $this->getTitleFor( $this->isSignup() ?
'Userlogin' :
'CreateAccount' );
1114 $linkq = $this->getReturnToQueryStringFragment();
1116 if ( $this->mLanguage ) {
1117 $linkq .=
'&uselang=' . urlencode( $this->mLanguage );
1119 if ( $this->mVariant ) {
1120 $linkq .=
'&variant=' . urlencode( $this->mVariant );
1122 $isLoggedIn = $this->
getUser()->isRegistered()
1123 && !$this->
getUser()->isTemp();
1125 $fieldDefinitions[
'createOrLogin'] = [
1128 'linkQuery' => $linkq,
1129 'default' =>
function (
$params ) use ( $isLoggedIn, $linkTitle ) {
1130 $buttonClasses =
'cdx-button cdx-button--action-progressive '
1131 .
'cdx-button--fake-button cdx-button--fake-button--enabled';
1133 return Html::rawElement(
'div',
1134 [
'id' =>
'mw-createaccount' . ( !$isLoggedIn ?
'-cta' :
'' ),
1135 'class' => ( $isLoggedIn ?
'mw-form-related-link-container' :
'mw-ui-vform-field' ) ],
1136 ( $isLoggedIn ?
'' : $this->msg(
'userlogin-noaccount' )->escaped() )
1139 'id' =>
'mw-createaccount-join' . ( $isLoggedIn ?
'-loggedin' :
'' ),
1140 'href' => $linkTitle->getLocalURL(
$params[
'linkQuery'] ),
1141 'class' => $isLoggedIn ?
'' : $buttonClasses,
1145 $isLoggedIn ?
'userlogin-createanother' :
'userlogin-joinproject'
1155 return $fieldDefinitions;
1168 $config = $this->getConfig();
1169 return $config->get(
'InitialSessionId' ) &&
1170 $this->
getRequest()->getSession()->getId() === (string)$config->get(
'InitialSessionId' );
1180 if ( $this->mReturnTo !==
'' ) {
1181 $returnto =
'returnto=' .
wfUrlencode( $this->mReturnTo );
1182 if ( $this->mReturnToQuery !==
'' ) {
1183 $returnto .=
'&returntoquery=' .
wfUrlencode( $this->mReturnToQuery );
1194 private function showCreateAccountLink() {
1195 return $this->isSignup() ||
1196 $this->
getContext()->getAuthority()->isAllowed(
'createaccount' );
1200 return $this->isSignup() ?
'wpCreateaccountToken' :
'wpLoginToken';
1210 $msg = $this->msg(
'loginlanguagelinks' )->inContentLanguage();
1211 if ( $msg->isBlank() ) {
1214 $langs = explode(
"\n", $msg->text() );
1216 foreach ( $langs as $lang ) {
1217 $lang = trim( $lang,
'* ' );
1218 $parts = explode(
'|', $lang );
1219 if ( count( $parts ) >= 2 ) {
1220 $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) );
1224 return count( $links ) > 0 ? $this->msg(
'loginlanguagelabel' )->rawParams(
1225 $this->getLanguage()->pipeList( $links ) )->escaped() :
'';
1237 if ( $this->getLanguage()->getCode() == $lang ) {
1239 return htmlspecialchars( $text );
1241 $query = [
'uselang' => $lang ];
1242 if ( $this->mVariant ) {
1243 $query[
'variant'] = $this->mVariant;
1245 if ( $this->mReturnTo !==
'' ) {
1246 $query[
'returnto'] = $this->mReturnTo;
1247 $query[
'returntoquery'] = $this->mReturnToQuery;
1252 ->getLanguage( $lang );
1253 $attr[
'lang'] = $attr[
'hreflang'] = $targetLanguage->getHtmlCode();
1255 return $this->getLinkRenderer()->makeKnownLink(
1256 $this->getPageTitle(),
1274 isset( $formDescriptor[
'username'] ) &&
1275 !isset( $formDescriptor[
'username'][
'default'] ) &&
1279 if ( $user->isRegistered() && !$user->isTemp() ) {
1280 $formDescriptor[
'username'][
'default'] = $user->getName();
1282 $formDescriptor[
'username'][
'default'] =
1283 $this->
getRequest()->getSession()->suggestLoginUsername();
1289 if ( !$this->needsSubmitButton( $requests ) ) {
1290 unset( $formDescriptor[
'createaccount'], $formDescriptor[
'loginattempt'] );
1293 if ( !$this->isSignup() ) {
1297 isset( $formDescriptor[
'username'] )
1298 && empty( $formDescriptor[
'username'][
'default'] )
1299 && !$this->
getRequest()->getCheck(
'wpName' )
1301 $formDescriptor[
'username'][
'autofocus'] =
true;
1302 } elseif ( isset( $formDescriptor[
'password'] ) ) {
1303 $formDescriptor[
'password'][
'autofocus'] =
true;
1307 $this->addTabIndex( $formDescriptor );
1316 $noticeContent = $this->msg(
'createacct-temp-warning', $this->
getUser()->getName() )->parse();
1317 return Html::noticeBox(
1321 'mw-userLogin-icon--user-temporary'
1328class_alias( LoginSignupSpecialPage::class,
'LoginSignupSpecialPage' );
wfUrlencode( $s)
We want some things to be included as literal characters in our title URLs for prettiness,...
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...
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
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.
logAuthResult( $success, $status=null)
Logs to the authmanager-stats channel.
postProcessFormDescriptor(&$formDescriptor, $requests)
makeLanguageSelectorLink( $text, $lang)
Create a language selector link for a particular language Links back to this page preserving type and...
getReturnToQueryStringFragment()
Returns a string that can be appended to the URL (without encoding) to preserve the return target.
showReturnToPage( $type, $returnTo='', $returnToQuery='', $stickHTTPS=false)
Add a "return to" link or redirect to it.
showSuccessPage( $type, $title, $msgname, $injected_html, $extraMessages)
Show the success page.
getPreservedParams( $withToken=false)
Returns URL query parameters which can be used to reload the page (or leave and return) while preserv...
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')
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,...
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 ...
getFieldDefinitions(array $fieldInfo)
Create a HTMLForm descriptor for the core login fields.
successfulAction( $direct=false, $extraMessages=null)
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...
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.