Index: modules/user/user.module =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.module,v retrieving revision 1.775 diff -u -r1.775 user.module --- modules/user/user.module 24 Apr 2007 13:53:15 -0000 1.775 +++ modules/user/user.module 30 Apr 2007 06:15:59 -0000 @@ -801,13 +801,19 @@ 'access callback' => 'user_is_anonymous', 'type' => MENU_LOCAL_TASK, ); - $items['user/reset/%/%/%'] = array( + $items['user/reset-password/%/%/%'] = array( 'title' => t('Reset password'), 'page callback' => 'drupal_get_form', 'page arguments' => array('user_pass_reset', 2, 3, 4), 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); + $items['user/change-mail'] = array( + 'title' => t('Change e-mail'), + 'callback' => 'user_change_mail', + 'access' => TRUE, + 'type' => MENU_CALLBACK + ); $items['user/help'] = array( 'title' => t('Help'), 'page callback' => 'user_help_page', @@ -1250,7 +1256,7 @@ $form['message'] = array('#value' => t('

This is a one-time login for %user_name and will expire on %expiration_date

Click on this button to login to the site and change your password.

', array('%user_name' => $account->name, '%expiration_date' => format_date($timestamp + $timeout)))); $form['help'] = array('#value' => '

'. t('This login can be used only once.') .'

'); $form['submit'] = array('#type' => 'submit', '#value' => t('Log in')); - $form['#action'] = url("user/reset/$uid/$timestamp/$hashed_pass/login"); + $form['#action'] = url("user/reset-password/$uid/$timestamp/$hashed_pass/login"); return $form; } } @@ -1269,7 +1275,7 @@ function user_pass_reset_url($account) { $timestamp = time(); - return url("user/reset/$account->uid/$timestamp/". user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE)); + return url("user/reset-password/$account->uid/$timestamp/". user_pass_rehash($account->pass, $timestamp, $account->login), NULL, NULL, TRUE); } function user_pass_rehash($password, $timestamp, $login) { @@ -1544,6 +1550,89 @@ if (isset($edit['roles'])) { $edit['roles'] = array_filter($edit['roles']); } + if ($user->mail != $edit['mail'] && !user_access('administer users')) { + $timestamp = time(); + $pass = $edit['pass'] ? md5($edit['pass']) : $user->pass; + $hash = user_email_rehash($pass, $edit['mail']); + $url = url("user/change-mail/$user->uid/$timestamp/". $edit['mail'] ."/$hash", NULL, NULL, TRUE); + $variables = array('!username' => $user->name, '!site' => variable_get('site_name', 'drupal'), '!email_url' => $url); + $subject = _user_mail_text('mail_change_subject', $variables); + $body = _user_mail_text('mail_change_body', $variables); + $from = variable_get('site_mail', ini_get('sendmail_from')); + if ($mail_success = drupal_mail('user_change_mail', $edit['mail'], $subject, $body, $from)) { + $body = _user_mail_text('mail_change_original_body', $variables); + drupal_mail('user_change_mail_original', $user->mail, $subject, $body, $from); + drupal_set_message(t('You will receive a confirmation e-mail at your new e-mail address shortly. You must follow the link provided in that e-mail within one day in order to complete your change.')); + } + unset($edit['mail']); + } +} + +function user_email_rehash($pass, $mail) { + return md5($pass . $mail); +} + +/** + * Menu callback; process one time email change confirm and redirects to the user page on success. + */ +function user_change_mail($uid, $timestamp, $new_mail, $hash, $action = '') { + global $user; + + $account = user_load(array('uid' => $uid)); + + // Time out, in seconds, until login URL expires. 24 hours = 86400 seconds. + $timeout = 86400; + $current = time(); + // Some redundant checks for extra security ? + if ($timestamp < $current && $account = user_load(array('uid' => $uid, 'status' => 1)) ) { + if ($current - $timestamp > $timeout) { + drupal_set_message(t('You have tried to use a one-time e-mail change link for %account that has expired--your change of e-mail request was not completed. Please visit your account edit page if you wish to attempt the change again.', array('%account' => $account->name)), 'error'); + if ($account->uid == $user->uid) { + drupal_goto("user/$account->uid/edit"); + } + else { + drupal_goto(''); + } + } + else if ($user->uid && $user->uid != $account->uid) { + drupal_set_message(t('You are currently logged in as %user, and are attempting to confirm an e-mail change for %account, which is not allowed. Please log in as %account and initiate a new change of e-mail request.', array('%user' => $user->name, '%account' => $account->name)), 'error'); + drupal_goto(''); + } + else if ($hash != user_email_rehash($account->pass, $new_mail)) { + drupal_set_message(t('There was a problem verifying your change of e-mail request--please visit your account edit page and attempt the change again'), 'error'); + if ($user->uid) { + drupal_goto("user/$user->uid/edit"); + } + else { + drupal_goto('user/login', "destination=user/$user->uid/edit"); + } + } + else if ($timestamp > $account->login && $timestamp < $current) { + watchdog('user', t('User %name used one-time e-mail change link at time %timestamp.', array('%name' => $account->name, '%timestamp' => $timestamp))); + db_query("UPDATE {users} SET mail = '%s' WHERE uid = %d", $new_mail, $account->uid); + drupal_set_message(t('Your e-mail address is now %mail.', array('%mail' => $new_mail))); + if ($user->uid) { + drupal_goto('user/' . $user->uid); + } + else { + drupal_goto('user'); + } + } + else { + drupal_set_message(t('You have tried to use a one-time e-mail change link which has either been used or has expired. Please request a new one.'), 'error'); + if ($user->uid) { + drupal_goto('user/'. $user->uid .'/edit'); + } + else { + drupal_goto('user/login', 'destination=user/'. $user->uid .'/edit'); + } + } + } + else { + // Deny access, no more clues. + // Everything will be in the watchdog's URL for the administrator to check. + drupal_access_denied(); + } } function user_edit($category = 'account') { @@ -1688,6 +1777,12 @@ return t('Replacement login information for !username at !site', $variables); case 'pass_body': return t("!username,\n\nA request to reset the password for your account has been made at !site.\n\nYou may now log in to !uri_brief clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once. It expires after one day and nothing will happen if it's not used.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.", $variables); + case 'mail_change_subject': + return t('E-mail change information for !username at !site', $variables); + case 'mail_change_body': + return t("!username,\n\nA request to change your e-mail address has been made at !site. You need to verify the change by clicking on the link below or copying and pasting it in your browser:\n\n!email_url\n\nThis is a one-time URL, so it can be used only once. It expires after one day. If not used, your e-mail address at !site will not change.", $variables); + case 'mail_change_original_body': + return t("!username,\n\nA request to change your e-mail address has been made at !site. In order to complete the change you will need to follow the instructions sent to your new e-mail address within one day.", $variables); } } }