commit
2d1688ba3d
4 changed files with 121 additions and 18 deletions
|
|
@ -205,7 +205,7 @@ const Config = require('../config')
|
||||||
// TO DO: move to common repo
|
// TO DO: move to common repo
|
||||||
/**
|
/**
|
||||||
* @typedef {object} SimpleSocket
|
* @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 {(eventName: string, handler: (data: any) => void) => void} on
|
||||||
* @prop {{ query: { 'x-shockwallet-device-id': string }}} handshake
|
* @prop {{ query: { 'x-shockwallet-device-id': string }}} handshake
|
||||||
*/
|
*/
|
||||||
|
|
@ -1475,5 +1475,6 @@ module.exports = {
|
||||||
getUser,
|
getUser,
|
||||||
mySEA,
|
mySEA,
|
||||||
getMySecret,
|
getMySecret,
|
||||||
freshGun
|
freshGun,
|
||||||
|
$$__SHOCKWALLET__ENCRYPTED__
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,53 @@ const mapValues = require('lodash/mapValues')
|
||||||
const Bluebird = require('bluebird')
|
const Bluebird = require('bluebird')
|
||||||
|
|
||||||
const { pubToEpub } = require('./contact-api/utils')
|
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
|
* @typedef {import('./contact-api/SimpleGUN').ValidDataValue} ValidDataValue
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ValidDataValue} value
|
||||||
|
* @param {string} publicKey
|
||||||
|
* @returns {Promise<ValidDataValue>}
|
||||||
|
*/
|
||||||
|
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
|
* @param {ValidDataValue} value
|
||||||
* @returns {Promise<ValidDataValue>}
|
* @returns {Promise<ValidDataValue>}
|
||||||
|
|
@ -148,5 +190,7 @@ const set = async (rawPath, value) => {
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
put,
|
put,
|
||||||
set
|
set,
|
||||||
|
deepDecryptIfNeeded,
|
||||||
|
deepEncryptIfNeeded
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2995,12 +2995,19 @@ module.exports = async (
|
||||||
* @prop {boolean} startFromUserGraph
|
* @prop {boolean} startFromUserGraph
|
||||||
* @prop {string} path
|
* @prop {string} path
|
||||||
* @prop {string=} publicKey
|
* @prop {string=} publicKey
|
||||||
|
* @prop {string=} publicKeyForDecryption
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* @param {HandleGunFetchParams} args0
|
* @param {HandleGunFetchParams} args0
|
||||||
* @returns {Promise<unknown>}
|
* @returns {Promise<unknown>}
|
||||||
*/
|
*/
|
||||||
const handleGunFetch = ({ type, startFromUserGraph, path, publicKey }) => {
|
const handleGunFetch = ({
|
||||||
|
type,
|
||||||
|
startFromUserGraph,
|
||||||
|
path,
|
||||||
|
publicKey,
|
||||||
|
publicKeyForDecryption
|
||||||
|
}) => {
|
||||||
const keys = path.split('.')
|
const keys = path.split('.')
|
||||||
const { tryAndWait } = require('../services/gunDB/contact-api/utils')
|
const { tryAndWait } = require('../services/gunDB/contact-api/utils')
|
||||||
console.log(keys)
|
console.log(keys)
|
||||||
|
|
@ -3014,76 +3021,106 @@ module.exports = async (
|
||||||
keys.forEach(key => (node = node.get(key)))
|
keys.forEach(key => (node = node.get(key)))
|
||||||
|
|
||||||
return new Promise(res => {
|
return new Promise(res => {
|
||||||
if (type === 'once') node.once(data => res(data))
|
const listener = async data => {
|
||||||
if (type === 'load') node.load(data => res(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) => {
|
ap.get('/api/gun/once/:path', async (req, res) => {
|
||||||
|
const publicKeyForDecryption = req.header(PUBKEY_FOR_DECRYPT_HEADER)
|
||||||
const { path } = req.params
|
const { path } = req.params
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
data: await handleGunFetch({
|
data: await handleGunFetch({
|
||||||
path,
|
path,
|
||||||
startFromUserGraph: false,
|
startFromUserGraph: false,
|
||||||
type: 'once'
|
type: 'once',
|
||||||
|
publicKeyForDecryption
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
ap.get('/api/gun/load/:path', async (req, res) => {
|
ap.get('/api/gun/load/:path', async (req, res) => {
|
||||||
|
const publicKeyForDecryption = req.header(PUBKEY_FOR_DECRYPT_HEADER)
|
||||||
const { path } = req.params
|
const { path } = req.params
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
data: await handleGunFetch({
|
data: await handleGunFetch({
|
||||||
path,
|
path,
|
||||||
startFromUserGraph: false,
|
startFromUserGraph: false,
|
||||||
type: 'load'
|
type: 'load',
|
||||||
|
publicKeyForDecryption
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
ap.get('/api/gun/user/once/:path', async (req, res) => {
|
ap.get('/api/gun/user/once/:path', async (req, res) => {
|
||||||
|
const publicKeyForDecryption = req.header(PUBKEY_FOR_DECRYPT_HEADER)
|
||||||
const { path } = req.params
|
const { path } = req.params
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
data: await handleGunFetch({
|
data: await handleGunFetch({
|
||||||
path,
|
path,
|
||||||
startFromUserGraph: true,
|
startFromUserGraph: true,
|
||||||
type: 'once'
|
type: 'once',
|
||||||
|
publicKeyForDecryption
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
ap.get('/api/gun/user/load/:path', async (req, res) => {
|
ap.get('/api/gun/user/load/:path', async (req, res) => {
|
||||||
|
const publicKeyForDecryption = req.header(PUBKEY_FOR_DECRYPT_HEADER)
|
||||||
const { path } = req.params
|
const { path } = req.params
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
data: await handleGunFetch({
|
data: await handleGunFetch({
|
||||||
path,
|
path,
|
||||||
startFromUserGraph: true,
|
startFromUserGraph: true,
|
||||||
type: 'load'
|
type: 'load',
|
||||||
|
publicKeyForDecryption
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
ap.get('/api/gun/otheruser/:publicKey/once/:path', async (req, res) => {
|
ap.get('/api/gun/otheruser/:publicKey/once/:path', async (req, res) => {
|
||||||
|
const publicKeyForDecryption = req.header(PUBKEY_FOR_DECRYPT_HEADER)
|
||||||
const { path, publicKey } = req.params
|
const { path, publicKey } = req.params
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
data: await handleGunFetch({
|
data: await handleGunFetch({
|
||||||
path,
|
path,
|
||||||
startFromUserGraph: false,
|
startFromUserGraph: false,
|
||||||
type: 'once',
|
type: 'once',
|
||||||
publicKey
|
publicKey,
|
||||||
|
publicKeyForDecryption
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
ap.get('/api/gun/otheruser/:publicKey/load/:path', async (req, res) => {
|
ap.get('/api/gun/otheruser/:publicKey/load/:path', async (req, res) => {
|
||||||
|
const publicKeyForDecryption = req.header(PUBKEY_FOR_DECRYPT_HEADER)
|
||||||
const { path, publicKey } = req.params
|
const { path, publicKey } = req.params
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
data: await handleGunFetch({
|
data: await handleGunFetch({
|
||||||
path,
|
path,
|
||||||
startFromUserGraph: false,
|
startFromUserGraph: false,
|
||||||
type: 'load',
|
type: 'load',
|
||||||
publicKey
|
publicKey,
|
||||||
|
publicKeyForDecryption
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
/** @prettier */
|
/**
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
const logger = require('winston')
|
const logger = require('winston')
|
||||||
|
|
||||||
const Encryption = require('../utils/encryptionStore')
|
const Encryption = require('../utils/encryptionStore')
|
||||||
const LightningServices = require('../utils/lightningServices')
|
const LightningServices = require('../utils/lightningServices')
|
||||||
const {
|
const {
|
||||||
|
|
@ -9,7 +12,16 @@ const {
|
||||||
getUser,
|
getUser,
|
||||||
isAuthenticated
|
isAuthenticated
|
||||||
} = require('../services/gunDB/Mediator')
|
} = 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) => {
|
const onPing = (socket, subID) => {
|
||||||
logger.warn('Subscribing to pings socket...' + subID)
|
logger.warn('Subscribing to pings socket...' + subID)
|
||||||
|
|
||||||
|
|
@ -296,7 +308,7 @@ module.exports = (
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const { $shock } = socket.handshake.query
|
const { $shock, publicKeyForDecryption } = socket.handshake.query
|
||||||
|
|
||||||
const [root, path, method] = $shock.split('::')
|
const [root, path, method] = $shock.split('::')
|
||||||
|
|
||||||
|
|
@ -316,12 +328,21 @@ module.exports = (
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {unknown} data
|
* @param {ValidDataValue} data
|
||||||
* @param {string} key
|
* @param {string} key
|
||||||
*/
|
*/
|
||||||
const listener = (data, key) => {
|
const listener = async (data, key) => {
|
||||||
try {
|
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) {
|
} catch (err) {
|
||||||
logger.error(
|
logger.error(
|
||||||
`Error for gun rpc socket, query ${$shock} -> ${err.message}`
|
`Error for gun rpc socket, query ${$shock} -> ${err.message}`
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue