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,
|
"requirePragma": true,
|
||||||
"semi": false,
|
"semi": false,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"endOfLine": "lf"
|
"endOfLine": "auto"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
const Gun = require('gun')
|
const Gun = require('gun')
|
||||||
const debounce = require('lodash/debounce')
|
const debounce = require('lodash/debounce')
|
||||||
const once = require('lodash/once')
|
const once = require('lodash/once')
|
||||||
|
const Encryption = require('../../../utils/encryptionStore')
|
||||||
|
|
||||||
/** @type {import('../contact-api/SimpleGUN').ISEA} */
|
/** @type {import('../contact-api/SimpleGUN').ISEA} */
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|
@ -96,6 +97,7 @@ const Action = require('../action-constants.js')
|
||||||
const API = require('../contact-api/index')
|
const API = require('../contact-api/index')
|
||||||
const Config = require('../config')
|
const Config = require('../config')
|
||||||
const Event = require('../event-constants')
|
const Event = require('../event-constants')
|
||||||
|
// const { nonEncryptedRoutes } = require('../../../utils/protectedRoutes')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('../contact-api/SimpleGUN').GUNNode} GUNNode
|
* @typedef {import('../contact-api/SimpleGUN').GUNNode} GUNNode
|
||||||
|
|
@ -281,37 +283,116 @@ class Mediator {
|
||||||
* @param {Readonly<SimpleSocket>} socket
|
* @param {Readonly<SimpleSocket>} socket
|
||||||
*/
|
*/
|
||||||
constructor(socket) {
|
constructor(socket) {
|
||||||
this.socket = socket
|
this.socket = this.encryptSocketInstance(socket)
|
||||||
|
|
||||||
this.connected = true
|
this.connected = true
|
||||||
|
|
||||||
socket.on('disconnect', this.onDisconnect)
|
this.socket.on('disconnect', this.onDisconnect)
|
||||||
|
|
||||||
socket.on(Action.ACCEPT_REQUEST, this.acceptRequest)
|
this.socket.on(Action.ACCEPT_REQUEST, this.acceptRequest)
|
||||||
socket.on(Action.BLACKLIST, this.blacklist)
|
this.socket.on(Action.BLACKLIST, this.blacklist)
|
||||||
socket.on(Action.GENERATE_NEW_HANDSHAKE_NODE, this.generateHandshakeNode)
|
this.socket.on(
|
||||||
socket.on(Action.SEND_HANDSHAKE_REQUEST, this.sendHandshakeRequest)
|
Action.GENERATE_NEW_HANDSHAKE_NODE,
|
||||||
socket.on(
|
this.generateHandshakeNode
|
||||||
|
)
|
||||||
|
this.socket.on(Action.SEND_HANDSHAKE_REQUEST, this.sendHandshakeRequest)
|
||||||
|
this.socket.on(
|
||||||
Action.SEND_HANDSHAKE_REQUEST_WITH_INITIAL_MSG,
|
Action.SEND_HANDSHAKE_REQUEST_WITH_INITIAL_MSG,
|
||||||
this.sendHRWithInitialMsg
|
this.sendHRWithInitialMsg
|
||||||
)
|
)
|
||||||
socket.on(Action.SEND_MESSAGE, this.sendMessage)
|
this.socket.on(Action.SEND_MESSAGE, this.sendMessage)
|
||||||
socket.on(Action.SEND_PAYMENT, this.sendPayment)
|
this.socket.on(Action.SET_AVATAR, this.setAvatar)
|
||||||
socket.on(Action.SET_AVATAR, this.setAvatar)
|
this.socket.on(Action.SET_DISPLAY_NAME, this.setDisplayName)
|
||||||
socket.on(Action.SET_DISPLAY_NAME, this.setDisplayName)
|
this.socket.on(Action.SEND_PAYMENT, this.sendPayment)
|
||||||
socket.on(Action.SET_BIO, this.setBio)
|
this.socket.on(Action.SET_BIO, this.setBio)
|
||||||
|
|
||||||
socket.on(Event.ON_AVATAR, this.onAvatar)
|
this.socket.on(Event.ON_AVATAR, this.onAvatar)
|
||||||
socket.on(Event.ON_BLACKLIST, this.onBlacklist)
|
this.socket.on(Event.ON_BLACKLIST, this.onBlacklist)
|
||||||
socket.on(Event.ON_CHATS, this.onChats)
|
this.socket.on(Event.ON_CHATS, this.onChats)
|
||||||
socket.on(Event.ON_DISPLAY_NAME, this.onDisplayName)
|
this.socket.on(Event.ON_DISPLAY_NAME, this.onDisplayName)
|
||||||
socket.on(Event.ON_HANDSHAKE_ADDRESS, this.onHandshakeAddress)
|
this.socket.on(Event.ON_HANDSHAKE_ADDRESS, this.onHandshakeAddress)
|
||||||
socket.on(Event.ON_RECEIVED_REQUESTS, this.onReceivedRequests)
|
this.socket.on(Event.ON_RECEIVED_REQUESTS, this.onReceivedRequests)
|
||||||
socket.on(Event.ON_SENT_REQUESTS, this.onSentRequests)
|
this.socket.on(Event.ON_SENT_REQUESTS, this.onSentRequests)
|
||||||
socket.on(Event.ON_BIO, this.onBio)
|
this.socket.on(Event.ON_BIO, this.onBio)
|
||||||
socket.on(Event.ON_SEED_BACKUP, this.onSeedBackup)
|
this.socket.on(Event.ON_SEED_BACKUP, this.onSeedBackup)
|
||||||
|
|
||||||
socket.on(IS_GUN_AUTH, this.isGunAuth)
|
this.socket.on(IS_GUN_AUTH, this.isGunAuth)
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptSocketInstance = socket => {
|
||||||
|
return {
|
||||||
|
on: (eventName, cb) => {
|
||||||
|
const deviceId = socket.handshake.query['x-shockwallet-device-id']
|
||||||
|
socket.on(eventName, data => {
|
||||||
|
try {
|
||||||
|
// if (nonEncryptedEvents.includes(eventName)) {
|
||||||
|
// return cb(data)
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return cb(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!deviceId) {
|
||||||
|
const error = {
|
||||||
|
field: 'deviceId',
|
||||||
|
message: 'Please specify a device ID'
|
||||||
|
}
|
||||||
|
console.error(error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Encryption.isAuthorizedDevice({ deviceId })) {
|
||||||
|
const error = {
|
||||||
|
field: 'deviceId',
|
||||||
|
message: 'Please specify a device ID'
|
||||||
|
}
|
||||||
|
console.error('Unknown Device', error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if(typeof data === 'string'){
|
||||||
|
data = JSON.parse(data)
|
||||||
|
}
|
||||||
|
console.log('Event:', eventName)
|
||||||
|
console.log('Data:', data)
|
||||||
|
console.log('Decrypt params:', {
|
||||||
|
deviceId,
|
||||||
|
message: data.encryptedKey
|
||||||
|
})
|
||||||
|
const decryptedKey = Encryption.decryptKey({
|
||||||
|
deviceId,
|
||||||
|
message: data.encryptedKey
|
||||||
|
})
|
||||||
|
const decryptedMessage = Encryption.decryptMessage({
|
||||||
|
message: data.encryptedData,
|
||||||
|
key: decryptedKey,
|
||||||
|
iv: data.iv
|
||||||
|
})
|
||||||
|
const decryptedData = JSON.parse(decryptedMessage)
|
||||||
|
return cb(decryptedData)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
emit: (eventName, data) => {
|
||||||
|
try {
|
||||||
|
const deviceId = socket.handshake.query['x-shockwallet-device-id']
|
||||||
|
const authorized = Encryption.isAuthorizedDevice({ deviceId })
|
||||||
|
const encryptedMessage = authorized
|
||||||
|
? Encryption.encryptMessage({
|
||||||
|
message: data,
|
||||||
|
deviceId
|
||||||
|
})
|
||||||
|
: data
|
||||||
|
console.log('Sending Message...', eventName, data, encryptedMessage)
|
||||||
|
socket.emit(eventName, encryptedMessage)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isGunAuth = () => {
|
isGunAuth = () => {
|
||||||
|
|
@ -725,6 +806,8 @@ class Mediator {
|
||||||
try {
|
try {
|
||||||
const { token } = body
|
const { token } = body
|
||||||
|
|
||||||
|
console.log('ON_CHATS', body)
|
||||||
|
|
||||||
await throwOnInvalidToken(token)
|
await throwOnInvalidToken(token)
|
||||||
|
|
||||||
API.Events.onChats(
|
API.Events.onChats(
|
||||||
|
|
|
||||||
244
src/routes.js
244
src/routes.js
|
|
@ -5,27 +5,37 @@
|
||||||
*/
|
*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const Http = require("axios");
|
const Axios = require("axios");
|
||||||
const Crypto = require("crypto");
|
const Crypto = require("crypto");
|
||||||
const logger = require("winston");
|
const logger = require("winston");
|
||||||
|
const httpsAgent = require("https");
|
||||||
const responseTime = require("response-time");
|
const responseTime = require("response-time");
|
||||||
|
const uuid = require("uuid/v4");
|
||||||
const getListPage = require("../utils/paginate");
|
const getListPage = require("../utils/paginate");
|
||||||
const auth = require("../services/auth/auth");
|
const auth = require("../services/auth/auth");
|
||||||
const FS = require("../utils/fs");
|
const FS = require("../utils/fs");
|
||||||
|
const Encryption = require("../utils/encryptionStore");
|
||||||
const LightningServices = require("../utils/lightningServices");
|
const LightningServices = require("../utils/lightningServices");
|
||||||
const GunDB = require("../services/gunDB/Mediator");
|
const GunDB = require("../services/gunDB/Mediator");
|
||||||
|
const { unprotectedRoutes, nonEncryptedRoutes } = require("../utils/protectedRoutes");
|
||||||
const GunActions = require("../services/gunDB/contact-api/actions")
|
const GunActions = require("../services/gunDB/contact-api/actions")
|
||||||
const { unprotectedRoutes } = require("../utils/protectedRoutes");
|
|
||||||
|
|
||||||
const DEFAULT_MAX_NUM_ROUTES_TO_QUERY = 10;
|
const DEFAULT_MAX_NUM_ROUTES_TO_QUERY = 10;
|
||||||
|
const SESSION_ID = uuid();
|
||||||
|
|
||||||
// module.exports = (app) => {
|
// module.exports = (app) => {
|
||||||
module.exports = (
|
module.exports = async (
|
||||||
app,
|
app,
|
||||||
config,
|
config,
|
||||||
mySocketsEvents,
|
mySocketsEvents,
|
||||||
{ serverPort }
|
{ serverPort, CA, CA_KEY, usetls }
|
||||||
) => {
|
) => {
|
||||||
|
const Http = Axios.create({
|
||||||
|
httpsAgent: new httpsAgent.Agent({
|
||||||
|
ca: await FS.readFile(CA)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
const sanitizeLNDError = (message = "") =>
|
const sanitizeLNDError = (message = "") =>
|
||||||
message.toLowerCase().includes("unknown")
|
message.toLowerCase().includes("unknown")
|
||||||
? message
|
? message
|
||||||
|
|
@ -82,7 +92,7 @@ module.exports = (
|
||||||
const serviceStatus = await getAvailableService();
|
const serviceStatus = await getAvailableService();
|
||||||
const LNDStatus = serviceStatus;
|
const LNDStatus = serviceStatus;
|
||||||
try {
|
try {
|
||||||
const APIHealth = await Http.get(`http://localhost:${serverPort}/ping`);
|
const APIHealth = await Http.get(`${usetls ? 'https' : 'http'}://localhost:${serverPort}/ping`);
|
||||||
const APIStatus = {
|
const APIStatus = {
|
||||||
message: APIHealth.data,
|
message: APIHealth.data,
|
||||||
responseTime: APIHealth.headers["x-response-time"],
|
responseTime: APIHealth.headers["x-response-time"],
|
||||||
|
|
@ -93,6 +103,7 @@ module.exports = (
|
||||||
APIStatus
|
APIStatus
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
const APIStatus = {
|
const APIStatus = {
|
||||||
message: err.response.data,
|
message: err.response.data,
|
||||||
responseTime: err.response.headers["x-response-time"],
|
responseTime: err.response.headers["x-response-time"],
|
||||||
|
|
@ -109,7 +120,7 @@ module.exports = (
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
if (err) {
|
if (err) {
|
||||||
res.send({
|
res.json({
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -117,7 +128,7 @@ module.exports = (
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -185,6 +196,58 @@ module.exports = (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
res.setHeader("x-session-id", SESSION_ID)
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
const deviceId = req.headers["x-shockwallet-device-id"];
|
||||||
|
try {
|
||||||
|
if (nonEncryptedRoutes.includes(req.path)) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!deviceId) {
|
||||||
|
const error = {
|
||||||
|
field: "deviceId",
|
||||||
|
message: "Please specify a device ID"
|
||||||
|
};
|
||||||
|
console.error(error)
|
||||||
|
return res.status(401).json(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Encryption.isAuthorizedDevice({ deviceId })) {
|
||||||
|
const error = {
|
||||||
|
field: "deviceId",
|
||||||
|
message: "Please specify a device ID"
|
||||||
|
};
|
||||||
|
console.error("Unknown Device", error)
|
||||||
|
return res.status(401).json(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.method === "GET") {
|
||||||
|
console.log("Method:", req.method);
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Body:", req.body)
|
||||||
|
console.log("Decrypt params:", { deviceId, message: req.body.encryptionKey })
|
||||||
|
const decryptedKey = Encryption.decryptKey({ deviceId, message: req.body.encryptionKey });
|
||||||
|
console.log("decryptedKey", decryptedKey)
|
||||||
|
const decryptedMessage = Encryption.decryptMessage({ message: req.body.data, key: decryptedKey, iv: req.body.iv })
|
||||||
|
req.body = JSON.parse(decryptedMessage);
|
||||||
|
return next();
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
return res
|
||||||
|
.status(401)
|
||||||
|
.json(
|
||||||
|
err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
app.use(async (req, res, next) => {
|
app.use(async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
console.log("Route:", req.path)
|
console.log("Route:", req.path)
|
||||||
|
|
@ -240,7 +303,7 @@ module.exports = (
|
||||||
*/
|
*/
|
||||||
app.get("/health", async (req, res) => {
|
app.get("/health", async (req, res) => {
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
res.send(health);
|
res.json(health);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -248,11 +311,11 @@ module.exports = (
|
||||||
*/
|
*/
|
||||||
app.get("/healthz", async (req, res) => {
|
app.get("/healthz", async (req, res) => {
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
res.send(health);
|
res.json(health);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/ping", (req, res) => {
|
app.get("/ping", (req, res) => {
|
||||||
res.send("OK");
|
res.json({ message: "OK" });
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/api/mobile/error", (req, res) => {
|
app.post("/api/mobile/error", (req, res) => {
|
||||||
|
|
@ -260,6 +323,38 @@ module.exports = (
|
||||||
res.json({ msg: "OK" });
|
res.json({ msg: "OK" });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.post("/api/security/exchangeKeys", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { publicKey, deviceId } = req.body;
|
||||||
|
|
||||||
|
if (!publicKey || publicKey.length < 600) {
|
||||||
|
return res.status(400).json({
|
||||||
|
field: 'publicKey',
|
||||||
|
message: "Please provide a valid public key"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!deviceId ||
|
||||||
|
!/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/iu
|
||||||
|
.test(deviceId)) {
|
||||||
|
return res.status(400).json({
|
||||||
|
field: 'deviceId',
|
||||||
|
message: "Please provide a valid device ID"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const authorizedDevice = await Encryption.authorizeDevice({ deviceId, publicKey })
|
||||||
|
console.log(authorizedDevice)
|
||||||
|
return res.status(200).json(authorizedDevice)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
return res.status(401).json({
|
||||||
|
field: 'unknown',
|
||||||
|
message: err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
app.get("/api/lnd/wallet/status", async (req, res) => {
|
app.get("/api/lnd/wallet/status", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const walletStatus = await walletExists();
|
const walletStatus = await walletExists();
|
||||||
|
|
@ -281,6 +376,7 @@ module.exports = (
|
||||||
|
|
||||||
app.post("/api/lnd/auth", async (req, res) => {
|
app.post("/api/lnd/auth", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
console.log("/api/lnd/auth Body:", req.body)
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
const walletInitialized = await walletExists();
|
const walletInitialized = await walletExists();
|
||||||
// If we're connected to lnd, unlock the wallet using the password supplied
|
// If we're connected to lnd, unlock the wallet using the password supplied
|
||||||
|
|
@ -326,7 +422,7 @@ module.exports = (
|
||||||
}
|
}
|
||||||
|
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({
|
res.json({
|
||||||
field: "health",
|
field: "health",
|
||||||
errorMessage: sanitizeLNDError(health.LNDStatus.message),
|
errorMessage: sanitizeLNDError(health.LNDStatus.message),
|
||||||
success: false
|
success: false
|
||||||
|
|
@ -335,7 +431,7 @@ module.exports = (
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.debug("Unlock Error:", err);
|
logger.debug("Unlock Error:", err);
|
||||||
res.status(400);
|
res.status(400);
|
||||||
res.send({ field: "user", errorMessage: sanitizeLNDError(err.message), success: false });
|
res.json({ field: "user", errorMessage: sanitizeLNDError(err.message), success: false });
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -357,10 +453,10 @@ module.exports = (
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400);
|
res.status(400);
|
||||||
res.send({ field: "WalletUnlocker", errorMessage: unlockErr.message });
|
res.json({ field: "WalletUnlocker", errorMessage: unlockErr.message });
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await recreateLnServices();
|
await recreateLnServices();
|
||||||
|
|
@ -424,12 +520,12 @@ module.exports = (
|
||||||
const message = genSeedErr.details;
|
const message = genSeedErr.details;
|
||||||
return res
|
return res
|
||||||
.status(400)
|
.status(400)
|
||||||
.send({ field: "GenSeed", errorMessage: message, success: false });
|
.json({ field: "GenSeed", errorMessage: message, success: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return res
|
||||||
.status(500)
|
.status(500)
|
||||||
.send({ field: "health", errorMessage: "LND is down", success: false });
|
.json({ field: "health", errorMessage: "LND is down", success: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug("GenSeed:", genSeedResponse);
|
logger.debug("GenSeed:", genSeedResponse);
|
||||||
|
|
@ -608,13 +704,13 @@ module.exports = (
|
||||||
logger.error("GetInfo Error:", err);
|
logger.error("GetInfo Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({
|
res.status(400).json({
|
||||||
field: "getInfo",
|
field: "getInfo",
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.info("GetInfo:", response);
|
logger.info("GetInfo:", response);
|
||||||
|
|
@ -639,13 +735,13 @@ module.exports = (
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400);
|
res.status(400);
|
||||||
res.send({
|
res.json({
|
||||||
field: "getNodeInfo",
|
field: "getNodeInfo",
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.debug("GetNodeInfo:", response);
|
logger.debug("GetNodeInfo:", response);
|
||||||
|
|
@ -661,13 +757,13 @@ module.exports = (
|
||||||
logger.debug("GetNetworkInfo Error:", err);
|
logger.debug("GetNetworkInfo Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({
|
res.status(400).json({
|
||||||
field: "getNodeInfo",
|
field: "getNodeInfo",
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.debug("GetNetworkInfo:", response);
|
logger.debug("GetNetworkInfo:", response);
|
||||||
|
|
@ -683,13 +779,13 @@ module.exports = (
|
||||||
logger.debug("ListPeers Error:", err);
|
logger.debug("ListPeers Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({
|
res.status(400).json({
|
||||||
field: "listPeers",
|
field: "listPeers",
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.debug("ListPeers:", response);
|
logger.debug("ListPeers:", response);
|
||||||
|
|
@ -705,13 +801,13 @@ module.exports = (
|
||||||
logger.debug("NewAddress Error:", err);
|
logger.debug("NewAddress Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({
|
res.status(400).json({
|
||||||
field: "newAddress",
|
field: "newAddress",
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.debug("NewAddress:", response);
|
logger.debug("NewAddress:", response);
|
||||||
|
|
@ -726,13 +822,13 @@ module.exports = (
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(403);
|
res.status(403);
|
||||||
return res.send({
|
return res.json({
|
||||||
field: "limituser",
|
field: "limituser",
|
||||||
errorMessage: "User limited"
|
errorMessage: "User limited"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
const connectRequest = {
|
const connectRequest = {
|
||||||
addr: { pubkey: req.body.pubkey, host: req.body.host },
|
addr: { pubkey: req.body.pubkey, host: req.body.host },
|
||||||
|
|
@ -742,7 +838,7 @@ module.exports = (
|
||||||
lightning.connectPeer(connectRequest, (err, response) => {
|
lightning.connectPeer(connectRequest, (err, response) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
logger.debug("ConnectPeer Error:", err);
|
logger.debug("ConnectPeer Error:", err);
|
||||||
res.status(500).send({ field: "connectPeer", errorMessage: sanitizeLNDError(err.message) });
|
res.status(500).json({ field: "connectPeer", errorMessage: sanitizeLNDError(err.message) });
|
||||||
} else {
|
} else {
|
||||||
logger.debug("ConnectPeer:", response);
|
logger.debug("ConnectPeer:", response);
|
||||||
res.json(response);
|
res.json(response);
|
||||||
|
|
@ -757,20 +853,20 @@ module.exports = (
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(403);
|
res.status(403);
|
||||||
return res.send({
|
return res.json({
|
||||||
field: "limituser",
|
field: "limituser",
|
||||||
errorMessage: "User limited"
|
errorMessage: "User limited"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
const disconnectRequest = { pub_key: req.body.pubkey };
|
const disconnectRequest = { pub_key: req.body.pubkey };
|
||||||
logger.debug("DisconnectPeer Request:", disconnectRequest);
|
logger.debug("DisconnectPeer Request:", disconnectRequest);
|
||||||
lightning.disconnectPeer(disconnectRequest, (err, response) => {
|
lightning.disconnectPeer(disconnectRequest, (err, response) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
logger.debug("DisconnectPeer Error:", err);
|
logger.debug("DisconnectPeer Error:", err);
|
||||||
res.status(400).send({ field: "disconnectPeer", errorMessage: sanitizeLNDError(err.message) });
|
res.status(400).json({ field: "disconnectPeer", errorMessage: sanitizeLNDError(err.message) });
|
||||||
} else {
|
} else {
|
||||||
logger.debug("DisconnectPeer:", response);
|
logger.debug("DisconnectPeer:", response);
|
||||||
res.json(response);
|
res.json(response);
|
||||||
|
|
@ -786,13 +882,13 @@ module.exports = (
|
||||||
logger.debug("ListChannels Error:", err);
|
logger.debug("ListChannels Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({
|
res.status(400).json({
|
||||||
field: "listChannels",
|
field: "listChannels",
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.debug("ListChannels:", response);
|
logger.debug("ListChannels:", response);
|
||||||
|
|
@ -808,13 +904,13 @@ module.exports = (
|
||||||
logger.debug("PendingChannels Error:", err);
|
logger.debug("PendingChannels Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({
|
res.status(400).json({
|
||||||
field: "pendingChannels",
|
field: "pendingChannels",
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.debug("PendingChannels:", response);
|
logger.debug("PendingChannels:", response);
|
||||||
|
|
@ -901,10 +997,10 @@ module.exports = (
|
||||||
logger.debug("ListInvoices Error:", err);
|
logger.debug("ListInvoices Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({ errorMessage: sanitizeLNDError(err.message), success: false });
|
res.status(400).json({ errorMessage: sanitizeLNDError(err.message), success: false });
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: health.LNDStatus.message, success: false });
|
res.json({ errorMessage: health.LNDStatus.message, success: false });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// logger.debug("ListInvoices:", response);
|
// logger.debug("ListInvoices:", response);
|
||||||
|
|
@ -927,13 +1023,13 @@ module.exports = (
|
||||||
logger.debug("ForwardingHistory Error:", err);
|
logger.debug("ForwardingHistory Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({
|
res.status(400).json({
|
||||||
field: "forwardingHistory",
|
field: "forwardingHistory",
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.debug("ForwardingHistory:", response);
|
logger.debug("ForwardingHistory:", response);
|
||||||
|
|
@ -949,13 +1045,13 @@ module.exports = (
|
||||||
logger.debug("WalletBalance Error:", err);
|
logger.debug("WalletBalance Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({
|
res.status(400).json({
|
||||||
field: "walletBalance",
|
field: "walletBalance",
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.debug("WalletBalance:", response);
|
logger.debug("WalletBalance:", response);
|
||||||
|
|
@ -971,13 +1067,13 @@ module.exports = (
|
||||||
if (err) {
|
if (err) {
|
||||||
logger.debug("WalletBalance Error:", err);
|
logger.debug("WalletBalance Error:", err);
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({
|
res.status(400).json({
|
||||||
field: "walletBalance",
|
field: "walletBalance",
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send(health.LNDStatus);
|
res.json(health.LNDStatus);
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
@ -986,13 +1082,13 @@ module.exports = (
|
||||||
if (err) {
|
if (err) {
|
||||||
logger.debug("ChannelBalance Error:", err);
|
logger.debug("ChannelBalance Error:", err);
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({
|
res.status(400).json({
|
||||||
field: "channelBalance",
|
field: "channelBalance",
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send(health.LNDStatus);
|
res.json(health.LNDStatus);
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
@ -1015,11 +1111,11 @@ module.exports = (
|
||||||
logger.debug("DecodePayReq Error:", err);
|
logger.debug("DecodePayReq Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(500).send({
|
res.status(500).json({
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500).send({ errorMessage: "LND is down" });
|
res.status(500).json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.info("DecodePayReq:", paymentRequest);
|
logger.info("DecodePayReq:", paymentRequest);
|
||||||
|
|
@ -1037,13 +1133,13 @@ module.exports = (
|
||||||
logger.debug("ChannelBalance Error:", err);
|
logger.debug("ChannelBalance Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({
|
res.status(400).json({
|
||||||
field: "channelBalance",
|
field: "channelBalance",
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.debug("ChannelBalance:", response);
|
logger.debug("ChannelBalance:", response);
|
||||||
|
|
@ -1060,7 +1156,7 @@ module.exports = (
|
||||||
res.sendStatus(403);
|
res.sendStatus(403);
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1084,10 +1180,10 @@ module.exports = (
|
||||||
logger.info("OpenChannelRequest Error:", err);
|
logger.info("OpenChannelRequest Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success && !res.headersSent) {
|
if (health.LNDStatus.success && !res.headersSent) {
|
||||||
res.status(500).send({ field: "openChannelRequest", errorMessage: sanitizeLNDError(err.message) });
|
res.status(500).json({ field: "openChannelRequest", errorMessage: sanitizeLNDError(err.message) });
|
||||||
} else if (!res.headersSent) {
|
} else if (!res.headersSent) {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
openedChannel.write(openChannelRequest)
|
openedChannel.write(openChannelRequest)
|
||||||
|
|
@ -1103,7 +1199,7 @@ module.exports = (
|
||||||
res.sendStatus(403);
|
res.sendStatus(403);
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const { channelPoint, outputIndex } = req.body;
|
const { channelPoint, outputIndex } = req.body;
|
||||||
|
|
@ -1131,13 +1227,13 @@ module.exports = (
|
||||||
if (!res.headersSent) {
|
if (!res.headersSent) {
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
logger.debug("CloseChannelRequest Error:", err);
|
logger.debug("CloseChannelRequest Error:", err);
|
||||||
res.status(400).send({
|
res.status(400).json({
|
||||||
field: "closeChannel",
|
field: "closeChannel",
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -1152,7 +1248,7 @@ module.exports = (
|
||||||
res.sendStatus(403);
|
res.sendStatus(403);
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const paymentRequest = { payment_request: req.body.payreq };
|
const paymentRequest = { payment_request: req.body.payreq };
|
||||||
|
|
@ -1184,12 +1280,12 @@ module.exports = (
|
||||||
logger.error("SendPayment Error:", err);
|
logger.error("SendPayment Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(500).send({
|
res.status(500).json({
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1205,7 +1301,7 @@ module.exports = (
|
||||||
res.sendStatus(403);
|
res.sendStatus(403);
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1221,13 +1317,13 @@ module.exports = (
|
||||||
logger.debug("AddInvoice Error:", err);
|
logger.debug("AddInvoice Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({
|
res.status(400).json({
|
||||||
field: "addInvoice",
|
field: "addInvoice",
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
@ -1245,7 +1341,7 @@ module.exports = (
|
||||||
res.sendStatus(403);
|
res.sendStatus(403);
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lightning.signMessage(
|
lightning.signMessage(
|
||||||
|
|
@ -1255,10 +1351,10 @@ module.exports = (
|
||||||
logger.debug("SignMessage Error:", err);
|
logger.debug("SignMessage Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({ field: "signMessage", errorMessage: sanitizeLNDError(err.message) });
|
res.status(400).json({ field: "signMessage", errorMessage: sanitizeLNDError(err.message) });
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.debug("SignMessage:", response);
|
logger.debug("SignMessage:", response);
|
||||||
|
|
@ -1277,10 +1373,10 @@ module.exports = (
|
||||||
logger.debug("VerifyMessage Error:", err);
|
logger.debug("VerifyMessage Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({ field: "verifyMessage", errorMessage: sanitizeLNDError(err.message) });
|
res.status(400).json({ field: "verifyMessage", errorMessage: sanitizeLNDError(err.message) });
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.debug("VerifyMessage:", response);
|
logger.debug("VerifyMessage:", response);
|
||||||
|
|
@ -1298,7 +1394,7 @@ module.exports = (
|
||||||
res.sendStatus(403);
|
res.sendStatus(403);
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const sendCoinsRequest = { addr: req.body.addr, amount: req.body.amount };
|
const sendCoinsRequest = { addr: req.body.addr, amount: req.body.amount };
|
||||||
|
|
@ -1308,13 +1404,13 @@ module.exports = (
|
||||||
logger.debug("SendCoins Error:", err);
|
logger.debug("SendCoins Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({
|
res.status(400).json({
|
||||||
field: "sendCoins",
|
field: "sendCoins",
|
||||||
errorMessage: sanitizeLNDError(err.message)
|
errorMessage: sanitizeLNDError(err.message)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.debug("SendCoins:", response);
|
logger.debug("SendCoins:", response);
|
||||||
|
|
@ -1334,10 +1430,10 @@ module.exports = (
|
||||||
logger.debug("QueryRoute Error:", err);
|
logger.debug("QueryRoute Error:", err);
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({ field: "queryRoute", errorMessage: sanitizeLNDError(err.message) });
|
res.status(400).json({ field: "queryRoute", errorMessage: sanitizeLNDError(err.message) });
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.debug("QueryRoute:", response);
|
logger.debug("QueryRoute:", response);
|
||||||
|
|
@ -1360,12 +1456,12 @@ module.exports = (
|
||||||
if (err) {
|
if (err) {
|
||||||
const health = await checkHealth();
|
const health = await checkHealth();
|
||||||
if (health.LNDStatus.success) {
|
if (health.LNDStatus.success) {
|
||||||
res.status(400).send({
|
res.status(400).json({
|
||||||
error: err.message
|
error: err.message
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send({ errorMessage: "LND is down" });
|
res.json({ errorMessage: "LND is down" });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.debug("EstimateFee:", fee);
|
logger.debug("EstimateFee:", fee);
|
||||||
|
|
|
||||||
230
src/server.js
230
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 bodyParser = require("body-parser");
|
const FS = require('../utils/fs')
|
||||||
const session = require("express-session");
|
const bodyParser = require('body-parser')
|
||||||
const methodOverride = require("method-override");
|
const session = require('express-session')
|
||||||
const { unprotectedRoutes, sensitiveRoutes } = require("../utils/protectedRoutes");
|
const methodOverride = require('method-override')
|
||||||
|
const {
|
||||||
|
unprotectedRoutes,
|
||||||
|
sensitiveRoutes,
|
||||||
|
nonEncryptedRoutes
|
||||||
|
} = require('../utils/protectedRoutes')
|
||||||
// load app default configuration data
|
// load app default configuration data
|
||||||
const defaults = require("../config/defaults")(program.mainnet);
|
const defaults = require('../config/defaults')(program.mainnet)
|
||||||
// define useful global variables ======================================
|
// define useful global variables ======================================
|
||||||
module.useTLS = program.usetls;
|
module.useTLS = program.usetls
|
||||||
module.serverPort = program.serverport || defaults.serverPort;
|
module.serverPort = program.serverport || defaults.serverPort
|
||||||
module.httpsPort = module.serverPort;
|
module.httpsPort = module.serverPort
|
||||||
module.serverHost = program.serverhost || defaults.serverHost;
|
module.serverHost = program.serverhost || defaults.serverHost
|
||||||
|
|
||||||
// setup winston logging ==========
|
// setup winston logging ==========
|
||||||
const logger = require("../config/log")(
|
const logger = require('../config/log')(
|
||||||
program.logfile || defaults.logfile,
|
program.logfile || defaults.logfile,
|
||||||
program.loglevel || defaults.loglevel
|
program.loglevel || defaults.loglevel
|
||||||
);
|
)
|
||||||
|
|
||||||
// utilities functions =================
|
// utilities functions =================
|
||||||
require("../utils/server-utils")(module);
|
require('../utils/server-utils')(module)
|
||||||
|
|
||||||
logger.info("Mainnet Mode:", !!program.mainnet);
|
logger.info('Mainnet Mode:', !!program.mainnet)
|
||||||
|
|
||||||
|
const modifyResponseBody = (req, res, next) => {
|
||||||
|
const deviceId = req.headers['x-shockwallet-device-id']
|
||||||
|
const oldSend = res.send
|
||||||
|
|
||||||
|
if (!nonEncryptedRoutes.includes(req.path)) {
|
||||||
|
res.send = (...args) => {
|
||||||
|
if (args[0] && args[0].encryptedData && args[0].encryptionKey) {
|
||||||
|
console.log('Response loop detected', req.path, args[0])
|
||||||
|
oldSend.apply(res, args)
|
||||||
|
} else {
|
||||||
|
// arguments[0] (or `data`) contains the response body
|
||||||
|
const authorized = Encryption.isAuthorizedDevice({ deviceId })
|
||||||
|
const encryptedMessage = authorized
|
||||||
|
? Encryption.encryptMessage({
|
||||||
|
message: args[0],
|
||||||
|
deviceId
|
||||||
|
})
|
||||||
|
: args[0]
|
||||||
|
args[0] = JSON.stringify(encryptedMessage)
|
||||||
|
oldSend.apply(res, args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
||||||
const wait = seconds =>
|
const wait = seconds =>
|
||||||
new Promise(resolve => {
|
new Promise(resolve => {
|
||||||
const timer = setTimeout(() => resolve(timer), seconds * 1000);
|
const timer = setTimeout(() => resolve(timer), seconds * 1000)
|
||||||
});
|
})
|
||||||
|
|
||||||
// eslint-disable-next-line consistent-return
|
// eslint-disable-next-line consistent-return
|
||||||
const startServer = async () => {
|
const startServer = async () => {
|
||||||
try {
|
try {
|
||||||
LightningServices.setDefaults(program);
|
LightningServices.setDefaults(program)
|
||||||
await LightningServices.init();
|
await LightningServices.init()
|
||||||
|
|
||||||
// init lnd module =================
|
// init lnd module =================
|
||||||
const lnd = require("../services/lnd/lnd")(LightningServices.services.lightning);
|
const lnd = require('../services/lnd/lnd')(
|
||||||
const auth = require("../services/auth/auth");
|
LightningServices.services.lightning
|
||||||
|
)
|
||||||
|
const auth = require('../services/auth/auth')
|
||||||
|
|
||||||
app.use(async (req, res, next) => {
|
app.use(async (req, res, next) => {
|
||||||
console.log("Route:", req.path)
|
console.log('Route:', req.path)
|
||||||
if (unprotectedRoutes[req.method][req.path]) {
|
if (unprotectedRoutes[req.method][req.path]) {
|
||||||
next();
|
next()
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const response = await auth.validateToken(
|
const response = await auth.validateToken(
|
||||||
req.headers.authorization.replace("Bearer ", "")
|
req.headers.authorization.replace('Bearer ', '')
|
||||||
);
|
)
|
||||||
if (response.valid) {
|
if (response.valid) {
|
||||||
next();
|
next()
|
||||||
} else {
|
} else {
|
||||||
res.status(401).json({ field: "authorization", errorMessage: "The authorization token you've supplied is invalid" });
|
res.status(401).json({
|
||||||
|
field: 'authorization',
|
||||||
|
errorMessage:
|
||||||
|
"The authorization token you've supplied is invalid"
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(
|
logger.error(
|
||||||
!req.headers.authorization
|
!req.headers.authorization
|
||||||
? "Please add an Authorization header"
|
? 'Please add an Authorization header'
|
||||||
: err
|
: err
|
||||||
);
|
)
|
||||||
res.status(401).json({ field: "authorization", errorMessage: "Please log in" });
|
res
|
||||||
|
.status(401)
|
||||||
|
.json({ field: 'authorization', errorMessage: 'Please log in' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
if (sensitiveRoutes[req.method][req.path]) {
|
if (sensitiveRoutes[req.method][req.path]) {
|
||||||
|
|
@ -84,7 +125,7 @@ const server = program => {
|
||||||
path: req.path,
|
path: req.path,
|
||||||
sessionId: req.sessionId
|
sessionId: req.sessionId
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
} else {
|
} else {
|
||||||
console.log(
|
console.log(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|
@ -96,10 +137,10 @@ const server = program => {
|
||||||
query: req.query,
|
query: req.query,
|
||||||
sessionId: req.sessionId
|
sessionId: req.sessionId
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
next();
|
next()
|
||||||
});
|
})
|
||||||
app.use(
|
app.use(
|
||||||
session({
|
session({
|
||||||
secret: defaults.sessionSecret,
|
secret: defaults.sessionSecret,
|
||||||
|
|
@ -108,79 +149,84 @@ const server = program => {
|
||||||
rolling: true,
|
rolling: true,
|
||||||
saveUninitialized: true
|
saveUninitialized: true
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
app.use(bodyParser.urlencoded({ extended: "true" }));
|
app.use(bodyParser.urlencoded({ extended: 'true' }))
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json())
|
||||||
app.use(bodyParser.json({ type: "application/vnd.api+json" }));
|
app.use(bodyParser.json({ type: 'application/vnd.api+json' }))
|
||||||
app.use(methodOverride());
|
app.use(methodOverride())
|
||||||
// WARNING
|
// WARNING
|
||||||
// error handler middleware, KEEP 4 parameters as express detects the
|
// error handler middleware, KEEP 4 parameters as express detects the
|
||||||
// arity of the function to treat it as a err handling middleware
|
// arity of the function to treat it as a err handling middleware
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
app.use((err, _, res, __) => {
|
app.use((err, _, res, __) => {
|
||||||
// Do logging and user-friendly error message display
|
// Do logging and user-friendly error message display
|
||||||
logger.error(err);
|
logger.error(err)
|
||||||
res
|
res.status(500).send({ status: 500, errorMessage: 'internal error' })
|
||||||
.status(500)
|
})
|
||||||
.send({ status: 500, errorMessage: "internal error" });
|
|
||||||
});
|
const CA = LightningServices.servicesConfig.lndCertPath
|
||||||
|
const CA_KEY = CA.replace('cert', 'key')
|
||||||
|
|
||||||
const createServer = async () => {
|
const createServer = async () => {
|
||||||
try {
|
try {
|
||||||
if (program.usetls) {
|
if (LightningServices.servicesConfig.lndCertPath && program.usetls) {
|
||||||
const [key, cert] = await Promise.all([
|
const [key, cert] = await Promise.all([
|
||||||
FS.readFile(program.usetls + "/key.pem"),
|
FS.readFile(CA_KEY),
|
||||||
FS.readFile(program.usetls + "/cert.pem")
|
FS.readFile(CA)
|
||||||
]);
|
])
|
||||||
const httpsServer = Https.createServer({ key, cert }, app);
|
const httpsServer = Https.createServer({ key, cert }, app)
|
||||||
|
|
||||||
return httpsServer;
|
return httpsServer
|
||||||
}
|
}
|
||||||
|
|
||||||
const httpServer = Http.Server(app);
|
const httpServer = Http.Server(app)
|
||||||
return httpServer;
|
return httpServer
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(err.message);
|
logger.error(err.message)
|
||||||
throw err;
|
logger.error(
|
||||||
|
'An error has occurred while finding an LND cert to use to open an HTTPS server'
|
||||||
|
)
|
||||||
|
logger.warn('Falling back to opening an HTTP server...')
|
||||||
|
const httpServer = Http.Server(app)
|
||||||
|
return httpServer
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const serverInstance = await createServer();
|
const serverInstance = await createServer()
|
||||||
|
|
||||||
const io = require("socket.io")(serverInstance);
|
const io = require('socket.io')(serverInstance)
|
||||||
|
|
||||||
const Sockets = require("./sockets")(
|
const Sockets = require('./sockets')(
|
||||||
io,
|
io,
|
||||||
lnd,
|
lnd,
|
||||||
program.user,
|
program.user,
|
||||||
program.pwd,
|
program.pwd,
|
||||||
program.limituser,
|
program.limituser,
|
||||||
program.limitpwd
|
program.limitpwd
|
||||||
);
|
)
|
||||||
|
|
||||||
require("./routes")(
|
require('./routes')(app, defaults, Sockets, {
|
||||||
app,
|
serverHost: module.serverHost,
|
||||||
defaults,
|
serverPort: module.serverPort,
|
||||||
Sockets,
|
usetls: program.usetls,
|
||||||
{
|
CA,
|
||||||
serverHost: module.serverHost,
|
CA_KEY
|
||||||
serverPort: module.serverPort
|
})
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// enable CORS headers
|
// enable CORS headers
|
||||||
app.use(require("./cors"));
|
app.use(require('./cors'))
|
||||||
// app.use(bodyParser.json({limit: '100000mb'}));
|
// app.use(bodyParser.json({limit: '100000mb'}));
|
||||||
app.use(bodyParser.json({ limit: "50mb" }));
|
app.use(bodyParser.json({ limit: '50mb' }))
|
||||||
app.use(bodyParser.urlencoded({ limit: "50mb", extended: true }));
|
app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }))
|
||||||
|
app.use(modifyResponseBody)
|
||||||
|
|
||||||
serverInstance.listen(module.serverPort, module.serverhost);
|
serverInstance.listen(module.serverPort, module.serverhost)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
"App listening on " + module.serverHost + " port " + module.serverPort
|
'App listening on ' + module.serverHost + ' port ' + module.serverPort
|
||||||
);
|
)
|
||||||
|
|
||||||
module.server = serverInstance;
|
module.server = serverInstance
|
||||||
|
|
||||||
// const localtunnel = require('localtunnel');
|
// const localtunnel = require('localtunnel');
|
||||||
//
|
//
|
||||||
|
|
@ -189,15 +235,15 @@ const server = program => {
|
||||||
// console.log('t', t.url);
|
// console.log('t', t.url);
|
||||||
// });
|
// });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.info(err);
|
logger.info(err)
|
||||||
logger.info("Restarting server in 30 seconds...");
|
logger.info('Restarting server in 30 seconds...')
|
||||||
await wait(30);
|
await wait(30)
|
||||||
startServer();
|
startServer()
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
startServer();
|
startServer()
|
||||||
};
|
}
|
||||||
|
|
||||||
module.exports = server;
|
module.exports = server
|
||||||
|
|
|
||||||
125
utils/encryptionStore.js
Normal file
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/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