From f638a7eaca4c91d94d62aeda75b1a5ecfcc80b7f Mon Sep 17 00:00:00 2001 From: Joshua Melville Date: Mon, 6 Jan 2020 12:20:41 +0200 Subject: [PATCH 1/6] testing certificate changes --- package-lock.json | 20 ++++++++++---------- package.json | 2 +- src/main/server/ensurePemKeyPair.js | 14 +++++++------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 35e00e984..5ad1e2d0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5777,7 +5777,7 @@ }, "bl": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", "requires": { "readable-stream": "^2.3.5", @@ -8473,7 +8473,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -12078,7 +12078,7 @@ }, "http-proxy-middleware": { "version": "0.18.0", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz", + "resolved": "http://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz", "integrity": "sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q==", "dev": true, "requires": { @@ -15398,9 +15398,9 @@ } }, "node-forge": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", - "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", + "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==" }, "node-gyp": { "version": "3.8.0", @@ -24011,11 +24011,11 @@ "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" }, "selfsigned": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.4.tgz", - "integrity": "sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz", + "integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==", "requires": { - "node-forge": "0.7.5" + "node-forge": "0.9.0" } }, "semver": { diff --git a/package.json b/package.json index a9c80a1bb..0a8eb2ec9 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "reselect": "^3.0.0", "restify": "^7.2.1", "restify-cors-middleware": "^1.1.1", - "selfsigned": "^1.10.3", + "selfsigned": "^1.10.7", "thread-loader": "^1.1.5", "uuid": "^3.3.2", "xmldom": "^0.1.27" diff --git a/src/main/server/ensurePemKeyPair.js b/src/main/server/ensurePemKeyPair.js index 817ce0c64..99ad320e0 100644 --- a/src/main/server/ensurePemKeyPair.js +++ b/src/main/server/ensurePemKeyPair.js @@ -37,20 +37,20 @@ const generatePemKeyPair = () => { keyEncipherment: true, dataEncipherment: true, }, + { + name: 'extKeyUsage', + serverAuth: true, + }, { name: 'subjectAltName', altNames: [ { type: AltNameTypeDNS, - value: 'localhost', - }, - { - type: AltNameTypeIP, - ip: '127.0.0.1', + value: 'networkcanvas.com', }, { type: AltNameTypeIP, - ip: '::', + ip: '185.101.98.135', }, ], }, @@ -59,7 +59,7 @@ const generatePemKeyPair = () => { // TODO: Ed25519 and/or native implementation const pems = selfsigned.generate(attrs, { algorithm: 'sha256', - days: 365 * 10, + days: 365 * 1, keySize: 2048, extensions, }); From 415288202c1ee2c00b02121a1628712d4590f225 Mon Sep 17 00:00:00 2001 From: Joshua Melville Date: Mon, 6 Jan 2020 16:03:29 +0200 Subject: [PATCH 2/6] add localhost back in --- src/main/server/ensurePemKeyPair.js | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/main/server/ensurePemKeyPair.js b/src/main/server/ensurePemKeyPair.js index 99ad320e0..afa33fcdc 100644 --- a/src/main/server/ensurePemKeyPair.js +++ b/src/main/server/ensurePemKeyPair.js @@ -1,4 +1,5 @@ const path = require('path'); +const os = require('os'); const selfsigned = require('selfsigned'); const logger = require('electron-log'); const { app } = require('electron'); @@ -21,6 +22,13 @@ const fingerprintFile = path.join(certDir, 'device-api-fingerprint.txt'); * @throws {Error} If files already exist */ const generatePemKeyPair = () => { + const isLinkLocal = addr => /^(fe80::|169\.254)/.test(addr); + const interfaces = Object.values(os.networkInterfaces()); + const IPAddress = [].concat(...interfaces) + .filter(iface => iface.internal === false && !isLinkLocal(iface.address)) + .map(iface => iface.address); + + const hostName = os.hostname(); const AltNameTypeDNS = 2; const AltNameTypeIP = 7; const attrs = [{ name: 'commonName', value: commonName }]; @@ -46,11 +54,23 @@ const generatePemKeyPair = () => { altNames: [ { type: AltNameTypeDNS, - value: 'networkcanvas.com', + value: hostName, + }, + { + type: AltNameTypeDNS, + value: 'localhost', + }, + { + type: AltNameTypeIP, + ip: IPAddress[0], + }, + { + type: AltNameTypeIP, + ip: '127.0.0.1', }, { type: AltNameTypeIP, - ip: '185.101.98.135', + ip: '::', }, ], }, From a5a3cfbb2db3e3f92e8d0e70f529b6c220500e16 Mon Sep 17 00:00:00 2001 From: Joshua Melville Date: Tue, 7 Jan 2020 13:06:39 +0200 Subject: [PATCH 3/6] finalize certificate changes --- src/main/server/ensurePemKeyPair.js | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/main/server/ensurePemKeyPair.js b/src/main/server/ensurePemKeyPair.js index afa33fcdc..8a33e9915 100644 --- a/src/main/server/ensurePemKeyPair.js +++ b/src/main/server/ensurePemKeyPair.js @@ -1,5 +1,4 @@ const path = require('path'); -const os = require('os'); const selfsigned = require('selfsigned'); const logger = require('electron-log'); const { app } = require('electron'); @@ -22,13 +21,6 @@ const fingerprintFile = path.join(certDir, 'device-api-fingerprint.txt'); * @throws {Error} If files already exist */ const generatePemKeyPair = () => { - const isLinkLocal = addr => /^(fe80::|169\.254)/.test(addr); - const interfaces = Object.values(os.networkInterfaces()); - const IPAddress = [].concat(...interfaces) - .filter(iface => iface.internal === false && !isLinkLocal(iface.address)) - .map(iface => iface.address); - - const hostName = os.hostname(); const AltNameTypeDNS = 2; const AltNameTypeIP = 7; const attrs = [{ name: 'commonName', value: commonName }]; @@ -52,18 +44,10 @@ const generatePemKeyPair = () => { { name: 'subjectAltName', altNames: [ - { - type: AltNameTypeDNS, - value: hostName, - }, { type: AltNameTypeDNS, value: 'localhost', }, - { - type: AltNameTypeIP, - ip: IPAddress[0], - }, { type: AltNameTypeIP, ip: '127.0.0.1', @@ -79,7 +63,7 @@ const generatePemKeyPair = () => { // TODO: Ed25519 and/or native implementation const pems = selfsigned.generate(attrs, { algorithm: 'sha256', - days: 365 * 1, + days: 365 * 2, keySize: 2048, extensions, }); From bfb68bc732266d1e9701096f32db0e9bf02389b8 Mon Sep 17 00:00:00 2001 From: Joshua Melville Date: Tue, 7 Jan 2020 14:56:07 +0200 Subject: [PATCH 4/6] implement certificate reset UI and link to reset data --- src/main/MainApp.js | 20 ++++++++++++++++++- src/main/data-managers/DeviceManager.js | 1 - src/main/server/AdminService.js | 7 ++++++- src/main/server/ServerFactory.js | 2 +- .../server/__tests__/ensurePemKeyPair-test.js | 2 +- src/main/server/ensurePemKeyPair.js | 19 +++++++++++++++++- src/main/utils/promised-fs.js | 1 + 7 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/main/MainApp.js b/src/main/MainApp.js index 23793b820..c1cf603bb 100644 --- a/src/main/MainApp.js +++ b/src/main/MainApp.js @@ -2,6 +2,7 @@ const { app, Menu } = require('electron'); const ProtocolManager = require('./data-managers/ProtocolManager'); const MainWindow = require('./components/mainWindow'); const { AdminService } = require('./server/AdminService'); +const { resetPemKeyPair } = require('./server/ensurePemKeyPair'); const { isWindows } = require('./utils/environment'); const { createTray } = require('./components/tray'); @@ -30,10 +31,23 @@ const createApp = () => { const updater = Updater(); updater.checkForUpdates(true); + const regenerateCertificates = () => { + const responseNum = dialog.showMessageBox(mainWindow.window, { + message: 'Regenerate certificates?', + detail: 'Regenerating security certificates will require you to re-pair all of your devices. Do you want to continue?', + buttons: ['Regenerate Certificates', 'Cancel'], + cancelId: 1, + defaultId: 0, + }); + if (responseNum === 0) { + resetPemKeyPair().then(adminService.resetDevices()).then(reloadHomeScreen); + } + }; + const resetAppData = () => { const responseNum = dialog.showMessageBox(mainWindow.window, { message: 'Destroy all application files and data?', - detail: 'This includes all imported protocols and paired devices', + detail: 'This will delete ALL existing data, including interview data, imported protocols and paired devices. Do you want to continue?', buttons: ['Reset Data', 'Cancel'], cancelId: 1, defaultId: 0, @@ -91,6 +105,10 @@ const createApp = () => { click: showImportProtocolDialog, }, { type: 'separator' }, + { + label: 'Regenerate Certificates...', + click: regenerateCertificates, + }, { label: 'Reset Data...', click: resetAppData, diff --git a/src/main/data-managers/DeviceManager.js b/src/main/data-managers/DeviceManager.js index 6fb4345e2..75cac11e4 100644 --- a/src/main/data-managers/DeviceManager.js +++ b/src/main/data-managers/DeviceManager.js @@ -25,7 +25,6 @@ class DeviceManager { return this.db.all(); } - // TODO: Probably remove after alpha testing destroyAllDevices() { return this.db.destroyAll(); } diff --git a/src/main/server/AdminService.js b/src/main/server/AdminService.js index 8eb1fcf10..80b8c0285 100644 --- a/src/main/server/AdminService.js +++ b/src/main/server/AdminService.js @@ -7,6 +7,7 @@ const apiRequestLogger = require('./apiRequestLogger'); const DeviceManager = require('../data-managers/DeviceManager'); const ProtocolManager = require('../data-managers/ProtocolManager'); const ExportManager = require('../data-managers/ExportManager'); +const { resetPemKeyPair } = require('../server/ensurePemKeyPair'); const { PairingRequestService } = require('./devices/PairingRequestService'); const { RequestError, ErrorMessages } = require('../errors/RequestError'); @@ -300,9 +301,13 @@ class AdminService { return api; } - // TODO: Probably remove after alpha testing + resetDevices() { + return this.deviceManager.destroyAllDevices(); + } + resetData() { return Promise.all([ + resetPemKeyPair(), this.deviceManager.destroyAllDevices(), this.protocolManager.destroyAllProtocols(), this.protocolManager.destroyAllSessions(), diff --git a/src/main/server/ServerFactory.js b/src/main/server/ServerFactory.js index 5cd0b8859..c8a191e9e 100644 --- a/src/main/server/ServerFactory.js +++ b/src/main/server/ServerFactory.js @@ -1,5 +1,5 @@ const Server = require('./Server'); -const ensurePemKeyPair = require('./ensurePemKeyPair'); +const { ensurePemKeyPair } = require('./ensurePemKeyPair'); const { ready: cipherReady } = require('../utils/shared-api/cipher'); const { deviceServiceEvents } = require('./devices/DeviceService'); diff --git a/src/main/server/__tests__/ensurePemKeyPair-test.js b/src/main/server/__tests__/ensurePemKeyPair-test.js index 11d2f8bf7..7bc70f01b 100644 --- a/src/main/server/__tests__/ensurePemKeyPair-test.js +++ b/src/main/server/__tests__/ensurePemKeyPair-test.js @@ -1,7 +1,7 @@ /* eslint-env jest */ const selfsigned = require('selfsigned'); -const ensurePemKeyPair = require('../ensurePemKeyPair'); +const { ensurePemKeyPair } = require('../ensurePemKeyPair'); const promisedFs = require('../../utils/promised-fs'); jest.mock('selfsigned'); diff --git a/src/main/server/ensurePemKeyPair.js b/src/main/server/ensurePemKeyPair.js index 8a33e9915..28724069d 100644 --- a/src/main/server/ensurePemKeyPair.js +++ b/src/main/server/ensurePemKeyPair.js @@ -109,4 +109,21 @@ const ensurePemKeyPair = () => ( }) ); -module.exports = ensurePemKeyPair; +const resetPemKeyPair = () => ( + Promise.all([ + promisedFs.tryUnlink(certPem), + promisedFs.tryUnlink(privatePem), + promisedFs.tryUnlink(publicPem), + promisedFs.tryUnlink(fingerprintFile), + ]) + .then(generatePemKeyPair) + .catch((err) => { + logger.error(err); + throw err; + }) +); + +module.exports = { + ensurePemKeyPair, + resetPemKeyPair, +}; diff --git a/src/main/utils/promised-fs.js b/src/main/utils/promised-fs.js index be2939a0e..76e47f7f5 100644 --- a/src/main/utils/promised-fs.js +++ b/src/main/utils/promised-fs.js @@ -68,6 +68,7 @@ const unlink = path => (new Promise((resolve, reject) => { } catch (err) { reject(err); } })); +// Ignore "file/directory doesn't exist" errors. const tryUnlink = path => unlink(path).catch((err) => { if (err.code !== 'ENOENT') { throw err; } }); From 1df45eee34fcb529c776548fcb91b7edc388039e Mon Sep 17 00:00:00 2001 From: Joshua Melville Date: Tue, 7 Jan 2020 14:58:31 +0200 Subject: [PATCH 5/6] rename ensurePemKeyPair -> certificateManager --- src/main/MainApp.js | 2 +- src/main/server/AdminService.js | 2 +- src/main/server/ServerFactory.js | 2 +- src/main/server/{ensurePemKeyPair.js => certificateManager.js} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename src/main/server/{ensurePemKeyPair.js => certificateManager.js} (100%) diff --git a/src/main/MainApp.js b/src/main/MainApp.js index c1cf603bb..3910ac0ca 100644 --- a/src/main/MainApp.js +++ b/src/main/MainApp.js @@ -2,7 +2,7 @@ const { app, Menu } = require('electron'); const ProtocolManager = require('./data-managers/ProtocolManager'); const MainWindow = require('./components/mainWindow'); const { AdminService } = require('./server/AdminService'); -const { resetPemKeyPair } = require('./server/ensurePemKeyPair'); +const { resetPemKeyPair } = require('./server/certificateManager'); const { isWindows } = require('./utils/environment'); const { createTray } = require('./components/tray'); diff --git a/src/main/server/AdminService.js b/src/main/server/AdminService.js index 80b8c0285..3888bbfea 100644 --- a/src/main/server/AdminService.js +++ b/src/main/server/AdminService.js @@ -7,7 +7,7 @@ const apiRequestLogger = require('./apiRequestLogger'); const DeviceManager = require('../data-managers/DeviceManager'); const ProtocolManager = require('../data-managers/ProtocolManager'); const ExportManager = require('../data-managers/ExportManager'); -const { resetPemKeyPair } = require('../server/ensurePemKeyPair'); +const { resetPemKeyPair } = require('./certificateManager'); const { PairingRequestService } = require('./devices/PairingRequestService'); const { RequestError, ErrorMessages } = require('../errors/RequestError'); diff --git a/src/main/server/ServerFactory.js b/src/main/server/ServerFactory.js index c8a191e9e..29b5f3bba 100644 --- a/src/main/server/ServerFactory.js +++ b/src/main/server/ServerFactory.js @@ -1,5 +1,5 @@ const Server = require('./Server'); -const { ensurePemKeyPair } = require('./ensurePemKeyPair'); +const { ensurePemKeyPair } = require('./certificateManager'); const { ready: cipherReady } = require('../utils/shared-api/cipher'); const { deviceServiceEvents } = require('./devices/DeviceService'); diff --git a/src/main/server/ensurePemKeyPair.js b/src/main/server/certificateManager.js similarity index 100% rename from src/main/server/ensurePemKeyPair.js rename to src/main/server/certificateManager.js From e5e35c8bebf2e63b41977e59796392d2b70b2732 Mon Sep 17 00:00:00 2001 From: Joshua Melville Date: Tue, 7 Jan 2020 15:09:32 +0200 Subject: [PATCH 6/6] update tests --- src/main/server/__tests__/ServerFactory-test.js | 2 +- .../{ensurePemKeyPair-test.js => certificateManager-test.js} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/main/server/__tests__/{ensurePemKeyPair-test.js => certificateManager-test.js} (97%) diff --git a/src/main/server/__tests__/ServerFactory-test.js b/src/main/server/__tests__/ServerFactory-test.js index 41d32ee0f..883001640 100644 --- a/src/main/server/__tests__/ServerFactory-test.js +++ b/src/main/server/__tests__/ServerFactory-test.js @@ -3,7 +3,7 @@ const path = require('path'); const { createServer } = require('../ServerFactory'); -jest.mock('../ensurePemKeyPair'); +jest.mock('../certificateManager'); const mockServerMethods = { close: jest.fn(), diff --git a/src/main/server/__tests__/ensurePemKeyPair-test.js b/src/main/server/__tests__/certificateManager-test.js similarity index 97% rename from src/main/server/__tests__/ensurePemKeyPair-test.js rename to src/main/server/__tests__/certificateManager-test.js index 7bc70f01b..620550ee5 100644 --- a/src/main/server/__tests__/ensurePemKeyPair-test.js +++ b/src/main/server/__tests__/certificateManager-test.js @@ -1,7 +1,7 @@ /* eslint-env jest */ const selfsigned = require('selfsigned'); -const { ensurePemKeyPair } = require('../ensurePemKeyPair'); +const { ensurePemKeyPair } = require('../certificateManager'); const promisedFs = require('../../utils/promised-fs'); jest.mock('selfsigned');