Merge branch 'master' into UX

pull/260/head
Shahana Farooqui 5 years ago
commit 9690222e66

@ -28,8 +28,6 @@ Pre-requisite for running RTL is a functioning and synced LND node. You can setu
* Windows/Mac users can follow Pierre Rochard's [Node Launcher](https://github.com/lightning-power-users/node-launcher) * Windows/Mac users can follow Pierre Rochard's [Node Launcher](https://github.com/lightning-power-users/node-launcher)
* Linux or Raspberry Pi users can follow Stadicus's [guide](https://github.com/Stadicus/guides/blob/master/raspibolt/README.md) * Linux or Raspberry Pi users can follow Stadicus's [guide](https://github.com/Stadicus/guides/blob/master/raspibolt/README.md)
RTL source code is available at this [repo](https://github.com/ShahanaFarooqui/RTLFullApplication)
For detailed screenshots and UI operation guide you can visit our [medium post](https://medium.com/@suheb.khan/how-to-ride-the-lightning-447af999dcd2) For detailed screenshots and UI operation guide you can visit our [medium post](https://medium.com/@suheb.khan/how-to-ride-the-lightning-447af999dcd2)
RTL is available on the below platforms/services: RTL is available on the below platforms/services:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -5,12 +5,9 @@
<title>RTL</title> <title>RTL</title>
<base href="/rtl/"> <base href="/rtl/">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="apple-touch-icon" sizes="180x180" href="assets/images/favicon/apple-touch-icon.png"> <link rel="icon" type="image/x-icon" href="assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="32x32" href="assets/images/favicon/favicon-32x32.png"> <link rel="stylesheet" href="styles.486014dd6111683683a1.css"></head>
<link rel="icon" type="image/png" sizes="16x16" href="assets/images/favicon/favicon-16x16.png">
<link rel="manifest" href="assets/images/favicon/site.webmanifest">
<link rel="stylesheet" href="styles.ee2f5e1373bdbaacbb41.css"></head>
<body> <body>
<rtl-app></rtl-app> <rtl-app></rtl-app>
<script src="runtime.f3bbd9f1dcc793925cae.js"></script><script src="polyfills-es5.92f4069201c83f4833ef.js" nomodule></script><script src="polyfills.5ddcccdb990eb395f306.js"></script><script src="main.21175c3b9bf3c4c8939e.js"></script></body> <script src="runtime.feee63dac552d8844834.js"></script><script src="polyfills-es5.92f4069201c83f4833ef.js" nomodule></script><script src="polyfills.5ddcccdb990eb395f306.js"></script><script src="main.bf4aafcd2364c6e5a38d.js"></script></body>
</html> </html>

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
!function(e){function r(r){for(var n,c,i=r[0],a=r[1],f=r[2],p=0,s=[];p<i.length;p++)o[c=i[p]]&&s.push(o[c][0]),o[c]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(l&&l(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++)0!==o[t[i]]&&(n=!1);n&&(u.splice(r--,1),e=c(c.s=t[0]))}return e}var n={},o={0:0},u=[];function c(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,c),t.l=!0,t.exports}c.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,i=document.createElement("script");i.charset="utf-8",i.timeout=120,c.nc&&i.setAttribute("nonce",c.nc),i.src=function(e){return c.p+""+({}[e]||e)+"."+{1:"dc65164c2cc38ecb3ec0",6:"8f2384e487c219c3bbe9",7:"5b9eec5877f949c48a68"}[e]+".js"}(e);var a=new Error;u=function(r){i.onerror=i.onload=null,clearTimeout(f);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;a.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",a.name="ChunkLoadError",a.type=n,a.request=u,t[1](a)}o[e]=void 0}};var f=setTimeout((function(){u({type:"timeout",target:i})}),12e4);i.onerror=i.onload=u,document.head.appendChild(i)}return Promise.all(r)},c.m=e,c.c=n,c.d=function(e,r,t){c.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},c.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},c.t=function(e,r){if(1&r&&(e=c(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(c.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)c.d(t,n,(function(r){return e[r]}).bind(null,n));return t},c.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return c.d(r,"a",r),r},c.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},c.p="",c.oe=function(e){throw console.error(e),e};var i=window.webpackJsonp=window.webpackJsonp||[],a=i.push.bind(i);i.push=r,i=i.slice();for(var f=0;f<i.length;f++)r(i[f]);var l=a;t()}([]);

File diff suppressed because one or more lines are too long

@ -24,36 +24,35 @@ common.getOptions = () => {
return common.selectedNode.options; return common.selectedNode.options;
}; };
common.setOptions = () => { common.updateSelectedNodeOptions = () => {
if (undefined !== common.nodes[0].options && undefined !== common.nodes[0].options.headers) { return; } common.selectedNode.options = {
url: '',
rejectUnauthorized: false,
json: true,
form: ''
};
try { try {
common.nodes.forEach(node => { if (common.selectedNode && common.selectedNode.ln_implementation && common.selectedNode.ln_implementation.toUpperCase() === 'CLT') {
node.options = { common.selectedNode.options.headers = { 'macaroon': Buffer.from(fs.readFileSync(path.join(common.selectedNode.macaroon_path, 'access.macaroon'))).toString("base64") };
url: '', } else {
rejectUnauthorized: false, common.selectedNode.options.headers = { 'Grpc-Metadata-macaroon': fs.readFileSync(path.join(common.selectedNode.macaroon_path, 'admin.macaroon')).toString('hex') };
json: true, }
form: '' return { status: 200, message: 'Updated Successfully!' };
}; } catch(err) {
if (node.ln_implementation && node.ln_implementation.toUpperCase() === 'CLT') {
node.options.headers = { 'macaroon': Buffer.from(fs.readFileSync(path.join(node.macaroon_path, 'access.macaroon'))).toString("base64") };
} else {
node.options.headers = { 'Grpc-Metadata-macaroon': fs.readFileSync(path.join(node.macaroon_path, 'admin.macaroon')).toString('hex') };
}
});
// Options cannot be set before selected node initializes. Updating selected node's options separatly
common.selectedNode.options = { common.selectedNode.options = {
url: '', url: '',
rejectUnauthorized: false, rejectUnauthorized: false,
json: true, json: true,
form: '' form: ''
}; };
if (common.selectedNode && common.selectedNode.ln_implementation && common.selectedNode.ln_implementation.toUpperCase() === 'CLT') { console.error('Common Update Selected Node Options Error:' + JSON.stringify(err));
common.selectedNode.options.headers = { 'macaroon': Buffer.from(fs.readFileSync(path.join(common.selectedNode.macaroon_path, 'access.macaroon'))).toString("base64") }; return { status: 502, message: err };
} else { }
common.selectedNode.options.headers = { 'Grpc-Metadata-macaroon': fs.readFileSync(path.join(common.selectedNode.macaroon_path, 'admin.macaroon')).toString('hex') }; }
}
} catch (err) { common.setOptions = () => {
console.error('Common Set Options Error:' + JSON.stringify(err)); if (undefined !== common.nodes[0].options && undefined !== common.nodes[0].options.headers) { return; }
if (common.nodes && common.nodes.length > 0) {
common.nodes.forEach(node => { common.nodes.forEach(node => {
node.options = { node.options = {
url: '', url: '',
@ -61,14 +60,23 @@ common.setOptions = () => {
json: true, json: true,
form: '' form: ''
}; };
try {
if (node.ln_implementation && node.ln_implementation.toUpperCase() === 'CLT') {
node.options.headers = { 'macaroon': Buffer.from(fs.readFileSync(path.join(node.macaroon_path, 'access.macaroon'))).toString("base64") };
} else {
node.options.headers = { 'Grpc-Metadata-macaroon': fs.readFileSync(path.join(node.macaroon_path, 'admin.macaroon')).toString('hex') };
}
} catch (err) {
console.error('Common Set Options Error:' + JSON.stringify(err));
node.options = {
url: '',
rejectUnauthorized: false,
json: true,
form: ''
};
}
}); });
// Options cannot be set before selected node initializes. Updating selected node's options separatly common.updateSelectedNodeOptions();
common.selectedNode.options = {
url: '',
rejectUnauthorized: false,
json: true,
form: ''
};
} }
} }

@ -219,14 +219,16 @@ connect.validateSingleNodeConfig = (config) => {
common.ln_implementation = 'LND'; common.ln_implementation = 'LND';
} }
if (undefined !== process.env.RTL_PASS) { if(!+config.SSO.rtlSSO) {
common.rtl_pass = hash.update(process.env.RTL_PASS).digest('hex'); if (undefined !== process.env.RTL_PASS) {
} else if (config.Authentication.rtlPassHashed !== '' && undefined !== config.Authentication.rtlPassHashed) { common.rtl_pass = hash.update(process.env.RTL_PASS).digest('hex');
common.rtl_pass = config.Authentication.rtlPassHashed; } else if (config.Authentication.rtlPassHashed !== '' && undefined !== config.Authentication.rtlPassHashed) {
} else if (config.Authentication.rtlPass !== '' && undefined !== config.Authentication.rtlPass) { common.rtl_pass = config.Authentication.rtlPassHashed;
common.rtl_pass = connect.convertCustomToHash('SINGLE'); } else if (config.Authentication.rtlPass !== '' && undefined !== config.Authentication.rtlPass) {
} common.rtl_pass = connect.convertCustomToHash('SINGLE');
}
}
if (upperCase(common.node_auth_type) === 'CUSTOM' && (common.rtl_pass === '' || undefined === common.rtl_pass)) { if (upperCase(common.node_auth_type) === 'CUSTOM' && (common.rtl_pass === '' || undefined === common.rtl_pass)) {
errMsg = errMsg + '\nCustom Node Authentication can be set with RTL password only. Please set RTL Password through environment or RTL.conf'; errMsg = errMsg + '\nCustom Node Authentication can be set with RTL password only. Please set RTL Password through environment or RTL.conf';
} }
@ -270,82 +272,84 @@ connect.validateSingleNodeConfig = (config) => {
} }
connect.validateMultiNodeConfig = (config) => { connect.validateMultiNodeConfig = (config) => {
common.node_auth_type = 'CUSTOM'; if(!+config.SSO.rtlSSO) {
if (undefined !== process.env.RTL_PASS) { common.node_auth_type = 'CUSTOM';
common.rtl_pass = hash.update(process.env.RTL_PASS).digest('hex'); if (undefined !== process.env.RTL_PASS) {
} else if (config.multiPassHashed !== '' && undefined !== config.multiPassHashed) { common.rtl_pass = hash.update(process.env.RTL_PASS).digest('hex');
common.rtl_pass = config.multiPassHashed; } else if (config.multiPassHashed !== '' && undefined !== config.multiPassHashed) {
} else if (config.multiPass !== '' && undefined !== config.multiPass) { common.rtl_pass = config.multiPassHashed;
common.rtl_pass = connect.convertCustomToHash('MULTI'); } else if (config.multiPass !== '' && undefined !== config.multiPass) {
} else { common.rtl_pass = connect.convertCustomToHash('MULTI');
errMsg = errMsg + '\nMulti Node Authentication can be set with multiPass only. Please set MultiPass in RTL-Multi-Node-Conf.json';
}
common.port = (undefined !== config.port) ? connect.normalizePort(config.port) : 3000;
config.nodes.forEach((node, idx) => {
common.nodes[idx] = {};
if(node.Authentication.macaroonPath === '' || undefined === node.Authentication.macaroonPath) {
errMsg = 'Please set macaroon path for node index ' + node.index + ' in RTL-Multi-Node-Conf.json!';
} else {
common.nodes[idx].macaroon_path = node.Authentication.macaroonPath;
}
if(
(node.Settings.lndServerUrl === '' || undefined === node.Settings.lndServerUrl)
&& (node.Settings.lnServerUrl === '' || undefined === node.Settings.lnServerUrl)
) {
errMsg = errMsg + '\nPlease set server URL for node index ' + node.index + ' in RTL-Multi-Node-Conf.json!';
} else { } else {
common.nodes[idx].ln_server_url = node.Settings.lndServerUrl ? node.Settings.lndServerUrl : node.Settings.lnServerUrl; errMsg = errMsg + '\nMulti Node Authentication can be set with multiPass only. Please set MultiPass in RTL-Multi-Node-Conf.json';
} }
}
common.port = (undefined !== config.port) ? connect.normalizePort(config.port) : 3000;
if (config.nodes && config.nodes.length > 0) {
config.nodes.forEach((node, idx) => {
common.nodes[idx] = {};
if(node.Authentication.macaroonPath === '' || undefined === node.Authentication.macaroonPath) {
errMsg = 'Please set macaroon path for node index ' + node.index + ' in RTL-Multi-Node-Conf.json!';
} else {
common.nodes[idx].macaroon_path = node.Authentication.macaroonPath;
}
common.nodes[idx].index = node.index; if(
common.nodes[idx].ln_node = node.lnNode; (node.Settings.lndServerUrl === '' || undefined === node.Settings.lndServerUrl)
common.nodes[idx].ln_implementation = node.lnImplementation; && (node.Settings.lnServerUrl === '' || undefined === node.Settings.lnServerUrl)
if (undefined !== node.Authentication && undefined !== node.Authentication.lndConfigPath) { ) {
common.nodes[idx].config_path = node.Authentication.lndConfigPath; errMsg = errMsg + '\nPlease set server URL for node index ' + node.index + ' in RTL-Multi-Node-Conf.json!';
} else if (undefined !== node.Authentication && undefined !== node.Authentication.configPath) { } else {
common.nodes[idx].config_path = node.Authentication.configPath; common.nodes[idx].ln_server_url = node.Settings.lndServerUrl ? node.Settings.lndServerUrl : node.Settings.lnServerUrl;
} else { }
common.nodes[idx].config_path = '';
}
common.nodes[idx].bitcoind_config_path = (undefined !== node.Settings.bitcoindConfigPath) ? node.Settings.bitcoindConfigPath : '';
common.nodes[idx].enable_logging = (undefined !== node.Settings.enableLogging) ? node.Settings.enableLogging : false;
common.nodes[idx].channel_backup_path = (undefined !== node.Settings.channelBackupPath) ? node.Settings.channelBackupPath : common.rtl_conf_file_path + common.path_separator + 'backup' + common.path_separator + 'node-' + node.index;
try {
connect.createDirectory(common.nodes[idx].channel_backup_path);
let exists = fs.existsSync(common.nodes[idx].channel_backup_path + common.path_separator + 'channel-all.bak');
if (!exists) {
try {
var createStream = fs.createWriteStream(common.nodes[idx].channel_backup_path + common.path_separator + 'channel-all.bak');
createStream.end();
} catch (err) {
console.error('Something went wrong while creating backup file: \n' + err);
}
}
} catch (err) {
console.error('Something went wrong while creating backup file: \n' + err);
}
if (common.nodes[idx].enable_logging) { common.nodes[idx].index = node.index;
common.nodes[idx].log_file = common.rtl_conf_file_path + '/logs/RTL-Node-' + node.index + '.log'; common.nodes[idx].ln_node = node.lnNode;
const log_file = common.nodes[idx].log_file; common.nodes[idx].ln_implementation = node.lnImplementation;
if (fs.existsSync(log_file)) { if (undefined !== node.Authentication && undefined !== node.Authentication.lndConfigPath) {
fs.writeFile(log_file, '', () => { }); common.nodes[idx].config_path = node.Authentication.lndConfigPath;
} else if (undefined !== node.Authentication && undefined !== node.Authentication.configPath) {
common.nodes[idx].config_path = node.Authentication.configPath;
} else { } else {
try { common.nodes[idx].config_path = '';
var dirname = path.dirname(log_file); }
connect.createDirectory(dirname); common.nodes[idx].bitcoind_config_path = (undefined !== node.Settings.bitcoindConfigPath) ? node.Settings.bitcoindConfigPath : '';
var createStream = fs.createWriteStream(log_file); common.nodes[idx].enable_logging = (undefined !== node.Settings.enableLogging) ? node.Settings.enableLogging : false;
createStream.end(); common.nodes[idx].channel_backup_path = (undefined !== node.Settings.channelBackupPath) ? node.Settings.channelBackupPath : common.rtl_conf_file_path + common.path_separator + 'backup' + common.path_separator + 'node-' + node.index;
} try {
catch (err) { connect.createDirectory(common.nodes[idx].channel_backup_path);
console.error('Something went wrong while creating log file ' + log_file + ': \n' + err); let exists = fs.existsSync(common.nodes[idx].channel_backup_path + common.path_separator + 'channel-all.bak');
if (!exists) {
try {
var createStream = fs.createWriteStream(common.nodes[idx].channel_backup_path + common.path_separator + 'channel-all.bak');
createStream.end();
} catch (err) {
console.error('Something went wrong while creating backup file: \n' + err);
}
}
} catch (err) {
console.error('Something went wrong while creating backup file: \n' + err);
}
if (common.nodes[idx].enable_logging) {
common.nodes[idx].log_file = common.rtl_conf_file_path + '/logs/RTL-Node-' + node.index + '.log';
const log_file = common.nodes[idx].log_file;
if (fs.existsSync(log_file)) {
fs.writeFile(log_file, '', () => { });
} else {
try {
var dirname = path.dirname(log_file);
connect.createDirectory(dirname);
var createStream = fs.createWriteStream(log_file);
createStream.end();
}
catch (err) {
console.error('Something went wrong while creating log file ' + log_file + ': \n' + err);
}
} }
} }
} });
}); }
connect.setSSOParams(config); connect.setSSOParams(config);
if (errMsg !== '') { throw new Error(errMsg); } if (errMsg !== '') { throw new Error(errMsg); }
@ -372,7 +376,11 @@ connect.setSSOParams = (config) => {
} else { } else {
common.rtl_cookie_path = common.rtl_conf_file_path + '/cookies/auth.cookie'; common.rtl_cookie_path = common.rtl_conf_file_path + '/cookies/auth.cookie';
} }
connect.readCookie(common.rtl_cookie_path); if (common.rtl_cookie_path === '') {
errMsg = 'Please set rtlCookiePath value for single sign on option!';
} else {
connect.readCookie(common.rtl_cookie_path);
}
} }
}; };
@ -400,7 +408,12 @@ connect.createDirectory = (dirname) => {
connect.readCookie = (cookieFile) => { connect.readCookie = (cookieFile) => {
let exists = fs.existsSync(cookieFile); let exists = fs.existsSync(cookieFile);
if (exists) { if (exists) {
common.cookie = fs.readFileSync(cookieFile, 'utf-8'); try {
common.cookie = fs.readFileSync(cookieFile, 'utf-8');
} catch (err) {
console.error('Something went wrong while reading cookie: \n' + err);
throw new Error(err);
}
} else { } else {
try { try {
var dirname = path.dirname(cookieFile); var dirname = path.dirname(cookieFile);
@ -409,7 +422,7 @@ connect.readCookie = (cookieFile) => {
common.cookie = fs.readFileSync(cookieFile, 'utf-8'); common.cookie = fs.readFileSync(cookieFile, 'utf-8');
} }
catch(err) { catch(err) {
console.error('Something went wrong while reading cookie: \n' + err); console.error('Something went wrong while reading the cookie: \n' + err);
throw new Error(err); throw new Error(err);
} }
} }
@ -427,7 +440,7 @@ connect.refreshCookie = (cookieFile) => {
} }
connect.logEnvVariables = () => { connect.logEnvVariables = () => {
if (common.multi_node_setup) { if (common.multi_node_setup && common.nodes && common.nodes.length > 0) {
common.nodes.forEach((node, idx) => { common.nodes.forEach((node, idx) => {
if (!node.enable_logging) { return; } if (!node.enable_logging) { return; }
logger.info({fileName: 'Config Setup Variable', msg: 'DEFAULT_NODE_INDEX: ' + common.selectedNode.index}); logger.info({fileName: 'Config Setup Variable', msg: 'DEFAULT_NODE_INDEX: ' + common.selectedNode.index});

@ -58,28 +58,30 @@ exports.getRTLConfig = (req, res, next) => {
const multiNodeConfig = JSON.parse(data); const multiNodeConfig = JSON.parse(data);
const sso = { rtlSSO: common.rtl_sso, logoutRedirectLink: common.logout_redirect_link }; const sso = { rtlSSO: common.rtl_sso, logoutRedirectLink: common.logout_redirect_link };
var nodesArr = []; var nodesArr = [];
multiNodeConfig.nodes.forEach((node, i) => { if (multiNodeConfig.nodes && multiNodeConfig.nodes.length > 0) {
const authentication = {}; multiNodeConfig.nodes.forEach((node, i) => {
authentication.nodeAuthType = 'CUSTOM'; const authentication = {};
if(node.Authentication && node.Authentication.lndConfigPath) { authentication.nodeAuthType = 'CUSTOM';
authentication.configPath = node.Authentication.lndConfigPath; if(node.Authentication && node.Authentication.lndConfigPath) {
} else if(node.Authentication && node.Authentication.configPath) { authentication.configPath = node.Authentication.lndConfigPath;
authentication.configPath = node.Authentication.configPath; } else if(node.Authentication && node.Authentication.configPath) {
} else { authentication.configPath = node.Authentication.configPath;
authentication.configPath = ''; } else {
} authentication.configPath = '';
}
if(node.Settings.bitcoindConfigPath) {
authentication.bitcoindConfigPath = node.Settings.bitcoindConfigPath; if(node.Settings.bitcoindConfigPath) {
} authentication.bitcoindConfigPath = node.Settings.bitcoindConfigPath;
node.Settings.channelBackupPath = (undefined !== node.Settings.channelBackupPath) ? node.Settings.channelBackupPath : common.nodes[i].channel_backup_path; }
nodesArr.push({ node.Settings.channelBackupPath = (undefined !== node.Settings.channelBackupPath) ? node.Settings.channelBackupPath : common.nodes[i].channel_backup_path;
index: node.index, nodesArr.push({
lnNode: node.lnNode, index: node.index,
lnImplementation: node.lnImplementation, lnNode: node.lnNode,
settings: node.Settings, lnImplementation: node.lnImplementation,
authentication: authentication}) settings: node.Settings,
}); authentication: authentication})
});
}
res.status(200).json({ selectedNodeIndex: common.selectedNode.index, sso: sso, nodes: nodesArr }); res.status(200).json({ selectedNodeIndex: common.selectedNode.index, sso: sso, nodes: nodesArr });
} }
}); });

@ -135,7 +135,7 @@ exports.listForwards = (req, res, next) => {
error: (undefined === body) ? 'Error From Server!' : body.error error: (undefined === body) ? 'Error From Server!' : body.error
}); });
} else { } else {
if (body.length > 0) { if (body && body.length > 0) {
body.forEach(event => { body.forEach(event => {
event.received_time_str = (undefined === event.received_time) ? '' : common.convertTimestampToDate(event.received_time); event.received_time_str = (undefined === event.received_time) ? '' : common.convertTimestampToDate(event.received_time);
event.resolved_time_str = (undefined === event.resolved_time) ? '' : common.convertTimestampToDate(event.resolved_time); event.resolved_time_str = (undefined === event.resolved_time) ? '' : common.convertTimestampToDate(event.resolved_time);

@ -37,7 +37,7 @@ exports.listInvoices = (req, res, next) => {
error: (undefined === body) ? 'Error From Server!' : body.error error: (undefined === body) ? 'Error From Server!' : body.error
}); });
} else { } else {
if (undefined !== body.invoices) { if (undefined !== body.invoices && body.invoices.length > 0) {
body.invoices.forEach(invoice => { body.invoices.forEach(invoice => {
invoice.paid_at_str = (undefined === invoice.paid_at) ? '' : common.convertTimestampToDate(invoice.paid_at); invoice.paid_at_str = (undefined === invoice.paid_at) ? '' : common.convertTimestampToDate(invoice.paid_at);
invoice.expires_at_str = (undefined === invoice.expires_at) ? '' : common.convertTimestampToDate(invoice.expires_at); invoice.expires_at_str = (undefined === invoice.expires_at) ? '' : common.convertTimestampToDate(invoice.expires_at);

@ -14,7 +14,7 @@ exports.listPayments = (req, res, next) => {
error: (undefined === body) ? 'Error From Server!' : body.error error: (undefined === body) ? 'Error From Server!' : body.error
}); });
} else { } else {
if (undefined !== body && undefined !== body.payments) { if (undefined !== body && undefined !== body.payments && body.payments.length > 0) {
body.payments.forEach(payment => { body.payments.forEach(payment => {
payment.created_at_str = (undefined === payment.created_at) ? '' : common.convertTimestampToDate(payment.created_at); payment.created_at_str = (undefined === payment.created_at) ? '' : common.convertTimestampToDate(payment.created_at);
}); });

@ -1,4 +1,5 @@
var request = require('request-promise'); var request = require('request-promise');
var upperCase = require('upper-case');
var common = require('../../common'); var common = require('../../common');
var logger = require('../logger'); var logger = require('../logger');
var options = {}; var options = {};
@ -10,10 +11,20 @@ exports.getBalance = (req, res, next) => {
request(options).then((body) => { request(options).then((body) => {
logger.info({fileName: 'Balance', msg: 'Request params: ' + JSON.stringify(req.params) + 'Request Query: ' + JSON.stringify(req.query) + ' Balance Received: ' + JSON.stringify(body)}); logger.info({fileName: 'Balance', msg: 'Request params: ' + JSON.stringify(req.params) + 'Request Query: ' + JSON.stringify(req.query) + ' Balance Received: ' + JSON.stringify(body)});
if(undefined !== body) { if(undefined !== body) {
body.btc_balance = (undefined === body.balance) ? 0 : common.convertToBTC(body.balance); if (upperCase(req.params.source) === 'BLOCKCHAIN') {
body.btc_total_balance = (undefined === body.total_balance) ? 0 : common.convertToBTC(body.total_balance); if (!body.total_balance) { body.total_balance = 0; }
body.btc_confirmed_balance = (undefined === body.confirmed_balance) ? 0 : common.convertToBTC(body.confirmed_balance); if (!body.confirmed_balance) { body.confirmed_balance = 0; }
body.btc_unconfirmed_balance = (undefined === body.unconfirmed_balance) ? 0 : common.convertToBTC(body.unconfirmed_balance); if (!body.unconfirmed_balance) { body.unconfirmed_balance = 0; }
body.btc_total_balance = common.convertToBTC(body.total_balance);
body.btc_confirmed_balance = common.convertToBTC(body.confirmed_balance);
body.btc_unconfirmed_balance = common.convertToBTC(body.unconfirmed_balance);
}
if (upperCase(req.params.source) === 'CHANNELS') {
if (!body.balance) { body.balance = 0; }
if (!body.pending_open_balance) { body.pending_open_balance = 0; }
body.btc_balance = common.convertToBTC(body.balance);
body.btc_pending_open_balance = common.convertToBTC(body.pending_open_balance);
}
res.status(200).json(body); res.status(200).json(body);
} }
}) })

@ -54,7 +54,7 @@ exports.getChannels = (req, res, next) => {
} else { } else {
body.btc_total_limbo_balance = common.convertToBTC(body.total_limbo_balance); body.btc_total_limbo_balance = common.convertToBTC(body.total_limbo_balance);
} }
if (req.params.channelType === 'closed') { if (req.params.channelType === 'closed' && body.channels && body.channels.length > 0) {
body.channels.forEach(channel => { body.channels.forEach(channel => {
channel.close_type = (undefined === channel.close_type) ? 'COOPERATIVE_CLOSE' : channel.close_type; channel.close_type = (undefined === channel.close_type) ? 'COOPERATIVE_CLOSE' : channel.close_type;
}); });

@ -10,15 +10,17 @@ function getFilesList(callback) {
let response = {all_restore_exists: false, files: []}; let response = {all_restore_exists: false, files: []};
fs.readdir(common.selectedNode.channel_backup_path + common.path_separator + 'restore', function (err, files) { fs.readdir(common.selectedNode.channel_backup_path + common.path_separator + 'restore', function (err, files) {
if (err && err.code !== 'ENOENT' && err.errno !== -4058) { response = { message: 'Channels Restore List Failed!', error: err } } if (err && err.code !== 'ENOENT' && err.errno !== -4058) { response = { message: 'Channels Restore List Failed!', error: err } }
files.forEach(file => { if(undefined !== files && files.length > 0) {
if (!file.includes('.restored')) { files.forEach(file => {
if (file === 'channel-all.bak') { if (!file.includes('.restored')) {
all_restore_exists = true; if (file === 'channel-all.bak') {
} else { all_restore_exists = true;
files_list.push({channel_point: file.substring(8, file.length - 4).replace('-', ':')}); } else {
files_list.push({channel_point: file.substring(8, file.length - 4).replace('-', ':')});
}
} }
} });
}); }
response = {all_restore_exists: all_restore_exists, files: files_list}; response = {all_restore_exists: all_restore_exists, files: files_list};
callback(response); callback(response);
}); });

@ -13,25 +13,33 @@ exports.getInfo = (req, res, next) => {
} else { } else {
logger.info({fileName:'GetInfo', msg: 'Single Node Setup!'}); logger.info({fileName:'GetInfo', msg: 'Single Node Setup!'});
} }
common.nodes.map(node => { if (node.lnImplementation === 'LND') { connect.getAllNodeAllChannelBackup(node); }}); if (!options.headers || !options.headers['Grpc-Metadata-macaroon']) {
logger.info({fileName: 'GetInfo', msg: 'Calling getinfo from lnd server url: ' + options.url}); logger.error({fileName: 'GetInfo', lineNum: 17, msg: 'Get info failed due to bad or missing macaroon!'});
request(options).then((body) => { res.status(502).json({
logger.info({fileName: 'GetInfo', msg: JSON.stringify(body)}); message: "Fetching Info Failed!",
const body_str = (undefined === body) ? '' : JSON.stringify(body); error: "Bad Macaroon"
const search_idx = (undefined === body) ? -1 : body_str.search('Not Found'); });
if(undefined === body || search_idx > -1 || body.error) { } else {
res.status(500).json({ common.nodes.map(node => { if (node.lnImplementation === 'LND') { connect.getAllNodeAllChannelBackup(node); }});
message: "Fetching Info failed!", logger.info({fileName: 'GetInfo', msg: 'Calling getinfo from lnd server url: ' + options.url});
error: (undefined === body || search_idx > -1) ? 'Error From Server!' : body.error request(options).then((body) => {
logger.info({fileName: 'GetInfo', msg: JSON.stringify(body)});
const body_str = (undefined === body) ? '' : JSON.stringify(body);
const search_idx = (undefined === body) ? -1 : body_str.search('Not Found');
if(undefined === body || search_idx > -1 || body.error) {
res.status(500).json({
message: "Fetching Info Failed!",
error: (undefined === body || search_idx > -1) ? 'Error From Server!' : body.error
});
} else {
res.status(200).json(body);
}
})
.catch(function (err) {
return res.status(500).json({
message: "Fetching Info Failed!",
error: err.error
}); });
} else {
res.status(200).json(body);
}
})
.catch(function (err) {
return res.status(500).json({
message: "Fetching Info failed!",
error: err.error
}); });
}); }
}; };

@ -128,7 +128,7 @@ exports.getQueryRoutes = (req, res, next) => {
error: (undefined === body) ? 'Error From Server!' : body.error error: (undefined === body) ? 'Error From Server!' : body.error
}); });
} }
if (undefined !== body.routes) { if (undefined !== body.routes && body.routes.length > 0) {
body.routes.forEach(route => { body.routes.forEach(route => {
if (undefined !== route.hops) { if (undefined !== route.hops) {
Promise.all( Promise.all(

@ -38,7 +38,7 @@ exports.listInvoices = (req, res, next) => {
error: (undefined === body || search_idx > -1) ? 'Error From Server!' : body.error error: (undefined === body || search_idx > -1) ? 'Error From Server!' : body.error
}); });
} else { } else {
if (undefined !== body.invoices) { if (undefined !== body.invoices && body.invoices.length > 0) {
body.invoices.forEach(invoice => { body.invoices.forEach(invoice => {
invoice.creation_date_str = (undefined === invoice.creation_date) ? '' : common.convertTimestampToDate(invoice.creation_date); invoice.creation_date_str = (undefined === invoice.creation_date) ? '' : common.convertTimestampToDate(invoice.creation_date);
invoice.settle_date_str = (undefined === invoice.settle_date) ? '' : common.convertTimestampToDate(invoice.settle_date); invoice.settle_date_str = (undefined === invoice.settle_date) ? '' : common.convertTimestampToDate(invoice.settle_date);

@ -16,7 +16,7 @@ exports.getPayments = (req, res, next) => {
error: (undefined === body || search_idx > -1) ? 'Error From Server!' : body.error error: (undefined === body || search_idx > -1) ? 'Error From Server!' : body.error
}); });
} else { } else {
if (undefined !== body.payments) { if (undefined !== body.payments && body.payments.length > 0) {
body.payments.forEach(payment => { body.payments.forEach(payment => {
payment.creation_date_str = (undefined === payment.creation_date) ? '' : common.convertTimestampToDate(payment.creation_date); payment.creation_date_str = (undefined === payment.creation_date) ? '' : common.convertTimestampToDate(payment.creation_date);
}); });

@ -30,7 +30,7 @@ exports.forwardingHistory = (req, res, next) => {
error: (undefined === body) ? 'Error From Server!' : body.error error: (undefined === body) ? 'Error From Server!' : body.error
}); });
} else { } else {
if (undefined !== body.forwarding_events) { if (undefined !== body.forwarding_events && body.forwarding_events.length > 0) {
body.forwarding_events.forEach(event => { body.forwarding_events.forEach(event => {
event.timestamp_str = (undefined === event.timestamp) ? '' : common.convertTimestampToDate(event.timestamp); event.timestamp_str = (undefined === event.timestamp) ? '' : common.convertTimestampToDate(event.timestamp);
}); });

@ -16,7 +16,7 @@ exports.getTransactions = (req, res, next) => {
error: (undefined === body || search_idx > -1) ? 'Error From Server!' : body.error error: (undefined === body || search_idx > -1) ? 'Error From Server!' : body.error
}); });
} else { } else {
if (undefined !== body.transactions) { if (undefined !== body.transactions && body.transactions.length > 0) {
body.transactions.forEach(transaction => { body.transactions.forEach(transaction => {
transaction.time_stamp_str = (undefined === transaction.time_stamp) ? '' : common.convertTimestampToDate(transaction.time_stamp); transaction.time_stamp_str = (undefined === transaction.time_stamp) ? '' : common.convertTimestampToDate(transaction.time_stamp);
}); });

@ -6,9 +6,10 @@ var options = {};
exports.genSeed = (req, res, next) => { exports.genSeed = (req, res, next) => {
options = common.getOptions(); options = common.getOptions();
options.url = common.getSelLNServerUrl() + '/genseed';
if (undefined !== req.params.passphrase) { if (undefined !== req.params.passphrase) {
options.form = JSON.stringify({aezeed_passphrase: atob(req.params.passphrase)}); options.url = common.getSelLNServerUrl() + '/genseed?aezeed_passphrase=' + Buffer.from(atob(req.params.passphrase)).toString('base64');
} else {
options.url = common.getSelLNServerUrl() + '/genseed';
} }
request(options).then((body) => { request(options).then((body) => {
if(undefined === body || body.error) { if(undefined === body || body.error) {
@ -86,8 +87,13 @@ exports.operateWallet = (req, res, next) => {
} else { } else {
res.status(500).json({ res.status(500).json({
message: err_message, message: err_message,
error: error.message error: error.error.message ? error.error.message : error.message
}); });
} }
}); });
}; };
exports.updateSelNodeOptions = (req, res, next) => {
let response = common.updateSelectedNodeOptions();
res.status(response.status).json({updateMessage: response.message});
}

@ -4,29 +4,25 @@
## High Level Goals ## High Level Goals
### Multi-node Management ### Improved UX
We want to provide users an ability to manage multiple-nodes via a single UI. The idea is to provide a top-level page, which will list all the nodes which are configured for RTL. User would be able drill down to each node from that page and manage nodes from a single RTL instance. Current focus is on complete over-haul of the UX, including the mobile interfaces. Primary user persona for RTL is 'Routing Node Operator'. The UX will be optimized for effective node operation. There will be special focus on Dashboard, Channel Management and Routing tracking.
### RTL installer We believe UX improvement is a never-ending cycle. And, we must keep the UI/UX fresh and optimal with ongoing user feedback and inputs from UX subject-matter-experts. Contribution on UX suggestions is always welcome.
Automate RTL setup so that installation process is simpler than the current method of following the steps provided in the Readme file. This should also help with configuration of nginx and letsencrypt, to enable access via https. Contribution on this is more than welcome.
### Better Mobile UX ### Automated Testing
Current UX for mobile users is less than optimal. We are attempting to provide a responsive UI, so that users can access the same app via browser on any device. This requires more UX optimization for mobile resolution. As the functional complexity increases, we need to add automated testing to ensure quality and less bugs. Another area, where developer contribution is more than welcome.
### C-Lightning ### LND Loop Integration
We want to extend the RTL UI framework to other lightning node implementations as well. The current architecture can support it without major re-engineering, as we have an api abstraction layer written in nodejs. LND's Loop-Out and Loop-In are important tools for channel re-balancing and will be integrated with RTL UI in the near future.
### Multi-Language Support ### Multi-Language Support
We can provide a customizable framework for multi-language support. But to extend support for other languages would require contribution from the development community, to use the framework and create multi-language support. We can provide a customizable framework for multi-language support. But to extend support for other languages would require contribution from the development community, to use the framework and create multi-language support
### Ongoing UX improvement ### Advanced Node Monitoring
We believe UX improvement is a never-ending cycle. And, we must keep the UI/UX fresh and optimal with ongoing user feedback and inputs from UX subject-matter-experts. Contribution on UX suggestions is more than welcome and we have created a project to exclusively focus on UX issues and priorities. Active node monitoring may be required to ensure reliability of routing nodes. Monitoring can include generating alerts for out-of-balance channels, inactive channels, disconnected peers, low activity channels etc. This feature will be required for professional node operaters running commercial routing nodes with a need to react to signals, requiring specific action to be taken.
Automated Testing As the functional complexity increases, we need to add automated testing to ensure quality and less bugs. Another area, where developer contribution is more than welcome.
### Advanced Multi-node Management
## Feature Backlog RTL currently allows managing multiple nodes (LND or C-Lightning), via single UI. More sophistication can be built on multi-node management, with advanced top level dashboards, which summarize node level summary in a single dashboard. This feature may be required for professional node operators, who are running commercial routing nodes.
### Channel re-balancing
- Loop Out ### RTL installer
### Invoice Management Automate RTL setup so that installation process is simpler than the current method of following the steps provided in the Readme file. This should also help with configuration of nginx and letsencrypt, to enable access via https. Contribution on this is more than welcome.
- Lookup Invoice
### Network
- Network explorer

623
package-lock.json generated

@ -1,6 +1,6 @@
{ {
"name": "rtl", "name": "rtl",
"version": "0.5.4-beta", "version": "0.5.5-beta",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -192,12 +192,6 @@
"requires": { "requires": {
"tslib": "^1.9.0" "tslib": "^1.9.0"
} }
},
"source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
"dev": true
} }
} }
}, },
@ -2907,12 +2901,6 @@
"yallist": "^3.0.2" "yallist": "^3.0.2"
} }
}, },
"y18n": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
"dev": true
},
"yallist": { "yallist": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
@ -2968,9 +2956,10 @@
"dev": true "dev": true
}, },
"camelcase": { "camelcase": {
"version": "2.1.1", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true
}, },
"camelcase-keys": { "camelcase-keys": {
"version": "2.1.0", "version": "2.1.0",
@ -2979,6 +2968,13 @@
"requires": { "requires": {
"camelcase": "^2.0.0", "camelcase": "^2.0.0",
"map-obj": "^1.0.0" "map-obj": "^1.0.0"
},
"dependencies": {
"camelcase": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
"integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8="
}
} }
}, },
"caniuse-lite": { "caniuse-lite": {
@ -3143,13 +3139,47 @@
"dev": true "dev": true
}, },
"cliui": { "cliui": {
"version": "3.2.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
"integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
"dev": true,
"requires": { "requires": {
"string-width": "^1.0.1", "string-width": "^2.1.1",
"strip-ansi": "^3.0.1", "strip-ansi": "^4.0.0",
"wrap-ansi": "^2.0.0" "wrap-ansi": "^2.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"dev": true
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
"dev": true
},
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
"dev": true,
"requires": {
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^4.0.0"
}
},
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"dev": true,
"requires": {
"ansi-regex": "^3.0.0"
}
}
} }
}, },
"clone": { "clone": {
@ -3182,9 +3212,9 @@
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
}, },
"codelyzer": { "codelyzer": {
"version": "5.1.2", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-5.1.2.tgz", "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-5.2.0.tgz",
"integrity": "sha512-1z7mtpwxcz5uUqq0HLO0ifj/tz2dWEmeaK+8c5TEZXAwwVxrjjg0118ODCOCCOcpfYaaEHxStNCaWVYo9FUPXw==", "integrity": "sha512-izfUfhEOOgAizszPlEDxo71DK/C4wprZw0vkY6UWcOSTQvN1JyfXf9DXwaV7WX+/JC+hH0ShXfdtGLA9Rca7LA==",
"dev": true, "dev": true,
"requires": { "requires": {
"app-root-path": "^2.2.1", "app-root-path": "^2.2.1",
@ -3507,18 +3537,6 @@
"is-directory": "^0.3.1", "is-directory": "^0.3.1",
"js-yaml": "^3.13.1", "js-yaml": "^3.13.1",
"parse-json": "^4.0.0" "parse-json": "^4.0.0"
},
"dependencies": {
"parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
"dev": true,
"requires": {
"error-ex": "^1.3.1",
"json-parse-better-errors": "^1.0.1"
}
}
} }
}, },
"create-ecdh": { "create-ecdh": {
@ -4257,23 +4275,6 @@
"dev": true, "dev": true,
"requires": { "requires": {
"path-type": "^3.0.0" "path-type": "^3.0.0"
},
"dependencies": {
"path-type": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
"dev": true,
"requires": {
"pify": "^3.0.0"
}
},
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"dev": true
}
} }
}, },
"dns-equal": { "dns-equal": {
@ -4367,9 +4368,9 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
}, },
"electron-to-chromium": { "electron-to-chromium": {
"version": "1.3.287", "version": "1.3.296",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.287.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.296.tgz",
"integrity": "sha512-0XlYcw6fJQ5Vh735iYJTMHysTMYjCwBFdOtyxhGbE3I9MQ2Wk2WXYIXjY1w8votvzh0fsQRaSVJ/bKUj073E9w==", "integrity": "sha512-s5hv+TSJSVRsxH190De66YHb50pBGTweT9XGWYu/LMR20KX6TsjFzObo36CjVAzM+PUeeKSBRtm/mISlCzeojQ==",
"dev": true "dev": true
}, },
"elliptic": { "elliptic": {
@ -4969,12 +4970,12 @@
} }
}, },
"find-up": { "find-up": {
"version": "1.1.2", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
"requires": { "requires": {
"path-exists": "^2.0.0", "locate-path": "^3.0.0"
"pinkie-promise": "^2.0.0"
} }
}, },
"flatted": { "flatted": {
@ -5495,9 +5496,9 @@
} }
}, },
"hosted-git-info": { "hosted-git-info": {
"version": "2.7.1", "version": "2.8.5",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
"integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==" "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg=="
}, },
"hpack.js": { "hpack.js": {
"version": "2.1.6", "version": "2.1.6",
@ -5608,9 +5609,9 @@
"dev": true "dev": true
}, },
"https-proxy-agent": { "https-proxy-agent": {
"version": "2.2.2", "version": "2.2.4",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
"integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
"dev": true, "dev": true,
"requires": { "requires": {
"agent-base": "^4.3.0", "agent-base": "^4.3.0",
@ -5904,9 +5905,10 @@
} }
}, },
"invert-kv": { "invert-kv": {
"version": "1.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
"dev": true
}, },
"ip": { "ip": {
"version": "1.1.5", "version": "1.1.5",
@ -7415,11 +7417,12 @@
} }
}, },
"lcid": { "lcid": {
"version": "1.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
"integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
"dev": true,
"requires": { "requires": {
"invert-kv": "^1.0.0" "invert-kv": "^2.0.0"
} }
}, },
"less": { "less": {
@ -7496,6 +7499,16 @@
"pify": "^2.0.0", "pify": "^2.0.0",
"pinkie-promise": "^2.0.0", "pinkie-promise": "^2.0.0",
"strip-bom": "^2.0.0" "strip-bom": "^2.0.0"
},
"dependencies": {
"parse-json": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
"integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
"requires": {
"error-ex": "^1.2.0"
}
}
} }
}, },
"loader-runner": { "loader-runner": {
@ -8219,6 +8232,16 @@
"version": "5.3.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8="
},
"tar": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz",
"integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==",
"requires": {
"block-stream": "*",
"fstream": "^1.0.12",
"inherits": "2"
}
} }
} }
}, },
@ -8262,9 +8285,9 @@
} }
}, },
"node-releases": { "node-releases": {
"version": "1.1.36", "version": "1.1.39",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.36.tgz", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.39.tgz",
"integrity": "sha512-ggXhX6QGyJSjj3r+6ml2LqqC28XOWmKtpb+a15/Zpr9V3yoNazxJNlcQDS9bYaid5FReEWHEgToH1mwoUceWwg==", "integrity": "sha512-8MRC/ErwNCHOlAFycy9OPca46fQYUjbJRDcZTHVWIGXIjYLM73k70vv3WkYutVnM4cCo4hE0MqBVVZjP6vjISA==",
"dev": true, "dev": true,
"requires": { "requires": {
"semver": "^6.3.0" "semver": "^6.3.0"
@ -8279,9 +8302,9 @@
} }
}, },
"node-sass": { "node-sass": {
"version": "4.12.0", "version": "4.13.0",
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.12.0.tgz", "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.0.tgz",
"integrity": "sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==", "integrity": "sha512-W1XBrvoJ1dy7VsvTAS5q1V45lREbTlZQqFbiHb3R3OTTCma0XBtuG6xZ6Z4506nR4lmHPTqVRwxT6KgtWC97CA==",
"requires": { "requires": {
"async-foreach": "^0.1.3", "async-foreach": "^0.1.3",
"chalk": "^1.1.1", "chalk": "^1.1.1",
@ -8290,7 +8313,7 @@
"get-stdin": "^4.0.1", "get-stdin": "^4.0.1",
"glob": "^7.0.3", "glob": "^7.0.3",
"in-publish": "^2.0.0", "in-publish": "^2.0.0",
"lodash": "^4.17.11", "lodash": "^4.17.15",
"meow": "^3.7.0", "meow": "^3.7.0",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"nan": "^2.13.2", "nan": "^2.13.2",
@ -9286,11 +9309,14 @@
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
}, },
"os-locale": { "os-locale": {
"version": "1.4.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
"dev": true,
"requires": { "requires": {
"lcid": "^1.0.0" "execa": "^1.0.0",
"lcid": "^2.0.0",
"mem": "^4.0.0"
} }
}, },
"os-tmpdir": { "os-tmpdir": {
@ -9418,21 +9444,6 @@
"yallist": "^3.0.2" "yallist": "^3.0.2"
} }
}, },
"tar": {
"version": "4.4.13",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz",
"integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==",
"dev": true,
"requires": {
"chownr": "^1.1.1",
"fs-minipass": "^1.2.5",
"minipass": "^2.8.6",
"minizlib": "^1.2.1",
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.2",
"yallist": "^3.0.3"
}
},
"yallist": { "yallist": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
@ -9473,11 +9484,13 @@
} }
}, },
"parse-json": { "parse-json": {
"version": "2.2.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
"dev": true,
"requires": { "requires": {
"error-ex": "^1.2.0" "error-ex": "^1.3.1",
"json-parse-better-errors": "^1.0.1"
} }
}, },
"parse5": { "parse5": {
@ -9559,13 +9572,20 @@
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
}, },
"path-type": { "path-type": {
"version": "1.1.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
"integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
"dev": true,
"requires": { "requires": {
"graceful-fs": "^4.1.2", "pify": "^3.0.0"
"pify": "^2.0.0", },
"pinkie-promise": "^2.0.0" "dependencies": {
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"dev": true
}
} }
}, },
"pbkdf2": { "pbkdf2": {
@ -9622,17 +9642,6 @@
"dev": true, "dev": true,
"requires": { "requires": {
"find-up": "^3.0.0" "find-up": "^3.0.0"
},
"dependencies": {
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
"requires": {
"locate-path": "^3.0.0"
}
}
} }
}, },
"portfinder": { "portfinder": {
@ -10167,6 +10176,18 @@
"load-json-file": "^1.0.0", "load-json-file": "^1.0.0",
"normalize-package-data": "^2.3.2", "normalize-package-data": "^2.3.2",
"path-type": "^1.0.0" "path-type": "^1.0.0"
},
"dependencies": {
"path-type": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
"integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
"requires": {
"graceful-fs": "^4.1.2",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0"
}
}
} }
}, },
"read-pkg-up": { "read-pkg-up": {
@ -10176,6 +10197,17 @@
"requires": { "requires": {
"find-up": "^1.0.0", "find-up": "^1.0.0",
"read-pkg": "^1.0.0" "read-pkg": "^1.0.0"
},
"dependencies": {
"find-up": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
"integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
"requires": {
"path-exists": "^2.0.0",
"pinkie-promise": "^2.0.0"
}
}
} }
}, },
"readable-stream": { "readable-stream": {
@ -10556,6 +10588,82 @@
"lodash": "^4.0.0", "lodash": "^4.0.0",
"scss-tokenizer": "^0.2.3", "scss-tokenizer": "^0.2.3",
"yargs": "^7.0.0" "yargs": "^7.0.0"
},
"dependencies": {
"camelcase": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
"integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo="
},
"cliui": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
"integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
"requires": {
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1",
"wrap-ansi": "^2.0.0"
}
},
"invert-kv": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY="
},
"lcid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
"integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
"requires": {
"invert-kv": "^1.0.0"
}
},
"os-locale": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
"requires": {
"lcid": "^1.0.0"
}
},
"which-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
"integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8="
},
"y18n": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE="
},
"yargs": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz",
"integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=",
"requires": {
"camelcase": "^3.0.0",
"cliui": "^3.2.0",
"decamelize": "^1.1.1",
"get-caller-file": "^1.0.1",
"os-locale": "^1.4.0",
"read-pkg-up": "^1.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^1.0.1",
"set-blocking": "^2.0.0",
"string-width": "^1.0.2",
"which-module": "^1.0.0",
"y18n": "^3.2.1",
"yargs-parser": "^5.0.0"
}
},
"yargs-parser": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
"integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
"requires": {
"camelcase": "^3.0.0"
}
}
} }
}, },
"sass-loader": { "sass-loader": {
@ -10613,6 +10721,16 @@
"requires": { "requires": {
"js-base64": "^2.1.8", "js-base64": "^2.1.8",
"source-map": "^0.4.2" "source-map": "^0.4.2"
},
"dependencies": {
"source-map": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
"requires": {
"amdefine": ">=0.0.4"
}
}
} }
}, },
"select-hose": { "select-hose": {
@ -11177,12 +11295,10 @@
"dev": true "dev": true
}, },
"source-map": { "source-map": {
"version": "0.4.4", "version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
"requires": { "dev": true
"amdefine": ">=0.0.4"
}
}, },
"source-map-loader": { "source-map-loader": {
"version": "0.2.4", "version": "0.2.4",
@ -11676,13 +11792,26 @@
"dev": true "dev": true
}, },
"tar": { "tar": {
"version": "2.2.2", "version": "4.4.13",
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz",
"integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==",
"dev": true,
"requires": { "requires": {
"block-stream": "*", "chownr": "^1.1.1",
"fstream": "^1.0.12", "fs-minipass": "^1.2.5",
"inherits": "2" "minipass": "^2.8.6",
"minizlib": "^1.2.1",
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.2",
"yallist": "^3.0.3"
},
"dependencies": {
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true
}
} }
}, },
"term-size": { "term-size": {
@ -13165,6 +13294,15 @@
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.8.tgz", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.8.tgz",
"integrity": "sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY=", "integrity": "sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY=",
"dev": true "dev": true
},
"source-map": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
"dev": true,
"requires": {
"amdefine": ">=0.0.4"
}
} }
} }
}, },
@ -13227,12 +13365,6 @@
"yargs": "12.0.5" "yargs": "12.0.5"
}, },
"dependencies": { "dependencies": {
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"dev": true
},
"anymatch": { "anymatch": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
@ -13278,12 +13410,6 @@
"to-regex": "^3.0.1" "to-regex": "^3.0.1"
} }
}, },
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true
},
"chokidar": { "chokidar": {
"version": "2.1.8", "version": "2.1.8",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
@ -13304,28 +13430,6 @@
"upath": "^1.1.1" "upath": "^1.1.1"
} }
}, },
"cliui": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
"integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
"dev": true,
"requires": {
"string-width": "^2.1.1",
"strip-ansi": "^4.0.0",
"wrap-ansi": "^2.0.0"
},
"dependencies": {
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"dev": true,
"requires": {
"ansi-regex": "^3.0.0"
}
}
}
},
"debug": { "debug": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
@ -13356,15 +13460,6 @@
"to-regex-range": "^2.1.0" "to-regex-range": "^2.1.0"
} }
}, },
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
"requires": {
"locate-path": "^3.0.0"
}
},
"fsevents": { "fsevents": {
"version": "1.2.9", "version": "1.2.9",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz",
@ -13913,12 +14008,6 @@
} }
} }
}, },
"invert-kv": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
"dev": true
},
"is-binary-path": { "is-binary-path": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
@ -13928,12 +14017,6 @@
"binary-extensions": "^1.0.0" "binary-extensions": "^1.0.0"
} }
}, },
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
"dev": true
},
"is-number": { "is-number": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
@ -13952,32 +14035,12 @@
"is-buffer": "^1.1.5" "is-buffer": "^1.1.5"
} }
}, },
"lcid": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
"integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
"dev": true,
"requires": {
"invert-kv": "^2.0.0"
}
},
"ms": { "ms": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true "dev": true
}, },
"os-locale": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
"integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
"dev": true,
"requires": {
"execa": "^1.0.0",
"lcid": "^2.0.0",
"mem": "^4.0.0"
}
},
"readdirp": { "readdirp": {
"version": "2.2.1", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
@ -13995,27 +14058,6 @@
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true "dev": true
}, },
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
"dev": true,
"requires": {
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^4.0.0"
},
"dependencies": {
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"dev": true,
"requires": {
"ansi-regex": "^3.0.0"
}
}
}
},
"supports-color": { "supports-color": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
@ -14034,42 +14076,6 @@
"is-number": "^3.0.0", "is-number": "^3.0.0",
"repeat-string": "^1.6.1" "repeat-string": "^1.6.1"
} }
},
"which-module": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true
},
"yargs": {
"version": "12.0.5",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
"integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
"dev": true,
"requires": {
"cliui": "^4.0.0",
"decamelize": "^1.2.0",
"find-up": "^3.0.0",
"get-caller-file": "^1.0.1",
"os-locale": "^3.0.0",
"require-directory": "^2.1.1",
"require-main-filename": "^1.0.1",
"set-blocking": "^2.0.0",
"string-width": "^2.0.0",
"which-module": "^2.0.0",
"y18n": "^3.2.1 || ^4.0.0",
"yargs-parser": "^11.1.1"
}
},
"yargs-parser": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
"integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
} }
} }
}, },
@ -14151,9 +14157,10 @@
} }
}, },
"which-module": { "which-module": {
"version": "1.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
"integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true
}, },
"wide-align": { "wide-align": {
"version": "1.1.3", "version": "1.1.3",
@ -14305,9 +14312,10 @@
"dev": true "dev": true
}, },
"y18n": { "y18n": {
"version": "3.2.1", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
"dev": true
}, },
"yallist": { "yallist": {
"version": "2.1.2", "version": "2.1.2",
@ -14315,45 +14323,66 @@
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
}, },
"yargs": { "yargs": {
"version": "7.1.0", "version": "12.0.5",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
"integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
"dev": true,
"requires": { "requires": {
"camelcase": "^3.0.0", "cliui": "^4.0.0",
"cliui": "^3.2.0", "decamelize": "^1.2.0",
"decamelize": "^1.1.1", "find-up": "^3.0.0",
"get-caller-file": "^1.0.1", "get-caller-file": "^1.0.1",
"os-locale": "^1.4.0", "os-locale": "^3.0.0",
"read-pkg-up": "^1.0.1",
"require-directory": "^2.1.1", "require-directory": "^2.1.1",
"require-main-filename": "^1.0.1", "require-main-filename": "^1.0.1",
"set-blocking": "^2.0.0", "set-blocking": "^2.0.0",
"string-width": "^1.0.2", "string-width": "^2.0.0",
"which-module": "^1.0.0", "which-module": "^2.0.0",
"y18n": "^3.2.1", "y18n": "^3.2.1 || ^4.0.0",
"yargs-parser": "^5.0.0" "yargs-parser": "^11.1.1"
}, },
"dependencies": { "dependencies": {
"camelcase": { "ansi-regex": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"dev": true
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
"dev": true
},
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
"dev": true,
"requires": {
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^4.0.0"
}
},
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"dev": true,
"requires": {
"ansi-regex": "^3.0.0"
}
} }
} }
}, },
"yargs-parser": { "yargs-parser": {
"version": "5.0.0", "version": "11.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
"integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
"dev": true,
"requires": { "requires": {
"camelcase": "^3.0.0" "camelcase": "^5.0.0",
}, "decamelize": "^1.2.0"
"dependencies": {
"camelcase": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
"integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo="
}
} }
}, },
"yeast": { "yeast": {

@ -1,6 +1,6 @@
{ {
"name": "rtl", "name": "rtl",
"version": "0.5.4-beta", "version": "0.5.5-beta",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
@ -45,7 +45,7 @@
"jsonwebtoken": "^8.4.0", "jsonwebtoken": "^8.4.0",
"material-design-icons": "^3.0.1", "material-design-icons": "^3.0.1",
"ngx-perfect-scrollbar": "^6.3.1", "ngx-perfect-scrollbar": "^6.3.1",
"node-sass": "^4.12.0", "node-sass": "^4.13.0",
"nodemon": "^1.19.4", "nodemon": "^1.19.4",
"optimist": "^0.6.1", "optimist": "^0.6.1",
"request-promise": "^4.2.2", "request-promise": "^4.2.2",
@ -65,7 +65,7 @@
"@types/jasmine": "~3.3.8", "@types/jasmine": "~3.3.8",
"@types/jasminewd2": "^2.0.8", "@types/jasminewd2": "^2.0.8",
"@types/node": "~8.9.4", "@types/node": "~8.9.4",
"codelyzer": "^5.1.2", "codelyzer": "^5.2.0",
"jasmine-core": "~3.4.0", "jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1", "jasmine-spec-reporter": "~4.2.1",
"karma": "~4.1.0", "karma": "~4.1.0",

@ -4,6 +4,7 @@ const router = express.Router();
const authCheck = require("../authCheck"); const authCheck = require("../authCheck");
router.get("/genseed/:passphrase?", authCheck, WalletController.genSeed); router.get("/genseed/:passphrase?", authCheck, WalletController.genSeed);
router.get("/updateSelNodeOptions", authCheck, WalletController.updateSelNodeOptions);
router.post("/:operation", authCheck, WalletController.operateWallet); router.post("/:operation", authCheck, WalletController.operateWallet);
module.exports = router; module.exports = router;

@ -9,6 +9,7 @@ import { UserIdleService } from 'angular-user-idle';
import * as sha256 from 'sha256'; import * as sha256 from 'sha256';
import { LoggerService } from './shared/services/logger.service'; import { LoggerService } from './shared/services/logger.service';
import { SessionService } from './shared/services/session.service';
import { RTLConfiguration, Settings, LightningNode, GetInfoRoot } from './shared/models/RTLconfig'; import { RTLConfiguration, Settings, LightningNode, GetInfoRoot } from './shared/models/RTLconfig';
import * as RTLActions from './store/rtl.actions'; import * as RTLActions from './store/rtl.actions';
@ -33,7 +34,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
unsubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()]; unsubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions, constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions,
private userIdle: UserIdleService, private router: Router, private activatedRoute: ActivatedRoute) {} private userIdle: UserIdleService, private router: Router, private sessionService: SessionService) {}
ngOnInit() { ngOnInit() {
this.store.dispatch(new RTLActions.FetchRTLConfig()); this.store.dispatch(new RTLActions.FetchRTLConfig());
@ -55,15 +56,16 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
this.smallScreen = true; this.smallScreen = true;
} }
this.logger.info(this.settings); this.logger.info(this.settings);
if (!sessionStorage.getItem('token')) { if (!this.sessionService.getItem('token')) {
this.flgLoading[0] = false; this.flgLoading[0] = false;
} }
}); });
this.actions$.pipe(takeUntil(this.unsubs[1]), this.actions$.pipe(takeUntil(this.unsubs[1]),
filter((action) => action.type === RTLActions.SET_RTL_CONFIG)) filter((action) => action.type === RTLActions.SET_RTL_CONFIG))
.subscribe((action: (RTLActions.SetRTLConfig)) => { .subscribe((action: (RTLActions.SetRTLConfig)) => {
if (action.type === RTLActions.SET_RTL_CONFIG) { if (action.type === RTLActions.SET_RTL_CONFIG) {
if (!sessionStorage.getItem('token')) { if (!this.sessionService.getItem('token')) {
if (+action.payload.sso.rtlSSO) { if (+action.payload.sso.rtlSSO) {
this.store.dispatch(new RTLActions.Signin(sha256(this.accessKey))); this.store.dispatch(new RTLActions.Signin(sha256(this.accessKey)));
} else { } else {
@ -82,7 +84,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
this.userIdle.startWatching(); this.userIdle.startWatching();
this.userIdle.onTimerStart().subscribe(count => {}); this.userIdle.onTimerStart().subscribe(count => {});
this.userIdle.onTimeout().subscribe(() => { this.userIdle.onTimeout().subscribe(() => {
if (sessionStorage.getItem('token')) { if (this.sessionService.getItem('token')) {
this.logger.warn('Time limit exceeded for session inactivity! Logging out!'); this.logger.warn('Time limit exceeded for session inactivity! Logging out!');
this.store.dispatch(new RTLActions.OpenAlert({ width: '75%', data: { this.store.dispatch(new RTLActions.OpenAlert({ width: '75%', data: {
type: 'WARN', type: 'WARN',

@ -23,7 +23,7 @@ import { ThemeOverlay } from './shared/theme/overlay-container/theme-overlay';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { environment } from '../environments/environment'; import { environment } from '../environments/environment';
import { CommonService } from './shared/services/common.service'; import { SessionService } from './shared/services/session.service';
import { LoggerService, ConsoleLoggerService } from './shared/services/logger.service'; import { LoggerService, ConsoleLoggerService } from './shared/services/logger.service';
import { AuthGuard } from './shared/services/auth.guard'; import { AuthGuard } from './shared/services/auth.guard';
import { AuthInterceptor } from './shared/services/auth.interceptor'; import { AuthInterceptor } from './shared/services/auth.interceptor';
@ -53,7 +53,7 @@ import { CLEffects } from './clightning/store/cl.effects';
{ provide: OverlayContainer, useClass: ThemeOverlay }, { provide: OverlayContainer, useClass: ThemeOverlay },
{ provide: PERFECT_SCROLLBAR_CONFIG, useValue: DEFAULT_PERFECT_SCROLLBAR_CONFIG }, { provide: PERFECT_SCROLLBAR_CONFIG, useValue: DEFAULT_PERFECT_SCROLLBAR_CONFIG },
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
AuthGuard, CommonService AuthGuard, SessionService
], ],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })

@ -6,7 +6,7 @@ import { NotFoundComponent } from './shared/components/not-found/not-found.compo
import { ServerConfigComponent } from './shared/components/server-config/server-config.component'; import { ServerConfigComponent } from './shared/components/server-config/server-config.component';
import { HelpComponent } from './shared/components/help/help.component'; import { HelpComponent } from './shared/components/help/help.component';
import { SigninComponent } from './shared/components/signin/signin.component'; import { SigninComponent } from './shared/components/signin/signin.component';
import { SsoFailedComponent } from './shared/components/sso-failed/sso-failed.component'; import { ErrorComponent } from './shared/components/error/error.component';
import { AuthGuard } from './shared/services/auth.guard'; import { AuthGuard } from './shared/services/auth.guard';
export const routes: Routes = [ export const routes: Routes = [
@ -16,7 +16,7 @@ export const routes: Routes = [
{ path: 'settings', component: AppSettingsComponent, canActivate: [AuthGuard] }, { path: 'settings', component: AppSettingsComponent, canActivate: [AuthGuard] },
{ path: 'help', component: HelpComponent }, { path: 'help', component: HelpComponent },
{ path: 'login', component: SigninComponent }, { path: 'login', component: SigninComponent },
{ path: 'ssoerror', component: SsoFailedComponent }, { path: 'error', component: ErrorComponent },
{ path: '**', component: NotFoundComponent } { path: '**', component: NotFoundComponent }
]; ];

@ -1,46 +1,10 @@
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Component } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil, filter } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import * as RTLActions from '../store/rtl.actions';
import * as fromRTLReducer from '../store/rtl.reducers';
@Component({ @Component({
selector: 'rtl-cl-root', selector: 'rtl-cl-root',
templateUrl: './cl-root.component.html', templateUrl: './cl-root.component.html',
styleUrls: ['./cl-root.component.scss'] styleUrls: ['./cl-root.component.scss']
}) })
export class CLRootComponent implements OnInit, OnDestroy { export class CLRootComponent {
unsubs: Array<Subject<void>> = [new Subject(), new Subject()]; constructor() {}
constructor(private store: Store<fromRTLReducer.RTLState>, private actions$: Actions, private router: Router, private activatedRoute: ActivatedRoute) {}
ngOnInit() {
this.store.dispatch(new RTLActions.FetchInfoCL());
this.actions$.pipe(takeUntil(this.unsubs[0]), filter((action) => action.type === RTLActions.SET_INFO_CL))
.subscribe((infoData: RTLActions.SetInfoCL) => {
if(infoData.type === RTLActions.SET_INFO_CL && undefined !== infoData.payload.id) {
this.initializeRemainingData();
}
});
}
initializeRemainingData() {
this.store.dispatch(new RTLActions.FetchFeesCL());
this.store.dispatch(new RTLActions.FetchBalanceCL());
this.store.dispatch(new RTLActions.FetchLocalRemoteBalanceCL());
this.store.dispatch(new RTLActions.FetchFeeRatesCL('perkw'));
this.store.dispatch(new RTLActions.FetchFeeRatesCL('perkb'));
this.store.dispatch(new RTLActions.FetchPeersCL());
}
ngOnDestroy() {
this.unsubs.forEach(unsub => {
unsub.next();
unsub.complete();
});
}
} }

@ -1,12 +1,14 @@
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators'; import { takeUntil, filter } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { LoggerService } from '../../shared/services/logger.service'; import { LoggerService } from '../../shared/services/logger.service';
import { GetInfoCL, FeesCL, BalanceCL, LocalRemoteBalanceCL, FeeRatesCL } from '../../shared/models/clModels'; import { GetInfoCL, FeesCL, BalanceCL, LocalRemoteBalanceCL, FeeRatesCL } from '../../shared/models/clModels';
import { SelNodeChild } from '../../shared/models/RTLconfig'; import { SelNodeChild } from '../../shared/models/RTLconfig';
import * as RTLActions from '../../store/rtl.actions';
import * as fromRTLReducer from '../../store/rtl.reducers'; import * as fromRTLReducer from '../../store/rtl.reducers';
@Component({ @Component({
@ -19,14 +21,14 @@ export class CLHomeComponent implements OnInit, OnDestroy {
public fees: FeesCL; public fees: FeesCL;
public information: GetInfoCL = {}; public information: GetInfoCL = {};
public totalBalance: BalanceCL = {}; public totalBalance: BalanceCL = {};
public lrBalance: LocalRemoteBalanceCL = {}; public lrBalance: LocalRemoteBalanceCL = { localBalance: 0, remoteBalance: 0 };
public flgLoading: Array<Boolean | 'error'> = [true, true, true, true, true]; public flgLoading: Array<Boolean | 'error'> = [true, true, true, true, true];
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()]; private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
public position = 'below'; public position = 'below';
barPadding = 0; barPadding = 0;
maxBalanceValue = 0; maxBalanceValue = 0;
lrBalances = [...[{'name': 'Local Balance', 'value': 0}, {'name': 'Remote Balance', 'value': 0}]]; lrBalances = [{'name': 'Local Balance', 'value': 0}, {'name': 'Remote Balance', 'value': 0}];
flgTotalCalculated = false; flgTotalCalculated = false;
view = []; view = [];
yAxisLabel = 'Balance'; yAxisLabel = 'Balance';
@ -34,7 +36,7 @@ export class CLHomeComponent implements OnInit, OnDestroy {
feeRatesPerKB: FeeRatesCL = {}; feeRatesPerKB: FeeRatesCL = {};
feeRatesPerKW: FeeRatesCL = {}; feeRatesPerKW: FeeRatesCL = {};
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>) { constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions) {
switch (true) { switch (true) {
case (window.innerWidth <= 730): case (window.innerWidth <= 730):
this.view = [250, 352]; this.view = [250, 352];
@ -56,7 +58,11 @@ export class CLHomeComponent implements OnInit, OnDestroy {
} }
ngOnInit() { ngOnInit() {
this.flgTotalCalculated = false; this.actions$.pipe(takeUntil(this.unsub[0]),
filter(action => action.type === RTLActions.SET_SELECTED_NODE))
.subscribe((data) => {
this.flgTotalCalculated = false;
});
this.store.select('cl') this.store.select('cl')
.pipe(takeUntil(this.unsub[0])) .pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore) => { .subscribe((rtlStore) => {
@ -96,9 +102,9 @@ export class CLHomeComponent implements OnInit, OnDestroy {
this.lrBalance = rtlStore.localRemoteBalance; this.lrBalance = rtlStore.localRemoteBalance;
this.maxBalanceValue = (rtlStore.localRemoteBalance.localBalance > rtlStore.localRemoteBalance.remoteBalance) ? rtlStore.localRemoteBalance.localBalance : rtlStore.localRemoteBalance.remoteBalance; this.maxBalanceValue = (rtlStore.localRemoteBalance.localBalance > rtlStore.localRemoteBalance.remoteBalance) ? rtlStore.localRemoteBalance.localBalance : rtlStore.localRemoteBalance.remoteBalance;
this.lrBalances = [...[{'name': 'Local Balance', 'value': +rtlStore.localRemoteBalance.localBalance}, {'name': 'Remote Balance', 'value': +rtlStore.localRemoteBalance.remoteBalance}]]; this.lrBalances = [{'name': 'Local Balance', 'value': +rtlStore.localRemoteBalance.localBalance}, {'name': 'Remote Balance', 'value': +rtlStore.localRemoteBalance.remoteBalance}];
if (this.flgLoading[3] !== 'error') { if (this.flgLoading[3] !== 'error') {
this.flgLoading[3] = ('' !== this.lrBalance) ? false : true; this.flgLoading[3] = (this.lrBalance.localBalance >= 0) ? false : true;
} }
this.feeRatesPerKB = rtlStore.feeRatesPerKB; this.feeRatesPerKB = rtlStore.feeRatesPerKB;

@ -1,13 +1,16 @@
import { Injectable, OnDestroy } from '@angular/core'; import { Injectable, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { Actions, Effect, ofType } from '@ngrx/effects'; import { Actions, Effect, ofType } from '@ngrx/effects';
import { Subject, of } from 'rxjs'; import { Subject, of } from 'rxjs';
import { map, mergeMap, catchError, withLatestFrom } from 'rxjs/operators'; import { map, mergeMap, catchError, withLatestFrom } from 'rxjs/operators';
import { formatDate } from '@angular/common'; import { formatDate } from '@angular/common';
import { Location } from '@angular/common';
import { environment, API_URL } from '../../../environments/environment'; import { environment, API_URL } from '../../../environments/environment';
import { LoggerService } from '../../shared/services/logger.service'; import { LoggerService } from '../../shared/services/logger.service';
import { SessionService } from '../../shared/services/session.service';
import { GetInfoCL, FeesCL, BalanceCL, LocalRemoteBalanceCL, PaymentCL, FeeRatesCL, ListInvoicesCL, InvoiceCL } from '../../shared/models/clModels'; import { GetInfoCL, FeesCL, BalanceCL, LocalRemoteBalanceCL, PaymentCL, FeeRatesCL, ListInvoicesCL, InvoiceCL } from '../../shared/models/clModels';
import * as fromRTLReducer from '../../store/rtl.reducers'; import * as fromRTLReducer from '../../store/rtl.reducers';
@ -22,51 +25,47 @@ export class CLEffects implements OnDestroy {
private actions$: Actions, private actions$: Actions,
private httpClient: HttpClient, private httpClient: HttpClient,
private store: Store<fromRTLReducer.RTLState>, private store: Store<fromRTLReducer.RTLState>,
private logger: LoggerService) { } private sessionService: SessionService,
private logger: LoggerService,
private router: Router,
private location: Location) { }
@Effect() @Effect()
infoFetchCL = this.actions$.pipe( infoFetchCL = this.actions$.pipe(
ofType(RTLActions.FETCH_INFO_CL), ofType(RTLActions.FETCH_INFO_CL),
withLatestFrom(this.store.select('root')), withLatestFrom(this.store.select('root')),
mergeMap(([action, store]) => { mergeMap(([action, store]: [RTLActions.FetchInfoCL, fromRTLReducer.RootState]) => {
this.store.dispatch(new RTLActions.ClearEffectErrorCl('FetchInfoCL')); this.store.dispatch(new RTLActions.ClearEffectErrorCl('FetchInfoCL'));
return this.httpClient.get<GetInfoCL>(this.CHILD_API_URL + environment.GETINFO_API) return this.httpClient.get<GetInfoCL>(this.CHILD_API_URL + environment.GETINFO_API)
.pipe( .pipe(
map((info) => { map((info) => {
this.logger.info(info); this.logger.info(info);
let chainObj = { chain: '', network: '' }; this.initializeRemainingData(info, action.payload.loadPage);
if (info.network === 'testnet') {
chainObj.chain = 'Bitcoin';
chainObj.network = 'Testnet';
} else if (info.network === 'bitcoin') {
chainObj.chain = 'Bitcoin';
chainObj.network = 'Mainnet';
} else if (info.network === 'litecoin') {
chainObj.chain = 'Litecoin';
chainObj.network = 'Mainnet';
} else if (info.network === 'litecoin-testnet') {
chainObj.chain = 'Litecoin';
chainObj.network = 'Testnet';
}
sessionStorage.setItem('clUnlocked', 'true');
const node_data = {
identity_pubkey: info.id,
alias: info.alias,
testnet: (info.network === 'testnet' || info.network === 'litecoin-testnet') ? true : false,
chains: [chainObj],
version: info.version,
currency_unit: 'BTC',
smaller_currency_unit: 'Sats',
numberOfPendingChannels: info.num_pending_channels
};
this.store.dispatch(new RTLActions.SetNodeData(node_data));
return { return {
type: RTLActions.SET_INFO_CL, type: RTLActions.SET_INFO_CL,
payload: (undefined !== info) ? info : {} payload: (undefined !== info) ? info : {}
}; };
}), }),
catchError((err) => { catchError((err) => {
return this.handleErrorWithAlert('ERROR', 'Get Info Failed', this.CHILD_API_URL + environment.GETINFO_API, err); let code = err.status ? err.status : '';
let message = err.error.message ? err.error.message + ' ' : '';
if (err.error && err.error.error) {
if (err.error.error.code) {
code = err.error.error.code;
} else if (err.error.error.message && err.error.error.message.code) {
code = err.error.error.message.code;
}
if (typeof err.error.error === 'string') {
message = message + err.error.error;
} else if (err.error.error.error) {
message = message + err.error.error.error;
} else if (err.error.error.errno) {
message = message + err.error.error.errno;
}
}
this.router.navigate(['/error'], { state: { errorCode: code, errorMessage: message }});
this.handleErrorWithoutAlert('FetchInfoCL', err);
return of({type: RTLActions.VOID});
}) })
); );
} }
@ -87,7 +86,8 @@ export class CLEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchFeesCL', err); this.handleErrorWithoutAlert('FetchFeesCL', err);
return of({type: RTLActions.VOID});
} }
)); ));
@ -106,7 +106,8 @@ export class CLEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchFeeRatesCL', err); this.handleErrorWithoutAlert('FetchFeeRatesCL', err);
return of({type: RTLActions.VOID});
} }
)); ));
@ -125,7 +126,8 @@ export class CLEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchBalanceCL', err); this.handleErrorWithoutAlert('FetchBalanceCL', err);
return of({type: RTLActions.VOID});
} }
)); ));
@ -144,7 +146,8 @@ export class CLEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchLocalRemoteBalanceCL', err); this.handleErrorWithoutAlert('FetchLocalRemoteBalanceCL', err);
return of({type: RTLActions.VOID});
} }
)); ));
@ -162,7 +165,8 @@ export class CLEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Generate New Address Failed', this.CHILD_API_URL + environment.ON_CHAIN_API + '?type=' + action.payload.addressId, err); this.handleErrorWithAlert('ERROR', 'Generate New Address Failed', this.CHILD_API_URL + environment.ON_CHAIN_API + '?type=' + action.payload.addressId, err);
return of({type: RTLActions.VOID});
})); }));
}) })
); );
@ -191,7 +195,8 @@ export class CLEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchPeersCL', err); this.handleErrorWithoutAlert('FetchPeersCL', err);
return of({type: RTLActions.VOID});
}) })
); );
} }
@ -213,7 +218,8 @@ export class CLEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Add Peer Failed', this.CHILD_API_URL + environment.PEERS_API, err); this.handleErrorWithAlert('ERROR', 'Add Peer Failed', this.CHILD_API_URL + environment.PEERS_API, err);
return of({type: RTLActions.VOID});
}) })
); );
} }
@ -235,7 +241,8 @@ export class CLEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Unable to Detach Peer. Try again later.', this.CHILD_API_URL + environment.PEERS_API + '/' + action.payload.id, err); this.handleErrorWithAlert('ERROR', 'Unable to Detach Peer. Try again later.', this.CHILD_API_URL + environment.PEERS_API + '/' + action.payload.id, err);
return of({type: RTLActions.VOID});
}) })
); );
} }
@ -256,7 +263,8 @@ export class CLEffects implements OnDestroy {
}; };
}, },
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchChannelsCL', err); this.handleErrorWithoutAlert('FetchChannelsCL', err);
return of({type: RTLActions.VOID});
}) })
)); ));
} }
@ -278,7 +286,8 @@ export class CLEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Open Channel Failed', this.CHILD_API_URL + environment.CHANNELS_API, err); this.handleErrorWithAlert('ERROR', 'Open Channel Failed', this.CHILD_API_URL + environment.CHANNELS_API, err);
return of({type: RTLActions.VOID});
}) })
); );
} }
@ -300,7 +309,8 @@ export class CLEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Update Channel Failed', this.CHILD_API_URL + environment.CHANNELS_API, err); this.handleErrorWithAlert('ERROR', 'Update Channel Failed', this.CHILD_API_URL + environment.CHANNELS_API, err);
return of({type: RTLActions.VOID});
}) })
); );
} }
@ -323,7 +333,8 @@ export class CLEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Unable to Close Channel. Try again later.', this.CHILD_API_URL + environment.CHANNELS_API, err); this.handleErrorWithAlert('ERROR', 'Unable to Close Channel. Try again later.', this.CHILD_API_URL + environment.CHANNELS_API, err);
return of({type: RTLActions.VOID});
}) })
); );
} }
@ -344,9 +355,10 @@ export class CLEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchPaymentsCL', err); this.handleErrorWithoutAlert('FetchPaymentsCL', err);
return of({type: RTLActions.VOID});
} }
)); ));
@Effect() @Effect()
decodePaymentCL = this.actions$.pipe( decodePaymentCL = this.actions$.pipe(
@ -363,7 +375,8 @@ export class CLEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Decode Payment Failed', this.CHILD_API_URL + environment.PAYMENTS_API + '/' + action.payload, err); this.handleErrorWithAlert('ERROR', 'Decode Payment Failed', this.CHILD_API_URL + environment.PAYMENTS_API + '/' + action.payload, err);
return of({type: RTLActions.VOID});
}) })
); );
}) })
@ -389,7 +402,7 @@ export class CLEffects implements OnDestroy {
this.logger.info(sendRes); this.logger.info(sendRes);
this.store.dispatch(new RTLActions.CloseSpinner()); this.store.dispatch(new RTLActions.CloseSpinner());
if (sendRes.error) { if (sendRes.error) {
return this.handleErrorWithAlert('ERROR', 'Send Payment Failed', this.CHILD_API_URL + environment.PAYMENTS_API, { status: sendRes.status, error: sendRes.error.message }); this.handleErrorWithAlert('ERROR', 'Send Payment Failed', this.CHILD_API_URL + environment.PAYMENTS_API, { status: sendRes.status, error: sendRes.error.message });
} else { } else {
this.store.dispatch(new RTLActions.OpenAlert({ this.store.dispatch(new RTLActions.OpenAlert({
width: '70%', width: '70%',
@ -405,7 +418,8 @@ export class CLEffects implements OnDestroy {
} }
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Send Payment Failed', this.CHILD_API_URL + environment.PAYMENTS_API, err); this.handleErrorWithAlert('ERROR', 'Send Payment Failed', this.CHILD_API_URL + environment.PAYMENTS_API, err);
return of({type: RTLActions.VOID});
}) })
); );
}) })
@ -426,7 +440,8 @@ export class CLEffects implements OnDestroy {
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.SetQueryRoutesCL({ routes: [] })); this.store.dispatch(new RTLActions.SetQueryRoutesCL({ routes: [] }));
return this.handleErrorWithAlert('ERROR', 'Get Query Routes Failed', this.CHILD_API_URL + environment.NETWORK_API + '/getRoute/' + action.payload.destPubkey + '/' + action.payload.amount, err); this.handleErrorWithAlert('ERROR', 'Get Query Routes Failed', this.CHILD_API_URL + environment.NETWORK_API + '/getRoute/' + action.payload.destPubkey + '/' + action.payload.amount, err);
return of({type: RTLActions.VOID});
}) })
); );
} }
@ -457,7 +472,8 @@ export class CLEffects implements OnDestroy {
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'LookupCL', code: err.status, message: err.error.message })); this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'LookupCL', code: err.status, message: err.error.message }));
return this.handleErrorWithAlert('ERROR', 'Peer Lookup Failed', this.CHILD_API_URL + environment.NETWORK_API + '/listNode/' + action.payload, err); this.handleErrorWithAlert('ERROR', 'Peer Lookup Failed', this.CHILD_API_URL + environment.NETWORK_API + '/listNode/' + action.payload, err);
return of({type: RTLActions.VOID});
}) })
); );
}) })
@ -480,7 +496,8 @@ export class CLEffects implements OnDestroy {
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'LookupCL', code: err.status, message: err.error.message })); this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'LookupCL', code: err.status, message: err.error.message }));
return this.handleErrorWithAlert('ERROR', 'Channel Lookup Failed', this.CHILD_API_URL + environment.NETWORK_API + '/listChannel/' + action.payload, err); this.handleErrorWithAlert('ERROR', 'Channel Lookup Failed', this.CHILD_API_URL + environment.NETWORK_API + '/listChannel/' + action.payload, err);
return of({type: RTLActions.VOID});
}) })
); );
}) })
@ -503,7 +520,8 @@ export class CLEffects implements OnDestroy {
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'LookupCL', code: err.status, message: err.error.message })); this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'LookupCL', code: err.status, message: err.error.message }));
return this.handleErrorWithAlert('ERROR', 'Invoice Lookup Failed', this.CHILD_API_URL + environment.NETWORK_API + '/listInvoice?label=' + action.payload, err); this.handleErrorWithAlert('ERROR', 'Invoice Lookup Failed', this.CHILD_API_URL + environment.NETWORK_API + '/listInvoice?label=' + action.payload, err);
return of({type: RTLActions.VOID});
}) })
); );
}) })
@ -538,7 +556,8 @@ export class CLEffects implements OnDestroy {
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'GetForwardingHistory', code: err.status, message: err.error.error })); this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'GetForwardingHistory', code: err.status, message: err.error.error }));
return this.handleErrorWithAlert('ERROR', 'Get Forwarding History Failed', this.CHILD_API_URL + environment.CHANNELS_API + '/listForwards', err); this.handleErrorWithAlert('ERROR', 'Get Forwarding History Failed', this.CHILD_API_URL + environment.CHANNELS_API + '/listForwards', err);
return of({type: RTLActions.VOID});
}) })
); );
}) })
@ -564,7 +583,8 @@ export class CLEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Delete Invoice Failed', this.CHILD_API_URL + environment.INVOICES_API, err); this.handleErrorWithAlert('ERROR', 'Delete Invoice Failed', this.CHILD_API_URL + environment.INVOICES_API, err);
return of({type: RTLActions.VOID});
}) })
); );
} }
@ -596,7 +616,8 @@ export class CLEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Add Invoice Failed', this.CHILD_API_URL + environment.INVOICES_API, err); this.handleErrorWithAlert('ERROR', 'Add Invoice Failed', this.CHILD_API_URL + environment.INVOICES_API, err);
return of({type: RTLActions.VOID});
}) })
); );
} }
@ -620,9 +641,10 @@ export class CLEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchInvoicesCL', err); this.handleErrorWithoutAlert('FetchInvoicesCL', err);
return of({type: RTLActions.VOID});
} }
)); ));
})); }));
@Effect() @Effect()
@ -643,20 +665,63 @@ export class CLEffects implements OnDestroy {
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'SetChannelTransactionCL', code: err.status, message: err.error.error })); this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'SetChannelTransactionCL', code: err.status, message: err.error.error }));
return this.handleErrorWithAlert('ERROR', 'Sending Fund Failed', this.CHILD_API_URL + environment.ON_CHAIN_API, err); this.handleErrorWithAlert('ERROR', 'Sending Fund Failed', this.CHILD_API_URL + environment.ON_CHAIN_API, err);
return of({type: RTLActions.VOID});
})); }));
}) })
); );
initializeRemainingData(info: any, landingPage: string) {
this.sessionService.setItem('clUnlocked', 'true');
let chainObj = { chain: '', network: '' };
if (info.network === 'testnet') {
chainObj.chain = 'Bitcoin';
chainObj.network = 'Testnet';
} else if (info.network === 'bitcoin') {
chainObj.chain = 'Bitcoin';
chainObj.network = 'Mainnet';
} else if (info.network === 'litecoin') {
chainObj.chain = 'Litecoin';
chainObj.network = 'Mainnet';
} else if (info.network === 'litecoin-testnet') {
chainObj.chain = 'Litecoin';
chainObj.network = 'Testnet';
}
const node_data = {
identity_pubkey: info.id,
alias: info.alias,
testnet: (info.network === 'testnet' || info.network === 'litecoin-testnet') ? true : false,
chains: [chainObj],
version: info.version,
currency_unit: 'BTC',
smaller_currency_unit: 'Sats',
numberOfPendingChannels: info.num_pending_channels
};
this.store.dispatch(new RTLActions.SetNodeData(node_data));
this.store.dispatch(new RTLActions.FetchFeesCL());
this.store.dispatch(new RTLActions.FetchBalanceCL());
this.store.dispatch(new RTLActions.FetchLocalRemoteBalanceCL());
this.store.dispatch(new RTLActions.FetchFeeRatesCL('perkw'));
this.store.dispatch(new RTLActions.FetchFeeRatesCL('perkb'));
this.store.dispatch(new RTLActions.FetchPeersCL());
let newRoute = this.location.path();
if (newRoute.includes('/login') || newRoute.includes('/error') || newRoute === '' || landingPage === 'HOME' || newRoute.includes('?access-key=')) {
newRoute = '/cl/home';
} else {
if(newRoute.includes('/lnd/')) {
newRoute = newRoute.replace('/lnd/', '/cl/');
}
}
this.router.navigate([newRoute]);
}
handleErrorWithoutAlert(actionName: string, err: { status: number, error: any }) { handleErrorWithoutAlert(actionName: string, err: { status: number, error: any }) {
this.logger.error(err); this.logger.error('ERROR IN: ' + actionName + '\n' + JSON.stringify(err));
if (err.status === 401) { if (err.status === 401) {
this.logger.info('Redirecting to Signin'); this.logger.info('Redirecting to Signin');
return of({ type: RTLActions.SIGNOUT }); this.store.dispatch(new RTLActions.Signout());
} else { } else {
this.store.dispatch(new RTLActions.EffectErrorCl({ action: actionName, code: err.status.toString(), message: err.error.error })); this.store.dispatch(new RTLActions.EffectErrorCl({ action: actionName, code: err.status.toString(), message: err.error.error }));
this.logger.error(err);
return of({ type: RTLActions.VOID });
} }
} }
@ -664,21 +729,15 @@ export class CLEffects implements OnDestroy {
this.logger.error(err); this.logger.error(err);
if (err.status === 401) { if (err.status === 401) {
this.logger.info('Redirecting to Signin'); this.logger.info('Redirecting to Signin');
return of({ type: RTLActions.SIGNOUT }); this.store.dispatch(new RTLActions.Signout());
} else { } else {
this.store.dispatch(new RTLActions.CloseSpinner()); this.store.dispatch(new RTLActions.CloseSpinner());
this.logger.error(err); this.store.dispatch(new RTLActions.OpenAlert({
return of( width: '70%', data: {
{ type: alerType, titleMessage: alertTitle,
type: RTLActions.OPEN_ALERT, message: JSON.stringify({ code: err.status, Message: err.error.error, URL: errURL })
payload: {
width: '70%', data: {
type: alerType, titleMessage: alertTitle,
message: JSON.stringify({ code: err.status, Message: err.error.error, URL: errURL })
}
}
} }
); }));
} }
} }

