diff options
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | lib/mail.js | 32 | ||||
| -rw-r--r-- | lib/send.js | 2 | ||||
| -rw-r--r-- | lib/sockets.js | 2 | ||||
| -rw-r--r-- | package.json | 2 | ||||
| -rw-r--r-- | routes/bitcoin/send.js | 55 | ||||
| -rw-r--r-- | routes/invoices.js | 4 | ||||
| -rw-r--r-- | routes/lightning/receive.js | 31 | ||||
| -rw-r--r-- | routes/liquid/fee.js | 9 | ||||
| -rw-r--r-- | routes/liquid/receive.js | 8 | ||||
| -rw-r--r-- | routes/liquid/send.js | 34 | ||||
| -rw-r--r-- | routes/payments.js | 6 | ||||
| -rw-r--r-- | routes/send.js | 2 | ||||
| -rw-r--r-- | routes/users.js | 25 | ||||
| -rwxr-xr-x | watcher.sh | 20 |
15 files changed, 134 insertions, 101 deletions
@@ -15,3 +15,6 @@ lnurl-server.sqlite3 watcher.log config mysql +build.json +build.sh +watcher.sh diff --git a/lib/mail.js b/lib/mail.js index 705880d2..ca2c2b81 100644 --- a/lib/mail.js +++ b/lib/mail.js @@ -10,6 +10,38 @@ function openInbox(cb) { imap.openBox("INBOX", true, cb); } +app.post( + "/contact-sil", + ah((req, res) => { + const mailgun = require("mailgun-js")(config.mailgun); + let data = { + subject: "Contact form", + text: JSON.stringify(req.body), + from: "[email protected]", + to: "[email protected]" + }; + + mailgun.messages().send(data); + res.send(req.body); + }) +); + +app.post( + "/contact", + ah((req, res) => { + const mailgun = require("mailgun-js")(config.mailgun); + let data = { + subject: "Contact form", + text: JSON.stringify(req.body), + from: "[email protected]", + to: "[email protected]" + }; + + mailgun.messages().send(data); + res.send(req.body); + }) +); + imap.once("ready", function() { openInbox(function(err, box) { if (err) throw err; diff --git a/lib/send.js b/lib/send.js index 660fcae4..fd577231 100644 --- a/lib/send.js +++ b/lib/send.js @@ -6,7 +6,7 @@ send = async (amount, memo, hash, user) => { let routingInfo = payreq.tags.find(t => t.tagName === "routing_info"); if ( routingInfo && - routingInfo.data.find(d => d.fee_proportional_millionths > 100) + routingInfo.data.find(d => d.fee_proportional_millionths > 1000) ) throw new Error("Fee rate too high"); diff --git a/lib/sockets.js b/lib/sockets.js index 931a9d23..bd59ee38 100644 --- a/lib/sockets.js +++ b/lib/sockets.js @@ -96,7 +96,7 @@ wss.on("connection", function(ws, req) { lastSeen[token] = new Date(); try { - if (!token || token === "null") return ws.close(); + if (!token || token === "null" || !jwt.decode(token)) return ws.close(); const username = jwt.decode(token).username; if (!username) throw new Error("Invalid JWT token"); diff --git a/package.json b/package.json index d1d126bd..a62f37cf 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "passport-local": "1.0.0", "pino": "^5.17.0", "pino-pretty": "^4.8.0", - "pm2": "^4.5.6", + "pm2": "^5.1.0", "query-string": "^6.13.1", "sequelize": "^5.21.3", "sqlite3": "^5.0.2", diff --git a/routes/bitcoin/send.js b/routes/bitcoin/send.js index cab79e06..470889b3 100644 --- a/routes/bitcoin/send.js +++ b/routes/bitcoin/send.js @@ -1,4 +1,3 @@ -const bitcoin = require("bitcoinjs-lib"); const btc = config.liquid.btcasset; module.exports = ah(async (req, res) => { @@ -32,10 +31,10 @@ module.exports = ah(async (req, res) => { total = total - change + fee; let amount = total - fee; - let params; + let account, params; try { await db.transaction(async transaction => { - let account = await db.Account.findOne({ + account = await db.Account.findOne({ where: { id: user.account_id }, @@ -62,38 +61,38 @@ module.exports = ah(async (req, res) => { await account.decrement({ balance: total }, { transaction }); await account.reload({ transaction }); + }); - params = { - amount: -amount, - fee, - memo, - account_id: account.id, - user_id: user.id, - rate: app.get("rates")[user.currency], - currency: user.currency, - address, - confirmed: true, - received: false, - network: "bitcoin" - }; + params = { + amount: -amount, + fee, + memo, + account_id: account.id, + user_id: user.id, + rate: app.get("rates")[user.currency], + currency: user.currency, + address, + confirmed: true, + received: false, + network: "bitcoin" + }; - if (config.bitcoin.walletpass) - await bc.walletPassphrase(config.bitcoin.walletpass, 300); + if (config.bitcoin.walletpass) + await bc.walletPassphrase(config.bitcoin.walletpass, 300); - hex = (await bc.signRawTransactionWithWallet(hex)).hex; - params.hash = await bc.sendRawTransaction(hex); + hex = (await bc.signRawTransactionWithWallet(hex)).hex; + params.hash = await bc.sendRawTransaction(hex); - let payment = await db.Payment.create(params, { transaction }); + let payment = await db.Payment.create(params); - 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); - res.send(payment); + emit(user.username, "payment", payment); + res.send(payment); - payments.push(params.hash); - l.info("sent bitcoin", user.username, total); - }); + payments.push(params.hash); + l.info("sent bitcoin", user.username, total); } catch (e) { l.error("error sending bitcoin", e.message); return res.status(500).send(e.message); diff --git a/routes/invoices.js b/routes/invoices.js index c188811e..51906b8c 100644 --- a/routes/invoices.js +++ b/routes/invoices.js @@ -27,6 +27,10 @@ app.post( let { liquidAddress, invoice, user, tx } = req.body; let { blindkey } = invoice; + if (invoice.amount < 0) throw new Error("amount out of range"); + if (invoice.tip > invoice.amount || invoice.tip > 1000000 || invoice.tip < 0) + throw new Error("tip amount out of range"); + if (liquidAddress) { l.info("conversion request for", liquidAddress, invoice.text); convert[invoice.text] = { address: liquidAddress, tx }; diff --git a/routes/lightning/receive.js b/routes/lightning/receive.js index 32c54de6..8d2aa750 100644 --- a/routes/lightning/receive.js +++ b/routes/lightning/receive.js @@ -1,20 +1,18 @@ const handlePayment = async msg => { + if (!msg.settled) return; let account, total, user; - try { - 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); + + try { + await db.transaction(async transaction => { const { text: hash, currency, memo, rate, tip, user_id } = invoice; const amount = parseInt(msg.amt_paid_sat) - tip; @@ -85,7 +83,12 @@ const handlePayment = async msg => { let c = convert[msg.payment_request]; if (msg.payment_request && c) { - l.info("lightning detected for conversion request", msg.payment_request, c.address, user.username); + l.info( + "lightning detected for conversion request", + msg.payment_request, + c.address, + user.username + ); user.account = account; diff --git a/routes/liquid/fee.js b/routes/liquid/fee.js index 2070873a..fad69f13 100644 --- a/routes/liquid/fee.js +++ b/routes/liquid/fee.js @@ -3,11 +3,6 @@ const buildTx = require("../../lib/buildliquidtx"); liquidTx = async ({ address, asset, amount, feeRate, replaceable, user }) => { let tx, fee; let node = lq; - /* - if (asset === config.liquid.btcasset) { - node = rare; - } - */ if (user.account.pubkey) { let psbt = await buildTx({ @@ -64,6 +59,8 @@ liquidTx = async ({ address, asset, amount, feeRate, replaceable, user }) => { } ); + l.info("funding tx for fee estimate", tx); + tx = await node.fundRawTransaction(tx, params); let blinded = await node.blindRawTransaction(tx.hex); @@ -81,7 +78,7 @@ module.exports = ah(async (req, res) => { let tx = await liquidTx({ ...req.body, user: req.user }) res.send(tx); } catch (e) { - l.error("error estimating liquid fee", e.message, e.stack); + l.error("error estimating liquid fee", e.message); return res.status(500).send(e.message); } }); diff --git a/routes/liquid/receive.js b/routes/liquid/receive.js index c377a6b5..259db7c7 100644 --- a/routes/liquid/receive.js +++ b/routes/liquid/receive.js @@ -101,7 +101,7 @@ zmqRawTx.on("message", async (topic, message, sequence) => { user_id: user.id, network: "liquid" }, - order: [["id", "DESC"]], + order: [["id", "DESC"]] }); if (!invoice) return; @@ -286,9 +286,9 @@ setInterval(async () => { for (let i = 0; i < arr.length; i++) { const hash = arr[i]; - let account, address, user, total; + let account, address, user, total, p; await db.transaction(async transaction => { - let p = await db.Payment.findOne({ + p = await db.Payment.findOne({ where: { hash, confirmed: 0, received: 1 }, include: [ { @@ -347,7 +347,7 @@ setInterval(async () => { }); let c = convert[address]; - if (address && c) { + if (address && c && p.account.asset === network.assetHash) { l.info( "liquid detected for conversion request", address, diff --git a/routes/liquid/send.js b/routes/liquid/send.js index 19b7344f..13f77d26 100644 --- a/routes/liquid/send.js +++ b/routes/liquid/send.js @@ -1,5 +1,6 @@ const btc = config.liquid.btcasset; const lcad = config.liquid.cadasset; +const { Transaction } = require("liquidjs-lib"); sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { if (amount > 10000000) throw new Error("Amount too large"); @@ -48,7 +49,8 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { const assets = Object.keys(totals); const payments = []; - return db.transaction(async transaction => { + let main, signed; + await db.transaction(async transaction => { for (let i = 0; i < assets.length; i++) { let asset = assets[i]; let amount = totals[asset]; @@ -75,12 +77,12 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { await faucet.reload({ transaction }); await faucet.save({ transaction }); } - - total += fee - covered; } + + total += fee - covered; } - if (limit && total > limit) + if (limit && total > limit + fee) throw new Error("Tx amount exceeds authorized amount"); if (asset !== btc || total) { @@ -132,16 +134,11 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { } } - if (config.liquid.walletpass) - await lq.walletPassphrase(config.liquid.walletpass, 300); - - let blinded = await lq.blindRawTransaction(tx.hex); - let signed = await lq.signRawTransactionWithWallet(blinded); - let txid = await lq.sendRawTransaction(signed.hex); - - l.info("sent liquid tx", txid, address); + signed = await lq.signRawTransactionWithWallet( + await lq.blindRawTransaction(tx.hex) + ); + let txid = Transaction.fromHex(signed.hex).getId(); - let main; for (let i = 0; i < assets.length; i++) { p = payments[i]; if (p) { @@ -157,15 +154,22 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { emit(user.username, "account", main.account); emit(user.username, "payment", main); - return main; }); + + if (config.liquid.walletpass) + await lq.walletPassphrase(config.liquid.walletpass, 300); + + let txid = await lq.sendRawTransaction(signed.hex); + l.info("sent liquid tx", txid, address); + + return main; }; module.exports = ah(async (req, res) => { let { user } = req; try { - res.send(await sendLiquid({...req.body, user })); + res.send(await sendLiquid({ ...req.body, user })); } catch (e) { l.error("problem sending liquid", user.username, e.message); return res.status(500).send(e); diff --git a/routes/payments.js b/routes/payments.js index a749e333..e78730d2 100644 --- a/routes/payments.js +++ b/routes/payments.js @@ -151,9 +151,9 @@ ah(async () => { const { hdkeypath } = await lq.getAddressInfo(address); const parts = hdkeypath.split("/"); app.set("lqAddressIndex", parts[parts.length - 1].slice(0, -1)); - } catch (e) { - console.error("Problem getting liquid address", e); - } + } catch(e) { + l.warn("Problem getting liquid address index", e.message); + } }, 50); } diff --git a/routes/send.js b/routes/send.js index 579e70b4..3aec9fb6 100644 --- a/routes/send.js +++ b/routes/send.js @@ -45,7 +45,7 @@ module.exports = ah(async (req, res, next) => { }; if (!username) { - return res.status(500).send("Vouchers temporarily disabled"); + throw new Error("Vouchers temporarily disabled"); l.info("creating redeemable payment"); params.redeemcode = uuidv4(); params.hash = `${req.get("origin")}/redeem/${params.redeemcode}`; diff --git a/routes/users.js b/routes/users.js index 71f4b89a..23f016c7 100644 --- a/routes/users.js +++ b/routes/users.js @@ -148,7 +148,8 @@ app.post( return res.status(500).send("Username taken"); } else { sockets[username] = sockets[user.username]; - if (user.username !== username) l.info("changing username", user.username, username); + if (user.username !== username) + l.info("changing username", user.username, username); user.username = username; token = jwt.sign({ username }, config.jwt); @@ -323,10 +324,7 @@ app.post( (user.password && !(await bcrypt.compare(req.body.password, user.password))) ) { - l.warn( - "invalid username or password attempt", - req.body.username - ); + l.warn("invalid username or password attempt", req.body.username); return res.status(401).end(); } @@ -426,11 +424,24 @@ app.get( : config.liquid.network ]; type = "p2sh"; - + // async request to node to bump its internal index but don't use result - lq.getNewAddress().catch(console.error); + lq.getNewAddress().catch(e => + l.warn("Problem bumping liquid address index", e.message) + ); i = parseInt(app.get("lqAddressIndex")); + + if (!i) { + const { hdkeypath } = await lq.getAddressInfo( + await lq.getNewAddress() + ); + const parts = hdkeypath.split("/"); + i = parts[parts.length - 1].slice(0, -1); + } + + if (!i) throw new Error("Problem generating address"); + hd = fromBase58(config.liquid.masterkey, n).derivePath(`m/0'/0'/${i}'`); app.set("lqAddressIndex", i + 1); } else { diff --git a/watcher.sh b/watcher.sh deleted file mode 100755 index 3fb60993..00000000 --- a/watcher.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -sats=100000000 -threshold=$1 -while true -do - ln=$(lncli --lnddir=/root/.lnda --network=mainnet --chain=bitcoin --rpcserver=localhost:10001 channelbalance | jr .balance) - bc=$(bitcoin-cli getbalance) - el=$(elements-cli getbalance | jr .bitcoin) - total=$(node -pe "$ln + $bc * $sats + $el * $sats") - low=$(node -pe "$total < $threshold") - echo $(date -Is) ln $ln bc $bc el $el tot $total - if "$low"; then - echo "Threshold hit, setting new threshold" - threshold=$total - # yarn pm2 stop 0 > /dev/null - node /root/mailgun/index.js - fi - sleep 10 -done |
