From 1eb6c659f731e15cb9fad8d13bc17a3702b730fc Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 7 Oct 2020 10:06:14 -0400 Subject: [PATCH 1/6] export constant --- services/gunDB/Mediator/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index 009ef65f..e5daf500 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -1475,5 +1475,6 @@ module.exports = { getUser, mySEA, getMySecret, - freshGun + freshGun, + $$__SHOCKWALLET__ENCRYPTED__ } From b856b901f684d4cc15aec32c20793754da28d297 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 7 Oct 2020 14:09:23 -0400 Subject: [PATCH 2/6] socket typings --- services/gunDB/Mediator/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index e5daf500..cb1cc805 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -205,7 +205,7 @@ const Config = require('../config') // TO DO: move to common repo /** * @typedef {object} SimpleSocket - * @prop {(eventName: string, data: Emission|EncryptedEmission) => void} emit + * @prop {(eventName: string, data?: Emission|EncryptedEmission) => void} emit * @prop {(eventName: string, handler: (data: any) => void) => void} on * @prop {{ query: { 'x-shockwallet-device-id': string }}} handshake */ From 3072646c27786024ecf3ccfd3dd6e15f175abe34 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 7 Oct 2020 14:17:12 -0400 Subject: [PATCH 3/6] deepDecryptIfNeeded() --- services/gunDB/rpc.js | 48 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/services/gunDB/rpc.js b/services/gunDB/rpc.js index 66213000..3611789b 100644 --- a/services/gunDB/rpc.js +++ b/services/gunDB/rpc.js @@ -7,11 +7,53 @@ const mapValues = require('lodash/mapValues') const Bluebird = require('bluebird') const { pubToEpub } = require('./contact-api/utils') -const { getGun, getUser, mySEA: SEA, getMySecret } = require('./Mediator') +const { + getGun, + getUser, + mySEA: SEA, + getMySecret, + $$__SHOCKWALLET__ENCRYPTED__ +} = require('./Mediator') /** * @typedef {import('./contact-api/SimpleGUN').ValidDataValue} ValidDataValue */ +/** + * @param {ValidDataValue} value + * @param {string} publicKey + * @returns {Promise} + */ +const deepDecryptIfNeeded = async (value, publicKey) => { + if (Schema.isObj(value)) { + return Bluebird.props( + mapValues(value, o => deepDecryptIfNeeded(o, publicKey)) + ) + } + + if ( + typeof value === 'string' && + value.indexOf($$__SHOCKWALLET__ENCRYPTED__) === 0 + ) { + const user = getUser() + if (!user.is) { + throw new Error(Constants.ErrorCode.NOT_AUTH) + } + + let sec = '' + if (user.is.pub === publicKey) { + sec = getMySecret() + } else { + sec = await SEA.secret(publicKey, user._.sea) + } + + const decrypted = SEA.decrypt(value, sec) + + return decrypted + } + + return value +} + /** * @param {ValidDataValue} value * @returns {Promise} @@ -148,5 +190,7 @@ const set = async (rawPath, value) => { module.exports = { put, - set + set, + deepDecryptIfNeeded, + deepEncryptIfNeeded } From b8199660ca7d68285ea5427cf12f18598c5719ce Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 7 Oct 2020 14:18:00 -0400 Subject: [PATCH 4/6] chore --- src/sockets.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sockets.js b/src/sockets.js index 4feecfdc..787e176c 100644 --- a/src/sockets.js +++ b/src/sockets.js @@ -1,7 +1,10 @@ -/** @prettier */ +/** + * @format + */ // @ts-check const logger = require('winston') + const Encryption = require('../utils/encryptionStore') const LightningServices = require('../utils/lightningServices') const { From 9069ae092175c31df98d630f38eb873e90da8c54 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 7 Oct 2020 15:06:13 -0400 Subject: [PATCH 5/6] decryption for socket gun rpc --- src/sockets.js | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/sockets.js b/src/sockets.js index 787e176c..5a8b4890 100644 --- a/src/sockets.js +++ b/src/sockets.js @@ -12,7 +12,16 @@ const { getUser, isAuthenticated } = require('../services/gunDB/Mediator') +const { deepDecryptIfNeeded } = require('../services/gunDB/rpc') +/** + * @typedef {import('../services/gunDB/Mediator').SimpleSocket} SimpleSocket + * @typedef {import('../services/gunDB/contact-api/SimpleGUN').ValidDataValue} ValidDataValue + */ +/** + * @param {SimpleSocket} socket + * @param {string} subID + */ const onPing = (socket, subID) => { logger.warn('Subscribing to pings socket...' + subID) @@ -299,7 +308,7 @@ module.exports = ( return } - const { $shock } = socket.handshake.query + const { $shock, publicKeyForDecryption } = socket.handshake.query const [root, path, method] = $shock.split('::') @@ -319,12 +328,21 @@ module.exports = ( } /** - * @param {unknown} data + * @param {ValidDataValue} data * @param {string} key */ - const listener = (data, key) => { + const listener = async (data, key) => { try { - socket.emit('$shock', data, key) + if (publicKeyForDecryption) { + const decData = await deepDecryptIfNeeded( + data, + publicKeyForDecryption + ) + + socket.emit('$shock', decData, key) + } else { + socket.emit('$shock', data, key) + } } catch (err) { logger.error( `Error for gun rpc socket, query ${$shock} -> ${err.message}` From 1ab388b72ff1cd59f471f97ea997c43915a5768b Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 7 Oct 2020 15:06:36 -0400 Subject: [PATCH 6/6] decryption for gun http rpc --- src/routes.js | 55 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/src/routes.js b/src/routes.js index eb78f6da..70cf450a 100644 --- a/src/routes.js +++ b/src/routes.js @@ -2995,12 +2995,19 @@ module.exports = async ( * @prop {boolean} startFromUserGraph * @prop {string} path * @prop {string=} publicKey + * @prop {string=} publicKeyForDecryption */ /** * @param {HandleGunFetchParams} args0 * @returns {Promise} */ - const handleGunFetch = ({ type, startFromUserGraph, path, publicKey }) => { + const handleGunFetch = ({ + type, + startFromUserGraph, + path, + publicKey, + publicKeyForDecryption + }) => { const keys = path.split('.') const { tryAndWait } = require('../services/gunDB/contact-api/utils') console.log(keys) @@ -3014,76 +3021,106 @@ module.exports = async ( keys.forEach(key => (node = node.get(key))) return new Promise(res => { - if (type === 'once') node.once(data => res(data)) - if (type === 'load') node.load(data => res(data)) + const listener = async data => { + if (publicKeyForDecryption) { + res( + await GunWriteRPC.deepDecryptIfNeeded( + data, + publicKeyForDecryption + ) + ) + } else { + res(data) + } + } + + if (type === 'once') node.once(listener) + if (type === 'load') node.load(listener) }) }) } + /** + * Used decryption of incoming data. + */ + const PUBKEY_FOR_DECRYPT_HEADER = 'public-key-for-decryption' + ap.get('/api/gun/once/:path', async (req, res) => { + const publicKeyForDecryption = req.header(PUBKEY_FOR_DECRYPT_HEADER) const { path } = req.params res.status(200).json({ data: await handleGunFetch({ path, startFromUserGraph: false, - type: 'once' + type: 'once', + publicKeyForDecryption }) }) }) ap.get('/api/gun/load/:path', async (req, res) => { + const publicKeyForDecryption = req.header(PUBKEY_FOR_DECRYPT_HEADER) const { path } = req.params res.status(200).json({ data: await handleGunFetch({ path, startFromUserGraph: false, - type: 'load' + type: 'load', + publicKeyForDecryption }) }) }) ap.get('/api/gun/user/once/:path', async (req, res) => { + const publicKeyForDecryption = req.header(PUBKEY_FOR_DECRYPT_HEADER) const { path } = req.params res.status(200).json({ data: await handleGunFetch({ path, startFromUserGraph: true, - type: 'once' + type: 'once', + publicKeyForDecryption }) }) }) ap.get('/api/gun/user/load/:path', async (req, res) => { + const publicKeyForDecryption = req.header(PUBKEY_FOR_DECRYPT_HEADER) const { path } = req.params res.status(200).json({ data: await handleGunFetch({ path, startFromUserGraph: true, - type: 'load' + type: 'load', + publicKeyForDecryption }) }) }) ap.get('/api/gun/otheruser/:publicKey/once/:path', async (req, res) => { + const publicKeyForDecryption = req.header(PUBKEY_FOR_DECRYPT_HEADER) const { path, publicKey } = req.params res.status(200).json({ data: await handleGunFetch({ path, startFromUserGraph: false, type: 'once', - publicKey + publicKey, + publicKeyForDecryption }) }) }) ap.get('/api/gun/otheruser/:publicKey/load/:path', async (req, res) => { + const publicKeyForDecryption = req.header(PUBKEY_FOR_DECRYPT_HEADER) const { path, publicKey } = req.params res.status(200).json({ data: await handleGunFetch({ path, startFromUserGraph: false, type: 'load', - publicKey + publicKey, + publicKeyForDecryption }) }) })