SpecialConfirmEmail.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <?php
  2. /**
  3. * Implements Special:Confirmemail
  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. use MediaWiki\MediaWikiServices;
  24. /**
  25. * Special page allows users to request email confirmation message, and handles
  26. * processing of the confirmation code when the link in the email is followed
  27. *
  28. * @ingroup SpecialPage
  29. * @author Brion Vibber
  30. * @author Rob Church <robchur@gmail.com>
  31. */
  32. class SpecialConfirmEmail extends UnlistedSpecialPage {
  33. public function __construct() {
  34. parent::__construct( 'Confirmemail', 'editmyprivateinfo' );
  35. }
  36. public function doesWrites() {
  37. return true;
  38. }
  39. /**
  40. * Main execution point
  41. *
  42. * @param null|string $code Confirmation code passed to the page
  43. * @throws PermissionsError
  44. * @throws ReadOnlyError
  45. * @throws UserNotLoggedIn
  46. */
  47. function execute( $code ) {
  48. // Ignore things like master queries/connections on GET requests.
  49. // It's very convenient to just allow formless link usage.
  50. $trxProfiler = Profiler::instance()->getTransactionProfiler();
  51. $this->setHeaders();
  52. $this->checkReadOnly();
  53. $this->checkPermissions();
  54. // This could also let someone check the current email address, so
  55. // require both permissions.
  56. if ( !MediaWikiServices::getInstance()
  57. ->getPermissionManager()
  58. ->userHasRight( $this->getUser(), 'viewmyprivateinfo' )
  59. ) {
  60. throw new PermissionsError( 'viewmyprivateinfo' );
  61. }
  62. if ( $code === null || $code === '' ) {
  63. $this->requireLogin( 'confirmemail_needlogin' );
  64. if ( Sanitizer::validateEmail( $this->getUser()->getEmail() ) ) {
  65. $this->showRequestForm();
  66. } else {
  67. $this->getOutput()->addWikiMsg( 'confirmemail_noemail' );
  68. }
  69. } else {
  70. $old = $trxProfiler->setSilenced( true );
  71. $this->attemptConfirm( $code );
  72. $trxProfiler->setSilenced( $old );
  73. }
  74. }
  75. /**
  76. * Show a nice form for the user to request a confirmation mail
  77. */
  78. function showRequestForm() {
  79. $user = $this->getUser();
  80. $out = $this->getOutput();
  81. if ( !$user->isEmailConfirmed() ) {
  82. $descriptor = [];
  83. if ( $user->isEmailConfirmationPending() ) {
  84. $descriptor += [
  85. 'pending' => [
  86. 'type' => 'info',
  87. 'raw' => true,
  88. 'default' => "<div class=\"error mw-confirmemail-pending\">\n" .
  89. $this->msg( 'confirmemail_pending' )->escaped() .
  90. "\n</div>",
  91. ],
  92. ];
  93. }
  94. $out->addWikiMsg( 'confirmemail_text' );
  95. $form = HTMLForm::factory( 'ooui', $descriptor, $this->getContext() );
  96. $form
  97. ->setMethod( 'post' )
  98. ->setAction( $this->getPageTitle()->getLocalURL() )
  99. ->setSubmitTextMsg( 'confirmemail_send' )
  100. ->setSubmitCallback( [ $this, 'submitSend' ] );
  101. $retval = $form->show();
  102. if ( $retval === true ) {
  103. // should never happen, but if so, don't let the user without any message
  104. $out->addWikiMsg( 'confirmemail_sent' );
  105. } elseif ( $retval instanceof Status && $retval->isGood() ) {
  106. $out->addWikiTextAsInterface( $retval->getValue() );
  107. }
  108. } else {
  109. // date and time are separate parameters to facilitate localisation.
  110. // $time is kept for backward compat reasons.
  111. // 'emailauthenticated' is also used in SpecialPreferences.php
  112. $lang = $this->getLanguage();
  113. $emailAuthenticated = $user->getEmailAuthenticationTimestamp();
  114. $time = $lang->userTimeAndDate( $emailAuthenticated, $user );
  115. $d = $lang->userDate( $emailAuthenticated, $user );
  116. $t = $lang->userTime( $emailAuthenticated, $user );
  117. $out->addWikiMsg( 'emailauthenticated', $time, $d, $t );
  118. }
  119. }
  120. /**
  121. * Callback for HTMLForm send confirmation mail.
  122. *
  123. * @return Status Status object with the result
  124. */
  125. public function submitSend() {
  126. $status = $this->getUser()->sendConfirmationMail();
  127. if ( $status->isGood() ) {
  128. return Status::newGood( $this->msg( 'confirmemail_sent' )->text() );
  129. } else {
  130. return Status::newFatal( new RawMessage(
  131. $status->getWikiText( 'confirmemail_sendfailed', false, $this->getLanguage() )
  132. ) );
  133. }
  134. }
  135. /**
  136. * Attempt to confirm the user's email address and show success or failure
  137. * as needed; if successful, take the user to log in
  138. *
  139. * @param string $code Confirmation code
  140. */
  141. private function attemptConfirm( $code ) {
  142. $user = User::newFromConfirmationCode( $code, User::READ_EXCLUSIVE );
  143. if ( !is_object( $user ) ) {
  144. $this->getOutput()->addWikiMsg( 'confirmemail_invalid' );
  145. return;
  146. }
  147. // rate limit email confirmations
  148. if ( $user->pingLimiter( 'confirmemail' ) ) {
  149. $this->getOutput()->addWikiMsg( 'actionthrottledtext' );
  150. return;
  151. }
  152. $user->confirmEmail();
  153. $user->saveSettings();
  154. $message = $this->getUser()->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success';
  155. $this->getOutput()->addWikiMsg( $message );
  156. if ( !$this->getUser()->isLoggedIn() ) {
  157. $title = SpecialPage::getTitleFor( 'Userlogin' );
  158. $this->getOutput()->returnToMain( true, $title );
  159. }
  160. }
  161. }