From 9a3dbdb5f581a61543e74fc8909cc24bfcdff386 Mon Sep 17 00:00:00 2001 From: emad-salah Date: Tue, 17 Dec 2019 13:25:25 +0100 Subject: [PATCH 1/2] API now checks for wallet unlock status before executing any requests --- src/routes.js | 49 ++++++++++++++++++++++++++++++++++++++++ src/server.js | 42 ++++++++-------------------------- utils/protectedRoutes.js | 30 ++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 33 deletions(-) create mode 100644 utils/protectedRoutes.js diff --git a/src/routes.js b/src/routes.js index f110c274..67a3e19c 100644 --- a/src/routes.js +++ b/src/routes.js @@ -14,6 +14,7 @@ const auth = require("../services/auth/auth"); const FS = require("../utils/fs"); const LightningServices = require("../utils/lightningServices"); const GunDB = require("../services/gunDB/Mediator"); +const { unprotectedRoutes } = require("../utils/protectedRoutes"); const DEFAULT_MAX_NUM_ROUTES_TO_QUERY = 10; @@ -181,6 +182,54 @@ module.exports = ( } }; + app.use(async (req, res, next) => { + try { + console.log("Route:", req.path) + + if (unprotectedRoutes[req.method][req.path]) { + next(); + return; + } + + if (req.path.includes("/api/lnd")) { + const walletStatus = await walletExists(); + const availableService = await getAvailableService(); + const statusMessage = availableService.walletStatus; + if (walletStatus) { + if (statusMessage === "unlocked") { + return next(); + } + + return res + .status(401) + .json({ + field: "wallet", + errorMessage: statusMessage + ? statusMessage + : "unknown" + }) + } + + return res + .status(401) + .json({ + field: "wallet", + errorMessage: "Please create a wallet before using the API" + }); + } + } catch (err) { + logger.error(err); + res + .status(500) + .json({ + field: "wallet", + errorMessage: err.message + ? err.message + : err + }); + } + }); + app.use(["/ping"], responseTime()); /** diff --git a/src/server.js b/src/server.js index cc81b9d1..b52f0210 100644 --- a/src/server.js +++ b/src/server.js @@ -9,11 +9,12 @@ const server = program => { const Express = require("express"); const LightningServices = require("../utils/lightningServices"); const app = Express(); - + const FS = require("../utils/fs"); const bodyParser = require("body-parser"); const session = require("express-session"); const methodOverride = require("method-override"); + const { unprotectedRoutes, sensitiveRoutes } = require("../utils/protectedRoutes"); // load app default configuration data const defaults = require("../config/defaults")(program.mainnet); // define useful global variables ====================================== @@ -46,26 +47,6 @@ const server = program => { // init lnd module ================= const lnd = require("../services/lnd/lnd")(LightningServices.services.lightning); - - const unprotectedRoutes = { - GET: { - "/healthz": true, - "/ping": true, - // Errors out when viewing an API page from the browser - "/favicon.ico": true, - "/api/lnd/connect": true, - "/api/lnd/wallet/status": true, - "/api/lnd/auth": true - }, - POST: { - "/api/lnd/connect": true, - "/api/lnd/wallet": true, - "/api/lnd/wallet/existing": true, - "/api/lnd/auth": true - }, - PUT: {}, - DELETE: {} - }; const auth = require("../services/auth/auth"); app.use(async (req, res, next) => { @@ -80,24 +61,19 @@ const server = program => { if (response.valid) { next(); } else { - res.status(401).json({ message: "Please log in" }); + res.status(401).json({ field: "authorization", errorMessage: "The authorization token you've supplied is invalid" }); } } catch (err) { - logger.error(err); - res.status(401).json({ message: "Please log in" }); + logger.error( + !req.headers.authorization + ? "Please add an Authorization header" + : err + ); + res.status(401).json({ field: "authorization", errorMessage: "Please log in" }); } } }); - const sensitiveRoutes = { - GET: {}, - POST: { - "/api/lnd/connect": true, - "/api/lnd/wallet": true - }, - PUT: {}, - DELETE: {} - }; app.use((req, res, next) => { if (sensitiveRoutes[req.method][req.path]) { console.log( diff --git a/utils/protectedRoutes.js b/utils/protectedRoutes.js new file mode 100644 index 00000000..a0b53ca7 --- /dev/null +++ b/utils/protectedRoutes.js @@ -0,0 +1,30 @@ +module.exports = { + unprotectedRoutes: { + GET: { + "/healthz": true, + "/ping": true, + // Errors out when viewing an API page from the browser + "/favicon.ico": true, + "/api/lnd/connect": true, + "/api/lnd/wallet/status": true, + "/api/lnd/auth": true + }, + POST: { + "/api/lnd/connect": true, + "/api/lnd/wallet": true, + "/api/lnd/wallet/existing": true, + "/api/lnd/auth": true + }, + PUT: {}, + DELETE: {} + }, + sensitiveRoutes: { + GET: {}, + POST: { + "/api/lnd/connect": true, + "/api/lnd/wallet": true + }, + PUT: {}, + DELETE: {} + } +} \ No newline at end of file From 2280fb1d174099f2c6df5663c239572e9b8d2c0f Mon Sep 17 00:00:00 2001 From: emad-salah Date: Tue, 17 Dec 2019 14:18:46 +0100 Subject: [PATCH 2/2] Minor auth token fix --- .eslintrc.json | 4 +++- services/auth/auth.js | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index d1038cb0..8bd8ef46 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -60,7 +60,9 @@ "consistent-return": "off", - "no-shadow": "off" + "no-shadow": "off", + // We're usually throwing objects throughout the API to allow for more detailed error messages + "no-throw-literal": "off" }, "parser": "babel-eslint", "env": { diff --git a/services/auth/auth.js b/services/auth/auth.js index a9f786e5..ede8219d 100644 --- a/services/auth/auth.js +++ b/services/auth/auth.js @@ -108,6 +108,9 @@ class Auth { const key = jwt.decode(token).data.timestamp const secrets = await this.readSecrets() const secret = secrets[key] + if (!secret) { + throw { valid: false } + } return new Promise((resolve, reject) => { jwt.verify(token, secret, (err, decoded) => { if (err) {