Index: includes/AutoLoader.php =================================================================== --- includes/AutoLoader.php (revision 32394) +++ includes/AutoLoader.php (working copy) @@ -73,6 +73,7 @@ 'eAccelBagOStuff' => 'includes/BagOStuff.php', 'EditPage' => 'includes/EditPage.php', 'EmailConfirmation' => 'includes/SpecialConfirmemail.php', + 'EmailInvalidation' => 'includes/SpecialConfirmemail.php', 'EmaillingJob' => 'includes/EmaillingJob.php', 'EmaillingJob' => 'includes/JobQueue.php', 'EmailNotification' => 'includes/UserMailer.php', Index: includes/SpecialConfirmemail.php =================================================================== --- includes/SpecialConfirmemail.php (revision 32394) +++ includes/SpecialConfirmemail.php (working copy) @@ -101,4 +101,44 @@ } - +/** + * Special page allows users to cancel an email confirmation using the e-mail + * confirmation code + * + * @addtogroup SpecialPage + */ +class EmailInvalidation extends UnlistedSpecialPage { + + public function __construct() { + parent::__construct( 'Invalidateemail' ); + } + + function execute( $code ) { + $this->setHeaders(); + $this->attemptInvalidate( $code ); + } + + /** + * Attempt to invalidate the user's email address and show success or failure + * as needed; if successful, link to main page + * + * @param $code Confirmation code + */ + function attemptInvalidate( $code ) { + global $wgUser, $wgOut; + $user = User::newFromConfirmationCode( $code ); + if( is_object( $user ) ) { + $user->invalidateEmail(); + if( $user->invalidateEmail() ) { + $wgOut->addWikiMsg( 'confirmemail_invalidated' ); + if( !$wgUser->isLoggedIn() ) { + $wgOut->returnToMain(); + } + } else { + $wgOut->addWikiMsg( 'confirmemail_error' ); + } + } else { + $wgOut->addWikiMsg( 'confirmemail_invalid' ); + } + } +} Index: includes/SpecialPage.php =================================================================== --- includes/SpecialPage.php (revision 32394) +++ includes/SpecialPage.php (working copy) @@ -182,6 +182,7 @@ if( $wgEmailAuthentication ) { self::$mList['Confirmemail'] = 'EmailConfirmation'; + self::$mList['Invalidateemail'] = 'EmailInvalidation'; } # Add extension special pages Index: includes/User.php =================================================================== --- includes/User.php (revision 32394) +++ includes/User.php (working copy) @@ -2020,7 +2020,9 @@ 'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ), 'user_options' => $this->encodeOptions(), 'user_touched' => $dbw->timestamp($this->mTouched), - 'user_token' => $this->mToken + 'user_token' => $this->mToken, + 'user_email_token' => $this->mEmailToken, + 'user_email_token_expires' => $this->mEmailTokenExpires ), array( /* WHERE */ 'user_id' => $this->mId ), __METHOD__ @@ -2376,7 +2378,7 @@ } /** - * Generate a new e-mail confirmation token and send a confirmation + * Generate a new e-mail confirmation token and send a confirmation/invalidation * mail to the user's given address. * * @return mixed True on success, a WikiError object on failure. @@ -2384,13 +2386,16 @@ function sendConfirmationMail() { global $wgContLang; $expiration = null; // gets passed-by-ref and defined in next line. - $url = $this->confirmationTokenUrl( $expiration ); + $token = $this->confirmationToken( $expiration ); + $url = $this->confirmationTokenUrl( $token ); + $invalidateURL = $this->invalidationTokenUrl( $token ); return $this->sendMail( wfMsg( 'confirmemail_subject' ), wfMsg( 'confirmemail_body', wfGetIP(), $this->getName(), $url, - $wgContLang->timeanddate( $expiration, false ) ) ); + $wgContLang->timeanddate( $expiration, false ), + $invalidateURL ) ); } /** @@ -2424,32 +2429,35 @@ $now = time(); $expires = $now + 7 * 24 * 60 * 60; $expiration = wfTimestamp( TS_MW, $expires ); - $token = $this->generateToken( $this->mId . $this->mEmail . $expires ); $hash = md5( $token ); - - $dbw = wfGetDB( DB_MASTER ); - $dbw->update( 'user', - array( 'user_email_token' => $hash, - 'user_email_token_expires' => $dbw->timestamp( $expires ) ), - array( 'user_id' => $this->mId ), - __METHOD__ ); - + $this->load(); + $this->mEmailToken = $hash; + $this->mEmailTokenExpires = $expiration; + $this->saveSettings(); return $token; } /** - * Generate and store a new e-mail confirmation token, and return - * the URL the user can use to confirm. - * @param &$expiration mixed output: accepts the expiration time + * Return a URL the user can use to confirm their email address. + * @param $token: accepts the email confirmation token * @return string * @private */ - function confirmationTokenUrl( &$expiration ) { - $token = $this->confirmationToken( $expiration ); + function confirmationTokenUrl( $token ) { $title = SpecialPage::getTitleFor( 'Confirmemail', $token ); return $title->getFullUrl(); } + /** + * Return a URL the user can use to invalidate their email address. + * @param $token: accepts the email confirmation token + * @return string + * @private + */ + function invalidationTokenUrl( $token ) { + $title = SpecialPage::getTitleFor( 'Invalidateemail', $token ); + return $title->getFullUrl(); + } /** * Mark the e-mail address confirmed and save. @@ -2460,6 +2468,19 @@ $this->saveSettings(); return true; } + + /** + * Invalidate the user's email confirmation, unauthenticate the email + * if it was already confirmed and save. + */ + function invalidateEmail() { + $this->load(); + $this->mEmailToken = null; + $this->mEmailTokenExpires = null; + $this->mEmailAuthenticated = null; + $this->saveSettings(); + return true; + } /** * Is this user allowed to send e-mails within limits of current Index: languages/messages/MessagesEn.php =================================================================== --- languages/messages/MessagesEn.php (revision 32434) +++ languages/messages/MessagesEn.php (working copy) @@ -428,6 +428,7 @@ 'Withoutinterwiki' => array( 'WithoutInterwiki' ), 'MergeHistory' => array( 'MergeHistory' ), 'Filepath' => array( 'FilePath' ), + 'Invalidateemail' => array( 'InvalidateEmail' ), ); /** @@ -2908,13 +2909,19 @@ 'confirmemail_loggedin' => 'Your e-mail address has now been confirmed.', 'confirmemail_error' => 'Something went wrong saving your confirmation.', 'confirmemail_subject' => '{{SITENAME}} e-mail address confirmation', -'confirmemail_body' => 'Someone, probably you, from IP address $1, has registered an account "$2" with this e-mail address on {{SITENAME}}. +'confirmemail_body' => 'Someone, probably you, from IP address $1, +has registered an account "$2" with this e-mail address on {{SITENAME}}. -To confirm that this account really does belong to you and activate e-mail features on {{SITENAME}}, open this link in your browser: +To confirm that this account really does belong to you and activate +e-mail features on {{SITENAME}}, open this link in your browser: $3 -If this is *not* you, don\'t follow the link. +If you did *not* register the account, follow this link +to cancel the email address confirmation: + +$5 + This confirmation code will expire at $4.', # Scary transclusion