@ -30,7 +30,7 @@ export const initCLState: CLState = {
feeRatesPerKB: {}, feeRatesPerKB: {},
feeRatesPerKW: {}, feeRatesPerKW: {},
balance: {}, balance: {},
localRemoteBalance: {}, localRemoteBalance: { localBalance: -1, remoteBalance: -1 },
peers: [], peers: [],
allChannels: [], allChannels: [],
payments: [], payments: [],

@ -1,10 +1,8 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Router, NavigationStart, ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { Subject } from 'rxjs';
import { Subject, Observable } from 'rxjs'; import { takeUntil } from 'rxjs/operators';
import { takeUntil, filter, map, subscribeOn } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { MatTableDataSource, MatSort } from '@angular/material'; import { MatTableDataSource, MatSort } from '@angular/material';
import { Channel, Peer, GetInfo } from '../../../shared/models/lndModels'; import { Channel, Peer, GetInfo } from '../../../shared/models/lndModels';

@ -40,11 +40,6 @@ export class ChannelRestoreComponent implements OnInit {
.pipe(takeUntil(this.unSubs[0])) .pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore) => { .subscribe((rtlStore) => {
this.selNode = rtlStore.nodeSettings; this.selNode = rtlStore.nodeSettings;
// rtlStore.effectErrorsLnd.forEach(effectsErr => {
// if (effectsErr.action === 'RestoreChannelsList') {
// this.flgLoading[0] = 'error';
// }
// });
this.logger.info(rtlStore); this.logger.info(rtlStore);
}); });
this.lndEffects.setRestoreChannelList this.lndEffects.setRestoreChannelList

