Limit the number of active sessions per user
authorTim Düsterhus <duesterhus@woltlab.com>
Tue, 16 Mar 2021 13:54:48 +0000 (14:54 +0100)
committerTim Düsterhus <duesterhus@woltlab.com>
Tue, 16 Mar 2021 13:54:48 +0000 (14:54 +0100)
wcfsetup/install/files/lib/system/session/SessionHandler.class.php

index db3fb09f4e27c885202b3a2b8e2deb7eaacbceb0..caa5929e42d2ca6dbc050df684c38c57fd2f5428 100644 (file)
@@ -134,6 +134,8 @@ final class SessionHandler extends SingletonFactory
 
     private const USER_SESSION_LIFETIME = 60 * 86400;
 
+    private const USER_SESSION_LIMIT = 30;
+
     private const CHANGE_USER_AFTER_MULTIFACTOR_KEY = self::class . "\0__changeUserAfterMultifactor__";
 
     private const PENDING_USER_LIFETIME = 15 * 60;
@@ -1032,6 +1034,28 @@ final class SessionHandler extends SingletonFactory
                 $this->sessionID,
             ]);
 
+            // ... delete any user sessions exceeding the limit ...
+            $sql = "SELECT  all_sessions.sessionID
+                    FROM    wcf" . WCF_N . "_user_session all_sessions
+                    LEFT JOIN (
+                        SELECT      sessionID
+                        FROM        wcf" . WCF_N . "_user_session
+                        WHERE       userID = ?
+                        ORDER BY    lastActivityTime DESC
+                        LIMIT       " . self::USER_SESSION_LIMIT . "
+                    ) newest_sessions
+                    ON      newest_sessions.sessionID = all_sessions.sessionID
+                    WHERE   all_sessions.userID = ?
+                        AND newest_sessions.sessionID IS NULL";
+            $statement = WCF::getDB()->prepareStatement($sql);
+            $statement->execute([
+                $user->userID,
+                $user->userID,
+            ]);
+            foreach ($statement->fetchAll(\PDO::FETCH_COLUMN) as $sessionID) {
+                $this->deleteUserSession($sessionID);
+            }
+
             // ... and reload the session with the updated information.
             $hasSession = $this->getExistingSession($this->sessionID);