import { ipcMain } from 'electron'; import { createHandler } from '../database/LocalSystem.js'; import * as bcrypt from 'bcrypt'; import { getSecureStorage } from '../storage/SecureStorage.js'; import { getDatabaseService } from '../database/database.service.js'; interface SetPinData { pin: string; } interface VerifyPinData { pin: string; } interface OfflineModeData { enabled: boolean; syncInterval?: number; // days } ipcMain.handle('offline:pin:set', async (_event, data: SetPinData) => { try { const storage = getSecureStorage(); const userId = storage.get('userId'); if (!userId) { return { success: false, error: 'No user logged in' }; } // Hash the PIN const hashedPin = await bcrypt.hash(data.pin, 10); // Store hashed PIN storage.set(`pin-${userId}`, hashedPin); storage.save(); console.log('[Offline] PIN set for user'); return { success: true }; } catch (error) { console.error('[Offline] Error setting PIN:', error); return { success: false, error: error instanceof Error ? error.message : 'Unknown error' }; } }); // Verify PIN for offline access ipcMain.handle('offline:pin:verify', async (_event, data: VerifyPinData) => { try { const storage = getSecureStorage(); // Try to get last known userId const lastUserId = storage.get('lastUserId'); if (!lastUserId) { return { success: false, error: 'No offline account found' }; } const hashedPin = storage.get(`pin-${lastUserId}`); if (!hashedPin) { return { success: false, error: 'No PIN configured' }; } // Verify PIN const isValid = await bcrypt.compare(data.pin, hashedPin); if (isValid) { // Set userId for session storage.set('userId', lastUserId); // Initialize database for offline use const encryptionKey = storage.get(`encryptionKey-${lastUserId}`); if (encryptionKey) { const db = getDatabaseService(); db.initialize(lastUserId, encryptionKey); } else { console.error('[Offline] No encryption key found for user'); return { success: false, error: 'No encryption key found' }; } console.log('[Offline] PIN verified, user authenticated locally'); return { success: true, userId: lastUserId }; } return { success: false, error: 'Invalid PIN' }; } catch (error) { console.error('[Offline] Error verifying PIN:', error); return { success: false, error: error instanceof Error ? error.message : 'Unknown error' }; } }); // Set offline mode preference ipcMain.handle('offline:mode:set', (_event, data: OfflineModeData) => { try { const storage = getSecureStorage(); storage.set('offlineMode', data.enabled); if (data.syncInterval) { storage.set('syncInterval', data.syncInterval); } storage.save(); console.log('[Offline] Mode set to:', data.enabled); return { success: true }; } catch (error) { console.error('[Offline] Error setting mode:', error); return { success: false, error: error instanceof Error ? error.message : 'Unknown error' }; } }); // Get offline mode status ipcMain.handle('offline:mode:get', () => { try { const storage = getSecureStorage(); const offlineMode = storage.get('offlineMode', false); const syncInterval = storage.get('syncInterval', 30); const lastUserId = storage.get('lastUserId'); const hasPin = lastUserId ? !!storage.get(`pin-${lastUserId}`) : false; return { enabled: offlineMode, syncInterval, hasPin, lastUserId }; } catch (error) { console.error('[Offline] Error getting mode:', error); return { enabled: false, syncInterval: 30, hasPin: false }; } }); // Check if should sync ipcMain.handle('offline:sync:check', () => { try { const storage = getSecureStorage(); const lastSync = storage.get('lastSync'); const syncInterval = storage.get('syncInterval', 30) || 30; if (!lastSync) { return { shouldSync: true }; } const daysSinceSync = Math.floor( (Date.now() - new Date(lastSync).getTime()) / (1000 * 60 * 60 * 24) ); return { shouldSync: daysSinceSync >= syncInterval, daysSinceSync, syncInterval }; } catch (error) { console.error('[Offline] Error checking sync:', error); return { shouldSync: false }; } }); console.log('[IPC] Offline handlers registered');