import { app, BrowserWindow, ipcMain } from 'electron'; import path from 'path'; import { fileURLToPath } from 'url'; import crypto from 'node:crypto'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); function createWindow() { const win = new BrowserWindow({ width: 1200, height: 800, webPreferences: { preload: path.join(__dirname, 'preload.cjs'), contextIsolation: true, sandbox: true, nodeIntegration: false, }, }); if (process.env.NODE_ENV === 'development' || process.argv.includes('--dev')) { win.loadURL('http://localhost:5173'); win.webContents.openDevTools(); } else { win.loadFile(path.join(__dirname, 'dist', 'index.html')); } } app.whenReady().then(() => { // Crypto IPC Handlers ipcMain.handle('crypto:deriveAuthKeys', async (_, password, salt) => { return new Promise((resolve, reject) => { crypto.pbkdf2(password, salt, 100000, 32, 'sha512', (err, derived) => { if (err) reject(err); resolve({ dek: derived.slice(0, 16).toString('hex'), dak: derived.slice(16, 32).toString('hex') }); }); }); }); ipcMain.handle('crypto:encryptData', (_, plaintext, keyHex, ivHex) => { const key = Buffer.from(keyHex, 'hex'); const iv = ivHex ? Buffer.from(ivHex, 'hex') : crypto.randomBytes(12); const cipher = crypto.createCipheriv('aes-128-gcm', key, iv); let encrypted = cipher.update(plaintext, 'utf8', 'hex'); encrypted += cipher.final('hex'); return { content: encrypted, tag: cipher.getAuthTag().toString('hex'), iv: iv.toString('hex') }; }); ipcMain.handle('crypto:decryptData', (_, ciphertext, keyHex, ivHex, tagHex) => { const key = Buffer.from(keyHex, 'hex'); const iv = Buffer.from(ivHex, 'hex'); const tag = Buffer.from(tagHex, 'hex'); const decipher = crypto.createDecipheriv('aes-128-gcm', key, iv); decipher.setAuthTag(tag); let decrypted = decipher.update(ciphertext, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; }); ipcMain.handle('crypto:generateKeys', async () => { const { publicKey: rsaPub, privateKey: rsaPriv } = crypto.generateKeyPairSync('rsa', { modulusLength: 2048, publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }); const { publicKey: edPub, privateKey: edPriv } = crypto.generateKeyPairSync('ed25519', { publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }); return { rsaPub, rsaPriv, edPub, edPriv }; }); ipcMain.handle('crypto:randomBytes', (_, size) => { return crypto.randomBytes(size).toString('hex'); }); ipcMain.handle('crypto:sha256', (_, data) => { return crypto.createHash('sha256').update(data).digest('hex'); }); createWindow(); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } });