thunder-bridge 1.5.0 → 2.1.1
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 +11 -9
- package/dist/{client-CzGZcByI.d.cts → bank-CEIuNhV_.d.cts} +191 -28
- package/dist/{client-Cc5gtjGV.d.ts → bank-M8flcMks.d.ts} +191 -28
- package/dist/bank.cjs +197 -0
- package/dist/bank.d.cts +4 -2
- package/dist/bank.d.ts +4 -2
- package/dist/bank.js +196 -0
- package/dist/{errors-Dmh-Uoh8.d.cts → errors-DriqW-lp.d.cts} +2 -2
- package/dist/{errors-0vbVoISA.d.ts → errors-ZEUT-MhO.d.ts} +2 -2
- package/dist/index.cjs +701 -310
- package/dist/index.d.cts +10 -10
- package/dist/index.d.ts +10 -10
- package/dist/index.js +701 -310
- package/dist/nwc.cjs +115 -31
- package/dist/nwc.d.cts +6 -4
- package/dist/nwc.d.ts +6 -4
- package/dist/nwc.js +112 -28
- package/dist/price.d.cts +2 -2
- package/dist/price.d.ts +2 -2
- package/dist/qr.cjs +20 -23
- package/dist/qr.js +20 -23
- package/dist/{types-BNPmVnA7.d.cts → types-DYZ9EkmJ.d.cts} +11 -2
- package/dist/{types-BNPmVnA7.d.ts → types-DYZ9EkmJ.d.ts} +11 -2
- package/openapi.yaml +29 -39
- package/package.json +1 -1
- package/dist/bank-B3mHISn1.d.cts +0 -92
- package/dist/bank-B3mHISn1.d.ts +0 -92
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { R as Resolved, Q as QrOptions } from './qr-CF-YeXU1.js';
|
|
2
|
-
import { A as Amount, T as Ticker, C as Charge,
|
|
3
|
-
import { a as BankTransferParams, B as BankTransfer, b as BankVerifyConfig } from './bank-B3mHISn1.js';
|
|
2
|
+
import { A as Amount, T as Ticker, C as Charge, f as MintedPayment, h as PaymentStatus, i as Priced, g as Msat, S as Settlement, P as Payment, Q as Quote, e as Held, H as Handover, j as SocketTicket } from './types-DYZ9EkmJ.js';
|
|
4
3
|
|
|
5
4
|
type Sent = {
|
|
6
5
|
method?: string;
|
|
7
6
|
headers?: Record<string, string>;
|
|
8
7
|
body?: string;
|
|
9
8
|
deadline?: AbortSignal;
|
|
9
|
+
staysOnOrigin?: boolean;
|
|
10
10
|
};
|
|
11
11
|
type Verified = {
|
|
12
12
|
address: string;
|
|
@@ -26,8 +26,9 @@ interface Order {
|
|
|
26
26
|
}
|
|
27
27
|
/** One way to pay one order, already registered with the gateway */
|
|
28
28
|
interface Leg {
|
|
29
|
-
/** The watched payment's id, which is what `firstSettled`, `payment` and `settled` take */
|
|
29
|
+
/** The watched payment's id, which with `paymentHash` is what `firstSettled`, `payment` and `settled` take */
|
|
30
30
|
id: string;
|
|
31
|
+
paymentHash: string;
|
|
31
32
|
/** Which rail made it, so a shop can label a leg without knowing how it was built */
|
|
32
33
|
rail: string;
|
|
33
34
|
/** What the payer reads, a BOLT11 invoice or a Short Payment Descriptor */
|
|
@@ -69,10 +70,13 @@ interface LightningRailConfig extends RailConfig {
|
|
|
69
70
|
/** The same rail with the invoice resolved here, so the gateway is told neither address nor amount */
|
|
70
71
|
interface BlindLightningRailConfig extends LightningRailConfig {
|
|
71
72
|
/**
|
|
72
|
-
* What the watcher needs and the gateway must not read, sealed
|
|
73
|
-
* before it goes anywhere near the gateway
|
|
73
|
+
* What the watcher needs and the gateway must not read, sealed under `secret`
|
|
74
|
+
* for the invoice's payment hash before it goes anywhere near the gateway
|
|
74
75
|
*/
|
|
75
|
-
sealed?:
|
|
76
|
+
sealed?: {
|
|
77
|
+
secret: string;
|
|
78
|
+
data: (order: Order) => unknown;
|
|
79
|
+
};
|
|
76
80
|
/**
|
|
77
81
|
* Where your own `serve.verify` endpoint is mounted, and its secret. Without
|
|
78
82
|
* it the gateway is handed the wallet's own URL, which a gateway enforcing its
|
|
@@ -96,12 +100,15 @@ interface BankRailConfig extends RailConfig {
|
|
|
96
100
|
/** When this leg stops being payable, in unix seconds */
|
|
97
101
|
expiresAt: (order: Order) => number;
|
|
98
102
|
/** Sealed before the gateway sees it, the way the blind Lightning rail does */
|
|
99
|
-
sealed?:
|
|
103
|
+
sealed?: {
|
|
104
|
+
secret: string;
|
|
105
|
+
data: (order: Order) => unknown;
|
|
106
|
+
};
|
|
100
107
|
/** The Czech variable symbol, taken off the reference's digits by default */
|
|
101
108
|
variableSymbol?: (order: Order) => string | undefined;
|
|
102
109
|
/**
|
|
103
|
-
* Register on a gateway you do not own anyway. The verify URL names
|
|
104
|
-
*
|
|
110
|
+
* Register on a gateway you do not own anyway. The sealed verify URL names
|
|
111
|
+
* nothing about the order, but its operator still learns every watch you place
|
|
105
112
|
*/
|
|
106
113
|
allowPublicGateway?: boolean;
|
|
107
114
|
}
|
|
@@ -180,7 +187,7 @@ interface PaymentRequest {
|
|
|
180
187
|
* unpaid or the wait is aborted. It follows a WebSocket and reconnects through
|
|
181
188
|
* a drop, so this is one await rather than a poll.
|
|
182
189
|
*
|
|
183
|
-
* `gateway.settled(
|
|
190
|
+
* `gateway.settled(payment)` is the wider question and ends on an expiry too. This
|
|
184
191
|
* one is about the payment that was asked for, and one that expired was never paid
|
|
185
192
|
*/
|
|
186
193
|
paid(options?: WaitOptions): Promise<MintedPayment>;
|
|
@@ -335,7 +342,7 @@ interface WrapAllowance {
|
|
|
335
342
|
* Throws `GatewayCheatError` when a check fails and `UnverifiedRecipientError`
|
|
336
343
|
* when the recipient could not be reached to run one
|
|
337
344
|
*/
|
|
338
|
-
declare function proveOrigin(payment: MintedPayment, asked: Priced): Promise<void>;
|
|
345
|
+
declare function proveOrigin(payment: MintedPayment, asked: Priced, askedAt?: number): Promise<void>;
|
|
339
346
|
/**
|
|
340
347
|
* Prove the money arrived by asking the recipient's own server, not the gateway,
|
|
341
348
|
* returns the preimage when the recipient says it settled and null when it says
|
|
@@ -429,9 +436,9 @@ interface WebhookHandlers {
|
|
|
429
436
|
*/
|
|
430
437
|
onSettled?: (settlement: Proven<Settlement>) => void | Promise<void>;
|
|
431
438
|
/**
|
|
432
|
-
* A delivery that carries no proof, so an expiry
|
|
433
|
-
*
|
|
434
|
-
*
|
|
439
|
+
* A delivery that carries no proof, so an expiry. Left unset, the handler
|
|
440
|
+
* answers `202` and does nothing, because acting on an unproven claim is the
|
|
441
|
+
* one thing this refuses to do
|
|
435
442
|
*/
|
|
436
443
|
onUnproven?: (settlement: Settlement) => void | Promise<void>;
|
|
437
444
|
/** A whole payment rather than a settlement, which is what an older gateway posts */
|
|
@@ -492,14 +499,8 @@ declare class Serve {
|
|
|
492
499
|
private credential;
|
|
493
500
|
}
|
|
494
501
|
|
|
495
|
-
/** How this instance talks to one gateway
|
|
502
|
+
/** How this instance talks to one gateway */
|
|
496
503
|
interface ThunderBridgeOptions {
|
|
497
|
-
/**
|
|
498
|
-
* Prove every payment against the recipient's own server before handing it
|
|
499
|
-
* back, and refuse a reported settlement whose preimage does not hash to the
|
|
500
|
-
* payment hash, defaults to true
|
|
501
|
-
*/
|
|
502
|
-
verify?: boolean;
|
|
503
504
|
/**
|
|
504
505
|
* Sent as `Authorization: Bearer`, which a gateway started with
|
|
505
506
|
* `GATEWAY_TOKEN` requires on every call, the socket handshake included. No
|
|
@@ -521,7 +522,7 @@ interface WaitOptions {
|
|
|
521
522
|
signal?: AbortSignal;
|
|
522
523
|
/**
|
|
523
524
|
* Mint a short-lived ticket and put that in the socket URL instead of the
|
|
524
|
-
* payment id. Implied by `token`. The id stays readable inside the ticket,
|
|
525
|
+
* payment id. Implied by `token` and by `secret`. The id stays readable inside the ticket,
|
|
525
526
|
* what changes is that a URL out of a log stops opening anything after a
|
|
526
527
|
* minute
|
|
527
528
|
*/
|
|
@@ -584,17 +585,32 @@ interface FollowOptions {
|
|
|
584
585
|
/**
|
|
585
586
|
* Mint a short-lived ticket and put that in the socket URL instead of the
|
|
586
587
|
* secret, one per connection. Keeps the secret out of access logs, at the cost
|
|
587
|
-
* of a POST before each connect. Implied by `token`. Leave it off for a
|
|
588
|
+
* of a POST before each connect. Implied by `token` and by `secret`. Leave it off for a
|
|
588
589
|
* microcontroller, where one hardcoded URL and a dumb reconnect loop is the
|
|
589
590
|
* whole point
|
|
590
591
|
*/
|
|
591
592
|
tickets?: boolean;
|
|
592
593
|
}
|
|
594
|
+
/** How this caller holds a socket open and what it answers on it */
|
|
595
|
+
interface AttendOptions {
|
|
596
|
+
/**
|
|
597
|
+
* What this caller answers when the gateway asks about one of its payments.
|
|
598
|
+
* The preimage when the money is there, null while it is not, and the gateway
|
|
599
|
+
* checks the preimage against the hash either way
|
|
600
|
+
*/
|
|
601
|
+
answer: (paymentHash: string) => Promise<string | null> | string | null;
|
|
602
|
+
/** Called when a connection drops or a frame is refused, the socket keeps going */
|
|
603
|
+
onError?: (error: unknown) => void;
|
|
604
|
+
/** Reconnect after a drop, defaults to true */
|
|
605
|
+
reconnect?: boolean;
|
|
606
|
+
/** The first wait after a drop, doubling and jittered, defaults to 3000 */
|
|
607
|
+
reconnectDelayMs?: number;
|
|
608
|
+
}
|
|
593
609
|
/** Talks to a Thunder Bridge gateway and trusts it for nothing it can check itself */
|
|
594
610
|
declare class ThunderBridge {
|
|
595
611
|
private readonly baseUrl;
|
|
596
|
-
private readonly verify;
|
|
597
612
|
private readonly token;
|
|
613
|
+
private readonly handedOut;
|
|
598
614
|
private readonly secret;
|
|
599
615
|
private strangers;
|
|
600
616
|
private speaks;
|
|
@@ -651,7 +667,7 @@ declare class ThunderBridge {
|
|
|
651
667
|
* for both sorts: `kind` says whether the gateway minted it or was handed it,
|
|
652
668
|
* and the address, amount and invoice are null on one it was never told
|
|
653
669
|
*/
|
|
654
|
-
payment(
|
|
670
|
+
payment(held: Held): Promise<Payment | null>;
|
|
655
671
|
/**
|
|
656
672
|
* List what this gateway is watching, newest first. Only a gateway started
|
|
657
673
|
* with `GATEWAY_TOKEN` serves this, because on a shared one it would hand
|
|
@@ -671,7 +687,7 @@ declare class ThunderBridge {
|
|
|
671
687
|
* one that has answered is followed until its own expiry, so the wait always
|
|
672
688
|
* ends by itself
|
|
673
689
|
*/
|
|
674
|
-
settled(
|
|
690
|
+
settled(held: Held, options?: WaitOptions): Promise<Payment>;
|
|
675
691
|
private followed;
|
|
676
692
|
/**
|
|
677
693
|
* Wait on several payments and keep the first one that is really paid, then stop
|
|
@@ -691,7 +707,7 @@ declare class ThunderBridge {
|
|
|
691
707
|
* really does pay twice and that shows up on `follow` as a second settlement to
|
|
692
708
|
* refund.
|
|
693
709
|
*/
|
|
694
|
-
firstSettled(
|
|
710
|
+
firstSettled(held: Held[], options?: WaitOptions): Promise<Payment | null>;
|
|
695
711
|
/**
|
|
696
712
|
* Hand over an invoice you obtained yourself so the gateway watches it without
|
|
697
713
|
* being told the address or the amount. It can then only refuse everyone
|
|
@@ -707,6 +723,12 @@ declare class ThunderBridge {
|
|
|
707
723
|
* because then the gateway names the payment and only it can
|
|
708
724
|
*/
|
|
709
725
|
nameFor(paymentHash: string): Promise<string | null>;
|
|
726
|
+
/**
|
|
727
|
+
* Hold a socket open and answer what the gateway asks about this caller's own
|
|
728
|
+
* payments, so a watch addressed to this caller settles without anybody
|
|
729
|
+
* hosting a URL. Reconnects on its own until the returned function is called
|
|
730
|
+
*/
|
|
731
|
+
attend(options: AttendOptions): () => void;
|
|
710
732
|
/**
|
|
711
733
|
* Follow every payment made to one trigger, replayed from the recent ones on
|
|
712
734
|
* connect and then live, reconnecting on its own until the returned function
|
|
@@ -727,7 +749,148 @@ declare class ThunderBridge {
|
|
|
727
749
|
private sending;
|
|
728
750
|
private reading;
|
|
729
751
|
private speaking;
|
|
752
|
+
private handOut;
|
|
730
753
|
private proven;
|
|
731
754
|
}
|
|
732
755
|
|
|
733
|
-
|
|
756
|
+
/** One incoming payment as the bank booked it, in the smallest unit of its currency */
|
|
757
|
+
interface Credit {
|
|
758
|
+
amountMinor: number;
|
|
759
|
+
currency: string;
|
|
760
|
+
/** Whatever the payer wrote, wherever this bank puts it. Matching is a whole word, so noise around it is fine */
|
|
761
|
+
reference: string;
|
|
762
|
+
/**
|
|
763
|
+
* Unix seconds. A bank that books a day rather than an instant, as Fio does,
|
|
764
|
+
* gives the day's midnight in its own zone, so rendering this in UTC can show
|
|
765
|
+
* the day before. Nothing here matches on it, it is yours to read
|
|
766
|
+
*/
|
|
767
|
+
bookedAt: number;
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Recent credits on one account, oldest or newest first, it makes no difference.
|
|
771
|
+
* This is the whole plugin seam: a bank is a function of this shape, and
|
|
772
|
+
* `fioStatement` is one implementation of it
|
|
773
|
+
*/
|
|
774
|
+
type Statement = (sinceUnix: number) => Promise<Credit[]>;
|
|
775
|
+
/** One transfer to ask for: what is owed, where it lands, and where its arrival is read back from */
|
|
776
|
+
interface BankTransferParams {
|
|
777
|
+
/**
|
|
778
|
+
* Long lived and server side, at least 32 characters. The preimage is derived
|
|
779
|
+
* from it and the verify query is sealed with it, so losing it loses every proof
|
|
780
|
+
*/
|
|
781
|
+
secret: string;
|
|
782
|
+
/** What the payer must leave on the transfer, an order id or a nonce. It is matched, not stored */
|
|
783
|
+
reference: string;
|
|
784
|
+
/** The price in the smallest unit, so 48055 is 480.55 CZK */
|
|
785
|
+
amountMinor: number;
|
|
786
|
+
/** The account the money goes to, as an IBAN */
|
|
787
|
+
iban: string;
|
|
788
|
+
/**
|
|
789
|
+
* Where `bankVerifyEndpoint` is mounted, a public https URL with no query of
|
|
790
|
+
* its own. Not needed when `answerBy` is "agent", because then nothing is polled
|
|
791
|
+
*/
|
|
792
|
+
verifyUrl?: string;
|
|
793
|
+
/**
|
|
794
|
+
* How the gateway gets its answer. "poll" hands it a URL it fetches, which
|
|
795
|
+
* needs a public host. "agent" hands it this caller's name instead, and the
|
|
796
|
+
* socket `bankAgent` holds open answers for it, which needs no host at all
|
|
797
|
+
*/
|
|
798
|
+
answerBy?: "poll" | "agent";
|
|
799
|
+
/** When the offer dies, in unix seconds. Money in a bank moves on banking days, so give it days */
|
|
800
|
+
expiresAt: number;
|
|
801
|
+
/** Defaults to CZK */
|
|
802
|
+
currency?: string;
|
|
803
|
+
/** Up to ten digits, for accounting systems that still want one */
|
|
804
|
+
variableSymbol?: string;
|
|
805
|
+
/**
|
|
806
|
+
* Groups this transfer with everything else paid to the same secret, so one
|
|
807
|
+
* `followTrigger` socket hears about it. Give the Lightning leg of the same
|
|
808
|
+
* order the same secret and both rails arrive on one stream
|
|
809
|
+
*/
|
|
810
|
+
trigger?: string;
|
|
811
|
+
/** How many settlements of that trigger the gateway keeps replayable past the hour, needs `trigger` */
|
|
812
|
+
replay?: number;
|
|
813
|
+
/**
|
|
814
|
+
* Handed back on that stream, so a watcher learns which order settled without
|
|
815
|
+
* asking anyone. It is sealed under `secret` for this transfer's payment hash,
|
|
816
|
+
* so the gateway can neither read it nor move it onto another payment
|
|
817
|
+
*/
|
|
818
|
+
sealed?: {
|
|
819
|
+
secret: string;
|
|
820
|
+
data: unknown;
|
|
821
|
+
};
|
|
822
|
+
/**
|
|
823
|
+
* Where the gateway posts once the money lands, a public https URL. Without one
|
|
824
|
+
* a transfer is only ever learned by following the trigger or asking
|
|
825
|
+
*/
|
|
826
|
+
webhookUrl?: string;
|
|
827
|
+
/**
|
|
828
|
+
* Register on a gateway you do not own anyway. The sealed verify URL tells its
|
|
829
|
+
* operator nothing about the order, but the URL itself still answers whether
|
|
830
|
+
* that order was paid. Say true only when that much is not worth hiding
|
|
831
|
+
*/
|
|
832
|
+
allowPublicGateway?: boolean;
|
|
833
|
+
}
|
|
834
|
+
/** A transfer the gateway is now watching, and the descriptor the payer scans */
|
|
835
|
+
interface BankTransfer {
|
|
836
|
+
/** The watched payment's id at the gateway, which is how you read this order back */
|
|
837
|
+
id: string;
|
|
838
|
+
/** What the gateway was given, and what the preimage has to hash to */
|
|
839
|
+
paymentHash: string;
|
|
840
|
+
/** The same URL you mounted, carrying what to look for and a signature over it */
|
|
841
|
+
verifyUrl: string;
|
|
842
|
+
/** The payer scans this, it is a Short Payment Descriptor, the Czech QR platba format */
|
|
843
|
+
spd: string;
|
|
844
|
+
}
|
|
845
|
+
/** The endpoint the gateway polls for a bank transfer, answering off your own statement */
|
|
846
|
+
interface BankVerifyConfig {
|
|
847
|
+
/** The same secret `bankTransfer` was given */
|
|
848
|
+
secret: string;
|
|
849
|
+
/** The IBAN this endpoint answers for, refusing a question sealed for another account */
|
|
850
|
+
iban: string;
|
|
851
|
+
/** The account to read */
|
|
852
|
+
statement: Statement;
|
|
853
|
+
/** How far back a credit still counts, seven days by default */
|
|
854
|
+
lookBackSecs?: number;
|
|
855
|
+
/**
|
|
856
|
+
* How often you want the gateway to ask, in seconds. It goes out as
|
|
857
|
+
* `Cache-Control: max-age`, so the pace is yours to set rather than the
|
|
858
|
+
* gateway's, and a bank that updates once a minute should say so instead of
|
|
859
|
+
* being polled every few seconds. Thirty by default, clamped to an hour
|
|
860
|
+
*/
|
|
861
|
+
pollEverySecs?: number;
|
|
862
|
+
}
|
|
863
|
+
/** One order this caller is waiting on, and the account it is waiting on it in */
|
|
864
|
+
interface BankOrder {
|
|
865
|
+
iban: string;
|
|
866
|
+
reference: string;
|
|
867
|
+
amountMinor: number;
|
|
868
|
+
currency?: string;
|
|
869
|
+
expiresAt: number;
|
|
870
|
+
statement: Statement;
|
|
871
|
+
}
|
|
872
|
+
/** What a caller needs to answer for its own transfers over a socket */
|
|
873
|
+
interface BankAgentConfig {
|
|
874
|
+
/** The gateway holding the watches this caller raised */
|
|
875
|
+
gateway: ThunderBridge;
|
|
876
|
+
/** The same secret `bankTransfer` was given, never leaving this device */
|
|
877
|
+
secret: string;
|
|
878
|
+
/** What the payment the gateway is asking about was asking for, or null when it is none of ours */
|
|
879
|
+
orders: (paymentHash: string) => Promise<BankOrder | null> | BankOrder | null;
|
|
880
|
+
/** How far back a credit still counts, seven days by default */
|
|
881
|
+
lookBackSecs?: number;
|
|
882
|
+
/** Called when a connection drops or a frame is refused, the socket keeps going */
|
|
883
|
+
onError?: (error: unknown) => void;
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Answer the gateway over a socket this device opens, so a transfer addressed to
|
|
887
|
+
* this caller settles from a till behind NAT, a browser tab or a phone. The
|
|
888
|
+
* preimage is derived here from the secret, so the gateway is told only that one
|
|
889
|
+
* exists and can check it against the hash it already holds.
|
|
890
|
+
*
|
|
891
|
+
* Call the returned function to stop attending. Whatever is still open is asked
|
|
892
|
+
* again on the gateway's own schedule, so leaving and coming back loses nothing
|
|
893
|
+
*/
|
|
894
|
+
declare function bankAgent(config: BankAgentConfig): () => void;
|
|
895
|
+
|
|
896
|
+
export { type AttendOptions as A, type BankAgentConfig as B, type Credit as C, type WebhookOptions as D, type WrapAllowance as E, type FollowOptions as F, answerVerifyChallenge as G, type Handler as H, carriesProof as I, invoiceFrom as J, proveOrigin as K, type Leg as L, type Minted as M, proveSettlement as N, type Order as O, type PaymentRequest as P, proveWrapped as Q, type RailConfig as R, type Statement as S, ThunderBridge as T, relayedVerifyUrl as U, wrapFeeCeiling as V, type WaitOptions as W, type BankOrder as a, type BankTransfer as b, type BankTransferParams as c, type BankVerifyConfig as d, bankAgent as e, type Rail as f, type ThunderBridgeOptions as g, type BankRailConfig as h, type BlindLightningRailConfig as i, type CreateOptions as j, type LightningRailConfig as k, type LightningVerifyConfig as l, type PaymentRequestInit as m, type PaymentRequestOptions as n, type Provable as o, type Proven as p, Rails as q, type Range as r, type Relayed as s, type Send as t, Serve as u, type TicketOptions as v, type TriggerConfig as w, type WatchTicketConfig as x, type WebhookCredential as y, type WebhookHandlers as z };
|
package/dist/bank.cjs
CHANGED
|
@@ -20,10 +20,206 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/entry/bank.ts
|
|
21
21
|
var bank_exports = {};
|
|
22
22
|
__export(bank_exports, {
|
|
23
|
+
bankAgent: () => bankAgent,
|
|
23
24
|
fioStatement: () => fioStatement
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(bank_exports);
|
|
26
27
|
|
|
28
|
+
// ../core/bytes.ts
|
|
29
|
+
function bytesToHex(bytes) {
|
|
30
|
+
let hex = "";
|
|
31
|
+
for (const byte of bytes) {
|
|
32
|
+
hex += byte.toString(16).padStart(2, "0");
|
|
33
|
+
}
|
|
34
|
+
return hex;
|
|
35
|
+
}
|
|
36
|
+
function hexToBytes(hex) {
|
|
37
|
+
const bytes = new Uint8Array(hex.length >> 1);
|
|
38
|
+
for (let at = 0; at < bytes.length; at++) {
|
|
39
|
+
bytes[at] = parseInt(hex.slice(at * 2, at * 2 + 2), 16);
|
|
40
|
+
}
|
|
41
|
+
return bytes;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ../core/ed25519.ts
|
|
45
|
+
var PKCS8_HEADER = hexToBytes("302e020100300506032b657004220420");
|
|
46
|
+
var SMALL_ORDER = [
|
|
47
|
+
"00".repeat(32),
|
|
48
|
+
`01${"00".repeat(31)}`,
|
|
49
|
+
"26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05",
|
|
50
|
+
"c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a",
|
|
51
|
+
`ec${"ff".repeat(30)}7f`,
|
|
52
|
+
`ed${"ff".repeat(30)}7f`,
|
|
53
|
+
`ee${"ff".repeat(30)}7f`
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
// ../core/hmac.ts
|
|
57
|
+
async function hmacHex(secret, payload) {
|
|
58
|
+
const raw = typeof secret === "string" ? new TextEncoder().encode(secret) : secret;
|
|
59
|
+
const key = await crypto.subtle.importKey(
|
|
60
|
+
"raw",
|
|
61
|
+
asBuffer(raw),
|
|
62
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
63
|
+
false,
|
|
64
|
+
["sign"]
|
|
65
|
+
);
|
|
66
|
+
const message = typeof payload === "string" ? new TextEncoder().encode(payload) : payload;
|
|
67
|
+
return bytesToHex(new Uint8Array(await crypto.subtle.sign("HMAC", key, asBuffer(message))));
|
|
68
|
+
}
|
|
69
|
+
function asBuffer(bytes) {
|
|
70
|
+
return bytes instanceof Uint8Array && bytes.buffer instanceof ArrayBuffer ? bytes : new Uint8Array(bytes);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ../core/sha256.ts
|
|
74
|
+
var ROUND_CONSTANTS = new Uint32Array([
|
|
75
|
+
1116352408,
|
|
76
|
+
1899447441,
|
|
77
|
+
3049323471,
|
|
78
|
+
3921009573,
|
|
79
|
+
961987163,
|
|
80
|
+
1508970993,
|
|
81
|
+
2453635748,
|
|
82
|
+
2870763221,
|
|
83
|
+
3624381080,
|
|
84
|
+
310598401,
|
|
85
|
+
607225278,
|
|
86
|
+
1426881987,
|
|
87
|
+
1925078388,
|
|
88
|
+
2162078206,
|
|
89
|
+
2614888103,
|
|
90
|
+
3248222580,
|
|
91
|
+
3835390401,
|
|
92
|
+
4022224774,
|
|
93
|
+
264347078,
|
|
94
|
+
604807628,
|
|
95
|
+
770255983,
|
|
96
|
+
1249150122,
|
|
97
|
+
1555081692,
|
|
98
|
+
1996064986,
|
|
99
|
+
2554220882,
|
|
100
|
+
2821834349,
|
|
101
|
+
2952996808,
|
|
102
|
+
3210313671,
|
|
103
|
+
3336571891,
|
|
104
|
+
3584528711,
|
|
105
|
+
113926993,
|
|
106
|
+
338241895,
|
|
107
|
+
666307205,
|
|
108
|
+
773529912,
|
|
109
|
+
1294757372,
|
|
110
|
+
1396182291,
|
|
111
|
+
1695183700,
|
|
112
|
+
1986661051,
|
|
113
|
+
2177026350,
|
|
114
|
+
2456956037,
|
|
115
|
+
2730485921,
|
|
116
|
+
2820302411,
|
|
117
|
+
3259730800,
|
|
118
|
+
3345764771,
|
|
119
|
+
3516065817,
|
|
120
|
+
3600352804,
|
|
121
|
+
4094571909,
|
|
122
|
+
275423344,
|
|
123
|
+
430227734,
|
|
124
|
+
506948616,
|
|
125
|
+
659060556,
|
|
126
|
+
883997877,
|
|
127
|
+
958139571,
|
|
128
|
+
1322822218,
|
|
129
|
+
1537002063,
|
|
130
|
+
1747873779,
|
|
131
|
+
1955562222,
|
|
132
|
+
2024104815,
|
|
133
|
+
2227730452,
|
|
134
|
+
2361852424,
|
|
135
|
+
2428436474,
|
|
136
|
+
2756734187,
|
|
137
|
+
3204031479,
|
|
138
|
+
3329325298
|
|
139
|
+
]);
|
|
140
|
+
var INITIAL_STATE = new Uint32Array([
|
|
141
|
+
1779033703,
|
|
142
|
+
3144134277,
|
|
143
|
+
1013904242,
|
|
144
|
+
2773480762,
|
|
145
|
+
1359893119,
|
|
146
|
+
2600822924,
|
|
147
|
+
528734635,
|
|
148
|
+
1541459225
|
|
149
|
+
]);
|
|
150
|
+
|
|
151
|
+
// ../core/sealed.ts
|
|
152
|
+
var MIN_SECRET_CHARS = 32;
|
|
153
|
+
var INFO = new TextEncoder().encode("thunder-bridge/sealed");
|
|
154
|
+
function refuseAWeakSecret(secret) {
|
|
155
|
+
if (secret.length < MIN_SECRET_CHARS) {
|
|
156
|
+
throw new Error(`the sealing secret needs ${MIN_SECRET_CHARS} characters of randomness`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/bank.ts
|
|
161
|
+
var DEFAULT_CURRENCY = "CZK";
|
|
162
|
+
var DEFAULT_LOOK_BACK_SECS = 7 * 24 * 60 * 60;
|
|
163
|
+
function bankAgent(config) {
|
|
164
|
+
refuseAWeakSecret(config.secret);
|
|
165
|
+
return config.gateway.attend({
|
|
166
|
+
onError: config.onError,
|
|
167
|
+
answer: async (paymentHash) => {
|
|
168
|
+
const order = await config.orders(paymentHash);
|
|
169
|
+
if (order === null) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
const currency = order.currency ?? DEFAULT_CURRENCY;
|
|
173
|
+
return await creditedPreimage({
|
|
174
|
+
secret: config.secret,
|
|
175
|
+
asked: {
|
|
176
|
+
iban: accountOf(order.iban),
|
|
177
|
+
reference: order.reference,
|
|
178
|
+
amountMinor: order.amountMinor,
|
|
179
|
+
currency,
|
|
180
|
+
expiresAt: order.expiresAt
|
|
181
|
+
},
|
|
182
|
+
statement: order.statement,
|
|
183
|
+
lookBackSecs: config.lookBackSecs
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
async function creditedPreimage(params) {
|
|
189
|
+
const since = unixNow() - (params.lookBackSecs ?? DEFAULT_LOOK_BACK_SECS);
|
|
190
|
+
const landed = (await params.statement(since)).some((credit) => pays(credit, params.asked));
|
|
191
|
+
if (!landed) {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
return await hmacHex(params.secret, `preimage|${subjectOf(params.asked)}`);
|
|
195
|
+
}
|
|
196
|
+
function pays(credit, asked) {
|
|
197
|
+
return credit.amountMinor === asked.amountMinor && credit.currency.toUpperCase() === asked.currency.toUpperCase() && namesOnly(credit.reference, asked.reference);
|
|
198
|
+
}
|
|
199
|
+
function namesOnly(written, reference) {
|
|
200
|
+
const wanted = reference.toUpperCase();
|
|
201
|
+
const alike = [...written.toUpperCase().matchAll(wordsShapedLike(wanted))].map(([word]) => word);
|
|
202
|
+
return alike.includes(wanted) && (!/\d/.test(wanted) || alike.every((word) => word === wanted));
|
|
203
|
+
}
|
|
204
|
+
function wordsShapedLike(reference) {
|
|
205
|
+
const shape = [...reference].map((char) => {
|
|
206
|
+
if (/\d/.test(char)) {
|
|
207
|
+
return "\\d";
|
|
208
|
+
}
|
|
209
|
+
return /\p{L}/u.test(char) ? "\\p{L}" : char.replace(/[\^$\\.*+?()[\]{}|/]/g, "\\$&");
|
|
210
|
+
}).join("");
|
|
211
|
+
return new RegExp(`(?<![\\p{L}\\p{N}])${shape}(?![\\p{L}\\p{N}])`, "gu");
|
|
212
|
+
}
|
|
213
|
+
function subjectOf({ iban, amountMinor, currency, expiresAt, reference }) {
|
|
214
|
+
return `${iban}|${amountMinor}|${currency.toUpperCase()}|${expiresAt}|${reference}`;
|
|
215
|
+
}
|
|
216
|
+
function accountOf(iban) {
|
|
217
|
+
return iban.replace(/\s+/g, "").toUpperCase();
|
|
218
|
+
}
|
|
219
|
+
function unixNow() {
|
|
220
|
+
return Math.floor(Date.now() / 1e3);
|
|
221
|
+
}
|
|
222
|
+
|
|
27
223
|
// src/fio.ts
|
|
28
224
|
var BASE_URL = "https://fioapi.fio.cz/v1/rest";
|
|
29
225
|
var MINOR_UNITS = 100;
|
|
@@ -137,5 +333,6 @@ function asDate(unix) {
|
|
|
137
333
|
}
|
|
138
334
|
// Annotate the CommonJS export names for ESM import in node:
|
|
139
335
|
0 && (module.exports = {
|
|
336
|
+
bankAgent,
|
|
140
337
|
fioStatement
|
|
141
338
|
});
|
package/dist/bank.d.cts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { S as Statement } from './bank-
|
|
2
|
-
export { B as
|
|
1
|
+
import { S as Statement } from './bank-CEIuNhV_.cjs';
|
|
2
|
+
export { B as BankAgentConfig, a as BankOrder, b as BankTransfer, c as BankTransferParams, d as BankVerifyConfig, C as Credit, e as bankAgent } from './bank-CEIuNhV_.cjs';
|
|
3
|
+
import './qr-CF-YeXU1.cjs';
|
|
4
|
+
import './types-DYZ9EkmJ.cjs';
|
|
3
5
|
|
|
4
6
|
/** A Fio account to read credits from, as its own API describes one */
|
|
5
7
|
interface FioConfig {
|
package/dist/bank.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { S as Statement } from './bank-
|
|
2
|
-
export { B as
|
|
1
|
+
import { S as Statement } from './bank-M8flcMks.js';
|
|
2
|
+
export { B as BankAgentConfig, a as BankOrder, b as BankTransfer, c as BankTransferParams, d as BankVerifyConfig, C as Credit, e as bankAgent } from './bank-M8flcMks.js';
|
|
3
|
+
import './qr-CF-YeXU1.js';
|
|
4
|
+
import './types-DYZ9EkmJ.js';
|
|
3
5
|
|
|
4
6
|
/** A Fio account to read credits from, as its own API describes one */
|
|
5
7
|
interface FioConfig {
|