From 63184c73ca4a28f26a4ee059fb99003ae607b1e0 Mon Sep 17 00:00:00 2001 From: Joshua K <22075247+joshuakraitberg@users.noreply.github.com> Date: Sun, 31 Oct 2021 16:33:35 +0000 Subject: [PATCH] Greatly improved overall security (#4) * Server no longer saves private keys To accomplish this, PrivateKey, PublicKey and PreSharedKey are regenerated every time the user requests access to the client configuration. So far this would be when QR code is displayed or config is requested for download. * Removed sesnitive info (private keys) from being logged Co-authored-by: joshuakraitberg --- src/lib/Util.js | 15 +++++++-------- src/lib/WireGuard.js | 45 +++++++++++++++++++++++++++++--------------- src/www/index.html | 10 ++++++++++ 3 files changed, 47 insertions(+), 23 deletions(-) diff --git a/src/lib/Util.js b/src/lib/Util.js index 2a47a20e..ee40c5a3 100644 --- a/src/lib/Util.js +++ b/src/lib/Util.js @@ -52,15 +52,14 @@ module.exports = class Util { }; } - static async exec(cmd, { - log = true, - } = {}) { - if (typeof log === 'string') { - // eslint-disable-next-line no-console - console.log(`$ ${log}`); - } else if (log === true) { - // eslint-disable-next-line no-console + static async exec(cmd, hide=null) { + // eslint-disable-next-line no-console + + if (hide == null) { console.log(`$ ${cmd}`); + } else { + // Don't log sensitive information + console.log(`$ ${cmd.replace(hide, "*HIDDEN*")}`); } if (process.platform !== 'linux') { diff --git a/src/lib/WireGuard.js b/src/lib/WireGuard.js index 0cfce218..4c96450d 100644 --- a/src/lib/WireGuard.js +++ b/src/lib/WireGuard.js @@ -40,9 +40,7 @@ module.exports = class WireGuard { debug('Configuration loaded.'); } catch (err) { const privateKey = await Util.exec('wg genkey'); - const publicKey = await Util.exec(`echo ${privateKey} | wg pubkey`, { - log: 'echo ***hidden*** | wg pubkey', - }); + const publicKey = await Util.exec(`echo ${privateKey} | wg pubkey`, privateKey); const address = WG_DEFAULT_ADDRESS.replace('x', '1'); config = { @@ -57,14 +55,7 @@ module.exports = class WireGuard { } await this.__saveConfig(config); - await Util.exec('wg-quick down wg0').catch(() => { }); - await Util.exec('wg-quick up wg0').catch(err => { - if (err && err.message && err.message.includes('Cannot find device "wg0"')) { - throw new Error('WireGuard exited with the error: Cannot find device "wg0"\nThis usually means that your host\'s kernel does not support WireGuard!'); - } - - throw err; - }); + await this.restartGateway(); await this.__syncConfig(); return config; @@ -74,6 +65,18 @@ module.exports = class WireGuard { return this.__configPromise; } + async restartGateway() { + this.gatewayUp = false; + await Util.exec('wg-quick down wg0').catch(() => { }); + await Util.exec('wg-quick up wg0').catch(err => { + if (err && err.message && err.message.includes('Cannot find device "wg0"')) { + throw new Error('WireGuard exited with the error: Cannot find device "wg0"\nThis usually means that your host\'s kernel does not support WireGuard!'); + } + throw err; + }); + this.gatewayUp = true; + } + async saveConfig() { const config = await this.getConfig(); await this.__saveConfig(config); @@ -144,6 +147,10 @@ AllowedIPs = ${client.address}/32`; transferTx: null, })); + if (!this.gatewayUp) { + return clients; + } + // Loop WireGuard status const dump = await Util.exec('wg show wg0 dump', { log: false, @@ -189,12 +196,21 @@ AllowedIPs = ${client.address}/32`; } async getClientConfiguration({ clientId }) { + // Keys of client are regenerated on each call! + // Gateway must be restarted to update to new keys + const config = await this.getConfig(); const client = await this.getClient({ clientId }); + const privateKey = await Util.exec('wg genkey'); + client.publicKey = await Util.exec(`echo ${privateKey} | wg pubkey`, privateKey); + client.preSharedKey = await Util.exec('wg genpsk'); + + await this.saveConfig(); + await this.restartGateway(); return ` [Interface] -PrivateKey = ${client.privateKey} +PrivateKey = ${privateKey} Address = ${client.address}/24 ${WG_DEFAULT_DNS ? `DNS = ${WG_DEFAULT_DNS}` : ''} ${WG_MTU ? `MTU = ${WG_MTU}` : ''} @@ -225,8 +241,8 @@ Endpoint = ${WG_HOST}:${WG_PORT}`; const config = await this.getConfig(); - const privateKey = await Util.exec('wg genkey'); - const publicKey = await Util.exec(`echo ${privateKey} | wg pubkey`); + // Public key is placeholder, new one is generated on getClientConfig + const publicKey = await Util.exec('wg genpsk'); const preSharedKey = await Util.exec('wg genpsk'); // Calculate next IP @@ -251,7 +267,6 @@ Endpoint = ${WG_HOST}:${WG_PORT}`; const client = { name, address, - privateKey, publicKey, preSharedKey, allowedIPs: allowedIPs, diff --git a/src/www/index.html b/src/www/index.html index d872549c..52684214 100644 --- a/src/www/index.html +++ b/src/www/index.html @@ -128,6 +128,16 @@
+ + +