From c04633361002df67a04458ac86ba449001eb9287 Mon Sep 17 00:00:00 2001
From: Dries Buytaert <dries@buytaert.net>
Date: Fri, 27 Jan 2006 18:49:48 +0000
Subject: [PATCH] - Patch #35499 by samo, m3avrck, et al: one-time login link
 does not provide adequate feedback to user errors.

---
 modules/user.module      | 72 +++++++++++++++++++++++-----------------
 modules/user/user.module | 72 +++++++++++++++++++++++-----------------
 2 files changed, 84 insertions(+), 60 deletions(-)

diff --git a/modules/user.module b/modules/user.module
index 333d10d49430..7daec0a087d3 100644
--- a/modules/user.module
+++ b/modules/user.module
@@ -683,7 +683,7 @@ function user_menu($may_cache) {
     $items[] = array('path' => 'user/password', 'title' => t('request new password'),
       'callback' => 'user_pass', 'access' => $user->uid == 0, 'type' => MENU_LOCAL_TASK);
     $items[] = array('path' => 'user/reset', 'title' => t('reset password'),
-      'callback' => 'user_pass_reset', 'access' => $user->uid == 0, 'type' => MENU_CALLBACK);
+      'callback' => 'user_pass_reset', 'access' => TRUE, 'type' => MENU_CALLBACK);
     $items[] = array('path' => 'user/help', 'title' => t('help'),
       'callback' => 'user_help_page', 'type' => MENU_CALLBACK);
 
