import { app, BrowserWindow, ipcMain, dialog } from 'electron'; import * as path from 'path'; import * as fs from 'fs'; import { exec } from 'child_process'; import { promisify } from 'util'; const execAsync = promisify(exec); const CONFIG_DIR = path.join(app.getPath('home'), '.config', 'wireguard-gui'); const CONFIG_FILE = path.join(CONFIG_DIR, 'current.conf'); const WG_INTERFACE = 'wg0'; const WG_CONF_PATH = `/etc/wireguard/${WG_INTERFACE}.conf`; let mainWindow: BrowserWindow | null = null; function createWindow() { mainWindow = new BrowserWindow({ width: 350, height: 650, resizable: false, autoHideMenuBar: true, webPreferences: { preload: path.join(__dirname, 'preload.js'), nodeIntegration: false, contextIsolation: true, devTools: process.env.NODE_ENV === 'development', }, }); // Remove menu bar completely mainWindow.setMenuBarVisibility(false); if (process.env.NODE_ENV === 'development') { mainWindow.loadURL('http://localhost:5173'); } else { mainWindow.loadFile(path.join(__dirname, '../dist/index.html')); } } // Ensure config directory exists function ensureConfigDir() { if (!fs.existsSync(CONFIG_DIR)) { fs.mkdirSync(CONFIG_DIR, { recursive: true }); } } // IPC Handlers ipcMain.handle('select-config-file', async () => { const result = await dialog.showOpenDialog(mainWindow!, { properties: ['openFile'], filters: [{ name: 'WireGuard Config', extensions: ['conf'] }], }); if (result.canceled || result.filePaths.length === 0) { return { success: false, error: 'No file selected' }; } return { success: true, filePath: result.filePaths[0] }; }); ipcMain.handle('load-config', async (_event, filePath: string) => { try { ensureConfigDir(); // Copy config to our storage fs.copyFileSync(filePath, CONFIG_FILE); // Create symlink with sudo (non-interactive) const symlinkCmd = `sudo -n ln -sf ${CONFIG_FILE} ${WG_CONF_PATH}`; await execAsync(symlinkCmd); return { success: true, configName: path.basename(filePath), message: 'Config loaded successfully', }; } catch (error: any) { return { success: false, error: error.message || 'Failed to load config', }; } }); ipcMain.handle('connect-wireguard', async () => { try { const cmd = `sudo -n wg-quick up ${WG_INTERFACE}`; const { stdout, stderr } = await execAsync(cmd); return { success: true, message: 'Connected successfully', output: stdout || stderr, }; } catch (error: any) { return { success: false, error: error.message || 'Failed to connect', }; } }); ipcMain.handle('disconnect-wireguard', async () => { try { const cmd = `sudo -n wg-quick down ${WG_INTERFACE}`; const { stdout, stderr } = await execAsync(cmd); return { success: true, message: 'Disconnected successfully', output: stdout || stderr, }; } catch (error: any) { return { success: false, error: error.message || 'Failed to disconnect', }; } }); ipcMain.handle('get-connection-status', async () => { try { // Check if interface exists without requiring root await execAsync(`ip link show ${WG_INTERFACE}`); return { success: true, connected: true, details: `${WG_INTERFACE} is up`, }; } catch { // ip link returns error if interface doesn't exist return { success: true, connected: false, details: '', }; } }); ipcMain.handle('get-current-config', async () => { try { if (fs.existsSync(CONFIG_FILE)) { const configName = 'current.conf'; return { success: true, hasConfig: true, configName, }; } return { success: true, hasConfig: false, }; } catch (error: any) { return { success: false, error: error.message, }; } }); app.whenReady().then(createWindow); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } });