thunder-bridge 0.8.2 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -6
- package/dist/index.cjs +97 -408
- package/dist/index.d.cts +18 -434
- package/dist/index.d.ts +18 -434
- package/dist/index.js +95 -406
- package/dist/rail-QZtUN1D-.d.cts +381 -0
- package/dist/rail-QZtUN1D-.d.ts +381 -0
- package/dist/server.cjs +807 -0
- package/dist/server.d.cts +64 -0
- package/dist/server.d.ts +64 -0
- package/dist/server.js +769 -0
- package/package.json +11 -2
package/README.md
CHANGED
|
@@ -106,7 +106,7 @@ them and this table does not repeat them.
|
|
|
106
106
|
|
|
107
107
|
| Export | What it does |
|
|
108
108
|
|---|---|
|
|
109
|
-
| `lnurlPayEndpoint(config)` | a whole LNURL-pay endpoint as one Fetch handler, so a static QR points at your domain |
|
|
109
|
+
| `lnurlPayEndpoint(config)` | a whole LNURL-pay endpoint as one Fetch handler, so a static QR points at your domain. From `thunder-bridge/server` |
|
|
110
110
|
| `seal(secret, plaintext)`, `unseal` | the blob the gateway stores and cannot read |
|
|
111
111
|
| `toLnurl(url)` | bech32-encode an endpoint url |
|
|
112
112
|
| `bankTransfer(params)` | register a Czech QR platba as a watched payment. Refuses a gateway that serves strangers |
|
|
@@ -127,7 +127,7 @@ whatever runtime you keep state in.
|
|
|
127
127
|
|---|---|
|
|
128
128
|
| `bankRail(config)` | a `Rail` selling for a bank transfer, reading back through any `Statement` |
|
|
129
129
|
| `lightningRail(config)` | a `Rail` where the gateway mints the invoice, so it learns the address and the amount |
|
|
130
|
-
| `blindLightningRail(config)` | a `Rail` that resolves the address itself and tells the gateway only a hash |
|
|
130
|
+
| `blindLightningRail(config)` | a `Rail` that resolves the address itself and tells the gateway only a hash. From `thunder-bridge/server` |
|
|
131
131
|
|
|
132
132
|
`Rail` is `(order: Order) => Promise<Leg>`. Everything that differs between rails
|
|
133
133
|
is bound once when the rail is built, so the only thing passed per sale is which
|
|
@@ -166,7 +166,8 @@ const tipJar = lnurlToSvg("https://agora.gripe/tip");
|
|
|
166
166
|
```
|
|
167
167
|
|
|
168
168
|
**Webhooks** - [`src/webhook.ts`](src/webhook.ts): `parseWebhookRequest`,
|
|
169
|
-
`parseWebhook`, `
|
|
169
|
+
`parseWebhook`, `parseWatchedWebhookRequest`, `parseWatchedWebhook`,
|
|
170
|
+
`verifyWebhookSignature`. See [Webhooks](#webhooks).
|
|
170
171
|
|
|
171
172
|
**Errors** - [`src/errors.ts`](src/errors.ts): `ProblemError`,
|
|
172
173
|
`NoWalletAvailableError`, `GatewayCheatError`, `UnverifiedRecipientError`,
|
|
@@ -225,6 +226,27 @@ such as `nas`, the trailing-dot `localhost.`, and anything whose last label is
|
|
|
225
226
|
|
|
226
227
|
It vets the first hop only. See below.
|
|
227
228
|
|
|
229
|
+
### Which transfer counts as paying
|
|
230
|
+
|
|
231
|
+
`bankVerifyEndpoint` calls a credit a settlement when the amount and the currency
|
|
232
|
+
match exactly and the reference appears anywhere in what the payer wrote,
|
|
233
|
+
case-insensitively. With `fioStatement` "what the payer wrote" is four Fio columns
|
|
234
|
+
joined: the variable symbol, the user identification, the message for the recipient
|
|
235
|
+
and the payer's own reference. So a bank that prefixes, appends, or moves the text
|
|
236
|
+
between those fields still settles.
|
|
237
|
+
|
|
238
|
+
Two shapes do not settle, and both leave the payment `pending` while the money is
|
|
239
|
+
already in the account:
|
|
240
|
+
|
|
241
|
+
- **A shortened reference.** The match asks whether the reference is inside what the
|
|
242
|
+
bank forwarded, not the other way round, so a bank that truncates it never matches.
|
|
243
|
+
- **A payer whose bank forwards nothing but a numeric variable symbol.** The
|
|
244
|
+
reference is alphanumeric and cannot travel in a numeric field, and the match does
|
|
245
|
+
not read `X-VS` as an alternative.
|
|
246
|
+
|
|
247
|
+
Neither has been seen with Fio, which forwards the message untouched. Check it
|
|
248
|
+
against the banks your payers actually use before you promise them a rail.
|
|
249
|
+
|
|
228
250
|
## What is still trusted
|
|
229
251
|
|
|
230
252
|
- **The gateway chooses which of your addresses gets paid.** Nothing here can
|
|
@@ -315,9 +337,9 @@ try {
|
|
|
315
337
|
|
|
316
338
|
## Webhooks
|
|
317
339
|
|
|
318
|
-
Pass `webhookUrl` and optionally `webhookSecret` when you create a payment
|
|
319
|
-
it reaches `paid` the gateway POSTs the same JSON the API returns,
|
|
320
|
-
a `Payment`. Every delivery carries `x-timestamp`, and with a secret set
|
|
340
|
+
Pass `webhookUrl` and optionally `webhookSecret` when you create a payment, or on
|
|
341
|
+
any rail. Once it reaches `paid` the gateway POSTs the same JSON the API returns,
|
|
342
|
+
so the body is a `Payment`. Every delivery carries `x-timestamp`, and with a secret set
|
|
321
343
|
`x-signature: sha256=<hmac>` over `<timestamp>.<body>` rather than the body alone,
|
|
322
344
|
so a captured delivery cannot be replayed at you later. Six attempts on a widening
|
|
323
345
|
backoff, then it parks. An invoice that expires fires nothing.
|
|
@@ -339,6 +361,29 @@ app.post("/hooks/paid", async (context) => {
|
|
|
339
361
|
});
|
|
340
362
|
```
|
|
341
363
|
|
|
364
|
+
### A watched payment sends a different body
|
|
365
|
+
|
|
366
|
+
`bankRail` and `blindLightningRail` register a payment the gateway was told almost
|
|
367
|
+
nothing about, so its webhook carries no address, no amount and no invoice. That is
|
|
368
|
+
not a `Payment`, and `parseWebhook` answers `null` for it, which looks exactly like a
|
|
369
|
+
bad signature. Use `parseWatchedWebhookRequest` there instead and you get a
|
|
370
|
+
`TriggerEvent`, the shape `getWatched` hands back.
|
|
371
|
+
|
|
372
|
+
```ts
|
|
373
|
+
import { parseWatchedWebhookRequest } from "thunder-bridge";
|
|
374
|
+
|
|
375
|
+
app.post("/hooks/bank", async (context) => {
|
|
376
|
+
const settled = await parseWatchedWebhookRequest(context.req.raw, secret);
|
|
377
|
+
if (settled === null) return context.text("bad signature", 401);
|
|
378
|
+
|
|
379
|
+
await fulfil(settled.id, settled.preimage);
|
|
380
|
+
return context.text("ok");
|
|
381
|
+
});
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Give each rail its own path, as above, and neither endpoint has to guess which body
|
|
385
|
+
it was handed.
|
|
386
|
+
|
|
342
387
|
`parseWebhookRequest` refuses anything more than five minutes out of date,
|
|
343
388
|
adjustable with `toleranceSecs`. The signature proves the body came from someone
|
|
344
389
|
holding your secret. It does not prove the payment happened, since the gateway
|