MediaWiki master
SpecialChangeEmail.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\Specials;
8
9use LogicException;
21
31 private $status;
32
33 public function __construct( AuthManager $authManager ) {
34 parent::__construct( 'ChangeEmail', 'editmyprivateinfo' );
35
36 $this->setAuthManager( $authManager );
37 }
38
40 public function doesWrites() {
41 return true;
42 }
43
47 public function isListed() {
48 return $this->getAuthManager()->allowsPropertyChange( 'emailaddress' );
49 }
50
55 public function execute( $par ) {
56 $out = $this->getOutput();
57 $out->disallowUserJs();
58 $out->addModules( 'mediawiki.special.changeemail' );
59 parent::execute( $par );
60 }
61
63 protected function getLoginSecurityLevel() {
64 return $this->getName();
65 }
66
67 protected function checkExecutePermissions( User $user ) {
68 if ( !$this->getAuthManager()->allowsPropertyChange( 'emailaddress' ) ) {
69 throw new ErrorPageError( 'changeemail', 'cannotchangeemail' );
70 }
71
72 $this->requireNamedUser( 'changeemail-no-info', 'exception-nologin', true );
73
74 // This could also let someone check the current email address, so
75 // require both permissions.
76 if ( !$this->getAuthority()->isAllowed( 'viewmyprivateinfo' ) ) {
77 throw new PermissionsError( 'viewmyprivateinfo' );
78 }
79
80 parent::checkExecutePermissions( $user );
81 }
82
84 protected function getFormFields() {
85 $user = $this->getUser();
86
87 return [
88 'Name' => [
89 'type' => 'info',
90 'label-message' => 'username',
91 'default' => $user->getName(),
92 ],
93 'OldEmail' => [
94 'type' => 'info',
95 'label-message' => 'changeemail-oldemail',
96 'default' => $user->getEmail() ?: $this->msg( 'changeemail-none' )->text(),
97 ],
98 'NewEmail' => [
99 'type' => 'email',
100 'label-message' => 'changeemail-newemail',
101 'autofocus' => true,
102 'maxlength' => 255,
103 'help-message' => 'changeemail-newemail-help',
104 ],
105 ];
106 }
107
109 protected function getDisplayFormat() {
110 return 'ooui';
111 }
112
113 protected function alterForm( HTMLForm $form ) {
114 $form->setId( 'mw-changeemail-form' );
115 $form->setTableId( 'mw-changeemail-table' );
116 $form->setSubmitTextMsg( 'changeemail-submit' );
117 $form->addHiddenFields( $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
118
119 $form->addHeaderHtml( $this->msg( 'changeemail-header' )->parseAsBlock() );
120 $form->setSubmitID( 'change_email_submit' );
121 }
122
124 public function onSubmit( array $data ) {
125 $this->status = $this->attemptChange( $this->getUser(), $data['NewEmail'] );
126
127 return $this->status;
128 }
129
130 public function onSuccess() {
131 $request = $this->getRequest();
132
133 $returnTo = $request->getVal( 'returnto' );
134 $titleObj = $returnTo !== null ? Title::newFromText( $returnTo ) : null;
135 if ( !$titleObj instanceof Title ) {
136 $titleObj = Title::newMainPage();
137 }
138 $query = $request->getVal( 'returntoquery', '' );
139
140 if ( $this->status->value === true ) {
141 $this->getOutput()->redirect( $titleObj->getFullUrlForRedirect( $query ) );
142 } elseif ( $this->status->value === 'eauth' ) {
143 # Notify user that a confirmation email has been sent...
144 $out = $this->getOutput();
145 $out->addModuleStyles( 'mediawiki.codex.messagebox.styles' );
146 $out->addHTML(
147 Html::warningBox(
148 $out->msg( 'eauthentsent', $this->getUser()->getName() )->parse()
149 )
150 );
151 // just show the link to go back
152 $this->getOutput()->addReturnTo( $titleObj, wfCgiToArray( $query ) );
153 }
154 }
155
162 private function attemptChange( User $user, $newAddr ) {
163 if ( $newAddr !== '' && !Sanitizer::validateEmail( $newAddr ) ) {
164 return Status::newFatal( 'invalidemailaddress' );
165 }
166
167 $oldAddr = $user->getEmail();
168 if ( $newAddr === $oldAddr ) {
169 return Status::newFatal( 'changeemail-nochange' );
170 }
171
172 if ( strlen( $newAddr ) > 255 ) {
173 return Status::newFatal( 'changeemail-maxlength' );
174 }
175
176 // To prevent spam, rate limit adding a new address, but do
177 // not rate limit removing an address.
178 if ( $newAddr !== '' ) {
179 // Enforce permissions, user blocks, and rate limits
180 $status = $this->authorizeAction( 'changeemail' );
181 if ( !$status->isGood() ) {
182 return Status::wrap( $status );
183 }
184 }
185
186 $userLatest = $user->getInstanceFromPrimary() ?? throw new LogicException( 'No user' );
187 $changeStatus = Status::newGood();
188 if (
189 !$this->getHookRunner()->onUserCanChangeEmail( $userLatest, $oldAddr, $newAddr, $changeStatus )
190 && !$changeStatus->isGood()
191 ) {
192 return $changeStatus;
193 }
194
195 $status = $userLatest->setEmailWithConfirmation( $newAddr );
196 if ( !$status->isGood() ) {
197 return $status;
198 }
199
200 LoggerFactory::getInstance( 'authentication' )->info(
201 'Changing email address for {user} from {oldemail} to {newemail}', [
202 'user' => $userLatest->getName(),
203 'oldemail' => $oldAddr,
204 'newemail' => $newAddr,
205 ]
206 );
207
208 $this->getHookRunner()->onPrefsEmailAudit( $userLatest, $oldAddr, $newAddr );
209
210 $userLatest->saveSettings();
211
212 return $status;
213 }
214
216 public function requiresUnblock() {
217 return false;
218 }
219
221 protected function getGroupName() {
222 return 'login';
223 }
224}
225
227class_alias( SpecialChangeEmail::class, 'SpecialChangeEmail' );
wfCgiToArray( $query)
This is the logical opposite of wfArrayToCgi(): it accepts a query string as its argument and returns...
AuthManager is the authentication system in MediaWiki and serves entry point for authentication.
An error page which can definitely be safely rendered using the OutputPage.
Show an error when a user tries to do something they do not have the necessary permissions for.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:195
setSubmitTextMsg( $msg)
Set the text for the submit button to a message.
setTableId( $id)
Set the id of the <table> or outermost <div> element.
addHiddenFields(array $fields)
Add an array of hidden fields to the output Array values are discarded for security reasons (per WebR...
setSubmitID( $t)
Set the id for the submit button.
addHeaderHtml( $html, $section=null)
Add HTML to the header, inside the form.
Definition HTMLForm.php:924
This class is a collection of static functions that serve two purposes:
Definition Html.php:43
Create PSR-3 logger objects.
HTML sanitizer for MediaWiki.
Definition Sanitizer.php:32
Special page which uses an HTMLForm to handle processing.
string null $par
The subpage of the special page.
getUser()
Shortcut to get the User executing this instance.
authorizeAction(?string $action=null)
Utility function for authorizing an action to be performed by the special page.
requireNamedUser( $reasonMsg='exception-nologin-text', $titleMsg='exception-nologin', bool $alwaysRedirectToLoginPage=false)
If the user is not logged in or is a temporary user, throws UserNotLoggedIn.
setAuthManager(AuthManager $authManager)
Set the injected AuthManager from the special page constructor.
getRequest()
Get the WebRequest being used for this instance.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getOutput()
Get the OutputPage being used for this instance.
getAuthority()
Shortcut to get the Authority executing this instance.
getName()
Get the canonical, unlocalized name of this special page without namespace.
Let users change their email address.
doesWrites()
Indicates whether POST requests to this special page require write access to the wiki....
onSuccess()
Do something exciting on successful processing of the form, most likely to show a confirmation messag...
getFormFields()
Get an HTMLForm descriptor array.array
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
alterForm(HTMLForm $form)
Play with the HTMLForm if you need to more substantially.
checkExecutePermissions(User $user)
Called from execute() to check if the given user can perform this action.
getDisplayFormat()
Get display format for the form.See HTMLForm documentation for available values.1....
onSubmit(array $data)
Process the form on submission.bool|string|array|Status As documented for HTMLForm::trySubmit.
requiresUnblock()
Whether this action cannot be executed by a blocked user, default to requiresPost()bool
getLoginSecurityLevel()
Tells if the special page does something security-sensitive and needs extra defense against a stolen ...
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:44
Represents a title within MediaWiki.
Definition Title.php:69
User class for the MediaWiki software.
Definition User.php:130
getInstanceFromPrimary(int $loadFlags=IDBAccessObject::READ_LATEST)
Get an instance of this user that was loaded from the primary DB.
Definition User.php:3239
getEmail()
Get the user's e-mail address.
Definition User.php:1861
getName()
Get the user name, or the IP of an anonymous user.
Definition User.php:1524
isGood()
Returns whether the operation completed and didn't have any error or warnings.