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`.
This commit is contained in:
natreex
2025-11-19 19:10:12 -05:00
parent 71d13e2b12
commit dde4683c38
11 changed files with 287 additions and 361 deletions

View File

@@ -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 (
<main className="flex min-h-screen flex-col items-center justify-center bg-background text-textPrimary p-4">
<div className="w-full max-w-md px-4 py-10">
@@ -32,6 +86,29 @@ export default function LoginPage() {
</div>
</div>
{/* Offline warning notification */}
{showOfflineWarning && (
<div className="mb-6 bg-gradient-to-r from-orange-500/20 to-amber-500/20 border border-orange-500/40 rounded-xl p-4 shadow-lg shadow-orange-500/10">
<div className="flex items-start gap-3">
<div className="flex-shrink-0 mt-0.5">
<div className="relative">
<FontAwesomeIcon icon={faWifi} className="w-5 h-5 text-orange-400" />
<div className="absolute inset-0 w-6 h-0.5 bg-orange-400 rotate-45 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2"></div>
</div>
</div>
<div className="flex-1">
<h3 className="font-semibold text-orange-200 mb-1 flex items-center gap-2">
<FontAwesomeIcon icon={faCloudArrowUp} className="w-4 h-4" />
{t('loginPage.offlineWarning.title')}
</h3>
<p className="text-sm text-orange-300/90 leading-relaxed">
{t('loginPage.offlineWarning.message')}
</p>
</div>
</div>
</div>
)}
<div
className="bg-tertiary rounded-2xl overflow-hidden shadow-xl shadow-primary/10 w-full relative">
<button