Merge pull request #22 from shocknet/feature/end-to-end-encryption
Feature/end to end encryption
This commit is contained in:
commit
2b043f5943
7 changed files with 551 additions and 192 deletions
|
|
@ -2,5 +2,5 @@
|
|||
"requirePragma": true,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"endOfLine": "lf"
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
const Gun = require('gun')
|
||||
const debounce = require('lodash/debounce')
|
||||
const once = require('lodash/once')
|
||||
const Encryption = require('../../../utils/encryptionStore')
|
||||
|
||||
/** @type {import('../contact-api/SimpleGUN').ISEA} */
|
||||
// @ts-ignore
|
||||
|
|
@ -96,6 +97,7 @@ const Action = require('../action-constants.js')
|
|||
const API = require('../contact-api/index')
|
||||
const Config = require('../config')
|
||||
const Event = require('../event-constants')
|
||||
// const { nonEncryptedRoutes } = require('../../../utils/protectedRoutes')
|
||||
|
||||
/**
|
||||
* @typedef {import('../contact-api/SimpleGUN').GUNNode} GUNNode
|
||||
|
|
@ -281,37 +283,116 @@ class Mediator {
|
|||
* @param {Readonly<SimpleSocket>} socket
|
||||
*/
|
||||
constructor(socket) {
|
||||
this.socket = socket
|
||||
this.socket = this.encryptSocketInstance(socket)
|
||||
|
||||
this.connected = true
|
||||
|
||||
socket.on('disconnect', this.onDisconnect)
|
||||
this.socket.on('disconnect', this.onDisconnect)
|
||||
|
||||
socket.on(Action.ACCEPT_REQUEST, this.acceptRequest)
|
||||
socket.on(Action.BLACKLIST, this.blacklist)
|
||||
socket.on(Action.GENERATE_NEW_HANDSHAKE_NODE, this.generateHandshakeNode)
|
||||
socket.on(Action.SEND_HANDSHAKE_REQUEST, this.sendHandshakeRequest)
|
||||
socket.on(
|
||||
this.socket.on(Action.ACCEPT_REQUEST, this.acceptRequest)
|
||||
this.socket.on(Action.BLACKLIST, this.blacklist)
|
||||
this.socket.on(
|
||||
Action.GENERATE_NEW_HANDSHAKE_NODE,
|
||||
this.generateHandshakeNode
|
||||
)
|
||||
this.socket.on(Action.SEND_HANDSHAKE_REQUEST, this.sendHandshakeRequest)
|
||||
this.socket.on(
|
||||
Action.SEND_HANDSHAKE_REQUEST_WITH_INITIAL_MSG,
|
||||
this.sendHRWithInitialMsg
|
||||
)
|
||||
socket.on(Action.SEND_MESSAGE, this.sendMessage)
|
||||
socket.on(Action.SEND_PAYMENT, this.sendPayment)
|
||||
socket.on(Action.SET_AVATAR, this.setAvatar)
|
||||
socket.on(Action.SET_DISPLAY_NAME, this.setDisplayName)
|
||||
socket.on(Action.SET_BIO, this.setBio)
|
||||
this.socket.on(Action.SEND_MESSAGE, this.sendMessage)
|
||||
this.socket.on(Action.SET_AVATAR, this.setAvatar)
|
||||
this.socket.on(Action.SET_DISPLAY_NAME, this.setDisplayName)
|
||||
this.socket.on(Action.SEND_PAYMENT, this.sendPayment)
|
||||
this.socket.on(Action.SET_BIO, this.setBio)
|
||||
|
||||
socket.on(Event.ON_AVATAR, this.onAvatar)
|
||||
socket.on(Event.ON_BLACKLIST, this.onBlacklist)
|
||||
socket.on(Event.ON_CHATS, this.onChats)
|
||||
socket.on(Event.ON_DISPLAY_NAME, this.onDisplayName)
|
||||
socket.on(Event.ON_HANDSHAKE_ADDRESS, this.onHandshakeAddress)
|
||||
socket.on(Event.ON_RECEIVED_REQUESTS, this.onReceivedRequests)
|
||||
socket.on(Event.ON_SENT_REQUESTS, this.onSentRequests)
|
||||
socket.on(Event.ON_BIO, this.onBio)
|
||||
socket.on(Event.ON_SEED_BACKUP, this.onSeedBackup)
|
||||
this.socket.on(Event.ON_AVATAR, this.onAvatar)
|
||||
this.socket.on(Event.ON_BLACKLIST, this.onBlacklist)
|
||||
this.socket.on(Event.ON_CHATS, this.onChats)
|
||||
this.socket.on(Event.ON_DISPLAY_NAME, this.onDisplayName)
|
||||
this.socket.on(Event.ON_HANDSHAKE_ADDRESS, this.onHandshakeAddress)
|
||||
this.socket.on(Event.ON_RECEIVED_REQUESTS, this.onReceivedRequests)
|
||||
this.socket.on(Event.ON_SENT_REQUESTS, this.onSentRequests)
|
||||
this.socket.on(Event.ON_BIO, this.onBio)
|
||||
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 = () => {
|
||||
|
|
@ -725,6 +806,8 @@ class Mediator {
|
|||
try {
|
||||
const { token } = body
|
||||
|
||||
console.log('ON_CHATS', body)
|
||||
|
||||
await throwOnInvalidToken(token)
|
||||
|
||||
API.Events.onChats(
|
||||
|
|
|
|||
244
src/routes.js
244
src/routes.js
|
|
@ -5,27 +5,37 @@
|
|||
*/
|
||||
"use strict";
|
||||
|
||||
const Http = require("axios");
|
||||
const Axios = require("axios");
|
||||
const Crypto = require("crypto");
|
||||
const logger = require("winston");
|
||||
const httpsAgent = require("https");
|
||||
const responseTime = require("response-time");
|
||||
const uuid = require("uuid/v4");
|
||||
const getListPage = require("../utils/paginate");
|
||||
const auth = require("../services/auth/auth");
|
||||
const FS = require("../utils/fs");
|
||||
const Encryption = require("../utils/encryptionStore");
|
||||
const LightningServices = require("../utils/lightningServices");
|
||||
const GunDB = require("../services/gunDB/Mediator");
|
||||
const { unprotectedRoutes, nonEncryptedRoutes } = require("../utils/protectedRoutes");
|
||||
const GunActions = require("../services/gunDB/contact-api/actions")
|
||||
const { unprotectedRoutes } = require("../utils/protectedRoutes");
|
||||
|
||||
const DEFAULT_MAX_NUM_ROUTES_TO_QUERY = 10;
|
||||
const SESSION_ID = uuid();
|
||||
|
||||
// module.exports = (app) => {
|
||||
module.exports = (
|
||||
module.exports = async (
|
||||
app,
|
||||
config,
|
||||
mySocketsEvents,
|
||||
{ serverPort }
|
||||
{ serverPort, CA, CA_KEY, usetls }
|
||||
) => {
|
||||
const Http = Axios.create({
|
||||
httpsAgent: new httpsAgent.Agent({
|
||||
ca: await FS.readFile(CA)
|
||||
})
|
||||
})
|
||||
|
||||
const sanitizeLNDError = (message = "") =>
|
||||
message.toLowerCase().includes("unknown")
|
||||
? message
|
||||
|
|
@ -82,7 +92,7 @@ module.exports = (
|
|||
const serviceStatus = await getAvailableService();
|
||||
const LNDStatus = serviceStatus;
|
||||
try {
|
||||
const APIHealth = await Http.get(`http://localhost:${serverPort}/ping`);
|
||||
const APIHealth = await Http.get(`${usetls ? 'https' : 'http'}://localhost:${serverPort}/ping`);
|
||||
const APIStatus = {
|
||||
message: APIHealth.data,
|
||||
responseTime: APIHealth.headers["x-response-time"],
|
||||
|
|
@ -93,6 +103,7 @@ module.exports = (
|
|||
APIStatus
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
const APIStatus = {
|
||||
message: err.response.data,
|
||||
responseTime: err.response.headers["x-response-time"],
|
||||
|
|
@ -109,7 +120,7 @@ module.exports = (
|
|||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
if (err) {
|
||||
res.send({
|
||||
res.json({
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
|
|
@ -117,7 +128,7 @@ module.exports = (
|
|||
}
|
||||
} else {
|
||||
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) => {
|
||||
try {
|
||||
console.log("Route:", req.path)
|
||||
|
|
@ -240,7 +303,7 @@ module.exports = (
|
|||
*/
|
||||
app.get("/health", async (req, res) => {
|
||||
const health = await checkHealth();
|
||||
res.send(health);
|
||||
res.json(health);
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -248,11 +311,11 @@ module.exports = (
|
|||
*/
|
||||
app.get("/healthz", async (req, res) => {
|
||||
const health = await checkHealth();
|
||||
res.send(health);
|
||||
res.json(health);
|
||||
});
|
||||
|
||||
app.get("/ping", (req, res) => {
|
||||
res.send("OK");
|
||||
res.json({ message: "OK" });
|
||||
});
|
||||
|
||||
app.post("/api/mobile/error", (req, res) => {
|
||||
|
|
@ -260,6 +323,38 @@ module.exports = (
|
|||
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) => {
|
||||
try {
|
||||
const walletStatus = await walletExists();
|
||||
|
|
@ -281,6 +376,7 @@ module.exports = (
|
|||
|
||||
app.post("/api/lnd/auth", async (req, res) => {
|
||||
try {
|
||||
console.log("/api/lnd/auth Body:", req.body)
|
||||
const health = await checkHealth();
|
||||
const walletInitialized = await walletExists();
|
||||
// If we're connected to lnd, unlock the wallet using the password supplied
|
||||
|
|
@ -326,7 +422,7 @@ module.exports = (
|
|||
}
|
||||
|
||||
res.status(500);
|
||||
res.send({
|
||||
res.json({
|
||||
field: "health",
|
||||
errorMessage: sanitizeLNDError(health.LNDStatus.message),
|
||||
success: false
|
||||
|
|
@ -335,7 +431,7 @@ module.exports = (
|
|||
} catch (err) {
|
||||
logger.debug("Unlock Error:", err);
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
|
@ -357,10 +453,10 @@ module.exports = (
|
|||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400);
|
||||
res.send({ field: "WalletUnlocker", errorMessage: unlockErr.message });
|
||||
res.json({ field: "WalletUnlocker", errorMessage: unlockErr.message });
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
} else {
|
||||
await recreateLnServices();
|
||||
|
|
@ -424,12 +520,12 @@ module.exports = (
|
|||
const message = genSeedErr.details;
|
||||
return res
|
||||
.status(400)
|
||||
.send({ field: "GenSeed", errorMessage: message, success: false });
|
||||
.json({ field: "GenSeed", errorMessage: message, success: false });
|
||||
}
|
||||
|
||||
return res
|
||||
.status(500)
|
||||
.send({ field: "health", errorMessage: "LND is down", success: false });
|
||||
.json({ field: "health", errorMessage: "LND is down", success: false });
|
||||
}
|
||||
|
||||
logger.debug("GenSeed:", genSeedResponse);
|
||||
|
|
@ -608,13 +704,13 @@ module.exports = (
|
|||
logger.error("GetInfo Error:", err);
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).send({
|
||||
res.status(400).json({
|
||||
field: "getInfo",
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
logger.info("GetInfo:", response);
|
||||
|
|
@ -639,13 +735,13 @@ module.exports = (
|
|||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400);
|
||||
res.send({
|
||||
res.json({
|
||||
field: "getNodeInfo",
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
logger.debug("GetNodeInfo:", response);
|
||||
|
|
@ -661,13 +757,13 @@ module.exports = (
|
|||
logger.debug("GetNetworkInfo Error:", err);
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).send({
|
||||
res.status(400).json({
|
||||
field: "getNodeInfo",
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
logger.debug("GetNetworkInfo:", response);
|
||||
|
|
@ -683,13 +779,13 @@ module.exports = (
|
|||
logger.debug("ListPeers Error:", err);
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).send({
|
||||
res.status(400).json({
|
||||
field: "listPeers",
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
logger.debug("ListPeers:", response);
|
||||
|
|
@ -705,13 +801,13 @@ module.exports = (
|
|||
logger.debug("NewAddress Error:", err);
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).send({
|
||||
res.status(400).json({
|
||||
field: "newAddress",
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
logger.debug("NewAddress:", response);
|
||||
|
|
@ -726,13 +822,13 @@ module.exports = (
|
|||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(403);
|
||||
return res.send({
|
||||
return res.json({
|
||||
field: "limituser",
|
||||
errorMessage: "User limited"
|
||||
});
|
||||
}
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
const connectRequest = {
|
||||
addr: { pubkey: req.body.pubkey, host: req.body.host },
|
||||
|
|
@ -742,7 +838,7 @@ module.exports = (
|
|||
lightning.connectPeer(connectRequest, (err, response) => {
|
||||
if (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 {
|
||||
logger.debug("ConnectPeer:", response);
|
||||
res.json(response);
|
||||
|
|
@ -757,20 +853,20 @@ module.exports = (
|
|||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(403);
|
||||
return res.send({
|
||||
return res.json({
|
||||
field: "limituser",
|
||||
errorMessage: "User limited"
|
||||
});
|
||||
}
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
const disconnectRequest = { pub_key: req.body.pubkey };
|
||||
logger.debug("DisconnectPeer Request:", disconnectRequest);
|
||||
lightning.disconnectPeer(disconnectRequest, (err, response) => {
|
||||
if (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 {
|
||||
logger.debug("DisconnectPeer:", response);
|
||||
res.json(response);
|
||||
|
|
@ -786,13 +882,13 @@ module.exports = (
|
|||
logger.debug("ListChannels Error:", err);
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).send({
|
||||
res.status(400).json({
|
||||
field: "listChannels",
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
logger.debug("ListChannels:", response);
|
||||
|
|
@ -808,13 +904,13 @@ module.exports = (
|
|||
logger.debug("PendingChannels Error:", err);
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).send({
|
||||
res.status(400).json({
|
||||
field: "pendingChannels",
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
logger.debug("PendingChannels:", response);
|
||||
|
|
@ -901,10 +997,10 @@ module.exports = (
|
|||
logger.debug("ListInvoices Error:", err);
|
||||
const health = await checkHealth();
|
||||
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 {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: health.LNDStatus.message, success: false });
|
||||
res.json({ errorMessage: health.LNDStatus.message, success: false });
|
||||
}
|
||||
} else {
|
||||
// logger.debug("ListInvoices:", response);
|
||||
|
|
@ -927,13 +1023,13 @@ module.exports = (
|
|||
logger.debug("ForwardingHistory Error:", err);
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).send({
|
||||
res.status(400).json({
|
||||
field: "forwardingHistory",
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
logger.debug("ForwardingHistory:", response);
|
||||
|
|
@ -949,13 +1045,13 @@ module.exports = (
|
|||
logger.debug("WalletBalance Error:", err);
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).send({
|
||||
res.status(400).json({
|
||||
field: "walletBalance",
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
logger.debug("WalletBalance:", response);
|
||||
|
|
@ -971,13 +1067,13 @@ module.exports = (
|
|||
if (err) {
|
||||
logger.debug("WalletBalance Error:", err);
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).send({
|
||||
res.status(400).json({
|
||||
field: "walletBalance",
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send(health.LNDStatus);
|
||||
res.json(health.LNDStatus);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
|
@ -986,13 +1082,13 @@ module.exports = (
|
|||
if (err) {
|
||||
logger.debug("ChannelBalance Error:", err);
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).send({
|
||||
res.status(400).json({
|
||||
field: "channelBalance",
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send(health.LNDStatus);
|
||||
res.json(health.LNDStatus);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
|
@ -1015,11 +1111,11 @@ module.exports = (
|
|||
logger.debug("DecodePayReq Error:", err);
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(500).send({
|
||||
res.status(500).json({
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500).send({ errorMessage: "LND is down" });
|
||||
res.status(500).json({ errorMessage: "LND is down" });
|
||||
}
|
||||
} else {
|
||||
logger.info("DecodePayReq:", paymentRequest);
|
||||
|
|
@ -1037,13 +1133,13 @@ module.exports = (
|
|||
logger.debug("ChannelBalance Error:", err);
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).send({
|
||||
res.status(400).json({
|
||||
field: "channelBalance",
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
logger.debug("ChannelBalance:", response);
|
||||
|
|
@ -1060,7 +1156,7 @@ module.exports = (
|
|||
res.sendStatus(403);
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -1084,10 +1180,10 @@ module.exports = (
|
|||
logger.info("OpenChannelRequest Error:", err);
|
||||
const health = await checkHealth();
|
||||
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) {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
});
|
||||
openedChannel.write(openChannelRequest)
|
||||
|
|
@ -1103,7 +1199,7 @@ module.exports = (
|
|||
res.sendStatus(403);
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
const { channelPoint, outputIndex } = req.body;
|
||||
|
|
@ -1131,13 +1227,13 @@ module.exports = (
|
|||
if (!res.headersSent) {
|
||||
if (health.LNDStatus.success) {
|
||||
logger.debug("CloseChannelRequest Error:", err);
|
||||
res.status(400).send({
|
||||
res.status(400).json({
|
||||
field: "closeChannel",
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -1152,7 +1248,7 @@ module.exports = (
|
|||
res.sendStatus(403);
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
const paymentRequest = { payment_request: req.body.payreq };
|
||||
|
|
@ -1184,12 +1280,12 @@ module.exports = (
|
|||
logger.error("SendPayment Error:", err);
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(500).send({
|
||||
res.status(500).json({
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -1205,7 +1301,7 @@ module.exports = (
|
|||
res.sendStatus(403);
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1221,13 +1317,13 @@ module.exports = (
|
|||
logger.debug("AddInvoice Error:", err);
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).send({
|
||||
res.status(400).json({
|
||||
field: "addInvoice",
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
|
@ -1245,7 +1341,7 @@ module.exports = (
|
|||
res.sendStatus(403);
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
lightning.signMessage(
|
||||
|
|
@ -1255,10 +1351,10 @@ module.exports = (
|
|||
logger.debug("SignMessage Error:", err);
|
||||
const health = await checkHealth();
|
||||
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 {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
logger.debug("SignMessage:", response);
|
||||
|
|
@ -1277,10 +1373,10 @@ module.exports = (
|
|||
logger.debug("VerifyMessage Error:", err);
|
||||
const health = await checkHealth();
|
||||
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 {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
logger.debug("VerifyMessage:", response);
|
||||
|
|
@ -1298,7 +1394,7 @@ module.exports = (
|
|||
res.sendStatus(403);
|
||||
} else {
|
||||
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 };
|
||||
|
|
@ -1308,13 +1404,13 @@ module.exports = (
|
|||
logger.debug("SendCoins Error:", err);
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).send({
|
||||
res.status(400).json({
|
||||
field: "sendCoins",
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
logger.debug("SendCoins:", response);
|
||||
|
|
@ -1334,10 +1430,10 @@ module.exports = (
|
|||
logger.debug("QueryRoute Error:", err);
|
||||
const health = await checkHealth();
|
||||
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 {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
logger.debug("QueryRoute:", response);
|
||||
|
|
@ -1360,12 +1456,12 @@ module.exports = (
|
|||
if (err) {
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).send({
|
||||
res.status(400).json({
|
||||
error: err.message
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.send({ errorMessage: "LND is down" });
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
} else {
|
||||
logger.debug("EstimateFee:", fee);
|
||||
|
|
|
|||
224
src/server.js
224
src/server.js
|
|
@ -1,78 +1,119 @@
|
|||
"use strict";
|
||||
/**
|
||||
* @prettier
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
const server = program => {
|
||||
const Https = require("https");
|
||||
const Http = require("http");
|
||||
const Express = require("express");
|
||||
const LightningServices = require("../utils/lightningServices");
|
||||
const app = Express();
|
||||
const Https = require('https')
|
||||
const Http = require('http')
|
||||
const Express = require('express')
|
||||
const LightningServices = require('../utils/lightningServices')
|
||||
const Encryption = require('../utils/encryptionStore')
|
||||
const app = Express()
|
||||
|
||||
const FS = require("../utils/fs");
|
||||
const bodyParser = require("body-parser");
|
||||
const session = require("express-session");
|
||||
const methodOverride = require("method-override");
|
||||
const { unprotectedRoutes, sensitiveRoutes } = require("../utils/protectedRoutes");
|
||||
const FS = require('../utils/fs')
|
||||
const bodyParser = require('body-parser')
|
||||
const session = require('express-session')
|
||||
const methodOverride = require('method-override')
|
||||
const {
|
||||
unprotectedRoutes,
|
||||
sensitiveRoutes,
|
||||
nonEncryptedRoutes
|
||||
} = require('../utils/protectedRoutes')
|
||||
// load app default configuration data
|
||||
const defaults = require("../config/defaults")(program.mainnet);
|
||||
const defaults = require('../config/defaults')(program.mainnet)
|
||||
// define useful global variables ======================================
|
||||
module.useTLS = program.usetls;
|
||||
module.serverPort = program.serverport || defaults.serverPort;
|
||||
module.httpsPort = module.serverPort;
|
||||
module.serverHost = program.serverhost || defaults.serverHost;
|
||||
module.useTLS = program.usetls
|
||||
module.serverPort = program.serverport || defaults.serverPort
|
||||
module.httpsPort = module.serverPort
|
||||
module.serverHost = program.serverhost || defaults.serverHost
|
||||
|
||||
// setup winston logging ==========
|
||||
const logger = require("../config/log")(
|
||||
const logger = require('../config/log')(
|
||||
program.logfile || defaults.logfile,
|
||||
program.loglevel || defaults.loglevel
|
||||
);
|
||||
)
|
||||
|
||||
// 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 =>
|
||||
new Promise(resolve => {
|
||||
const timer = setTimeout(() => resolve(timer), seconds * 1000);
|
||||
});
|
||||
const timer = setTimeout(() => resolve(timer), seconds * 1000)
|
||||
})
|
||||
|
||||
// eslint-disable-next-line consistent-return
|
||||
const startServer = async () => {
|
||||
try {
|
||||
LightningServices.setDefaults(program);
|
||||
await LightningServices.init();
|
||||
LightningServices.setDefaults(program)
|
||||
await LightningServices.init()
|
||||
|
||||
// init lnd module =================
|
||||
const lnd = require("../services/lnd/lnd")(LightningServices.services.lightning);
|
||||
const auth = require("../services/auth/auth");
|
||||
const lnd = require('../services/lnd/lnd')(
|
||||
LightningServices.services.lightning
|
||||
)
|
||||
const auth = require('../services/auth/auth')
|
||||
|
||||
app.use(async (req, res, next) => {
|
||||
console.log("Route:", req.path)
|
||||
console.log('Route:', req.path)
|
||||
if (unprotectedRoutes[req.method][req.path]) {
|
||||
next();
|
||||
next()
|
||||
} else {
|
||||
try {
|
||||
const response = await auth.validateToken(
|
||||
req.headers.authorization.replace("Bearer ", "")
|
||||
);
|
||||
req.headers.authorization.replace('Bearer ', '')
|
||||
)
|
||||
if (response.valid) {
|
||||
next();
|
||||
next()
|
||||
} 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) {
|
||||
logger.error(
|
||||
!req.headers.authorization
|
||||
? "Please add an Authorization header"
|
||||
? 'Please add an Authorization header'
|
||||
: 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) => {
|
||||
if (sensitiveRoutes[req.method][req.path]) {
|
||||
|
|
@ -84,7 +125,7 @@ const server = program => {
|
|||
path: req.path,
|
||||
sessionId: req.sessionId
|
||||
})
|
||||
);
|
||||
)
|
||||
} else {
|
||||
console.log(
|
||||
JSON.stringify({
|
||||
|
|
@ -96,10 +137,10 @@ const server = program => {
|
|||
query: req.query,
|
||||
sessionId: req.sessionId
|
||||
})
|
||||
);
|
||||
)
|
||||
}
|
||||
next();
|
||||
});
|
||||
next()
|
||||
})
|
||||
app.use(
|
||||
session({
|
||||
secret: defaults.sessionSecret,
|
||||
|
|
@ -108,79 +149,84 @@ const server = program => {
|
|||
rolling: true,
|
||||
saveUninitialized: true
|
||||
})
|
||||
);
|
||||
app.use(bodyParser.urlencoded({ extended: "true" }));
|
||||
app.use(bodyParser.json());
|
||||
app.use(bodyParser.json({ type: "application/vnd.api+json" }));
|
||||
app.use(methodOverride());
|
||||
)
|
||||
app.use(bodyParser.urlencoded({ extended: 'true' }))
|
||||
app.use(bodyParser.json())
|
||||
app.use(bodyParser.json({ type: 'application/vnd.api+json' }))
|
||||
app.use(methodOverride())
|
||||
// WARNING
|
||||
// error handler middleware, KEEP 4 parameters as express detects the
|
||||
// arity of the function to treat it as a err handling middleware
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
app.use((err, _, res, __) => {
|
||||
// Do logging and user-friendly error message display
|
||||
logger.error(err);
|
||||
res
|
||||
.status(500)
|
||||
.send({ status: 500, errorMessage: "internal error" });
|
||||
});
|
||||
logger.error(err)
|
||||
res.status(500).send({ status: 500, errorMessage: 'internal error' })
|
||||
})
|
||||
|
||||
const CA = LightningServices.servicesConfig.lndCertPath
|
||||
const CA_KEY = CA.replace('cert', 'key')
|
||||
|
||||
const createServer = async () => {
|
||||
try {
|
||||
if (program.usetls) {
|
||||
if (LightningServices.servicesConfig.lndCertPath && program.usetls) {
|
||||
const [key, cert] = await Promise.all([
|
||||
FS.readFile(program.usetls + "/key.pem"),
|
||||
FS.readFile(program.usetls + "/cert.pem")
|
||||
]);
|
||||
const httpsServer = Https.createServer({ key, cert }, app);
|
||||
FS.readFile(CA_KEY),
|
||||
FS.readFile(CA)
|
||||
])
|
||||
const httpsServer = Https.createServer({ key, cert }, app)
|
||||
|
||||
return httpsServer;
|
||||
return httpsServer
|
||||
}
|
||||
|
||||
const httpServer = Http.Server(app);
|
||||
return httpServer;
|
||||
const httpServer = Http.Server(app)
|
||||
return httpServer
|
||||
} catch (err) {
|
||||
logger.error(err.message);
|
||||
throw err;
|
||||
logger.error(err.message)
|
||||
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,
|
||||
lnd,
|
||||
program.user,
|
||||
program.pwd,
|
||||
program.limituser,
|
||||
program.limitpwd
|
||||
);
|
||||
)
|
||||
|
||||
require("./routes")(
|
||||
app,
|
||||
defaults,
|
||||
Sockets,
|
||||
{
|
||||
require('./routes')(app, defaults, Sockets, {
|
||||
serverHost: module.serverHost,
|
||||
serverPort: module.serverPort
|
||||
}
|
||||
);
|
||||
serverPort: module.serverPort,
|
||||
usetls: program.usetls,
|
||||
CA,
|
||||
CA_KEY
|
||||
})
|
||||
|
||||
// enable CORS headers
|
||||
app.use(require("./cors"));
|
||||
app.use(require('./cors'))
|
||||
// app.use(bodyParser.json({limit: '100000mb'}));
|
||||
app.use(bodyParser.json({ limit: "50mb" }));
|
||||
app.use(bodyParser.urlencoded({ limit: "50mb", extended: true }));
|
||||
app.use(bodyParser.json({ limit: '50mb' }))
|
||||
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(
|
||||
"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');
|
||||
//
|
||||
|
|
@ -189,15 +235,15 @@ const server = program => {
|
|||
// console.log('t', t.url);
|
||||
// });
|
||||
} catch (err) {
|
||||
logger.info(err);
|
||||
logger.info("Restarting server in 30 seconds...");
|
||||
await wait(30);
|
||||
startServer();
|
||||
return false;
|
||||
logger.info(err)
|
||||
logger.info('Restarting server in 30 seconds...')
|
||||
await wait(30)
|
||||
startServer()
|
||||
return false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
startServer();
|
||||
};
|
||||
startServer()
|
||||
}
|
||||
|
||||
module.exports = server;
|
||||
module.exports = server
|
||||
|
|
|
|||
125
utils/encryptionStore.js
Normal file
125
utils/encryptionStore.js
Normal 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
|
||||
|
|
@ -13,7 +13,8 @@ module.exports = {
|
|||
"/api/lnd/connect": true,
|
||||
"/api/lnd/wallet": true,
|
||||
"/api/lnd/wallet/existing": true,
|
||||
"/api/lnd/auth": true
|
||||
"/api/lnd/auth": true,
|
||||
"/api/security/exchangeKeys": true
|
||||
},
|
||||
PUT: {},
|
||||
DELETE: {}
|
||||
|
|
@ -26,5 +27,6 @@ module.exports = {
|
|||
},
|
||||
PUT: {},
|
||||
DELETE: {}
|
||||
}
|
||||
},
|
||||
nonEncryptedRoutes: ['/api/security/exchangeKeys', '/healthz', '/ping', '/api/lnd/wallet/status']
|
||||
}
|
||||
|
|
@ -873,7 +873,7 @@ ascli@~1:
|
|||
colour "~0.7.1"
|
||||
optjs "~3.2.2"
|
||||
|
||||
asn1@~0.2.3:
|
||||
asn1@^0.2.4, asn1@~0.2.3:
|
||||
version "0.2.4"
|
||||
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
|
||||
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
|
||||
|
|
@ -4341,6 +4341,13 @@ node-pre-gyp@^0.13.0:
|
|||
semver "^5.3.0"
|
||||
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:
|
||||
version "1.19.3"
|
||||
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.19.3.tgz#db71b3e62aef2a8e1283a9fa00164237356102c0"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue