From e9ccbeab201ef6ae5239d59dfde2e53733454a0f Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Mon, 13 Dec 2021 20:53:43 -0400 Subject: [PATCH 01/12] Foundations for ECC subprocess --- utils/ECC/subprocess.js | 167 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 utils/ECC/subprocess.js diff --git a/utils/ECC/subprocess.js b/utils/ECC/subprocess.js new file mode 100644 index 00000000..18a9d58a --- /dev/null +++ b/utils/ECC/subprocess.js @@ -0,0 +1,167 @@ +/** + * @format + */ +const Crypto = require('crypto') +const ECCrypto = require('eccrypto') +const uuid = require('uuid/v1') +const { Buffer } = require('buffer') + +const logger = require('../../config/log') + +logger.info('crypto subprocess invoked') + +process.on('uncaughtException', e => { + logger.error('Uncaught exception inside crypto subprocess:') + logger.error(e) +}) + +process.on('unhandledRejection', e => { + logger.error('Unhandled rejection inside crypto subprocess:') + logger.error(e) +}) + +/** + * @typedef {'generateRandomString' | 'convertUTF8ToBuffer' + * | 'convertBase64ToBuffer' | 'convertBufferToBase64' | 'generatePrivate' + * | 'getPublic' | 'encrypt' | 'decrypt' + * } Method + */ + +/** + * @typedef {object} Msg + * @prop {any[]} args + * @prop {string} id + * @prop {Method} method + */ + +/** + * @param {Msg} msg + */ +const handleMsg = async msg => { + if (typeof msg !== 'object' || msg === null) { + logger.error('Msg in crypto subprocess not an object') + } + + const { args, id, method } = msg + + try { + if (method === 'generateRandomString') { + const [length] = args + + Crypto.randomBytes(length / 2, (err, buffer) => { + if (err) { + // @ts-expect-error + process.send({ + id, + err: err.message + }) + return + } + + const token = buffer.toString('hex') + // @ts-expect-error + process.send({ + id, + payload: token + }) + }) + } + if (method === 'convertUTF8ToBuffer') { + const [value] = args + + // @ts-expect-error + process.send({ + id, + payload: Buffer.from(value, 'utf8') + }) + } + if (method === 'convertBase64ToBuffer') { + const [value] = args + + // @ts-expect-error + process.send({ + id, + payload: Buffer.from(value, 'base64') + }) + } + if (method === 'convertBufferToBase64') { + const [buffer] = args + + // @ts-expect-error + process.send({ + id, + payload: buffer.toString('base64') + }) + } + if (method === 'generatePrivate') { + // @ts-expect-error + process.send({ + id, + payload: ECCrypto.generatePrivate() + }) + } + if (method === 'getPublic') { + const [privateKey] = args + // @ts-expect-error + process.send({ + id, + payload: ECCrypto.getPublic(privateKey) + }) + } + if (method === 'encrypt') { + const [processedPublicKey, messageBuffer] = args + // @ts-expect-error + process.send({ + id, + payload: ECCrypto.encrypt(processedPublicKey, messageBuffer) + }) + } + if (method === 'decrypt') { + const [processedPrivateKey, encryptedMessage] = args + // @ts-expect-error + process.send({ + id, + payload: await ECCrypto.decrypt(processedPrivateKey, encryptedMessage) + }) + } + } catch (e) { + // @ts-expect-error + process.send({ + err: e.message + }) + } +} + +process.on('message', handleMsg) + +/** + * @param {Method} method + * @param {any[]} args + * @param {import('child_process').ChildProcess} cryptoSubprocess + * @returns {Promise} + */ +const invoke = (method, args, cryptoSubprocess) => + new Promise((res, rej) => { + const id = uuid() + /** @param {any} msg */ + const listener = msg => { + if (msg.id === id) { + cryptoSubprocess.off('message', listener) + if (msg.err) { + rej(new Error(msg.err)) + } else { + res(msg.payload) + } + } + } + cryptoSubprocess.on('message', listener) + cryptoSubprocess.send({ + args, + id, + method + }) + }) + +module.exports = { + invoke +} From 6a5b6af31fb65daf27f7e0d30bffda3c71985fd9 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 14 Dec 2021 13:54:14 -0400 Subject: [PATCH 02/12] Better test --- utils/ECC/crypto.spec.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/ECC/crypto.spec.js b/utils/ECC/crypto.spec.js index 9b9904a0..a848b65b 100644 --- a/utils/ECC/crypto.spec.js +++ b/utils/ECC/crypto.spec.js @@ -13,7 +13,8 @@ const { describe('generateRandomString()', () => { it('creates a random string of the specified length', async () => { expect.hasAssertions() - const len = Math.ceil(Math.random() * 100) + const base = Math.ceil(Math.random() * 100) + const len = base % 2 !== 0 ? base + 1 : base const result = await generateRandomString(len) expect(result.length).toEqual(len) From ece11954a1812471b6ef21a07537a8f779add9a0 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 14 Dec 2021 17:11:42 -0400 Subject: [PATCH 03/12] Move generateRandomString() to subprocess --- utils/ECC/crypto.js | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/utils/ECC/crypto.js b/utils/ECC/crypto.js index 6d329eb7..7a4cb5c9 100644 --- a/utils/ECC/crypto.js +++ b/utils/ECC/crypto.js @@ -2,9 +2,14 @@ * @format */ const { Buffer } = require('buffer') -const Crypto = require('crypto') +const { fork } = require('child_process') + const FieldError = require('../fieldError') +const { invoke } = require('./subprocess') + +const cryptoSubprocess = fork('utils/ECC/subprocess') + /** * @typedef {object} EncryptedMessageBuffer * @prop {Buffer} ciphertext @@ -23,19 +28,15 @@ const FieldError = require('../fieldError') * @prop {any?} metadata */ -const generateRandomString = (length = 16) => - new Promise((resolve, reject) => { - // Gotta halve because randomBytes returns a sequence twice the size - Crypto.randomBytes(length / 2, (err, buffer) => { - if (err) { - reject(err) - return - } +const generateRandomString = async (length = 16) => { + if (length % 2 !== 0 || length < 2) { + throw new Error('Random string length must be an even number.') + } - const token = buffer.toString('hex') - resolve(token) - }) - }) + const res = await invoke('generateRandomString', [length], cryptoSubprocess) + + return res +} /** * @param {string} value From 1342fb5b3f41f77e1b2cdcc0e0c02443e012c8c9 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 14 Dec 2021 17:14:39 -0400 Subject: [PATCH 04/12] Make async in preparation for future change --- utils/ECC/ECC.js | 6 +++--- utils/ECC/ECC.spec.js | 16 +++++++++------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/utils/ECC/ECC.js b/utils/ECC/ECC.js index 990eac62..2d8de174 100644 --- a/utils/ECC/ECC.js +++ b/utils/ECC/ECC.js @@ -47,9 +47,9 @@ const isEncryptedMessage = message => * Generates a new encryption key pair that will be used * when communicating with the deviceId specified * @param {string} deviceId - * @returns {Pair} + * @returns {Promise} */ -const generateKeyPair = deviceId => { +const generateKeyPair = async deviceId => { try { const existingKey = nodeKeyPairs.get(deviceId) @@ -107,7 +107,7 @@ const isAuthorizedDevice = ({ deviceId }) => devicePublicKeys.has(deviceId) const authorizeDevice = async ({ deviceId, publicKey }) => { const hostId = await Storage.get('encryption/hostId') devicePublicKeys.set(deviceId, convertBase64ToBuffer(publicKey)) - const keyPair = generateKeyPair(deviceId) + const keyPair = await generateKeyPair(deviceId) return { success: true, diff --git a/utils/ECC/ECC.spec.js b/utils/ECC/ECC.spec.js index e4fbb9f7..7252e7c0 100644 --- a/utils/ECC/ECC.spec.js +++ b/utils/ECC/ECC.spec.js @@ -22,18 +22,20 @@ const storageDirectory = Path.resolve(__dirname, `./.test-storage`) console.log(`Storage directory: ${storageDirectory}`) describe('generateKeyPair()', () => { - it('generates a keypair', () => { - const pair = generateKeyPair(uuid()) + it('generates a keypair', async () => { + expect.hasAssertions() + const pair = await generateKeyPair(uuid()) expect(pair.privateKey).toBeInstanceOf(Buffer) expect(typeof pair.privateKeyBase64 === 'string').toBeTruthy() expect(pair.publicKey).toBeInstanceOf(Buffer) expect(typeof pair.publicKeyBase64 === 'string').toBeTruthy() }) - it('returns the same pair for the same device', () => { + it('returns the same pair for the same device', async () => { + expect.hasAssertions() const id = uuid() - const pair = generateKeyPair(id) - const pairAgain = generateKeyPair(id) + const pair = await generateKeyPair(id) + const pairAgain = await generateKeyPair(id) expect(pairAgain).toStrictEqual(pair) }) @@ -46,7 +48,7 @@ describe('authorizeDevice()/isAuthorizedDevice()', () => { dir: storageDirectory }) const deviceId = uuid() - const pair = generateKeyPair(deviceId) + const pair = await generateKeyPair(deviceId) await authorizeDevice({ deviceId, publicKey: pair.publicKeyBase64 }) expect(isAuthorizedDevice({ deviceId })).toBeTruthy() }) @@ -96,7 +98,7 @@ describe('encryptMessage()/decryptMessage()', () => { expect.hasAssertions() const deviceId = uuid() - const pair = generateKeyPair(deviceId) + const pair = await generateKeyPair(deviceId) await authorizeDevice({ deviceId, publicKey: pair.publicKeyBase64 }) From ef3064bbdd99a563576d237ea852a666dcde3294 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 15 Dec 2021 15:47:10 -0400 Subject: [PATCH 05/12] Deserialize buffers in/out of subprocess --- utils/ECC/subprocess.js | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/utils/ECC/subprocess.js b/utils/ECC/subprocess.js index 18a9d58a..987ee279 100644 --- a/utils/ECC/subprocess.js +++ b/utils/ECC/subprocess.js @@ -5,6 +5,7 @@ const Crypto = require('crypto') const ECCrypto = require('eccrypto') const uuid = require('uuid/v1') const { Buffer } = require('buffer') +const mapValues = require('lodash/mapValues') const logger = require('../../config/log') @@ -27,6 +28,20 @@ process.on('unhandledRejection', e => { * } Method */ +/** + * @param {any} obj + * @returns {any} + */ +const processBufferAfterSerialization = obj => { + if (typeof obj === 'object' && obj !== null) { + if (obj.type === 'Buffer') { + return Buffer.from(obj.data) + } + return mapValues(obj, processBufferAfterSerialization) + } + return obj +} + /** * @typedef {object} Msg * @prop {any[]} args @@ -42,7 +57,8 @@ const handleMsg = async msg => { logger.error('Msg in crypto subprocess not an object') } - const { args, id, method } = msg + const { id, method } = msg + const args = msg.args.map(processBufferAfterSerialization) try { if (method === 'generateRandomString') { @@ -113,7 +129,7 @@ const handleMsg = async msg => { // @ts-expect-error process.send({ id, - payload: ECCrypto.encrypt(processedPublicKey, messageBuffer) + payload: await ECCrypto.encrypt(processedPublicKey, messageBuffer) }) } if (method === 'decrypt') { @@ -150,7 +166,7 @@ const invoke = (method, args, cryptoSubprocess) => if (msg.err) { rej(new Error(msg.err)) } else { - res(msg.payload) + res(processBufferAfterSerialization(msg.payload)) } } } From 99103b84b8f53f1a368e9df4501b73e7634e8df8 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 15 Dec 2021 15:47:40 -0400 Subject: [PATCH 06/12] Generate keypair through subprocess --- utils/ECC/ECC.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/utils/ECC/ECC.js b/utils/ECC/ECC.js index 2d8de174..2dbf265f 100644 --- a/utils/ECC/ECC.js +++ b/utils/ECC/ECC.js @@ -1,6 +1,8 @@ /** @format */ const ECCrypto = require('eccrypto') const Storage = require('node-persist') +const { fork } = require('child_process') + const FieldError = require('../fieldError') const logger = require('../../config/log') const { @@ -12,6 +14,9 @@ const { convertToEncryptedMessage, convertBase64ToBuffer } = require('./crypto') +const { invoke } = require('./subprocess') + +const cryptoSubprocess = fork('utils/ECC/subprocess') const nodeKeyPairs = new Map() const devicePublicKeys = new Map() @@ -62,8 +67,8 @@ const generateKeyPair = async deviceId => { } } - const privateKey = ECCrypto.generatePrivate() - const publicKey = ECCrypto.getPublic(privateKey) + const privateKey = await invoke('generatePrivate', [], cryptoSubprocess) + const publicKey = await invoke('getPublic', [privateKey], cryptoSubprocess) const privateKeyBase64 = convertBufferToBase64(privateKey) const publicKeyBase64 = convertBufferToBase64(publicKey) From e081e1616ac61d83bdc5ec9866cf26783f696446 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 15 Dec 2021 15:48:01 -0400 Subject: [PATCH 07/12] Encrypt through subprocess --- utils/ECC/ECC.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/utils/ECC/ECC.js b/utils/ECC/ECC.js index 2dbf265f..8de6ad7e 100644 --- a/utils/ECC/ECC.js +++ b/utils/ECC/ECC.js @@ -142,10 +142,12 @@ const encryptMessage = async ({ message = '', deviceId }) => { const processedPublicKey = processKey(publicKey) const messageBuffer = convertUTF8ToBuffer(parsedMessage) - const encryptedMessage = await ECCrypto.encrypt( - processedPublicKey, - messageBuffer + const encryptedMessage = await invoke( + 'encrypt', + [processedPublicKey, messageBuffer], + cryptoSubprocess ) + const encryptedMessageResponse = { ciphertext: encryptedMessage.ciphertext, iv: encryptedMessage.iv, From 459b67503950b2c8c4ff64b5194792826db11714 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 15 Dec 2021 15:52:59 -0400 Subject: [PATCH 08/12] Decrypt through subprocess --- utils/ECC/ECC.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/utils/ECC/ECC.js b/utils/ECC/ECC.js index 8de6ad7e..4e53a5b3 100644 --- a/utils/ECC/ECC.js +++ b/utils/ECC/ECC.js @@ -1,5 +1,4 @@ /** @format */ -const ECCrypto = require('eccrypto') const Storage = require('node-persist') const { fork } = require('child_process') @@ -180,9 +179,10 @@ const decryptMessage = async ({ encryptedMessage, deviceId }) => { } const processedPrivateKey = processKey(keyPair.privateKey) - const decryptedMessage = await ECCrypto.decrypt( - processedPrivateKey, - convertToEncryptedMessage(encryptedMessage) + const decryptedMessage = await invoke( + 'decrypt', + [processedPrivateKey, convertToEncryptedMessage(encryptedMessage)], + cryptoSubprocess ) const parsedMessage = decryptedMessage.toString('utf8') From 22f989ee99c8c71a1527521431fe031c6d1e9313 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 16 Dec 2021 09:48:36 -0400 Subject: [PATCH 09/12] Restore eslint config on having one describe This was actually a good rule in order to have file-level after() hook. --- .eslintrc.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index d18a89c7..6d35aae7 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -95,10 +95,7 @@ "no-warning-comments": "off", // broken - "sort-imports": "off", - - // Would require to needlessly split code into too many files. - "mocha/max-top-level-suites": "off" + "sort-imports": "off" }, "parser": "babel-eslint", "env": { From 0166636ccc134960a88383d6552ce099071bdaba Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 16 Dec 2021 11:02:42 -0400 Subject: [PATCH 10/12] Typings stuff --- utils/ECC/ECC.spec.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/utils/ECC/ECC.spec.js b/utils/ECC/ECC.spec.js index 7252e7c0..a6a7a71b 100644 --- a/utils/ECC/ECC.spec.js +++ b/utils/ECC/ECC.spec.js @@ -15,7 +15,10 @@ const { isAuthorizedDevice } = require('./ECC') -const uuid = () => words({ exactly: 24 }).join('-') +const uuid = () => { + const arr = /** @type {string[]} */ (words({ exactly: 24 })) + return arr.join('-') +} const storageDirectory = Path.resolve(__dirname, `./.test-storage`) From 5542d7b8dbe2b916f9cea06580170d54fd4af9ac Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 16 Dec 2021 11:07:03 -0400 Subject: [PATCH 11/12] Use top level describe() --- utils/ECC/ECC.spec.js | 160 ++++++++++++++++++++------------------- utils/ECC/crypto.spec.js | 40 +++++----- 2 files changed, 102 insertions(+), 98 deletions(-) diff --git a/utils/ECC/ECC.spec.js b/utils/ECC/ECC.spec.js index a6a7a71b..e088844a 100644 --- a/utils/ECC/ECC.spec.js +++ b/utils/ECC/ECC.spec.js @@ -24,96 +24,98 @@ const storageDirectory = Path.resolve(__dirname, `./.test-storage`) console.log(`Storage directory: ${storageDirectory}`) -describe('generateKeyPair()', () => { - it('generates a keypair', async () => { - expect.hasAssertions() - const pair = await generateKeyPair(uuid()) +describe('ECC', () => { + describe('generateKeyPair()', () => { + it('generates a keypair', async () => { + expect.hasAssertions() + const pair = await generateKeyPair(uuid()) - expect(pair.privateKey).toBeInstanceOf(Buffer) - expect(typeof pair.privateKeyBase64 === 'string').toBeTruthy() - expect(pair.publicKey).toBeInstanceOf(Buffer) - expect(typeof pair.publicKeyBase64 === 'string').toBeTruthy() - }) - it('returns the same pair for the same device', async () => { - expect.hasAssertions() - const id = uuid() - const pair = await generateKeyPair(id) - const pairAgain = await generateKeyPair(id) - - expect(pairAgain).toStrictEqual(pair) - }) -}) - -describe('authorizeDevice()/isAuthorizedDevice()', () => { - it('authorizes a device given its ID', async () => { - expect.hasAssertions() - await Storage.init({ - dir: storageDirectory + expect(pair.privateKey).toBeInstanceOf(Buffer) + expect(typeof pair.privateKeyBase64 === 'string').toBeTruthy() + expect(pair.publicKey).toBeInstanceOf(Buffer) + expect(typeof pair.publicKeyBase64 === 'string').toBeTruthy() }) - const deviceId = uuid() - const pair = await generateKeyPair(deviceId) - await authorizeDevice({ deviceId, publicKey: pair.publicKeyBase64 }) - expect(isAuthorizedDevice({ deviceId })).toBeTruthy() - }) -}) + it('returns the same pair for the same device', async () => { + expect.hasAssertions() + const id = uuid() + const pair = await generateKeyPair(id) + const pairAgain = await generateKeyPair(id) -describe('encryptMessage()/decryptMessage()', () => { - before(() => - Storage.init({ - dir: storageDirectory + expect(pairAgain).toStrictEqual(pair) }) - ) - it('throws if provided with an unauthorized device id when encrypting', async () => { - expect.hasAssertions() - const deviceId = uuid() + }) - try { - await encryptMessage({ - message: uuid(), - deviceId + describe('authorizeDevice()/isAuthorizedDevice()', () => { + it('authorizes a device given its ID', async () => { + expect.hasAssertions() + await Storage.init({ + dir: storageDirectory }) - throw new Error('encryptMessage() did not throw') - } catch (_) { - expect(true).toBeTruthy() - } + const deviceId = uuid() + const pair = await generateKeyPair(deviceId) + await authorizeDevice({ deviceId, publicKey: pair.publicKeyBase64 }) + expect(isAuthorizedDevice({ deviceId })).toBeTruthy() + }) }) - it('throws if provided with an unknown device id when decrypting', async () => { - expect.hasAssertions() - const deviceId = uuid() - try { - await decryptMessage({ + describe('encryptMessage()/decryptMessage()', () => { + before(() => + Storage.init({ + dir: storageDirectory + }) + ) + it('throws if provided with an unauthorized device id when encrypting', async () => { + expect.hasAssertions() + const deviceId = uuid() + + try { + await encryptMessage({ + message: uuid(), + deviceId + }) + throw new Error('encryptMessage() did not throw') + } catch (_) { + expect(true).toBeTruthy() + } + }) + it('throws if provided with an unknown device id when decrypting', async () => { + expect.hasAssertions() + const deviceId = uuid() + + try { + await decryptMessage({ + deviceId, + encryptedMessage: { + ciphertext: uuid(), + ephemPublicKey: uuid(), + iv: uuid(), + mac: uuid(), + metadata: uuid() + } + }) + throw new Error('decryptMessage() did not throw') + } catch (_) { + expect(true).toBeTruthy() + } + }) + it('encrypts and decrypts messages when given a known device id', async () => { + expect.hasAssertions() + const deviceId = uuid() + + const pair = await generateKeyPair(deviceId) + + await authorizeDevice({ deviceId, publicKey: pair.publicKeyBase64 }) + + const message = 'Bitcoin fixes this' + + const encryptedMessage = await encryptMessage({ deviceId, message }) + + const decrypted = await decryptMessage({ deviceId, - encryptedMessage: { - ciphertext: uuid(), - ephemPublicKey: uuid(), - iv: uuid(), - mac: uuid(), - metadata: uuid() - } + encryptedMessage }) - throw new Error('decryptMessage() did not throw') - } catch (_) { - expect(true).toBeTruthy() - } - }) - it('encrypts and decrypts messages when given a known device id', async () => { - expect.hasAssertions() - const deviceId = uuid() - const pair = await generateKeyPair(deviceId) - - await authorizeDevice({ deviceId, publicKey: pair.publicKeyBase64 }) - - const message = 'Bitcoin fixes this' - - const encryptedMessage = await encryptMessage({ deviceId, message }) - - const decrypted = await decryptMessage({ - deviceId, - encryptedMessage + expect(decrypted).toEqual(message) }) - - expect(decrypted).toEqual(message) }) }) diff --git a/utils/ECC/crypto.spec.js b/utils/ECC/crypto.spec.js index a848b65b..d367006d 100644 --- a/utils/ECC/crypto.spec.js +++ b/utils/ECC/crypto.spec.js @@ -10,25 +10,27 @@ const { convertBufferToBase64 } = require('./crypto') -describe('generateRandomString()', () => { - it('creates a random string of the specified length', async () => { - expect.hasAssertions() - const base = Math.ceil(Math.random() * 100) - const len = base % 2 !== 0 ? base + 1 : base - const result = await generateRandomString(len) +describe('crypto', () => { + describe('generateRandomString()', () => { + it('creates a random string of the specified length', async () => { + expect.hasAssertions() + const base = Math.ceil(Math.random() * 100) + const len = base % 2 !== 0 ? base + 1 : base + const result = await generateRandomString(len) - expect(result.length).toEqual(len) - }) -}) - -describe('Buffer <> String <> Buffer', () => { - it('preserves values', async () => { - const rnd = await generateRandomString(24) - - const asBuffer = convertBase64ToBuffer(rnd) - - const asStringAgain = convertBufferToBase64(asBuffer) - - expect(asStringAgain).toEqual(rnd) + expect(result.length).toEqual(len) + }) + }) + + describe('Buffer <> String <> Buffer', () => { + it('preserves values', async () => { + const rnd = await generateRandomString(24) + + const asBuffer = convertBase64ToBuffer(rnd) + + const asStringAgain = convertBufferToBase64(asBuffer) + + expect(asStringAgain).toEqual(rnd) + }) }) }) From 8e4d94817267ec2245c7601b8e5778ef67d87c28 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 16 Dec 2021 11:11:11 -0400 Subject: [PATCH 12/12] Kill crypto subprocess so tests actually finish running --- utils/ECC/ECC.js | 8 +++++++- utils/ECC/ECC.spec.js | 5 ++++- utils/ECC/crypto.js | 8 +++++++- utils/ECC/crypto.spec.js | 5 ++++- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/utils/ECC/ECC.js b/utils/ECC/ECC.js index 4e53a5b3..5420e93b 100644 --- a/utils/ECC/ECC.js +++ b/utils/ECC/ECC.js @@ -210,5 +210,11 @@ module.exports = { authorizeDevice, generateRandomString, nodeKeyPairs, - devicePublicKeys + devicePublicKeys, + /** + * Used for tests. + */ + killECCCryptoSubprocess() { + cryptoSubprocess.kill() + } } diff --git a/utils/ECC/ECC.spec.js b/utils/ECC/ECC.spec.js index e088844a..60a7e013 100644 --- a/utils/ECC/ECC.spec.js +++ b/utils/ECC/ECC.spec.js @@ -12,7 +12,8 @@ const { decryptMessage, encryptMessage, generateKeyPair, - isAuthorizedDevice + isAuthorizedDevice, + killECCCryptoSubprocess } = require('./ECC') const uuid = () => { @@ -118,4 +119,6 @@ describe('ECC', () => { expect(decrypted).toEqual(message) }) }) + + after(killECCCryptoSubprocess) }) diff --git a/utils/ECC/crypto.js b/utils/ECC/crypto.js index 7a4cb5c9..7f17e6f8 100644 --- a/utils/ECC/crypto.js +++ b/utils/ECC/crypto.js @@ -136,5 +136,11 @@ module.exports = { convertBufferToBase64, convertToEncryptedMessage, convertToEncryptedMessageResponse, - processKey + processKey, + /** + * Used for tests. + */ + killCryptoCryptoSubprocess() { + cryptoSubprocess.kill() + } } diff --git a/utils/ECC/crypto.spec.js b/utils/ECC/crypto.spec.js index d367006d..1b9c3175 100644 --- a/utils/ECC/crypto.spec.js +++ b/utils/ECC/crypto.spec.js @@ -7,7 +7,8 @@ const expect = require('expect') const { generateRandomString, convertBase64ToBuffer, - convertBufferToBase64 + convertBufferToBase64, + killCryptoCryptoSubprocess } = require('./crypto') describe('crypto', () => { @@ -33,4 +34,6 @@ describe('crypto', () => { expect(asStringAgain).toEqual(rnd) }) }) + + after(killCryptoCryptoSubprocess) })