From f9eec86672e0c2922034efbb8235609fdeebe6c8 Mon Sep 17 00:00:00 2001
From: timothycarambat <rambat1010@gmail.com>
Date: Thu, 5 Oct 2023 14:34:30 -0700
Subject: [PATCH] Fix login modal popping up on protected routes

---
 .../src/components/Modals/Password/index.jsx  | 21 ++++++++++++++++++-
 frontend/src/models/system.js                 | 14 +++++++++++--
 frontend/src/pages/Main/index.jsx             |  4 +++-
 frontend/src/pages/WorkspaceChat/index.jsx    |  4 +++-
 frontend/src/utils/constants.js               |  1 +
 server/endpoints/system.js                    |  2 +-
 6 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/frontend/src/components/Modals/Password/index.jsx b/frontend/src/components/Modals/Password/index.jsx
index 6be4b3f6a..11da0fc27 100644
--- a/frontend/src/components/Modals/Password/index.jsx
+++ b/frontend/src/components/Modals/Password/index.jsx
@@ -17,6 +17,7 @@ export default function PasswordModal({ mode = "single" }) {
 
 export function usePasswordModal() {
   const [auth, setAuth] = useState({
+    loading: true,
     required: false,
     mode: "single",
   });
@@ -24,14 +25,26 @@ export function usePasswordModal() {
   useEffect(() => {
     async function checkAuthReq() {
       if (!window) return;
-      const settings = await System.keys();
 
+      // If the last validity check is still valid
+      // we can skip the loading.
+      if (!System.needsAuthCheck()) {
+        setAuth({
+          loading: false,
+          requiresAuth: false,
+          mode: "multi",
+        });
+        return;
+      }
+
+      const settings = await System.keys();
       if (settings?.MultiUserMode) {
         const currentToken = window.localStorage.getItem(AUTH_TOKEN);
         if (!!currentToken) {
           const valid = await System.checkAuth(currentToken);
           if (!valid) {
             setAuth({
+              loading: false,
               requiresAuth: true,
               mode: "multi",
             });
@@ -40,6 +53,7 @@ export function usePasswordModal() {
             return;
           } else {
             setAuth({
+              loading: false,
               requiresAuth: false,
               mode: "multi",
             });
@@ -47,6 +61,7 @@ export function usePasswordModal() {
           }
         } else {
           setAuth({
+            loading: false,
             requiresAuth: true,
             mode: "multi",
           });
@@ -58,6 +73,7 @@ export function usePasswordModal() {
         const requiresAuth = settings?.RequiresAuth || false;
         if (!requiresAuth) {
           setAuth({
+            loading: false,
             requiresAuth: false,
             mode: "single",
           });
@@ -69,6 +85,7 @@ export function usePasswordModal() {
           const valid = await System.checkAuth(currentToken);
           if (!valid) {
             setAuth({
+              loading: false,
               requiresAuth: true,
               mode: "single",
             });
@@ -76,6 +93,7 @@ export function usePasswordModal() {
             return;
           } else {
             setAuth({
+              loading: false,
               requiresAuth: false,
               mode: "single",
             });
@@ -83,6 +101,7 @@ export function usePasswordModal() {
           }
         } else {
           setAuth({
+            loading: false,
             requiresAuth: true,
             mode: "single",
           });
diff --git a/frontend/src/models/system.js b/frontend/src/models/system.js
index 219690d18..6e74eb2a5 100644
--- a/frontend/src/models/system.js
+++ b/frontend/src/models/system.js
@@ -1,4 +1,4 @@
-import { API_BASE } from "../utils/constants";
+import { API_BASE, AUTH_TIMESTAMP } from "../utils/constants";
 import { baseHeaders } from "../utils/request";
 
 const System = {
@@ -39,12 +39,22 @@ const System = {
       .then((res) => res.localFiles)
       .catch(() => null);
   },
+  needsAuthCheck: function () {
+    const lastAuthCheck = window.localStorage.getItem(AUTH_TIMESTAMP);
+    if (!lastAuthCheck) return true;
+    const expiresAtMs = Number(lastAuthCheck) + 60 * 5 * 1000; // expires in 5 minutes in ms
+    return Number(new Date()) > expiresAtMs;
+  },
+
   checkAuth: async function (currentToken = null) {
-    return await fetch(`${API_BASE}/system/check-token`, {
+    const valid = await fetch(`${API_BASE}/system/check-token`, {
       headers: baseHeaders(currentToken),
     })
       .then((res) => res.ok)
       .catch(() => false);
+
+    window.localStorage.setItem(AUTH_TIMESTAMP, Number(new Date()));
+    return valid;
   },
   requestToken: async function (body) {
     return await fetch(`${API_BASE}/request-token`, {
diff --git a/frontend/src/pages/Main/index.jsx b/frontend/src/pages/Main/index.jsx
index bfef421f4..0a1e508f6 100644
--- a/frontend/src/pages/Main/index.jsx
+++ b/frontend/src/pages/Main/index.jsx
@@ -5,10 +5,12 @@ import PasswordModal, {
   usePasswordModal,
 } from "../../components/Modals/Password";
 import { isMobile } from "react-device-detect";
+import { FullScreenLoader } from "../../components/Preloader";
 
 export default function Main() {
-  const { requiresAuth, mode } = usePasswordModal();
+  const { loading, requiresAuth, mode } = usePasswordModal();
 
+  if (loading) return <FullScreenLoader />;
   if (requiresAuth !== false) {
     return <>{requiresAuth !== null && <PasswordModal mode={mode} />}</>;
   }
diff --git a/frontend/src/pages/WorkspaceChat/index.jsx b/frontend/src/pages/WorkspaceChat/index.jsx
index db065cd2a..5b466bda3 100644
--- a/frontend/src/pages/WorkspaceChat/index.jsx
+++ b/frontend/src/pages/WorkspaceChat/index.jsx
@@ -7,10 +7,12 @@ import PasswordModal, {
   usePasswordModal,
 } from "../../components/Modals/Password";
 import { isMobile } from "react-device-detect";
+import { FullScreenLoader } from "../../components/Preloader";
 
 export default function WorkspaceChat() {
-  const { requiresAuth, mode } = usePasswordModal();
+  const { loading, requiresAuth, mode } = usePasswordModal();
 
+  if (loading) return <FullScreenLoader />;
   if (requiresAuth !== false) {
     return <>{requiresAuth !== null && <PasswordModal mode={mode} />}</>;
   }
diff --git a/frontend/src/utils/constants.js b/frontend/src/utils/constants.js
index fe3a2308e..602460fd2 100644
--- a/frontend/src/utils/constants.js
+++ b/frontend/src/utils/constants.js
@@ -2,3 +2,4 @@ export const API_BASE = import.meta.env.VITE_API_BASE || "/api";
 
 export const AUTH_USER = "anythingllm_user";
 export const AUTH_TOKEN = "anythingllm_authToken";
+export const AUTH_TIMESTAMP = "anythingllm_authTimestamp";
diff --git a/server/endpoints/system.js b/server/endpoints/system.js
index 0dceddeab..eed85839a 100644
--- a/server/endpoints/system.js
+++ b/server/endpoints/system.js
@@ -316,7 +316,7 @@ function systemEndpoints(app) {
 
         updateENV(
           {
-            AuthToken: '',
+            AuthToken: "",
             JWTSecret: process.env.JWT_SECRET ?? v4(),
           },
           true
-- 
GitLab