Remove SyncService and introduce context-based offline mode and state management
- Delete `SyncService` and its associated bidirectional synchronization logic. - Add multiple context providers (`OfflineProvider`, `AlertProvider`, `LangContext`, `UserContext`, `SessionContext`, `WorldContext`, `SettingBookContext`) for contextual state management. - Implement `SecureStorage` for OS-level secure data encryption and replace dependency on `SyncService` synchronization. - Update localization files (`en.json`, `fr.json`) with offline mode and error-related strings.
This commit is contained in:
@@ -5,6 +5,8 @@ import { fileURLToPath } from 'url';
|
||||
import * as fs from 'fs';
|
||||
import { getDatabaseService } from './database/database.service.js';
|
||||
import { getSecureStorage } from './storage/SecureStorage.js';
|
||||
import { getUserEncryptionKey, setUserEncryptionKey, hasUserEncryptionKey } from './database/keyManager.js';
|
||||
import { generateUserEncryptionKey } from './database/encryption.js';
|
||||
|
||||
// Import IPC handlers
|
||||
import './ipc/book.ipc.js';
|
||||
@@ -120,7 +122,10 @@ function createMainWindow(): void {
|
||||
// IPC Handlers pour la gestion du token (OS-encrypted storage)
|
||||
ipcMain.handle('get-token', () => {
|
||||
const storage = getSecureStorage();
|
||||
return storage.get('authToken', null);
|
||||
const token = storage.get('authToken', null);
|
||||
console.log('[GetToken] Token requested, exists:', !!token);
|
||||
console.log('[GetToken] Storage has authToken:', storage.has('authToken'));
|
||||
return token;
|
||||
});
|
||||
|
||||
ipcMain.handle('set-token', (_event, token: string) => {
|
||||
@@ -156,12 +161,9 @@ ipcMain.handle('init-user', async (_event, userId: string) => {
|
||||
storage.set('lastUserId', userId); // Save for offline mode
|
||||
|
||||
try {
|
||||
const { getUserEncryptionKey, setUserEncryptionKey, hasUserEncryptionKey } = await import('./database/keyManager.js');
|
||||
|
||||
let encryptionKey: string | null = null;
|
||||
|
||||
if (!hasUserEncryptionKey(userId)) {
|
||||
const { generateUserEncryptionKey } = await import('./database/encryption.js');
|
||||
encryptionKey = generateUserEncryptionKey(userId);
|
||||
|
||||
console.log('[InitUser] Generated new encryption key for user');
|
||||
@@ -214,8 +216,10 @@ ipcMain.handle('init-user', async (_event, userId: string) => {
|
||||
});
|
||||
|
||||
ipcMain.on('login-success', async (_event, token: string) => {
|
||||
console.log('[Login] Received token, setting in storage');
|
||||
const storage = getSecureStorage();
|
||||
storage.set('authToken', token);
|
||||
console.log('[Login] Token set in cache, has authToken:', storage.has('authToken'));
|
||||
// Note: userId will be set later when we get user info from server
|
||||
|
||||
if (loginWindow) {
|
||||
@@ -298,7 +302,6 @@ interface SyncUserData {
|
||||
|
||||
ipcMain.handle('db:user:sync', async (_event, data: SyncUserData): Promise<boolean> => {
|
||||
try {
|
||||
// Import User models dynamically to avoid circular dependencies
|
||||
const { default: User } = await import('./database/models/User.js');
|
||||
const { default: UserRepo } = await import('./database/repositories/user.repository.js');
|
||||
|
||||
@@ -339,8 +342,6 @@ ipcMain.handle('db:user:sync', async (_event, data: SyncUserData): Promise<boole
|
||||
*/
|
||||
ipcMain.handle('generate-encryption-key', async (_event, userId: string) => {
|
||||
try {
|
||||
// Import encryption module dynamically
|
||||
const { generateUserEncryptionKey } = await import('./database/encryption.js');
|
||||
const key = generateUserEncryptionKey(userId);
|
||||
return { success: true, key };
|
||||
} catch (error) {
|
||||
@@ -453,43 +454,8 @@ app.whenReady().then(() => {
|
||||
console.log('[Startup] Has PIN:', hasPin);
|
||||
|
||||
if (token) {
|
||||
// Token existe, ouvrir la fenêtre principale
|
||||
createMainWindow();
|
||||
} else if (offlineMode && hasPin && lastUserId) {
|
||||
// Mode offline activé avec PIN, ouvrir login offline
|
||||
console.log('[Startup] Opening offline login page');
|
||||
loginWindow = new BrowserWindow({
|
||||
width: 500,
|
||||
height: 900,
|
||||
resizable: false,
|
||||
...(process.platform !== 'darwin' && { icon: iconPath }),
|
||||
webPreferences: {
|
||||
preload: preloadPath,
|
||||
contextIsolation: true,
|
||||
nodeIntegration: false,
|
||||
sandbox: true,
|
||||
},
|
||||
frame: true,
|
||||
show: false,
|
||||
});
|
||||
|
||||
if (isDev) {
|
||||
const devPort = process.env.PORT || '4000';
|
||||
loginWindow.loadURL(`http://localhost:${devPort}/login/offline`);
|
||||
loginWindow.webContents.openDevTools();
|
||||
} else {
|
||||
loginWindow.loadURL('app://./login/offline/index.html');
|
||||
}
|
||||
|
||||
loginWindow.once('ready-to-show', () => {
|
||||
loginWindow?.show();
|
||||
});
|
||||
|
||||
loginWindow.on('closed', () => {
|
||||
loginWindow = null;
|
||||
});
|
||||
} else {
|
||||
// Pas de token ou pas de mode offline, ouvrir la fenêtre de login normale
|
||||
createLoginWindow();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user