stonix-wallet
Version:
A minimalistic wallet GUI for c-lightning
194 lines (156 loc) • 9.3 kB
JavaScript
;
var _express = _interopRequireDefault(require("express"));
var _clightningClient = _interopRequireDefault(require("clightning-client"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
// Extend clightning-client with custom RPC commands
Object.assign(_clightningClient["default"].LightningClient.prototype, require('./cmd').commands);
var proute = function proute(fn) {
return function (req, res, next) {
return fn(req, res)["catch"](next);
};
};
_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
var app, ln, connFailed, lninfo, qrterm, qrKey, serviceReady;
return regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
serviceReady = function _serviceReady(name, url) {
url = url.replace(/\/$/, '');
console.log("\n".concat(name, " running on ").concat(url));
if (qrterm) {
if (!url.includes('://localhost:')) {
console.log("Scan QR to ".concat(qrKey ? 'pair with' : 'open', " ").concat(name, ":"));
qrterm.generate("".concat(url, "/").concat(qrKey), {
small: true
});
qrKey && console.log('[NOTE: This QR contains your secret access key, which provides full access to your wallet.]\n');
} else if (!process.env.ONION) {
// Display a warning if we don't have a publicly accessible URL and onion is off
console.error('Refusing to generate a QR for localhost; Please specify --host, --public-url or --onion to have a publicly accessible URL that can be reached from other devices.');
}
}
if (process.env.PAIRING_URL) {
console.log('Pairing URL:', "".concat(url, "/?access-key=").concat(app.settings.accessKey));
console.log('[NOTE: This URL contains your secret access key, which provides full access to your wallet.]\n');
}
process.send && process.send({
serverUrl: url
});
};
// IIFE
app = (0, _express["default"])(), ln = (0, _clightningClient["default"])(process.env.LN_PATH); // Test connection
if (process.env.NO_TEST_CONN) {
_context2.next = 10;
break;
}
connFailed = function connFailed(err) {
throw err;
};
ln.on('error', connFailed);
_context2.next = 7;
return ln.getinfo();
case 7:
lninfo = _context2.sent;
ln.removeListener('error', connFailed);
console.log("Connected to c-lightning ".concat(lninfo.version, " with id ").concat(lninfo.id, " on network ").concat(lninfo.network, " at ").concat(ln.rpcPath));
case 10:
// Settings
app.set('port', process.env.PORT || 9737);
app.set('host', process.env.HOST || 'localhost');
app.set('trust proxy', process.env.PROXIED || 'loopback');
app.set('tls', !process.env.NO_TLS && (app.settings.host !== 'localhost' || process.env.FORCE_TLS)); // Middlewares
app.use(require('morgan')('dev'));
app.use(require('body-parser').json());
app.use(require('./auth')(app, process.env.COOKIE_FILE, process.env.LOGIN));
app.use(require('compression')());
app.use(require('helmet')({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-eval'"],
fontSrc: ["'self'", 'data:'],
imgSrc: ["'self'", 'data:']
}
},
ieNoOpen: false
})); // CSRF protection. Require the X-Access header or access-key query string arg for POST requests.
app.post('*', function (req, res, next) {
return !req.csrfSafe ? res.sendStatus(403) : next();
}); // CORS
process.env.ALLOW_CORS && app.use(function (req, res, next) {
res.set('Access-Control-Allow-Origin', process.env.ALLOW_CORS);
res.set('Access-Control-Allow-Headers', 'Content-Type, Accept');
res.set('Access-Control-Allow-Methods', 'POST');
next();
}); // RPC API
app.post('/rpc', proute( /*#__PURE__*/function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(req, res) {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
req.setTimeout(5 * 60 * 1000);
_context.t0 = res;
_context.next = 4;
return ln[req.body.method] ? ln[req.body.method].apply(ln, _toConsumableArray(req.body.params)) : ln.call(req.body.method, req.body.params);
case 4:
_context.t1 = _context.sent;
_context.t0.send.call(_context.t0, _context.t1);
case 6:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return function (_x, _x2) {
return _ref2.apply(this, arguments);
};
}())); // Streaming API
app.get('/stream', require('./stream')(ln)); // Frontend
process.env.NO_WEBUI || require('./webui')(app); // Error handler
app.use(function (err, req, res, next) {
console.error(err.stack || err.toString());
res.status(err.status || 500).send(err.type && err || err.message || err);
}); // HTTPS server (the default for non-localhost hosts)
app.enabled('tls') ? require('./transport/tls')(app, process.env.TLS_NAME, process.env.TLS_PATH, process.env.LETSENCRYPT).then(function (url) {
return serviceReady('HTTPS server', process.env.PUBLIC_URL || url);
}) // HTTP server (for localhost or when --no-tls is specified)
: require('./transport/http')(app).then(function (url) {
return serviceReady('HTTP server', process.env.PUBLIC_URL || url);
}); // Tor Onion Hidden Service
process.env.ONION && require('./transport/onion')(app, process.env.ONION_PATH).then(function (url) {
return serviceReady('Tor Onion Hidden Service v3', url);
});
qrterm = process.env.PRINT_QR && require('qrcode-terminal'), qrKey = process.env.PAIRING_QR ? "?access-key=".concat(app.settings.accessKey) : '';
process.env.PRINT_KEY && console.log('Access key for remote API access:', app.settings.accessKey);
case 29:
case "end":
return _context2.stop();
}
}
}, _callee2);
}))();
['unhandledRejection', 'uncaughtException'].forEach(function (ev) {
return process.on(ev, function (err) {
process.send && process.send({
error: err.toString()
});
console.error("".concat(ev, ", stopping process"));
console.error(err.stack || err);
process.exit(1);
});
});
process.on('SIGTERM', function (err) {
console.error('Caught SIGTERM, shutting down');
process.exit(0);
});