diff --git a/build/Dockerfile b/build/Dockerfile index d3a48ff8..2d235b66 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -6,7 +6,8 @@ RUN apk add --update --no-cache \ docker \ git \ libpcap-dev \ - linux-headers + linux-headers \ + bash RUN git clone https://github.com/xelerance/xl2tpd.git && cd xl2tpd && make diff --git a/build/src/src/calls/setStaticIp.js b/build/src/src/calls/setStaticIp.js index 64f5c0d0..12a9ae30 100644 --- a/build/src/src/calls/setStaticIp.js +++ b/build/src/src/calls/setStaticIp.js @@ -15,12 +15,8 @@ async function setStaticIp({staticIp}) { if (!oldStaticIp && staticIp) { message = `Enabled static IP: ${staticIp}`; } else if (oldStaticIp && !staticIp) { - message = `Disabled static IP`; - // If the staticIp is being disabled but there is no keys: register to dyndns - if (!await db.get('registeredToDyndns')) { - await dyndnsClient.updateIp(); - message += `, and registered to dyndns: ${await db.get('domain')}`; - } + await dyndnsClient.updateIp(); + message = `Disabled static IP, and registered to dyndns: ${await db.get('domain')}`; } else { message = `Updated static IP: ${staticIp}`; } diff --git a/build/src/src/client.js b/build/src/src/client.js index c38f0efe..4b5e89f7 100644 --- a/build/src/src/client.js +++ b/build/src/src/client.js @@ -67,6 +67,8 @@ async function start() { // init.sh // 1. Create VPN's address + publicKey + privateKey if it doesn't exist yet + // Also, verify if the privateKey is corrupted or lost. + // In that case generate a new identity and alert the user await dyndnsClient.generateKeys(); // fetchVpnParameters read the output files from the .sh scripts @@ -100,9 +102,6 @@ async function start() { // Print db censoring privateKey const _db = await db.get(); - if (_db && _db.privateKey) { - _db.privateKey = _db.privateKey.replace(/./g, '*'); - } logs.info(JSON.stringify(_db, null, 2 )); // /////////////////////// diff --git a/build/src/src/db.js b/build/src/src/db.js index e36b8c6e..2225bc59 100644 --- a/build/src/src/db.js +++ b/build/src/src/db.js @@ -25,7 +25,7 @@ const get = async (key) => { if (key) { return db.get(key).value(); } else { - return db.getState(); + return Object.assign({}, db.getState()); } }; diff --git a/build/src/src/dyndnsClient/generateKeys.js b/build/src/src/dyndnsClient/generateKeys.js index a30bc2d4..484015f8 100644 --- a/build/src/src/dyndnsClient/generateKeys.js +++ b/build/src/src/dyndnsClient/generateKeys.js @@ -2,6 +2,18 @@ const EthCrypto = require('eth-crypto'); const db = require('../db'); const logs = require('../logs.js')(module); +const corruptedPrivateKeyMessage = +` + + +===================================================================== + Found corrupted privateKey. + Reseting DYNDNS subdomain, please update your user's profiles +===================================================================== + + +`; + /** * EthCrypto reference * @@ -33,11 +45,27 @@ function getDyndnsHost() { : DYNDNS_DOMAIN; } +function isPrivateKeyValid(privateKey) { + try { + EthCrypto.publicKeyByPrivateKey(privateKey); + return true; + } catch (e) { + /* eslint-disable max-len */ + logs.warn('Private key verification failed. EthCrypto.publicKeyByPrivateKey returned error: '+e.stack); + return false; + } +} + async function generateKeys() { - if (await db.get('privateKey')) { - logs.info(`Skipping keys generation, found identity in db`); - return; + const currentPrivateKey = await db.get('privateKey'); + if (currentPrivateKey) { + if (isPrivateKeyValid(currentPrivateKey)) { + logs.info(`Skipping keys generation, found identity in db`); + return; + } else { + logs.warn(corruptedPrivateKeyMessage); + } } const {address, privateKey, publicKey} = EthCrypto.createIdentity(); await db.set('address', address); diff --git a/build/src/src/dyndnsClient/updateIp.js b/build/src/src/dyndnsClient/updateIp.js index b4a09edc..f4ec4898 100644 --- a/build/src/src/dyndnsClient/updateIp.js +++ b/build/src/src/dyndnsClient/updateIp.js @@ -70,7 +70,6 @@ async function updateIp() { if (res.code === 200) { logs.info(`dyndns client success: ${data.message}`); await db.set('domain', data.domain); - await db.set('registeredToDyndns', true); return data.domain; } else { const errorMsg = data.message || JSON.stringify(data); diff --git a/build/src/test/dyndnsClient/generateKeys.test.js b/build/src/test/dyndnsClient/generateKeys.test.js index fd1a1ebe..85455053 100644 --- a/build/src/test/dyndnsClient/generateKeys.test.js +++ b/build/src/test/dyndnsClient/generateKeys.test.js @@ -5,6 +5,7 @@ const logs = require('../../src/logs.js')(module); const unlink = util.promisify(fs.unlink); const {exec} = require('child_process'); let db = require('../../src/db'); +const EthCrypto = require('eth-crypto'); process.env.DYNDNS_DOMAIN = 'dyn.test.io'; const dbPath = './vpndb'; @@ -70,4 +71,30 @@ describe('generateKeys', function() { }); }); }); + + describe('recover a corrupted privateKey', () => { + it('should detect that a privateKey is corrupted', async () => { + /* eslint-disable max-len */ + // Store old private key and domain to assert the change + const oldPrivateKey = await db.get('privateKey'); + const oldDomain = await db.get('domain'); + + // corrupt the private key + const corruptedPrivateKey = '******************************************************************'; + await db.set('privateKey', corruptedPrivateKey); + + // Call generateKeys. This function will be called always when the VPN resets + await generateKeys(); + + // Assert that a new valid private key is created. + // Also that the domain changed + const newPrivateKey = await db.get('privateKey'); + const newDomain = await db.get('domain'); + expect(newPrivateKey).to.not.equal(oldPrivateKey); + expect(newPrivateKey).to.not.equal(corruptedPrivateKey); + const publicKey = EthCrypto.publicKeyByPrivateKey(newPrivateKey); + expect(publicKey).to.exist; + expect(newDomain).to.not.equal(oldDomain); + }); + }); }); diff --git a/dappnode_package.json b/dappnode_package.json index fc4db213..c55982d9 100644 --- a/dappnode_package.json +++ b/dappnode_package.json @@ -1,6 +1,6 @@ { "name": "vpn.dnp.dappnode.eth", - "version": "0.1.18", + "version": "0.1.19", "description": "Dappnode package responsible for providing the VPN (L2TP/IPSec) connection", "avatar": "/ipfs/QmWwMb3XhuCH6JnCF6m6EQzA4mW9pHHtg7rqAfhDr2ofi8", "type": "dncore", diff --git a/docker-compose-vpn.yml b/docker-compose-vpn.yml index 18355c29..79eca472 100644 --- a/docker-compose-vpn.yml +++ b/docker-compose-vpn.yml @@ -11,7 +11,7 @@ volumes: services: vpn.dnp.dappnode.eth: build: ./build - image: 'vpn.dnp.dappnode.eth:0.1.18' + image: 'vpn.dnp.dappnode.eth:0.1.19' container_name: DAppNodeCore-vpn.dnp.dappnode.eth privileged: true restart: always