diff --git a/app/lib/lnd/lightning.js b/app/lib/lnd/lightning.js index 499df485..961d8293 100644 --- a/app/lib/lnd/lightning.js +++ b/app/lib/lnd/lightning.js @@ -5,7 +5,8 @@ import { loadSync } from '@grpc/proto-loader' import { BrowserWindow } from 'electron' import StateMachine from 'javascript-state-machine' import LndConfig from './config' -import { getDeadline, validateHost, createSslCreds, createMacaroonCreds, waitForFile } from './util' +import { getDeadline, createSslCreds, createMacaroonCreds, waitForFile } from './util' +import { validateHost } from '../utils/validateHost' import methods from './methods' import { mainLog } from '../utils/log' import subscribeToTransactions from './subscribe/transactions' diff --git a/app/lib/lnd/util.js b/app/lib/lnd/util.js index 50ddfe2e..29648dca 100644 --- a/app/lib/lnd/util.js +++ b/app/lib/lnd/util.js @@ -1,4 +1,3 @@ -import dns from 'dns' import fs from 'fs' import axios from 'axios' import { promisify } from 'util' @@ -7,14 +6,10 @@ import { platform } from 'os' import { app } from 'electron' import isDev from 'electron-is-dev' import grpc from 'grpc' -import isFQDN from 'validator/lib/isFQDN' -import isIP from 'validator/lib/isIP' -import isPort from 'validator/lib/isPort' import get from 'lodash.get' import { mainLog } from '../utils/log' const fsReadFile = promisify(fs.readFile) -const dnsLookup = promisify(dns.lookup) // ------------------------------------ // Constants @@ -107,40 +102,6 @@ export const getDeadline = timeoutSecs => { return deadline.getTime() } -/** - * Helper function to check a hostname in the format hostname:port is valid for passing to node-grpc. - * @param {string} host A hostname + optional port in the format [hostname]:[port?] - * @returns {Promise} - */ -export const validateHost = async host => { - var splits = host.split(':') - const lndHost = splits[0] - const lndPort = splits[1] - - // If the hostname starts with a number, ensure that it is a valid IP address. - if (!isFQDN(lndHost, { require_tld: false }) && !isIP(lndHost)) { - const error = new Error(`${lndHost} is not a valid IP address or hostname`) - error.code = 'LND_GRPC_HOST_ERROR' - return Promise.reject(error) - } - - // If the host includes a port, ensure that it is a valid. - if (lndPort && !isPort(lndPort)) { - const error = new Error(`${lndPort} is not a valid port`) - error.code = 'LND_GRPC_HOST_ERROR' - return Promise.reject(error) - } - - // Do a DNS lookup to ensure that the host is reachable. - return dnsLookup(lndHost) - .then(() => true) - .catch(e => { - const error = new Error(`${lndHost} is not accessible: ${e.message}`) - error.code = 'LND_GRPC_HOST_ERROR' - return Promise.reject(error) - }) -} - /** * Validates and creates the ssl channel credentials from the specified file path * @param {String} certPath diff --git a/app/lib/lnd/walletUnlocker.js b/app/lib/lnd/walletUnlocker.js index f80abb12..19dcd5e6 100644 --- a/app/lib/lnd/walletUnlocker.js +++ b/app/lib/lnd/walletUnlocker.js @@ -4,7 +4,8 @@ import grpc from 'grpc' import { loadSync } from '@grpc/proto-loader' import StateMachine from 'javascript-state-machine' import LndConfig from './config' -import { getDeadline, validateHost, createSslCreds } from './util' +import { getDeadline, createSslCreds } from './util' +import { validateHost } from '../utils/validateHost' import methods from './walletUnlockerMethods' import { mainLog } from '../utils/log' diff --git a/app/lib/utils/fileExists.js b/app/lib/utils/fileExists.js new file mode 100644 index 00000000..dfee5a65 --- /dev/null +++ b/app/lib/utils/fileExists.js @@ -0,0 +1,7 @@ +import fs from 'fs' +import { promisify } from 'util' +import untildify from 'untildify' + +const fsReadFile = promisify(fs.readFile) + +export const fileExists = async path => fsReadFile(untildify(path)) diff --git a/app/lib/utils/validateHost.js b/app/lib/utils/validateHost.js new file mode 100644 index 00000000..0ea99959 --- /dev/null +++ b/app/lib/utils/validateHost.js @@ -0,0 +1,41 @@ +import dns from 'dns' +import { promisify } from 'util' +import isFQDN from 'validator/lib/isFQDN' +import isIP from 'validator/lib/isIP' +import isPort from 'validator/lib/isPort' + +const dnsLookup = promisify(dns.lookup) + +/** + * Helper function to check a hostname in the format hostname:port is valid for passing to node-grpc. + * @param {string} host A hostname + optional port in the format [hostname]:[port?] + * @returns {Promise} + */ +export const validateHost = async host => { + var splits = host.split(':') + const lndHost = splits[0] + const lndPort = splits[1] + + // If the hostname starts with a number, ensure that it is a valid IP address. + if (!isFQDN(lndHost, { require_tld: false }) && !isIP(lndHost)) { + const error = new Error(`${lndHost} is not a valid IP address or hostname`) + error.code = 'LND_GRPC_HOST_ERROR' + return Promise.reject(error) + } + + // If the host includes a port, ensure that it is a valid. + if (lndPort && !isPort(lndPort)) { + const error = new Error(`${lndPort} is not a valid port`) + error.code = 'LND_GRPC_HOST_ERROR' + return Promise.reject(error) + } + + // Do a DNS lookup to ensure that the host is reachable. + return dnsLookup(lndHost) + .then(() => true) + .catch(e => { + const error = new Error(`${lndHost} is not accessible: ${e.message}`) + error.code = 'LND_GRPC_HOST_ERROR' + return Promise.reject(error) + }) +} diff --git a/test/unit/lnd/util.spec.js b/test/unit/lnd/util.spec.js index 9fd05636..83121c35 100644 --- a/test/unit/lnd/util.spec.js +++ b/test/unit/lnd/util.spec.js @@ -1,4 +1,4 @@ -import { validateHost } from 'lib/lnd/util' +import { validateHost } from 'lib/utils/validateHost' jest.mock('dns')