54use Wikimedia\ScopedCallback;
77 private $reasonValidatorResult =
null;
109 protected function setRequest( array $data, $wasPosted =
null ) {
110 parent::setRequest( $data, $wasPosted );
111 $this->mLoadedRequest =
false;
117 private function loadRequestParameters() {
118 if ( $this->mLoadedRequest ) {
121 $this->mLoadedRequest =
true;
124 $this->mPosted = $request->wasPosted();
125 $this->mAction = $request->getRawVal(
'action' );
126 $this->mFromHTTP = $request->getBool(
'fromhttp',
false )
127 || $request->getBool(
'wpFromhttp',
false );
129 || ( !$this->mFromHTTP && $request->getProtocol() ===
'https' )
130 || $request->getBool(
'wpForceHttps',
false );
131 $this->mLanguage = $request->getText(
'uselang' );
132 $this->mVariant = $request->getText(
'variant' );
133 $this->mReturnTo = $request->getVal(
'returnto',
'' );
134 $this->mReturnToQuery = $request->getVal(
'returntoquery',
'' );
143 $this->loadRequestParameters();
144 if ( $this->mLoaded ) {
147 $this->mLoaded =
true;
150 $securityLevel = $this->
getRequest()->getText(
'force' );
161 $this->mToken = $request->getVal( $this->
getTokenName() );
164 $entryError = $this->
msg( $request->getVal(
'error',
'' ) );
165 $entryWarning = $this->
msg( $request->getVal(
'warning',
'' ) );
170 $this->
msg(
'loginreqlink' )->text(),
173 'returnto' => $this->mReturnTo,
174 'returntoquery' => $this->mReturnToQuery,
175 'uselang' => $this->mLanguage ?:
null,
176 'variant' => $this->mVariant ?:
null,
178 $this->mFromHTTP ?
'1' :
null,
183 if ( $entryError->exists()
186 $this->mEntryErrorType =
'error';
187 $this->mEntryError = $entryError->rawParams( $loginreqlink )->parse();
189 } elseif ( $entryWarning->exists()
192 $this->mEntryErrorType =
'warning';
193 $this->mEntryError = $entryWarning->rawParams( $loginreqlink )->parse();
196 # 1. When switching accounts, it sucks to get automatically logged out
197 # 2. Do not return to PasswordReset after a successful password change
198 # but goto Wiki start page (Main_Page) instead ( T35997 )
199 $returnToTitle = Title::newFromText( $this->mReturnTo );
200 if ( is_object( $returnToTitle )
201 && ( $returnToTitle->isSpecial(
'Userlogout' )
202 || $returnToTitle->isSpecial(
'PasswordReset' ) )
204 $this->mReturnTo =
'';
205 $this->mReturnToQuery =
'';
210 $params = parent::getPreservedParams( $withToken );
212 'returnto' => $this->mReturnTo ?:
null,
213 'returntoquery' => $this->mReturnToQuery ?:
null,
216 $params[
'fromhttp'] = $this->mFromHTTP ?
'1' :
null;
223 $this->loadRequestParameters();
224 return parent::beforeExecute(
$subPage );
232 if ( $this->mPosted ) {
233 $time = microtime(
true );
234 $profilingScope =
new ScopedCallback(
function () use ( $time ) {
235 $time = microtime(
true ) - $time;
237 $stats->getTiming(
'auth_specialpage_executeTiming_seconds' )
238 ->setLabel(
'action', $this->authAction )
239 ->copyToStatsdAt(
"timing.login.ui.{$this->authAction}" )
240 ->observe( $time * 1000 );
245 $session = SessionManager::getGlobalSession();
252 $this->
getOutput()->disableClientCache();
259 if ( !$this->
isSignup() && !$authManager->canAuthenticateNow() ) {
260 if ( !$session->canSetUser() ) {
261 throw new ErrorPageError(
'cannotloginnow-title',
'cannotloginnow-text', [
262 $session->getProvider()->describe( $this->getLanguage() )
265 throw new ErrorPageError(
'cannotlogin-title',
'cannotlogin-text' );
266 } elseif ( $this->
isSignup() && !$authManager->canCreateAccounts() ) {
267 throw new ErrorPageError(
'cannotcreateaccount-title',
'cannotcreateaccount-text' );
288 if ( !$this->
isSignup() && !$this->mPosted && !$this->securityLevel &&
289 ( $this->mReturnTo !==
'' || $this->mReturnToQuery !==
'' ) &&
297 if ( $this->
getRequest()->getProtocol() !==
'https' ) {
301 ( $this->mEntryErrorType ===
'error' ?
'error'
302 :
'warning' ) => $this->mEntryError,
304 $url = $title->getFullURL( $query,
false,
PROTO_HTTPS );
310 $this->
getOutput()->addVaryHeader(
'X-Forwarded-Proto' );
317 if ( str_starts_with( $url,
'https://' ) ) {
318 $this->mSecureLoginUrl = $url;
327 $this->
mainLoginForm( [],
'authpage-cannot-' . $this->authAction );
331 if ( $this->canBypassForm( $button_name ) ) {
334 if ( $button_name ) {
335 $this->
getRequest()->setVal( $button_name,
true );
341 if ( !$status || !$status->isGood() ) {
342 $this->
mainLoginForm( $this->authRequests, $status ? $status->getMessage() :
'',
'error' );
347 $response = $status->getValue();
351 switch ( $response->status ) {
352 case AuthenticationResponse::PASS:
354 $this->proxyAccountCreation = $this->
isSignup() && $this->
getUser()->isNamed();
355 $this->targetUser = User::newFromName( $response->username );
358 !$this->proxyAccountCreation
359 && $response->loginRequest
360 && $authManager->canAuthenticateNow()
363 $response2 = $authManager->beginAuthentication( [ $response->loginRequest ],
365 if ( $response2->status !== AuthenticationResponse::PASS ) {
366 LoggerFactory::getInstance(
'login' )
367 ->error(
'Could not log in after account creation' );
368 $this->
successfulAction(
true, Status::newFatal(
'createacct-loginerror' ) );
373 if ( !$this->proxyAccountCreation ) {
380 case AuthenticationResponse::FAIL:
382 case AuthenticationResponse::RESTART:
383 unset( $this->authForm );
384 if ( $response->status === AuthenticationResponse::FAIL ) {
386 $messageType =
'error';
389 $messageType =
'warning';
391 $this->
logAuthResult(
false, $response->message ? $response->message->getKey() :
'-' );
393 $this->
mainLoginForm( $this->authRequests, $response->message, $messageType );
395 case AuthenticationResponse::REDIRECT:
396 unset( $this->authForm );
397 $this->
getOutput()->redirect( $response->redirectTarget );
399 case AuthenticationResponse::UI:
400 unset( $this->authForm );
401 $this->authAction = $this->
isSignup() ? AuthManager::ACTION_CREATE_CONTINUE
402 : AuthManager::ACTION_LOGIN_CONTINUE;
403 $this->authRequests = $response->neededRequests;
404 $this->
mainLoginForm( $response->neededRequests, $response->message, $response->messageType );
407 throw new LogicException(
'invalid AuthenticationResponse' );
424 private function canBypassForm( &$button_name ) {
429 $fields = AuthenticationRequest::mergeFieldInfo( $this->authRequests );
430 foreach ( $fields as $fieldname => $field ) {
431 if ( !isset( $field[
'type'] ) ) {
434 if ( !empty( $field[
'skippable'] ) ) {
437 if ( $field[
'type'] ===
'button' ) {
438 if ( $button_name !==
null ) {
442 $button_name = $fieldname;
444 } elseif ( $field[
'type'] !==
'null' ) {
461 $type, $title, $msgname, $injected_html, $extraMessages
464 if ( is_string( $title ) ) {
465 wfDeprecated( __METHOD__ .
' with string title',
'1.41' );
466 $title = (
new RawMessage(
'$1' ) )->rawParams( $title );
468 $out->setPageTitleMsg( $title );
472 if ( $extraMessages ) {
473 $extraMessages = Status::wrap( $extraMessages );
474 $out->addWikiTextAsInterface(
475 $extraMessages->getWikiText(
false,
false, $this->getLanguage() )
479 $out->addHTML( $injected_html );
482 $helper->showReturnToPage( $type, $this->mReturnTo, $this->mReturnToQuery, $this->mStickHTTPS );
501 $type, $returnTo =
'', $returnToQuery =
'', $stickHTTPS =
false
504 $helper->showReturnToPage( $type, $returnTo, $returnToQuery, $stickHTTPS );
515 $context = RequestContext::getMain();
517 if ( $context !== $localContext ) {
522 $user = $context->getRequest()->getSession()->getUser();
524 StubGlobalUser::setUser( $user );
525 $context->setUser( $user );
528 $wgLang = $context->getLanguage();
544 protected function mainLoginForm( array $requests, $msg =
'', $msgtype =
'error' ) {
552 $this->authForm =
null;
554 ->getAuthenticationRequests( $this->authAction, $user );
558 $out->addModuleStyles( [
559 'mediawiki.special.userlogin.common.styles'
563 $out->addJsConfigVars(
'wgCreateacctImgcaptchaHelp',
564 $this->
msg(
'createacct-imgcaptcha-help' )->parse() );
567 $out->addModules(
'mediawiki.special.createaccount' );
568 $out->addModuleStyles( [
569 'mediawiki.special.userlogin.signup.styles'
573 $out->addModuleStyles( [
574 'mediawiki.special.userlogin.login.styles'
577 $out->disallowUserJs();
579 $form = $this->
getAuthForm( $requests, $this->authAction );
580 $form->prepareForm();
582 $submitStatus = Status::newGood();
583 if ( $msg && $msgtype ===
'warning' ) {
584 $submitStatus->warning( $msg );
585 } elseif ( $msg && $msgtype ===
'error' ) {
586 $submitStatus->fatal( $msg );
592 $this->
getUser()->isRegistered() &&
594 $this->authAction !== AuthManager::ACTION_LOGIN_CONTINUE
596 $reauthMessage = $this->securityLevel ?
'userlogin-reauth' :
'userlogin-loggedin';
597 $submitStatus->warning( $reauthMessage, $this->
getUser()->
getName() );
600 $formHtml = $form->getHTML( $submitStatus );
612 $loginPrompt = $this->
isSignup() ?
'' : Html::rawElement(
'div',
613 [
'id' =>
'userloginprompt' ], $this->
msg(
'loginprompt' )->parseAsBlock() );
616 $signupStartMsg = $this->
msg(
'signupstart' );
617 $signupStart = ( $this->
isSignup() && !$signupStartMsg->isDisabled() )
618 ? Html::rawElement(
'div', [
'id' =>
'signupstart' ], $signupStartMsg->parseAsBlock() ) :
'';
619 if ( $languageLinks ) {
620 $languageLinks = Html::rawElement(
'div', [
'id' =>
'languagelinks' ],
621 Html::rawElement(
'p', [], $languageLinks )
624 if ( $this->
getUser()->isTemp() ) {
629 $formBlock = Html::rawElement(
'div', [
'id' =>
'userloginForm' ], $formHtml );
630 $formAndBenefits = $formBlock;
632 $benefitsContainerHtml =
null;
638 'beforeForm' =>
false,
641 $benefitsContainerHtml, $info, $options
643 if ( $benefitsContainerHtml ===
null ) {
646 $formAndBenefits = $options[
'beforeForm']
647 ? ( $benefitsContainerHtml . $formBlock )
648 : ( $formBlock . $benefitsContainerHtml );
651 return Html::rawElement(
'div', [
'class' =>
'mw-ui-container' ],
668 $benefitsContainer =
'';
669 $this->
getOutput()->addModuleStyles( [
'oojs-ui.styles.icons-user' ] );
671 if ( !$this->
getUser()->isTemp() ) {
678 for ( $benefitIdx = 1; $benefitIdx <= $benefitCount; $benefitIdx++ ) {
679 $headUnescaped = $this->
msg(
"createacct-benefit-head$benefitIdx" )->text();
680 $iconClass = $this->
msg(
"createacct-benefit-icon$benefitIdx" )->text();
681 $benefitList .= Html::rawElement(
'div', [
'class' =>
"mw-number-text $iconClass" ],
682 Html::rawElement(
'h3', [],
683 $this->
msg(
"createacct-benefit-head$benefitIdx" )->escaped()
685 . Html::rawElement(
'p', [],
686 $this->
msg(
"createacct-benefit-body$benefitIdx" )->params( $headUnescaped )->escaped()
690 $benefitsContainer = Html::rawElement(
'div', [
'class' =>
'mw-createacct-benefits-container' ],
691 Html::rawElement(
'h2', [], $this->
msg(
'createacct-benefit-heading' )->escaped() )
692 . Html::rawElement(
'div', [
'class' =>
'mw-createacct-benefits-list' ], $benefitList )
698 'oojs-ui.styles.icons-moderation',
699 'oojs-ui.styles.icons-interactions',
704 'icon' =>
'oo-ui-icon-unStar',
705 'description' => $this->
msg(
"benefit-1-description" )->escaped()
708 'icon' =>
'oo-ui-icon-userContributions',
709 'description' => $this->
msg(
"benefit-2-description" )->escaped()
712 'icon' =>
'oo-ui-icon-settings',
713 'description' => $this->
msg(
"benefit-3-description" )->escaped()
716 foreach ( $benefits as $benefit ) {
717 $benefitContent = Html::rawElement(
'div', [
'class' =>
'mw-benefit-item' ],
718 Html::rawElement(
'span', [
'class' => $benefit[
'icon' ] ] )
719 . Html::rawElement(
'p', [], $benefit[
'description'] )
722 $benefitList .= Html::rawElement(
723 'div', [
'class' =>
'mw-benefit-item-wrapper' ], $benefitContent );
726 $benefitsListWrapper = Html::rawElement(
727 'div', [
'class' =>
'mw-benefit-list-wrapper' ], $benefitList );
729 $headingSubheadingWrapper = Html::rawElement(
'div', [
'class' =>
'mw-heading-subheading-wrapper' ],
730 Html::rawElement(
'h2', [], $this->
msg(
'createacct-benefit-heading-temp-user' )->escaped() )
731 . Html::rawElement(
'p', [
'class' =>
'mw-benefit-subheading' ], $this->
msg(
732 'createacct-benefit-subheading-temp-user' )->escaped() )
735 $benefitsContainer = Html::rawElement(
736 'div', [
'class' =>
'mw-createacct-benefits-container' ],
737 $headingSubheadingWrapper
738 . $benefitsListWrapper
742 return $benefitsContainer;
754 if ( isset( $this->authForm ) ) {
755 return $this->authForm;
758 $usingHTTPS = $this->
getRequest()->getProtocol() ===
'https';
761 $fieldInfo = AuthenticationRequest::mergeFieldInfo( $requests );
763 $formDescriptor = $this->fieldInfoToFormDescriptor( $requests, $fieldInfo, $this->authAction );
764 $this->postProcessFormDescriptor( $formDescriptor, $requests );
767 if ( $context->getRequest() !== $this->getRequest() ) {
772 $form = HTMLForm::factory(
'codex', $formDescriptor, $context );
774 $form->addHiddenField(
'authAction', $this->authAction );
775 if ( $this->mLanguage ) {
776 $form->addHiddenField(
'uselang', $this->mLanguage );
778 if ( $this->mVariant ) {
779 $form->addHiddenField(
'variant', $this->mVariant );
781 $form->addHiddenField(
'force', $this->securityLevel );
782 $form->addHiddenField( $this->getTokenName(), $this->getToken()->toString() );
783 $config = $this->getConfig();
787 if ( !$this->isSignup() ) {
788 $form->addHiddenField(
'wpForceHttps', (
int)$this->mStickHTTPS );
789 $form->addHiddenField(
'wpFromhttp', $usingHTTPS );
794 $form->setAction( $this->getPageTitle()->getLocalURL( $this->getReturnToQueryStringFragment() ) );
795 $form->setName(
'userlogin' . ( $this->isSignup() ?
'2' :
'' ) );
796 if ( $this->isSignup() ) {
797 $form->setId(
'userlogin2' );
800 $form->suppressDefaultSubmit();
802 $this->authForm = $form;
809 array $requests, array $fieldInfo, array &$formDescriptor, $action
811 $formDescriptor = self::mergeDefaultFormDescriptor( $fieldInfo, $formDescriptor,
812 $this->getFieldDefinitions( $fieldInfo ) );
822 return $this->authAction !== $this->getContinueAction( $this->authAction )
823 && !$this->securityLevel;
832 $isLoggedIn = $this->
getUser()->isRegistered();
833 $continuePart = $this->isContinued() ?
'continue-' :
'';
834 $anotherPart = $isLoggedIn ?
'another-' :
'';
836 $expiration = $this->
getRequest()->getSession()->getProvider()->getRememberUserDuration();
837 $expirationDays = ceil( $expiration / ( 3600 * 24 ) );
838 $secureLoginLink =
'';
839 if ( $this->mSecureLoginUrl ) {
841 'href' => $this->mSecureLoginUrl,
842 'class' =>
'mw-login-flush-right mw-secure',
843 ], $this->msg(
'userlogin-signwithsecure' )->text() );
845 $usernameHelpLink =
'';
846 if ( !$this->msg(
'createacct-helpusername' )->isDisabled() ) {
847 $usernameHelpLink = Html::rawElement(
'span', [
848 'class' =>
'mw-login-flush-right',
849 ], $this->msg(
'createacct-helpusername' )->parse() );
852 if ( $this->isSignup() ) {
853 $config = $this->getConfig();
854 $hideIf = isset( $fieldInfo[
'mailpassword'] ) ? [
'hide-if' => [
'===',
'mailpassword',
'1' ] ] : [];
855 $fieldDefinitions = [
861 'default' =>
Html::element(
'div', [
'id' =>
'mw-createacct-status-area' ] ),
865 'label-raw' => $this->msg(
'userlogin-yourname' )->escaped() . $usernameHelpLink,
867 'placeholder-message' => $isLoggedIn ?
'createacct-another-username-ph'
868 :
'userlogin-yourname-ph',
873 'label-message' =>
'createaccountmail',
874 'name' =>
'wpCreateaccountMail',
875 'id' =>
'wpCreateaccountMail',
878 'id' =>
'wpPassword2',
879 'autocomplete' =>
'new-password',
880 'placeholder-message' =>
'createacct-yourpassword-ph',
881 'help-message' =>
'createacct-useuniquepass',
885 'type' =>
'password',
886 'label-message' =>
'createacct-yourpasswordagain',
888 'cssclass' =>
'loginPassword',
890 'autocomplete' =>
'new-password',
891 'validation-callback' =>
function ( $value, $alldata ) {
892 if ( empty( $alldata[
'mailpassword'] ) && !empty( $alldata[
'password'] ) ) {
894 return $this->msg(
'htmlform-required' );
895 } elseif ( $value !== $alldata[
'password'] ) {
896 return $this->msg(
'badretype' );
901 'placeholder-message' =>
'createacct-yourpasswordagain-ph',
906 ?
'createacct-emailrequired' :
'createacct-emailoptional',
908 'cssclass' =>
'loginText',
911 'autocomplete' =>
'email',
914 'validation-callback' =>
function ( $value, $alldata ) {
922 return $this->msg(
'noemailtitle' );
923 } elseif ( !$value && !empty( $alldata[
'mailpassword'] ) ) {
925 return $this->msg(
'noemailcreate' );
926 } elseif ( $value && !Sanitizer::validateEmail( $value ) ) {
927 return $this->msg(
'invalidemailaddress' );
928 } elseif ( is_string( $value ) && strlen( $value ) > 255 ) {
929 return $this->msg(
'changeemail-maxlength' );
936 'placeholder-message' =>
'createacct-' . $anotherPart .
'email-ph',
940 'help-message' => $isLoggedIn ?
'createacct-another-realname-tip'
941 :
'prefs-help-realname',
942 'label-message' =>
'createacct-realname',
943 'cssclass' =>
'loginText',
945 'placeholder-message' =>
'createacct-realname',
946 'id' =>
'wpRealName',
947 'autocomplete' =>
'name',
952 'label-message' =>
'createacct-reason',
953 'cssclass' =>
'loginText',
956 'validation-callback' =>
function ( $value, $alldata ) {
959 if ( $value && Sanitizer::validateEmail( $value ) ) {
960 if ( $this->reasonValidatorResult !==
null ) {
961 return $this->reasonValidatorResult;
963 $this->reasonValidatorResult =
true;
965 if ( !$authManager->getAuthenticationSessionData(
'reason-retry',
false ) ) {
966 $authManager->setAuthenticationSessionData(
'reason-retry',
true );
967 $this->reasonValidatorResult = $this->msg(
'createacct-reason-confirm' );
969 return $this->reasonValidatorResult;
973 'placeholder-message' =>
'createacct-reason-ph',
983 'default' => $this->msg(
'createacct-' . $anotherPart . $continuePart .
985 'name' =>
'wpCreateaccount',
986 'id' =>
'wpCreateaccount',
990 if ( !$this->msg(
'createacct-username-help' )->isDisabled() ) {
991 $fieldDefinitions[
'username'][
'help-message'] =
'createacct-username-help';
997 $passwordRequest = AuthenticationRequest::getRequestByClass( $this->authRequests,
998 PasswordAuthenticationRequest::class );
999 $changePassword = $passwordRequest && $passwordRequest->action == AuthManager::ACTION_CHANGE;
1000 $fieldDefinitions = [
1003 'label-raw' => $this->msg(
'userlogin-yourname' )->escaped() . $secureLoginLink,
1005 'placeholder-message' =>
'userlogin-yourname-ph',
1006 ] + ( $changePassword ? [
1009 'baseField' =>
'password',
1012 'cssclass' =>
'mw-htmlform-hidden-field',
1017 'autocomplete' =>
'new-password',
1018 'placeholder-message' =>
'createacct-yourpassword-ph',
1019 'help-message' =>
'createacct-useuniquepass',
1021 'id' =>
'wpPassword1',
1022 'autocomplete' =>
'current-password',
1023 'placeholder-message' =>
'userlogin-yourpassword-ph',
1027 'type' =>
'password',
1028 'autocomplete' =>
'new-password',
1029 'placeholder-message' =>
'createacct-yourpasswordagain-ph',
1035 'cssclass' =>
'mw-userlogin-rememberme',
1036 'name' =>
'wpRemember',
1037 'label-message' => $this->msg(
'userlogin-remembermypassword' )
1038 ->numParams( $expirationDays ),
1039 'id' =>
'wpRemember',
1047 'default' => $this->msg(
'pt-login-' . $continuePart .
'button' )->text(),
1048 'id' =>
'wpLoginAttempt',
1051 'linkcontainer' => [
1054 'cssclass' =>
'mw-form-related-link-container mw-userlogin-help',
1059 ->inContentLanguage()
1061 ], $this->msg(
'userlogin-helplink2' )->text() ),
1072 $fieldDefinitions[
'username'] += [
1075 'cssclass' =>
'loginText mw-userlogin-username',
1077 'autocomplete' =>
'username',
1080 $fieldDefinitions[
'password'] += [
1081 'type' =>
'password',
1083 'name' =>
'wpPassword',
1084 'cssclass' =>
'loginPassword mw-userlogin-password',
1089 if ( $this->mEntryError ) {
1091 if ( $this->mEntryErrorType ===
'error' ) {
1092 $defaultHtml = Html::errorBox( $this->mEntryError );
1093 } elseif ( $this->mEntryErrorType ===
'warning' ) {
1094 $defaultHtml = Html::warningBox( $this->mEntryError );
1096 $fieldDefinitions[
'entryError'] = [
1098 'default' => $defaultHtml,
1104 if ( !$this->showExtraInformation() ) {
1105 unset( $fieldDefinitions[
'linkcontainer'], $fieldDefinitions[
'signupend'] );
1107 if ( $this->isSignup() && $this->showExtraInformation() ) {
1110 $signupendMsg = $this->msg(
'signupend' );
1111 $signupendHttpsMsg = $this->msg(
'signupend-https' );
1112 if ( !$signupendMsg->isDisabled() ) {
1113 $usingHTTPS = $this->
getRequest()->getProtocol() ===
'https';
1114 $signupendText = ( $usingHTTPS && !$signupendHttpsMsg->isBlank() )
1115 ? $signupendHttpsMsg->parse() : $signupendMsg->parse();
1116 $fieldDefinitions[
'signupend'] = [
1119 'default' => Html::rawElement(
'div', [
'id' =>
'signupend' ], $signupendText ),
1124 if ( !$this->isSignup() && $this->showExtraInformation() ) {
1126 if ( $passwordReset->isAllowed( $this->getUser() )->isGood() ) {
1127 $fieldDefinitions[
'passwordReset'] = [
1130 'cssclass' =>
'mw-form-related-link-container',
1131 'default' => $this->getLinkRenderer()->makeLink(
1133 $this->msg(
'userlogin-resetpassword-link' )->text()
1140 if ( $this->showCreateAccountLink() ) {
1142 $linkTitle = $this->getTitleFor( $this->isSignup() ?
'Userlogin' :
'CreateAccount' );
1143 $linkq = $this->getReturnToQueryStringFragment();
1145 if ( $this->mLanguage ) {
1146 $linkq .=
'&uselang=' . urlencode( $this->mLanguage );
1148 if ( $this->mVariant ) {
1149 $linkq .=
'&variant=' . urlencode( $this->mVariant );
1151 $isLoggedIn = $this->
getUser()->isRegistered()
1152 && !$this->
getUser()->isTemp();
1154 $fieldDefinitions[
'createOrLogin'] = [
1157 'linkQuery' => $linkq,
1158 'default' =>
function (
$params ) use ( $isLoggedIn, $linkTitle ) {
1159 $buttonClasses =
'cdx-button cdx-button--action-progressive '
1160 .
'cdx-button--fake-button cdx-button--fake-button--enabled';
1162 return Html::rawElement(
'div',
1163 [
'id' =>
'mw-createaccount' . ( !$isLoggedIn ?
'-cta' :
'' ),
1164 'class' => ( $isLoggedIn ?
'mw-form-related-link-container' :
'mw-ui-vform-field' ) ],
1165 ( $isLoggedIn ?
'' : $this->msg(
'userlogin-noaccount' )->escaped() )
1168 'id' =>
'mw-createaccount-join' . ( $isLoggedIn ?
'-loggedin' :
'' ),
1169 'href' => $linkTitle->getLocalURL(
$params[
'linkQuery'] ),
1170 'class' => $isLoggedIn ?
'' : $buttonClasses,
1174 $isLoggedIn ?
'userlogin-createanother' :
'userlogin-joinproject'
1184 return $fieldDefinitions;
1197 $config = $this->getConfig();
1198 return $config->get(
'InitialSessionId' ) &&
1199 $this->
getRequest()->getSession()->getId() === (string)$config->get(
'InitialSessionId' );
1209 if ( $this->mReturnTo !==
'' ) {
1210 $returnto =
'returnto=' .
wfUrlencode( $this->mReturnTo );
1211 if ( $this->mReturnToQuery !==
'' ) {
1212 $returnto .=
'&returntoquery=' .
wfUrlencode( $this->mReturnToQuery );
1223 private function showCreateAccountLink() {
1224 return $this->isSignup() ||
1225 $this->
getContext()->getAuthority()->isAllowed(
'createaccount' );
1229 return $this->isSignup() ?
'wpCreateaccountToken' :
'wpLoginToken';
1239 $msg = $this->msg(
'loginlanguagelinks' )->inContentLanguage();
1240 if ( $msg->isBlank() ) {
1243 $langs = explode(
"\n", $msg->text() );
1245 foreach ( $langs as $lang ) {
1246 $lang = trim( $lang,
'* ' );
1247 $parts = explode(
'|', $lang );
1248 if ( count( $parts ) >= 2 ) {
1249 $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) );
1253 return count( $links ) > 0 ? $this->msg(
'loginlanguagelabel' )->rawParams(
1254 $this->getLanguage()->pipeList( $links ) )->escaped() :
'';
1266 if ( $this->getLanguage()->getCode() == $lang ) {
1268 return htmlspecialchars( $text );
1270 $query = [
'uselang' => $lang ];
1271 if ( $this->mVariant ) {
1272 $query[
'variant'] = $this->mVariant;
1274 if ( $this->mReturnTo !==
'' ) {
1275 $query[
'returnto'] = $this->mReturnTo;
1276 $query[
'returntoquery'] = $this->mReturnToQuery;
1281 ->getLanguage( $lang );
1282 $attr[
'lang'] = $attr[
'hreflang'] = $targetLanguage->getHtmlCode();
1284 return $this->getLinkRenderer()->makeKnownLink(
1285 $this->getPageTitle(),
1303 isset( $formDescriptor[
'username'] ) &&
1304 !isset( $formDescriptor[
'username'][
'default'] ) &&
1308 if ( $user->isRegistered() && !$user->isTemp() ) {
1309 $formDescriptor[
'username'][
'default'] = $user->getName();
1311 $formDescriptor[
'username'][
'default'] =
1312 $this->
getRequest()->getSession()->suggestLoginUsername();
1318 if ( !$this->needsSubmitButton( $requests ) ) {
1319 unset( $formDescriptor[
'createaccount'], $formDescriptor[
'loginattempt'] );
1322 if ( !$this->isSignup() ) {
1326 isset( $formDescriptor[
'username'] )
1327 && empty( $formDescriptor[
'username'][
'default'] )
1328 && !$this->
getRequest()->getCheck(
'wpName' )
1330 $formDescriptor[
'username'][
'autofocus'] =
true;
1331 } elseif ( isset( $formDescriptor[
'password'] ) ) {
1332 $formDescriptor[
'password'][
'autofocus'] =
true;
1336 $this->addTabIndex( $formDescriptor );
1345 $noticeContent = $this->msg(
'createacct-temp-warning', $this->
getUser()->getName() )->parse();
1346 return Html::noticeBox(
1350 'mw-userLogin-icon--user-temporary'
1357class_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.
if(!defined( 'MW_NO_SESSION') &&MW_ENTRY_POINT !=='cli' $wgLang
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...
setSessionUserForCurrentRequest()
Replace some globals to make sure the fact that the user has just been logged in is reflected in the ...
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.