@ -135,7 +135,7 @@
<mat-divider></mat-divider> <mat-divider></mat-divider>
</mat-list> </mat-list>
</div> </div>
<mat-progress-bar *ngIf="flgLoading[6]===true" mode="indeterminate" class="mt-minus-5"></mat-progress-bar> <mat-progress-bar *ngIf="flgLoading[5]===true" mode="indeterminate" class="mt-minus-5"></mat-progress-bar>
<mat-divider></mat-divider> <mat-divider></mat-divider>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>

@ -1,12 +1,14 @@
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators'; import { takeUntil, filter } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { LoggerService } from '../../shared/services/logger.service'; import { LoggerService } from '../../shared/services/logger.service';
import { GetInfo, NetworkInfo, Fees, Peer } from '../../shared/models/lndModels'; import { GetInfo, NetworkInfo, Fees, Peer } from '../../shared/models/lndModels';
import { SelNodeChild } from '../../shared/models/RTLconfig'; import { SelNodeChild } from '../../shared/models/RTLconfig';
import * as RTLActions from '../../store/rtl.actions';
import * as fromRTLReducer from '../../store/rtl.reducers'; import * as fromRTLReducer from '../../store/rtl.reducers';
@Component({ @Component({
@ -20,10 +22,10 @@ export class HomeComponent implements OnInit, OnDestroy {
public information: GetInfo = {}; public information: GetInfo = {};
public remainder = 0; public remainder = 0;
public totalPeers = -1; public totalPeers = -1;
public totalBalance = ''; public totalBalance = 0;
public channelBalance = ''; public channelBalance = 0;
public BTCtotalBalance = ''; public BTCtotalBalance = 0;
public BTCchannelBalance = ''; public BTCchannelBalance = 0;
public networkInfo: NetworkInfo = {}; public networkInfo: NetworkInfo = {};
public flgLoading: Array<Boolean | 'error'> = [true, true, true, true, true, true, true, true]; // 0: Info, 1: Fee, 2: Wallet, 3: Channel, 4: Network public flgLoading: Array<Boolean | 'error'> = [true, true, true, true, true, true, true, true]; // 0: Info, 1: Fee, 2: Wallet, 3: Channel, 4: Network
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()]; private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
@ -35,13 +37,13 @@ export class HomeComponent implements OnInit, OnDestroy {
public peers: Peer[] = []; public peers: Peer[] = [];
barPadding = 0; barPadding = 0;
maxBalanceValue = 0; maxBalanceValue = 0;
totalBalances = [...[{'name': 'Local Balance', 'value': 0}, {'name': 'Remote Balance', 'value': 0}]]; totalBalances = [{'name': 'Local Balance', 'value': 0}, {'name': 'Remote Balance', 'value': 0}];
flgTotalCalculated = false; flgTotalCalculated = false;
view = []; view = [];
yAxisLabel = 'Balance'; yAxisLabel = 'Balance';
colorScheme = {domain: ['#FFFFFF']}; colorScheme = {domain: ['#FFFFFF']};
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>) { constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions) {
switch (true) { switch (true) {
case (window.innerWidth <= 730): case (window.innerWidth <= 730):
this.view = [250, 352]; this.view = [250, 352];
@ -63,9 +65,13 @@ export class HomeComponent implements OnInit, OnDestroy {
} }
ngOnInit() { ngOnInit() {
this.flgTotalCalculated = false; this.actions$.pipe(takeUntil(this.unsub[0]),
filter(action => action.type === RTLActions.SET_SELECTED_NODE))
.subscribe((data) => {
this.flgTotalCalculated = false;
});
this.store.select('lnd') this.store.select('lnd')
.pipe(takeUntil(this.unsub[0])) .pipe(takeUntil(this.unsub[1]))
.subscribe((rtlStore) => { .subscribe((rtlStore) => {
rtlStore.effectErrorsLnd.forEach(effectsErr => { rtlStore.effectErrorsLnd.forEach(effectsErr => {
if (effectsErr.action === 'FetchInfo') { if (effectsErr.action === 'FetchInfo') {
@ -102,13 +108,13 @@ export class HomeComponent implements OnInit, OnDestroy {
this.totalBalance = rtlStore.blockchainBalance.total_balance; this.totalBalance = rtlStore.blockchainBalance.total_balance;
this.BTCtotalBalance = rtlStore.blockchainBalance.btc_total_balance; this.BTCtotalBalance = rtlStore.blockchainBalance.btc_total_balance;
if (this.flgLoading[2] !== 'error') { if (this.flgLoading[2] !== 'error') {
this.flgLoading[2] = ('' !== this.totalBalance) ? false : true; this.flgLoading[2] = (this.totalBalance >= 0) ? false : true;
} }
this.channelBalance = rtlStore.channelBalance.balance; this.channelBalance = rtlStore.channelBalance.balance;
this.BTCchannelBalance = rtlStore.channelBalance.btc_balance; this.BTCchannelBalance = rtlStore.channelBalance.btc_balance;
if (this.flgLoading[3] !== 'error') { if (this.flgLoading[3] !== 'error') {
this.flgLoading[3] = ('' !== this.channelBalance) ? false : true; this.flgLoading[3] = (this.channelBalance >= 0) ? false : true;
} }
this.networkInfo = rtlStore.networkInfo; this.networkInfo = rtlStore.networkInfo;
@ -116,9 +122,9 @@ export class HomeComponent implements OnInit, OnDestroy {
this.flgLoading[4] = (undefined !== this.networkInfo.num_nodes) ? false : true; this.flgLoading[4] = (undefined !== this.networkInfo.num_nodes) ? false : true;
} }
this.totalBalances = [...[{'name': 'Local Balance', 'value': +rtlStore.totalLocalBalance}, {'name': 'Remote Balance', 'value': +rtlStore.totalRemoteBalance}]];
this.maxBalanceValue = (rtlStore.totalLocalBalance > rtlStore.totalRemoteBalance) ? rtlStore.totalLocalBalance : rtlStore.totalRemoteBalance;
if (rtlStore.totalLocalBalance >= 0 && rtlStore.totalRemoteBalance >= 0) { if (rtlStore.totalLocalBalance >= 0 && rtlStore.totalRemoteBalance >= 0) {
this.totalBalances = [{'name': 'Local Balance', 'value': rtlStore.totalLocalBalance}, {'name': 'Remote Balance', 'value': rtlStore.totalRemoteBalance}];
this.maxBalanceValue = (rtlStore.totalLocalBalance > rtlStore.totalRemoteBalance) ? rtlStore.totalLocalBalance : rtlStore.totalRemoteBalance;
this.flgTotalCalculated = true; this.flgTotalCalculated = true;
if (this.flgLoading[5] !== 'error') { if (this.flgLoading[5] !== 'error') {
this.flgLoading[5] = false; this.flgLoading[5] = false;

@ -80,7 +80,7 @@ export class InvoicesComponent implements OnInit, OnDestroy {
this.firstOffset = +rtlStore.invoices.first_index_offset; this.firstOffset = +rtlStore.invoices.first_index_offset;
this.lastOffset = +rtlStore.invoices.last_index_offset; this.lastOffset = +rtlStore.invoices.last_index_offset;
this.logger.info(rtlStore); this.logger.info(rtlStore);
this.loadInvoicesTable(rtlStore.invoices.invoices); this.loadInvoicesTable(rtlStore.invoices.invoices ? rtlStore.invoices.invoices : []);
if (this.flgLoading[0] !== 'error') { if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== rtlStore.invoices) ? false : true; this.flgLoading[0] = (undefined !== rtlStore.invoices) ? false : true;
} }

@ -1,48 +1,10 @@
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Component } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil, filter } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import * as RTLActions from '../store/rtl.actions';
import * as fromRTLReducer from '../store/rtl.reducers';
@Component({ @Component({
selector: 'rtl-lnd-root', selector: 'rtl-lnd-root',
templateUrl: './lnd-root.component.html', templateUrl: './lnd-root.component.html',
styleUrls: ['./lnd-root.component.scss'] styleUrls: ['./lnd-root.component.scss']
}) })
export class LNDRootComponent implements OnInit, OnDestroy { export class LNDRootComponent {
unsubs: Array<Subject<void>> = [new Subject(), new Subject()]; constructor() {}
constructor(private store: Store<fromRTLReducer.RTLState>, private actions$: Actions, private router: Router, private activatedRoute: ActivatedRoute) {}
ngOnInit() {
this.store.dispatch(new RTLActions.FetchInfo());
this.actions$.pipe(takeUntil(this.unsubs[0]), filter((action) => action.type === RTLActions.SET_INFO))
.subscribe((infoData: RTLActions.SetInfo) => {
if(infoData.type === RTLActions.SET_INFO && undefined !== infoData.payload.identity_pubkey) {
this.initializeRemainingData();
}
});
}
initializeRemainingData() {
this.store.dispatch(new RTLActions.FetchFees());
this.store.dispatch(new RTLActions.FetchPeers());
this.store.dispatch(new RTLActions.FetchBalance('channels'));
this.store.dispatch(new RTLActions.FetchNetwork());
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'all'}));
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'pending'}));
this.store.dispatch(new RTLActions.FetchInvoices({num_max_invoices: 25, reversed: true}));
this.store.dispatch(new RTLActions.FetchPayments());
}
ngOnDestroy() {
this.unsubs.forEach(unsub => {
unsub.next();
unsub.complete();
});
}
} }

@ -19,13 +19,13 @@ import { RoutingPeersComponent } from './routing-peers/routing-peers.component';
import { ChannelBackupComponent } from './channels/channel-backup/channel-backup.component'; import { ChannelBackupComponent } from './channels/channel-backup/channel-backup.component';
import { ChannelRestoreComponent } from './channels/channel-restore/channel-restore.component'; import { ChannelRestoreComponent } from './channels/channel-restore/channel-restore.component';
import { LNDUnlockedGuard } from '../shared/services/auth.guard'; import { AuthGuard, LNDUnlockedGuard } from '../shared/services/auth.guard';
import { NotFoundComponent } from '../shared/components/not-found/not-found.component'; import { NotFoundComponent } from '../shared/components/not-found/not-found.component';
export const LndRoutes: Routes = [ export const LndRoutes: Routes = [
{ path: '', component: LNDRootComponent, { path: '', component: LNDRootComponent,
children: [ children: [
{ path: 'unlocklnd', component: UnlockLNDComponent }, { path: 'unlocklnd', component: UnlockLNDComponent, canActivate: [AuthGuard] },
{ path: 'home', component: HomeComponent, canActivate: [LNDUnlockedGuard] }, { path: 'home', component: HomeComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'peers', component: PeersComponent, canActivate: [LNDUnlockedGuard] }, { path: 'peers', component: PeersComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'chnlclosed', component: ChannelClosedComponent, canActivate: [LNDUnlockedGuard] }, { path: 'chnlclosed', component: ChannelClosedComponent, canActivate: [LNDUnlockedGuard] },

@ -4,12 +4,14 @@ import { Router } from '@angular/router';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { Actions, Effect, ofType } from '@ngrx/effects'; import { Actions, Effect, ofType } from '@ngrx/effects';
import { of, Subject } from 'rxjs'; import { of, Subject } from 'rxjs';
import { map, mergeMap, catchError, take, withLatestFrom } from 'rxjs/operators'; import { map, mergeMap, catchError, withLatestFrom } from 'rxjs/operators';
import { Location } from '@angular/common';
import { MatDialog } from '@angular/material'; import { MatDialog } from '@angular/material';
import { environment, API_URL } from '../../../environments/environment'; import { environment, API_URL } from '../../../environments/environment';
import { LoggerService } from '../../shared/services/logger.service'; import { LoggerService } from '../../shared/services/logger.service';
import { SessionService } from '../../shared/services/session.service';
import { GetInfo, GetInfoChain, Fees, Balance, NetworkInfo, Payment, GraphNode, Transaction, SwitchReq, ListInvoices } from '../../shared/models/lndModels'; import { GetInfo, GetInfoChain, Fees, Balance, NetworkInfo, Payment, GraphNode, Transaction, SwitchReq, ListInvoices } from '../../shared/models/lndModels';
import * as RTLActions from '../../store/rtl.actions'; import * as RTLActions from '../../store/rtl.actions';
@ -26,22 +28,23 @@ export class LNDEffects implements OnDestroy {
private httpClient: HttpClient, private httpClient: HttpClient,
private store: Store<fromRTLReducer.RTLState>, private store: Store<fromRTLReducer.RTLState>,
private logger: LoggerService, private logger: LoggerService,
private sessionService: SessionService,
public dialog: MatDialog, public dialog: MatDialog,
private router: Router) { } private router: Router,
private location: Location) { }
@Effect() @Effect()
infoFetch = this.actions$.pipe( infoFetch = this.actions$.pipe(
ofType(RTLActions.FETCH_INFO), ofType(RTLActions.FETCH_INFO),
withLatestFrom(this.store.select('root')), withLatestFrom(this.store.select('root')),
mergeMap(([action, store]) => { mergeMap(([action, store]: [RTLActions.FetchInfo, fromRTLReducer.RootState]) => {
this.store.dispatch(new RTLActions.ClearEffectErrorLnd('FetchInfo')); this.store.dispatch(new RTLActions.ClearEffectErrorLnd('FetchInfo'));
return this.httpClient.get<GetInfo>(this.CHILD_API_URL + environment.GETINFO_API) return this.httpClient.get<GetInfo>(this.CHILD_API_URL + environment.GETINFO_API)
.pipe( .pipe(
map((info) => { map((info) => {
this.logger.info(info); this.logger.info(info);
if (undefined === info.identity_pubkey) { if (undefined === info.identity_pubkey) {
sessionStorage.removeItem('lndUnlocked'); this.sessionService.removeItem('lndUnlocked');
this.logger.info('Redirecting to Unlock'); this.logger.info('Redirecting to Unlock');
this.router.navigate(['/lnd/unlocklnd']); this.router.navigate(['/lnd/unlocklnd']);
return { return {
@ -49,33 +52,7 @@ export class LNDEffects implements OnDestroy {
payload: {} payload: {}
}; };
} else { } else {
sessionStorage.setItem('lndUnlocked', 'true'); this.initializeRemainingData(info, action.payload.loadPage);
if (undefined !== info.chains) {
if (typeof info.chains[0] === 'string') {
info.smaller_currency_unit = (info.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? 'Litoshis' : 'Sats';
info.currency_unit = (info.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? 'LTC' : 'BTC';
} else if (typeof info.chains[0] === 'object' && info.chains[0].hasOwnProperty('chain')) {
const getInfoChain = <GetInfoChain>info.chains[0];
info.smaller_currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? 'Litoshis' : 'Sats';
info.currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? 'LTC' : 'BTC';
}
info.version = (undefined === info.version) ? '' : info.version.split(' ')[0];
} else {
info.smaller_currency_unit = 'Sats';
info.currency_unit = 'BTC';
info.version = (undefined === info.version) ? '' : info.version.split(' ')[0];
}
const node_data = {
identity_pubkey: info.identity_pubkey,
alias: info.alias,
testnet: info.testnet,
chains: info.chains,
version: info.version,
currency_unit: info.currency_unit,
smaller_currency_unit: info.smaller_currency_unit,
numberOfPendingChannels: info.num_pending_channels
};
this.store.dispatch(new RTLActions.SetNodeData(node_data));
return { return {
type: RTLActions.SET_INFO, type: RTLActions.SET_INFO,
payload: (undefined !== info) ? info : {} payload: (undefined !== info) ? info : {}
@ -83,14 +60,31 @@ export class LNDEffects implements OnDestroy {
} }
}), }),
catchError((err) => { catchError((err) => {
this.logger.error(err); if ((typeof err.error.error === 'string' && err.error.error.includes('Not Found')) || err.status === 502) {
if (err.status === 401) { this.sessionService.removeItem('lndUnlocked');
this.logger.info('Redirecting to Signin');
return of({ type: RTLActions.SIGNOUT });
} else {
this.logger.info('Redirecting to Unlock'); this.logger.info('Redirecting to Unlock');
this.router.navigate(['/lnd/unlocklnd']); this.router.navigate(['/lnd/unlocklnd']);
return of(); this.handleErrorWithoutAlert('FetchInfo', err);
} else {
let code = err.status ? err.status : '';
let message = err.error.message ? err.error.message + ' ' : '';
if (err.error && err.error.error) {
if (err.error.error.code) {
code = err.error.error.code;
} else if (err.error.error.message && err.error.error.message.code) {
code = err.error.error.message.code;
}
if (typeof err.error.error === 'string') {
message = message + err.error.error;
} else if (err.error.error.error) {
message = message + err.error.error.error;
} else if (err.error.error.errno) {
message = message + err.error.error.errno;
}
}
this.router.navigate(['/error'], { state: { errorCode: code, errorMessage: message }});
this.handleErrorWithoutAlert('FetchInfo', err);
return of({type: RTLActions.VOID});
} }
}) })
); );
@ -112,12 +106,11 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchPeers', code: err.status, message: err.error.error })); this.handleErrorWithoutAlert('FetchPeers', err);
this.logger.error(err); return of({type: RTLActions.VOID});
return of();
}) })
); );
} }
)); ));
@Effect() @Effect()
@ -136,22 +129,11 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner()); this.handleErrorWithAlert('ERROR', 'Add Peer Failed', this.CHILD_API_URL + environment.PEERS_API, err);
this.logger.error(err); return of({type: RTLActions.VOID});
return of(
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Add Peer Failed',
message: JSON.stringify({ code: err.status, Message: err.error.error })
}
}
}
);
}) })
); );
} }
)); ));
@Effect() @Effect()
@ -170,22 +152,11 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner()); this.handleErrorWithAlert('ERROR', 'Unable to Detach Peer. Try again later.', this.CHILD_API_URL + environment.PEERS_API + '/' + action.payload.pubkey, err);
this.logger.error(err); return of({type: RTLActions.VOID});
return of(
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Unable to Detach Peer. Try again later.',
message: JSON.stringify({ code: err.status, Message: err.error.error })
}
}
}
);
}) })
); );
} }
)); ));
@Effect() @Effect()
@ -216,19 +187,8 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner()); this.handleErrorWithAlert('ERROR', 'Add Invoice Failed', this.CHILD_API_URL + environment.INVOICES_API, err);
this.logger.error(err); return of({type: RTLActions.VOID});
return of(
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Add Invoice Failed',
message: JSON.stringify({ code: err.status, Message: err.error.error })
}
}
}
);
}) })
); );
} }
@ -255,23 +215,12 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner()); this.handleErrorWithAlert('ERROR', 'Open Channel Failed', this.CHILD_API_URL + environment.CHANNELS_API, err);
this.logger.error(err); return of({type: RTLActions.VOID});
return of(
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Open Channel Failed',
message: JSON.stringify({ code: err.status, Message: err.error.error })
}
}
}
);
}) })
); );
} }
)); ));
@Effect() @Effect()
updateChannel = this.actions$.pipe( updateChannel = this.actions$.pipe(
@ -290,23 +239,12 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner()); this.handleErrorWithAlert('ERROR', 'Update Channel Failed', this.CHILD_API_URL + environment.CHANNELS_API + '/chanPolicy', err);
this.logger.error(err); return of({type: RTLActions.VOID});
return of(
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Update Channel Failed',
message: JSON.stringify({ code: err.status, Message: err.error.error })
}
}
}
);
}) })
); );
} }
)); ));
@Effect() @Effect()
closeChannel = this.actions$.pipe( closeChannel = this.actions$.pipe(
@ -332,23 +270,12 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner()); this.handleErrorWithAlert('ERROR', 'Unable to Close Channel. Try again later.', this.CHILD_API_URL + environment.CHANNELS_API + '/' + action.payload.channelPoint + '?force=' + action.payload.forcibly, err);
this.logger.error(err); return of({type: RTLActions.VOID});
return of(
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Unable to Close Channel. Try again later.',
message: JSON.stringify({ code: err.status, Message: err.error.error.message })
}
}
}
);
}) })
); );
} }
)); ));
@Effect() @Effect()
backupChannels = this.actions$.pipe( backupChannels = this.actions$.pipe(
@ -367,24 +294,13 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner());
this.logger.error(err);
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'BackupChannels', code: err.status, message: err.error.error })); this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'BackupChannels', code: err.status, message: err.error.error }));
return of( this.handleErrorWithAlert('ERROR', action.payload.showMessage + ' ' + 'Unable to Backup Channel. Try again later.', this.CHILD_API_URL + environment.CHANNELS_BACKUP_API + '/' + action.payload.channelPoint, err);
{ return of({type: RTLActions.VOID});
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: action.payload.showMessage + ' ' + 'Unable to Backup Channel. Try again later.',
message: JSON.stringify({ code: err.status, Message: err.error.message })
}
}
}
);
}) })
); );
} }
)); ));
@Effect() @Effect()
verifyChannels = this.actions$.pipe( verifyChannels = this.actions$.pipe(
@ -403,23 +319,12 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner());
this.logger.error(err);
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'VerifyChannels', code: err.status, message: err.error.error })); this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'VerifyChannels', code: err.status, message: err.error.error }));
return of( this.handleErrorWithAlert('ERROR', 'Unable to Verify Channel. Try again later.', this.CHILD_API_URL + environment.CHANNELS_BACKUP_API + '/verify/' + action.payload.channelPoint, err);
{ return of({type: RTLActions.VOID});
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Unable to Verify Channel. Try again later.',
message: JSON.stringify({ code: err.status, Message: err.error.message })
}
}
}
);
}) })
); );
} }
)); ));
@Effect() @Effect()
@ -440,20 +345,9 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner());
this.logger.error(err);
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'RestoreChannels', code: err.status, message: err.error.error })); this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'RestoreChannels', code: err.status, message: err.error.error }));
return of( this.handleErrorWithAlert('ERROR', 'Unable to Restore Channel. Try again later.', this.CHILD_API_URL + environment.CHANNELS_BACKUP_API + '/restore/' + action.payload.channelPoint, err);
{ return of({type: RTLActions.VOID});
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Unable to Restore Channel. Try again later.',
message: JSON.stringify({ code: err.status, Message: err.error.error })
}
}
}
);
}) })
); );
} }
@ -474,11 +368,10 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.logger.error(err); this.handleErrorWithoutAlert('FetchFees', err);
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchFees', code: err.status, message: err.error.error })); return of({type: RTLActions.VOID});
return of(); })
} );
));
@Effect() @Effect()
balanceFetch = this.actions$.pipe( balanceFetch = this.actions$.pipe(
@ -499,13 +392,12 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.logger.error(err); this.handleErrorWithoutAlert('FetchBalance/' + action.payload, err);
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchBalance/' + action.payload, code: err.status, message: err.error.error })); return of({type: RTLActions.VOID});
return of();
} }
)); ));
} }
)); ));
@Effect() @Effect()
networkInfoFetch = this.actions$.pipe( networkInfoFetch = this.actions$.pipe(
@ -522,11 +414,10 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.logger.error(err); this.handleErrorWithoutAlert('FetchNetwork', err);
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchNetwork', code: err.status, message: err.error.error })); return of({type: RTLActions.VOID});
return of();
} }
)); ));
@Effect() @Effect()
channelsFetch = this.actions$.pipe( channelsFetch = this.actions$.pipe(
@ -571,14 +462,13 @@ export class LNDEffects implements OnDestroy {
}; };
} }
}, },
catchError((err: any) => { catchError((err: any) => {
this.logger.error(err); this.handleErrorWithoutAlert('FetchChannels/' + action.payload.routeParam, err);
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchChannels/' + action.payload.routeParam, code: err.status, message: err.error.error })); return of({type: RTLActions.VOID});
return of(); })
}) ));
));
} }
)); ));
@Effect() @Effect()
invoicesFetch = this.actions$.pipe( invoicesFetch = this.actions$.pipe(
@ -599,13 +489,12 @@ export class LNDEffects implements OnDestroy {
payload: res payload: res
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.logger.error(err); this.handleErrorWithoutAlert('FetchInvoices', err);
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchInvoices', code: err.status, message: err.error.error })); return of({type: RTLActions.VOID});
return of(); }
} ));
)); }));
}));
@Effect() @Effect()
transactionsFetch = this.actions$.pipe( transactionsFetch = this.actions$.pipe(
@ -622,11 +511,10 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.logger.error(err); this.handleErrorWithoutAlert('FetchTransactions', err);
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchTransactions', code: err.status, message: err.error.error })); return of({type: RTLActions.VOID});
return of();
} }
)); ));
@Effect() @Effect()
paymentsFetch = this.actions$.pipe( paymentsFetch = this.actions$.pipe(
@ -643,11 +531,10 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.logger.error(err); this.handleErrorWithoutAlert('FetchPayments', err);
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchPayments', code: err.status, message: err.error.error })); return of({type: RTLActions.VOID});
return of();
} }
)); ));
@Effect() @Effect()
decodePayment = this.actions$.pipe( decodePayment = this.actions$.pipe(
@ -664,19 +551,8 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner()); this.handleErrorWithAlert('ERROR', 'Decode Payment Failed', this.CHILD_API_URL + environment.PAYREQUEST_API + '/' + action.payload, err);
this.logger.error(err); return of({type: RTLActions.VOID});
return of(
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Decode Payment Failed',
message: JSON.stringify({ Code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.PAYREQUEST_API + '/' + action.payload })
}
}
}
);
}) })
); );
}) })
@ -709,7 +585,7 @@ export class LNDEffects implements OnDestroy {
this.store.dispatch(new RTLActions.CloseSpinner()); this.store.dispatch(new RTLActions.CloseSpinner());
if (sendRes.payment_error) { if (sendRes.payment_error) {
this.logger.error('Error: ' + sendRes.payment_error); this.logger.error('Error: ' + sendRes.payment_error);
return of({ return {
type: RTLActions.OPEN_ALERT, type: RTLActions.OPEN_ALERT,
payload: { payload: {
width: '70%', data: { width: '70%', data: {
@ -719,7 +595,7 @@ export class LNDEffects implements OnDestroy {
) )
} }
} }
}); };
} else { } else {
const confirmationMsg = { 'Destination': action.payload[1].destination, 'Timestamp': action.payload[1].timestamp_str, 'Expiry': action.payload[1].expiry }; const confirmationMsg = { 'Destination': action.payload[1].destination, 'Timestamp': action.payload[1].timestamp_str, 'Expiry': action.payload[1].expiry };
confirmationMsg['Amount (' + ((undefined === store.nodeData.smaller_currency_unit) ? confirmationMsg['Amount (' + ((undefined === store.nodeData.smaller_currency_unit) ?
@ -742,19 +618,8 @@ export class LNDEffects implements OnDestroy {
} }
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner()); this.handleErrorWithAlert('ERROR', 'Send Payment Failed', this.CHILD_API_URL + environment.CHANNELS_API + '/transactions', err);
this.logger.error(err); return of({type: RTLActions.VOID});
return of(
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Send Payment Failed',
message: JSON.stringify({ code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.CHANNELS_API + '/transactions/' + action.payload[0] })
}
}
}
);
}) })
); );
}) })
@ -773,23 +638,12 @@ export class LNDEffects implements OnDestroy {
payload: (undefined !== graphNode) ? graphNode : {} payload: (undefined !== graphNode) ? graphNode : {}
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner()); this.handleErrorWithAlert('ERROR', 'Get Node Address Failed', this.CHILD_API_URL + environment.NETWORK_API + '/node/' + action.payload, err);
this.logger.error(err); return of({type: RTLActions.VOID});
return of( }));
{ }
type: RTLActions.OPEN_ALERT, ));
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Get Node Address Failed',
message: JSON.stringify({ Code: err.status, Message: err.error.error })
}
}
}
);
}));
}
));
@Effect({ dispatch: false }) @Effect({ dispatch: false })
setGraphNode = this.actions$.pipe( setGraphNode = this.actions$.pipe(
@ -813,21 +667,10 @@ export class LNDEffects implements OnDestroy {
payload: (undefined !== newAddress && undefined !== newAddress.address) ? newAddress.address : {} payload: (undefined !== newAddress && undefined !== newAddress.address) ? newAddress.address : {}
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner()); this.handleErrorWithAlert('ERROR', 'Generate New Address Failed', this.CHILD_API_URL + environment.NEW_ADDRESS_API + '?type=' + action.payload.addressId, err);
this.logger.error(err); return of({type: RTLActions.VOID});
return of( }));
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Generate New Address Failed',
message: JSON.stringify({ Code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.NEW_ADDRESS_API + '?type=' + action.payload.addressId })
}
}
}
);
}));
}) })
); );
@ -859,22 +702,11 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'SetChannelTransaction', code: err.status, message: err.error.error })); this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'SetChannelTransaction', code: err.status, message: err.error.error }));
this.logger.error(err); this.handleErrorWithAlert('ERROR', 'Sending Fund Failed', this.CHILD_API_URL + environment.TRANSACTIONS_API, err);
return of( return of({type: RTLActions.VOID});
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Sending Fund Failed',
message: JSON.stringify({ Code: err.status, Message: err.error.error })
}
}
}
);
})); }));
}) })
); );
@Effect() @Effect()
@ -896,18 +728,8 @@ export class LNDEffects implements OnDestroy {
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'GetForwardingHistory', code: err.status, message: err.error.error })); this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'GetForwardingHistory', code: err.status, message: err.error.error }));
this.logger.error(err); this.handleErrorWithAlert('ERROR', 'Get Forwarding History Failed', this.CHILD_API_URL + environment.SWITCH_API, err);
return of( return of({type: RTLActions.VOID});
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Get Forwarding History Failed',
message: JSON.stringify({ code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.SWITCH_API })
}
}
}
);
}) })
); );
}) })
@ -928,18 +750,8 @@ export class LNDEffects implements OnDestroy {
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.SetQueryRoutes({})); this.store.dispatch(new RTLActions.SetQueryRoutes({}));
this.logger.error(err); this.handleErrorWithAlert('ERROR', 'Get Query Routes Failed', this.CHILD_API_URL + environment.NETWORK_API, err);
return of( return of({type: RTLActions.VOID});
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Get Query Routes Failed',
message: JSON.stringify({ code: err.status, Message: err.error.error.error, URL: this.CHILD_API_URL + environment.NETWORK_API })
}
}
}
);
}) })
); );
} }
@ -969,14 +781,34 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err) => { catchError((err) => {
this.handleErrorWithAlert('ERROR', err.error.message + ' ' + err.error.error.code, this.CHILD_API_URL + environment.WALLET_API + '/genseed/' + action.payload, err);
return of({type: RTLActions.VOID});
})
);
}
));
@Effect()
updateSelNodeOptions = this.actions$.pipe(
ofType(RTLActions.UPDATE_SELECTED_NODE_OPTIONS),
mergeMap((action: RTLActions.UpdateSelectedNodeOptions) => {
return this.httpClient.get(this.CHILD_API_URL + environment.WALLET_API + '/updateSelNodeOptions')
.pipe(
map((postRes: any) => {
this.logger.info('Update Sel Node Successfull');
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner()); this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: { type: 'ERROR', titleMessage: err.error.message + ' ' + err.error.error.code } })); return {
this.logger.error(err.error.error); type: RTLActions.VOID
return of(); };
}),
catchError((err) => {
this.handleErrorWithAlert('ERROR', 'Update macaroon for newly initialized node failed! Please check the macaroon path and restart the server!', 'Update Macaroon', err);
return of({type: RTLActions.VOID});
}) })
); );
} }
)); ));
@Effect({ dispatch: false }) @Effect({ dispatch: false })
genSeedResponse = this.actions$.pipe( genSeedResponse = this.actions$.pipe(
@ -1014,14 +846,12 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err) => { catchError((err) => {
this.store.dispatch(new RTLActions.CloseSpinner()); this.handleErrorWithAlert('ERROR', err.error.error, this.CHILD_API_URL + environment.WALLET_API + '/initwallet', err);
this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: { type: 'ERROR', titleMessage: err.error.error } })); return of({type: RTLActions.VOID});
this.logger.error(err.error.error);
return of();
}) })
); );
} }
)); ));
@Effect({ dispatch: false }) @Effect({ dispatch: false })
unlockWallet = this.actions$.pipe( unlockWallet = this.actions$.pipe(
@ -1034,20 +864,17 @@ export class LNDEffects implements OnDestroy {
this.store.dispatch(new RTLActions.CloseSpinner()); this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenSpinner('Initializing Node...')); this.store.dispatch(new RTLActions.OpenSpinner('Initializing Node...'));
this.logger.info('Successfully Unlocked!'); this.logger.info('Successfully Unlocked!');
sessionStorage.setItem('lndUnlocked', 'true'); this.sessionService.setItem('lndUnlocked', 'true');
setTimeout(() => { setTimeout(() => {
this.store.dispatch(new RTLActions.CloseSpinner()); this.store.dispatch(new RTLActions.CloseSpinner());
this.logger.info('Successfully Initialized!'); this.logger.info('Successfully Initialized!');
this.store.dispatch(new RTLActions.InitAppData()); this.store.dispatch(new RTLActions.FetchInfo({loadPage: 'HOME'}));
this.router.navigate(['/lnd/']);
}, 1000 * 90); }, 1000 * 90);
return of({}); return { type: RTLActions.VOID };
}), }),
catchError((err) => { catchError((err) => {
this.store.dispatch(new RTLActions.CloseSpinner()); this.handleErrorWithAlert('ERROR', err.error.error, this.CHILD_API_URL + environment.WALLET_API + '/unlockwallet', err);
this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: { type: 'ERROR', titleMessage: err.error.error } })); return of({ type: RTLActions.VOID });
this.logger.error(err.error.error);
return of();
}) })
); );
} }
@ -1069,20 +896,9 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'Lookup', code: err.status, message: err.error.message })); this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'Lookup', code: err.status, message: err.error.message }));
this.logger.error(err); this.handleErrorWithAlert('ERROR', 'Peer Lookup Failed', this.CHILD_API_URL + environment.NETWORK_API + '/node/' + action.payload, err);
return of( return of({type: RTLActions.VOID});
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Peer Lookup Failed',
message: JSON.stringify({ Code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.NETWORK_API + '/node/' + action.payload })
}
}
}
);
}) })
); );
}) })
@ -1104,20 +920,9 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'Lookup', code: err.status, message: err.error.message })); this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'Lookup', code: err.status, message: err.error.message }));
this.logger.error(err); this.handleErrorWithAlert('ERROR', 'Channel Lookup Failed', this.CHILD_API_URL + environment.NETWORK_API + '/edge/' + action.payload, err);
return of( return of({type: RTLActions.VOID});
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Channel Lookup Failed',
message: JSON.stringify({ Code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.NETWORK_API + '/edge/' + action.payload })
}
}
}
);
}) })
); );
}) })
@ -1139,20 +944,9 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'Lookup', code: err.status, message: err.error.message })); this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'Lookup', code: err.status, message: err.error.message }));
this.logger.error(err); this.handleErrorWithAlert('ERROR', 'Invoice Lookup Failed', this.CHILD_API_URL + environment.INVOICES_API + '/' + action.payload, err);
return of( return of({type: RTLActions.VOID});
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Invoice Lookup Failed',
message: JSON.stringify({ Code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.INVOICES_API + '/' + action.payload })
}
}
}
);
}) })
); );
}) })
@ -1184,20 +978,9 @@ export class LNDEffects implements OnDestroy {
}; };
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'RestoreChannelsList', code: err.status, message: err.error.message })); this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'RestoreChannelsList', code: err.status, message: err.error.message }));
this.logger.error(err); this.handleErrorWithAlert('ERROR', 'Restore Channels List Failed', this.CHILD_API_URL + environment.CHANNELS_BACKUP_API, err);
return of( return of({type: RTLActions.VOID});
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Restore Channels List Failed',
message: JSON.stringify({ Code: err.status, Message: err.error, URL: this.CHILD_API_URL + environment.CHANNELS_BACKUP_API })
}
}
}
);
}) })
); );
}) })
@ -1212,6 +995,79 @@ export class LNDEffects implements OnDestroy {
}) })
); );
initializeRemainingData(info: any, landingPage: string) {
this.sessionService.setItem('lndUnlocked', 'true');
if (undefined !== info.chains) {
if (typeof info.chains[0] === 'string') {
info.smaller_currency_unit = (info.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? 'Litoshis' : 'Sats';
info.currency_unit = (info.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? 'LTC' : 'BTC';
} else if (typeof info.chains[0] === 'object' && info.chains[0].hasOwnProperty('chain')) {
const getInfoChain = <GetInfoChain>info.chains[0];
info.smaller_currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? 'Litoshis' : 'Sats';
info.currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? 'LTC' : 'BTC';
}
info.version = (undefined === info.version) ? '' : info.version.split(' ')[0];
} else {
info.smaller_currency_unit = 'Sats';
info.currency_unit = 'BTC';
info.version = (undefined === info.version) ? '' : info.version.split(' ')[0];
}
const node_data = {
identity_pubkey: info.identity_pubkey,
alias: info.alias,
testnet: info.testnet,
chains: info.chains,
version: info.version,
currency_unit: info.currency_unit,
smaller_currency_unit: info.smaller_currency_unit,
numberOfPendingChannels: info.num_pending_channels
};
this.store.dispatch(new RTLActions.SetNodeData(node_data));
this.store.dispatch(new RTLActions.FetchFees());
this.store.dispatch(new RTLActions.FetchPeers());
this.store.dispatch(new RTLActions.FetchBalance('channels'));
this.store.dispatch(new RTLActions.FetchNetwork());
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'all'}));
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'pending'}));
this.store.dispatch(new RTLActions.FetchInvoices({num_max_invoices: 25, reversed: true}));
this.store.dispatch(new RTLActions.FetchPayments());
let newRoute = this.location.path();
if (newRoute.includes('/unlock') || newRoute.includes('/login') || newRoute.includes('/error') || newRoute === '' || landingPage === 'HOME' || newRoute.includes('?access-key=')) {
newRoute = '/lnd/home';
} else {
if(newRoute.includes('/cl/')) {
newRoute = newRoute.replace('/cl/', '/lnd/');
}
}
this.router.navigate([newRoute]);
}
handleErrorWithoutAlert(actionName: string, err: { status: number, error: any }) {
this.logger.error('ERROR IN: ' + actionName + '\n' + JSON.stringify(err));
if (err.status === 401) {
this.logger.info('Redirecting to Signin');
this.store.dispatch(new RTLActions.Signout());
} else {
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: actionName, code: err.status.toString(), message: err.error.error }));
}
}
handleErrorWithAlert(alertType: string, alertTitle: string, errURL: string, err: { status: number, error: any }) {
this.logger.error(err);
if (err.status === 401) {
this.logger.info('Redirecting to Signin');
this.store.dispatch(new RTLActions.Signout());
} else {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenAlert({
width: '70%', data: {
type: alertType, titleMessage: alertTitle,
message: JSON.stringify({ code: err.status, Message: err.error.error, URL: errURL })
}
}));
}
}
ngOnDestroy() { ngOnDestroy() {
this.unSubs.forEach(completeSub => { this.unSubs.forEach(completeSub => {
completeSub.next(); completeSub.next();

@ -37,8 +37,8 @@ export const initLNDState: LNDState = {
peers: [], peers: [],
fees: {}, fees: {},
networkInfo: {}, networkInfo: {},
channelBalance: {balance: '', btc_balance: ''}, channelBalance: { balance: -1, btc_balance: -1 },
blockchainBalance: { total_balance: '', btc_total_balance: ''}, blockchainBalance: { total_balance: -1, btc_total_balance: -1 },
allChannels: [], allChannels: [],
closedChannels: [], closedChannels: [],
pendingChannels: {}, pendingChannels: {},

@ -58,13 +58,13 @@ export class SendReceiveTransComponent implements OnInit, OnDestroy {
this.blockchainBalance = rtlStore.blockchainBalance; this.blockchainBalance = rtlStore.blockchainBalance;
if (undefined === this.blockchainBalance.total_balance) { if (undefined === this.blockchainBalance.total_balance) {
this.blockchainBalance.total_balance = '0'; this.blockchainBalance.total_balance = 0;
} }
if (undefined === this.blockchainBalance.confirmed_balance) { if (undefined === this.blockchainBalance.confirmed_balance) {
this.blockchainBalance.confirmed_balance = '0'; this.blockchainBalance.confirmed_balance = 0;
} }
if (undefined === this.blockchainBalance.unconfirmed_balance) { if (undefined === this.blockchainBalance.unconfirmed_balance) {
this.blockchainBalance.unconfirmed_balance = '0'; this.blockchainBalance.unconfirmed_balance = 0;
} }
if (this.flgLoadingWallet !== 'error') { if (this.flgLoadingWallet !== 'error') {
this.flgLoadingWallet = false; this.flgLoadingWallet = false;

@ -95,18 +95,18 @@ export class UnlockLNDComponent implements OnInit, OnDestroy {
.pipe(takeUntil(this.unsubs[3])) .pipe(takeUntil(this.unsubs[3]))
.subscribe(genSeedRes => { .subscribe(genSeedRes => {
this.genSeedResponse = genSeedRes; this.genSeedResponse = genSeedRes;
// if (this.passphraseFormGroup.controls.enterPassphrase.value) { if (this.passphraseFormGroup.controls.enterPassphrase.value) {
// this.store.dispatch(new RTLActions.InitWallet({ this.store.dispatch(new RTLActions.InitWallet({
// pwd: window.btoa(this.passwordFormGroup.controls.initWalletPassword.value), pwd: window.btoa(this.passwordFormGroup.controls.initWalletPassword.value),
// cipher: this.genSeedResponse, cipher: this.genSeedResponse,
// passphrase: window.btoa(this.passphraseFormGroup.controls.passphrase.value) passphrase: window.btoa(this.passphraseFormGroup.controls.passphrase.value)
// })); }));
// } else { } else {
this.store.dispatch(new RTLActions.InitWallet({ this.store.dispatch(new RTLActions.InitWallet({
pwd: window.btoa(this.passwordFormGroup.controls.initWalletPassword.value), pwd: window.btoa(this.passwordFormGroup.controls.initWalletPassword.value),
cipher: this.genSeedResponse cipher: this.genSeedResponse
})); }));
// } }
}); });
} }
@ -143,8 +143,8 @@ export class UnlockLNDComponent implements OnInit, OnDestroy {
onGoToHome() { onGoToHome() {
setTimeout(() => { setTimeout(() => {
this.store.dispatch(new RTLActions.InitAppData()); this.store.dispatch(new RTLActions.UpdateSelectedNodeOptions());
this.router.navigate(['/lnd/']); this.store.dispatch(new RTLActions.FetchInfo({loadPage:'HOME'}));
}, 1000 * 1); }, 1000 * 1);
} }

@ -1,14 +1,14 @@
<div fxLayout="column" fxLayoutAlign="center center"> <div fxLayout="column" fxLayoutAlign="center center">
<mat-card class="mat-elevation-z24 not-found-box"> <mat-card class="mat-elevation-z24 not-found-box">
<div fxLayout="column" fxLayoutAlign="center center" class="bg-primary pt-2"> <div fxLayout="column" fxLayoutAlign="center center" class="bg-primary py-2">
<button mat-fab color="accent" class="mat-elevation-z12"> <button mat-fab color="accent" class="mat-elevation-z12">
<mat-icon>error</mat-icon> <mat-icon>error</mat-icon>
</button> </button>
<h1 class="error">401</h1> <h1 class="error">{{error.errorCode}}</h1>
</div> </div>
<mat-card-content fxLayout="row" fxLayoutAlign="center center"> <mat-card-content fxLayout="row" fxLayoutAlign="center center">
<mat-card fxLayout="column" fxLayoutAlign="center center" class="mat-elevation-z12 w-100"> <mat-card fxLayout="column" fxLayoutAlign="center center" class="mat-elevation-z12 w-100">
<div class="box-text">Single Sign On Failed!</div> <div class="box-text">{{error.errorMessage}}</div>
</mat-card> </mat-card>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>

@ -0,0 +1,25 @@
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
import { Subject } from 'rxjs';
import { filter, map, takeUntil } from 'rxjs/operators';
@Component({
selector: 'rtl-error',
templateUrl: './error.component.html'
})
export class ErrorComponent implements OnInit {
error = {errorCode: '', errorMessage: ''};
private unsubs: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(private router: Router, private activatedRoute: ActivatedRoute) { }
ngOnInit() {
this.activatedRoute.paramMap
.pipe(takeUntil(this.unsubs[0]))
.subscribe(data => {
this.error = window.history.state;
});
}
}

@ -1,12 +1,9 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil, filter } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { faEject } from '@fortawesome/free-solid-svg-icons'; import { SessionService } from '../../../services/session.service';
import { LoggerService } from '../../../services/logger.service';
import { MENU_DATA } from '../../../models/navMenu'; import { MENU_DATA } from '../../../models/navMenu';
import { RTLEffects } from '../../../../store/rtl.effects'; import { RTLEffects } from '../../../../store/rtl.effects';
@ -18,14 +15,14 @@ import * as fromRTLReducer from '../../../../store/rtl.reducers';
templateUrl: './horizontal-navigation.component.html', templateUrl: './horizontal-navigation.component.html',
styleUrls: ['./horizontal-navigation.component.scss'] styleUrls: ['./horizontal-navigation.component.scss']
}) })
export class HorizontalNavigationComponent implements OnInit { export class HorizontalNavigationComponent implements OnInit, OnDestroy {
public menuNodes = []; public menuNodes = [];
public logoutNode = []; public logoutNode = [];
public showLogout = false; public showLogout = false;
public numPendingChannels = 0; public numPendingChannels = 0;
private unSubs = [new Subject(), new Subject(), new Subject()]; private unSubs = [new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions, private rtlEffects: RTLEffects) { constructor(private sessionService: SessionService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects) {
} }
ngOnInit() { ngOnInit() {
@ -39,21 +36,15 @@ export class HorizontalNavigationComponent implements OnInit {
this.menuNodes = MENU_DATA.LNDChildren; this.menuNodes = MENU_DATA.LNDChildren;
} }
}); });
this.actions$ this.sessionService.watchSession()
.pipe( .pipe(takeUntil(this.unSubs[1]))
takeUntil(this.unSubs[2]), .subscribe(session => {
filter((action) => action.type === RTLActions.SIGNOUT || action.type === RTLActions.SIGNIN) if(session.token) {
).subscribe((action) => { this.menuNodes.push({id: 200, parentId: 0, name: 'Logout', icon: 'eject'});
if (action.type === RTLActions.SIGNIN) { } else {
this.menuNodes.push({id: 200, parentId: 0, name: 'Logout', iconType: 'SVG', icon: 'logout'});
}
if (action.type === RTLActions.SIGNOUT) {
this.menuNodes.pop(); this.menuNodes.pop();
} }
}); });
if (sessionStorage.getItem('token')) {
this.menuNodes.push({id: 200, parentId: 0, name: 'Logout', iconType: 'SVG', icon: 'logout'});
}
} }
onClick(node) { onClick(node) {
@ -62,7 +53,7 @@ export class HorizontalNavigationComponent implements OnInit {
width: '70%', data: { type: 'CONFIRM', titleMessage: 'Logout from this device?', noBtnText: 'Cancel', yesBtnText: 'Logout' width: '70%', data: { type: 'CONFIRM', titleMessage: 'Logout from this device?', noBtnText: 'Cancel', yesBtnText: 'Logout'
}})); }}));
this.rtlEffects.closeConfirm this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unSubs[1])) .pipe(takeUntil(this.unSubs[3]))
.subscribe(confirmRes => { .subscribe(confirmRes => {
if (confirmRes) { if (confirmRes) {
this.showLogout = false; this.showLogout = false;
@ -71,4 +62,11 @@ export class HorizontalNavigationComponent implements OnInit {
}); });
} }
} }
ngOnDestroy() {
this.unSubs.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
}
} }

