From 4bbcc5276bfdf9002733b4bd06ae614e03f76658 Mon Sep 17 00:00:00 2001 From: CallMeTechie <34693633+CallMeTechie@users.noreply.github.com> Date: Sun, 31 May 2026 09:59:42 +0200 Subject: [PATCH 1/2] feat(wg-config): validate imported config via shared validateWgConfig (fail-closed) --- src/main/main.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/main.js b/src/main/main.js index 3063a95..d98b104 100644 --- a/src/main/main.js +++ b/src/main/main.js @@ -19,6 +19,7 @@ const { createLogger, createStores, registerBaseHandlers, + validateWgConfig, } = require('@gatecontrol/client-core'); const { i18n } = require('@gatecontrol/client-core'); @@ -720,10 +721,14 @@ app.whenReady().then(async () => { try { const newConfig = await apiClient.checkConfigUpdate(); if (newConfig) { - // Validate before applying — reject empty or malformed configs - if (!newConfig.includes('[Interface]') || !newConfig.includes('PrivateKey')) { - log.warn('Config update rejected: missing [Interface] or PrivateKey'); + // Validate before applying — fail-closed via shared validator. + const validation = validateWgConfig(newConfig); + if (!validation.ok) { + log.warn('Config update rejected: ' + validation.errors.join(', ')); } else { + if (validation.warnings && validation.warnings.length > 0) { + log.warn('Config update warnings: ' + validation.warnings.join(', ')); + } log.info('Neue Konfiguration vom Server erhalten'); await wgService.writeConfig(WG_CONFIG_FILE, newConfig); if (tunnelState.connected) { From d58bc51303a05863d2a979a60beb20f9a58447ca Mon Sep 17 00:00:00 2001 From: CallMeTechie <34693633+CallMeTechie@users.noreply.github.com> Date: Sun, 31 May 2026 10:06:33 +0200 Subject: [PATCH 2/2] fix(wg-config): validate fetched config before overwriting on connect --- src/main/main.js | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/main.js b/src/main/main.js index d98b104..1353857 100644 --- a/src/main/main.js +++ b/src/main/main.js @@ -307,15 +307,30 @@ async function connectTunnel() { const apiKey = store.get('server.apiKey'); if (serverUrl && apiKey) { + let fetchedConfig = null; try { - const config = await apiClient.fetchConfig(); - if (config) { - await wgService.writeConfig(WG_CONFIG_FILE, config); - log.info('Konfiguration vom Server aktualisiert'); - } + fetchedConfig = await apiClient.fetchConfig(); } catch (err) { log.warn('Config-Abruf fehlgeschlagen, nutze lokale Config:', err.message); } + if (fetchedConfig) { + // Fail-closed: validate before overwriting the existing config. + // A bad fetch must NOT clobber a good local config; abort the connect. + const validation = validateWgConfig(fetchedConfig); + if (!validation.ok) { + const msg = 'Invalid WireGuard config: ' + validation.errors.join(', '); + log.error('Config-Update abgelehnt, behalte lokale Config: ' + msg); + updateTray('disconnected'); + broadcastState('error', msg); + showNotification(t('notify.connectionError'), msg); + return; + } + if (validation.warnings && validation.warnings.length > 0) { + log.warn('Config-Warnungen: ' + validation.warnings.join(', ')); + } + await wgService.writeConfig(WG_CONFIG_FILE, fetchedConfig); + log.info('Konfiguration vom Server aktualisiert'); + } } if (store.get('tunnel.killSwitch', false)) {