Encrypted LND Sockets

This commit is contained in:
emad-salah 2020-05-27 00:26:02 +00:00
parent 643443434d
commit 9dc028d8fb

View file

@ -1,67 +1,169 @@
/** @prettier */
// app/sockets.js // app/sockets.js
const logger = require("winston"); const logger = require('winston')
const LightningServices = require("../utils/lightningServices"); const Encryption = require('../utils/encryptionStore')
const LightningServices = require('../utils/lightningServices')
module.exports = ( module.exports = (
/** @type {import('socket.io').Server} */ /** @type {import('socket.io').Server} */
io io
) => { ) => {
const Mediator = require("../services/gunDB/Mediator/index.js"); const Mediator = require('../services/gunDB/Mediator/index.js')
// This should be used for encrypting and emitting your data
const emitEncryptedEvent = ({ eventName, data, socket }) => {
try {
if (Encryption.isNonEncrypted(eventName)) {
return socket.emit(eventName, data)
}
const deviceId = socket.handshake.query['x-shockwallet-device-id']
const authorized = Encryption.isAuthorizedDevice({ deviceId })
if (!deviceId) {
throw {
field: 'deviceId',
message: 'Please specify a device ID'
}
}
if (!authorized) {
throw {
field: 'deviceId',
message: 'Please exchange keys with the API before using the socket'
}
}
const encryptedMessage = Encryption.encryptMessage({
message: data,
deviceId
})
return socket.emit(eventName, encryptedMessage)
} catch (err) {
logger.error(
`[SOCKET] An error has occurred while encrypting an event (${eventName}):`,
err
)
return socket.emit('encryption:error', err)
}
}
const parseJSON = data => {
try {
if (typeof data === 'string') {
return JSON.parse(data)
}
return data
} catch (err) {
return data
}
}
const decryptEvent = ({ eventName, data, socket }) => {
try {
const deviceId = socket.handshake.query['x-shockwallet-device-id']
if (Encryption.isNonEncrypted(eventName)) {
return data
}
if (!data) {
return data
}
const parsedData = parseJSON(data)
if (!deviceId) {
throw {
field: 'deviceId',
message: 'Please specify a device ID'
}
}
if (!Encryption.isAuthorizedDevice({ deviceId })) {
throw {
field: 'deviceId',
message: 'Please exchange keys with the API before using the socket'
}
}
const decryptedKey = Encryption.decryptKey({
deviceId,
message: parsedData.encryptedKey
})
const decryptedMessage = Encryption.decryptMessage({
message: parsedData.encryptedData,
key: decryptedKey,
iv: parsedData.iv
})
const decryptedData = JSON.parse(decryptedMessage)
return decryptedData
} catch (err) {
logger.error(
`[SOCKET] An error has occurred while decrypting an event (${eventName}):`,
err
)
return socket.emit('encryption:error', err)
}
}
const onNewInvoice = socket => { const onNewInvoice = socket => {
const { lightning } = LightningServices.services; const { lightning } = LightningServices.services
logger.warn("Subscribing to invoices socket...") logger.warn('Subscribing to invoices socket...')
const stream = lightning.subscribeInvoices({}); const stream = lightning.subscribeInvoices({})
stream.on("data", data => { stream.on('data', data => {
logger.info("[SOCKET] New invoice data:", data); logger.info('[SOCKET] New invoice data:', data)
socket.emit("invoice:new", data) emitEncryptedEvent({ eventName: 'invoice:new', data, socket })
}) })
stream.on("end", () => { stream.on('end', () => {
logger.info("New invoice stream ended, starting a new one...") logger.info('New invoice stream ended, starting a new one...')
onNewInvoice(socket); onNewInvoice(socket)
}) })
stream.on("error", err => { stream.on('error', err => {
logger.error("New invoice stream error:", err); logger.error('New invoice stream error:', err)
}) })
stream.on("status", status => { stream.on('status', status => {
logger.error("New invoice stream status:", status); logger.warn('New invoice stream status:', status)
if (status.code === 14) { if (status.code === 14) {
onNewInvoice(socket); onNewInvoice(socket)
} }
}) })
} }
const onNewTransaction = socket => { const onNewTransaction = socket => {
const { lightning } = LightningServices.services; const { lightning } = LightningServices.services
const stream = lightning.subscribeTransactions({}); const stream = lightning.subscribeTransactions({})
logger.warn("Subscribing to transactions socket...") logger.warn('Subscribing to transactions socket...')
stream.on("data", data => { stream.on('data', data => {
logger.info("[SOCKET] New transaction data:", data); logger.info('[SOCKET] New transaction data:', data)
socket.emit("transaction:new", data) emitEncryptedEvent({ eventName: 'transaction:new', data, socket })
}) })
stream.on("end", () => { stream.on('end', () => {
logger.info("New invoice stream ended, starting a new one...") logger.info('New invoice stream ended, starting a new one...')
onNewTransaction(socket); onNewTransaction(socket)
}) })
stream.on("error", err => { stream.on('error', err => {
logger.error("New invoice stream error:", err); logger.error('New invoice stream error:', err)
}) })
stream.on("status", status => { stream.on('status', status => {
logger.error("New invoice stream status:", status); logger.error('New invoice stream status:', status)
if (status.code === 14) { if (status.code === 14) {
onNewTransaction(socket); onNewTransaction(socket)
} }
}) })
} }
io.on("connection", socket => { io.on('connection', socket => {
logger.info(`io.onconnection`) logger.info(`io.onconnection`)
logger.info("socket.handshake", socket.handshake); logger.info('socket.handshake', socket.handshake)
/** printing out the client who joined */ /** printing out the client who joined */
logger.info("New socket client connected (id=" + socket.id + ")."); logger.info('New socket client connected (id=' + socket.id + ').')
const isOneTimeUseSocket = !!socket.handshake.query.IS_GUN_AUTH const isOneTimeUseSocket = !!socket.handshake.query.IS_GUN_AUTH
const isLNDSocket = !!socket.handshake.query.IS_LND_SOCKET const isLNDSocket = !!socket.handshake.query.IS_LND_SOCKET
@ -92,18 +194,18 @@ module.exports = (
logger.info('New socket is NOT one time use') logger.info('New socket is NOT one time use')
// this is where we create the websocket connection // this is where we create the websocket connection
// with the GunDB service. // with the GunDB service.
Mediator.createMediator(socket); Mediator.createMediator(socket)
if (isLNDSocket) { if (isLNDSocket) {
onNewInvoice(socket); onNewInvoice(socket)
onNewTransaction(socket); onNewTransaction(socket)
} }
/** listening if client has disconnected */ /** listening if client has disconnected */
socket.on("disconnect", () => { socket.on('disconnect', () => {
logger.info("client disconnected (id=" + socket.id + ")."); logger.info('client disconnected (id=' + socket.id + ').')
}); })
} }
}) })
return io; return io
}; }