@ -12,6 +12,7 @@ import { faEject } from '@fortawesome/free-solid-svg-icons';
import { LightningNode, Settings, GetInfoRoot } from '../../../models/RTLconfig'; import { LightningNode, Settings, GetInfoRoot } from '../../../models/RTLconfig';
import { LoggerService } from '../../../services/logger.service'; import { LoggerService } from '../../../services/logger.service';
import { SessionService } from '../../../services/session.service';
import { GetInfoChain } from '../../../models/lndModels'; import { GetInfoChain } from '../../../models/lndModels';
import { MenuChildNode, MENU_DATA } from '../../../models/navMenu'; import { MenuChildNode, MENU_DATA } from '../../../models/navMenu';
@ -38,13 +39,13 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
public numPendingChannels = 0; public numPendingChannels = 0;
public smallScreen = false; public smallScreen = false;
public childRootRoute = ''; public childRootRoute = '';
private unSubs = [new Subject(), new Subject(), new Subject()]; private unSubs = [new Subject(), new Subject(), new Subject(), new Subject()];
treeControlLogout = new NestedTreeControl<MenuChildNode>(node => node.children); treeControlLogout = new NestedTreeControl<MenuChildNode>(node => node.children);
treeControlNested = new NestedTreeControl<MenuChildNode>(node => node.children); treeControlNested = new NestedTreeControl<MenuChildNode>(node => node.children);
navMenus = new MatTreeNestedDataSource<MenuChildNode>(); navMenus = new MatTreeNestedDataSource<MenuChildNode>();
navMenusLogout = new MatTreeNestedDataSource<MenuChildNode>(); navMenusLogout = new MatTreeNestedDataSource<MenuChildNode>();
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions, private rtlEffects: RTLEffects, private router: Router, private activatedRoute: ActivatedRoute) { constructor(private logger: LoggerService, private sessionService: SessionService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions, private rtlEffects: RTLEffects, private router: Router, private activatedRoute: ActivatedRoute) {
this.version = environment.VERSION; this.version = environment.VERSION;
if (MENU_DATA.LNDChildren[MENU_DATA.LNDChildren.length - 1].id === 200) { if (MENU_DATA.LNDChildren[MENU_DATA.LNDChildren.length - 1].id === 200) {
MENU_DATA.LNDChildren.pop(); MENU_DATA.LNDChildren.pop();
@ -77,10 +78,6 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
} }
this.flgLoading = (undefined !== this.information.identity_pubkey) ? false : true; this.flgLoading = (undefined !== this.information.identity_pubkey) ? false : true;
this.showLogout = (sessionStorage.getItem('token')) ? true : false;
if (!sessionStorage.getItem('token')) {
this.flgLoading = false;
}
if (window.innerWidth <= 414) { if (window.innerWidth <= 414) {
this.smallScreen = true; this.smallScreen = true;
} }
@ -91,6 +88,12 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
} }
this.logger.info(rtlStore); this.logger.info(rtlStore);
}); });
this.sessionService.watchSession()
.pipe(takeUntil(this.unSubs[1]))
.subscribe(session => {
this.showLogout = session.token ? true : false;
this.flgLoading = session.token ? true : false;
});
this.actions$.pipe(takeUntil(this.unSubs[2]), this.actions$.pipe(takeUntil(this.unSubs[2]),
filter((action) => action.type === RTLActions.SIGNOUT)) filter((action) => action.type === RTLActions.SIGNOUT))
.subscribe((action: RTLActions.Signout) => { .subscribe((action: RTLActions.Signout) => {
@ -106,7 +109,7 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
width: '70%', data: { type: 'CONFIRM', titleMessage: 'Logout from this device?', noBtnText: 'Cancel', yesBtnText: 'Logout' width: '70%', data: { type: 'CONFIRM', titleMessage: 'Logout from this device?', noBtnText: 'Cancel', yesBtnText: 'Logout'
}})); }}));
this.rtlEffects.closeConfirm this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unSubs[1])) .pipe(takeUntil(this.unSubs[3]))
.subscribe(confirmRes => { .subscribe(confirmRes => {
if (confirmRes) { if (confirmRes) {
this.showLogout = false; this.showLogout = false;

@ -6,6 +6,7 @@ import { Actions } from '@ngrx/effects';
import { GetInfoRoot, LightningNode } from '../../../models/RTLconfig'; import { GetInfoRoot, LightningNode } from '../../../models/RTLconfig';
import { LoggerService } from '../../../services/logger.service'; import { LoggerService } from '../../../services/logger.service';
import { SessionService } from '../../../services/session.service';
import { GetInfoChain } from '../../../models/lndModels'; import { GetInfoChain } from '../../../models/lndModels';
import { environment } from '../../../../../environments/environment'; import { environment } from '../../../../../environments/environment';
@ -30,9 +31,9 @@ export class TopMenuComponent implements OnInit, OnDestroy {
public informationChain: GetInfoChain = {}; public informationChain: GetInfoChain = {};
public flgLoading = true; public flgLoading = true;
public showLogout = false; public showLogout = false;
private unSubs = [new Subject(), new Subject(), new Subject()]; private unSubs = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects, private actions$: Actions) { constructor(private logger: LoggerService, private sessionService: SessionService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects, private actions$: Actions) {
this.version = environment.VERSION; this.version = environment.VERSION;
} }
@ -58,12 +59,13 @@ export class TopMenuComponent implements OnInit, OnDestroy {
this.informationChain.chain = ''; this.informationChain.chain = '';
this.informationChain.network = ''; this.informationChain.network = '';
} }
this.showLogout = (sessionStorage.getItem('token')) ? true : false;
this.logger.info(rtlStore); this.logger.info(rtlStore);
if (!sessionStorage.getItem('token')) { });
this.flgLoading = false; this.sessionService.watchSession()
} .pipe(takeUntil(this.unSubs[1]))
.subscribe(session => {
this.showLogout = session.token ? true : false;
this.flgLoading = session.token ? true : false;
}); });
this.actions$ this.actions$
.pipe( .pipe(
@ -79,7 +81,7 @@ export class TopMenuComponent implements OnInit, OnDestroy {
width: '70%', data: { type: 'CONFIRM', titleMessage: 'Logout from this device?', noBtnText: 'Cancel', yesBtnText: 'Logout' width: '70%', data: { type: 'CONFIRM', titleMessage: 'Logout from this device?', noBtnText: 'Cancel', yesBtnText: 'Logout'
}})); }}));
this.rtlEffects.closeConfirm this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unSubs[1])) .pipe(takeUntil(this.unSubs[3]))
.subscribe(confirmRes => { .subscribe(confirmRes => {
if (confirmRes) { if (confirmRes) {
this.showLogout = false; this.showLogout = false;

@ -1,14 +0,0 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'rtl-sso-failed',
templateUrl: './sso-failed.component.html'
})
export class SsoFailedComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}

@ -43,8 +43,8 @@ export interface BalanceCL {
} }
export interface LocalRemoteBalanceCL { export interface LocalRemoteBalanceCL {
localBalance?: number; localBalance: number;
remoteBalance?: number; remoteBalance: number;
btc_localBalance?: number; btc_localBalance?: number;
btc_remoteBalance?: number; btc_remoteBalance?: number;
} }

@ -5,16 +5,16 @@ export interface AddressType {
} }
export interface Balance { export interface Balance {
btc_balance?: string; btc_balance?: number;
balance?: string; balance?: number;
btc_pending_open_balance?: string; btc_pending_open_balance?: number;
pending_open_balance?: string; pending_open_balance?: number;
btc_total_balance?: string; btc_total_balance?: number;
total_balance?: string; total_balance?: number;
btc_confirmed_balance?: string; btc_confirmed_balance?: number;
confirmed_balance?: string; confirmed_balance?: number;
btc_unconfirmed_balance?: string; btc_unconfirmed_balance?: number;
unconfirmed_balance?: string; unconfirmed_balance?: number;
} }
export interface ChannelFeeReport { export interface ChannelFeeReport {

@ -2,12 +2,14 @@ import { CanActivate } from '@angular/router';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { SessionService } from './session.service';
@Injectable() @Injectable()
export class AuthGuard implements CanActivate { export class AuthGuard implements CanActivate {
constructor() {} constructor(private sessionService: SessionService) {}
canActivate(): boolean | Observable<boolean> | Promise<boolean> { canActivate(): boolean | Observable<boolean> | Promise<boolean> {
if (!sessionStorage.getItem('token')) { if (!this.sessionService.getItem('token')) {
return false; return false;
} else { } else {
return true; return true;
@ -17,10 +19,10 @@ export class AuthGuard implements CanActivate {
@Injectable() @Injectable()
export class LNDUnlockedGuard implements CanActivate { export class LNDUnlockedGuard implements CanActivate {
constructor() {} constructor(private sessionService: SessionService) {}
canActivate(): boolean | Observable<boolean> | Promise<boolean> { canActivate(): boolean | Observable<boolean> | Promise<boolean> {
if (!sessionStorage.getItem('lndUnlocked')) { if (!this.sessionService.getItem('lndUnlocked')) {
return false; return false;
} else { } else {
return true; return true;
@ -30,11 +32,11 @@ export class LNDUnlockedGuard implements CanActivate {
@Injectable() @Injectable()
export class CLUnlockedGuard implements CanActivate { export class CLUnlockedGuard implements CanActivate {
constructor() {} constructor(private sessionService: SessionService) {}
canActivate(): boolean | Observable<boolean> | Promise<boolean> { canActivate(): boolean | Observable<boolean> | Promise<boolean> {
return true; return true;
if (!sessionStorage.getItem('clUnlocked')) { if (!this.sessionService.getItem('clUnlocked')) {
return false; return false;
} else { } else {
return true; return true;

@ -2,15 +2,17 @@ import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { SessionService } from './session.service';
@Injectable() @Injectable()
export class AuthInterceptor implements HttpInterceptor { export class AuthInterceptor implements HttpInterceptor {
constructor() {} constructor(private sessionService: SessionService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (sessionStorage.getItem('token')) { if (this.sessionService.getItem('token')) {
const cloned = req.clone({ const cloned = req.clone({
headers: req.headers.set('Authorization', 'Bearer ' + sessionStorage.getItem('token')) headers: req.headers.set('Authorization', 'Bearer ' + this.sessionService.getItem('token'))
}); });
return next.handle(cloned); return next.handle(cloned);
} else { } else {

@ -0,0 +1,25 @@
import { Injectable } from '@angular/core';
import { Subject, Observable } from 'rxjs';
@Injectable()
export class SessionService {
private sessionSub= new Subject<any>();
watchSession(): Observable<any> {
return this.sessionSub.asObservable();
}
getItem(key) {
return sessionStorage.getItem(key);
}
setItem(key: string, data: any) {
sessionStorage.setItem(key, data);
this.sessionSub.next(sessionStorage);
}
removeItem(key) {
sessionStorage.removeItem(key);
this.sessionSub.next(sessionStorage);
}
}

@ -27,7 +27,7 @@ import { TopMenuComponent } from './components/navigation/top-menu/top-menu.comp
import { HorizontalNavigationComponent } from './components/navigation/horizontal-navigation/horizontal-navigation.component'; import { HorizontalNavigationComponent } from './components/navigation/horizontal-navigation/horizontal-navigation.component';
import { SettingsNavComponent } from './components/settings-nav/settings-nav.component'; import { SettingsNavComponent } from './components/settings-nav/settings-nav.component';
import { ServerConfigComponent } from './components/server-config/server-config.component'; import { ServerConfigComponent } from './components/server-config/server-config.component';
import { SsoFailedComponent } from './components/sso-failed/sso-failed.component'; import { ErrorComponent } from './components/error/error.component';
import { ClipboardDirective } from './directive/clipboard.directive'; import { ClipboardDirective } from './directive/clipboard.directive';
import { RemoveLeadingZerosPipe } from './pipes/remove-leading-zero.pipe'; import { RemoveLeadingZerosPipe } from './pipes/remove-leading-zero.pipe';
@ -135,7 +135,7 @@ import { RemoveLeadingZerosPipe } from './pipes/remove-leading-zero.pipe';
HelpComponent, HelpComponent,
ServerConfigComponent, ServerConfigComponent,
ClipboardDirective, ClipboardDirective,
SsoFailedComponent, ErrorComponent,
RemoveLeadingZerosPipe RemoveLeadingZerosPipe
], ],
entryComponents: [ entryComponents: [

@ -10,6 +10,7 @@ import {
} from '../shared/models/lndModels'; } from '../shared/models/lndModels';
export const VOID = 'VOID'; export const VOID = 'VOID';
export const UPDATE_SELECTED_NODE_OPTIONS = 'UPDATE_SELECTED_NODE_OPTIONS';
export const RESET_ROOT_STORE = 'RESET_ROOT_STORE'; export const RESET_ROOT_STORE = 'RESET_ROOT_STORE';
export const CLEAR_EFFECT_ERROR_ROOT = 'CLEAR_EFFECT_ERROR_ROOT'; export const CLEAR_EFFECT_ERROR_ROOT = 'CLEAR_EFFECT_ERROR_ROOT';
export const EFFECT_ERROR_ROOT = 'EFFECT_ERROR_ROOT'; export const EFFECT_ERROR_ROOT = 'EFFECT_ERROR_ROOT';
@ -90,7 +91,6 @@ export const IS_AUTHORIZED = 'IS_AUTHORIZED';
export const IS_AUTHORIZED_RES = 'IS_AUTHORIZED_RES'; export const IS_AUTHORIZED_RES = 'IS_AUTHORIZED_RES';
export const SIGNIN = 'SIGNIN'; export const SIGNIN = 'SIGNIN';
export const SIGNOUT = 'SIGNOUT'; export const SIGNOUT = 'SIGNOUT';
export const INIT_APP_DATA = 'INIT_APP_DATA';
export const PEER_LOOKUP = 'PEER_LOOKUP'; export const PEER_LOOKUP = 'PEER_LOOKUP';
export const CHANNEL_LOOKUP = 'CHANNEL_LOOKUP'; export const CHANNEL_LOOKUP = 'CHANNEL_LOOKUP';
export const INVOICE_LOOKUP = 'INVOICE_LOOKUP'; export const INVOICE_LOOKUP = 'INVOICE_LOOKUP';
@ -211,6 +211,10 @@ export class CloseConfirmation implements Action {
constructor(public payload: boolean) {} constructor(public payload: boolean) {}
} }
export class UpdateSelectedNodeOptions implements Action {
readonly type = UPDATE_SELECTED_NODE_OPTIONS;
}
export class ResetRootStore implements Action { export class ResetRootStore implements Action {
readonly type = RESET_ROOT_STORE; readonly type = RESET_ROOT_STORE;
constructor(public payload: LightningNode) {} constructor(public payload: LightningNode) {}
@ -262,6 +266,7 @@ export class SetChildNodeSettings implements Action {
export class FetchInfo implements Action { export class FetchInfo implements Action {
readonly type = FETCH_INFO; readonly type = FETCH_INFO;
constructor(public payload: {loadPage: string}) {}
} }
export class SetInfo implements Action { export class SetInfo implements Action {
@ -583,10 +588,6 @@ export class Signout implements Action {
constructor() {} constructor() {}
} }
export class InitAppData implements Action {
readonly type = INIT_APP_DATA;
}
export class SetChildNodeSettingsCL implements Action { export class SetChildNodeSettingsCL implements Action {
readonly type = SET_CHILD_NODE_SETTINGS_CL; readonly type = SET_CHILD_NODE_SETTINGS_CL;
constructor(public payload: SelNodeChild) {} constructor(public payload: SelNodeChild) {}
@ -594,6 +595,7 @@ export class SetChildNodeSettingsCL implements Action {
export class FetchInfoCL implements Action { export class FetchInfoCL implements Action {
readonly type = FETCH_INFO_CL; readonly type = FETCH_INFO_CL;
constructor(public payload: {loadPage: string}) {}
} }
export class SetInfoCL implements Action { export class SetInfoCL implements Action {
@ -635,7 +637,7 @@ export class FetchLocalRemoteBalanceCL implements Action {
export class SetLocalRemoteBalanceCL implements Action { export class SetLocalRemoteBalanceCL implements Action {
readonly type = SET_LOCAL_REMOTE_BALANCE_CL; readonly type = SET_LOCAL_REMOTE_BALANCE_CL;
constructor(public payload: {}) {} constructor(public payload: {localBalance: number, remoteBalance: number}) {}
} }
export class GetNewAddressCL implements Action { export class GetNewAddressCL implements Action {
@ -809,7 +811,7 @@ export type RTLActions =
ClearEffectErrorRoot | EffectErrorRoot | ClearEffectErrorLnd | EffectErrorLnd | ClearEffectErrorCl | EffectErrorCl | ClearEffectErrorRoot | EffectErrorRoot | ClearEffectErrorLnd | EffectErrorLnd | ClearEffectErrorCl | EffectErrorCl |
VoidAction | OpenSpinner | CloseSpinner | FetchRTLConfig | SetRTLConfig | SaveSettings | VoidAction | OpenSpinner | CloseSpinner | FetchRTLConfig | SetRTLConfig | SaveSettings |
OpenAlert | CloseAlert | OpenConfirmation | CloseConfirmation | OpenAlert | CloseAlert | OpenConfirmation | CloseConfirmation |
ResetRootStore | ResetLNDStore | ResetCLStore | UpdateSelectedNodeOptions | ResetRootStore | ResetLNDStore | ResetCLStore |
SetSelelectedNode | SetNodeData | SetNodePendingChannelsData | SetChildNodeSettings | FetchInfo | SetInfo | SetSelelectedNode | SetNodeData | SetNodePendingChannelsData | SetChildNodeSettings | FetchInfo | SetInfo |
FetchPeers | SetPeers | AddPeer | DetachPeer | SaveNewPeer | RemovePeer | FetchPeers | SetPeers | AddPeer | DetachPeer | SaveNewPeer | RemovePeer |
AddInvoice | SaveNewInvoice | GetForwardingHistory | SetForwardingHistory | AddInvoice | SaveNewInvoice | GetForwardingHistory | SetForwardingHistory |
@ -828,7 +830,7 @@ export type RTLActions =
GetNewAddress | SetNewAddress | SetChannelTransaction | GetNewAddress | SetNewAddress | SetChannelTransaction |
GenSeed | GenSeedResponse | InitWallet | InitWalletResponse | UnlockWallet | GenSeed | GenSeedResponse | InitWallet | InitWalletResponse | UnlockWallet |
FetchConfig | ShowConfig | PeerLookup | ChannelLookup | InvoiceLookup | SetLookup | FetchConfig | ShowConfig | PeerLookup | ChannelLookup | InvoiceLookup | SetLookup |
IsAuthorized | IsAuthorizedRes | Signin | Signout | InitAppData | IsAuthorized | IsAuthorizedRes | Signin | Signout |
SetChildNodeSettingsCL | FetchInfoCL | SetInfoCL | FetchFeesCL | SetFeesCL | FetchFeeRatesCL | SetFeeRatesCL | SetChildNodeSettingsCL | FetchInfoCL | SetInfoCL | FetchFeesCL | SetFeesCL | FetchFeeRatesCL | SetFeeRatesCL |
FetchBalanceCL | SetBalanceCL | FetchLocalRemoteBalanceCL | SetLocalRemoteBalanceCL | FetchBalanceCL | SetBalanceCL | FetchLocalRemoteBalanceCL | SetLocalRemoteBalanceCL |
GetNewAddressCL | SetNewAddressCL | GetNewAddressCL | SetNewAddressCL |

@ -11,6 +11,7 @@ import { MatDialog } from '@angular/material';
import { environment, API_URL } from '../../environments/environment'; import { environment, API_URL } from '../../environments/environment';
import { LoggerService } from '../shared/services/logger.service'; import { LoggerService } from '../shared/services/logger.service';
import { SessionService } from '../shared/services/session.service';
import { Settings, RTLConfiguration, AuthenticateWith } from '../shared/models/RTLconfig'; import { Settings, RTLConfiguration, AuthenticateWith } from '../shared/models/RTLconfig';
import { SpinnerDialogComponent } from '../shared/components/spinner-dialog/spinner-dialog.component'; import { SpinnerDialogComponent } from '../shared/components/spinner-dialog/spinner-dialog.component';
@ -31,6 +32,7 @@ export class RTLEffects implements OnDestroy {
private httpClient: HttpClient, private httpClient: HttpClient,
private store: Store<fromRTLReducer.RTLState>, private store: Store<fromRTLReducer.RTLState>,
private logger: LoggerService, private logger: LoggerService,
private sessionService: SessionService,
public dialog: MatDialog, public dialog: MatDialog,
private router: Router, private router: Router,
private location: Location) { } private location: Location) { }
@ -162,7 +164,7 @@ export class RTLEffects implements OnDestroy {
this.store.dispatch(new RTLActions.ClearEffectErrorRoot('IsAuthorized')); this.store.dispatch(new RTLActions.ClearEffectErrorRoot('IsAuthorized'));
return this.httpClient.post(environment.AUTHENTICATE_API, { return this.httpClient.post(environment.AUTHENTICATE_API, {
authenticateWith: (undefined === action.payload || action.payload == null || action.payload === '') ? AuthenticateWith.TOKEN : AuthenticateWith.PASSWORD, authenticateWith: (undefined === action.payload || action.payload == null || action.payload === '') ? AuthenticateWith.TOKEN : AuthenticateWith.PASSWORD,
authenticationValue: (undefined === action.payload || action.payload == null || action.payload === '') ? (sessionStorage.getItem('token') ? sessionStorage.getItem('token') : '') : action.payload authenticationValue: (undefined === action.payload || action.payload == null || action.payload === '') ? (this.sessionService.getItem('token') ? this.sessionService.getItem('token') : '') : action.payload
}) })
.pipe( .pipe(
map((postRes: any) => { map((postRes: any) => {
@ -202,18 +204,14 @@ export class RTLEffects implements OnDestroy {
this.store.dispatch(new RTLActions.ClearEffectErrorRoot('Signin')); this.store.dispatch(new RTLActions.ClearEffectErrorRoot('Signin'));
return this.httpClient.post(environment.AUTHENTICATE_API, { return this.httpClient.post(environment.AUTHENTICATE_API, {
authenticateWith: (undefined === action.payload || action.payload == null || action.payload === '') ? AuthenticateWith.TOKEN : AuthenticateWith.PASSWORD, authenticateWith: (undefined === action.payload || action.payload == null || action.payload === '') ? AuthenticateWith.TOKEN : AuthenticateWith.PASSWORD,
authenticationValue: (undefined === action.payload || action.payload == null || action.payload === '') ? (sessionStorage.getItem('token') ? sessionStorage.getItem('token') : '') : action.payload authenticationValue: (undefined === action.payload || action.payload == null || action.payload === '') ? (this.sessionService.getItem('token') ? this.sessionService.getItem('token') : '') : action.payload
}) })
.pipe( .pipe(
map((postRes: any) => { map((postRes: any) => {
this.logger.info(postRes); this.logger.info(postRes);
this.logger.info('Successfully Authorized!'); this.logger.info('Successfully Authorized!');
this.SetToken(postRes.token); this.SetToken(postRes.token);
if(rootStore.selNode.lnImplementation.toUpperCase() === 'CLT') { this.store.dispatch(new RTLActions.SetSelelectedNode({lnNode: rootStore.selNode, isInitialSetup: true}))
this.router.navigate(['/cl/home']);
} else {
this.router.navigate(['/lnd/home']);
}
}), }),
catchError((err) => { catchError((err) => {
this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'ERROR', message: JSON.stringify(err.error)}})); this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'ERROR', message: JSON.stringify(err.error)}}));
@ -221,7 +219,7 @@ export class RTLEffects implements OnDestroy {
this.logger.error(err.error); this.logger.error(err.error);
this.logger.info('Redirecting to Signin Error Page'); this.logger.info('Redirecting to Signin Error Page');
if (+rootStore.appConfig.sso.rtlSSO) { if (+rootStore.appConfig.sso.rtlSSO) {
this.router.navigate(['/ssoerror']); this.router.navigate(['/error'], { state: { errorCode: '401', errorMessage: 'Single Sign On Failed!' }});
} else { } else {
this.router.navigate([rootStore.appConfig.sso.logoutRedirectLink]); this.router.navigate([rootStore.appConfig.sso.logoutRedirectLink]);
} }
@ -240,9 +238,9 @@ export class RTLEffects implements OnDestroy {
} else { } else {
this.router.navigate([store.appConfig.sso.logoutRedirectLink]); this.router.navigate([store.appConfig.sso.logoutRedirectLink]);
} }
sessionStorage.removeItem('clUnlocked'); this.sessionService.removeItem('clUnlocked');
sessionStorage.removeItem('lndUnlocked'); this.sessionService.removeItem('lndUnlocked');
sessionStorage.removeItem('token'); this.sessionService.removeItem('token');
this.logger.warn('LOGGED OUT'); this.logger.warn('LOGGED OUT');
return of(); return of();
})); }));
@ -257,45 +255,8 @@ export class RTLEffects implements OnDestroy {
map((postRes: any) => { map((postRes: any) => {
this.logger.info(postRes); this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner()); this.store.dispatch(new RTLActions.CloseSpinner());
let selNode = { channelBackupPath: action.payload.lnNode.settings.channelBackupPath, satsToBTC: action.payload.lnNode.settings.satsToBTC }; this.initializeNode(action.payload.lnNode, action.payload.isInitialSetup);
this.store.dispatch(new RTLActions.ResetRootStore(action.payload.lnNode)); return { type: RTLActions.VOID };
this.store.dispatch(new RTLActions.ResetLNDStore(selNode));
this.store.dispatch(new RTLActions.ResetCLStore(selNode));
if (sessionStorage.getItem('token')) {
let newRoute = this.location.path();
if(action.payload.lnNode.lnImplementation.toUpperCase() === 'CLT') {
if(newRoute.includes('/lnd/')) {
newRoute = newRoute.replace('/lnd/', '/cl/');
} else if(newRoute === '/') {
newRoute = '/cl/home';
}
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
this.router.onSameUrlNavigation = 'reload';
this.router.navigate([newRoute]);
this.CHILD_API_URL = API_URL + '/cl';
return { type: RTLActions.VOID };
} else {
if(newRoute.includes('/cl/')) {
newRoute = newRoute.replace('/cl/', '/lnd/');
} else if(newRoute === '/') {
newRoute = '/lnd/home';
}
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
this.router.onSameUrlNavigation = 'reload';
this.router.navigate([newRoute]);
this.CHILD_API_URL = API_URL + '/lnd';
return { type: RTLActions.VOID };
}
} else {
if (!action.payload.isInitialSetup) {
return {
type: RTLActions.OPEN_ALERT,
payload: { width: '70%', data: {type: 'WARN', titleMessage: 'Authorization required to get the data from the node!' }}
};
} else {
return { type: RTLActions.VOID };
}
}
}), }),
catchError((err: any) => { catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner()); this.store.dispatch(new RTLActions.CloseSpinner());
@ -312,16 +273,32 @@ export class RTLEffects implements OnDestroy {
}) })
); );
} }
)); ));
initializeNode(node: any, isInitialSetup: boolean) {
const landingPage = isInitialSetup ? '' : 'HOME';
let selNode = { channelBackupPath: node.settings.channelBackupPath, satsToBTC: node.settings.satsToBTC };
this.store.dispatch(new RTLActions.ResetRootStore(node));
this.store.dispatch(new RTLActions.ResetLNDStore(selNode));
this.store.dispatch(new RTLActions.ResetCLStore(selNode));
if(this.sessionService.getItem('token')) {
if(node.lnImplementation.toUpperCase() === 'CLT') {
this.CHILD_API_URL = API_URL + '/cl';
this.store.dispatch(new RTLActions.FetchInfoCL({loadPage: landingPage}));
} else {
this.CHILD_API_URL = API_URL + '/lnd';
this.store.dispatch(new RTLActions.FetchInfo({loadPage: landingPage}));
}
}
}
SetToken(token: string) { SetToken(token: string) {
if (token) { if (token) {
sessionStorage.setItem('lndUnlocked', 'true'); this.sessionService.setItem('lndUnlocked', 'true');
sessionStorage.setItem('token', token); this.sessionService.setItem('token', token);
this.store.dispatch(new RTLActions.InitAppData());
} else { } else {
sessionStorage.removeItem('lndUnlocked'); this.sessionService.removeItem('lndUnlocked');
sessionStorage.removeItem('token'); this.sessionService.removeItem('token');
} }
} }

@ -1 +1 @@
export const VERSION = '0.5.4-beta'; export const VERSION = '0.5.5-beta';
Loading…
Cancel
Save