UNPKG

stonix-wallet

Version:

A minimalistic wallet GUI for c-lightning

194 lines (156 loc) 9.3 kB
"use strict"; 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); });