@@ -1011,38 +1011,50 @@ function theme_user_pass($form) {
 }
 
 /**
- * Menu callback; process one time login URL, and redirects to the user page on success.
+ * Menu callback; process one time login link and redirects to the user page on success.
  */
 function user_pass_reset($uid, $timestamp, $hashed_pass) {
   global $user;
-  // 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 && is_numeric($uid) && $account = user_load(array('uid' => $uid, 'status' => 1)) ) {
-    // No time out for first time login.
-    if ($account->login && $current - $timestamp > $timeout) {
-      drupal_set_message(t('You have tried to use a one time login URL which has expired. Please request a new one using the form below.'));
-      drupal_goto('user/password');
-    }
-    if ($account->uid && !$user->uid && !empty($account) && $timestamp > $account->login && $timestamp < $current &&
-        $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
-      watchdog('user', t('One time login URL used for %name with timestamp %timestamp.', array('%name' => "<em>$account->name</em>", '%timestamp' => $timestamp)));
-      // Update the user table noting user has logged in.
-      // And this also makes this hashed password a one-time-only login.
-      db_query("UPDATE {users} SET login = %d WHERE uid = %d", time(), $account->uid);
-      // Now we can set the new user.
-      $user = $account;
-      // And proceed with normal login, going to user page.
-      user_module_invoke('login', $edit, $user);
-      drupal_set_message(t("You have used a one-time login, which won't be valid anymore."));
-      drupal_set_message(t('Please change your password.'));
-      drupal_goto('user/'. $user->uid .'/edit');
-    }
-  }
-  // Deny access, no more clues.
-  // Everything will be in the watchdog's URL for the administrator to check.
-  drupal_access_denied();
+
+  // Check if the user is already logged in. The back button is often the culprit here.
+  if ($user->uid) {
+    drupal_set_message(t('You have already used this one-time login link. It is not necessary to use this link to login anymore. You are already logged in.'));
+    drupal_goto(variable_get('site_frontpage', 'node'));
+  }
+  else {
+    // 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)) ) {
+      // No time out for first time login.
+      if ($account->login && $current - $timestamp > $timeout) {
+        drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'));
+        drupal_goto('user/password');
+      }
+      else if ($account->uid && $timestamp > $account->login && $timestamp < $current && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
+        watchdog('user', t('User %name used one-time login link at time %timestamp.', array('%name' => "<em>$account->name</em>", '%timestamp' => $timestamp)));
+        // Update the user table noting user has logged in.
+        // And this also makes this hashed password a one-time-only login.
+        db_query("UPDATE {users} SET login = %d WHERE uid = %d", time(), $account->uid);
+        // Now we can set the new user.
+        $user = $account;
+        // And proceed with normal login, going to user page.
+        user_module_invoke('login', $edit, $user);
+        drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to login. Please change your password.'));
+        drupal_goto('user/'. $user->uid .'/edit');
+      }
+      else {
+        drupal_set_message(t('You have tried to use a one-time login link which has either been used or is no longer valid. Please request a new one using the form below.'));
+        drupal_goto('user/password');
+      }
+    }
+    else {
+      // Deny access, no more clues.
+      // Everything will be in the watchdog's URL for the administrator to check.
+      drupal_access_denied();
+    }
+  }
 }
 
 function user_pass_reset_url($account) {
diff --git a/modules/user/user.module b/modules/user/user.module
index 333d10d49430..7daec0a087d3 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -683,7 +683,7 @@ function user_menu($may_cache) {
     $items[] = array('path' => 'user/password', 'title' => t('request new password'),
       'callback' => 'user_pass', 'access' => $user->uid == 0, 'type' => MENU_LOCAL_TASK);
     $items[] = array('path' => 'user/reset', 'title' => t('reset password'),
-      'callback' => 'user_pass_reset', 'access' => $user->uid == 0, 'type' => MENU_CALLBACK);
+      'callback' => 'user_pass_reset', 'access' => TRUE, 'type' => MENU_CALLBACK);
     $items[] = array('path' => 'user/help', 'title' => t('help'),
       'callback' => 'user_help_page', 'type' => MENU_CALLBACK);
 
@@ -1011,38 +1011,50 @@ function theme_user_pass($form) {
 }
 
 /**
- * Menu callback; process one time login URL, and redirects to the user page on success.
+ * Menu callback; process one time login link and redirects to the user page on success.
  */
 function user_pass_reset($uid, $timestamp, $hashed_pass) {
   global $user;
-  // 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 && is_numeric($uid) && $account = user_load(array('uid' => $uid, 'status' => 1)) ) {
-    // No time out for first time login.
-    if ($account->login && $current - $timestamp > $timeout) {
-      drupal_set_message(t('You have tried to use a one time login URL which has expired. Please request a new one using the form below.'));
-      drupal_goto('user/password');
-    }
-    if ($account->uid && !$user->uid && !empty($account) && $timestamp > $account->login && $timestamp < $current &&
-        $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
-      watchdog('user', t('One time login URL used for %name with timestamp %timestamp.', array('%name' => "<em>$account->name</em>", '%timestamp' => $timestamp)));
-      // Update the user table noting user has logged in.
-      // And this also makes this hashed password a one-time-only login.
-      db_query("UPDATE {users} SET login = %d WHERE uid = %d", time(), $account->uid);
-      // Now we can set the new user.
-      $user = $account;
-      // And proceed with normal login, going to user page.
-      user_module_invoke('login', $edit, $user);
-      drupal_set_message(t("You have used a one-time login, which won't be valid anymore."));
-      drupal_set_message(t('Please change your password.'));
-      drupal_goto('user/'. $user->uid .'/edit');
-    }
-  }
-  // Deny access, no more clues.
-  // Everything will be in the watchdog's URL for the administrator to check.
-  drupal_access_denied();
+
+  // Check if the user is already logged in. The back button is often the culprit here.
+  if ($user->uid) {
+    drupal_set_message(t('You have already used this one-time login link. It is not necessary to use this link to login anymore. You are already logged in.'));
+    drupal_goto(variable_get('site_frontpage', 'node'));
+  }
+  else {
+    // 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)) ) {
+      // No time out for first time login.
+      if ($account->login && $current - $timestamp > $timeout) {
+        drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'));
+        drupal_goto('user/password');
+      }
+      else if ($account->uid && $timestamp > $account->login && $timestamp < $current && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
+        watchdog('user', t('User %name used one-time login link at time %timestamp.', array('%name' => "<em>$account->name</em>", '%timestamp' => $timestamp)));
+        // Update the user table noting user has logged in.
+        // And this also makes this hashed password a one-time-only login.
+        db_query("UPDATE {users} SET login = %d WHERE uid = %d", time(), $account->uid);
+        // Now we can set the new user.
+        $user = $account;
+        // And proceed with normal login, going to user page.
+        user_module_invoke('login', $edit, $user);
+        drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to login. Please change your password.'));
+        drupal_goto('user/'. $user->uid .'/edit');
+      }
+      else {
+        drupal_set_message(t('You have tried to use a one-time login link which has either been used or is no longer valid. Please request a new one using the form below.'));
+        drupal_goto('user/password');
+      }
+    }
+    else {
+      // Deny access, no more clues.
+      // Everything will be in the watchdog's URL for the administrator to check.
+      drupal_access_denied();
+    }
+  }
 }
 
 function user_pass_reset_url($account) {
-- 
GitLab