mirror of
https://github.com/alexbosworth/balanceofsatoshis.git
synced 2026-08-13 12:33:37 +02:00
add more lnd path selection options
This commit is contained in:
parent
e94a9ad14a
commit
22317a992f
10 changed files with 179 additions and 24 deletions
|
|
@ -1,5 +1,10 @@
|
|||
# Versions
|
||||
|
||||
## 12.12.0
|
||||
|
||||
- Add `BOS_DEFAULT_LND_PATH` to set the default path to LND data directory
|
||||
- Adjust support for Umbrel LND path detection
|
||||
|
||||
## 12.11.2
|
||||
|
||||
- `telegram`: Add inbound and outbound fee rates to /liquidity message
|
||||
|
|
|
|||
|
|
@ -204,6 +204,10 @@ Default LND directories:
|
|||
|
||||
It will check first for a mainnet macaroon, then a testnet macaroon.
|
||||
|
||||
The LND directory can be overriden with an environment variable:
|
||||
|
||||
`BOS_DEFAULT_LND_PATH=/path/to/lnd/data/dir`
|
||||
|
||||
### Saved Nodes
|
||||
|
||||
If you have another node and it is already using `balanceofsatoshis`, you can
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ const certPath = ['tls.cert'];
|
|||
platform: <Platform Function> () => <Platform Name String>
|
||||
userInfo: <User Info Function> () => {username: <User Name String>}
|
||||
}
|
||||
[path]: <Lnd Data Directory Path String>
|
||||
}
|
||||
|
||||
@returns via cbk or Promise
|
||||
|
|
@ -28,7 +29,7 @@ const certPath = ['tls.cert'];
|
|||
[cert]: <Cert File Base64 Encoded String>
|
||||
}
|
||||
*/
|
||||
module.exports = ({fs, node, os}, cbk) => {
|
||||
module.exports = ({fs, node, os, path}, cbk) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
return asyncAuto({
|
||||
// Check arguments
|
||||
|
|
@ -50,9 +51,9 @@ module.exports = ({fs, node, os}, cbk) => {
|
|||
return cbk();
|
||||
}
|
||||
|
||||
const {path} = lndDirectory({os});
|
||||
const dir = path || lndDirectory({os}).path;
|
||||
|
||||
return fs.getFile(join(...[path].concat(certPath)), (err, cert) => {
|
||||
return fs.getFile(join(...[dir].concat(certPath)), (err, cert) => {
|
||||
if (!!err) {
|
||||
return cbk([503, 'UnexpectedErrorGettingCertFileData', {err}]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ const macName = 'admin.macaroon';
|
|||
platform: <Platform Function> () => <Platform Name String>
|
||||
userInfo: <User Info Function> () => {username: <User Name String>}
|
||||
}
|
||||
[path]: <LND Data Directory Path String>
|
||||
}
|
||||
|
||||
@returns via cbk or Promise
|
||||
|
|
@ -30,7 +31,7 @@ const macName = 'admin.macaroon';
|
|||
[macaroon]: <Base64 Encoded Macaroon String>
|
||||
}
|
||||
*/
|
||||
module.exports = ({fs, node, os}, cbk) => {
|
||||
module.exports = ({fs, node, os, path}, cbk) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
return asyncAuto({
|
||||
// Check arguments
|
||||
|
|
@ -55,7 +56,7 @@ module.exports = ({fs, node, os}, cbk) => {
|
|||
|
||||
const [chains, nets] = defaults;
|
||||
let defaultMacaroon;
|
||||
const {path} = lndDirectory({os});
|
||||
const dir = path || lndDirectory({os}).path;
|
||||
|
||||
const all = chains.map(chain => {
|
||||
return nets.map(network => ({chain, network}));
|
||||
|
|
@ -65,7 +66,7 @@ module.exports = ({fs, node, os}, cbk) => {
|
|||
return asyncDetectSeries(flatten(all), ({chain, network}, cbk) => {
|
||||
const macPath = [].concat(macDirs).concat([chain, network, macName]);
|
||||
|
||||
return fs.getFile(join(...[path].concat(macPath)), (_, macaroon) => {
|
||||
return fs.getFile(join(...[dir].concat(macPath)), (_, macaroon) => {
|
||||
defaultMacaroon = macaroon;
|
||||
|
||||
return cbk(null, !!defaultMacaroon);
|
||||
|
|
|
|||
71
lnd/get_path.js
Normal file
71
lnd/get_path.js
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
const {join} = require('path');
|
||||
|
||||
const asyncAuto = require('async/auto');
|
||||
const asyncDetect = require('async/detect');
|
||||
const {returnResult} = require('asyncjs-util');
|
||||
|
||||
const certPath = ['tls.cert'];
|
||||
const umbrelUser = 'umbrel';
|
||||
const umbrelV0Path = '/home/umbrel/umbrel/lnd';
|
||||
const umbrelV1Path = '/home/umbrel/umbrel/app-data/lightning/data/lnd';
|
||||
|
||||
/** Look for the LND directory path
|
||||
|
||||
{
|
||||
fs: {
|
||||
getFile: <Get File Function>
|
||||
}
|
||||
os: {
|
||||
userInfo: <Get User Info Function>
|
||||
}
|
||||
}
|
||||
|
||||
@returns via cbk or Promise
|
||||
{
|
||||
[path]: <Found LND Directory Path String>
|
||||
}
|
||||
*/
|
||||
module.exports = ({fs, os}, cbk) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
return asyncAuto({
|
||||
// Check arguments
|
||||
validate: cbk => {
|
||||
if (!fs) {
|
||||
return cbk([400, 'ExpectedFileSystemMethodsToGetPath']);
|
||||
}
|
||||
|
||||
if (!os) {
|
||||
return cbk([400, 'ExpectedOperatingSystemMethodsToGetPath']);
|
||||
}
|
||||
|
||||
return cbk();
|
||||
},
|
||||
|
||||
// Paths to look for
|
||||
paths: ['validate', ({}, cbk) => {
|
||||
// Exit early when the user is not Umbrel
|
||||
if (os.userInfo().username !== umbrelUser) {
|
||||
return cbk(null, []);
|
||||
}
|
||||
|
||||
return cbk(null, [umbrelV0Path, umbrelV1Path]);
|
||||
}],
|
||||
|
||||
// Look through the paths to find a cert file
|
||||
findCert: ['paths', ({paths}, cbk) => {
|
||||
return asyncDetect(paths, (path, cbk) => {
|
||||
return fs.getFile(join(...[path].concat(certPath)), (err, cert) => {
|
||||
return cbk(null, !err && !!cert);
|
||||
});
|
||||
},
|
||||
cbk);
|
||||
}],
|
||||
|
||||
// Final path result
|
||||
path: ['findCert', ({findCert}, cbk) => {
|
||||
return cbk(null, {path: findCert || undefined});
|
||||
}],
|
||||
},
|
||||
returnResult({reject, resolve, of: 'path'}, cbk));
|
||||
});
|
||||
};
|
||||
|
|
@ -25,6 +25,7 @@ const scheme = 'rpc://';
|
|||
platform: <Platform Function> () => <Platform Name String>
|
||||
userInfo: <User Info Function> () => {username: <User Name String>}
|
||||
}
|
||||
[path]: <Lnd Data Directory Path String>
|
||||
}
|
||||
|
||||
@returns via cbk or Promise
|
||||
|
|
@ -32,7 +33,7 @@ const scheme = 'rpc://';
|
|||
[socket]: <RPC Socket String>
|
||||
}
|
||||
*/
|
||||
module.exports = ({fs, node, os}, cbk) => {
|
||||
module.exports = ({fs, node, os, path}, cbk) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
return asyncAuto({
|
||||
// Check arguments
|
||||
|
|
@ -55,9 +56,9 @@ module.exports = ({fs, node, os}, cbk) => {
|
|||
return cbk();
|
||||
}
|
||||
|
||||
const {path} = lndDirectory({os});
|
||||
const dir = path || lndDirectory({os}).path;
|
||||
|
||||
return fs.getFile(join(...[path].concat(confPath)), (err, conf) => {
|
||||
return fs.getFile(join(...[dir].concat(confPath)), (err, conf) => {
|
||||
// Don't report errors, the conf file is either there or not
|
||||
return cbk(null, conf);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,12 +17,14 @@ const {decryptCiphertext} = require('./../encryption');
|
|||
const {derAsPem} = require('./../encryption');
|
||||
const getCert = require('./get_cert');
|
||||
const getMacaroon = require('./get_macaroon');
|
||||
const getPath = require('./get_path');
|
||||
const {getSavedCredentials} = require('./../nodes');
|
||||
const getSocket = require('./get_socket');
|
||||
const {noSpendPerms} = require('./constants');
|
||||
const {permissionEntities} = require('./constants');
|
||||
|
||||
const config = 'config.json';
|
||||
const defaultLndDirPath = process.env.BOS_DEFAULT_LND_PATH;
|
||||
const defaultNodeName = process.env.BOS_DEFAULT_SAVED_NODE;
|
||||
const fs = {getFile: readFile};
|
||||
const home = '.bos';
|
||||
|
|
@ -89,14 +91,29 @@ module.exports = (args, cbk) => {
|
|||
});
|
||||
},
|
||||
|
||||
// Look for a special path
|
||||
getPath: ['forNode', ({forNode}, cbk) => {
|
||||
// Exit early when a specific node is used
|
||||
if (!!forNode) {
|
||||
return cbk(null, {});
|
||||
}
|
||||
|
||||
// Exit early when there is a default LND path
|
||||
if (!!defaultLndDirPath) {
|
||||
return cbk(null, {path: defaultLndDirPath});
|
||||
}
|
||||
|
||||
return getPath({fs, os}, cbk);
|
||||
}],
|
||||
|
||||
// Get the default cert
|
||||
getCert: ['forNode', ({forNode}, cbk) => {
|
||||
return getCert({fs, os, node: forNode}, cbk);
|
||||
getCert: ['forNode', 'getPath', ({forNode, getPath}, cbk) => {
|
||||
return getCert({fs, os, node: forNode, path: getPath.path}, cbk);
|
||||
}],
|
||||
|
||||
// Get the default macaroon
|
||||
getMacaroon: ['forNode', ({forNode}, cbk) => {
|
||||
return getMacaroon({fs, os, node: forNode}, cbk);
|
||||
getMacaroon: ['forNode', 'getPath', ({forNode, getPath}, cbk) => {
|
||||
return getMacaroon({fs, os, node: forNode, path: getPath.path}, cbk);
|
||||
}],
|
||||
|
||||
// Get the node credentials, if applicable
|
||||
|
|
@ -109,8 +126,8 @@ module.exports = (args, cbk) => {
|
|||
}],
|
||||
|
||||
// Get the socket out of the ini file
|
||||
getSocket: ['forNode', ({forNode}, cbk) => {
|
||||
return getSocket({fs, os, node: forNode}, cbk);
|
||||
getSocket: ['forNode', 'getPath', ({forNode, getPath}, cbk) => {
|
||||
return getSocket({fs, os, node: forNode, path: getPath.path}, cbk);
|
||||
}],
|
||||
|
||||
// Node credentials
|
||||
|
|
|
|||
16
package-lock.json
generated
16
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "balanceofsatoshis",
|
||||
"version": "12.11.2",
|
||||
"version": "12.12.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "balanceofsatoshis",
|
||||
"version": "12.11.2",
|
||||
"version": "12.12.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alexbosworth/caporal": "1.4.4",
|
||||
|
|
@ -4460,9 +4460,9 @@
|
|||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.150",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.150.tgz",
|
||||
"integrity": "sha512-MP3oBer0X7ZeS9GJ0H6lmkn561UxiwOIY9TTkdxVY7lI9G6GVCKfgJaHaDcakwdKxBXA4T3ybeswH/WBIN/KTA==",
|
||||
"version": "1.4.151",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.151.tgz",
|
||||
"integrity": "sha512-XaG2LpZi9fdiWYOqJh0dJy4SlVywCvpgYXhzOlZTp4JqSKqxn5URqOjbm9OMYB3aInA2GuHQiem1QUOc1yT0Pw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/elliptic": {
|
||||
|
|
@ -13840,9 +13840,9 @@
|
|||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.4.150",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.150.tgz",
|
||||
"integrity": "sha512-MP3oBer0X7ZeS9GJ0H6lmkn561UxiwOIY9TTkdxVY7lI9G6GVCKfgJaHaDcakwdKxBXA4T3ybeswH/WBIN/KTA==",
|
||||
"version": "1.4.151",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.151.tgz",
|
||||
"integrity": "sha512-XaG2LpZi9fdiWYOqJh0dJy4SlVywCvpgYXhzOlZTp4JqSKqxn5URqOjbm9OMYB3aInA2GuHQiem1QUOc1yT0Pw==",
|
||||
"dev": true
|
||||
},
|
||||
"elliptic": {
|
||||
|
|
|
|||
|
|
@ -84,5 +84,5 @@
|
|||
"postpublish": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t alexbosworth/balanceofsatoshis --push .",
|
||||
"test": "tap --branches=1 --functions=1 --lines=1 --statements=1 -t 60 test/arrays/*.js test/balances/*.js test/chain/*.js test/display/*.js test/encryption/*.js test/lnd/*.js test/network/*.js test/nodes/*.js test/peers/*.js test/responses/*.js test/routing/*.js test/services/*.js test/swaps/*.js test/tags/*.js test/telegram/*.js test/wallets/*.js"
|
||||
},
|
||||
"version": "12.11.2"
|
||||
"version": "12.12.0"
|
||||
}
|
||||
|
|
|
|||
55
test/lnd/test_get_path.js
Normal file
55
test/lnd/test_get_path.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
const {test} = require('@alexbosworth/tap');
|
||||
|
||||
const getPath = require('./../../lnd/get_path');
|
||||
|
||||
const os = {userInfo: () => ({username: 'umbrel'})};
|
||||
|
||||
const tests = [
|
||||
{
|
||||
args: {},
|
||||
description: 'File system methods are required',
|
||||
error: [400, 'ExpectedFileSystemMethodsToGetPath'],
|
||||
},
|
||||
{
|
||||
args: {fs: {getFile: () => {}}},
|
||||
description: 'OS methods are required',
|
||||
error: [400, 'ExpectedOperatingSystemMethodsToGetPath'],
|
||||
},
|
||||
{
|
||||
args: {os, fs: {getFile: ({}, cbk) => cbk('err')}},
|
||||
description: 'A filesystem error results in no path',
|
||||
expected: {path: undefined},
|
||||
},
|
||||
{
|
||||
args: {os, fs: {getFile: ({}, cbk) => cbk()}},
|
||||
description: 'An absent file results in no path',
|
||||
expected: {path: undefined},
|
||||
},
|
||||
{
|
||||
args: {
|
||||
fs: {getFile: ({}, cbk) => cbk()},
|
||||
os: {userInfo: () => ({username: 'username'})},
|
||||
},
|
||||
description: 'A normal user returns no path',
|
||||
expected: {path: undefined},
|
||||
},
|
||||
{
|
||||
args: {os, fs: {getFile: ({}, cbk) => cbk(null, Buffer.alloc(1))}},
|
||||
description: 'A path is returned',
|
||||
expected: {path: '/home/umbrel/umbrel/lnd'},
|
||||
},
|
||||
];
|
||||
|
||||
tests.forEach(({args, description, error, expected}) => {
|
||||
return test(description, async ({end, rejects, strictSame}) => {
|
||||
if (!!error) {
|
||||
await rejects(getPath(args), error, 'Got expected error');
|
||||
} else {
|
||||
const res = await getPath(args);
|
||||
|
||||
strictSame(res, expected, 'Got expected result');
|
||||
}
|
||||
|
||||
return end();
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue