1<?php 2/** 3 * Implements Special:PasswordReset 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 * @ingroup SpecialPage 22 */ 23 24/** 25 * Special page for requesting a password reset email. 26 * 27 * Requires the TemporaryPasswordPrimaryAuthenticationProvider and the 28 * EmailNotificationSecondaryAuthenticationProvider (or something providing equivalent 29 * functionality) to be enabled. 30 * 31 * @ingroup SpecialPage 32 */ 33class SpecialPasswordReset extends FormSpecialPage { 34 /** @var PasswordReset */ 35 private $passwordReset; 36 37 /** 38 * @var Status 39 */ 40 private $result; 41 42 /** 43 * @var string Identifies which password reset field was specified by the user. 44 */ 45 private $method; 46 47 /** 48 * @param PasswordReset $passwordReset 49 */ 50 public function __construct( PasswordReset $passwordReset ) { 51 parent::__construct( 'PasswordReset', 'editmyprivateinfo' ); 52 53 $this->passwordReset = $passwordReset; 54 } 55 56 public function doesWrites() { 57 return true; 58 } 59 60 public function userCanExecute( User $user ) { 61 return $this->passwordReset->isAllowed( $user )->isGood(); 62 } 63 64 public function checkExecutePermissions( User $user ) { 65 $status = Status::wrap( $this->passwordReset->isAllowed( $user ) ); 66 if ( !$status->isGood() ) { 67 throw new ErrorPageError( 'internalerror', $status->getMessage() ); 68 } 69 70 parent::checkExecutePermissions( $user ); 71 } 72 73 /** 74 * @param string|null $par 75 */ 76 public function execute( $par ) { 77 $out = $this->getOutput(); 78 $out->disallowUserJs(); 79 parent::execute( $par ); 80 } 81 82 protected function getFormFields() { 83 $resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' ); 84 $a = []; 85 if ( isset( $resetRoutes['username'] ) && $resetRoutes['username'] ) { 86 $a['Username'] = [ 87 'type' => 'text', 88 'default' => $this->getRequest()->getSession()->suggestLoginUsername(), 89 'label-message' => 'passwordreset-username', 90 ]; 91 92 if ( $this->getUser()->isRegistered() ) { 93 $a['Username']['default'] = $this->getUser()->getName(); 94 } 95 } 96 97 if ( isset( $resetRoutes['email'] ) && $resetRoutes['email'] ) { 98 $a['Email'] = [ 99 'type' => 'email', 100 'label-message' => 'passwordreset-email', 101 ]; 102 } 103 104 return $a; 105 } 106 107 protected function getDisplayFormat() { 108 return 'ooui'; 109 } 110 111 public function alterForm( HTMLForm $form ) { 112 $resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' ); 113 114 $form->setSubmitDestructive(); 115 116 $form->addHiddenFields( $this->getRequest()->getValues( 'returnto', 'returntoquery' ) ); 117 118 $i = 0; 119 if ( isset( $resetRoutes['username'] ) && $resetRoutes['username'] ) { 120 $i++; 121 } 122 if ( isset( $resetRoutes['email'] ) && $resetRoutes['email'] ) { 123 $i++; 124 } 125 126 $message = ( $i > 1 ) ? 'passwordreset-text-many' : 'passwordreset-text-one'; 127 128 $form->setHeaderText( $this->msg( $message, $i )->parseAsBlock() ); 129 $form->setSubmitTextMsg( 'mailmypassword' ); 130 } 131 132 /** 133 * Process the form. At this point we know that the user passes all the criteria in 134 * userCanExecute(), and if the data array contains 'Username', etc, then Username 135 * resets are allowed. 136 * @param array $data 137 * @throws MWException 138 * @throws ThrottledError|PermissionsError 139 * @return Status 140 */ 141 public function onSubmit( array $data ) { 142 $username = $data['Username'] ?? null; 143 $email = $data['Email'] ?? null; 144 145 $this->method = $username ? 'username' : 'email'; 146 $this->result = Status::wrap( 147 $this->passwordReset->execute( $this->getUser(), $username, $email ) ); 148 149 if ( $this->result->hasMessage( 'actionthrottledtext' ) ) { 150 throw new ThrottledError; 151 } 152 153 return $this->result; 154 } 155 156 /** 157 * Show a message on the successful processing of the form. 158 * This doesn't necessarily mean a reset email was sent. 159 */ 160 public function onSuccess() { 161 $output = $this->getOutput(); 162 163 // Information messages. 164 $output->addWikiMsg( 'passwordreset-success' ); 165 $output->addWikiMsg( 'passwordreset-success-details-generic', 166 $this->getConfig()->get( 'PasswordReminderResendTime' ) ); 167 168 // Confirmation of what the user has just submitted. 169 $info = "\n"; 170 $postVals = $this->getRequest()->getPostValues(); 171 if ( isset( $postVals['wpUsername'] ) && $postVals['wpUsername'] !== '' ) { 172 $info .= "* " . $this->msg( 'passwordreset-username' ) . ' ' 173 . wfEscapeWikiText( $postVals['wpUsername'] ) . "\n"; 174 } 175 if ( isset( $postVals['wpEmail'] ) && $postVals['wpEmail'] !== '' ) { 176 $info .= "* " . $this->msg( 'passwordreset-email' ) . ' ' 177 . wfEscapeWikiText( $postVals['wpEmail'] ) . "\n"; 178 } 179 $output->addWikiMsg( 'passwordreset-success-info', $info ); 180 181 // Link to main page. 182 $output->returnToMain(); 183 } 184 185 /** 186 * Hide the password reset page if resets are disabled. 187 * @return bool 188 */ 189 public function isListed() { 190 if ( $this->passwordReset->isAllowed( $this->getUser() )->isGood() ) { 191 return parent::isListed(); 192 } 193 194 return false; 195 } 196 197 protected function getGroupName() { 198 return 'users'; 199 } 200} 201