55use Wikimedia\ScopedCallback;
111 private $reasonValidatorResult =
null;
144 protected function setRequest( array $data, $wasPosted =
null ) {
145 parent::setRequest( $data, $wasPosted );
146 $this->mLoadedRequest =
false;
152 private function loadRequestParameters() {
153 if ( $this->mLoadedRequest ) {
156 $this->mLoadedRequest =
true;
159 $this->mPosted = $request->wasPosted();
160 $this->mAction = $request->getRawVal(
'action' );
161 $this->mFromHTTP = $request->getBool(
'fromhttp',
false )
162 || $request->getBool(
'wpFromhttp',
false );
164 || ( !$this->mFromHTTP && $request->getProtocol() ===
'https' )
165 || $request->getBool(
'wpForceHttps',
false );
166 $this->mReturnTo = $request->getVal(
'returnto',
'' );
167 $this->mReturnToQuery = $request->getVal(
'returntoquery',
'' );
168 $this->mReturnToAnchor = $request->getVal(
'returntoanchor',
'' );
169 if ( $request->getRawVal(
'display' ) ===
'popup' ) {
170 $this->mDisplay =
'popup';
180 $this->loadRequestParameters();
181 if ( $this->mLoaded ) {
184 $this->mLoaded =
true;
187 $securityLevel = $this->
getRequest()->getText(
'force' );
198 $this->mToken = $request->getVal( $this->
getTokenName() );
201 $entryError = $this->
msg( $request->getVal(
'error',
'' ) );
202 $entryWarning = $this->
msg( $request->getVal(
'warning',
'' ) );
203 $entryNotice = $this->
msg( $request->getVal(
'notice',
'' ) );
208 $this->
msg(
'loginreqlink' )->text(),
214 $validErrorMessages = LoginHelper::getValidErrorMessages();
215 if ( $entryError->exists()
216 && in_array( $entryError->getKey(), $validErrorMessages,
true )
218 $this->mEntryErrorType =
'error';
219 $this->mEntryError = $entryError->rawParams( $loginreqlink )->parse();
221 } elseif ( $entryWarning->exists()
222 && in_array( $entryWarning->getKey(), $validErrorMessages,
true )
224 $this->mEntryErrorType =
'warning';
225 $this->mEntryError = $entryWarning->rawParams( $loginreqlink )->parse();
226 } elseif ( $entryNotice->exists()
227 && in_array( $entryNotice->getKey(), $validErrorMessages,
true )
229 $this->mEntryErrorType =
'notice';
230 $this->mEntryError = $entryNotice->parse();
233 # 1. When switching accounts, it sucks to get automatically logged out
234 # 2. Do not return to PasswordReset after a successful password change
235 # but goto Wiki start page (Main_Page) instead ( T35997 )
236 $returnToTitle = Title::newFromText( $this->mReturnTo );
237 if ( is_object( $returnToTitle )
238 && ( $returnToTitle->isSpecial(
'Userlogout' )
239 || $returnToTitle->isSpecial(
'PasswordReset' ) )
241 $this->mReturnTo =
'';
242 $this->mReturnToQuery =
'';
248 $params = parent::getPreservedParams( $options );
252 $this->loadRequestParameters();
254 'returnto' =>
'mReturnTo',
255 'returntoquery' =>
'mReturnToQuery',
256 'returntoanchor' =>
'mReturnToAnchor',
258 foreach ( $properties as $key => $prop ) {
259 $value = $this->$prop;
260 if ( $value !==
'' ) {
261 $params[$key] = $value;
263 unset( $params[$key] );
268 $params[
'fromhttp'] = $this->mFromHTTP ?
'1' :
null;
270 if ( $this->mDisplay !==
'page' ) {
274 return array_filter( $params,
static fn ( $val ) => $val !==
null );
279 $this->loadRequestParameters();
280 return parent::beforeExecute(
$subPage );
287 if ( $this->mPosted ) {
288 $time = microtime(
true );
289 $profilingScope =
new ScopedCallback(
function () use ( $time ) {
290 $time = microtime(
true ) - $time;
292 $stats->getTiming(
'auth_specialpage_executeTiming_seconds' )
293 ->setLabel(
'action', $this->authAction )
294 ->copyToStatsdAt(
"timing.login.ui.{$this->authAction}" )
295 ->observe( $time * 1000 );
300 $session = SessionManager::getGlobalSession();
310 $this->
getOutput()->disableClientCache();
315 if ( $this->mDisplay ===
'popup' ) {
320 $this->
getContext()->setSkin( $skinFactory->makeSkin(
'authentication-popup' ) );
327 if ( !$this->
isSignup() && !$authManager->canAuthenticateNow() ) {
328 if ( !$session->canSetUser() ) {
329 throw new ErrorPageError(
'cannotloginnow-title',
'cannotloginnow-text', [
330 $session->getProvider()->describe( $this->getLanguage() )
333 throw new ErrorPageError(
'cannotlogin-title',
'cannotlogin-text' );
334 } elseif ( $this->
isSignup() && !$authManager->canCreateAccounts() ) {
335 throw new ErrorPageError(
'cannotcreateaccount-title',
'cannotcreateaccount-text' );
356 if ( !$this->
isSignup() && !$this->mPosted && !$this->securityLevel &&
357 ( $this->mReturnTo !==
'' || $this->mReturnToQuery !==
'' ) &&
365 if ( $this->
getRequest()->getProtocol() !==
'https' ) {
369 ( $this->mEntryErrorType ===
'error' ?
'error'
370 :
'warning' ) => $this->mEntryError,
378 $this->
getOutput()->addVaryHeader(
'X-Forwarded-Proto' );
385 if ( str_starts_with(
$url,
'https://' ) ) {
386 $this->mSecureLoginUrl =
$url;
395 $this->
mainLoginForm( [],
'authpage-cannot-' . $this->authAction );
399 if ( $this->canBypassForm( $button_name ) ) {
402 if ( $button_name ) {
403 $this->
getRequest()->setVal( $button_name,
true );
409 if ( !$status || !$status->isGood() ) {
410 $this->
mainLoginForm( $this->authRequests, $status ? $status->getMessage() :
'',
'error' );
415 $response = $status->getValue();
419 switch ( $response->status ) {
420 case AuthenticationResponse::PASS:
422 $this->proxyAccountCreation = $this->
isSignup() && $this->
getUser()->isNamed();
423 $this->targetUser = User::newFromName( $response->username );
426 !$this->proxyAccountCreation
427 && $response->loginRequest
428 && $authManager->canAuthenticateNow()
431 $response2 = $authManager->beginAuthentication( [ $response->loginRequest ],
433 if ( $response2->status !== AuthenticationResponse::PASS ) {
434 LoggerFactory::getInstance(
'login' )
435 ->error(
'Could not log in after account creation' );
436 $this->
successfulAction(
true, Status::newFatal(
'createacct-loginerror' ) );
441 if ( !$this->proxyAccountCreation ) {
442 $context = RequestContext::getMain();
444 if ( $context !== $localContext ) {
454 case AuthenticationResponse::FAIL:
456 case AuthenticationResponse::RESTART:
457 $this->authForm =
null;
458 if ( $response->status === AuthenticationResponse::FAIL ) {
460 $messageType =
'error';
463 $messageType =
'warning';
465 $this->
logAuthResult(
false, $performer, $response->message ? $response->message->getKey() :
'-' );
467 $this->
mainLoginForm( $this->authRequests, $response->message, $messageType );
469 case AuthenticationResponse::REDIRECT:
470 $this->authForm =
null;
471 $this->
getOutput()->redirect( $response->redirectTarget );
473 case AuthenticationResponse::UI:
474 $this->authForm =
null;
475 $this->authAction = $this->
isSignup() ? AuthManager::ACTION_CREATE_CONTINUE
476 : AuthManager::ACTION_LOGIN_CONTINUE;
477 $this->authRequests = $response->neededRequests;
478 $this->
mainLoginForm( $response->neededRequests, $response->message, $response->messageType );
481 throw new LogicException(
'invalid AuthenticationResponse' );
498 private function canBypassForm( &$button_name ) {
503 $fields = AuthenticationRequest::mergeFieldInfo( $this->authRequests );
504 foreach ( $fields as $fieldname => $field ) {
505 if ( !isset( $field[
'type'] ) ) {
508 if ( !empty( $field[
'skippable'] ) ) {
511 if ( $field[
'type'] ===
'button' ) {
512 if ( $button_name !==
null ) {
516 $button_name = $fieldname;
518 } elseif ( $field[
'type'] !==
'null' ) {
535 $type, $title, $msgname, $injected_html, $extraMessages
538 if ( is_string( $title ) ) {
539 wfDeprecated( __METHOD__ .
' with string title',
'1.41' );
540 $title = (
new RawMessage(
'$1' ) )->rawParams( $title );
542 $out->setPageTitleMsg( $title );
546 if ( $extraMessages ) {
547 $extraMessages = Status::wrap( $extraMessages );
548 $out->addWikiTextAsInterface(
549 $extraMessages->getWikiText(
false,
false, $this->getLanguage() )
553 $out->addHTML( $injected_html );
556 $helper->showReturnToPage( $type, $this->mReturnTo, $this->mReturnToQuery,
557 $this->mStickHTTPS, $this->mReturnToAnchor );
573 protected function mainLoginForm( array $requests, $msg =
'', $msgtype =
'error' ) {
581 $this->authForm =
null;
583 ->getAuthenticationRequests( $this->authAction, $user );
587 $out->addModuleStyles( [
588 'mediawiki.special.userlogin.common.styles',
589 'mediawiki.codex.messagebox.styles'
593 $out->addModules(
'mediawiki.special.createaccount' );
594 $out->addModuleStyles( [
595 'mediawiki.special.userlogin.signup.styles'
599 $out->addModuleStyles( [
600 'mediawiki.special.userlogin.login.styles'
603 $out->disallowUserJs();
605 $form = $this->
getAuthForm( $requests, $this->authAction );
606 $form->prepareForm();
608 $submitStatus = Status::newGood();
609 if ( $msg && $msgtype ===
'warning' ) {
610 $submitStatus->warning( $msg );
611 } elseif ( $msg && $msgtype ===
'error' ) {
612 $submitStatus->fatal( $msg );
618 $this->
getUser()->isRegistered() &&
620 $this->authAction !== AuthManager::ACTION_LOGIN_CONTINUE
622 $reauthMessage = $this->securityLevel ?
'userlogin-reauth' :
'userlogin-loggedin';
623 $submitStatus->warning( $reauthMessage, $this->
getUser()->
getName() );
626 $formHtml = $form->getHTML( $submitStatus );
638 $loginPrompt = $this->
isSignup() ?
'' : Html::rawElement(
'div',
639 [
'id' =>
'userloginprompt' ], $this->
msg(
'loginprompt' )->parseAsBlock() );
642 $signupStartMsg = $this->
msg(
'signupstart' );
643 $signupStart = ( $this->
isSignup() && !$signupStartMsg->isDisabled() )
644 ? Html::rawElement(
'div', [
'id' =>
'signupstart' ], $signupStartMsg->parseAsBlock() ) :
'';
645 if ( $languageLinks ) {
646 $languageLinks = Html::rawElement(
'div', [
'id' =>
'languagelinks' ],
647 Html::rawElement(
'p', [], $languageLinks )
650 if ( $this->
getUser()->isTemp() ) {
655 $formBlock = Html::rawElement(
'div', [
'id' =>
'userloginForm' ], $formHtml );
656 $formAndBenefits = $formBlock;
658 $benefitsContainerHtml =
null;
664 'beforeForm' =>
false,
667 $benefitsContainerHtml, $info, $options
670 $formAndBenefits = $options[
'beforeForm']
671 ? ( $benefitsContainerHtml . $formBlock )
672 : ( $formBlock . $benefitsContainerHtml );
679 . Html::rawElement(
'div', [
'class' =>
'mw-ui-container' ],
692 $benefitsContainer =
'';
693 $this->
getOutput()->addModuleStyles( [
'oojs-ui.styles.icons-user' ] );
695 if ( !$this->
getUser()->isTemp() ) {
702 for ( $benefitIdx = 1; $benefitIdx <= $benefitCount; $benefitIdx++ ) {
703 $headUnescaped = $this->
msg(
"createacct-benefit-head$benefitIdx" )->text();
704 $iconClass = $this->
msg(
"createacct-benefit-icon$benefitIdx" )->text();
705 $benefitList .= Html::rawElement(
'div', [
'class' =>
"mw-number-text $iconClass" ],
706 Html::rawElement(
'span', [],
707 $this->
msg(
"createacct-benefit-head$benefitIdx" )->escaped()
709 . Html::rawElement(
'p', [],
710 $this->
msg(
"createacct-benefit-body$benefitIdx" )->params( $headUnescaped )->escaped()
714 $benefitsContainer = Html::rawElement(
'div', [
'class' =>
'mw-createacct-benefits-container' ],
715 Html::rawElement(
'div', [
'class' =>
'mw-createacct-benefits-heading' ],
716 $this->
msg(
'createacct-benefit-heading' )->escaped()
718 . Html::rawElement(
'div', [
'class' =>
'mw-createacct-benefits-list' ], $benefitList )
724 'oojs-ui.styles.icons-moderation',
725 'oojs-ui.styles.icons-interactions',
730 'icon' =>
'oo-ui-icon-unStar',
731 'description' => $this->
msg(
"benefit-1-description" )->escaped()
734 'icon' =>
'oo-ui-icon-userContributions',
735 'description' => $this->
msg(
"benefit-2-description" )->escaped()
738 'icon' =>
'oo-ui-icon-settings',
739 'description' => $this->
msg(
"benefit-3-description" )->escaped()
742 foreach ( $benefits as $benefit ) {
743 $benefitContent = Html::rawElement(
'div', [
'class' =>
'mw-benefit-item' ],
744 Html::rawElement(
'span', [
'class' => $benefit[
'icon' ] ] )
745 . Html::rawElement(
'p', [], $benefit[
'description'] )
748 $benefitList .= Html::rawElement(
749 'div', [
'class' =>
'mw-benefit-item-wrapper' ], $benefitContent );
752 $benefitsListWrapper = Html::rawElement(
753 'div', [
'class' =>
'mw-benefit-list-wrapper' ], $benefitList );
755 $headingSubheadingWrapper = Html::rawElement(
'div', [
'class' =>
'mw-heading-subheading-wrapper' ],
756 Html::rawElement(
'h2', [], $this->
msg(
'createacct-benefit-heading-temp-user' )->escaped() )
757 . Html::rawElement(
'p', [
'class' =>
'mw-benefit-subheading' ], $this->
msg(
758 'createacct-benefit-subheading-temp-user' )->escaped() )
761 $benefitsContainer = Html::rawElement(
762 'div', [
'class' =>
'mw-createacct-benefits-container' ],
763 $headingSubheadingWrapper
764 . $benefitsListWrapper
768 return $benefitsContainer;
780 if ( $this->authForm ) {
781 return $this->authForm;
784 $usingHTTPS = $this->getRequest()->getProtocol() ===
'https';
787 $fieldInfo = AuthenticationRequest::mergeFieldInfo( $requests );
789 $formDescriptor = $this->fieldInfoToFormDescriptor( $requests, $fieldInfo, $this->authAction );
790 $this->postProcessFormDescriptor( $formDescriptor, $requests );
792 $context = $this->getContext();
793 if ( $context->getRequest() !== $this->getRequest() ) {
796 $context->setRequest( $this->getRequest() );
798 $form = HTMLForm::factory(
'codex', $formDescriptor, $context );
800 $form->addHiddenField(
'authAction', $this->authAction );
801 $form->addHiddenField(
'force', $this->securityLevel );
802 $form->addHiddenField( $this->getTokenName(), $this->getToken()->toString() );
803 $config = $this->getConfig();
807 if ( !$this->isSignup() ) {
808 $form->addHiddenField(
'wpForceHttps', (
int)$this->mStickHTTPS );
809 $form->addHiddenField(
'wpFromhttp', $usingHTTPS );
813 $form->setAction( $this->getPageTitle()->getLocalURL( $this->getPreservedParams(
817 $form->setName(
'userlogin' . ( $this->isSignup() ?
'2' :
'' ) );
818 if ( $this->isSignup() ) {
819 $form->setId(
'userlogin2' );
822 $form->suppressDefaultSubmit();
824 $this->authForm = $form;
831 array $requests, array $fieldInfo, array &$formDescriptor, $action
833 $formDescriptor = self::mergeDefaultFormDescriptor( $fieldInfo, $formDescriptor,
834 $this->getFieldDefinitions( $fieldInfo, $requests ) );
844 return $this->authAction !== $this->getContinueAction( $this->authAction )
845 && !$this->securityLevel;
857 $isLoggedIn = $this->getUser()->isRegistered();
858 $continuePart = $this->isContinued() ?
'continue-' :
'';
859 $anotherPart = $isLoggedIn ?
'another-' :
'';
861 $expiration = $this->getRequest()->getSession()->getProvider()->getRememberUserDuration();
862 $expirationDays = ceil( $expiration / ( 3600 * 24 ) );
863 $secureLoginLink =
'';
864 if ( $this->mSecureLoginUrl ) {
865 $secureLoginLink = Html::rawElement(
'a', [
866 'href' => $this->mSecureLoginUrl,
867 'class' =>
'mw-login-flush-right mw-secure',
868 ],
Html::element(
'span', [
'class' =>
'mw-secure--icon' ] ) .
869 $this->msg(
'userlogin-signwithsecure' )->parse() );
871 $usernameHelpLink =
'';
872 if ( !$this->msg(
'createacct-helpusername' )->isDisabled() ) {
873 $usernameHelpLink = Html::rawElement(
'span', [
874 'class' =>
'mw-login-flush-right',
875 ], $this->msg(
'createacct-helpusername' )->parse() );
878 if ( $this->isSignup() ) {
879 $config = $this->getConfig();
880 $hideIf = isset( $fieldInfo[
'mailpassword'] ) ? [
'hide-if' => [
'===',
'mailpassword',
'1' ] ] : [];
881 $fieldDefinitions = [
883 'label-raw' => $this->msg(
'userlogin-yourname' )->escaped() . $usernameHelpLink,
885 'placeholder-message' => $isLoggedIn ?
'createacct-another-username-ph'
886 :
'userlogin-yourname-ph',
891 'label-message' =>
'createaccountmail',
892 'name' =>
'wpCreateaccountMail',
893 'id' =>
'wpCreateaccountMail',
896 'id' =>
'wpPassword2',
897 'autocomplete' =>
'new-password',
898 'placeholder-message' =>
'createacct-yourpassword-ph',
899 'help-message' =>
'createacct-useuniquepass',
903 'type' =>
'password',
904 'label-message' =>
'createacct-yourpasswordagain',
906 'cssclass' =>
'loginPassword',
908 'autocomplete' =>
'new-password',
909 'validation-callback' =>
function ( $value, $alldata ) {
910 if ( empty( $alldata[
'mailpassword'] ) && !empty( $alldata[
'password'] ) ) {
912 return $this->msg(
'htmlform-required' );
913 } elseif ( $value !== $alldata[
'password'] ) {
914 return $this->msg(
'badretype' );
919 'placeholder-message' =>
'createacct-yourpasswordagain-ph',
924 ?
'createacct-emailrequired' :
'createacct-emailoptional',
926 'cssclass' =>
'loginText',
929 'autocomplete' =>
'email',
932 'validation-callback' =>
function ( $value, $alldata ) {
940 return $this->msg(
'noemailtitle' );
941 } elseif ( !$value && !empty( $alldata[
'mailpassword'] ) ) {
943 return $this->msg(
'noemailcreate' );
944 } elseif ( $value && !Sanitizer::validateEmail( $value ) ) {
945 return $this->msg(
'invalidemailaddress' );
946 } elseif ( is_string( $value ) && strlen( $value ) > 255 ) {
947 return $this->msg(
'changeemail-maxlength' );
954 'placeholder-message' =>
'createacct-' . $anotherPart .
'email-ph',
958 'help-message' => $isLoggedIn ?
'createacct-another-realname-tip'
959 :
'prefs-help-realname',
960 'label-message' =>
'createacct-realname',
961 'cssclass' =>
'loginText',
963 'placeholder-message' =>
'createacct-realname',
964 'id' =>
'wpRealName',
965 'autocomplete' =>
'name',
970 'label-message' =>
'createacct-reason',
971 'cssclass' =>
'loginText',
974 'validation-callback' =>
function ( $value, $alldata ) {
977 if ( $value && Sanitizer::validateEmail( $value ) ) {
978 if ( $this->reasonValidatorResult !==
null ) {
979 return $this->reasonValidatorResult;
981 $this->reasonValidatorResult =
true;
983 if ( !$authManager->getAuthenticationSessionData(
'reason-retry',
false ) ) {
984 $authManager->setAuthenticationSessionData(
'reason-retry',
true );
985 $this->reasonValidatorResult = $this->msg(
'createacct-reason-confirm' );
987 return $this->reasonValidatorResult;
991 'placeholder-message' =>
'createacct-reason-ph',
1001 'default' => $this->msg(
'createacct-' . $anotherPart . $continuePart .
1003 'name' =>
'wpCreateaccount',
1004 'id' =>
'wpCreateaccount',
1008 if ( !$this->msg(
'createacct-username-help' )->isDisabled() ) {
1009 $fieldDefinitions[
'username'][
'help-message'] =
'createacct-username-help';
1015 $passwordRequest = AuthenticationRequest::getRequestByClass( $this->authRequests,
1016 PasswordAuthenticationRequest::class );
1017 $changePassword = $passwordRequest && $passwordRequest->action == AuthManager::ACTION_CHANGE;
1018 $fieldDefinitions = [
1021 'label-raw' => $this->msg(
'userlogin-yourname' )->escaped() . $secureLoginLink,
1023 'placeholder-message' =>
'userlogin-yourname-ph',
1024 ] + ( $changePassword ? [
1027 'baseField' =>
'password',
1030 'cssclass' =>
'mw-htmlform-hidden-field',
1035 'autocomplete' =>
'new-password',
1036 'placeholder-message' =>
'createacct-yourpassword-ph',
1037 'help-message' =>
'createacct-useuniquepass',
1039 'id' =>
'wpPassword1',
1040 'autocomplete' =>
'current-password',
1041 'placeholder-message' =>
'userlogin-yourpassword-ph',
1045 'type' =>
'password',
1046 'autocomplete' =>
'new-password',
1047 'placeholder-message' =>
'createacct-yourpasswordagain-ph',
1053 'cssclass' =>
'mw-userlogin-rememberme',
1054 'name' =>
'wpRemember',
1055 'label-message' => $this->msg(
'userlogin-remembermypassword' )
1056 ->numParams( $expirationDays ),
1057 'id' =>
'wpRemember',
1065 'default' => $this->msg(
'pt-login-' . $continuePart .
'button' )->text(),
1066 'id' =>
'wpLoginAttempt',
1069 'linkcontainer' => [
1072 'cssclass' =>
'mw-form-related-link-container mw-userlogin-help',
1076 'href' => Skin::makeInternalOrExternalUrl( $this->msg(
'helplogin-url' )
1077 ->inContentLanguage()
1079 ], $this->msg(
'userlogin-helplink2' )->text() ),
1093 $isUsernameOrPasswordRequest =
1094 AuthenticationRequest::getRequestByClass( $requests, UsernameAuthenticationRequest::class ) ||
1095 AuthenticationRequest::getRequestByClass( $requests, PasswordAuthenticationRequest::class );
1097 if ( $isUsernameOrPasswordRequest ) {
1098 $fieldDefinitions[
'username'] += [
1101 'cssclass' =>
'loginText mw-userlogin-username',
1103 'autocomplete' =>
'username',
1106 $fieldDefinitions[
'password'] += [
1107 'type' =>
'password',
1109 'name' =>
'wpPassword',
1110 'cssclass' =>
'loginPassword mw-userlogin-password',
1116 if ( $this->mEntryError ) {
1118 if ( $this->mEntryErrorType ===
'error' ) {
1119 $defaultHtml = Html::errorBox( $this->mEntryError );
1120 } elseif ( $this->mEntryErrorType ===
'warning' ) {
1121 $defaultHtml = Html::warningBox( $this->mEntryError );
1122 } elseif ( $this->mEntryErrorType ===
'notice' ) {
1123 $defaultHtml = Html::noticeBox( $this->mEntryError,
'' );
1125 $fieldDefinitions[
'entryError'] = [
1127 'default' => $defaultHtml,
1133 if ( !$this->showExtraInformation() ) {
1134 unset( $fieldDefinitions[
'linkcontainer'], $fieldDefinitions[
'signupend'] );
1136 if ( $this->isSignup() && $this->showExtraInformation() ) {
1139 $signupendMsg = $this->msg(
'signupend' );
1140 $signupendHttpsMsg = $this->msg(
'signupend-https' );
1141 if ( !$signupendMsg->isDisabled() ) {
1142 $usingHTTPS = $this->getRequest()->getProtocol() ===
'https';
1143 $signupendText = ( $usingHTTPS && !$signupendHttpsMsg->isBlank() )
1144 ? $signupendHttpsMsg->parse() : $signupendMsg->parse();
1145 $fieldDefinitions[
'signupend'] = [
1148 'default' => Html::rawElement(
'div', [
'id' =>
'signupend' ], $signupendText ),
1153 if ( !$this->isSignup() && $this->showExtraInformation() ) {
1155 if ( $passwordReset->isAllowed( $this->getUser() )->isGood() ) {
1156 $fieldDefinitions[
'passwordReset'] = [
1159 'cssclass' =>
'mw-form-related-link-container',
1160 'default' => $this->getLinkRenderer()->makeLink(
1162 $this->msg(
'userlogin-resetpassword-link' )->text()
1169 if ( $this->showCreateAccountLink() ) {
1171 $linkTitle = $this->getTitleFor( $this->isSignup() ?
'Userlogin' :
'CreateAccount' );
1172 $linkq =
wfArrayToCgi( $this->getPreservedParams( [
'reset' =>
true ] ) );
1173 $isLoggedIn = $this->getUser()->isRegistered()
1174 && !$this->getUser()->isTemp();
1176 $fieldDefinitions[
'createOrLogin'] = [
1179 'linkQuery' => $linkq,
1180 'default' =>
function ( $params ) use ( $isLoggedIn, $linkTitle ) {
1181 $buttonClasses =
'cdx-button cdx-button--action-progressive '
1182 .
'cdx-button--fake-button cdx-button--fake-button--enabled';
1184 return Html::rawElement(
'div',
1187 [
'id' =>
'mw-createaccount' . ( !$isLoggedIn ?
'-cta' :
'' ),
1188 'class' => ( $isLoggedIn ?
'mw-form-related-link-container' :
'mw-ui-vform-field' ) ],
1189 ( $isLoggedIn ?
'' : $this->msg(
'userlogin-noaccount' )->escaped() )
1194 'id' =>
'mw-createaccount-join' . ( $isLoggedIn ?
'-loggedin' :
'' ),
1195 'href' => $linkTitle->getLocalURL( $params[
'linkQuery'] ),
1196 'class' => [
'mw-authentication-popup-link', $buttonClasses => !$isLoggedIn ],
1197 'target' =>
'_self',
1201 $isLoggedIn ?
'userlogin-createanother' :
'userlogin-joinproject'
1211 return $fieldDefinitions;
1235 private function showCreateAccountLink() {
1236 return $this->isSignup() ||
1237 $this->getContext()->getAuthority()->isAllowed(
'createaccount' );
1241 return $this->isSignup() ?
'wpCreateaccountToken' :
'wpLoginToken';
1251 $msg = $this->msg(
'loginlanguagelinks' )->inContentLanguage();
1252 if ( $msg->isBlank() ) {
1255 $langs = explode(
"\n", $msg->text() );
1257 foreach ( $langs as $lang ) {
1258 $lang = trim( $lang,
'* ' );
1259 $parts = explode(
'|', $lang );
1260 if ( count( $parts ) >= 2 ) {
1261 $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) );
1265 return count( $links ) > 0 ? $this->msg(
'loginlanguagelabel' )->rawParams(
1266 $this->getLanguage()->pipeList( $links ) )->escaped() :
'';
1280 if ( $this->getLanguage()->getCode() == $lang
1281 || !$services->getLanguageNameUtils()->isValidCode( $lang )
1285 return htmlspecialchars( $text );
1288 $query = $this->getPreservedParams();
1289 $query[
'uselang'] = $lang;
1292 $targetLanguage = $services->getLanguageFactory()->getLanguage( $lang );
1293 $attr[
'lang'] = $attr[
'hreflang'] = $targetLanguage->getHtmlCode();
1294 $attr[
'class'] =
'mw-authentication-popup-link';
1295 $attr[
'title'] =
false;
1297 return $this->getLinkRenderer()->makeKnownLink(
1298 $this->getPageTitle(),
1316 isset( $formDescriptor[
'username'] ) &&
1317 !isset( $formDescriptor[
'username'][
'default'] ) &&
1320 $user = $this->getUser();
1321 if ( $user->isRegistered() && !$user->isTemp() ) {
1322 $formDescriptor[
'username'][
'default'] = $user->getName();
1324 $formDescriptor[
'username'][
'default'] =
1325 $this->getRequest()->getSession()->suggestLoginUsername();
1331 if ( !$this->needsSubmitButton( $requests ) ) {
1332 unset( $formDescriptor[
'createaccount'], $formDescriptor[
'loginattempt'] );
1335 if ( !$this->isSignup() ) {
1339 isset( $formDescriptor[
'username'] )
1340 && empty( $formDescriptor[
'username'][
'default'] )
1341 && !$this->getRequest()->getCheck(
'wpName' )
1343 $formDescriptor[
'username'][
'autofocus'] =
true;
1344 } elseif ( isset( $formDescriptor[
'password'] ) ) {
1345 $formDescriptor[
'password'][
'autofocus'] =
true;
1349 $this->addTabIndex( $formDescriptor );
1358 $noticeContent = $this->msg(
'createacct-temp-warning', $this->getUser()->getName() )->parse();
1359 return Html::noticeBox(
1361 'mw-createaccount-temp-warning',
1363 'mw-userLogin-icon--user-temporary'
1370class_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
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.
Holds shared logic for login and account creation pages.
setRequest(array $data, $wasPosted=null)
Override the POST data, GET data from the real request is preserved.
postProcessFormDescriptor(&$formDescriptor, $requests)
makeLanguageSelectorLink( $text, $lang)
Create a language selector link for a particular language Links back to this page preserving type and...
string string $mReturnToAnchor
The fragment part of the URL to return to after authentication finishes.
beforeExecute( $subPage)
Gets called before SpecialPage::execute.Return false to prevent calling execute() (since 1....
string null $mSecureLoginUrl
showSuccessPage( $type, $title, $msgname, $injected_html, $extraMessages)
Show the success page.
getAuthForm(array $requests, $action)
Generates a form from the given request.
getTokenName()
Returns the name of the CSRF token (under which it should be found in the POST or GET data).
getBenefitsContainerHtml()
The HTML to be shown in the "benefits to signing in / creating an account" section of the signup/logi...
mainLoginForm(array $requests, $msg='', $msgtype='error')
getPreservedParams( $options=[])
Returns URL query parameters which should be preserved between authentication requests....
logAuthResult( $success, UserIdentity $performer, $status=null)
Logs to the authmanager-stats channel.
bool $proxyAccountCreation
True if the user if creating an account for someone else.
showExtraInformation()
Show extra information such as password recovery information, link from login to signup,...
string string $mReturnToQuery
The query string part of the URL to return to after authentication finishes.
onAuthChangeFormFields(array $requests, array $fieldInfo, array &$formDescriptor, $action)
Change the form descriptor that determines how a field will look in the authentication form....
makeLanguageSelector()
Produce a bar of links which allow the user to select another language during login/registration but ...
successfulAction( $direct=false, $extraMessages=null)
string string $mReturnTo
The title of the page to return to after authentication finishes, or the empty string when there is n...
getNoticeHtml()
Generates the HTML for a notice box to be displayed to a temporary user.
hasSessionCookie()
Check if a session cookie is present.
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
getFieldDefinitions(array $fieldInfo, array $requests)
Create a HTMLForm descriptor for the core login fields.
getPageHtml( $formHtml)
Add page elements which are outside the form.
User $targetUser
FIXME another flag for passing data.
load( $subPage)
Load data from request.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
getUser()
Shortcut to get the User executing this instance.
getPageTitle( $subpage=false)
Get a self-referential title object.
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
getConfig()
Shortcut to get main config object.
getContext()
Gets the context this SpecialPage is executed in.
setContext( $context)
Sets the context this SpecialPage is executed in.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getOutput()
Get the OutputPage being used for this instance.
getName()
Get the canonical, unlocalized name of this special page without namespace.
getFullTitle()
Return the full title, including $par.
Generic operation result class Has warning/error list, boolean status and arbitrary value.