diff options
| author | Adam Soltys <[email protected]> | 2025-07-17 16:16:56 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2025-07-17 16:16:56 -0700 |
| commit | 8fae698d9ce0f318481ab739a63ea0a580372f86 (patch) | |
| tree | f8be08e1f3c72d39087ed753811f7655787c7dc7 | |
| parent | 161678b774cee184fdb5afcf84686639acb7a5e2 (diff) | |
| download | coinos-server-8fae698d9ce0f318481ab739a63ea0a580372f86.tar.gz coinos-server-8fae698d9ce0f318481ab739a63ea0a580372f86.zip | |
square endpoints
| -rwxr-xr-x | bun.lockb | bin | 209762 -> 232678 bytes | |||
| -rw-r--r-- | index.ts | 6 | ||||
| -rw-r--r-- | package.json | 2 | ||||
| -rw-r--r-- | routes/invoices.ts | 1 | ||||
| -rw-r--r-- | routes/square.ts | 89 |
5 files changed, 96 insertions, 2 deletions
| Binary files differ @@ -19,6 +19,7 @@ import nostr from "$routes/nostr"; import payments from "$routes/payments"; import rates from "$routes/rates"; import shopify from "$routes/shopify"; +import square from "$routes/square"; import users from "$routes/users"; try { @@ -82,8 +83,9 @@ app.post("/replace", auth, payments.replace); app.get("/decode/:bolt11", payments.decode); app.post("/fetchinvoice", payments.fetchinvoice); -app.get("/auth", payments.auth); -app.post("/order", payments.order); +app.get("/square/connect", auth, square.connect); +app.get("/square/auth", auth, square.auth); +app.post("/square/payment", square.payment); app.get("/encode", lnurl.encode); app.get("/decode", lnurl.decode); diff --git a/package.json b/package.json index 8881ff03..9e6de648 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@fastify/static": "^6.5.0", "@fastify/websocket": "^10.0.1", "@noble/hashes": "^1.4.0", + "@scure/base": "^1.2.6", "bech32": "^2.0.0", "buffer-crc32": "^0.2.13", "clightning-client": "github:asoltys/lightning-client-js#master", @@ -45,6 +46,7 @@ "readable-stream-clone": "^0.0.7", "redis": "^4.6.10", "sharp": "^0.33.5", + "square": "^43.0.0", "strfry-rpc": "^0.0.1", "uuid": "8", "web-push": "^3.6.7", diff --git a/routes/invoices.ts b/routes/invoices.ts index ecac713c..6c2f713d 100644 --- a/routes/invoices.ts +++ b/routes/invoices.ts @@ -28,6 +28,7 @@ export default { if (body.user) user = body.user; if (req.user.username === user.username) invoice.own = true; + else invoice.own = false; try { const result = await generate({ invoice, user }); diff --git a/routes/square.ts b/routes/square.ts new file mode 100644 index 00000000..f7902e11 --- /dev/null +++ b/routes/square.ts @@ -0,0 +1,89 @@ +import * as crypto from "crypto"; +import config from "$config"; +import { db, g, s } from "$lib/db"; +import { generate } from "$lib/invoices"; +import { SATS, bail, getUser } from "$lib/utils"; +import { sha256 } from "@noble/hashes/sha256"; +import { utf8ToBytes } from "@noble/hashes/utils"; +import { base64urlnopad as base64 } from "@scure/base"; +import { SquareClient } from "square"; + +const { scopes, url, appId, environment } = config.square; + +export default { + async connect(req, res) { + const { user } = req; + + if (await db.exists(`${user.id}:square`)) { + return res.send("connected"); + } + + const codeVerifier = base64.encode(crypto.randomBytes(32)); + await s(`${user.id}:codeVerifier`, codeVerifier); + + const challenge = base64.encode(sha256(utf8ToBytes(codeVerifier))); + + const state = base64.encode(crypto.randomBytes(12)); + const scope = scopes.join("+"); + + res.send( + `${url}oauth2/authorize?client_id=${appId}&session=false&scope=${scope}&state=${state}&code_challenge=${challenge}`, + ); + }, + + async auth(req, res) { + const { user } = req; + + const codeVerifier = await g(`${user.id}:codeVerifier`); + + const client = new SquareClient({ + environment, + }); + + const { code } = req.query; + + try { + const result = await client.oAuth.obtainToken({ + code, + clientId: appId, + grantType: "authorization_code", + codeVerifier, + }); + + await s(`${user.id}:square`, result); + await s(result.merchantId, user.id); + res.send({}); + } catch (e) { + console.log(e); + } + }, + + async payment(req, res) { + try { + const { body } = req; + const { data, type, merchant_id } = body; + const { payment } = data.object; + + if (type === "payment.created" && payment.source_type === "CASH") { + const { + amount_money: { amount, currency }, + } = payment; + const rates = await g("rates"); + const rate = rates[currency]; + const uid = await g(merchant_id); + const user = await getUser(uid); + const invoice = { + amount: Math.round(((amount / 100) * SATS) / rate), + own: true, + type: "lightning", + }; + + await generate({ invoice, user }); + } + + res.send({}); + } catch (e) { + bail(res, e.message); + } + }, +}; |
