39use Wikimedia\ScopedCallback;
95 private $reasonValidatorResult =
null;
132 protected function setRequest( array $data, $wasPosted =
null ) {
133 parent::setRequest( $data, $wasPosted );
134 $this->mLoadedRequest =
false;
140 private function loadRequestParameters() {
141 if ( $this->mLoadedRequest ) {
144 $this->mLoadedRequest =
true;
147 $this->mPosted = $request->wasPosted();
148 $this->mAction = $request->getRawVal(
'action' );
149 $this->mFromHTTP = $request->getBool(
'fromhttp',
false )
150 || $request->getBool(
'wpFromhttp',
false );
152 || ( !$this->mFromHTTP && $request->getProtocol() ===
'https' )
153 || $request->getBool(
'wpForceHttps',
false );
154 $this->mReturnTo = $request->getVal(
'returnto',
'' );
155 $this->mReturnToQuery = $request->getVal(
'returntoquery',
'' );
156 $this->mReturnToAnchor = $request->getVal(
'returntoanchor',
'' );
157 if ( $request->getRawVal(
'display' ) ===
'popup' ) {
158 $this->mDisplay =
'popup';
168 $this->loadRequestParameters();
169 if ( $this->mLoaded ) {
172 $this->mLoaded =
true;
175 $securityLevel = $this->
getRequest()->getText(
'force' );
186 $this->mToken = $request->getVal( $this->
getTokenName() );
189 $entryError = $this->
msg( $request->getVal(
'error',
'' ) );
190 $entryWarning = $this->
msg( $request->getVal(
'warning',
'' ) );
191 $entryNotice = $this->
msg( $request->getVal(
'notice',
'' ) );
196 $this->
msg(
'loginreqlink' )->text(),
202 $validErrorMessages = LoginHelper::getValidErrorMessages();
203 if ( $entryError->exists()
204 && in_array( $entryError->getKey(), $validErrorMessages,
true )
206 $this->mEntryErrorType =
'error';
207 $this->mEntryError = $entryError->rawParams( $loginreqlink )->parse();
209 } elseif ( $entryWarning->exists()
210 && in_array( $entryWarning->getKey(), $validErrorMessages,
true )
212 $this->mEntryErrorType =
'warning';
213 $this->mEntryError = $entryWarning->rawParams( $loginreqlink )->parse();
214 } elseif ( $entryNotice->exists()
215 && in_array( $entryNotice->getKey(), $validErrorMessages,
true )
217 $this->mEntryErrorType =
'notice';
218 $this->mEntryError = $entryNotice->parse();
221 # 1. When switching accounts, it sucks to get automatically logged out
222 # 2. Do not return to PasswordReset after a successful password change
223 # but goto Wiki start page (Main_Page) instead ( T35997 )
224 $returnToTitle = Title::newFromText( $this->mReturnTo );
225 if ( is_object( $returnToTitle )
226 && ( $returnToTitle->isSpecial(
'Userlogout' )
227 || $returnToTitle->isSpecial(
'PasswordReset' ) )
229 $this->mReturnTo =
'';
230 $this->mReturnToQuery =
'';
236 $params = parent::getPreservedParams( $options );
240 $this->loadRequestParameters();
242 'returnto' =>
'mReturnTo',
243 'returntoquery' =>
'mReturnToQuery',
244 'returntoanchor' =>
'mReturnToAnchor',
246 foreach ( $properties as $key => $prop ) {
247 $value = $this->$prop;
248 if ( $value !==
'' ) {
249 $params[$key] = $value;
251 unset( $params[$key] );
256 $params[
'fromhttp'] = $this->mFromHTTP ?
'1' :
null;
258 if ( $this->mDisplay !==
'page' ) {
262 return array_filter( $params,
static fn ( $val ) => $val !==
null );
268 $this->loadRequestParameters();
269 return parent::beforeExecute(
$subPage );
276 if ( $this->mPosted ) {
278 ->getTiming(
'auth_specialpage_executeTiming_seconds' )
280 $profilingScope =
new ScopedCallback(
function () use ( $timer ) {
282 ->setLabel(
'action', $this->authAction )
298 $this->
getOutput()->disableClientCache();
303 if ( $this->mDisplay ===
'popup' ) {
308 $this->
getContext()->setSkin( $skinFactory->makeSkin(
'authentication-popup' ) );
315 if ( !$this->
isSignup() && !$authManager->canAuthenticateNow() ) {
316 if ( !$session->canSetUser() ) {
317 throw new ErrorPageError(
'cannotloginnow-title',
'cannotloginnow-text', [
318 $session->getProvider()->describe( $this->getLanguage() )
321 throw new ErrorPageError(
'cannotlogin-title',
'cannotlogin-text' );
322 } elseif ( $this->
isSignup() && !$authManager->canCreateAccounts() ) {
323 throw new ErrorPageError(
'cannotcreateaccount-title',
'cannotcreateaccount-text' );
344 if ( !$this->
isSignup() && !$this->mPosted && !$this->securityLevel &&
345 ( $this->mReturnTo !==
'' || $this->mReturnToQuery !==
'' ) &&
353 if ( $this->
getRequest()->getProtocol() !==
'https' ) {
357 ( $this->mEntryErrorType ===
'error' ?
'error'
358 :
'warning' ) => $this->mEntryError,
366 $this->
getOutput()->addVaryHeader(
'X-Forwarded-Proto' );
373 if ( str_starts_with(
$url,
'https://' ) ) {
374 $this->mSecureLoginUrl =
$url;
383 $this->
mainLoginForm( [],
'authpage-cannot-' . $this->authAction );
387 if ( $this->canBypassForm( $button_name ) ) {
390 if ( $button_name ) {
391 $this->
getRequest()->setVal( $button_name,
true );
397 if ( !$status || !$status->isGood() ) {
398 $this->
mainLoginForm( $this->authRequests, $status ? $status->getMessage() :
'',
'error' );
403 $response = $status->getValue();
407 switch ( $response->status ) {
408 case AuthenticationResponse::PASS:
410 $this->proxyAccountCreation = $this->
isSignup() && $this->
getUser()->isNamed();
411 $this->targetUser = User::newFromName( $response->username );
414 !$this->proxyAccountCreation
415 && $response->loginRequest
416 && $authManager->canAuthenticateNow()
419 $response2 = $authManager->beginAuthentication( [ $response->loginRequest ],
421 if ( $response2->status !== AuthenticationResponse::PASS ) {
422 LoggerFactory::getInstance(
'login' )
423 ->error(
'Could not log in after account creation' );
424 $this->
successfulAction(
true, Status::newFatal(
'createacct-loginerror' ) );
429 if ( !$this->proxyAccountCreation ) {
430 $context = RequestContext::getMain();
432 if ( $context !== $localContext ) {
442 case AuthenticationResponse::FAIL:
444 case AuthenticationResponse::RESTART:
445 $this->authForm =
null;
446 if ( $response->status === AuthenticationResponse::FAIL ) {
448 $messageType =
'error';
451 $messageType =
'warning';
453 $this->
logAuthResult(
false, $performer, $response->message ? $response->message->getKey() :
'-' );
455 $this->
mainLoginForm( $this->authRequests, $response->message, $messageType );
457 case AuthenticationResponse::REDIRECT:
458 $this->authForm =
null;
459 $this->
getOutput()->redirect( $response->redirectTarget );
461 case AuthenticationResponse::UI:
462 $this->authForm =
null;
463 $this->authAction = $this->
isSignup() ? AuthManager::ACTION_CREATE_CONTINUE
464 : AuthManager::ACTION_LOGIN_CONTINUE;
465 $this->authRequests = $response->neededRequests;
466 $this->
mainLoginForm( $response->neededRequests, $response->message, $response->messageType );
469 throw new LogicException(
'invalid AuthenticationResponse' );
486 private function canBypassForm( &$button_name ) {
491 $fields = AuthenticationRequest::mergeFieldInfo( $this->authRequests );
492 foreach ( $fields as $fieldname => $field ) {
493 if ( !isset( $field[
'type'] ) ) {
496 if ( !empty( $field[
'skippable'] ) ) {
499 if ( $field[
'type'] ===
'button' ) {
500 if ( $button_name !==
null ) {
504 $button_name = $fieldname;
506 } elseif ( $field[
'type'] !==
'null' ) {
523 $type, $title, $msgname, $injected_html, $extraMessages
526 $out->setPageTitleMsg( $title );
530 if ( $extraMessages ) {
531 $extraMessages = Status::wrap( $extraMessages );
532 $out->addWikiTextAsInterface(
533 $extraMessages->getWikiText(
false,
false, $this->getLanguage() )
537 $out->addHTML( $injected_html );
540 $helper->showReturnToPage( $type, $this->mReturnTo, $this->mReturnToQuery,
541 $this->mStickHTTPS, $this->mReturnToAnchor );
557 protected function mainLoginForm( array $requests, $msg =
'', $msgtype =
'error' ) {
565 $this->authForm =
null;
567 ->getAuthenticationRequests( $this->authAction, $user );
571 $out->addModuleStyles( [
572 'mediawiki.special.userlogin.common.styles',
573 'mediawiki.codex.messagebox.styles'
577 $out->addModules(
'mediawiki.special.createaccount' );
578 $out->addModuleStyles( [
579 'mediawiki.special.userlogin.signup.styles'
583 $out->addModuleStyles( [
584 'mediawiki.special.userlogin.login.styles'
587 $out->disallowUserJs();
589 $form = $this->
getAuthForm( $requests, $this->authAction );
590 $form->prepareForm();
592 $submitStatus = Status::newGood();
593 if ( $msg && $msgtype ===
'warning' ) {
594 $submitStatus->warning( $msg );
595 } elseif ( $msg && $msgtype ===
'error' ) {
596 $submitStatus->fatal( $msg );
601 if ( !$this->
isSignup() && $this->securityLevel ) {
602 $submitStatus->warning(
'userlogin-reauth', $this->
getUser()->
getName() );
608 Html::warningBox( $this->
msg(
609 $this->
isSignup() ?
'createacct-loggedin' :
'userlogin-loggedin',
612 '<div class="cdx-field"><div class="cdx-field__control">' .
615 'class' =>
'cdx-button cdx-button--fake-button cdx-button--fake-button--enabled ' .
616 'cdx-button--action-progressive cdx-button--weight-primary mw-htmlform-submit',
617 'href' => ( Title::newFromText( $this->mReturnTo ) ?: Title::newMainPage() )
618 ->createFragmentTarget( $this->mReturnToAnchor )->getLinkURL( $this->mReturnToQuery ),
621 $this->
isSignup() ?
'createacct-loggedin-continue-as' :
'userlogin-loggedin-continue-as',
627 $this->
isSignup() ?
'createacct-loggedin-heading' :
'userlogin-loggedin-heading'
630 $this->
isSignup() ?
'createacct-loggedin-prompt' :
'userlogin-loggedin-prompt'
636 $formHtml = $form->getHTML( $submitStatus );
648 $loginPrompt = $this->
isSignup() ?
'' : Html::rawElement(
'div',
649 [
'id' =>
'userloginprompt' ], $this->
msg(
'loginprompt' )->parseAsBlock() );
652 $signupStartMsg = $this->
msg(
'signupstart' );
653 $signupStart = ( $this->
isSignup() && !$signupStartMsg->isDisabled() )
654 ? Html::rawElement(
'div', [
'id' =>
'signupstart' ], $signupStartMsg->parseAsBlock() ) :
'';
655 if ( $languageLinks ) {
656 $languageLinks = Html::rawElement(
'div', [
'id' =>
'languagelinks' ],
657 Html::rawElement(
'p', [], $languageLinks )
660 if ( $this->
getUser()->isTemp() ) {
665 $formBlock = Html::rawElement(
'div', [
'id' =>
'userloginForm' ], $formHtml );
666 $formAndBenefits = $formBlock;
668 $benefitsContainerHtml =
null;
674 'beforeForm' =>
false,
677 $benefitsContainerHtml, $info, $options
680 $formAndBenefits = $options[
'beforeForm']
681 ? ( $benefitsContainerHtml . $formBlock )
682 : ( $formBlock . $benefitsContainerHtml );
689 . Html::rawElement(
'div', [
'class' =>
'mw-ui-container' ],
702 $benefitsContainer =
'';
703 $this->
getOutput()->addModuleStyles( [
'oojs-ui.styles.icons-user' ] );
705 if ( !$this->
getUser()->isTemp() ) {
712 for ( $benefitIdx = 1; $benefitIdx <= $benefitCount; $benefitIdx++ ) {
713 $numberUnescaped = $this->
msg(
"createacct-benefit-head$benefitIdx" )->text();
714 $numberHtml = Html::rawElement(
'strong', [], $numberUnescaped );
715 $iconClass = $this->
msg(
"createacct-benefit-icon$benefitIdx" )->text();
716 $benefitList .= Html::rawElement(
'div', [
'class' =>
"mw-number-text $iconClass" ],
717 Html::rawElement(
'p', [],
718 $this->
msg(
"createacct-benefit-text$benefitIdx" )->params(
725 $benefitsContainer = Html::rawElement(
'div', [
'class' =>
'mw-createacct-benefits-container' ],
726 Html::element(
'div', [
'class' =>
'mw-createacct-benefits-heading' ],
727 $this->
msg(
'createacct-benefit-heading' )->text()
729 . Html::rawElement(
'div', [
'class' =>
'mw-createacct-benefits-list' ], $benefitList )
735 'oojs-ui.styles.icons-moderation',
736 'oojs-ui.styles.icons-interactions',
741 'icon' =>
'oo-ui-icon-unStar',
742 'description' => $this->
msg(
"benefit-1-description" )->escaped()
745 'icon' =>
'oo-ui-icon-userContributions',
746 'description' => $this->
msg(
"benefit-2-description" )->escaped()
749 'icon' =>
'oo-ui-icon-settings',
750 'description' => $this->
msg(
"benefit-3-description" )->escaped()
753 foreach ( $benefits as $benefit ) {
754 $benefitContent = Html::rawElement(
'div', [
'class' =>
'mw-benefit-item' ],
755 Html::rawElement(
'span', [
'class' => $benefit[
'icon' ] ] )
756 . Html::rawElement(
'p', [], $benefit[
'description'] )
759 $benefitList .= Html::rawElement(
760 'div', [
'class' =>
'mw-benefit-item-wrapper' ], $benefitContent );
763 $benefitsListWrapper = Html::rawElement(
764 'div', [
'class' =>
'mw-benefit-list-wrapper' ], $benefitList );
766 $headingSubheadingWrapper = Html::rawElement(
'div', [
'class' =>
'mw-heading-subheading-wrapper' ],
768 $this->
msg(
'createacct-benefit-heading-temp-user' )->text()
770 .
Html::element(
'p', [
'class' =>
'mw-benefit-subheading' ],
771 $this->
msg(
'createacct-benefit-subheading-temp-user' )->text()
775 $benefitsContainer = Html::rawElement(
776 'div', [
'class' =>
'mw-createacct-benefits-container' ],
777 $headingSubheadingWrapper
778 . $benefitsListWrapper
782 return $benefitsContainer;
794 if ( $this->authForm ) {
795 return $this->authForm;
798 $usingHTTPS = $this->getRequest()->getProtocol() ===
'https';
801 $fieldInfo = AuthenticationRequest::mergeFieldInfo( $requests );
803 $formDescriptor = $this->fieldInfoToFormDescriptor( $requests, $fieldInfo, $this->authAction );
804 $this->postProcessFormDescriptor( $formDescriptor, $requests );
806 $context = $this->getContext();
807 if ( $context->getRequest() !== $this->getRequest() ) {
810 $context->setRequest( $this->getRequest() );
812 $form = HTMLForm::factory(
'codex', $formDescriptor, $context );
814 $form->addHiddenField(
'authAction', $this->authAction );
815 $form->addHiddenField(
'force', $this->securityLevel );
816 $form->addHiddenField( $this->getTokenName(), $this->getToken()->toString() );
817 $config = $this->getConfig();
821 if ( !$this->isSignup() ) {
822 $form->addHiddenField(
'wpForceHttps', (
int)$this->mStickHTTPS );
823 $form->addHiddenField(
'wpFromhttp', $usingHTTPS );
827 $form->setAction( $this->getPageTitle()->getLocalURL( $this->getPreservedParams(
831 $form->setName(
'userlogin' . ( $this->isSignup() ?
'2' :
'' ) );
832 if ( $this->isSignup() ) {
833 $form->setId(
'userlogin2' );
836 $form->suppressDefaultSubmit();
838 $this->authForm = $form;
845 array $requests, array $fieldInfo, array &$formDescriptor, $action
847 $formDescriptor = self::mergeDefaultFormDescriptor( $fieldInfo, $formDescriptor,
848 $this->getFieldDefinitions( $fieldInfo, $requests ) );
858 return $this->authAction !== $this->getContinueAction( $this->authAction )
859 && ( !$this->securityLevel || !$this->getUser()->isNamed() );
871 $isLoggedIn = $this->getUser()->isRegistered();
872 $continuePart = $this->isContinued() ?
'continue-' :
'';
873 $anotherPart = $isLoggedIn ?
'another-' :
'';
875 $expiration = $this->getRequest()->getSession()->getProvider()->getRememberUserDuration();
876 $expirationDays = ceil( $expiration / ( 3600 * 24 ) );
877 $secureLoginLink =
'';
878 if ( $this->mSecureLoginUrl ) {
879 $secureLoginLink = Html::rawElement(
'a', [
880 'href' => $this->mSecureLoginUrl,
881 'class' =>
'mw-login-flush-right mw-secure',
882 ],
Html::element(
'span', [
'class' =>
'mw-secure--icon' ] ) .
883 $this->msg(
'userlogin-signwithsecure' )->parse() );
885 $usernameHelpLink =
'';
886 if ( !$this->msg(
'createacct-helpusername' )->isDisabled() ) {
887 $usernameHelpLink = Html::rawElement(
'span', [
888 'class' =>
'mw-login-flush-right',
889 ], $this->msg(
'createacct-helpusername' )->parse() );
892 if ( $this->isSignup() ) {
893 $config = $this->getConfig();
894 $hideIf = isset( $fieldInfo[
'mailpassword'] ) ? [
'hide-if' => [
'===',
'mailpassword',
'1' ] ] : [];
895 $fieldDefinitions = [
897 'label-raw' => $this->msg(
'userlogin-yourname' )->escaped() . $usernameHelpLink,
899 'placeholder-message' => $isLoggedIn ?
'createacct-another-username-ph'
900 :
'userlogin-yourname-ph',
905 'label-message' =>
'createaccountmail',
906 'name' =>
'wpCreateaccountMail',
907 'id' =>
'wpCreateaccountMail',
910 'id' =>
'wpPassword2',
911 'autocomplete' =>
'new-password',
912 'placeholder-message' =>
'createacct-yourpassword-ph',
913 'help-message' =>
'createacct-useuniquepass',
917 'type' =>
'password',
918 'label-message' =>
'createacct-yourpasswordagain',
920 'cssclass' =>
'loginPassword',
922 'autocomplete' =>
'new-password',
923 'validation-callback' =>
function ( $value, $alldata ) {
924 if ( empty( $alldata[
'mailpassword'] ) && !empty( $alldata[
'password'] ) ) {
926 return $this->msg(
'htmlform-required' );
927 } elseif ( $value !== $alldata[
'password'] ) {
928 return $this->msg(
'badretype' );
933 'placeholder-message' =>
'createacct-yourpasswordagain-ph',
938 ?
'createacct-emailrequired' :
'createacct-emailoptional',
940 'cssclass' =>
'loginText',
943 'autocomplete' =>
'email',
946 'validation-callback' =>
function ( $value, $alldata ) {
954 return $this->msg(
'noemailtitle' );
955 } elseif ( !$value && !empty( $alldata[
'mailpassword'] ) ) {
957 return $this->msg(
'noemailcreate' );
958 } elseif ( $value && !Sanitizer::validateEmail( $value ) ) {
959 return $this->msg(
'invalidemailaddress' );
960 } elseif ( is_string( $value ) && strlen( $value ) > 255 ) {
961 return $this->msg(
'changeemail-maxlength' );
968 'placeholder-message' =>
'createacct-' . $anotherPart .
'email-ph',
972 'help-message' => $isLoggedIn ?
'createacct-another-realname-tip'
973 :
'prefs-help-realname',
974 'label-message' =>
'createacct-realname',
975 'cssclass' =>
'loginText',
977 'placeholder-message' =>
'createacct-realname',
978 'id' =>
'wpRealName',
979 'autocomplete' =>
'name',
984 'label-message' =>
'createacct-reason',
985 'cssclass' =>
'loginText',
988 'validation-callback' =>
function ( $value, $alldata ) {
991 if ( $value && Sanitizer::validateEmail( $value ) ) {
992 if ( $this->reasonValidatorResult !==
null ) {
993 return $this->reasonValidatorResult;
995 $this->reasonValidatorResult =
true;
997 if ( !$authManager->getAuthenticationSessionData(
'reason-retry',
false ) ) {
998 $authManager->setAuthenticationSessionData(
'reason-retry',
true );
999 $this->reasonValidatorResult = $this->msg(
'createacct-reason-confirm' );
1001 return $this->reasonValidatorResult;
1005 'placeholder-message' =>
'createacct-reason-ph',
1007 'createaccount' => [
1015 'default' => $this->msg(
'createacct-' . $anotherPart . $continuePart .
1017 'name' =>
'wpCreateaccount',
1018 'id' =>
'wpCreateaccount',
1022 if ( !$this->msg(
'createacct-username-help' )->isDisabled() ) {
1023 $fieldDefinitions[
'username'][
'help-message'] =
'createacct-username-help';
1029 $passwordRequest = AuthenticationRequest::getRequestByClass( $this->authRequests,
1030 PasswordAuthenticationRequest::class );
1031 $changePassword = $passwordRequest && $passwordRequest->action == AuthManager::ACTION_CHANGE;
1032 $fieldDefinitions = [
1035 'label-raw' => $this->msg(
'userlogin-yourname' )->escaped() . $secureLoginLink,
1037 'placeholder-message' =>
'userlogin-yourname-ph',
1038 ] + ( $changePassword ? [
1041 'baseField' =>
'password',
1044 'cssclass' =>
'mw-htmlform-hidden-field',
1049 'autocomplete' =>
'new-password',
1050 'placeholder-message' =>
'createacct-yourpassword-ph',
1051 'help-message' =>
'createacct-useuniquepass',
1053 'id' =>
'wpPassword1',
1054 'autocomplete' =>
'current-password',
1055 'placeholder-message' =>
'userlogin-yourpassword-ph',
1059 'type' =>
'password',
1060 'autocomplete' =>
'new-password',
1061 'placeholder-message' =>
'createacct-yourpasswordagain-ph',
1067 'cssclass' =>
'mw-userlogin-rememberme',
1068 'name' =>
'wpRemember',
1069 'label-message' => $this->msg(
'userlogin-remembermypassword' )
1070 ->numParams( $expirationDays ),
1071 'id' =>
'wpRemember',
1079 'default' => $this->msg(
'pt-login-' . $continuePart .
'button' )->text(),
1080 'id' =>
'wpLoginAttempt',
1083 'linkcontainer' => [
1086 'cssclass' =>
'mw-form-related-link-container mw-userlogin-help',
1090 'href' => Skin::makeInternalOrExternalUrl( $this->msg(
'helplogin-url' )
1091 ->inContentLanguage()
1093 ], $this->msg(
'userlogin-helplink2' )->text() ),
1107 $isUsernameOrPasswordRequest =
1108 AuthenticationRequest::getRequestByClass( $requests, UsernameAuthenticationRequest::class ) ||
1109 AuthenticationRequest::getRequestByClass( $requests, PasswordAuthenticationRequest::class );
1111 if ( $isUsernameOrPasswordRequest ) {
1112 $fieldDefinitions[
'username'] += [
1115 'cssclass' =>
'loginText mw-userlogin-username',
1117 'autocomplete' =>
'username',
1120 $fieldDefinitions[
'password'] += [
1121 'type' =>
'password',
1123 'name' =>
'wpPassword',
1124 'cssclass' =>
'loginPassword mw-userlogin-password',
1130 if ( $this->mEntryError ) {
1132 if ( $this->mEntryErrorType ===
'error' ) {
1133 $defaultHtml = Html::errorBox( $this->mEntryError );
1134 } elseif ( $this->mEntryErrorType ===
'warning' ) {
1135 $defaultHtml = Html::warningBox( $this->mEntryError );
1136 } elseif ( $this->mEntryErrorType ===
'notice' ) {
1137 $defaultHtml = Html::noticeBox( $this->mEntryError );
1139 $fieldDefinitions[
'entryError'] = [
1141 'default' => $defaultHtml,
1147 if ( !$this->showExtraInformation() ) {
1148 unset( $fieldDefinitions[
'linkcontainer'], $fieldDefinitions[
'signupend'] );
1150 if ( $this->isSignup() && $this->showExtraInformation() ) {
1153 $signupendMsg = $this->msg(
'signupend' );
1154 $signupendHttpsMsg = $this->msg(
'signupend-https' );
1155 if ( !$signupendMsg->isDisabled() ) {
1156 $usingHTTPS = $this->getRequest()->getProtocol() ===
'https';
1157 $signupendText = ( $usingHTTPS && !$signupendHttpsMsg->isBlank() )
1158 ? $signupendHttpsMsg->parse() : $signupendMsg->parse();
1159 $fieldDefinitions[
'signupend'] = [
1162 'default' => Html::rawElement(
'div', [
'id' =>
'signupend' ], $signupendText ),
1167 if ( !$this->isSignup() && $this->showExtraInformation() ) {
1169 if ( $passwordReset->isEnabled()->isGood() ) {
1170 $fieldDefinitions[
'passwordReset'] = [
1173 'cssclass' =>
'mw-form-related-link-container',
1174 'default' => $this->getLinkRenderer()->makeLink(
1176 $this->msg(
'userlogin-resetpassword-link' )->text()
1183 if ( $this->showCreateAccountLink() ) {
1186 $linkq =
wfArrayToCgi( $this->getPreservedParams( [
'reset' =>
true ] ) );
1187 $isLoggedIn = $this->getUser()->isRegistered()
1188 && !$this->getUser()->isTemp();
1190 $fieldDefinitions[
'createOrLogin'] = [
1193 'linkQuery' => $linkq,
1194 'default' =>
function ( $params ) use ( $isLoggedIn, $linkTitle ) {
1195 $buttonClasses =
'cdx-button cdx-button--action-progressive '
1196 .
'cdx-button--fake-button cdx-button--fake-button--enabled';
1198 return Html::rawElement(
'div',
1201 [
'id' =>
'mw-createaccount' . ( !$isLoggedIn ?
'-cta' :
'' ),
1202 'class' => ( $isLoggedIn ?
'mw-form-related-link-container' :
'' ) ],
1203 ( $isLoggedIn ?
'' : $this->msg(
'userlogin-noaccount' )->escaped() )
1208 'id' =>
'mw-createaccount-join' . ( $isLoggedIn ?
'-loggedin' :
'' ),
1209 'href' => $linkTitle->getLocalURL( $params[
'linkQuery'] ),
1210 'class' => [
'mw-authentication-popup-link', $buttonClasses => !$isLoggedIn ],
1211 'target' =>
'_self',
1215 $isLoggedIn ?
'userlogin-createanother' :
'userlogin-joinproject'
1225 return $fieldDefinitions;
1233 private function showCreateAccountLink() {
1234 return $this->isSignup() ||
1235 $this->getContext()->getAuthority()->isAllowed(
'createaccount' );
1242 return $this->isSignup() ?
'wpCreateaccountToken' :
'wpLoginToken';
1252 $msg = $this->msg(
'loginlanguagelinks' )->inContentLanguage();
1253 if ( $msg->isBlank() ) {
1256 $langs = explode(
"\n", $msg->text() );
1258 foreach ( $langs as $lang ) {
1259 $lang = trim( $lang,
'* ' );
1260 $parts = explode(
'|', $lang );
1261 if ( count( $parts ) >= 2 ) {
1262 $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) );
1266 return count( $links ) > 0 ? $this->msg(
'loginlanguagelabel' )->rawParams(
1267 $this->getLanguage()->pipeList( $links ) )->escaped() :
'';
1281 if ( $this->getLanguage()->getCode() == $lang
1282 || !$services->getLanguageNameUtils()->isValidCode( $lang )
1286 return htmlspecialchars( $text );
1289 $query = $this->getPreservedParams();
1290 $query[
'uselang'] = $lang;
1293 $targetLanguage = $services->getLanguageFactory()->getLanguage( $lang );
1294 $attr[
'lang'] = $attr[
'hreflang'] = $targetLanguage->getHtmlCode();
1295 $attr[
'class'] =
'mw-authentication-popup-link';
1296 $attr[
'title'] =
false;
1298 return $this->getLinkRenderer()->makeKnownLink(
1299 $this->getPageTitle(),
1318 isset( $formDescriptor[
'username'] ) &&
1319 !isset( $formDescriptor[
'username'][
'default'] ) &&
1322 $user = $this->getUser();
1323 if ( $user->isRegistered() && !$user->isTemp() ) {
1324 $formDescriptor[
'username'][
'default'] = $user->getName();
1326 $formDescriptor[
'username'][
'default'] =
1327 $this->getRequest()->getSession()->suggestLoginUsername();
1333 if ( !$this->needsSubmitButton( $requests ) ) {
1334 unset( $formDescriptor[
'createaccount'], $formDescriptor[
'loginattempt'] );
1337 if ( $this->getUser()->isNamed() && !$this->isContinued() ) {
1339 if ( isset( $formDescriptor[
'createaccount'] ) ) {
1340 $formDescriptor[
'createaccount'][
'flags'] = [
'progressive' ];
1342 if ( isset( $formDescriptor[
'loginattempt'] ) ) {
1343 $formDescriptor[
'loginattempt'][
'flags'] = [
'progressive' ];
1347 if ( !$this->isSignup() ) {
1351 isset( $formDescriptor[
'username'] )
1352 && empty( $formDescriptor[
'username'][
'default'] )
1353 && !$this->getRequest()->getCheck(
'wpName' )
1355 $formDescriptor[
'username'][
'autofocus'] =
true;
1356 } elseif ( isset( $formDescriptor[
'password'] ) ) {
1357 $formDescriptor[
'password'][
'autofocus'] =
true;
1361 $this->addTabIndex( $formDescriptor );
1370 $noticeContent = $this->msg(
'createacct-temp-warning', $this->getUser()->getName() )->parse();
1371 return Html::noticeBox(
1373 'mw-createaccount-temp-warning',
1375 'mw-userLogin-icon--user-temporary'
1382class_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....
Helper functions for the login form that need to be shared with other special pages (such as CentralA...
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.
An error page which can definitely be safely rendered using the OutputPage.
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.WebRequest 1.18
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.Used to preserve POST data over a...
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 execute.Return false to prevent calling execute() (since 1.27+)....
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.
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.
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.
Generic operation result class Has warning/error list, boolean status and arbitrary value.