More modificiations to session handling to support multiple tabs

Chris Pollett [2024-06-24 17:Jun:th]
More modificiations to session handling to support multiple tabs
Filename
src/configs/Config.php
src/controllers/Controller.php
diff --git a/src/configs/Config.php b/src/configs/Config.php
index ba199f6e6..c94792c02 100755
--- a/src/configs/Config.php
+++ b/src/configs/Config.php
@@ -650,6 +650,8 @@ nsconddefine('TIMEZONE', 'America/Los_Angeles');
  */
 nsconddefine('SESSION_NAME', "yioopbiscuit");
 nsconddefine('CSRF_TOKEN', "YIOOP_TOKEN");
+//max number of devices a user can simultaneously be logged in from
+nsconddefine('MAX_DEVICES', 5);
 nsconddefine('RESOURCE_CACHE_TIME', "" . ONE_HOUR);
 nsconddefine('AUTOLOGOUT', "" . ONE_HOUR);
 nsconddefine('COOKIE_LIFETIME', "" . ONE_YEAR);
diff --git a/src/controllers/Controller.php b/src/controllers/Controller.php
index 870787ddc..3cb466e0a 100755
--- a/src/controllers/Controller.php
+++ b/src/controllers/Controller.php
@@ -623,9 +623,28 @@ abstract class Controller
     public function generateCSRFToken($user)
     {
         $time = time();
-        $_SESSION['OLD_CSRF_TIME'] = (isset($_SESSION['CSRF_TIME'])) ?
-            $_SESSION['CSRF_TIME'] : 0;
-        $_SESSION['CSRF_TIME'] = $time;
+        $ip_address = L\remoteAddress();
+        /*remember _SESSION loaded from UserModel::getUserSession not just
+            cookie
+         */
+        $_SESSION['OLD_CSRF_TIME'] = (empty($_SESSION['OLD_CSRF_TIME']) ||
+            !is_array($_SESSION['OLD_CSRF_TIME'])) ? [] :
+            $_SESSION['OLD_CSRF_TIME']; // create empty array if not set
+        if (count($_SESSION['OLD_CSRF_TIME']) > C\MAX_DEVICES) {
+            $_SESSION['OLD_CSRF_TIME'] = array_slice($_SESSION['OLD_CSRF_TIME'],
+                -C\MAX_DEVICES);
+        }
+        $_SESSION['OLD_CSRF_TIME'][$ip_address] =
+            (isset($_SESSION['CSRF_TIME'][$ip_address])) ?
+            $_SESSION['CSRF_TIME'][$ip_address] : 0;
+        $_SESSION['CSRF_TIME'] = (empty($_SESSION['CSRF_TIME']) ||
+            !is_array($_SESSION['CSRF_TIME'])) ? [] :
+            $_SESSION['CSRF_TIME']; // create empty array if not set
+        if (count($_SESSION['CSRF_TIME']) > C\MAX_DEVICES) {
+            $_SESSION['CSRF_TIME'] = array_slice($_SESSION['CSRF_TIME'],
+                -C\MAX_DEVICES);
+        }
+        $_SESSION['CSRF_TIME'][$ip_address] = $time;
         return L\crawlHash($user . $time . C\AUTH_KEY)."*$time";
     }
     /**
@@ -674,9 +693,14 @@ abstract class Controller
             $token_parts = explode("*", $_REQUEST[$token_name]);
             if (isset($token_parts[1])) {
                 $timestamp_to_check = $token_parts[1];
+                $ip_address = L\remoteAddress();
+                /*remember _SESSION loaded from UserModel::getUserSession not
+                    just cookie
+                 */
                 if ($action == "") {
-                    if (isset($_SESSION['OLD_CSRF_TIME']) &&
-                        $token_parts[1] == $_SESSION['OLD_CSRF_TIME']) {
+                    if (isset($_SESSION['OLD_CSRF_TIME'][$ip_address]) &&
+                        $token_parts[1] ==
+                            $_SESSION['OLD_CSRF_TIME'][$ip_address]) {
                         $token_okay = true;
                     }
                 } else {
@@ -687,10 +711,10 @@ abstract class Controller
                         $_SESSION['OLD_ACTION_STAMPS'][$action] =
                             $timestamp_to_check;
                         $token_okay = true;
-                        $cull_time = time() - C\ONE_HOUR;
+                        $cull_time = time() - C\AUTOLOGOUT;
                         foreach ($_SESSION['OLD_ACTION_STAMPS'] as $act =>
                             $time) {
-                            if ($time < $cull_time) {
+                            if (intval($time) < $cull_time) {
                                 unset($_SESSION['OLD_ACTION_STAMPS'][$act]);
                             }
                         }
@@ -702,6 +726,8 @@ abstract class Controller
     }
     /**
      * Used to return just the timestamp portion of the CSRF token
+     * if it exists. 0 if the user has a non-expired session from this
+     * ip address, but no CSRF token, and -1 otherwise.
      *
      * @param string $token_name name of a $_REQUEST field used to hold a
      *     CSRF_TOKEN
@@ -709,12 +735,18 @@ abstract class Controller
      */
     public function getCSRFTime($token_name)
     {
-        $timestamp = 0;
+        $timestamp = -1;
+        $ip_address = L\remoteAddress();
         if (isset($_REQUEST[$token_name])) {
             $token_parts = explode("*", $_REQUEST[$token_name]);
             if (isset($token_parts[1])) {
                 return intval($token_parts[1]);
             }
+        } else if (!empty($_SESSION['OLD_CSRF_TIME'][$ip_address])) {
+            $old_time = $_SESSION['OLD_CSRF_TIME'][$ip_address];
+            if (time() - intval($old_time) < C\AUTOLOGOUT) {
+                $timestamp = 0;
+            }
         }
         return $timestamp;
     }
ViewGit