54use Wikimedia\ScopedCallback;
110 private $reasonValidatorResult =
null;
142 protected function setRequest( array $data, $wasPosted =
null ) {
143 parent::setRequest( $data, $wasPosted );
144 $this->mLoadedRequest =
false;
150 private function loadRequestParameters() {
151 if ( $this->mLoadedRequest ) {
154 $this->mLoadedRequest =
true;
157 $this->mPosted = $request->wasPosted();
158 $this->mAction = $request->getRawVal(
'action' );
159 $this->mFromHTTP = $request->getBool(
'fromhttp',
false )
160 || $request->getBool(
'wpFromhttp',
false );
162 || ( !$this->mFromHTTP && $request->getProtocol() ===
'https' )
163 || $request->getBool(
'wpForceHttps',
false );
164 $this->mReturnTo = $request->getVal(
'returnto',
'' );
165 $this->mReturnToQuery = $request->getVal(
'returntoquery',
'' );
166 $this->mReturnToAnchor = $request->getVal(
'returntoanchor',
'' );
167 if ( $request->getVal(
'display' ) ===
'popup' ) {
168 $this->mDisplay =
'popup';
178 $this->loadRequestParameters();
179 if ( $this->mLoaded ) {
182 $this->mLoaded =
true;
185 $securityLevel = $this->
getRequest()->getText(
'force' );
196 $this->mToken = $request->getVal( $this->
getTokenName() );
199 $entryError = $this->
msg( $request->getVal(
'error',
'' ) );
200 $entryWarning = $this->
msg( $request->getVal(
'warning',
'' ) );
201 $entryNotice = $this->
msg( $request->getVal(
'notice',
'' ) );
206 $this->
msg(
'loginreqlink' )->text(),
213 if ( $entryError->exists()
214 && in_array( $entryError->getKey(), $validErrorMessages,
true )
216 $this->mEntryErrorType =
'error';
217 $this->mEntryError = $entryError->rawParams( $loginreqlink )->parse();
219 } elseif ( $entryWarning->exists()
220 && in_array( $entryWarning->getKey(), $validErrorMessages,
true )
222 $this->mEntryErrorType =
'warning';
223 $this->mEntryError = $entryWarning->rawParams( $loginreqlink )->parse();
224 } elseif ( $entryNotice->exists()
225 && in_array( $entryNotice->getKey(), $validErrorMessages,
true )
227 $this->mEntryErrorType =
'notice';
228 $this->mEntryError = $entryNotice->parse();
231 # 1. When switching accounts, it sucks to get automatically logged out
232 # 2. Do not return to PasswordReset after a successful password change
233 # but goto Wiki start page (Main_Page) instead ( T35997 )
234 $returnToTitle = Title::newFromText( $this->mReturnTo );
235 if ( is_object( $returnToTitle )
236 && ( $returnToTitle->isSpecial(
'Userlogout' )
237 || $returnToTitle->isSpecial(
'PasswordReset' ) )
239 $this->mReturnTo =
'';
240 $this->mReturnToQuery =
'';
246 $params = parent::getPreservedParams( $options );
250 $this->loadRequestParameters();
252 'returnto' =>
'mReturnTo',
253 'returntoquery' =>
'mReturnToQuery',
254 'returntoanchor' =>
'mReturnToAnchor',
256 foreach ( $properties as $key => $prop ) {
257 $value = $this->$prop;
258 if ( $value !==
'' ) {
266 $params[
'fromhttp'] = $this->mFromHTTP ?
'1' :
null;
268 if ( $this->mDisplay !==
'page' ) {
272 return array_filter(
$params, fn ( $val ) => $val !==
null );
277 $this->loadRequestParameters();
278 return parent::beforeExecute(
$subPage );
286 if ( $this->mPosted ) {
287 $time = microtime(
true );
288 $profilingScope =
new ScopedCallback(
function () use ( $time ) {
289 $time = microtime(
true ) - $time;
291 $stats->getTiming(
'auth_specialpage_executeTiming_seconds' )
292 ->setLabel(
'action', $this->authAction )
293 ->copyToStatsdAt(
"timing.login.ui.{$this->authAction}" )
294 ->observe( $time * 1000 );
299 $session = SessionManager::getGlobalSession();
306 $this->
getOutput()->disableClientCache();
311 if ( $this->mDisplay ===
'popup' ) {
316 $this->
getContext()->setSkin( $skinFactory->makeSkin(
'authentication-popup' ) );
323 if ( !$this->
isSignup() && !$authManager->canAuthenticateNow() ) {
324 if ( !$session->canSetUser() ) {
325 throw new ErrorPageError(
'cannotloginnow-title',
'cannotloginnow-text', [
326 $session->getProvider()->describe( $this->getLanguage() )
329 throw new ErrorPageError(
'cannotlogin-title',
'cannotlogin-text' );
330 } elseif ( $this->
isSignup() && !$authManager->canCreateAccounts() ) {
331 throw new ErrorPageError(
'cannotcreateaccount-title',
'cannotcreateaccount-text' );
352 if ( !$this->
isSignup() && !$this->mPosted && !$this->securityLevel &&
353 ( $this->mReturnTo !==
'' || $this->mReturnToQuery !==
'' ) &&
361 if ( $this->
getRequest()->getProtocol() !==
'https' ) {
365 ( $this->mEntryErrorType ===
'error' ?
'error'
366 :
'warning' ) => $this->mEntryError,
374 $this->
getOutput()->addVaryHeader(
'X-Forwarded-Proto' );
381 if ( str_starts_with(
$url,
'https://' ) ) {
382 $this->mSecureLoginUrl =
$url;
391 $this->
mainLoginForm( [],
'authpage-cannot-' . $this->authAction );
395 if ( $this->canBypassForm( $button_name ) ) {
398 if ( $button_name ) {
399 $this->
getRequest()->setVal( $button_name,
true );
405 if ( !$status || !$status->isGood() ) {
406 $this->
mainLoginForm( $this->authRequests, $status ? $status->getMessage() :
'',
'error' );
411 $response = $status->getValue();
415 switch ( $response->status ) {
416 case AuthenticationResponse::PASS:
418 $this->proxyAccountCreation = $this->
isSignup() && $this->
getUser()->isNamed();
419 $this->targetUser = User::newFromName( $response->username );
422 !$this->proxyAccountCreation
423 && $response->loginRequest
424 && $authManager->canAuthenticateNow()
427 $response2 = $authManager->beginAuthentication( [ $response->loginRequest ],
429 if ( $response2->status !== AuthenticationResponse::PASS ) {
430 LoggerFactory::getInstance(
'login' )
431 ->error(
'Could not log in after account creation' );
432 $this->
successfulAction(
true, Status::newFatal(
'createacct-loginerror' ) );
437 if ( !$this->proxyAccountCreation ) {
438 $context = RequestContext::getMain();
440 if ( $context !== $localContext ) {
450 case AuthenticationResponse::FAIL:
452 case AuthenticationResponse::RESTART:
453 unset( $this->authForm );
454 if ( $response->status === AuthenticationResponse::FAIL ) {
456 $messageType =
'error';
459 $messageType =
'warning';
461 $this->
logAuthResult(
false, $response->message ? $response->message->getKey() :
'-' );
463 $this->
mainLoginForm( $this->authRequests, $response->message, $messageType );
465 case AuthenticationResponse::REDIRECT:
466 unset( $this->authForm );
467 $this->
getOutput()->redirect( $response->redirectTarget );
469 case AuthenticationResponse::UI:
470 unset( $this->authForm );
471 $this->authAction = $this->
isSignup() ? AuthManager::ACTION_CREATE_CONTINUE
472 : AuthManager::ACTION_LOGIN_CONTINUE;
473 $this->authRequests = $response->neededRequests;
474 $this->
mainLoginForm( $response->neededRequests, $response->message, $response->messageType );
477 throw new LogicException(
'invalid AuthenticationResponse' );
494 private function canBypassForm( &$button_name ) {
499 $fields = AuthenticationRequest::mergeFieldInfo( $this->authRequests );
500 foreach ( $fields as $fieldname => $field ) {
501 if ( !isset( $field[
'type'] ) ) {
504 if ( !empty( $field[
'skippable'] ) ) {
507 if ( $field[
'type'] ===
'button' ) {
508 if ( $button_name !==
null ) {
512 $button_name = $fieldname;
514 } elseif ( $field[
'type'] !==
'null' ) {
531 $type, $title, $msgname, $injected_html, $extraMessages
534 if ( is_string( $title ) ) {
535 wfDeprecated( __METHOD__ .
' with string title',
'1.41' );
536 $title = (
new RawMessage(
'$1' ) )->rawParams( $title );
538 $out->setPageTitleMsg( $title );
542 if ( $extraMessages ) {
543 $extraMessages = Status::wrap( $extraMessages );
544 $out->addWikiTextAsInterface(
545 $extraMessages->getWikiText(
false,
false, $this->getLanguage() )
549 $out->addHTML( $injected_html );
552 $helper->showReturnToPage( $type, $this->mReturnTo, $this->mReturnToQuery,
553 $this->mStickHTTPS, $this->mReturnToAnchor );
569 protected function mainLoginForm( array $requests, $msg =
'', $msgtype =
'error' ) {
577 $this->authForm =
null;
579 ->getAuthenticationRequests( $this->authAction, $user );
583 $out->addModuleStyles( [
584 'mediawiki.special.userlogin.common.styles'
588 $out->addModules(
'mediawiki.special.createaccount' );
589 $out->addModuleStyles( [
590 'mediawiki.special.userlogin.signup.styles'
594 $out->addModuleStyles( [
595 'mediawiki.special.userlogin.login.styles'
598 $out->disallowUserJs();
600 $form = $this->
getAuthForm( $requests, $this->authAction );
601 $form->prepareForm();
603 $submitStatus = Status::newGood();
604 if ( $msg && $msgtype ===
'warning' ) {
605 $submitStatus->warning( $msg );
606 } elseif ( $msg && $msgtype ===
'error' ) {
607 $submitStatus->fatal( $msg );
613 $this->
getUser()->isRegistered() &&
615 $this->authAction !== AuthManager::ACTION_LOGIN_CONTINUE
617 $reauthMessage = $this->securityLevel ?
'userlogin-reauth' :
'userlogin-loggedin';
618 $submitStatus->warning( $reauthMessage, $this->
getUser()->
getName() );
621 $formHtml = $form->getHTML( $submitStatus );
633 $loginPrompt = $this->
isSignup() ?
'' : Html::rawElement(
'div',
634 [
'id' =>
'userloginprompt' ], $this->
msg(
'loginprompt' )->parseAsBlock() );
637 $signupStartMsg = $this->
msg(
'signupstart' );
638 $signupStart = ( $this->
isSignup() && !$signupStartMsg->isDisabled() )
639 ? Html::rawElement(
'div', [
'id' =>
'signupstart' ], $signupStartMsg->parseAsBlock() ) :
'';
640 if ( $languageLinks ) {
641 $languageLinks = Html::rawElement(
'div', [
'id' =>
'languagelinks' ],
642 Html::rawElement(
'p', [], $languageLinks )
645 if ( $this->
getUser()->isTemp() ) {
650 $formBlock = Html::rawElement(
'div', [
'id' =>
'userloginForm' ], $formHtml );
651 $formAndBenefits = $formBlock;
653 $benefitsContainerHtml =
null;
659 'beforeForm' =>
false,
662 $benefitsContainerHtml, $info, $options
665 $formAndBenefits = $options[
'beforeForm']
666 ? ( $benefitsContainerHtml . $formBlock )
667 : ( $formBlock . $benefitsContainerHtml );
674 . Html::rawElement(
'div', [
'class' =>
'mw-ui-container' ],
687 $benefitsContainer =
'';
688 $this->
getOutput()->addModuleStyles( [
'oojs-ui.styles.icons-user' ] );
690 if ( !$this->
getUser()->isTemp() ) {
697 for ( $benefitIdx = 1; $benefitIdx <= $benefitCount; $benefitIdx++ ) {
698 $headUnescaped = $this->
msg(
"createacct-benefit-head$benefitIdx" )->text();
699 $iconClass = $this->
msg(
"createacct-benefit-icon$benefitIdx" )->text();
700 $benefitList .= Html::rawElement(
'div', [
'class' =>
"mw-number-text $iconClass" ],
701 Html::rawElement(
'span', [],
702 $this->
msg(
"createacct-benefit-head$benefitIdx" )->escaped()
704 . Html::rawElement(
'p', [],
705 $this->
msg(
"createacct-benefit-body$benefitIdx" )->params( $headUnescaped )->escaped()
709 $benefitsContainer = Html::rawElement(
'div', [
'class' =>
'mw-createacct-benefits-container' ],
710 Html::rawElement(
'div', [
'class' =>
'mw-createacct-benefits-heading' ],
711 $this->
msg(
'createacct-benefit-heading' )->escaped()
713 . Html::rawElement(
'div', [
'class' =>
'mw-createacct-benefits-list' ], $benefitList )
719 'oojs-ui.styles.icons-moderation',
720 'oojs-ui.styles.icons-interactions',
725 'icon' =>
'oo-ui-icon-unStar',
726 'description' => $this->
msg(
"benefit-1-description" )->escaped()
729 'icon' =>
'oo-ui-icon-userContributions',
730 'description' => $this->
msg(
"benefit-2-description" )->escaped()
733 'icon' =>
'oo-ui-icon-settings',
734 'description' => $this->
msg(
"benefit-3-description" )->escaped()
737 foreach ( $benefits as $benefit ) {
738 $benefitContent = Html::rawElement(
'div', [
'class' =>
'mw-benefit-item' ],
739 Html::rawElement(
'span', [
'class' => $benefit[
'icon' ] ] )
740 . Html::rawElement(
'p', [], $benefit[
'description'] )
743 $benefitList .= Html::rawElement(
744 'div', [
'class' =>
'mw-benefit-item-wrapper' ], $benefitContent );
747 $benefitsListWrapper = Html::rawElement(
748 'div', [
'class' =>
'mw-benefit-list-wrapper' ], $benefitList );
750 $headingSubheadingWrapper = Html::rawElement(
'div', [
'class' =>
'mw-heading-subheading-wrapper' ],
751 Html::rawElement(
'h2', [], $this->
msg(
'createacct-benefit-heading-temp-user' )->escaped() )
752 . Html::rawElement(
'p', [
'class' =>
'mw-benefit-subheading' ], $this->
msg(
753 'createacct-benefit-subheading-temp-user' )->escaped() )
756 $benefitsContainer = Html::rawElement(
757 'div', [
'class' =>
'mw-createacct-benefits-container' ],
758 $headingSubheadingWrapper
759 . $benefitsListWrapper
763 return $benefitsContainer;
775 if ( isset( $this->authForm ) ) {
776 return $this->authForm;
779 $usingHTTPS = $this->getRequest()->getProtocol() ===
'https';
782 $fieldInfo = AuthenticationRequest::mergeFieldInfo( $requests );
784 $formDescriptor = $this->fieldInfoToFormDescriptor( $requests, $fieldInfo, $this->authAction );
785 $this->postProcessFormDescriptor( $formDescriptor, $requests );
787 $context = $this->getContext();
788 if ( $context->getRequest() !== $this->getRequest() ) {
791 $context->setRequest( $this->getRequest() );
793 $form = HTMLForm::factory(
'codex', $formDescriptor, $context );
795 $form->addHiddenField(
'authAction', $this->authAction );
796 $form->addHiddenField(
'force', $this->securityLevel );
797 $form->addHiddenField( $this->getTokenName(), $this->getToken()->toString() );
798 $config = $this->getConfig();
802 if ( !$this->isSignup() ) {
803 $form->addHiddenField(
'wpForceHttps', (
int)$this->mStickHTTPS );
804 $form->addHiddenField(
'wpFromhttp', $usingHTTPS );
808 $form->setAction( $this->getPageTitle()->getLocalURL( $this->getPreservedParams(
812 $form->setName(
'userlogin' . ( $this->isSignup() ?
'2' :
'' ) );
813 if ( $this->isSignup() ) {
814 $form->setId(
'userlogin2' );
817 $form->suppressDefaultSubmit();
819 $this->authForm = $form;
826 array $requests, array $fieldInfo, array &$formDescriptor, $action
828 $formDescriptor = self::mergeDefaultFormDescriptor( $fieldInfo, $formDescriptor,
829 $this->getFieldDefinitions( $fieldInfo, $requests ) );
839 return $this->authAction !== $this->getContinueAction( $this->authAction )
840 && !$this->securityLevel;
852 $isLoggedIn = $this->getUser()->isRegistered();
853 $continuePart = $this->isContinued() ?
'continue-' :
'';
854 $anotherPart = $isLoggedIn ?
'another-' :
'';
856 $expiration = $this->getRequest()->getSession()->getProvider()->getRememberUserDuration();
857 $expirationDays = ceil( $expiration / ( 3600 * 24 ) );
858 $secureLoginLink =
'';
859 if ( $this->mSecureLoginUrl ) {
860 $secureLoginLink = Html::rawElement(
'a', [
861 'href' => $this->mSecureLoginUrl,
862 'class' =>
'mw-login-flush-right mw-secure',
863 ],
Html::element(
'span', [
'class' =>
'mw-secure--icon' ] ) .
864 $this->msg(
'userlogin-signwithsecure' )->parse() );
866 $usernameHelpLink =
'';
867 if ( !$this->msg(
'createacct-helpusername' )->isDisabled() ) {
868 $usernameHelpLink = Html::rawElement(
'span', [
869 'class' =>
'mw-login-flush-right',
870 ], $this->msg(
'createacct-helpusername' )->parse() );
873 if ( $this->isSignup() ) {
874 $config = $this->getConfig();
875 $hideIf = isset( $fieldInfo[
'mailpassword'] ) ? [
'hide-if' => [
'===',
'mailpassword',
'1' ] ] : [];
876 $fieldDefinitions = [
878 'label-raw' => $this->msg(
'userlogin-yourname' )->escaped() . $usernameHelpLink,
880 'placeholder-message' => $isLoggedIn ?
'createacct-another-username-ph'
881 :
'userlogin-yourname-ph',
886 'label-message' =>
'createaccountmail',
887 'name' =>
'wpCreateaccountMail',
888 'id' =>
'wpCreateaccountMail',
891 'id' =>
'wpPassword2',
892 'autocomplete' =>
'new-password',
893 'placeholder-message' =>
'createacct-yourpassword-ph',
894 'help-message' =>
'createacct-useuniquepass',
898 'type' =>
'password',
899 'label-message' =>
'createacct-yourpasswordagain',
901 'cssclass' =>
'loginPassword',
903 'autocomplete' =>
'new-password',
904 'validation-callback' =>
function ( $value, $alldata ) {
905 if ( empty( $alldata[
'mailpassword'] ) && !empty( $alldata[
'password'] ) ) {
907 return $this->msg(
'htmlform-required' );
908 } elseif ( $value !== $alldata[
'password'] ) {
909 return $this->msg(
'badretype' );
914 'placeholder-message' =>
'createacct-yourpasswordagain-ph',
919 ?
'createacct-emailrequired' :
'createacct-emailoptional',
921 'cssclass' =>
'loginText',
924 'autocomplete' =>
'email',
927 'validation-callback' =>
function ( $value, $alldata ) {
935 return $this->msg(
'noemailtitle' );
936 } elseif ( !$value && !empty( $alldata[
'mailpassword'] ) ) {
938 return $this->msg(
'noemailcreate' );
939 } elseif ( $value && !Sanitizer::validateEmail( $value ) ) {
940 return $this->msg(
'invalidemailaddress' );
941 } elseif ( is_string( $value ) && strlen( $value ) > 255 ) {
942 return $this->msg(
'changeemail-maxlength' );
949 'placeholder-message' =>
'createacct-' . $anotherPart .
'email-ph',
953 'help-message' => $isLoggedIn ?
'createacct-another-realname-tip'
954 :
'prefs-help-realname',
955 'label-message' =>
'createacct-realname',
956 'cssclass' =>
'loginText',
958 'placeholder-message' =>
'createacct-realname',
959 'id' =>
'wpRealName',
960 'autocomplete' =>
'name',
965 'label-message' =>
'createacct-reason',
966 'cssclass' =>
'loginText',
969 'validation-callback' =>
function ( $value, $alldata ) {
972 if ( $value && Sanitizer::validateEmail( $value ) ) {
973 if ( $this->reasonValidatorResult !==
null ) {
974 return $this->reasonValidatorResult;
976 $this->reasonValidatorResult =
true;
978 if ( !$authManager->getAuthenticationSessionData(
'reason-retry',
false ) ) {
979 $authManager->setAuthenticationSessionData(
'reason-retry',
true );
980 $this->reasonValidatorResult = $this->msg(
'createacct-reason-confirm' );
982 return $this->reasonValidatorResult;
986 'placeholder-message' =>
'createacct-reason-ph',
996 'default' => $this->msg(
'createacct-' . $anotherPart . $continuePart .
998 'name' =>
'wpCreateaccount',
999 'id' =>
'wpCreateaccount',
1003 if ( !$this->msg(
'createacct-username-help' )->isDisabled() ) {
1004 $fieldDefinitions[
'username'][
'help-message'] =
'createacct-username-help';
1010 $passwordRequest = AuthenticationRequest::getRequestByClass( $this->authRequests,
1011 PasswordAuthenticationRequest::class );
1012 $changePassword = $passwordRequest && $passwordRequest->action == AuthManager::ACTION_CHANGE;
1013 $fieldDefinitions = [
1016 'label-raw' => $this->msg(
'userlogin-yourname' )->escaped() . $secureLoginLink,
1018 'placeholder-message' =>
'userlogin-yourname-ph',
1019 ] + ( $changePassword ? [
1022 'baseField' =>
'password',
1025 'cssclass' =>
'mw-htmlform-hidden-field',
1030 'autocomplete' =>
'new-password',
1031 'placeholder-message' =>
'createacct-yourpassword-ph',
1032 'help-message' =>
'createacct-useuniquepass',
1034 'id' =>
'wpPassword1',
1035 'autocomplete' =>
'current-password',
1036 'placeholder-message' =>
'userlogin-yourpassword-ph',
1040 'type' =>
'password',
1041 'autocomplete' =>
'new-password',
1042 'placeholder-message' =>
'createacct-yourpasswordagain-ph',
1048 'cssclass' =>
'mw-userlogin-rememberme',
1049 'name' =>
'wpRemember',
1050 'label-message' => $this->msg(
'userlogin-remembermypassword' )
1051 ->numParams( $expirationDays ),
1052 'id' =>
'wpRemember',
1060 'default' => $this->msg(
'pt-login-' . $continuePart .
'button' )->text(),
1061 'id' =>
'wpLoginAttempt',
1064 'linkcontainer' => [
1067 'cssclass' =>
'mw-form-related-link-container mw-userlogin-help',
1072 ->inContentLanguage()
1074 ], $this->msg(
'userlogin-helplink2' )->text() ),
1088 $isUsernameOrPasswordRequest =
1089 AuthenticationRequest::getRequestByClass( $requests, UsernameAuthenticationRequest::class ) ||
1090 AuthenticationRequest::getRequestByClass( $requests, PasswordAuthenticationRequest::class );
1092 if ( $isUsernameOrPasswordRequest ) {
1093 $fieldDefinitions[
'username'] += [
1096 'cssclass' =>
'loginText mw-userlogin-username',
1098 'autocomplete' =>
'username',
1101 $fieldDefinitions[
'password'] += [
1102 'type' =>
'password',
1104 'name' =>
'wpPassword',
1105 'cssclass' =>
'loginPassword mw-userlogin-password',
1111 if ( $this->mEntryError ) {
1113 if ( $this->mEntryErrorType ===
'error' ) {
1114 $defaultHtml = Html::errorBox( $this->mEntryError );
1115 } elseif ( $this->mEntryErrorType ===
'warning' ) {
1116 $defaultHtml = Html::warningBox( $this->mEntryError );
1117 } elseif ( $this->mEntryErrorType ===
'notice' ) {
1118 $defaultHtml = Html::noticeBox( $this->mEntryError,
'' );
1120 $fieldDefinitions[
'entryError'] = [
1122 'default' => $defaultHtml,
1128 if ( !$this->showExtraInformation() ) {
1129 unset( $fieldDefinitions[
'linkcontainer'], $fieldDefinitions[
'signupend'] );
1131 if ( $this->isSignup() && $this->showExtraInformation() ) {
1134 $signupendMsg = $this->msg(
'signupend' );
1135 $signupendHttpsMsg = $this->msg(
'signupend-https' );
1136 if ( !$signupendMsg->isDisabled() ) {
1137 $usingHTTPS = $this->getRequest()->getProtocol() ===
'https';
1138 $signupendText = ( $usingHTTPS && !$signupendHttpsMsg->isBlank() )
1139 ? $signupendHttpsMsg->parse() : $signupendMsg->parse();
1140 $fieldDefinitions[
'signupend'] = [
1143 'default' => Html::rawElement(
'div', [
'id' =>
'signupend' ], $signupendText ),
1148 if ( !$this->isSignup() && $this->showExtraInformation() ) {
1150 if ( $passwordReset->isAllowed( $this->getUser() )->isGood() ) {
1151 $fieldDefinitions[
'passwordReset'] = [
1154 'cssclass' =>
'mw-form-related-link-container',
1155 'default' => $this->getLinkRenderer()->makeLink(
1157 $this->msg(
'userlogin-resetpassword-link' )->text()
1164 if ( $this->showCreateAccountLink() ) {
1166 $linkTitle = $this->getTitleFor( $this->isSignup() ?
'Userlogin' :
'CreateAccount' );
1167 $linkq =
wfArrayToCgi( $this->getPreservedParams( [
'reset' =>
true ] ) );
1168 $isLoggedIn = $this->getUser()->isRegistered()
1169 && !$this->getUser()->isTemp();
1171 $fieldDefinitions[
'createOrLogin'] = [
1174 'linkQuery' => $linkq,
1175 'default' =>
function (
$params ) use ( $isLoggedIn, $linkTitle ) {
1176 $buttonClasses =
'cdx-button cdx-button--action-progressive '
1177 .
'cdx-button--fake-button cdx-button--fake-button--enabled';
1179 return Html::rawElement(
'div',
1182 [
'id' =>
'mw-createaccount' . ( !$isLoggedIn ?
'-cta' :
'' ),
1183 'class' => ( $isLoggedIn ?
'mw-form-related-link-container' :
'mw-ui-vform-field' ) ],
1184 ( $isLoggedIn ?
'' : $this->msg(
'userlogin-noaccount' )->escaped() )
1189 'id' =>
'mw-createaccount-join' . ( $isLoggedIn ?
'-loggedin' :
'' ),
1190 'href' => $linkTitle->getLocalURL(
$params[
'linkQuery'] ),
1191 'class' => [
'mw-authentication-popup-link', $buttonClasses => !$isLoggedIn ],
1192 'target' =>
'_self',
1196 $isLoggedIn ?
'userlogin-createanother' :
'userlogin-joinproject'
1206 return $fieldDefinitions;
1230 private function showCreateAccountLink() {
1231 return $this->isSignup() ||
1232 $this->getContext()->getAuthority()->isAllowed(
'createaccount' );
1236 return $this->isSignup() ?
'wpCreateaccountToken' :
'wpLoginToken';
1246 $msg = $this->msg(
'loginlanguagelinks' )->inContentLanguage();
1247 if ( $msg->isBlank() ) {
1250 $langs = explode(
"\n", $msg->text() );
1252 foreach ( $langs as $lang ) {
1253 $lang = trim( $lang,
'* ' );
1254 $parts = explode(
'|', $lang );
1255 if ( count( $parts ) >= 2 ) {
1256 $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) );
1260 return count( $links ) > 0 ? $this->msg(
'loginlanguagelabel' )->rawParams(
1261 $this->getLanguage()->pipeList( $links ) )->escaped() :
'';
1275 if ( $this->getLanguage()->getCode() == $lang
1276 || !$services->getLanguageNameUtils()->isValidCode( $lang )
1280 return htmlspecialchars( $text );
1283 $query = $this->getPreservedParams();
1284 $query[
'uselang'] = $lang;
1287 $targetLanguage = $services->getLanguageFactory()->getLanguage( $lang );
1288 $attr[
'lang'] = $attr[
'hreflang'] = $targetLanguage->getHtmlCode();
1289 $attr[
'class'] =
'mw-authentication-popup-link';
1291 return $this->getLinkRenderer()->makeKnownLink(
1292 $this->getPageTitle(),
1310 isset( $formDescriptor[
'username'] ) &&
1311 !isset( $formDescriptor[
'username'][
'default'] ) &&
1314 $user = $this->getUser();
1315 if ( $user->isRegistered() && !$user->isTemp() ) {
1316 $formDescriptor[
'username'][
'default'] = $user->getName();
1318 $formDescriptor[
'username'][
'default'] =
1319 $this->getRequest()->getSession()->suggestLoginUsername();
1325 if ( !$this->needsSubmitButton( $requests ) ) {
1326 unset( $formDescriptor[
'createaccount'], $formDescriptor[
'loginattempt'] );
1329 if ( !$this->isSignup() ) {
1333 isset( $formDescriptor[
'username'] )
1334 && empty( $formDescriptor[
'username'][
'default'] )
1335 && !$this->getRequest()->getCheck(
'wpName' )
1337 $formDescriptor[
'username'][
'autofocus'] =
true;
1338 } elseif ( isset( $formDescriptor[
'password'] ) ) {
1339 $formDescriptor[
'password'][
'autofocus'] =
true;
1343 $this->addTabIndex( $formDescriptor );
1352 $noticeContent = $this->msg(
'createacct-temp-warning', $this->getUser()->getName() )->parse();
1353 return Html::noticeBox(
1355 'mw-createaccount-temp-warning',
1357 'mw-userLogin-icon--user-temporary'
1364class_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.
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...
string string $mReturnToAnchor
The fragment part of the URL to return to after authentication finishes.
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....
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.