diff options
| -rw-r--r-- | lib/createLnrpc.js | 2 | ||||
| -rw-r--r-- | models/users.js | 9 | ||||
| -rw-r--r-- | package.json | 3 | ||||
| -rw-r--r-- | payUser.js | 11 | ||||
| -rw-r--r-- | payments.js | 7 | ||||
| -rw-r--r-- | queryRoutes.js | 11 | ||||
| -rw-r--r-- | schema.sql | 74 | ||||
| -rw-r--r-- | sendLiquid.js | 7 | ||||
| -rw-r--r-- | sendPayment.js | 92 | ||||
| -rw-r--r-- | users.js | 98 | ||||
| -rw-r--r-- | yarn.lock | 71 |
11 files changed, 244 insertions, 141 deletions
diff --git a/lib/createLnrpc.js b/lib/createLnrpc.js index 661440bb..e32f6be3 100644 --- a/lib/createLnrpc.js +++ b/lib/createLnrpc.js @@ -23,7 +23,7 @@ module.exports = async ({ server, tls, macaroon, channelpeers }) => { let fn; if (streaming) { - if (key === "sendPayment") { + if (key === "sendPayment" || key === "sendToRoute") { fn = params => method.call(lnrpc, target.meta, params); } else { fn = params => method.call(lnrpc, params, target.meta); diff --git a/models/users.js b/models/users.js index 8edc94b0..467a0e3b 100644 --- a/models/users.js +++ b/models/users.js @@ -85,6 +85,15 @@ module.exports = sequelize => { comment: null, field: "symbol" }, + otpsecret: { + type: DataTypes.STRING(255), + allowNull: true, + defaultValue: "CAD", + primaryKey: false, + autoIncrement: false, + comment: null, + field: "otpsecret" + }, currency: { type: DataTypes.STRING(255), allowNull: true, diff --git a/package.json b/package.json index b63e65bf..d558f398 100644 --- a/package.json +++ b/package.json @@ -32,13 +32,14 @@ "grpc": "^1.23.3", "http-proxy-middleware": "^0.20.0", "jsonwebtoken": "^8.5.1", - "lnrpc": "^0.6.1", + "lnrpc": "^0.6.2", "lodash": "^4.17.13", "mailgun-js": "^0.22.0", "moment": "^2.24.0", "morgan": "^1.9.1", "mysql": "^2.17.1", "mysql2": "^1.6.5", + "otplib": "^12.0.1", "passport": "0.4.0", "passport-jwt": "^4.0.0", "passport-local": "1.0.0", @@ -1,4 +1,6 @@ -module.exports = (app, db, lnb) => async (req, res) => { +const bolt11 = require("bolt11"); + +module.exports = (app, db, lna, lnb) => async (req, res) => { let { payuser, amount } = req.body; let user = await db.User.findOne({ @@ -34,6 +36,11 @@ module.exports = (app, db, lnb) => async (req, res) => { }); req.url = "/sendPayment"; - req.body.payreq = invoice.payment_request; + let payreq = bolt11.decode(hash); + const { routes } = await lna.queryRoutes({ "pub_key": payreq.payeeNodeKey, "amt": payreq.satoshis }); + if (routes.length) req.body.route = routes[0]; + else return res.status(500).send("No route available"); + req.body.payreq = hash; + return app._router.handle(req, res); }; diff --git a/payments.js b/payments.js index 9866d244..ed8bfccf 100644 --- a/payments.js +++ b/payments.js @@ -10,11 +10,16 @@ module.exports = async (app, auth, addresses, bc, db, emit, seen, payments) => { require("./lightningPayments")(app, db, lna, lnb, emit, payments); app.post( + "/queryRoutes", + auth, + require("./queryRoutes")(app, db, emit, seen, lna, lnb) + ); + app.post( "/sendPayment", auth, require("./sendPayment")(app, db, emit, seen, lna, lnb) ); - app.post("/payUser", auth, require("./payUser")(app, db, lnb)); + app.post("/payUser", auth, require("./payUser")(app, db, lna, lnb)); app.post("/sendCoins", auth, require("./sendCoins")(app, bc, db, emit)); app.post("/sendLiquid", auth, require("./sendLiquid")(app, db, emit)); app.post("/addInvoice", auth, require("./addInvoice")(app, db, lnb)); diff --git a/queryRoutes.js b/queryRoutes.js new file mode 100644 index 00000000..068027e7 --- /dev/null +++ b/queryRoutes.js @@ -0,0 +1,11 @@ +const bolt11 = require("bolt11"); +const config = require("./config"); + +const l = console.log; + +module.exports = (app, db, emit, seen, lna, lnb) => async (req, res) => { + let hash = req.body.payreq; + let payreq = bolt11.decode(hash); + const routes = await lna.queryRoutes({ "pub_key": payreq.payeeNodeKey, "amt": payreq.satoshis }); + res.send(routes); +}; @@ -1,8 +1,8 @@ --- MySQL dump 10.17 Distrib 10.3.12-MariaDB, for debian-linux-gnu (x86_64) +-- MySQL dump 10.17 Distrib 10.3.22-MariaDB, for debian-linux-gnu (x86_64) -- -- Host: localhost Database: coinos -- ------------------------------------------------------ --- Server version 10.3.12-MariaDB-1:10.3.12+maria~bionic +-- Server version 10.3.22-MariaDB-1:10.3.22+maria~bionic /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; @@ -31,24 +31,6 @@ CREATE TABLE `SequelizeMeta` ( /*!40101 SET character_set_client = @saved_cs_client */; -- --- Table structure for table `orders` --- - -DROP TABLE IF EXISTS `orders`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `orders` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `amount` int(11) DEFAULT NULL, - `price` int(11) DEFAULT NULL, - `type` varchar(255) DEFAULT NULL, - `pair` varchar(255) DEFAULT NULL, - `createdAt` datetime DEFAULT current_timestamp(), - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- -- Table structure for table `payments` -- @@ -58,18 +40,20 @@ DROP TABLE IF EXISTS `payments`; CREATE TABLE `payments` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) DEFAULT NULL, - `hash` varchar(255) DEFAULT NULL, + `hash` text DEFAULT NULL, `createdAt` datetime NOT NULL, `updatedAt` datetime NOT NULL, `rate` double DEFAULT NULL, - `currency` varchar(255) DEFAULT NULL, - `address` int(11) DEFAULT NULL, + `currency` varchar(255) NOT NULL, + `address` varchar(255) DEFAULT NULL, `received` tinyint(1) DEFAULT NULL, `amount` double DEFAULT NULL, `tip` double DEFAULT NULL, - `confirmed` tinyint(1) DEFAULT NOT NULL, + `confirmed` tinyint(1) NOT NULL, + `fee` double DEFAULT NULL, + `asset` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1611 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=2782 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -87,7 +71,7 @@ CREATE TABLE `users` ( `address` varchar(255) DEFAULT NULL, `unit` varchar(255) DEFAULT NULL, `symbol` varchar(255) DEFAULT NULL, - `currency` varchar(255) NOT NULL DEFAULT 'CAD', + `currency` varchar(255) DEFAULT NULL, `commission` varchar(255) DEFAULT NULL, `title` varchar(255) DEFAULT NULL, `pubkey` varchar(255) DEFAULT NULL, @@ -106,42 +90,18 @@ CREATE TABLE `users` ( `pic` varchar(255) DEFAULT NULL, `emailToken` varchar(255) DEFAULT NULL, `phone` varchar(255) DEFAULT NULL, - `phoneVerified` varchar(255) DEFAULT NULL, + `phoneVerified` tinyint(1) DEFAULT NULL, `twofa` tinyint(1) DEFAULT NULL, `authyId` varchar(255) DEFAULT NULL, `pin` varchar(255) DEFAULT NULL, `emailVerified` tinyint(1) DEFAULT NULL, `phoneToken` varchar(255) DEFAULT NULL, + `confidential` varchar(255) DEFAULT NULL, + `liquid` varchar(255) DEFAULT NULL, + `currencies` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL, + `otp` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=305 DEFAULT CHARSET=latin1; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Table structure for table `users_balances` --- - -DROP TABLE IF EXISTS `users_balances`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `users_balances` ( - `user_id` int(11) DEFAULT NULL, - `symbol` varchar(255) DEFAULT NULL, - `balance` int(11) DEFAULT NULL, - `pending` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Table structure for table `users_channels` --- - -DROP TABLE IF EXISTS `users_channels`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `users_channels` ( - `user_id` int(11) DEFAULT NULL, - `channel_id` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +) ENGINE=InnoDB AUTO_INCREMENT=420 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; @@ -153,4 +113,4 @@ CREATE TABLE `users_channels` ( /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2019-02-09 15:40:59 +-- Dump completed on 2020-02-09 15:22:43 diff --git a/sendLiquid.js b/sendLiquid.js index 1a218afe..1008f014 100644 --- a/sendLiquid.js +++ b/sendLiquid.js @@ -30,6 +30,7 @@ module.exports = (app, db, emit) => async (req, res) => { fee = parseInt(fee * SATS); total = amount + fee; } catch (e) { + l("funding failed", e); return res.status(500).send(e.message); } @@ -52,13 +53,13 @@ module.exports = (app, db, emit) => async (req, res) => { await user.save({ transaction }); }); } catch (e) { - l(e); + l("balance check failed", e); return res.status(500).send("Not enough satoshis"); } try { if (config.liquid.walletpass) - await bc.walletPassphrase(config.bitcoin.walletpass, 300); + await bc.walletPassphrase(config.liquid.walletpass, 300); rawtx = (await bc.signRawTransactionWithWallet(hex)).hex; let txid = await bc.sendRawTransaction(rawtx); @@ -87,7 +88,7 @@ module.exports = (app, db, emit) => async (req, res) => { res.send(payment); }); } catch (e) { - l(e); + l("send failed", e); return res.status(500).send(e.message); } }; diff --git a/sendPayment.js b/sendPayment.js index ff5b9609..1bc8b99a 100644 --- a/sendPayment.js +++ b/sendPayment.js @@ -6,6 +6,7 @@ const l = console.log; module.exports = (app, db, emit, seen, lna, lnb) => async (req, res) => { let hash = req.body.payreq; let payreq = bolt11.decode(hash); + let { route } = req.body; let { user } = req; l("sending lightning", user.username, payreq.satoshis); @@ -36,60 +37,57 @@ module.exports = (app, db, emit, seen, lna, lnb) => async (req, res) => { return res.status(500).send("Not enough satoshis"); } - const stream = lna.sendPayment(lna.meta, {}); - stream.write({ payment_request: req.body.payreq }); - - stream.on("data", async m => { - if (m.payment_error) { - res.status(500).send(m.payment_error); - } else { - if (seen.includes(m.payment_preimage)) return; - seen.push(m.payment_preimage); - - let total = parseInt(m.payment_route.total_amt); - let fee = m.payment_route.total_fees; + let m; + try { + let paymentHash = payreq.tags.find(t => t.tagName === 'payment_hash').data; + m = await lna.sendToRouteSync({ + "payment_hash": Buffer.from(paymentHash, 'hex'), + route + }); - user.balance -= total - payreq.satoshis; + if (seen.includes(m.payment_preimage)) return; + seen.push(m.payment_preimage); - await db.transaction(async transaction => { - await user.save({ transaction }); + let total = parseInt(m.payment_route.total_amt); + let fee = m.payment_route.total_fees; - const payment = await db.Payment.create( - { - amount: -total, - fee, - user_id: user.id, - hash, - rate: app.get("rates")[user.currency], - currency: user.currency, - confirmed: true, - asset: 'LNBTC', - }, - { transaction } - ); + user.balance -= total - payreq.satoshis; - emit(user.username, "payment", payment); - emit(user.username, "user", user); + await db.transaction(async transaction => { + await user.save({ transaction }); - if (payreq.payeeNodeKey === config.lnb.id) { - let invoice = await lna.addInvoice({ value: payreq.satoshis }); - let payback = lnb.sendPayment(lnb.meta, {}); + const payment = await db.Payment.create( + { + amount: -total, + fee, + user_id: user.id, + hash, + rate: app.get("rates")[user.currency], + currency: user.currency, + confirmed: true, + asset: 'LNBTC', + }, + { transaction } + ); - /* eslint-disable-next-line */ - let { payment_request } = invoice; - /* eslint-disable-next-line */ - payback.write({ payment_request }); - } + emit(user.username, "payment", payment); + emit(user.username, "user", user); - seen.push(hash); - res.send(payment); - }); - } - }); + if (payreq.payeeNodeKey === config.lnb.id) { + let invoice = await lna.addInvoice({ value: payreq.satoshis }); + let payback = lnb.sendPayment(lnb.meta, {}); - stream.on("error", e => { - let msg = e.message; + /* eslint-disable-next-line */ + let { payment_request } = invoice; + /* eslint-disable-next-line */ + payback.write({ payment_request }); + } - res.status(500).send(msg); - }); + seen.push(hash); + res.send(payment); + }); + } catch (e) { + l(e); + return res.status(500).send(e); + } }; @@ -1,23 +1,30 @@ -const { Client } = require("authy-client"); const axios = require("axios"); const bcrypt = require("bcrypt"); const jwt = require("jsonwebtoken"); const mailgun = require("mailgun-js"); const uuidv4 = require("uuid/v4"); const BitcoinCore = require("bitcoin-core"); -const authyVerify = require("./authy"); const config = require("./config"); -const authy = new Client({ key: config.authy.key }); const whitelist = require("./whitelist"); const fb = "https://graph.facebook.com/"; const liquid = new BitcoinCore(config.liquid); const Sequelize = require("sequelize"); +const authenticator = require("otplib").authenticator; const pick = (O, ...K) => K.reduce((o, k) => ((o[k] = O[k]), o), {}); const l = console.log; let faucet = 1000; const DAY = 24 * 60 * 60 * 1000; +const twofa = (req, res, next) => { + let { + user, + body: { token } + } = req; + if (!user.twofa || authenticator.check(token, user.otpsecret)) next(); + else res.status(401).send("2fa required"); +}; + module.exports = (addresses, auth, app, bc, db, emit) => { app.get("/liquidate", async (req, res) => { let users = await db.User.findAll(); @@ -30,6 +37,11 @@ module.exports = (addresses, auth, app, bc, db, emit) => { )).unconfidential; await user.save(); } + + if (!user.otpsecret) { + user.otpsecret = authenticator.generateSecret(); + await user.save(); + } } res.end(); }); @@ -40,17 +52,17 @@ module.exports = (addresses, auth, app, bc, db, emit) => { faucet -= 100; const payment = await db.Payment.create({ user_id: user.id, - hash: 'Welcome Gift', + hash: "Welcome Gift", amount: 100, currency: user.currency, rate: app.get("rates")[user.currency], received: true, confirmed: 1, - asset: 'GIFT', + asset: "GIFT" }); await user.save(); } - } + }; app.post("/register", async (req, res) => { let err = m => res.status(500).send(m); @@ -66,24 +78,24 @@ module.exports = (addresses, auth, app, bc, db, emit) => { user.confidential )).unconfidential; user.name = user.username; - let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; + let ip = req.headers["x-forwarded-for"] || req.connection.remoteAddress; let countries = { CA: "CAD", US: "USD", JP: "JPY", CN: "CNY", AU: "AUD", - GB: "GBP", + GB: "GBP" }; - if (ip === "127.0.0.1") - user.currency = "CAD"; + if (ip === "127.0.0.1") user.currency = "CAD"; else { let info = await axios.get(`http://api.ipstack.com/${ip}?access_key=${config.ipstack}`); user.currency = countries[info.data.country_code] || "USD"; } user.currencies = [user.currency]; + user.otpsecret = authenticator.generateSecret(); addresses[user.address] = user.username; addresses[user.liquid] = user.username; @@ -143,6 +155,38 @@ module.exports = (addresses, auth, app, bc, db, emit) => { res.end(); }); + app.post("/disable2fa", auth, twofa, async (req, res) => { + let { user } = req; + user.twofa = false; + await user.save(); + emit(user.username, "user", user); + emit(user.username, "otpsecret", user.otpsecret); + res.end(); + }); + + app.get("/otpsecret", auth, twofa, async (req, res) => { + let { user } = req; + emit(user.username, "otpsecret", user.otpsecret); + res.end(); + }); + + app.post("/2fa", auth, async (req, res) => { + let { user } = req; + try { + const isValid = authenticator.check(req.body.token, req.user.otpsecret); + if (isValid) { + user.twofa = true; + user.save(); + emit(user.username, "user", req.user); + } else { + return res.status(500).send("Invalid token"); + } + } catch (e) { + l(e); + } + res.end(); + }); + app.post("/user", auth, async (req, res) => { try { let { user } = req; @@ -170,7 +214,9 @@ module.exports = (addresses, auth, app, bc, db, emit) => { addresses[user.address] = username; addresses[user.liquid] = user.username; token = jwt.sign({ username }, config.jwt); - res.cookie("token", token, { expires: new Date(Date.now() + 432000000) }); + res.cookie("token", token, { + expires: new Date(Date.now() + 432000000) + }); } if (email && user.email !== email) { @@ -206,15 +252,6 @@ module.exports = (addresses, auth, app, bc, db, emit) => { user.password = await bcrypt.hash(password, 1); } - if (twofa && !user.authyId && user.phoneVerified) { - try { - let r = await authy.registerUser({ countryCode: "CA", email, phone }); - user.authyId = r.user.id; - } catch (e) { - l(e); - } - } - await user.save(); emit(user.username, "user", req.user); res.send({ user, token }); @@ -297,6 +334,8 @@ module.exports = (addresses, auth, app, bc, db, emit) => { }); app.post("/login", async (req, res) => { + let twofa = req.body.token; + try { let user = await db.User.findOne({ where: { @@ -306,12 +345,15 @@ module.exports = (addresses, auth, app, bc, db, emit) => { if ( !user || - (user.password && !(await bcrypt.compare(req.body.password, user.password))) || - (user.twofa && !(await authyVerify(user))) + (user.password && + !(await bcrypt.compare(req.body.password, user.password))) ) { return res.status(401).end(); } + if (user.twofa && (typeof twofa === "undefined" || !authenticator.check(twofa, user.otpsecret))) + return res.status(401).send("2fa required"); + let payload = { username: user.username }; let token = jwt.sign(payload, config.jwt); res.cookie("token", token, { expires: new Date(Date.now() + 432000000) }); @@ -319,13 +361,14 @@ module.exports = (addresses, auth, app, bc, db, emit) => { user = pick(user, ...whitelist); res.send({ user, token }); } catch (err) { - console.log(err); + l(err); res.status(401).end(); } }); app.post("/facebookLogin", async (req, res) => { let { accessToken, userID } = req.body; + let twofa = req.body.token; let url = `https://graph.facebook.com/debug_token?input_token=${accessToken}&access_token=${ config.facebook.appToken @@ -367,17 +410,18 @@ module.exports = (addresses, auth, app, bc, db, emit) => { await gift(user); } + if (user.twofa && (typeof twofa === "undefined" || !authenticator.check(twofa, user.otpsecret))) + return res.status(401).send("2fa required"); + user.pic = (await axios.get( `${fb}/me/picture?access_token=${accessToken}&redirect=false` )).data.data.url; user.fbtoken = accessToken; await user.save(); - if (user.twofa && !(await authyVerify(user))) res.status(401).end(); - let payload = { username: user.username }; let token = jwt.sign(payload, config.jwt); - res.cookie("token", token, { expires: new Date(Date.now() + 432000000) }); + res.cookie("token", token , { expires: new Date(Date.now() + 432000000) }); res.send({ user, token }); } catch (err) { l(err); @@ -423,5 +467,5 @@ module.exports = (addresses, auth, app, bc, db, emit) => { } }); - setInterval(() => faucet = 2000, DAY) + setInterval(() => (faucet = 2000), DAY); }; @@ -161,6 +161,54 @@ __metadata: languageName: node linkType: hard +"@otplib/core@npm:^12.0.1": + version: 12.0.1 + resolution: "@otplib/core@npm:12.0.1" + checksum: 3a73c409dc4e9a3dbb8d1e4bd3cb438883c0c7f287c8a7485ef558b47e8e72af18e23e4817d085b9f5e40ce970d7b0ce11ae5524692927c964c80ce399840480 + languageName: node + linkType: hard + +"@otplib/plugin-crypto@npm:^12.0.1": + version: 12.0.1 + resolution: "@otplib/plugin-crypto@npm:12.0.1" + dependencies: + "@otplib/core": ^12.0.1 + checksum: f83458ed5a4ac91118d7bc113385d0ab296c7b97e243903a887f2097c1b03421e5f670be60f808d96a9934f3a0049aceb2af02f71e54d5f22f065000b841a0c6 + languageName: node + linkType: hard + +"@otplib/plugin-thirty-two@npm:^12.0.1": + version: 12.0.1 + resolution: "@otplib/plugin-thirty-two@npm:12.0.1" + dependencies: + "@otplib/core": ^12.0.1 + thirty-two: ^1.0.2 + checksum: 4deec8586480f880239a087f6f6599eb4425abdda184e383112f97993bb5961943fdb435fbea086b1f9d1116768ec0c2fb6df9e8a0dbb854b7c0765dbbdcd9fe + languageName: node + linkType: hard + +"@otplib/preset-default@npm:^12.0.1": + version: 12.0.1 + resolution: "@otplib/preset-default@npm:12.0.1" + dependencies: + "@otplib/core": ^12.0.1 + "@otplib/plugin-crypto": ^12.0.1 + "@otplib/plugin-thirty-two": ^12.0.1 + checksum: 32b214c0f750c793147f1e988093959aef8eded36c9d7df2c2c7ff4e4fb54de85b76b5ff28ee8ee39b1572c933d205c081a3c8f2df192199813b3572e61a7305 + languageName: node + linkType: hard + +"@otplib/preset-v11@npm:^12.0.1": + version: 12.0.1 + resolution: "@otplib/preset-v11@npm:12.0.1" + dependencies: + "@otplib/core": ^12.0.1 + "@otplib/plugin-crypto": ^12.0.1 + "@otplib/plugin-thirty-two": ^12.0.1 + checksum: 89366b1c52a8de2a1cd434c9fd534d97fcde0b103f92d15ff3cf37ed1d3579746b7b4b70efe398aa532ab44e15daa008d471f90f8b4de04f8cba81c05dfda7de + languageName: node + linkType: hard + "@pm2/agent-node@npm:^1.1.10": version: 1.1.10 resolution: "@pm2/agent-node@npm:1.1.10" @@ -1877,7 +1925,7 @@ __metadata: grpc: ^1.23.3 http-proxy-middleware: ^0.20.0 jsonwebtoken: ^8.5.1 - lnrpc: ^0.6.1 + lnrpc: ^0.6.2 lodash: ^4.17.13 mailgun-js: ^0.22.0 moment: ^2.24.0 @@ -1885,6 +1933,7 @@ __metadata: mysql: ^2.17.1 mysql2: ^1.6.5 nodemon: ^2.0.2 + otplib: ^12.0.1 passport: 0.4.0 passport-jwt: ^4.0.0 passport-local: 1.0.0 @@ -4970,7 +5019,7 @@ fsevents@~2.1.2: languageName: node linkType: hard -"lnrpc@npm:^0.6.1": +"lnrpc@npm:^0.6.2": version: 0.6.2 resolution: "lnrpc@npm:0.6.2" dependencies: @@ -6070,6 +6119,17 @@ fsevents@~2.1.2: languageName: node linkType: hard +"otplib@npm:^12.0.1": + version: 12.0.1 + resolution: "otplib@npm:12.0.1" + dependencies: + "@otplib/core": ^12.0.1 + "@otplib/preset-default": ^12.0.1 + "@otplib/preset-v11": ^12.0.1 + checksum: 93b006b69d7c51fa1e8d6e7a661c1208aa9410be10274a8eb81dcd1d2b1b08c3b9f1e2ef4e10d2a4ad4ef3a8f3e43da4830d21d674161a4fa43ac9e23594c437 + languageName: node + linkType: hard + "p-cancelable@npm:^0.3.0": version: 0.3.0 resolution: "p-cancelable@npm:0.3.0" @@ -8350,6 +8410,13 @@ fsevents@~2.1.2: languageName: node linkType: hard +"thirty-two@npm:^1.0.2": + version: 1.0.2 + resolution: "thirty-two@npm:1.0.2" + checksum: 573755c8a09da50666b4354fe6b6f8624cf2bfcf2c71ffbed531b6d73b988e1907be792ef23664749144978620ddb7026a158fc1c72d3eee4545b422dfc4e814 + languageName: node + linkType: hard + "through@npm:^2.3.8": version: 2.3.8 resolution: "through@npm:2.3.8" |
