From 7ee4b81f972e7f43ed2455092df8e29bfc421f36 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Thu, 25 Sep 2025 08:10:19 +0800 Subject: [PATCH] FIX: Implement automatic logout on DEK session invalidation and database sync - Add 423 status code handling for DATA_LOCKED errors in frontend axios interceptor - Automatically clear JWT tokens and reload page when DEK becomes invalid - Prevent silent failures when server restarts invalidate DEK sessions - Add database save trigger after update operations for proper synchronization - Improve user experience by forcing re-authentication when data access is locked --- src/backend/utils/simple-db-ops.ts | 3 +++ src/ui/main-axios.ts | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/backend/utils/simple-db-ops.ts b/src/backend/utils/simple-db-ops.ts index fcc4b185..24fd6f82 100644 --- a/src/backend/utils/simple-db-ops.ts +++ b/src/backend/utils/simple-db-ops.ts @@ -144,6 +144,9 @@ class SimpleDBOps { .where(where) .returning(); + // Trigger database save after update + DatabaseSaveTrigger.triggerSave(`update_${tableName}`); + // Decrypt return data using the same key const decryptedResults = DataCrypto.decryptRecords( tableName, diff --git a/src/ui/main-axios.ts b/src/ui/main-axios.ts index 243ed8b7..f30fa91e 100644 --- a/src/ui/main-axios.ts +++ b/src/ui/main-axios.ts @@ -280,6 +280,27 @@ function createApiInstance( } } + // Handle DEK (Data Encryption Key) invalidation + if (status === 423) { + const errorData = error.response?.data; + if (errorData?.error === "DATA_LOCKED" || errorData?.message?.includes("DATA_LOCKED")) { + // DEK session has expired (likely due to server restart or timeout) + // Force logout to require re-authentication and DEK unlock + if (isElectron()) { + localStorage.removeItem("jwt"); + } else { + document.cookie = + "jwt=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; + localStorage.removeItem("jwt"); + } + + // Trigger a page reload to redirect to login + if (typeof window !== "undefined") { + setTimeout(() => window.location.reload(), 100); + } + } + } + return Promise.reject(error); }, );