End to end encryption completed through HTTP!
This commit is contained in:
parent
2a604edb9e
commit
4126fd503a
6 changed files with 389 additions and 184 deletions
|
|
@ -2,5 +2,5 @@
|
||||||
"requirePragma": true,
|
"requirePragma": true,
|
||||||
"semi": false,
|
"semi": false,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"endOfLine": "lf"
|
"endOfLine": "auto"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
221
src/routes.js
221
src/routes.js
|
|
@ -10,14 +10,17 @@ const Crypto = require("crypto");
|
||||||
const logger = require("winston");
|
const logger = require("winston");
|
||||||
const httpsAgent = require("https");
|
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 } = require("../utils/protectedRoutes");
|
const { unprotectedRoutes, nonEncryptedRoutes } = 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 = async (
|
module.exports = async (
|
||||||
|
|
@ -116,7 +119,7 @@ module.exports = async (
|
||||||
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 {
|
||||||
|
|
@ -124,7 +127,7 @@ module.exports = async (
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -192,6 +195,53 @@ module.exports = async (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
@ -247,7 +297,7 @@ module.exports = async (
|
||||||
*/
|
*/
|
||||||
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);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -255,11 +305,11 @@ module.exports = async (
|
||||||
*/
|
*/
|
||||||
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) => {
|
||||||
|
|
@ -267,8 +317,36 @@ module.exports = async (
|
||||||
res.json({ msg: "OK" });
|
res.json({ msg: "OK" });
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/api/security/exchangeKeys", (req, res) => {
|
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) => {
|
||||||
|
|
@ -292,6 +370,7 @@ module.exports = async (
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -337,7 +416,7 @@ module.exports = async (
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -346,7 +425,7 @@ module.exports = async (
|
||||||
} 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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -368,10 +447,10 @@ module.exports = async (
|
||||||
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();
|
||||||
|
|
@ -435,12 +514,12 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -613,13 +692,13 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -644,13 +723,13 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -666,13 +745,13 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -688,13 +767,13 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -710,13 +789,13 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -731,13 +810,13 @@ module.exports = async (
|
||||||
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 },
|
||||||
|
|
@ -747,7 +826,7 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -762,20 +841,20 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -791,13 +870,13 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -813,13 +892,13 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -906,10 +985,10 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -932,13 +1011,13 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -954,13 +1033,13 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -976,13 +1055,13 @@ module.exports = async (
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
@ -991,13 +1070,13 @@ module.exports = async (
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
@ -1020,11 +1099,11 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -1042,13 +1121,13 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -1065,7 +1144,7 @@ module.exports = async (
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
@ -1089,10 +1168,10 @@ module.exports = async (
|
||||||
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)
|
||||||
|
|
@ -1108,7 +1187,7 @@ module.exports = async (
|
||||||
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;
|
||||||
|
|
@ -1136,13 +1215,13 @@ module.exports = async (
|
||||||
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" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -1157,7 +1236,7 @@ module.exports = async (
|
||||||
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 };
|
||||||
|
|
@ -1189,12 +1268,12 @@ module.exports = async (
|
||||||
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" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1210,7 +1289,7 @@ module.exports = async (
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
@ -1226,13 +1305,13 @@ module.exports = async (
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
@ -1250,7 +1329,7 @@ module.exports = async (
|
||||||
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(
|
||||||
|
|
@ -1260,10 +1339,10 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -1282,10 +1361,10 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -1303,7 +1382,7 @@ module.exports = async (
|
||||||
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 };
|
||||||
|
|
@ -1313,13 +1392,13 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -1339,10 +1418,10 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
@ -1365,12 +1444,12 @@ module.exports = async (
|
||||||
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);
|
||||||
|
|
|
||||||
213
src/server.js
213
src/server.js
|
|
@ -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 FS = require('../utils/fs')
|
||||||
const bodyParser = require("body-parser");
|
const bodyParser = require('body-parser')
|
||||||
const session = require("express-session");
|
const session = require('express-session')
|
||||||
const methodOverride = require("method-override");
|
const methodOverride = require('method-override')
|
||||||
const { unprotectedRoutes, sensitiveRoutes } = require("../utils/protectedRoutes");
|
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,25 +149,23 @@ 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 = LightningServices.servicesConfig.lndCertPath
|
||||||
const CA_KEY = CA.replace("cert", "key")
|
const CA_KEY = CA.replace('cert', 'key')
|
||||||
|
|
||||||
const createServer = async () => {
|
const createServer = async () => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -134,62 +173,60 @@ const server = program => {
|
||||||
const [key, cert] = await Promise.all([
|
const [key, cert] = await Promise.all([
|
||||||
FS.readFile(CA_KEY),
|
FS.readFile(CA_KEY),
|
||||||
FS.readFile(CA)
|
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)
|
||||||
logger.error("An error has occurred while finding an LND cert to use to open an HTTPS server")
|
logger.error(
|
||||||
logger.warn("Falling back to opening an HTTP server...")
|
'An error has occurred while finding an LND cert to use to open an HTTPS server'
|
||||||
const httpServer = Http.Server(app);
|
)
|
||||||
|
logger.warn('Falling back to opening an HTTP server...')
|
||||||
|
const httpServer = Http.Server(app)
|
||||||
return httpServer
|
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,
|
|
||||||
defaults,
|
|
||||||
Sockets,
|
|
||||||
{
|
|
||||||
serverHost: module.serverHost,
|
serverHost: module.serverHost,
|
||||||
serverPort: module.serverPort,
|
serverPort: module.serverPort,
|
||||||
usetls: program.usetls,
|
usetls: program.usetls,
|
||||||
CA,
|
CA,
|
||||||
CA_KEY
|
CA_KEY
|
||||||
}
|
})
|
||||||
);
|
|
||||||
|
|
||||||
// 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');
|
||||||
//
|
//
|
||||||
|
|
@ -198,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
|
||||||
|
|
|
||||||
|
|
@ -6,52 +6,130 @@ const { Buffer } = require('buffer')
|
||||||
const APIKeyPair = new Map()
|
const APIKeyPair = new Map()
|
||||||
const authorizedDevices = new Map()
|
const authorizedDevices = new Map()
|
||||||
|
|
||||||
module.exports = {
|
const Encryption = {
|
||||||
encrypt: ({ deviceId, message }) => {
|
encryptKey: ({ deviceId, message }) => {
|
||||||
if (!authorizedDevices.has(deviceId)) {
|
if (!authorizedDevices.has(deviceId)) {
|
||||||
throw { field: 'deviceId', message: 'Unknown Device ID' }
|
throw { field: 'deviceId', message: 'Unknown Device ID' }
|
||||||
}
|
}
|
||||||
|
|
||||||
const devicePublicKey = authorizedDevices.get(deviceId)
|
const devicePublicKey = authorizedDevices.get(deviceId)
|
||||||
const data = Buffer.from(message)
|
const data = Buffer.from(message)
|
||||||
const encryptedData = Crypto.publicEncrypt(devicePublicKey, data)
|
const encryptedData = Crypto.publicEncrypt(
|
||||||
|
{
|
||||||
|
key: devicePublicKey,
|
||||||
|
padding: Crypto.constants.RSA_PKCS1_PADDING
|
||||||
|
},
|
||||||
|
data
|
||||||
|
)
|
||||||
return encryptedData.toString('base64')
|
return encryptedData.toString('base64')
|
||||||
},
|
},
|
||||||
decrypt: ({ deviceId, message }) => {
|
decryptKey: ({ deviceId, message }) => {
|
||||||
if (!authorizedDevices.has(deviceId)) {
|
if (!authorizedDevices.has(deviceId)) {
|
||||||
throw { field: 'deviceId', message: 'Unknown Device ID' }
|
throw { field: 'deviceId', message: 'Unknown Device ID' }
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = Buffer.from(message, 'base64')
|
const data = Buffer.from(message, 'base64')
|
||||||
const encryptedData = Crypto.privateDecrypt(APIKeyPair.private, data)
|
const encryptedData = Crypto.privateDecrypt(
|
||||||
return encryptedData.toString('base64')
|
{
|
||||||
|
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 }) => {
|
||||||
|
console.log(
|
||||||
|
'deviceId',
|
||||||
|
deviceId,
|
||||||
|
Object.fromEntries(authorizedDevices.entries()),
|
||||||
|
authorizedDevices.has(deviceId)
|
||||||
|
)
|
||||||
|
if (authorizedDevices.has(deviceId)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
},
|
},
|
||||||
authorizeDevice: ({ deviceId, publicKey }) =>
|
authorizeDevice: ({ deviceId, publicKey }) =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
if (authorizedDevices.has(deviceId)) {
|
if (authorizedDevices.has(deviceId)) {
|
||||||
const error = { success: false, message: 'Device already exists' }
|
const devicePublicKey = APIKeyPair.get(deviceId).publicKey
|
||||||
reject(error)
|
const deviceExists = {
|
||||||
return error
|
success: true,
|
||||||
|
APIPublicKey: devicePublicKey
|
||||||
|
}
|
||||||
|
resolve(deviceExists)
|
||||||
|
return deviceExists
|
||||||
}
|
}
|
||||||
|
|
||||||
authorizedDevices.set(deviceId, publicKey)
|
authorizedDevices.set(deviceId, publicKey)
|
||||||
|
|
||||||
Crypto.generateKeyPair(
|
Crypto.generateKeyPair(
|
||||||
'rsa',
|
'rsa',
|
||||||
{
|
{
|
||||||
modulusLength: 4096
|
modulusLength: 4096,
|
||||||
|
privateKeyEncoding: {
|
||||||
|
type: 'pkcs1',
|
||||||
|
format: 'pem'
|
||||||
|
},
|
||||||
|
publicKeyEncoding: {
|
||||||
|
type: 'pkcs1',
|
||||||
|
format: 'pem'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
(err, publicKey, privateKey) => {
|
(err, publicKey, privateKey) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject({ field: 'APIKeyPair', errorMessage: err })
|
console.error(err)
|
||||||
|
reject(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
APIKeyPair.set(deviceId, {
|
const exportedKey = {
|
||||||
publicKey,
|
publicKey,
|
||||||
privateKey
|
privateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
APIKeyPair.set(deviceId, exportedKey)
|
||||||
|
resolve({
|
||||||
|
success: true,
|
||||||
|
APIPublicKey: exportedKey.publicKey
|
||||||
})
|
})
|
||||||
resolve({ success: true })
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
|
@ -59,3 +137,5 @@ module.exports = {
|
||||||
authorizedDevices.delete(deviceId)
|
authorizedDevices.delete(deviceId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = Encryption
|
||||||
|
|
|
||||||
|
|
@ -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']
|
||||||
}
|
}
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue