Browse Source

lnd api

power-cycle
Mayank 4 years ago
parent
commit
148b78b5b9
  1. 28
      logic/auth.js
  2. 21
      middlewares/incorrectPasswordAuthHandler.js
  3. 5
      package.json
  4. 35
      routes/v1/account.js
  5. 73
      services/lndApi.js
  6. 2
      utils/jwt.js

28
logic/auth.js

@ -2,7 +2,7 @@ const bcrypt = require('bcrypt');
const iocane = require("iocane");
const diskLogic = require('logic/disk.js');
// const dockerComposeLogic = require('logic/docker-compose.js');
// const lnapiService = require('services/lnapi.js');
const lndApiService = require('services/lndApi.js');
const bashService = require('services/bash.js');
const NodeError = require('models/errors.js').NodeError;
const JWTHelper = require('utils/jwt.js');
@ -57,7 +57,7 @@ async function changePassword(currentPassword, newPassword, jwt) {
// call lnapi to change password
changePasswordStatus.percent = 60 + attempt; // eslint-disable-line no-magic-numbers
// await lnapiService.changePassword(currentPassword, newPassword, jwt);
await lndApiService.changePassword(currentPassword, newPassword, jwt);
// update user file
const user = await diskLogic.readUserFile();
@ -67,8 +67,7 @@ async function changePassword(currentPassword, newPassword, jwt) {
const decryptedSeed = await iocane.createSession().decrypt(user.seed, currentPassword);
const encryptedSeed = await iocane.createSession().encrypt(decryptedSeed, newPassword);
// replace user file
// await diskLogic.deleteUserFile();
// update user file
await diskLogic.writeUserFile({ name: user.name, password: credentials.password, seed: encryptedSeed });
// update ssh password
@ -140,14 +139,30 @@ async function login(user) {
// cachePassword(user.plainTextPassword);
cachePassword(user.password);
//unlock lnd wallet
// await lndApiService.unlock(user.plainTextPassword, jwt);
return { jwt: jwt };
} catch (error) {
console.log(error);
throw new NodeError('Unable to generate JWT');
}
}
async function getInfo() {
try {
const user = await diskLogic.readUserFile();
//remove sensitive info
delete user.password;
delete user.seed;
return user;
} catch (error) {
throw new NodeError('Unable to get account info');
}
};
async function seed(user) {
//Decrypt mnemonic seed
@ -195,7 +210,7 @@ async function register(user, seed) {
//initialize lnd wallet
try {
// await lnapiService.initializeWallet(user.plainTextPassword, seed, jwt);
await lndApiService.initializeWallet(user.plainTextPassword, seed, jwt);
} catch (error) {
await diskLogic.deleteUserFile();
throw new NodeError(error.response.data);
@ -223,6 +238,7 @@ module.exports = {
getChangePasswordStatus,
hashCredentials,
isRegistered,
getInfo,
seed,
login,
register,

21
middlewares/incorrectPasswordAuthHandler.js

@ -0,0 +1,21 @@
/* eslint-disable no-unused-vars, no-magic-numbers */
const constants = require('utils/const.js');
const NodeError = require('models/errors.js').NodeError;
function handleError(error, req, res, next) {
// If a incorrect password was given, respond with 403 instead of 401.
// Reasoning: sending 401 on a request such as when the user tries to
// change password with an incorrect password or enters an incorrect
// password to view seed will log him out due to interceptor on front-end
if (error.message && error.message === 'Incorrect password') {
return next(new NodeError('Incorrect password', 403));
} else {
return next();
}
}
module.exports = handleError;

5
package.json

@ -1,16 +1,17 @@
{
"name": "umbrel-manager",
"version": "0.0.0",
"version": "0.1.0",
"description": "Manager for Umbrel Node",
"author": "Umbrel",
"scripts": {
"lint": "eslint",
"start": "nodemon --exec node ./bin/www",
"start": "node ./bin/www",
"test": "mocha --file test.setup 'test/**/*.js'",
"coverage": "nyc --all mocha --file test.setup 'test/**/*.js'",
"postcoverage": "codecov"
},
"dependencies": {
"axios": "^0.19.2",
"bcrypt": "^4.0.1",
"big.js": "^5.2.2",
"body-parser": "^1.18.2",

35
routes/v1/account.js

@ -5,6 +5,7 @@ const router = express.Router();
const authLogic = require('logic/auth.js');
const auth = require('middlewares/auth.js');
const incorrectPasswordAuthHandler = require('middlewares/incorrectPasswordAuthHandler.js');
const constants = require('utils/const.js');
const safeHandler = require('utils/safeHandler');
@ -14,7 +15,7 @@ const COMPLETE = 100;
// Endpoint to change your lnd password. Wallet must exist and be unlocked. This endpoint is authorized with basic auth
// or the property password from the body.
router.post('/change-password', auth.convertReqBodyToBasicAuth, auth.basic,
router.post('/change-password', auth.convertReqBodyToBasicAuth, auth.basic, incorrectPasswordAuthHandler,
safeHandler(async (req, res, next) => {
// Use password from the body by default. Basic auth has issues handling special characters.
@ -49,13 +50,13 @@ router.post('/change-password', auth.convertReqBodyToBasicAuth, auth.basic,
}));
// Returns the current status of the change password process.
router.get('/changePassword/status', auth.jwt, safeHandler(async (req, res) => {
router.get('/change-password/status', auth.jwt, safeHandler(async (req, res) => {
const status = await authLogic.getChangePasswordStatus();
return res.status(constants.STATUS_CODES.OK).json(status);
}));
// Registered does not need auth.This is because the user may not be registered at the time and thus won't always have
// Registered does not need auth. This is because the user may not be registered at the time and thus won't always have
// an auth token.
router.get('/registered', safeHandler((req, res) =>
authLogic.isRegistered()
@ -66,9 +67,6 @@ router.get('/registered', safeHandler((req, res) =>
// or the property password from the body.
router.post('/register', auth.convertReqBodyToBasicAuth, auth.register, safeHandler(async (req, res, next) => {
// return res.json({ seed: req.body.seed });
const seed = req.body.seed;
if (seed.length !== 24) { // eslint-disable-line no-magic-numbers
@ -83,11 +81,10 @@ router.post('/register', auth.convertReqBodyToBasicAuth, auth.register, safeHand
return next(error);
}
const user = {
name: req.body.name,
password: req.user.password,
plainTextPassword: req.user.plainTextPassword
};
const user = req.user;
//add name to user obj
user.name = req.body.name;
const jwt = await authLogic.register(user, seed);
@ -102,7 +99,13 @@ router.post('/login', auth.convertReqBodyToBasicAuth, auth.basic, safeHandler(as
));
router.post('/seed', auth.convertReqBodyToBasicAuth, auth.basic, safeHandler(async (req, res) => {
router.get('/info', auth.jwt, safeHandler(async (req, res) => {
const info = await authLogic.getInfo();
return res.status(constants.STATUS_CODES.OK).json(info);
}));
router.post('/seed', auth.convertReqBodyToBasicAuth, auth.basic, incorrectPasswordAuthHandler, safeHandler(async (req, res) => {
const seed = await authLogic.seed(req.user);
return res.json(seed);
@ -110,9 +113,9 @@ router.post('/seed', auth.convertReqBodyToBasicAuth, auth.basic, safeHandler(asy
));
// router.post('/refresh', auth.jwt, safeHandler((req, res) =>
// applicationLogic.refresh(req.user)
// .then(jwt => res.json(jwt))
// ));
router.post('/refresh', auth.jwt, safeHandler((req, res) =>
authLogic.refresh(req.user)
.then(jwt => res.json(jwt))
));
module.exports = router;

73
services/lndApi.js

@ -0,0 +1,73 @@
const axios = require('axios');
// axios requires http
const lnapiUrl = process.env.LND_API_URL || 'http://localhost';
const lnapiPort = process.env.LND_API_URL || 3005;
async function changePassword(currentPassword, newPassword, jwt) {
const headers = {
headers: {
Authorization: 'JWT ' + jwt,
}
};
const body = {
currentPassword,
newPassword,
};
return axios
.post(lnapiUrl + ':' + lnapiPort + '/v1/lnd/wallet/changePassword', body, headers);
}
async function initializeWallet(password, seed, jwt) {
const headers = {
headers: {
Authorization: 'JWT ' + jwt,
}
};
const body = {
password,
seed,
};
return axios
.post(lnapiUrl + ':' + lnapiPort + '/v1/lnd/wallet/init', body, headers);
}
async function unlockLnd(password, jwt) {
const headers = {
headers: {
Authorization: 'JWT ' + jwt,
}
};
const body = {
password,
};
return axios
.post(lnapiUrl + ':' + lnapiPort + '/v1/lnd/wallet/unlock', body, headers);
}
async function getBitcoindAddresses(jwt) {
const headers = {
headers: {
Authorization: 'JWT ' + jwt,
}
};
return axios
.get(lnapiUrl + ':' + lnapiPort + '/v1/bitcoind/info/addresses', headers);
}
module.exports = {
changePassword,
initializeWallet,
unlockLnd,
getBitcoindAddresses,
};

2
utils/jwt.js

@ -3,7 +3,7 @@ const diskLogic = require('logic/disk.js');
// Environmental variables are Strings, the expiry will be interpreted as milliseconds if not converted to int.
// eslint-disable-next-line no-magic-numbers
const expiresIn = process.env.JWT_EXPIRATION ? parseInt(process.env.JWT_EXPIRATION, 3600) : 3600;
const expiresIn = process.env.JWT_EXPIRATION ? parseInt(process.env.JWT_EXPIRATION) : 3600;
async function generateJWT(account) {

Loading…
Cancel
Save