diff options
| -rw-r--r-- | index.ts | 11 | ||||
| -rw-r--r-- | lib/nwc.ts | 28 | ||||
| -rw-r--r-- | routes/users.ts | 67 |
3 files changed, 94 insertions, 12 deletions
@@ -113,7 +113,9 @@ app.post("/superuser", users.superuser); app.get("/verify/:code", users.verify); app.post("/request", auth, users.request); app.post("/forgot", users.forgot); -app.post("/login", { +app.post( + "/login", + { config: { rateLimit: { max: 5, @@ -122,10 +124,15 @@ app.post("/login", { }, }, }, - users.login); + users.login, +); app.post("/printer", users.printer); app.get("/challenge", users.challenge); app.post("/nostrLogin", users.nostrLogin); +app.get("/app/:pubkey", auth, users.app); +app.get("/apps", auth, users.apps); +app.post("/app", auth, users.updateApp); +app.post("/apps/delete", auth, users.deleteApp); app.get("/subscriptions", auth, users.subscriptions); app.post("/subscription", auth, users.subscription); @@ -52,11 +52,11 @@ export default () => { if (!methods.includes(method)) return; - const uid = await g(pubkey); - const user = await g(`user:${uid}`); + const app = await g(pubkey); + const user = await g(`user:${app.uid}`); try { - const result = await handle(method, params, user, ev); + const result = await handle(method, params, ev, app, user); const payload = JSON.stringify({ result_type: method, ...result }); content = await nip04.encrypt(sk, pubkey, payload); @@ -77,7 +77,7 @@ export default () => { err( "problem with nwc", pubkey, - user?.username, + app?.name, JSON.stringify(params), e.message, ); @@ -89,7 +89,7 @@ export default () => { }); }; -const handle = (method, params, user, ev) => +const handle = (method, params, ev, app, user) => ({ async pay_invoice() { const { invoice: pr } = params; @@ -102,13 +102,17 @@ const handle = (method, params, user, ev) => const recipient = await g(`user:${invoice.uid}`); if (recipient?.username !== "mint") { - const { id: preimage } = await sendInternal({ + const { id: pid } = await sendInternal({ amount, invoice, recipient, sender: user, }); + const preimage = pid; + if (app.pubkey !== user.pubkey) + await db.lPush(`${pubkey}:payments`, pid); + if (invoice.memo?.includes("9734")) { const { invoices } = await ln.listinvoices({ invstring: pr }); const inv = invoices[0]; @@ -124,12 +128,15 @@ const handle = (method, params, user, ev) => return result({ preimage }); } } - await sendLightning({ + + const { id: pid } = await sendLightning({ amount, user, pr, }); + if (app.pubkey !== user.pubkey) await db.lPush(`${pubkey}:payments`, pid); + for (let i = 0; i < 10; i++) { const { pays } = await ln.listpays(pr); const p = pays.find((p) => p.status === "complete"); @@ -144,7 +151,8 @@ const handle = (method, params, user, ev) => }, async pay_keysend() { - const { amount, pubkey, tlv_records: extratlvs } = params; + const { amount: amount_msat, pubkey, tlv_records: extratlvs } = params; + const amount = Math.round(amount_msat / 1000); try { const { payment_hash } = await sendKeysend({ @@ -276,7 +284,9 @@ const handle = (method, params, user, ev) => async list_transactions() { const { from, until, limit = 10, offset = 0, type } = params; - const payments = await db.lRange(`${user.id}:payments`, 0, -1); + const { pubkey } = app; + const k = pubkey === user.pubkey ? user.id : pubkey; + const payments = await db.lRange(`${k}:payments`, 0, -1); let transactions = []; for (const pid of payments) { diff --git a/routes/users.ts b/routes/users.ts index 16c2d407..ddadec5f 100644 --- a/routes/users.ts +++ b/routes/users.ts @@ -5,7 +5,7 @@ import { requirePin } from "$lib/auth"; import { db, g, s } from "$lib/db"; import { err, l, warn } from "$lib/logging"; import { mail, templates } from "$lib/mail"; -import { getNostrUser, getProfile } from "$lib/nostr"; +import { getNostrUser, getProfile, serverPubkey } from "$lib/nostr"; import { reconcile, types } from "$lib/payments"; import register from "$lib/register"; import { emit } from "$lib/sockets"; @@ -261,6 +261,7 @@ export default { } user.haspin = !!user.pin; + user.destination = user.destination.trim(); await s(`user:${user.pubkey}`, user.id); await s( `user:${user.username.toLowerCase().replace(/\s/g, "")}`, @@ -821,4 +822,68 @@ export default { res.code(500).send({ error: "Failed to generate LittleFS image" }); } }, + + async app(req, res) { + const { pubkey } = req.params; + const app = await g(pubkey); + res.send(app); + }, + + async apps(req, res) { + const { user } = req; + const pubkeys = await db.sMembers(`${user.id}:apps`); + const apps = await Promise.all(pubkeys.map((p) => g(p))); + + const { host } = new URL(process.env.URL); + const lud16 = `${user.username}@${host}`; + const relay = encodeURIComponent(config.nostr); + + await Promise.all( + apps.map(async (a) => { + if (a.secret) + a.nwc = `nostr+walletconnect://${serverPubkey}?relay=${relay}&secret=${a.secret}&lud16=${lud16}`; + + a.spent = (await db.lRange(`${a.pubkey}:payments`, 0, -1)).reduce( + (a, b) => a + (Math.abs(b.amount) + b.fee + b.ourfee), + 0, + ); + }), + ); + + res.send(apps); + }, + + async updateApp(req, res) { + try { + let { secret, pubkey, max_amount, budget_renewal, name } = req.body; + const { user } = req; + const uid = user.id; + let app = await g(pubkey); + if (app && uid !== app.uid) fail("Unauthorized"); + if (secret) pubkey = getPublicKey(secret); + app = { ...app, pubkey, max_amount, budget_renewal, name, uid, secret }; + await s(pubkey, app); + await db.sAdd(`${uid}:apps`, pubkey); + res.send({}); + } catch (e) { + console.log(e); + bail(res, e.message); + } + }, + + async deleteApp(req, res) { + try { + const { user } = req; + const uid = user.id; + const { pubkey } = req.body; + const app = await g(pubkey); + if (app && uid !== app.uid) fail("Unauthorized"); + await db.sRem(`${uid}:apps`, pubkey); + await db.del(pubkey); + res.send({}); + } catch (e) { + console.log(e); + bail(res, e.message); + } + }, }; |
