From dde4683c3845f7ecba78786c032f625b228a4763 Mon Sep 17 00:00:00 2001 From: natreex Date: Wed, 19 Nov 2025 19:10:12 -0500 Subject: [PATCH] Migrate from `electron-store` to OS-level secure storage (`getSecureStorage`) - Replace `electron-store` with OS-level encrypted storage for secure token, userId, and language management in `LocalSystem` and `keyManager`. - Add `init-user` IPC handler to initialize user data and manage encryption keys. - Update login process to handle encrypted storage saving with fallback for macOS issues. - Add offline warning component to `login/page.tsx` to handle first-time sync requirements. - Remove `electron-store` and associated dependencies from `package.json` and `package-lock.json`. --- app/login/login/page.tsx | 83 ++++++++- app/page.tsx | 14 ++ electron.d.ts | 5 +- electron/database/LocalSystem.ts | 21 +-- electron/database/keyManager.ts | 32 ++-- electron/main.ts | 180 +++++++++++++++---- electron/preload.ts | 5 +- lib/locales/en.json | 6 +- lib/locales/fr.json | 6 +- package-lock.json | 294 ------------------------------- package.json | 2 - 11 files changed, 287 insertions(+), 361 deletions(-) diff --git a/app/login/login/page.tsx b/app/login/login/page.tsx index 823f41d..20d5faa 100755 --- a/app/login/login/page.tsx +++ b/app/login/login/page.tsx @@ -1,7 +1,7 @@ 'use client' -import {useContext} from 'react'; +import {useContext, useEffect, useState} from 'react'; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; -import {faEnvelope} from "@fortawesome/free-solid-svg-icons"; +import {faEnvelope, faWifi, faCloudArrowUp} from "@fortawesome/free-solid-svg-icons"; import LoginForm from "@/app/login/login/LoginForm"; import SocialForm from "@/app/login/login/SocialForm"; import {useTranslations} from "next-intl"; @@ -11,13 +11,67 @@ import System from "@/lib/models/System"; export default function LoginPage() { const t = useTranslations(); const {lang, setLang} = useContext(LangContext); - + const [showOfflineWarning, setShowOfflineWarning] = useState(false); + const [isOnline, setIsOnline] = useState(true); + const toggleLanguage = () => { const newLang = lang === 'fr' ? 'en' : 'fr'; setLang(newLang); System.setCookie('lang', newLang, 365); }; + useEffect(() => { + async function checkFirstConnectionAndNetwork() { + // Check if we're in Electron + if (!window.electron) { + return; + } + + try { + // Check if token exists (first connection) + const token = await window.electron.getToken(); + const hasToken = !!token; + + // Check network status + const online = navigator.onLine; + setIsOnline(online); + + // Show warning if first connection AND offline + if (!hasToken && !online) { + setShowOfflineWarning(true); + } + } catch (error) { + console.error('Error checking first connection:', error); + } + } + + checkFirstConnectionAndNetwork(); + + // Listen for online/offline events + const handleOnline = () => { + setIsOnline(true); + setShowOfflineWarning(false); + }; + const handleOffline = async () => { + setIsOnline(false); + // Check if token exists + if (window.electron) { + const token = await window.electron.getToken(); + if (!token) { + setShowOfflineWarning(true); + } + } + }; + + window.addEventListener('online', handleOnline); + window.addEventListener('offline', handleOffline); + + return () => { + window.removeEventListener('online', handleOnline); + window.removeEventListener('offline', handleOffline); + }; + }, []); + return (
@@ -32,6 +86,29 @@ export default function LoginPage() {
+ {/* Offline warning notification */} + {showOfflineWarning && ( +
+
+
+
+ +
+
+
+
+

+ + {t('loginPage.offlineWarning.title')} +

+

+ {t('loginPage.offlineWarning.message')} +

+
+
+
+ )} +