Merge pull request #22 from shocknet/feature/end-to-end-encryption

Feature/end to end encryption
This commit is contained in:
Daniel Lugo 2020-01-30 16:42:05 -04:00 committed by GitHub
commit 2b043f5943
7 changed files with 551 additions and 192 deletions

View file

@ -2,5 +2,5 @@
"requirePragma": true, "requirePragma": true,
"semi": false, "semi": false,
"singleQuote": true, "singleQuote": true,
"endOfLine": "lf" "endOfLine": "auto"
} }

View file

@ -4,6 +4,7 @@
const Gun = require('gun') const Gun = require('gun')
const debounce = require('lodash/debounce') const debounce = require('lodash/debounce')
const once = require('lodash/once') const once = require('lodash/once')
const Encryption = require('../../../utils/encryptionStore')
/** @type {import('../contact-api/SimpleGUN').ISEA} */ /** @type {import('../contact-api/SimpleGUN').ISEA} */
// @ts-ignore // @ts-ignore
@ -96,6 +97,7 @@ const Action = require('../action-constants.js')
const API = require('../contact-api/index') const API = require('../contact-api/index')
const Config = require('../config') const Config = require('../config')
const Event = require('../event-constants') const Event = require('../event-constants')
// const { nonEncryptedRoutes } = require('../../../utils/protectedRoutes')
/** /**
* @typedef {import('../contact-api/SimpleGUN').GUNNode} GUNNode * @typedef {import('../contact-api/SimpleGUN').GUNNode} GUNNode
@ -281,37 +283,116 @@ class Mediator {
* @param {Readonly<SimpleSocket>} socket * @param {Readonly<SimpleSocket>} socket
*/ */
constructor(socket) { constructor(socket) {
this.socket = socket this.socket = this.encryptSocketInstance(socket)
this.connected = true this.connected = true
socket.on('disconnect', this.onDisconnect) this.socket.on('disconnect', this.onDisconnect)
socket.on(Action.ACCEPT_REQUEST, this.acceptRequest) this.socket.on(Action.ACCEPT_REQUEST, this.acceptRequest)
socket.on(Action.BLACKLIST, this.blacklist) this.socket.on(Action.BLACKLIST, this.blacklist)
socket.on(Action.GENERATE_NEW_HANDSHAKE_NODE, this.generateHandshakeNode) this.socket.on(
socket.on(Action.SEND_HANDSHAKE_REQUEST, this.sendHandshakeRequest) Action.GENERATE_NEW_HANDSHAKE_NODE,
socket.on( this.generateHandshakeNode
)
this.socket.on(Action.SEND_HANDSHAKE_REQUEST, this.sendHandshakeRequest)
this.socket.on(
Action.SEND_HANDSHAKE_REQUEST_WITH_INITIAL_MSG, Action.SEND_HANDSHAKE_REQUEST_WITH_INITIAL_MSG,
this.sendHRWithInitialMsg this.sendHRWithInitialMsg
) )
socket.on(Action.SEND_MESSAGE, this.sendMessage) this.socket.on(Action.SEND_MESSAGE, this.sendMessage)
socket.on(Action.SEND_PAYMENT, this.sendPayment) this.socket.on(Action.SET_AVATAR, this.setAvatar)
socket.on(Action.SET_AVATAR, this.setAvatar) this.socket.on(Action.SET_DISPLAY_NAME, this.setDisplayName)
socket.on(Action.SET_DISPLAY_NAME, this.setDisplayName) this.socket.on(Action.SEND_PAYMENT, this.sendPayment)
socket.on(Action.SET_BIO, this.setBio) this.socket.on(Action.SET_BIO, this.setBio)
socket.on(Event.ON_AVATAR, this.onAvatar) this.socket.on(Event.ON_AVATAR, this.onAvatar)
socket.on(Event.ON_BLACKLIST, this.onBlacklist) this.socket.on(Event.ON_BLACKLIST, this.onBlacklist)
socket.on(Event.ON_CHATS, this.onChats) this.socket.on(Event.ON_CHATS, this.onChats)
socket.on(Event.ON_DISPLAY_NAME, this.onDisplayName) this.socket.on(Event.ON_DISPLAY_NAME, this.onDisplayName)
socket.on(Event.ON_HANDSHAKE_ADDRESS, this.onHandshakeAddress) this.socket.on(Event.ON_HANDSHAKE_ADDRESS, this.onHandshakeAddress)
socket.on(Event.ON_RECEIVED_REQUESTS, this.onReceivedRequests) this.socket.on(Event.ON_RECEIVED_REQUESTS, this.onReceivedRequests)
socket.on(Event.ON_SENT_REQUESTS, this.onSentRequests) this.socket.on(Event.ON_SENT_REQUESTS, this.onSentRequests)
socket.on(Event.ON_BIO, this.onBio) this.socket.on(Event.ON_BIO, this.onBio)
socket.on(Event.ON_SEED_BACKUP, this.onSeedBackup) this.socket.on(Event.ON_SEED_BACKUP, this.onSeedBackup)
socket.on(IS_GUN_AUTH, this.isGunAuth) this.socket.on(IS_GUN_AUTH, this.isGunAuth)
}
encryptSocketInstance = socket => {
return {
on: (eventName, cb) => {
const deviceId = socket.handshake.query['x-shockwallet-device-id']
socket.on(eventName, data => {
try {
// if (nonEncryptedEvents.includes(eventName)) {
// return cb(data)
// }
if (!data) {
return cb(data)
}
if (!deviceId) {
const error = {
field: 'deviceId',
message: 'Please specify a device ID'
}
console.error(error)
return false
}
if (!Encryption.isAuthorizedDevice({ deviceId })) {
const error = {
field: 'deviceId',
message: 'Please specify a device ID'
}
console.error('Unknown Device', error)
return false
}
if(typeof data === 'string'){
data = JSON.parse(data)
}
console.log('Event:', eventName)
console.log('Data:', data)
console.log('Decrypt params:', {
deviceId,
message: data.encryptedKey
})
const decryptedKey = Encryption.decryptKey({
deviceId,
message: data.encryptedKey
})
const decryptedMessage = Encryption.decryptMessage({
message: data.encryptedData,
key: decryptedKey,
iv: data.iv
})
const decryptedData = JSON.parse(decryptedMessage)
return cb(decryptedData)
} catch (err) {
console.error(err)
return false
}
})
},
emit: (eventName, data) => {
try {
const deviceId = socket.handshake.query['x-shockwallet-device-id']
const authorized = Encryption.isAuthorizedDevice({ deviceId })
const encryptedMessage = authorized
? Encryption.encryptMessage({
message: data,
deviceId
})
: data
console.log('Sending Message...', eventName, data, encryptedMessage)
socket.emit(eventName, encryptedMessage)
} catch (err) {
console.error(err)
}
}
}
} }
isGunAuth = () => { isGunAuth = () => {
@ -725,6 +806,8 @@ class Mediator {
try { try {
const { token } = body const { token } = body
console.log('ON_CHATS', body)
await throwOnInvalidToken(token) await throwOnInvalidToken(token)
API.Events.onChats( API.Events.onChats(

View file

@ -5,27 +5,37 @@
*/ */
"use strict"; "use strict";
const Http = require("axios"); const Axios = require("axios");
const Crypto = require("crypto"); const Crypto = require("crypto");
const logger = require("winston"); const logger = require("winston");
const httpsAgent = require("https");
const responseTime = require("response-time"); const responseTime = require("response-time");
const uuid = require("uuid/v4");
const getListPage = require("../utils/paginate"); const getListPage = require("../utils/paginate");
const auth = require("../services/auth/auth"); const auth = require("../services/auth/auth");
const FS = require("../utils/fs"); const FS = require("../utils/fs");
const Encryption = require("../utils/encryptionStore");
const LightningServices = require("../utils/lightningServices"); const LightningServices = require("../utils/lightningServices");
const GunDB = require("../services/gunDB/Mediator"); const GunDB = require("../services/gunDB/Mediator");
const { unprotectedRoutes, nonEncryptedRoutes } = require("../utils/protectedRoutes");
const GunActions = require("../services/gunDB/contact-api/actions") const GunActions = require("../services/gunDB/contact-api/actions")
const { unprotectedRoutes } = require("../utils/protectedRoutes");
const DEFAULT_MAX_NUM_ROUTES_TO_QUERY = 10; const DEFAULT_MAX_NUM_ROUTES_TO_QUERY = 10;
const SESSION_ID = uuid();
// module.exports = (app) => { // module.exports = (app) => {
module.exports = ( module.exports = async (
app, app,
config, config,
mySocketsEvents, mySocketsEvents,
{ serverPort } { serverPort, CA, CA_KEY, usetls }
) => { ) => {
const Http = Axios.create({
httpsAgent: new httpsAgent.Agent({
ca: await FS.readFile(CA)
})
})
const sanitizeLNDError = (message = "") => const sanitizeLNDError = (message = "") =>
message.toLowerCase().includes("unknown") message.toLowerCase().includes("unknown")
? message ? message
@ -82,7 +92,7 @@ module.exports = (
const serviceStatus = await getAvailableService(); const serviceStatus = await getAvailableService();
const LNDStatus = serviceStatus; const LNDStatus = serviceStatus;
try { try {
const APIHealth = await Http.get(`http://localhost:${serverPort}/ping`); const APIHealth = await Http.get(`${usetls ? 'https' : 'http'}://localhost:${serverPort}/ping`);
const APIStatus = { const APIStatus = {
message: APIHealth.data, message: APIHealth.data,
responseTime: APIHealth.headers["x-response-time"], responseTime: APIHealth.headers["x-response-time"],
@ -93,6 +103,7 @@ module.exports = (
APIStatus APIStatus
}; };
} catch (err) { } catch (err) {
console.error(err);
const APIStatus = { const APIStatus = {
message: err.response.data, message: err.response.data,
responseTime: err.response.headers["x-response-time"], responseTime: err.response.headers["x-response-time"],
@ -109,7 +120,7 @@ module.exports = (
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
if (err) { if (err) {
res.send({ res.json({
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
@ -117,7 +128,7 @@ module.exports = (
} }
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
}; };
@ -185,6 +196,58 @@ module.exports = (
} }
}; };
app.use((req, res, next) => {
res.setHeader("x-session-id", SESSION_ID)
next()
})
app.use((req, res, next) => {
const deviceId = req.headers["x-shockwallet-device-id"];
try {
if (nonEncryptedRoutes.includes(req.path)) {
return next();
}
if (!deviceId) {
const error = {
field: "deviceId",
message: "Please specify a device ID"
};
console.error(error)
return res.status(401).json(error);
}
if (!Encryption.isAuthorizedDevice({ deviceId })) {
const error = {
field: "deviceId",
message: "Please specify a device ID"
};
console.error("Unknown Device", error)
return res.status(401).json(error);
}
if (req.method === "GET") {
console.log("Method:", req.method);
return next();
}
console.log("Body:", req.body)
console.log("Decrypt params:", { deviceId, message: req.body.encryptionKey })
const decryptedKey = Encryption.decryptKey({ deviceId, message: req.body.encryptionKey });
console.log("decryptedKey", decryptedKey)
const decryptedMessage = Encryption.decryptMessage({ message: req.body.data, key: decryptedKey, iv: req.body.iv })
req.body = JSON.parse(decryptedMessage);
return next();
} catch (err) {
console.error(err);
return res
.status(401)
.json(
err
);
}
})
app.use(async (req, res, next) => { app.use(async (req, res, next) => {
try { try {
console.log("Route:", req.path) console.log("Route:", req.path)
@ -240,7 +303,7 @@ module.exports = (
*/ */
app.get("/health", async (req, res) => { app.get("/health", async (req, res) => {
const health = await checkHealth(); const health = await checkHealth();
res.send(health); res.json(health);
}); });
/** /**
@ -248,11 +311,11 @@ module.exports = (
*/ */
app.get("/healthz", async (req, res) => { app.get("/healthz", async (req, res) => {
const health = await checkHealth(); const health = await checkHealth();
res.send(health); res.json(health);
}); });
app.get("/ping", (req, res) => { app.get("/ping", (req, res) => {
res.send("OK"); res.json({ message: "OK" });
}); });
app.post("/api/mobile/error", (req, res) => { app.post("/api/mobile/error", (req, res) => {
@ -260,6 +323,38 @@ module.exports = (
res.json({ msg: "OK" }); res.json({ msg: "OK" });
}); });
app.post("/api/security/exchangeKeys", async (req, res) => {
try {
const { publicKey, deviceId } = req.body;
if (!publicKey || publicKey.length < 600) {
return res.status(400).json({
field: 'publicKey',
message: "Please provide a valid public key"
})
}
if (!deviceId ||
!/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/iu
.test(deviceId)) {
return res.status(400).json({
field: 'deviceId',
message: "Please provide a valid device ID"
})
}
const authorizedDevice = await Encryption.authorizeDevice({ deviceId, publicKey })
console.log(authorizedDevice)
return res.status(200).json(authorizedDevice)
} catch (err) {
console.error(err)
return res.status(401).json({
field: 'unknown',
message: err
})
}
})
app.get("/api/lnd/wallet/status", async (req, res) => { app.get("/api/lnd/wallet/status", async (req, res) => {
try { try {
const walletStatus = await walletExists(); const walletStatus = await walletExists();
@ -281,6 +376,7 @@ module.exports = (
app.post("/api/lnd/auth", async (req, res) => { app.post("/api/lnd/auth", async (req, res) => {
try { try {
console.log("/api/lnd/auth Body:", req.body)
const health = await checkHealth(); const health = await checkHealth();
const walletInitialized = await walletExists(); const walletInitialized = await walletExists();
// If we're connected to lnd, unlock the wallet using the password supplied // If we're connected to lnd, unlock the wallet using the password supplied
@ -326,7 +422,7 @@ module.exports = (
} }
res.status(500); res.status(500);
res.send({ res.json({
field: "health", field: "health",
errorMessage: sanitizeLNDError(health.LNDStatus.message), errorMessage: sanitizeLNDError(health.LNDStatus.message),
success: false success: false
@ -335,7 +431,7 @@ module.exports = (
} catch (err) { } catch (err) {
logger.debug("Unlock Error:", err); logger.debug("Unlock Error:", err);
res.status(400); res.status(400);
res.send({ field: "user", errorMessage: sanitizeLNDError(err.message), success: false }); res.json({ field: "user", errorMessage: sanitizeLNDError(err.message), success: false });
return err; return err;
} }
}); });
@ -357,10 +453,10 @@ module.exports = (
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400); res.status(400);
res.send({ field: "WalletUnlocker", errorMessage: unlockErr.message }); res.json({ field: "WalletUnlocker", errorMessage: unlockErr.message });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} else { } else {
await recreateLnServices(); await recreateLnServices();
@ -424,12 +520,12 @@ module.exports = (
const message = genSeedErr.details; const message = genSeedErr.details;
return res return res
.status(400) .status(400)
.send({ field: "GenSeed", errorMessage: message, success: false }); .json({ field: "GenSeed", errorMessage: message, success: false });
} }
return res return res
.status(500) .status(500)
.send({ field: "health", errorMessage: "LND is down", success: false }); .json({ field: "health", errorMessage: "LND is down", success: false });
} }
logger.debug("GenSeed:", genSeedResponse); logger.debug("GenSeed:", genSeedResponse);
@ -608,13 +704,13 @@ module.exports = (
logger.error("GetInfo Error:", err); logger.error("GetInfo Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ res.status(400).json({
field: "getInfo", field: "getInfo",
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
logger.info("GetInfo:", response); logger.info("GetInfo:", response);
@ -639,13 +735,13 @@ module.exports = (
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400); res.status(400);
res.send({ res.json({
field: "getNodeInfo", field: "getNodeInfo",
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
logger.debug("GetNodeInfo:", response); logger.debug("GetNodeInfo:", response);
@ -661,13 +757,13 @@ module.exports = (
logger.debug("GetNetworkInfo Error:", err); logger.debug("GetNetworkInfo Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ res.status(400).json({
field: "getNodeInfo", field: "getNodeInfo",
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
logger.debug("GetNetworkInfo:", response); logger.debug("GetNetworkInfo:", response);
@ -683,13 +779,13 @@ module.exports = (
logger.debug("ListPeers Error:", err); logger.debug("ListPeers Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ res.status(400).json({
field: "listPeers", field: "listPeers",
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
logger.debug("ListPeers:", response); logger.debug("ListPeers:", response);
@ -705,13 +801,13 @@ module.exports = (
logger.debug("NewAddress Error:", err); logger.debug("NewAddress Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ res.status(400).json({
field: "newAddress", field: "newAddress",
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
logger.debug("NewAddress:", response); logger.debug("NewAddress:", response);
@ -726,13 +822,13 @@ module.exports = (
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(403); res.status(403);
return res.send({ return res.json({
field: "limituser", field: "limituser",
errorMessage: "User limited" errorMessage: "User limited"
}); });
} }
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
const connectRequest = { const connectRequest = {
addr: { pubkey: req.body.pubkey, host: req.body.host }, addr: { pubkey: req.body.pubkey, host: req.body.host },
@ -742,7 +838,7 @@ module.exports = (
lightning.connectPeer(connectRequest, (err, response) => { lightning.connectPeer(connectRequest, (err, response) => {
if (err) { if (err) {
logger.debug("ConnectPeer Error:", err); logger.debug("ConnectPeer Error:", err);
res.status(500).send({ field: "connectPeer", errorMessage: sanitizeLNDError(err.message) }); res.status(500).json({ field: "connectPeer", errorMessage: sanitizeLNDError(err.message) });
} else { } else {
logger.debug("ConnectPeer:", response); logger.debug("ConnectPeer:", response);
res.json(response); res.json(response);
@ -757,20 +853,20 @@ module.exports = (
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(403); res.status(403);
return res.send({ return res.json({
field: "limituser", field: "limituser",
errorMessage: "User limited" errorMessage: "User limited"
}); });
} }
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
const disconnectRequest = { pub_key: req.body.pubkey }; const disconnectRequest = { pub_key: req.body.pubkey };
logger.debug("DisconnectPeer Request:", disconnectRequest); logger.debug("DisconnectPeer Request:", disconnectRequest);
lightning.disconnectPeer(disconnectRequest, (err, response) => { lightning.disconnectPeer(disconnectRequest, (err, response) => {
if (err) { if (err) {
logger.debug("DisconnectPeer Error:", err); logger.debug("DisconnectPeer Error:", err);
res.status(400).send({ field: "disconnectPeer", errorMessage: sanitizeLNDError(err.message) }); res.status(400).json({ field: "disconnectPeer", errorMessage: sanitizeLNDError(err.message) });
} else { } else {
logger.debug("DisconnectPeer:", response); logger.debug("DisconnectPeer:", response);
res.json(response); res.json(response);
@ -786,13 +882,13 @@ module.exports = (
logger.debug("ListChannels Error:", err); logger.debug("ListChannels Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ res.status(400).json({
field: "listChannels", field: "listChannels",
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
logger.debug("ListChannels:", response); logger.debug("ListChannels:", response);
@ -808,13 +904,13 @@ module.exports = (
logger.debug("PendingChannels Error:", err); logger.debug("PendingChannels Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ res.status(400).json({
field: "pendingChannels", field: "pendingChannels",
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
logger.debug("PendingChannels:", response); logger.debug("PendingChannels:", response);
@ -901,10 +997,10 @@ module.exports = (
logger.debug("ListInvoices Error:", err); logger.debug("ListInvoices Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ errorMessage: sanitizeLNDError(err.message), success: false }); res.status(400).json({ errorMessage: sanitizeLNDError(err.message), success: false });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: health.LNDStatus.message, success: false }); res.json({ errorMessage: health.LNDStatus.message, success: false });
} }
} else { } else {
// logger.debug("ListInvoices:", response); // logger.debug("ListInvoices:", response);
@ -927,13 +1023,13 @@ module.exports = (
logger.debug("ForwardingHistory Error:", err); logger.debug("ForwardingHistory Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ res.status(400).json({
field: "forwardingHistory", field: "forwardingHistory",
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
logger.debug("ForwardingHistory:", response); logger.debug("ForwardingHistory:", response);
@ -949,13 +1045,13 @@ module.exports = (
logger.debug("WalletBalance Error:", err); logger.debug("WalletBalance Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ res.status(400).json({
field: "walletBalance", field: "walletBalance",
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
logger.debug("WalletBalance:", response); logger.debug("WalletBalance:", response);
@ -971,13 +1067,13 @@ module.exports = (
if (err) { if (err) {
logger.debug("WalletBalance Error:", err); logger.debug("WalletBalance Error:", err);
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ res.status(400).json({
field: "walletBalance", field: "walletBalance",
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500); res.status(500);
res.send(health.LNDStatus); res.json(health.LNDStatus);
} }
return err; return err;
} }
@ -986,13 +1082,13 @@ module.exports = (
if (err) { if (err) {
logger.debug("ChannelBalance Error:", err); logger.debug("ChannelBalance Error:", err);
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ res.status(400).json({
field: "channelBalance", field: "channelBalance",
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500); res.status(500);
res.send(health.LNDStatus); res.json(health.LNDStatus);
} }
return err; return err;
} }
@ -1015,11 +1111,11 @@ module.exports = (
logger.debug("DecodePayReq Error:", err); logger.debug("DecodePayReq Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(500).send({ res.status(500).json({
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500).send({ errorMessage: "LND is down" }); res.status(500).json({ errorMessage: "LND is down" });
} }
} else { } else {
logger.info("DecodePayReq:", paymentRequest); logger.info("DecodePayReq:", paymentRequest);
@ -1037,13 +1133,13 @@ module.exports = (
logger.debug("ChannelBalance Error:", err); logger.debug("ChannelBalance Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ res.status(400).json({
field: "channelBalance", field: "channelBalance",
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
logger.debug("ChannelBalance:", response); logger.debug("ChannelBalance:", response);
@ -1060,7 +1156,7 @@ module.exports = (
res.sendStatus(403); res.sendStatus(403);
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
return; return;
} }
@ -1084,10 +1180,10 @@ module.exports = (
logger.info("OpenChannelRequest Error:", err); logger.info("OpenChannelRequest Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success && !res.headersSent) { if (health.LNDStatus.success && !res.headersSent) {
res.status(500).send({ field: "openChannelRequest", errorMessage: sanitizeLNDError(err.message) }); res.status(500).json({ field: "openChannelRequest", errorMessage: sanitizeLNDError(err.message) });
} else if (!res.headersSent) { } else if (!res.headersSent) {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
}); });
openedChannel.write(openChannelRequest) openedChannel.write(openChannelRequest)
@ -1103,7 +1199,7 @@ module.exports = (
res.sendStatus(403); res.sendStatus(403);
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
const { channelPoint, outputIndex } = req.body; const { channelPoint, outputIndex } = req.body;
@ -1131,13 +1227,13 @@ module.exports = (
if (!res.headersSent) { if (!res.headersSent) {
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
logger.debug("CloseChannelRequest Error:", err); logger.debug("CloseChannelRequest Error:", err);
res.status(400).send({ res.status(400).json({
field: "closeChannel", field: "closeChannel",
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
}); });
@ -1152,7 +1248,7 @@ module.exports = (
res.sendStatus(403); res.sendStatus(403);
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
const paymentRequest = { payment_request: req.body.payreq }; const paymentRequest = { payment_request: req.body.payreq };
@ -1184,12 +1280,12 @@ module.exports = (
logger.error("SendPayment Error:", err); logger.error("SendPayment Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(500).send({ res.status(500).json({
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
}); });
@ -1205,7 +1301,7 @@ module.exports = (
res.sendStatus(403); res.sendStatus(403);
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
return false; return false;
} }
@ -1221,13 +1317,13 @@ module.exports = (
logger.debug("AddInvoice Error:", err); logger.debug("AddInvoice Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ res.status(400).json({
field: "addInvoice", field: "addInvoice",
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
return err; return err;
} }
@ -1245,7 +1341,7 @@ module.exports = (
res.sendStatus(403); res.sendStatus(403);
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
lightning.signMessage( lightning.signMessage(
@ -1255,10 +1351,10 @@ module.exports = (
logger.debug("SignMessage Error:", err); logger.debug("SignMessage Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ field: "signMessage", errorMessage: sanitizeLNDError(err.message) }); res.status(400).json({ field: "signMessage", errorMessage: sanitizeLNDError(err.message) });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
logger.debug("SignMessage:", response); logger.debug("SignMessage:", response);
@ -1277,10 +1373,10 @@ module.exports = (
logger.debug("VerifyMessage Error:", err); logger.debug("VerifyMessage Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ field: "verifyMessage", errorMessage: sanitizeLNDError(err.message) }); res.status(400).json({ field: "verifyMessage", errorMessage: sanitizeLNDError(err.message) });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
logger.debug("VerifyMessage:", response); logger.debug("VerifyMessage:", response);
@ -1298,7 +1394,7 @@ module.exports = (
res.sendStatus(403); res.sendStatus(403);
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
const sendCoinsRequest = { addr: req.body.addr, amount: req.body.amount }; const sendCoinsRequest = { addr: req.body.addr, amount: req.body.amount };
@ -1308,13 +1404,13 @@ module.exports = (
logger.debug("SendCoins Error:", err); logger.debug("SendCoins Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ res.status(400).json({
field: "sendCoins", field: "sendCoins",
errorMessage: sanitizeLNDError(err.message) errorMessage: sanitizeLNDError(err.message)
}); });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
logger.debug("SendCoins:", response); logger.debug("SendCoins:", response);
@ -1334,10 +1430,10 @@ module.exports = (
logger.debug("QueryRoute Error:", err); logger.debug("QueryRoute Error:", err);
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ field: "queryRoute", errorMessage: sanitizeLNDError(err.message) }); res.status(400).json({ field: "queryRoute", errorMessage: sanitizeLNDError(err.message) });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} }
logger.debug("QueryRoute:", response); logger.debug("QueryRoute:", response);
@ -1360,12 +1456,12 @@ module.exports = (
if (err) { if (err) {
const health = await checkHealth(); const health = await checkHealth();
if (health.LNDStatus.success) { if (health.LNDStatus.success) {
res.status(400).send({ res.status(400).json({
error: err.message error: err.message
}); });
} else { } else {
res.status(500); res.status(500);
res.send({ errorMessage: "LND is down" }); res.json({ errorMessage: "LND is down" });
} }
} else { } else {
logger.debug("EstimateFee:", fee); logger.debug("EstimateFee:", fee);

View file

@ -1,78 +1,119 @@
"use strict"; /**
* @prettier
*/
/** /**
* Module dependencies. * Module dependencies.
*/ */
const server = program => { const server = program => {
const Https = require("https"); const Https = require('https')
const Http = require("http"); const Http = require('http')
const Express = require("express"); const Express = require('express')
const LightningServices = require("../utils/lightningServices"); const LightningServices = require('../utils/lightningServices')
const app = Express(); const Encryption = require('../utils/encryptionStore')
const app = Express()
const FS = require("../utils/fs");
const bodyParser = require("body-parser"); const FS = require('../utils/fs')
const session = require("express-session"); const bodyParser = require('body-parser')
const methodOverride = require("method-override"); const session = require('express-session')
const { unprotectedRoutes, sensitiveRoutes } = require("../utils/protectedRoutes"); const methodOverride = require('method-override')
const {
unprotectedRoutes,
sensitiveRoutes,
nonEncryptedRoutes
} = require('../utils/protectedRoutes')
// load app default configuration data // load app default configuration data
const defaults = require("../config/defaults")(program.mainnet); const defaults = require('../config/defaults')(program.mainnet)
// define useful global variables ====================================== // define useful global variables ======================================
module.useTLS = program.usetls; module.useTLS = program.usetls
module.serverPort = program.serverport || defaults.serverPort; module.serverPort = program.serverport || defaults.serverPort
module.httpsPort = module.serverPort; module.httpsPort = module.serverPort
module.serverHost = program.serverhost || defaults.serverHost; module.serverHost = program.serverhost || defaults.serverHost
// setup winston logging ========== // setup winston logging ==========
const logger = require("../config/log")( const logger = require('../config/log')(
program.logfile || defaults.logfile, program.logfile || defaults.logfile,
program.loglevel || defaults.loglevel program.loglevel || defaults.loglevel
); )
// utilities functions ================= // utilities functions =================
require("../utils/server-utils")(module); require('../utils/server-utils')(module)
logger.info("Mainnet Mode:", !!program.mainnet); logger.info('Mainnet Mode:', !!program.mainnet)
const modifyResponseBody = (req, res, next) => {
const deviceId = req.headers['x-shockwallet-device-id']
const oldSend = res.send
if (!nonEncryptedRoutes.includes(req.path)) {
res.send = (...args) => {
if (args[0] && args[0].encryptedData && args[0].encryptionKey) {
console.log('Response loop detected', req.path, args[0])
oldSend.apply(res, args)
} else {
// arguments[0] (or `data`) contains the response body
const authorized = Encryption.isAuthorizedDevice({ deviceId })
const encryptedMessage = authorized
? Encryption.encryptMessage({
message: args[0],
deviceId
})
: args[0]
args[0] = JSON.stringify(encryptedMessage)
oldSend.apply(res, args)
}
}
}
next()
}
const wait = seconds => const wait = seconds =>
new Promise(resolve => { new Promise(resolve => {
const timer = setTimeout(() => resolve(timer), seconds * 1000); const timer = setTimeout(() => resolve(timer), seconds * 1000)
}); })
// eslint-disable-next-line consistent-return // eslint-disable-next-line consistent-return
const startServer = async () => { const startServer = async () => {
try { try {
LightningServices.setDefaults(program); LightningServices.setDefaults(program)
await LightningServices.init(); await LightningServices.init()
// init lnd module ================= // init lnd module =================
const lnd = require("../services/lnd/lnd")(LightningServices.services.lightning); const lnd = require('../services/lnd/lnd')(
const auth = require("../services/auth/auth"); LightningServices.services.lightning
)
const auth = require('../services/auth/auth')
app.use(async (req, res, next) => { app.use(async (req, res, next) => {
console.log("Route:", req.path) console.log('Route:', req.path)
if (unprotectedRoutes[req.method][req.path]) { if (unprotectedRoutes[req.method][req.path]) {
next(); next()
} else { } else {
try { try {
const response = await auth.validateToken( const response = await auth.validateToken(
req.headers.authorization.replace("Bearer ", "") req.headers.authorization.replace('Bearer ', '')
); )
if (response.valid) { if (response.valid) {
next(); next()
} else { } else {
res.status(401).json({ field: "authorization", errorMessage: "The authorization token you've supplied is invalid" }); res.status(401).json({
field: 'authorization',
errorMessage:
"The authorization token you've supplied is invalid"
})
} }
} catch (err) { } catch (err) {
logger.error( logger.error(
!req.headers.authorization !req.headers.authorization
? "Please add an Authorization header" ? 'Please add an Authorization header'
: err : err
); )
res.status(401).json({ field: "authorization", errorMessage: "Please log in" }); res
.status(401)
.json({ field: 'authorization', errorMessage: 'Please log in' })
} }
} }
}); })
app.use((req, res, next) => { app.use((req, res, next) => {
if (sensitiveRoutes[req.method][req.path]) { if (sensitiveRoutes[req.method][req.path]) {
@ -84,7 +125,7 @@ const server = program => {
path: req.path, path: req.path,
sessionId: req.sessionId sessionId: req.sessionId
}) })
); )
} else { } else {
console.log( console.log(
JSON.stringify({ JSON.stringify({
@ -96,10 +137,10 @@ const server = program => {
query: req.query, query: req.query,
sessionId: req.sessionId sessionId: req.sessionId
}) })
); )
} }
next(); next()
}); })
app.use( app.use(
session({ session({
secret: defaults.sessionSecret, secret: defaults.sessionSecret,
@ -108,79 +149,84 @@ const server = program => {
rolling: true, rolling: true,
saveUninitialized: true saveUninitialized: true
}) })
); )
app.use(bodyParser.urlencoded({ extended: "true" })); app.use(bodyParser.urlencoded({ extended: 'true' }))
app.use(bodyParser.json()); app.use(bodyParser.json())
app.use(bodyParser.json({ type: "application/vnd.api+json" })); app.use(bodyParser.json({ type: 'application/vnd.api+json' }))
app.use(methodOverride()); app.use(methodOverride())
// WARNING // WARNING
// error handler middleware, KEEP 4 parameters as express detects the // error handler middleware, KEEP 4 parameters as express detects the
// arity of the function to treat it as a err handling middleware // arity of the function to treat it as a err handling middleware
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
app.use((err, _, res, __) => { app.use((err, _, res, __) => {
// Do logging and user-friendly error message display // Do logging and user-friendly error message display
logger.error(err); logger.error(err)
res res.status(500).send({ status: 500, errorMessage: 'internal error' })
.status(500) })
.send({ status: 500, errorMessage: "internal error" });
}); const CA = LightningServices.servicesConfig.lndCertPath
const CA_KEY = CA.replace('cert', 'key')
const createServer = async () => { const createServer = async () => {
try { try {
if (program.usetls) { if (LightningServices.servicesConfig.lndCertPath && program.usetls) {
const [key, cert] = await Promise.all([ const [key, cert] = await Promise.all([
FS.readFile(program.usetls + "/key.pem"), FS.readFile(CA_KEY),
FS.readFile(program.usetls + "/cert.pem") FS.readFile(CA)
]); ])
const httpsServer = Https.createServer({ key, cert }, app); const httpsServer = Https.createServer({ key, cert }, app)
return httpsServer; return httpsServer
} }
const httpServer = Http.Server(app); const httpServer = Http.Server(app)
return httpServer; return httpServer
} catch (err) { } catch (err) {
logger.error(err.message); logger.error(err.message)
throw err; logger.error(
'An error has occurred while finding an LND cert to use to open an HTTPS server'
)
logger.warn('Falling back to opening an HTTP server...')
const httpServer = Http.Server(app)
return httpServer
} }
}; }
const serverInstance = await createServer(); const serverInstance = await createServer()
const io = require("socket.io")(serverInstance); const io = require('socket.io')(serverInstance)
const Sockets = require("./sockets")( const Sockets = require('./sockets')(
io, io,
lnd, lnd,
program.user, program.user,
program.pwd, program.pwd,
program.limituser, program.limituser,
program.limitpwd program.limitpwd
); )
require("./routes")( require('./routes')(app, defaults, Sockets, {
app, serverHost: module.serverHost,
defaults, serverPort: module.serverPort,
Sockets, usetls: program.usetls,
{ CA,
serverHost: module.serverHost, CA_KEY
serverPort: module.serverPort })
}
);
// enable CORS headers // enable CORS headers
app.use(require("./cors")); app.use(require('./cors'))
// app.use(bodyParser.json({limit: '100000mb'})); // app.use(bodyParser.json({limit: '100000mb'}));
app.use(bodyParser.json({ limit: "50mb" })); app.use(bodyParser.json({ limit: '50mb' }))
app.use(bodyParser.urlencoded({ limit: "50mb", extended: true })); app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }))
app.use(modifyResponseBody)
serverInstance.listen(module.serverPort, module.serverhost); serverInstance.listen(module.serverPort, module.serverhost)
logger.info( logger.info(
"App listening on " + module.serverHost + " port " + module.serverPort 'App listening on ' + module.serverHost + ' port ' + module.serverPort
); )
module.server = serverInstance; module.server = serverInstance
// const localtunnel = require('localtunnel'); // const localtunnel = require('localtunnel');
// //
@ -189,15 +235,15 @@ const server = program => {
// console.log('t', t.url); // console.log('t', t.url);
// }); // });
} catch (err) { } catch (err) {
logger.info(err); logger.info(err)
logger.info("Restarting server in 30 seconds..."); logger.info('Restarting server in 30 seconds...')
await wait(30); await wait(30)
startServer(); startServer()
return false; return false
} }
}; }
startServer(); startServer()
}; }
module.exports = server; module.exports = server

125
utils/encryptionStore.js Normal file
View file

@ -0,0 +1,125 @@
/**
* @prettier
*/
const Crypto = require('crypto')
const { Buffer } = require('buffer')
const APIKeyPair = new Map()
const authorizedDevices = new Map()
const Encryption = {
encryptKey: ({ deviceId, message }) => {
if (!authorizedDevices.has(deviceId)) {
throw { field: 'deviceId', message: 'Unknown Device ID' }
}
const devicePublicKey = authorizedDevices.get(deviceId)
const data = Buffer.from(message)
const encryptedData = Crypto.publicEncrypt(
{
key: devicePublicKey,
padding: Crypto.constants.RSA_PKCS1_PADDING
},
data
)
return encryptedData.toString('base64')
},
decryptKey: ({ deviceId, message }) => {
if (!authorizedDevices.has(deviceId)) {
throw { field: 'deviceId', message: 'Unknown Device ID' }
}
const data = Buffer.from(message, 'base64')
const encryptedData = Crypto.privateDecrypt(
{
key: APIKeyPair.get(deviceId).privateKey,
padding: Crypto.constants.RSA_PKCS1_PADDING
},
data
)
console.log('Decrypted Data:', encryptedData)
return encryptedData.toString()
},
encryptMessage: ({ deviceId, message }) => {
const parsedMessage =
typeof message === 'object' ? JSON.stringify(message) : message
const data = Buffer.from(parsedMessage)
const key = Crypto.randomBytes(32)
const iv = Crypto.randomBytes(16)
const encryptedKey = Encryption.encryptKey({
deviceId,
message: key.toString('hex')
})
const cipher = Crypto.createCipheriv('aes-256-cbc', key, iv)
const encryptedCipher = cipher.update(data)
const encryptedBuffer = Buffer.concat([
Buffer.from(encryptedCipher),
Buffer.from(cipher.final())
])
const encryptedData = encryptedBuffer.toString('base64')
return { encryptedData, encryptedKey, iv: iv.toString('hex') }
},
decryptMessage: ({ message, key, iv }) => {
const data = Buffer.from(message, 'base64')
const cipher = Crypto.createDecipheriv(
'aes-256-cbc',
Buffer.from(key, 'hex'),
Buffer.from(iv, 'hex')
)
const decryptedCipher = cipher.update(data)
const decryptedBuffer = Buffer.concat([
Buffer.from(decryptedCipher),
Buffer.from(cipher.final())
])
const decryptedData = decryptedBuffer.toString()
console.log('Decrypted Data:', decryptedData)
return decryptedData.toString()
},
isAuthorizedDevice: ({ deviceId }) => {
if (authorizedDevices.has(deviceId)) {
return true
}
return false
},
authorizeDevice: ({ deviceId, publicKey }) =>
new Promise((resolve, reject) => {
authorizedDevices.set(deviceId, publicKey)
Crypto.generateKeyPair(
'rsa',
{
modulusLength: 4096,
privateKeyEncoding: {
type: 'pkcs1',
format: 'pem'
},
publicKeyEncoding: {
type: 'pkcs1',
format: 'pem'
}
},
(err, publicKey, privateKey) => {
if (err) {
console.error(err)
reject(err)
return err
}
const exportedKey = {
publicKey,
privateKey
}
APIKeyPair.set(deviceId, exportedKey)
resolve({
success: true,
APIPublicKey: exportedKey.publicKey
})
}
)
}),
unAuthorizeDevice: ({ deviceId }) => {
authorizedDevices.delete(deviceId)
}
}
module.exports = Encryption

View file

@ -13,7 +13,8 @@ module.exports = {
"/api/lnd/connect": true, "/api/lnd/connect": true,
"/api/lnd/wallet": true, "/api/lnd/wallet": true,
"/api/lnd/wallet/existing": true, "/api/lnd/wallet/existing": true,
"/api/lnd/auth": true "/api/lnd/auth": true,
"/api/security/exchangeKeys": true
}, },
PUT: {}, PUT: {},
DELETE: {} DELETE: {}
@ -26,5 +27,6 @@ module.exports = {
}, },
PUT: {}, PUT: {},
DELETE: {} DELETE: {}
} },
nonEncryptedRoutes: ['/api/security/exchangeKeys', '/healthz', '/ping', '/api/lnd/wallet/status']
} }

View file

@ -873,7 +873,7 @@ ascli@~1:
colour "~0.7.1" colour "~0.7.1"
optjs "~3.2.2" optjs "~3.2.2"
asn1@~0.2.3: asn1@^0.2.4, asn1@~0.2.3:
version "0.2.4" version "0.2.4"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
@ -4341,6 +4341,13 @@ node-pre-gyp@^0.13.0:
semver "^5.3.0" semver "^5.3.0"
tar "^4" tar "^4"
node-rsa@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/node-rsa/-/node-rsa-1.0.7.tgz#85b7a6d6fa8ee624be6402a6b41be49272d58055"
integrity sha512-idwRXma6scFufZmbaKkHpJoLL93yynRefP6yur13wZ5i9FR35ex451KCoF2OORDeJanyRVahmjjiwmUlCnTqJA==
dependencies:
asn1 "^0.2.4"
nodemon@^1.19.3: nodemon@^1.19.3:
version "1.19.3" version "1.19.3"
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.19.3.tgz#db71b3e62aef2a8e1283a9fa00164237356102c0" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.19.3.tgz#db71b3e62aef2a8e1283a9fa00164237356102c0"