Skip to content

Commit

Permalink
chore: testing with a real card
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicolas Burtey committed Sep 17, 2023
1 parent 4ad04ee commit db15975
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 23 deletions.
4 changes: 4 additions & 0 deletions apps/boltcard/TODO.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- rate limits
- proper link of .gql (instead of copy)
- Tilt setup
- next-apisation?
6 changes: 6 additions & 0 deletions apps/boltcard/bats/e2e-test.bats
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,10 @@ load "../../../test/bats/helpers/ln"

result=$(curl -s "${CALLBACK_URL}?k1=${K1_VALUE}&pr=${payment_request}")
[[ result.status == "OK" ]] || exit 1
}

@test "wipecard" {
"skip"
id=""
curl -s http://localhost:3000/wipeboltcard
}
25 changes: 20 additions & 5 deletions apps/boltcard/callback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,15 @@ boltcardRouter.get("/callback", async (req: express.Request, res: express.Respon
},
})

const data = await graphQLClient.request<GetUsdWalletIdQuery>(getUsdWalletIdQuery)
let data: GetUsdWalletIdQuery
try {
data = await graphQLClient.request<GetUsdWalletIdQuery>(getUsdWalletIdQuery)
} catch (error) {
console.error(error)
res.status(400).send({ status: "ERROR", reason: "issue fetching walletId" })
return
}

const wallets = data.me?.defaultAccount.wallets

if (!wallets) {
Expand All @@ -116,10 +124,17 @@ boltcardRouter.get("/callback", async (req: express.Request, res: express.Respon
return
}

const result = await graphQLClient.request<LnInvoicePaymentSendMutation>({
document: lnInvoicePaymentSendMutation,
variables: { input: { walletId: usdWalletId, paymentRequest: pr } },
})
let result: LnInvoicePaymentSendMutation
try {
result = await graphQLClient.request<LnInvoicePaymentSendMutation>({
document: lnInvoicePaymentSendMutation,
variables: { input: { walletId: usdWalletId, paymentRequest: pr } },
})
} catch (error) {
console.error(error)
res.status(400).send({ status: "ERROR", reason: "payment failed" })
return
}

if (result.lnInvoicePaymentSend.status === "SUCCESS") {
res.json({ status: "OK" })
Expand Down
3 changes: 2 additions & 1 deletion apps/boltcard/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export const serverUrl = process.env.SERVER_URL ?? "http://localhost:3000"

export const apiUrl = process.env.API_URL ?? "http://localhost:4002/graphql"

const AES_DECRYPT_KEY = process.env.AES_DECRYPT_KEY ?? "0c3b25d92b38ae443229dd59ad34b85d"
export const AES_DECRYPT_KEY =
process.env.AES_DECRYPT_KEY ?? "0c3b25d92b38ae443229dd59ad34b85d"

export const aesDecryptKey = Buffer.from(AES_DECRYPT_KEY, "hex")
3 changes: 3 additions & 0 deletions apps/boltcard/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ import { boltcardRouter } from "./router"
import { lnurlw } from "./lnurlw"
import { callback } from "./callback"
import { createboltcard } from "./new"
import { wipe } from "./wipe"

import { createTable } from "./knex"

lnurlw
callback
createboltcard
wipe

await createTable()

Expand Down
2 changes: 1 addition & 1 deletion apps/boltcard/knex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export async function createTable() {
table.string("token").notNullable()

table.string("k0AuthKey").notNullable()
table.string("k2CmacKey").notNullable().index().unique()
table.string("k2CmacKey").notNullable() // .index().unique() enforcing uniqueness would ensure there is no reusage of keys
table.string("k3").notNullable()
table.string("k4").notNullable()
})
Expand Down
3 changes: 3 additions & 0 deletions apps/boltcard/lnurlw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ boltcardRouter.get("/ln", async (req: express.Request, res: express.Response) =>
}
}

// TODO: check walletId and fail if not found
// this would improve the experience of the POS

const k1 = generateSecureRandomString(32)

await insertk1({ k1, cardId: card.id })
Expand Down
34 changes: 18 additions & 16 deletions apps/boltcard/new.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ boltcardRouter.get(
// TODO: token validation?

const oneTimeCode = randomHex()
const k0AuthKey = "0c3b25d92b38ae443229dd59ad34b85d"
const k2CmacKey = "b45775776cb224c75bcde7ca3704e933"
const k0AuthKey = randomHex()
const k2CmacKey = randomHex()
const k3 = randomHex()
const k4 = randomHex()

Expand Down Expand Up @@ -71,13 +71,13 @@ interface NewCardResponse {
PROTOCOL_NAME: string
PROTOCOL_VERSION: number
CARD_NAME: string
LNURLW_BASE: string
K0: string
K1: string
K2: string
K3: string
K4: string
UID_PRIVACY: string
lnurlw_base: string
k0: string
k1: string
k2: string
k3: string
k4: string
uid_privacy: string
}

boltcardRouter.get("/new", async (req: express.Request, res: express.Response) => {
Expand Down Expand Up @@ -113,19 +113,21 @@ boltcardRouter.get("/new", async (req: express.Request, res: express.Response) =
}

const lnurlwBase = `${serverUrl}/ln`
.replace("http://", "lnurlw://")
.replace("https://", "lnurlw://")
const k1DecryptKey = aesDecryptKey.toString("hex")

const response: NewCardResponse = {
PROTOCOL_NAME: "create_bolt_card_response",
PROTOCOL_VERSION: 2,
CARD_NAME: "dummy",
LNURLW_BASE: lnurlwBase,
K0: cardInit.k0AuthKey,
K1: k1DecryptKey,
K2: cardInit.k2CmacKey,
K3: cardInit.k3,
K4: cardInit.k4,
UID_PRIVACY: "Y",
lnurlw_base: lnurlwBase,
k0: cardInit.k0AuthKey,
k1: k1DecryptKey,
k2: cardInit.k2CmacKey,
k3: cardInit.k3,
k4: cardInit.k4,
uid_privacy: "Y",
}

res.status(200).json(response)
Expand Down
59 changes: 59 additions & 0 deletions apps/boltcard/wipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import express from "express"

import { boltcardRouter } from "./router"
import { fetchByCardId, fetchByOneTimeCode } from "./knex"
import { AES_DECRYPT_KEY } from "./config"

boltcardRouter.get(
"/wipeboltcard",
async (req: express.Request, res: express.Response) => {
// should be pass with POST? not sure if this would be compatible
// with the wallet that can create cards
const cardId = req.query.cardId
const oneTimeCode = req.query.a

if (!cardId && !oneTimeCode) {
res.status(400).send({ status: "ERROR", reason: "cardId missing" })
return
}
// TODO authorization

// TODO may be both on CardInit and Card table
let card
if (cardId) {
if (typeof cardId !== "string") {
res.status(400).send({ status: "ERROR", reason: "cardId is not a string" })
return
}

card = await fetchByCardId(cardId)
} else {
if (typeof oneTimeCode !== "string") {
res.status(400).send({ status: "ERROR", reason: "oneTimeCode is not a string" })
return
}

card = await fetchByOneTimeCode(oneTimeCode)
}

if (!card) {
res.status(400).send({ status: "ERROR", reason: "card not found" })
return
}

res.json({
status: "OK",
action: "wipe",
k0: card.k0AuthKey,
k1: AES_DECRYPT_KEY,
k2: card.k2CmacKey,
k3: card.k3,
k4: card.k4,
uid: card.uid,
version: 1,
})
},
)

const wipe = ""
export { wipe }

0 comments on commit db15975

Please sign in to comment.