Browse Source

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 <[email protected]>
pull/238/head
Joshua K 5 years ago
committed by joshuakraitberg
parent
commit
63184c73ca
  1. 15
      src/lib/Util.js
  2. 45
      src/lib/WireGuard.js
  3. 10
      src/www/index.html

15
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') {

45
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,

10
src/www/index.html

@ -128,6 +128,16 @@
<!-- Info -->
<div class="text-gray-400 text-xs">
<!-- Show QR-->
<button class="align-middle bg-gray-100 hover:bg-red-800 hover:text-white p-2 rounded transition"
title="Show QR Code" @click="qrcode = `/api/wireguard/client/${client.id}/qrcode.svg?${Date.now()}`;">
<svg class="w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 4v1m6 11h2m-6 0h-2v4m0-11v3m0 0h.01M12 12h4.01M16 20h4M4 12h4m12 0h.01M5 8h2a1 1 0 001-1V5a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1zm12 0h2a1 1 0 001-1V5a1 1 0 00-1-1h-2a1 1 0 00-1 1v2a1 1 0 001 1zM5 20h2a1 1 0 001-1v-2a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1z" />
</svg>
</button>
<!-- Address -->
<span class="group">

Loading…
Cancel
Save