diff options
| author | Adam Soltys <[email protected]> | 2020-08-03 21:38:29 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2020-08-03 21:38:29 -0700 |
| commit | 2bcd5e9cd2233934b6d78724a07172b187ceb0b0 (patch) | |
| tree | dba0c6451c1fa962dda1c3aa848abaa36d7012ab /routes | |
| parent | 1f44dadfb24913d9a6835f3b18340ede580e886a (diff) | |
| download | coinos-server-2bcd5e9cd2233934b6d78724a07172b187ceb0b0.tar.gz coinos-server-2bcd5e9cd2233934b6d78724a07172b187ceb0b0.zip | |
user urls
Diffstat (limited to 'routes')
| -rw-r--r-- | routes/invoices.js | 23 | ||||
| -rw-r--r-- | routes/lightning/invoice.js | 2 | ||||
| -rw-r--r-- | routes/lightning/receive.js | 139 | ||||
| -rw-r--r-- | routes/lnurl.js | 381 | ||||
| -rw-r--r-- | routes/payments.js | 2 | ||||
| -rw-r--r-- | routes/users.js | 12 |
6 files changed, 295 insertions, 264 deletions
diff --git a/routes/invoices.js b/routes/invoices.js index fdfb39d8..f344e9f9 100644 --- a/routes/invoices.js +++ b/routes/invoices.js @@ -14,14 +14,23 @@ app.get("/invoice", auth, ah(async (req, res, next) => { } })); -app.post("/invoice", auth, ah(async (req, res, next) => { - const { invoice } = req.body; - invoice.user_id = req.user.id; +app.post("/invoice", ah(async (req, res, next) => { + let { invoice, user } = req.body; + if (!user) ({ user } = req); + else { + user = await db.User.findOne({ + where: { + username: user.username, + } + }); + } + if (!user) throw new Error("user not provided"); + invoice.user_id = user.id; l.info( "creating invoice", invoice.text, - req.user.username, + user.username, invoice.network, invoice.amount, invoice.tip, @@ -44,7 +53,7 @@ app.post("/invoice", auth, ah(async (req, res, next) => { }, }); - res.send( - exists ? await exists.update(invoice) : await db.Invoice.create(invoice) - ); + invoice = exists ? await exists.update(invoice) : await db.Invoice.create(invoice); + addresses[invoice.address] = user.username; + res.send(invoice); })); diff --git a/routes/lightning/invoice.js b/routes/lightning/invoice.js index 689c696a..51eff332 100644 --- a/routes/lightning/invoice.js +++ b/routes/lightning/invoice.js @@ -1,8 +1,6 @@ module.exports = ah(async (req, res) => { const { amount, memo, tip } = req.body; - l.info("adding lightning invoice", req.user.username, amount, tip); - try { if (config.lna.clightning) { const invoice = await lnb.invoice(`${amount + tip}sat` || "any", new Date(), memo, 360); diff --git a/routes/lightning/receive.js b/routes/lightning/receive.js index 34ac1fc3..e8246ab9 100644 --- a/routes/lightning/receive.js +++ b/routes/lightning/receive.js @@ -1,90 +1,97 @@ const asset = "LNBTC"; -const handlePayment = async msg => { +const handlePayment = async (msg) => { try { - await db.transaction(async transaction => { - if (!msg.settled) return; + await db.transaction(async (transaction) => { + if (!msg.settled) return; - const invoice = await db.Invoice.findOne({ - where: { - text: msg.payment_request - } - }); + const invoice = await db.Invoice.findOne({ + where: { + text: msg.payment_request, + }, + }); + + if (!invoice) + return l.warn( + "received lightning with no invoice", + msg.payment_request + ); - if (!invoice) return l.warn("received lightning with no invoice", msg.payment_request); + const { text: hash, currency, memo, rate, tip, user_id } = invoice; + const amount = parseInt(msg.amt_paid_sat) - tip; - const { text: hash, currency, memo, rate, tip, user_id } = invoice; - const amount = parseInt(msg.amt_paid_sat) - tip; + const account = await db.Account.findOne({ + where: { + user_id, + asset: config.liquid.btcasset, + }, + include: { + model: db.User, + as: "user", + }, + lock: transaction.LOCK.UPDATE, + transaction, + }); - const account = await db.Account.findOne({ - where: { - user_id, - asset: config.liquid.btcasset - }, - include: { - model: db.User, - as: 'user', - }, - lock: transaction.LOCK.UPDATE, - transaction - }); + const { user } = account; - const { user } = account; + let preimage = msg.r_preimage.toString("hex"); - let preimage = msg.r_preimage.toString("hex"); + let payment = await db.Payment.create( + { + account_id: account.id, + user_id, + hash, + memo, + amount, + currency, + preimage, + rate, + received: true, + confirmed: true, + network: "LNBTC", + tip, + }, + { transaction } + ); - let payment = await db.Payment.create({ - account_id: account.id, - user_id, - hash, - memo, - amount, - currency, - preimage, - rate, - received: true, - confirmed: true, - network: "LNBTC", - tip - }, - { transaction }); + let total = amount + tip; + invoice.received += total; + account.balance += total; - let total = amount + tip; - invoice.received += total; - account.balance += total; + await account.save({ transaction }); + await invoice.save({ transaction }); + await payment.save({ transaction }); + payments.push(msg.payment_request); - await account.save({ transaction }); - await invoice.save({ transaction }); - await payment.save({ transaction }); - payments.push(msg.payment_request); + payment = payment.get({ plain: true }); + payment.account = account.get({ plain: true }); - payment = payment.get({ plain: true }); - payment.account = account.get({ plain: true }); - emit(user.username, "payment", payment); - emit(user.username, "account", payment.account); - notify(user, `Received ${total} SAT`); + emit(user.username, "payment", payment); + emit(user.username, "account", payment.account); + notify(user, `Received ${total} SAT`); - l.info( - "lightning payment received", - user.username, - payment.amount, - payment.tip - ); - }); - } catch(e) { + l.info( + "lightning payment received", + user.username, + payment.amount, + payment.tip + ); + }); + } catch (e) { l.error("problem receiving lightning payment", e.message); - } + } }; if (config.lna.clightning) { - const poll = async ln => { - const wait = async i => { + const poll = async (ln) => { + const wait = async (i) => { const { bolt11: payment_request, pay_index, status, msatoshi_received, - payment_preimage: r_preimage + payment_preimage: r_preimage, } = await ln.waitanyinvoice(i); let settled = status === "paid"; @@ -94,13 +101,13 @@ if (config.lna.clightning) { payment_request, settled, amt_paid_sat, - r_preimage + r_preimage, }); wait(pay_index); }; const { invoices } = await ln.listinvoices(); - wait(Math.max(...invoices.map(i => i.pay_index).filter(n => n))); + wait(Math.max(...invoices.map((i) => i.pay_index).filter((n) => n))); }; poll(lna); diff --git a/routes/lnurl.js b/routes/lnurl.js index d8336709..44eb0fb9 100644 --- a/routes/lnurl.js +++ b/routes/lnurl.js @@ -17,186 +17,217 @@ var optionalAuth = function (req, res, next) { })(req, res, next); }; -app.get("/url", ah(async (req, res, next) => { - try { - const code = await db.Code.findOne({ - where: { - code: req.query.code, - }, - }); +app.get( + "/url", + ah(async (req, res, next) => { + try { + const code = await db.Code.findOne({ + where: { + code: req.query.code, + }, + }); - if (code) { - res.send(code.text); - } else { - throw new Error("code not found"); + if (code) { + res.send(code.text); + } else { + throw new Error("code not found"); + } + } catch (e) { + l.error("couldn't find url", e.message); } - } catch (e) { - l.error("couldn't find url", e.message); - } -})); - -app.get("/withdraw", auth, ah(async (req, res, next) => { - const { min, max } = req.query; - try { - const result = await lnurlServer.generateNewUrl("withdrawRequest", { - minWithdrawable: min * 1000, - maxWithdrawable: max * 1000, - defaultDescription: "coinos voucher", - }); + }) +); - withdrawals[result.secret] = req.user; +app.get( + "/withdraw", + auth, + ah(async (req, res, next) => { + const { min, max } = req.query; + try { + const result = await lnurlServer.generateNewUrl("withdrawRequest", { + minWithdrawable: min * 1000, + maxWithdrawable: max * 1000, + defaultDescription: "coinos voucher", + }); - res.send(result); - } catch (e) { - l.error("problem generating withdrawl url", e.message); - res.status(500).send(e.message); - } -})); + withdrawals[result.secret] = req.user; -app.post("/code", ah(async (req, res, next) => { - try { - const { encoded } = req.body.lnurl; - const code = await db.Code.create({ - code: "lnurl:" + encoded.substr(-32), - text: encoded, - }); + res.send(result); + } catch (e) { + l.error("problem generating withdrawl url", e.message); + res.status(500).send(e.message); + } + }) +); - res.send(code); - } catch (e) { - res.status(500).send(e.message); - } -})); +app.post( + "/code", + ah(async (req, res, next) => { + try { + const { encoded } = req.body.lnurl; + const code = await db.Code.create({ + code: "lnurl:" + encoded.substr(-32), + text: encoded, + }); -app.post("/withdraw", auth, ah(async (req, res, next) => { - const { user } = req; - const { - amount: value, - params: { callback, k1 }, - } = req.body; - const invoice = await lna.addInvoice({ value }); - const { payment_request: pr } = invoice; - const url = `${callback}?k1=${k1}&pr=${pr}`; + res.send(code); + } catch (e) { + res.status(500).send(e.message); + } + }) +); - await db.Invoice.create({ - user_id: user.id, - text: pr, - rate: app.get("rates")[user.currency], - currency: user.currency, - amount: value, - tip: 0, - network: "BTC", - }); +app.post( + "/withdraw", + auth, + ah(async (req, res, next) => { + const { user } = req; + const { + amount: value, + params: { callback, k1 }, + } = req.body; + const invoice = await lna.addInvoice({ value }); + const { payment_request: pr } = invoice; + const url = `${callback}?k1=${k1}&pr=${pr}`; - try { - result = (await axios.get(url)).data; - res.send(result); - } catch (e) { - l.error("failed to withdraw", e.message); - res.status(500).send(e.message); - } -})); + await db.Invoice.create({ + user_id: user.id, + text: pr, + rate: app.get("rates")[user.currency], + currency: user.currency, + amount: value, + tip: 0, + network: "BTC", + }); -const pay = async ({ amount, minSendable, maxSendable }, res, user) => { - minSendable = minSendable || 1000; - maxSendable = maxSendable || 1000000000; - if (parseInt(amount)) minSendable = maxSendable = amount * 1000; + try { + result = (await axios.get(url)).data; + res.send(result); + } catch (e) { + l.error("failed to withdraw", e.message); + res.status(500).send(e.message); + } + }) +); - try { - const result = await lnurlServer.generateNewUrl("payRequest", { - minSendable, - maxSendable, - metadata: JSON.stringify([["text/plain", `paying ${user.username}`]]), +app.get( + "/pay/:username", + ah(async (req, res, next) => { + const { username } = req.params; + let user = await db.User.findOne({ + where: { + username, + }, }); - recipients[result.secret] = user; - l.info("recipient", user.username, result.secret); - res.send(result); - } catch (e) { - l.error("problem generating payment url", e.message); - res.status(500).send(e.message); - } -}; + let { amount, minSendable, maxSendable } = req.query; + minSendable = minSendable || 1000; + maxSendable = maxSendable || 1000000000; + if (parseInt(amount)) minSendable = maxSendable = amount * 1000; -app.get("/pay/:username", ah(async (req, res, next) => { - const { username } = req.params; - let user = await db.User.findOne({ - where: { - username, - }, - }); - pay(req.query, res, user); -})); + let invoices = await db.Invoice.findAll({ + where: { + amount, + }, + order: [["id", "DESC"]], + limit: 1, + }); -app.get("/pay", auth, ah(async (req, res, next) => { - const { user } = req; - pay(req.query, res, user); -})); + if (invoices.length) await invoices[0].destroy(); -app.post("/pay", auth, ah(async (req, res, next) => { - const { user } = req; - const { - amount, - params: { callback, k1 }, - } = req.body; + try { + const result = await lnurlServer.generateNewUrl("payRequest", { + minSendable, + maxSendable, + metadata: JSON.stringify([["text/plain", `paying ${user.username}`]]), + }); - const url = `${callback}?amount=${amount * 1000}`; - l.info("url", url); + recipients[result.secret] = user; + l.info("recipient", user.username, result.secret); + res.send(result); + } catch (e) { + l.error("problem generating payment url", e.message); + res.status(500).send(e.message); + } + }) +); - try { - const parts = callback.split("/"); - const secret = parts[parts.length - 1]; - payments[secret] = user; +app.post( + "/pay", + auth, + ah(async (req, res, next) => { + const { user } = req; + const { + amount, + params: { callback, k1 }, + } = req.body; - const result = (await axios.get(url)).data; - res.send(await send(amount, '', result.pr, user)); - } catch (e) { - l.error("failed to send payment", e.message); - res.status(500).send(e.message); - } -})); + const url = `${callback}?amount=${amount * 1000}`; -app.get("/login", optionalAuth, ah(async (req, res, next) => { - try { - const result = await lnurlServer.generateNewUrl("login"); + try { + const parts = callback.split("/"); + const secret = parts[parts.length - 1]; + payments[secret] = user; - if (req.user) { - logins[result.secret] = req.user.username; + const result = (await axios.get(url)).data; + res.send(await send(amount, "", result.pr, user)); + } catch (e) { + l.error("failed to send payment", e.message); + throw e; + res.status(500).send(e.message); } + }) +); - res.send(result); - } catch (e) { - l.error("problem generating login url", e.message); - res.status(500).send(e.message); - } -})); +app.get( + "/login", + optionalAuth, + ah(async (req, res, next) => { + try { + const result = await lnurlServer.generateNewUrl("login"); -app.get("/decode", ah(async (req, res, next) => { - const { text } = req.query; + if (req.user) { + logins[result.secret] = req.user.username; + } - try { - const url = lnurl.decode(text); - let spl = url.split("?"); - if (spl.length > 1 && qs.parse(spl[1]).tag === "login") { - return res.send({ - tag: "login", - k1: qs.parse(spl[1]).k1, - callback: url, - domain: url - .split("://")[1] - .split("/")[0] - .split("@") - .slice(-1)[0] - .split(":")[0], - }); + res.send(result); + } catch (e) { + l.error("problem generating login url", e.message); + res.status(500).send(e.message); } + }) +); - const { data: params } = await axios.get(url); - res.send(params); - } catch (e) { - l.error("problem decoding lnurl", e.message); - res.status(500).send(e.message); - } -})); +app.get( + "/decode", + ah(async (req, res, next) => { + const { text } = req.query; + + try { + const url = lnurl.decode(text); + let spl = url.split("?"); + if (spl.length > 1 && qs.parse(spl[1]).tag === "login") { + return res.send({ + tag: "login", + k1: qs.parse(spl[1]).k1, + callback: url, + domain: url + .split("://")[1] + .split("/")[0] + .split("@") + .slice(-1)[0] + .split(":")[0], + }); + } + + const { data: params } = await axios.get(url); + res.send(params); + } catch (e) { + l.error("problem decoding lnurl", e.message); + res.status(500).send(e.message); + } + }) +); lnurlServer.bindToHook( "middleware:signedLnurl:afterCheckSignature", @@ -221,36 +252,29 @@ lnurlServer.bindToHook( if (account.balance < amount) { throw new Error("Insufficient funds"); } - - l.info("lnurl payment", user.username, amount); } const recipient = recipients[secret]; if (recipient) { - setTimeout(async () => { - try { - let { invoices } = await lnb.listInvoices({ - pending_only: true, - num_max_invoices: 1, - reversed: true, - }); - let i = invoices.find((i) => parseInt(i.value) === amount); - if (i) { - await db.Invoice.create({ - user_id: recipient.id, - text: i.payment_request, - rate: app.get("rates")[recipient.currency], - currency: recipient.currency, - amount: Math.round(amount / 1000), - tip: 0, - network: "BTC", - }); - } - } catch (e) { - l.error("problem trying to get create payment invoice", e); - } - }, 1000); + setTimeout(async () => { + let { invoices } = await lnb.listInvoices({ + pending_only: true, + }); + + if (invoices.length) { + let invoice = await db.Invoice.create({ + user_id: recipient.id, + text: invoices[invoices.length - 1].payment_request, + rate: app.get("rates")[recipient.currency], + currency: recipient.currency, + amount, + tip: 0, + network: "BTC", + }); + l.info("invoice created", invoice.text, invoice.amount); + } + }, 100); } } @@ -337,6 +361,7 @@ lnurlServer.bindToHook( let p = payments.find((p) => p.payment_request === pr); if (p) { + l.info("found payment", pr); payment.fee = p.fee; account.balance -= p.fee; await account.save(); diff --git a/routes/payments.js b/routes/payments.js index dcd76f2e..d88c95a7 100644 --- a/routes/payments.js +++ b/routes/payments.js @@ -95,7 +95,7 @@ const read = require("../lib/read"); "/lightning/channelRequest", require("./lightning/channelRequest") ); - app.post("/lightning/invoice", auth, require("./lightning/invoice")); + app.post("/lightning/invoice", require("./lightning/invoice")); app.post("/lightning/query", auth, require("./lightning/query")); app.post("/lightning/send", auth, require("./lightning/send")); require("./lightning/receive"); diff --git a/routes/users.js b/routes/users.js index 1a0f82c1..471a4e5e 100644 --- a/routes/users.js +++ b/routes/users.js @@ -294,23 +294,15 @@ app.post( }) ); -app.post( +app.get( "/address", - auth, ah(async (req, res) => { if (!config.bitcoin) return res.status(500).send("Bitcoin not configured"); - let { user } = req; - delete addresses[user.address]; - if (config.bitcoin.walletpass) await bc.walletPassphrase(config.bitcoin.walletpass, 300); - user.address = await bc.getNewAddress("", req.body.type || "bech32"); - await user.save(); - addresses[user.address] = user.username; - emit(user.username, "user", user); - res.send(user.address); + res.send(await bc.getNewAddress("", req.query.type || "bech32")); }) ); |
