From f9eec86672e0c2922034efbb8235609fdeebe6c8 Mon Sep 17 00:00:00 2001 From: timothycarambat 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 6be4b3f6..11da0fc2 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 219690d1..6e74eb2a 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 bfef421f..0a1e508f 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 ; if (requiresAuth !== false) { return <>{requiresAuth !== null && }; } diff --git a/frontend/src/pages/WorkspaceChat/index.jsx b/frontend/src/pages/WorkspaceChat/index.jsx index db065cd2..5b466bda 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 ; if (requiresAuth !== false) { return <>{requiresAuth !== null && }; } diff --git a/frontend/src/utils/constants.js b/frontend/src/utils/constants.js index fe3a2308..602460fd 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 0dceddea..eed85839 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