diff --git a/build/Dockerfile b/build/Dockerfile index fdba8517..577a3059 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -85,7 +85,7 @@ RUN chmod 755 check_upnp.sh RUN mkdir -p /usr/src/app/secrets # envs for init.sh -> node communication ENV DB_PATH /usr/src/app/secrets/db.json -ENV INSTALLATION_STATIC_IP /usr/src/dappnode/ip.value +ENV INSTALLATION_STATIC_IP /usr/src/app/config/static_ip ENV KEYPAIR_PATH /usr/src/app/secrets/keypair ENV CREDENTIALS_PATH /usr/src/app/secrets/chap-secrets ENV PUBLIC_IP_PATH /usr/src/app/secrets/server-ip diff --git a/build/src/package-lock.json b/build/src/package-lock.json index bdab63a1..899cbe49 100644 --- a/build/src/package-lock.json +++ b/build/src/package-lock.json @@ -2430,6 +2430,16 @@ "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==" }, + "fill-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", + "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", + "dev": true, + "requires": { + "is-object": "~1.0.1", + "merge-descriptors": "~1.0.0" + } + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -3647,6 +3657,12 @@ } } }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, "is-path-cwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", @@ -4260,6 +4276,12 @@ "supports-color": "5.4.0" } }, + "module-not-found-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", + "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", + "dev": true + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -6747,6 +6769,12 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, "path-to-regexp": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", @@ -6887,6 +6915,17 @@ "ipaddr.js": "1.8.0" } }, + "proxyquire": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.0.tgz", + "integrity": "sha512-kptdFArCfGRtQFv3Qwjr10lwbEV0TBJYvfqzhwucyfEXqVgmnAkyEw/S3FYzR5HI9i5QOq4rcqQjZ6AlknlCDQ==", + "dev": true, + "requires": { + "fill-keys": "^1.0.2", + "module-not-found-error": "^1.0.0", + "resolve": "~1.8.1" + } + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -7153,6 +7192,15 @@ "resolve-from": "^1.0.0" } }, + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "dev": true, + "requires": { + "path-parse": "^1.0.5" + } + }, "resolve-cwd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", diff --git a/build/src/package.json b/build/src/package.json index d9677f4a..26c56496 100644 --- a/build/src/package.json +++ b/build/src/package.json @@ -33,6 +33,7 @@ "eslint-config-google": "^0.9.1", "mocha": "^5.2.0", "nyc": "^12.0.2", + "proxyquire": "^2.1.0", "sinon": "^5.1.0", "sinon-chai": "^3.1.0" } diff --git a/build/src/src/client.js b/build/src/src/client.js index e7df389a..3d3535f8 100644 --- a/build/src/src/client.js +++ b/build/src/src/client.js @@ -6,7 +6,6 @@ const dyndnsClient = require('./dyndnsClient'); const calls = require('./calls'); const logAdminCredentials = require('./logAdminCredentials'); const fetchVpnParameters = require('./fetchVpnParameters'); -const getInstallationStaticIp = require('./utils/getInstallationStaticIp'); const URL = 'ws://my.wamp.dnp.dappnode.eth:8080/ws'; const REALM = 'dappnode_admin'; @@ -55,16 +54,8 @@ async function start() { logs.info('Loading VPN parameters... It may take a while'); await fetchVpnParameters(); - // Load the static IP defined in the installation - if (!db.get('staticIp').value()) { - const installationStaticIp = await getInstallationStaticIp(); - if (installationStaticIp) { - logs.info(`Static IP was set during installation: ${installationStaticIp}`); - db.set('staticIp', installationStaticIp).value(); - } - } - // If the user has not defined a static IP use dynamic DNS + // > staticIp is set in `await fetchVpnParameters();` if (!db.get('staticIp').value()) { logs.info('Registering to the dynamic DNS...'); await dyndnsClient.updateIp(); @@ -87,7 +78,12 @@ async function start() { } }, publicIpCheckInterval); - logs.info('VPN credentials fetched'); + logs.info('VPN credentials fetched: '); + // Print db censoring privateKey + const dbClone = JSON.parse(JSON.stringify(db.getState())); + dbClone.keypair.privateKey = dbClone.keypair.privateKey.replace(/./g, '*'); + logs.info(JSON.stringify(dbClone, null, 2 )); + logAdminCredentials(); } diff --git a/build/src/src/dyndnsClient/getKeys.js b/build/src/src/dyndnsClient/getKeys.js index 6792f83c..c723d551 100644 --- a/build/src/src/dyndnsClient/getKeys.js +++ b/build/src/src/dyndnsClient/getKeys.js @@ -1,7 +1,5 @@ const EthCrypto = require('eth-crypto'); -const fs = require('file-system'); -const util = require('util'); -const logs = require('../logs.js')(module); +const db = require('../db'); /** * EthCrypto reference @@ -27,12 +25,10 @@ const logs = require('../logs.js')(module); // dyndnsHost has to be stripped of http(s):// tag // process.env.DYNDNS_HOST should include said tag -const {DEV, DYNDNS_HOST} = process.env; -const dyndnsHost = DEV - ? 'dyn.test.io' - : (DYNDNS_HOST && DYNDNS_HOST.includes('://')) - ? DYNDNS_HOST.split('://')[1] - : DYNDNS_HOST; +const {DYNDNS_HOST} = process.env; +const dyndnsHost = DYNDNS_HOST && DYNDNS_HOST.includes('://') + ? DYNDNS_HOST.split('://')[1] + : DYNDNS_HOST; function generateKeys() { const identity = EthCrypto.createIdentity(); @@ -43,26 +39,16 @@ function generateKeys() { }; } -const readFile = util.promisify(fs.readFile); -const writeFile = util.promisify(fs.writeFile); - function getKeys() { - let path = process.env.DEV ? './mockFiles/keypair' : process.env.KEYPAIR_PATH; - if (!path) { - path = '/usr/src/app/secrets/keypair'; - logs.warn('KEYPAIR_FILE_path is not defined. Defaulting to /usr/src/app/secrets/keypair'); + const currentKeypair = db.get('keypair').value(); + if (currentKeypair) { + return currentKeypair; + } else { + const newKeypair = generateKeys(); + db.set('keypair', newKeypair).write(); + db.set('domain', newKeypair.domain).write(); + return newKeypair; } - return readFile(path) - .then(JSON.parse) - .catch((err) => { - if (err.code === 'ENOENT') { - const keydata = generateKeys(); - return writeFile(path, JSON.stringify(keydata)) - .then(() => keydata); - } else { - logs.error('Error getting keys from '+path+': '+ err.stack); - } - }); } module.exports = getKeys; diff --git a/build/src/src/dyndnsClient/test.js b/build/src/src/dyndnsClient/test.js deleted file mode 100644 index 4ffae59b..00000000 --- a/build/src/src/dyndnsClient/test.js +++ /dev/null @@ -1,18 +0,0 @@ -const updateIp = require('./updateIp'); - -/* eslint-disable */ - -/** - * Some env variables are needed to run the test - * -ENV DYNDNS_HOST https://ns.dappnode.io -ENV PUBLIC_IP_URL https://ns.dappnode.io/myip -ENV KEYPAIR_PATH /usr/src/app/secrets/keypair - - -KEYPAIR_PATH=./mockFiles/keypair DYNDNS_HOST=https://ns.dappnode.io PUBLIC_IP_URL=https://ns.dappnode.io/myip node src/dyndnsClient/test.js - - */ - -updateIp(); - diff --git a/build/src/src/dyndnsClient/updateIp.js b/build/src/src/dyndnsClient/updateIp.js index 3be64119..63943976 100644 --- a/build/src/src/dyndnsClient/updateIp.js +++ b/build/src/src/dyndnsClient/updateIp.js @@ -37,53 +37,53 @@ const db = require('../db'); */ function updateIp() { // get keys - return getKeys().then((identity) => { - // From identity - const {privateKey} = identity; + const identity = getKeys(); - // Prepare message - const timestamp = Math.floor(new Date() / 1000); - const messageHash = EthCrypto.hash.keccak256(timestamp.toString()); - const signature = EthCrypto.sign(privateKey, messageHash); - const publicKey = EthCrypto.publicKeyByPrivateKey(privateKey); - const address = EthCrypto.publicKey.toAddress(publicKey); + // From identity + const {privateKey} = identity; - // Send message - const parameters = [ - `address=${address}`, - `timestamp=${timestamp}`, - `sig=${signature}`, - ]; - // dyndnsHost has to contain http(s):// tag - // process.env.DYNDNS_HOST should include said tag - const dyndnsHost = process.env.DYNDNS_HOST; - const url = `${dyndnsHost}/?${parameters.join('&')}`; + // Prepare message + const timestamp = Math.floor(new Date() / 1000); + const messageHash = EthCrypto.hash.keccak256(timestamp.toString()); + const signature = EthCrypto.sign(privateKey, messageHash); + const publicKey = EthCrypto.publicKeyByPrivateKey(privateKey); + const address = EthCrypto.publicKey.toAddress(publicKey); - return httpGetRequest(url, {format: 'json'}) - .then((res) => { - const data = res.data || {}; - // Deal with the answer - // Sample res: - // res.data = { - // 'ip': '63.84.220.164', - // 'domain': '1234abcd1234acbd.dyndns.dappnode.io', - // 'message': 'Your dynamic domain 1234abcd1234acbd.dyndns.dappnode.io - // has been updated to 63.11.22.164', - // }; - if (res.code === 200) { - logs.info(`dyndns client success: ${data.message}`); - return data.domain; - } else { - const errorMsg = data.message || JSON.stringify(data); - logs.error(`dyndns client error code ${res.code}: ${errorMsg}`); - } - }) - .then((domain) => { - db.set('domain', domain).write(); - }) - .catch((err) => { - logs.error(`httpGetRequest error: ${err.stack || err.message}`); - }); + // Send message + const parameters = [ + `address=${address}`, + `timestamp=${timestamp}`, + `sig=${signature}`, + ]; + // dyndnsHost has to contain http(s):// tag + // process.env.DYNDNS_HOST should include said tag + const dyndnsHost = process.env.DYNDNS_HOST; + const url = `${dyndnsHost}/?${parameters.join('&')}`; + + return httpGetRequest(url, {format: 'json'}) + .then((res) => { + const data = res.data || {}; + // Deal with the answer + // Sample res: + // res.data = { + // 'ip': '63.84.220.164', + // 'domain': '1234abcd1234acbd.dyndns.dappnode.io', + // 'message': 'Your dynamic domain 1234abcd1234acbd.dyndns.dappnode.io + // has been updated to 63.11.22.164', + // }; + if (res.code === 200) { + logs.info(`dyndns client success: ${data.message}`); + return data.domain; + } else { + const errorMsg = data.message || JSON.stringify(data); + logs.error(`dyndns client error code ${res.code}: ${errorMsg}`); + } + }) + .then((domain) => { + db.set('domain', domain).write(); + }) + .catch((err) => { + logs.error(`httpGetRequest error: ${err.stack || err.message}`); }); } diff --git a/build/src/src/utils/getInstallationStaticIp.js b/build/src/src/fetchVpnParameters/getInstallationStaticIp.js similarity index 59% rename from build/src/src/utils/getInstallationStaticIp.js rename to build/src/src/fetchVpnParameters/getInstallationStaticIp.js index dda9143f..df05c548 100644 --- a/build/src/src/utils/getInstallationStaticIp.js +++ b/build/src/src/fetchVpnParameters/getInstallationStaticIp.js @@ -13,9 +13,16 @@ function getInstallationStaticIp() { .then((data) => String(data).trim()) // If the file is empty return null .then((data) => data.length ? data : null) - .then((ip) => ipRegex({exact: true}).test(ip)) + .then((ip) => { + if (ipRegex({exact: true}).test(ip)) return ip; + else return null; + }) .catch((err) => { - logs.error(`Error reading INSTALLATION_STATIC_IP ${INSTALLATION_STATIC_IP}: ${err.stack || err.message}`); + if (err.code === 'ENOENT') { + logs.warn(`INSTALLATION_STATIC_IP file not found at ${INSTALLATION_STATIC_IP}: ${err.stack || err.message}`); + } else { + logs.error(`Error reading INSTALLATION_STATIC_IP ${INSTALLATION_STATIC_IP}: ${err.stack || err.message}`); + } return null; }); } diff --git a/build/src/src/fetchVpnParameters/index.js b/build/src/src/fetchVpnParameters/index.js index 18f75018..bb83a325 100644 --- a/build/src/src/fetchVpnParameters/index.js +++ b/build/src/src/fetchVpnParameters/index.js @@ -3,11 +3,11 @@ const {promisify} = require('util'); const readFileAsync = promisify(fs.readFile); const db = require('../db'); const logs = require('../logs.js')(module); - -const DEV = process.env.DEV; +const dyndnsClient = require('../dyndnsClient'); const getUpnpStatus = require('./getUpnpStatus'); const getExternalIpResolves = require('./getExternalIpResolves'); +const getInstallationStaticIp = require('./getInstallationStaticIp'); // Fetch VPN parameters loads all files containing parameters and status @@ -15,13 +15,12 @@ const getExternalIpResolves = require('./getExternalIpResolves'); // The computation of this parameters is triggered from somewhere else. -const publicIpPath = DEV ? './mockFiles/ip' : process.env.PUBLIC_IP_PATH; -const pskPath = DEV ? './mockFiles/psk' : process.env.PSK_PATH; -const serverNamePath = DEV ? './mockFiles/name' : process.env.SERVER_NAME_PATH; -const internalIpPath = DEV ? './mockFiles/internal-ip' : process.env.INTERNAL_IP_PATH; -const externalIpPath = DEV ? './mockFiles/external-ip' : process.env.EXTERNAL_IP_PATH; -const publicIpResolvedPath = - DEV ? './mockFiles/public-ip-resolved' : process.env.PUBLIC_IP_RESOLVED_PATH; +const publicIpPath = process.env.PUBLIC_IP_PATH; +const pskPath = process.env.PSK_PATH; +const serverNamePath = process.env.SERVER_NAME_PATH; +const internalIpPath = process.env.INTERNAL_IP_PATH; +const externalIpPath = process.env.EXTERNAL_IP_PATH; +const publicIpResolvedPath = process.env.PUBLIC_IP_RESOLVED_PATH; const maxAttempts = 3 * 60; // 3 min const pauseTime = 1000; @@ -30,6 +29,8 @@ async function fetchVpnParameters() { // The second parameter is a fallback value // Not providing if enforces the existance of the file + // Step 1: Get variables coming from the init.sh process + // ===================================================== // > This files contain raw variables const ip = await fetchVpnParameter(publicIpPath); const psk = await fetchVpnParameter(pskPath); @@ -39,9 +40,6 @@ async function fetchVpnParameters() { await fetchVpnParameter(publicIpResolvedPath) == '1' ? true : false; const name = await fetchVpnParameter(serverNamePath, 'DAppNode_server'); - // > This files contain stringified jsons - const externalIpResolves = getExternalIpResolves(ip, internalIp, publicIpResolved); - const {openPorts, upnpAvailable} = getUpnpStatus(ip, externalIp, internalIp); db.set('ip', ip).write(); db.set('psk', psk).write(); @@ -49,21 +47,41 @@ async function fetchVpnParameters() { db.set('externalIp', externalIp).write(); db.set('publicIpResolved', publicIpResolved).write(); db.set('name', name).write(); + + + // Step 2: Process the loaded variables + // ============================================= + // > This files contain stringified jsons + const externalIpResolves = getExternalIpResolves(ip, internalIp, publicIpResolved); + const {openPorts, upnpAvailable} = getUpnpStatus(ip, externalIp, internalIp); + // Get the static ip possibly set during the installation + db.set('externalIpResolves', externalIpResolves).write(); db.set('openPorts', openPorts).write(); db.set('upnpAvailable', upnpAvailable).write(); - return { - ip, - psk, - internalIp, - externalIp, - publicIpResolved, - name, - externalIpResolves, - openPorts, - upnpAvailable, - }; + + // Step 3: Get ip (maybe) set during the installation + // ================================================== + // > Only write the IP if it comes from the installation + if (!db.get('initialized').value()) { + const staticIp = await getInstallationStaticIp(); + db.set('initialized', true).write(); + if (staticIp) { + logs.info(`Static IP was set during installation: ${staticIp}`); + db.set('staticIp', staticIp).write(); + } else { + logs.info(`Static IP was NOT set during installation`); + } + } + + // Step 4: Get the keys to register to the dyndns + // > The keys will be automatically stored in the db + // db.set('keypair', newKeypair).write(); + // db.set('domain', newKeypair.domain).write(); + if (!db.get('staticIp').value()) { + await dyndnsClient.getKeys(); + } } async function fileToExist(path, fallbackValue) { diff --git a/build/src/src/logAdminCredentials.js b/build/src/src/logAdminCredentials.js index 0f901ab0..7036388b 100644 --- a/build/src/src/logAdminCredentials.js +++ b/build/src/src/logAdminCredentials.js @@ -60,6 +60,9 @@ ${columns.map((col) => col.value).join(' ')}`; /* eslint-disable no-console */ console.log(msg); /* eslint-enable no-console */ + + // return msg for testing + return msg; } function parseUpnpStatus(openPorts, upnpAvailable) { diff --git a/build/src/test/dyndnsClient/getKeys.test.js b/build/src/test/dyndnsClient/getKeys.test.js index a09e5f66..8434046d 100644 --- a/build/src/test/dyndnsClient/getKeys.test.js +++ b/build/src/test/dyndnsClient/getKeys.test.js @@ -1,15 +1,29 @@ -const chai = require('chai'); const expect = require('chai').expect; -const getKeys = require('../../src/dyndnsClient/getKeys'); const fs = require('file-system'); const util = require('util'); const logs = require('../../src/logs.js')(module); - const unlink = util.promisify(fs.unlink); +const proxyquire = require('proxyquire'); + +const testFoler = './mockFiles'; +process.env.KEYPAIR_PATH = `${testFoler}/keypair`; +process.env.DYNDNS_HOST = 'dyn.test.io'; -chai.should(); +const dbResult = {}; +const db = { + set: (key, val) => ({ + write: () => { + dbResult[key] = val; + }, + }), + get: (key) => ({ + value: () => dbResult[key], + }), +}; -const KEYPAIR_PATH = './mockFiles/keypair'; +const getKeys = proxyquire('../../src/dyndnsClient/getKeys', { + '../db': db, +}); describe('Get keys function', function() { // Initialize calls @@ -19,15 +33,15 @@ describe('Get keys function', function() { describe('read non-existent file and create it', function() { before(async () => { // Clean files - await unlink(KEYPAIR_PATH).catch((err) => { + await unlink(process.env.KEYPAIR_PATH).catch((err) => { if (err.code !== 'ENOENT') { - logs.error('\n\n\n', err, '\n\n\n'); + logs.error(err); } }); }); it('should return an identity object', async () => { - _res = await getKeys(); + _res = await getKeys(db); expect(_res).to.be.an('Object'); expect(_res).to.have.property('address'); expect(_res).to.have.property('domain'); @@ -42,18 +56,22 @@ describe('Get keys function', function() { expect(host.join('.')).to.equal('dyn.test.io'); }); - it('should have created the keypair file', async () => { - expect(fs.existsSync(KEYPAIR_PATH)).to.be.true; + it('should have created the keypair object', async () => { + const keypair = db.get('keypair').value(); + expect(keypair).to.an('object'); + ['address', 'domain', 'privateKey', 'publicKey'].forEach((key) => { + expect(keypair).to.have.property(key); + }); }); it('should return the same identity the second time ', async () => { - const res = await getKeys(); + const res = await getKeys(db); expect(res).to.deep.equal(_res); }); after(async () => { // Clean files - await unlink(KEYPAIR_PATH).catch((err) => { + await unlink(process.env.KEYPAIR_PATH).catch((err) => { logs.error('\n\n\n', err, '\n\n\n'); }); }); diff --git a/build/src/test/fetchVpnParameters/getInstallationStaticIp.test.js b/build/src/test/fetchVpnParameters/getInstallationStaticIp.test.js new file mode 100644 index 00000000..bf562237 --- /dev/null +++ b/build/src/test/fetchVpnParameters/getInstallationStaticIp.test.js @@ -0,0 +1,56 @@ +const chai = require('chai'); +const expect = require('chai').expect; +const fs = require('fs'); + +chai.should(); + +const testFoler = './mockFiles'; +process.env.INSTALLATION_STATIC_IP = `${testFoler}/staticIp`; + +const getInstallationStaticIp = require('../../src/fetchVpnParameters/getInstallationStaticIp'); + +describe('Util: getInstallationStaticIp', function() { + before(() => { + try { + fs.mkdirSync(testFoler); + } catch (e) { + // + } + }); + + it('should return null if the file is missing', async () => { + const staticIp = await getInstallationStaticIp(); + expect(staticIp).to.equal(null); + }); + + it('should return null if the file is empty', async () => { + fs.writeFileSync(process.env.INSTALLATION_STATIC_IP, ''); + const staticIp = await getInstallationStaticIp(); + expect(staticIp).to.equal(null); + }); + + it('should return null if the ip is incorrect', async () => { + fs.writeFileSync(process.env.INSTALLATION_STATIC_IP, '333.45.43.1111'); + const staticIp = await getInstallationStaticIp(); + expect(staticIp).to.equal(null); + }); + + it('should return the ip if the ip is valid', async () => { + fs.writeFileSync(process.env.INSTALLATION_STATIC_IP, '85.4.52.53'); + const staticIp = await getInstallationStaticIp(); + expect(staticIp).to.equal('85.4.52.53'); + }); + + after(() => { + try { + fs.unlinkSync(process.env.INSTALLATION_STATIC_IP); + } catch (e) { + // + } + try { + fs.rmdirSync(testFoler); + } catch (e) { + // + } + }); +}); diff --git a/build/src/test/fetchVpnParameters/index.test.js b/build/src/test/fetchVpnParameters/index.test.js index d685245f..b8aef9ba 100644 --- a/build/src/test/fetchVpnParameters/index.test.js +++ b/build/src/test/fetchVpnParameters/index.test.js @@ -1,42 +1,41 @@ const chai = require('chai'); const expect = require('chai').expect; const fs = require('fs'); -const fetchVpnParameters = require('../../src/fetchVpnParameters'); +const db = require('../../src/db'); -chai.should(); +const paramsToWrite = { + staticIp: {data: '85.34.3.13', envName: 'INSTALLATION_STATIC_IP'}, + ip: {data: 'fakeIp', envName: 'PUBLIC_IP_PATH'}, + psk: {data: 'fakePsk', envName: 'PSK_PATH'}, + name: {data: 'fakeName', envName: 'SERVER_NAME_PATH'}, + internalIp: {data: 'fakeInternalIp', envName: 'INTERNAL_IP_PATH'}, + externalIp: {data: 'fakeExternalIp', envName: 'EXTERNAL_IP_PATH'}, + publicIpResolved: {data: '1', envName: 'PUBLIC_IP_RESOLVED_PATH'}, +}; -describe('fetchVpnParameters test', function() { - const paramsToWrite = { - ip: { - path: './mockFiles/ip', - data: 'fakeIp', - }, - psk: { - path: './mockFiles/psk', - data: 'fakePsk', - }, - name: { - path: './mockFiles/name', - data: 'fakeName', - }, - internalIp: { - path: './mockFiles/internal-ip', - data: 'fakeInternalIp', - }, - externalIp: { - path: './mockFiles/external-ip', - data: 'fakeExternalIp', - }, - publicIpResolved: { - path: './mockFiles/public-ip-resolved', - data: '1', - }, - }; +const testFoler = './mockFiles'; +Object.keys(paramsToWrite).forEach((paramName) => { + const param = paramsToWrite[paramName]; + param.path = `${testFoler}/${paramName}`; + process.env[param.envName] = param.path; +}); +process.env.DYNDNS_HOST = 'dyn.test.io'; - let params = {}; +const fetchVpnParameters = require('../../src/fetchVpnParameters'); +const getKeys = require('../../src/dyndnsClient/getKeys'); +const logAdminCredentials = require('../../src/logAdminCredentials'); +chai.should(); + +describe('fetchVpnParameters test', function() { before(() => { + // Restart db + try { + fs.unlinkSync('./db.json'); + } catch (e) { + // + } // Create the files try { fs.mkdirSync('./mockFiles'); @@ -49,12 +48,49 @@ describe('fetchVpnParameters test', function() { }); }); - it('should call fetchVpnParameters without crashing', async () => { - params = await fetchVpnParameters(); + it('should call correctly write the params in the db', async () => { + await fetchVpnParameters(); + expect(db.getState()).to.deep.equal({ + ip: 'fakeIp', + psk: 'fakePsk', + internalIp: 'fakeInternalIp', + externalIp: 'fakeExternalIp', + publicIpResolved: true, + name: 'fakeName', + externalIpResolves: true, + openPorts: true, + upnpAvailable: true, + staticIp: '85.34.3.13', + initialized: true, + }); + expect(db.getState().keypair).to.equal(undefined); + expect(db.getState().domain).to.equal(undefined); + }); + + it('should not refetch the staticIp from the installation file', async () => { + db.set('staticIp', '100.1.1.1').write(); + await fetchVpnParameters(); + expect(db.getState()).to.deep.include({ + staticIp: '100.1.1.1', + }); }); - it('the params object should be correct', () => { - expect(params).to.deep.equal({ + it('should call log adminCredentials', async () => { + const credentialsFile = require('../../src/utils/credentialsFile'); + const credentialsArray = [ + {name: 'SUPERadmin', password: 'MockPass2', ip: '172.33.10.1'}, + ]; + await credentialsFile.write(credentialsArray); + const log = await logAdminCredentials(); + expect(log).to.include('100.1.1.1'); + }); + + it('should get a new keypair if there is no staticIp', async () => { + db.set('staticIp', null).write(); + await fetchVpnParameters(); + // Deep clone. Calling getKeys() will generate keys if there weren't + const currentDb = JSON.parse(JSON.stringify(db.getState())); + expect(currentDb).to.deep.equal({ ip: 'fakeIp', psk: 'fakePsk', internalIp: 'fakeInternalIp', @@ -64,13 +100,33 @@ describe('fetchVpnParameters test', function() { externalIpResolves: true, openPorts: true, upnpAvailable: true, + staticIp: null, + initialized: true, + keypair: getKeys(), + domain: getKeys().domain, }); }); + it('should call log adminCredentials', async () => { + const credentialsFile = require('../../src/utils/credentialsFile'); + const credentialsArray = [ + {name: 'SUPERadmin', password: 'MockPass2', ip: '172.33.10.1'}, + ]; + await credentialsFile.write(credentialsArray); + const log = await logAdminCredentials(); + expect(log).to.include('.dyn.test.io'); + }); + after(() => { Object.keys(paramsToWrite).forEach((paramName) => { const param = paramsToWrite[paramName]; fs.unlinkSync(param.path); }); + // Restart db + try { + fs.unlinkSync('./db.json'); + } catch (e) { + // + } }); }); diff --git a/dappnode_package.json b/dappnode_package.json index ea10199e..e0d67bbe 100644 --- a/dappnode_package.json +++ b/dappnode_package.json @@ -1,18 +1,19 @@ { "name": "vpn.dnp.dappnode.eth", - "version": "0.1.14", + "version": "0.1.15", "description": "Dappnode package responsible for providing the VPN (L2TP/IPSec) connection", "avatar": "/ipfs/QmWwMb3XhuCH6JnCF6m6EQzA4mW9pHHtg7rqAfhDr2ofi8", "type": "dncore", "image": { - "path": "vpn.dnp.dappnode.eth_0.1.13.tar.xz", + "path": "", "hash": "", "size": 0, "volumes": [ "/etc/hostname:/etc/vpnname:ro", "/lib/modules:/lib/modules:ro", "vpndnpdappnodeeth_data:/usr/src/app/secrets", - "/var/run/docker.sock:/var/run/docker.sock" + "/var/run/docker.sock:/var/run/docker.sock", + "/usr/src/dappnode/config:/usr/src/app/config:ro" ], "ports": [ "4500:4500/udp", diff --git a/docker-compose-vpn.yml b/docker-compose-vpn.yml index 7c176abd..51563cca 100644 --- a/docker-compose-vpn.yml +++ b/docker-compose-vpn.yml @@ -1,25 +1,26 @@ -version: '3.4' +version: "3.4" networks: - network: - driver: bridge - ipam: - config: - - subnet: 172.33.0.0/16 + network: + driver: bridge + ipam: + config: + - subnet: 172.33.0.0/16 volumes: - vpndnpdappnodeeth_data: {} + vpndnpdappnodeeth_data: {} services: vpn.dnp.dappnode.eth: build: ./build - image: vpn.dnp.dappnode.eth:0.1.14 + image: vpn.dnp.dappnode.eth:0.1.15 container_name: DAppNodeCore-vpn.dnp.dappnode.eth privileged: true restart: always volumes: - /var/run/docker.sock:/var/run/docker.sock - /etc/hostname:/etc/vpnname:ro + - /usr/src/dappnode/config:/usr/src/app/config:ro - /lib/modules:/lib/modules:ro - vpndnpdappnodeeth_data:/usr/src/app/secrets ports: @@ -28,4 +29,4 @@ services: dns: 172.33.1.2 networks: network: - ipv4_address: 172.33.1.4 \ No newline at end of file + ipv4_address: 172.33.1.4