aboutsummaryrefslogtreecommitdiffstats
path: root/routes/square.ts
blob: dc89fd7dd2e3321968e6e55da369722648d79b4a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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/sha2.js";
import { utf8ToBytes } from "@noble/hashes/utils.js";
import { base64urlnopad as base64 } from "@scure/base";
import { SquareClient } from "square";
const { scopes, url, appId, clientSecret: _clientSecret, environment } = config.square;

export default {
  async connect(c) {
    const user = c.get("user");

    if (await db.exists(`${user.id}:square`)) {
      return c.json("connected");
    }

    const codeVerifier = base64.encode(crypto.randomBytes(32) as any);
    await s(`${user.id}:codeVerifier`, codeVerifier);

    const challenge = base64.encode(sha256(utf8ToBytes(codeVerifier)));

    const state = base64.encode(crypto.randomBytes(12) as any);
    const scope = scopes.join("+");

    return c.json(
      `${url}oauth2/authorize?client_id=${appId}&session=false&scope=${scope}&state=${state}&code_challenge=${challenge}`,
    );
  },

  async auth(c) {
    const user = c.get("user");

    const codeVerifier = await g(`${user.id}:codeVerifier`);

    const client = new SquareClient({
      environment,
    });

    const code = c.req.query("code");

    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);
      return c.json({});
    } catch (e) {
      console.log(e);
    }
  },

  async payment(c) {
    try {
      const body = await c.req.json();
      const { data, type, merchant_id } = body;
      const { payment } = data.object;

      if (
        type === "payment.created" &&
        (payment.source_type === "CASH" || payment.source_type === "EXTERNAL")
      ) {
        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,
          prompt: user.prompt,
          type: "lightning",
        };

        await generate({ invoice, user });
      }

      return c.json({});
    } catch (e) {
      return bail(c, e.message);
    }
  },
};