@run402/sdk 4.113.0 → 4.114.0
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/dist/node/lightning-paid-fetch.d.ts +2 -0
- package/dist/node/lightning-paid-fetch.d.ts.map +1 -1
- package/dist/node/lightning-paid-fetch.js +44 -10
- package/dist/node/lightning-paid-fetch.js.map +1 -1
- package/dist/node/lightning-x402-lnbtc.d.ts +62 -0
- package/dist/node/lightning-x402-lnbtc.d.ts.map +1 -0
- package/dist/node/lightning-x402-lnbtc.js +170 -0
- package/dist/node/lightning-x402-lnbtc.js.map +1 -0
- package/dist/node/vendor/x402-lnbtc/LICENSE +201 -0
- package/dist/node/vendor/x402-lnbtc/VENDORED.md +25 -0
- package/dist/node/vendor/x402-lnbtc/binding.d.ts +80 -0
- package/dist/node/vendor/x402-lnbtc/binding.d.ts.map +1 -0
- package/dist/node/vendor/x402-lnbtc/binding.js +268 -0
- package/dist/node/vendor/x402-lnbtc/binding.js.map +1 -0
- package/dist/node/vendor/x402-lnbtc/bolt11.d.ts +39 -0
- package/dist/node/vendor/x402-lnbtc/bolt11.d.ts.map +1 -0
- package/dist/node/vendor/x402-lnbtc/bolt11.js +209 -0
- package/dist/node/vendor/x402-lnbtc/bolt11.js.map +1 -0
- package/dist/node/vendor/x402-lnbtc/constants.d.ts +75 -0
- package/dist/node/vendor/x402-lnbtc/constants.d.ts.map +1 -0
- package/dist/node/vendor/x402-lnbtc/constants.js +81 -0
- package/dist/node/vendor/x402-lnbtc/constants.js.map +1 -0
- package/dist/node/vendor/x402-lnbtc/exact/client/scheme.d.ts +58 -0
- package/dist/node/vendor/x402-lnbtc/exact/client/scheme.d.ts.map +1 -0
- package/dist/node/vendor/x402-lnbtc/exact/client/scheme.js +108 -0
- package/dist/node/vendor/x402-lnbtc/exact/client/scheme.js.map +1 -0
- package/dist/node/vendor/x402-lnbtc/jcs.d.ts +19 -0
- package/dist/node/vendor/x402-lnbtc/jcs.d.ts.map +1 -0
- package/dist/node/vendor/x402-lnbtc/jcs.js +81 -0
- package/dist/node/vendor/x402-lnbtc/jcs.js.map +1 -0
- package/dist/node/vendor/x402-lnbtc/types.d.ts +81 -0
- package/dist/node/vendor/x402-lnbtc/types.d.ts.map +1 -0
- package/dist/node/vendor/x402-lnbtc/types.js +2 -0
- package/dist/node/vendor/x402-lnbtc/types.js.map +1 -0
- package/dist/node/vendor/x402-lnbtc/validation.d.ts +94 -0
- package/dist/node/vendor/x402-lnbtc/validation.d.ts.map +1 -0
- package/dist/node/vendor/x402-lnbtc/validation.js +165 -0
- package/dist/node/vendor/x402-lnbtc/validation.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { HTTP_PROFILE, MCP_PROFILE } from "./constants.js";
|
|
2
|
+
export type RequestBindingProfile = typeof HTTP_PROFILE | typeof MCP_PROFILE;
|
|
3
|
+
/**
|
|
4
|
+
* The request-binding fields carried in `PaymentRequirements.extra`.
|
|
5
|
+
*/
|
|
6
|
+
export interface RequestBindingExtra {
|
|
7
|
+
requestHash: string;
|
|
8
|
+
requestBindingProfile: RequestBindingProfile;
|
|
9
|
+
requestBindingParams: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A request binding computed from the actual request or tool call.
|
|
13
|
+
*/
|
|
14
|
+
export interface RequestBinding extends RequestBindingExtra {
|
|
15
|
+
/** For `http:1`, the request URL that `PaymentRequired.resource.url` must equal. */
|
|
16
|
+
resourceUrl?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* HTTP request inputs for the `http:1` profile.
|
|
20
|
+
*/
|
|
21
|
+
export interface HttpRequestInput {
|
|
22
|
+
/** HTTP method, case preserved (RFC 9421 `@method`). */
|
|
23
|
+
method: string;
|
|
24
|
+
/** Absolute http(s) target URI including the query, no fragment or userinfo. */
|
|
25
|
+
url: string;
|
|
26
|
+
/** Content bytes after transfer decoding, before content decoding; empty if absent. */
|
|
27
|
+
body?: Uint8Array;
|
|
28
|
+
/** Lowercase header names to bind, configured by the server for the resource. */
|
|
29
|
+
boundHeaders: readonly string[];
|
|
30
|
+
/** Header lookup by lowercase name; `undefined` when absent. */
|
|
31
|
+
getHeader: (name: string) => string | readonly string[] | undefined;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* MCP `tools/call` inputs for the `mcp:1` profile.
|
|
35
|
+
*/
|
|
36
|
+
export interface McpToolCallInput {
|
|
37
|
+
/** Configured absolute URI identifying the MCP server. */
|
|
38
|
+
server: string;
|
|
39
|
+
/** Actual `params.name`. */
|
|
40
|
+
name: string;
|
|
41
|
+
/** Actual `params.arguments`, before defaults; `undefined` when omitted. */
|
|
42
|
+
arguments?: unknown;
|
|
43
|
+
/** Actual `params._meta`; `undefined` when omitted. */
|
|
44
|
+
meta?: unknown;
|
|
45
|
+
/** `_meta` member names to bind, configured by the server for the tool. */
|
|
46
|
+
boundMetadata: readonly string[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Computes the `http:1` binding for an HTTP request.
|
|
50
|
+
*
|
|
51
|
+
* @param input - The actual request and the configured bound headers
|
|
52
|
+
* @returns The binding, including the expected `PaymentRequired.resource.url`
|
|
53
|
+
* @throws LnbtcError `invalid_exact_lnbtc_request_binding` on malformed input
|
|
54
|
+
*/
|
|
55
|
+
export declare function httpRequestBinding(input: HttpRequestInput): RequestBinding;
|
|
56
|
+
/**
|
|
57
|
+
* Computes the `mcp:1` binding for an MCP `tools/call`.
|
|
58
|
+
*
|
|
59
|
+
* @param input - The actual tool call and the configured server and metadata names
|
|
60
|
+
* @returns The binding
|
|
61
|
+
* @throws LnbtcError `invalid_exact_lnbtc_request_binding` on malformed input
|
|
62
|
+
*/
|
|
63
|
+
export declare function mcpToolCallBinding(input: McpToolCallInput): RequestBinding;
|
|
64
|
+
/**
|
|
65
|
+
* Validates the binding fields of a requirements `extra` object.
|
|
66
|
+
*
|
|
67
|
+
* @param extra - `PaymentRequirements.extra`
|
|
68
|
+
* @returns The validated binding fields
|
|
69
|
+
* @throws LnbtcError `invalid_exact_lnbtc_request_binding` when missing or malformed
|
|
70
|
+
*/
|
|
71
|
+
export declare function parseBindingExtra(extra: Record<string, unknown> | undefined): RequestBindingExtra;
|
|
72
|
+
/**
|
|
73
|
+
* Compares two validated bindings: hash, profile, and JCS-equal parameters.
|
|
74
|
+
*
|
|
75
|
+
* @param a - First binding
|
|
76
|
+
* @param b - Second binding
|
|
77
|
+
* @returns Whether they are equal
|
|
78
|
+
*/
|
|
79
|
+
export declare function bindingsEqual(a: RequestBindingExtra, b: RequestBindingExtra): boolean;
|
|
80
|
+
//# sourceMappingURL=binding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../../../src/node/vendor/x402-lnbtc/binding.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiC,YAAY,EAAc,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGtG,MAAM,MAAM,qBAAqB,GAAG,OAAO,YAAY,GAAG,OAAO,WAAW,CAAC;AAE7E;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/C;AAED;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,mBAAmB;IACzD,oFAAoF;IACpF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;IACZ,uFAAuF;IACvF,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,iFAAiF;IACjF,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,gEAAgE;IAChE,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CACrE;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,uDAAuD;IACvD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,2EAA2E;IAC3E,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAYD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,GAAG,cAAc,CAwB1E;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,GAAG,cAAc,CA4B1E;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,mBAAmB,CAcjG;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAMrF"}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
2
|
+
import { bytesToHex } from "@noble/hashes/utils.js";
|
|
3
|
+
import { BINDING_DOMAIN_PREFIX, Errors, HTTP_PROFILE, LnbtcError, MCP_PROFILE } from "./constants.js";
|
|
4
|
+
import { canonicalize, isWellFormed } from "./jcs.js";
|
|
5
|
+
const TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
6
|
+
const LOWER_TOKEN = /^[!#$%&'*+\-.^_`|~0-9a-z]+$/;
|
|
7
|
+
const HEX64 = /^[0-9a-f]{64}$/;
|
|
8
|
+
// RFC 3986 URI characters (no fragment) with well-formed percent escapes.
|
|
9
|
+
// Square brackets are accepted outside the host too, as common clients send them raw.
|
|
10
|
+
const URI_SYNTAX = /^[A-Za-z][A-Za-z0-9+.-]*:(?:[A-Za-z0-9\-._~:/?[\]@!$&'()*+,;=]|%[0-9A-Fa-f]{2})*$/;
|
|
11
|
+
const ABSENT_HASH = bytesToHex(sha256(Uint8Array.of(0x00)));
|
|
12
|
+
const EXCLUDED_METADATA = new Set(["x402/payment", "progressToken"]);
|
|
13
|
+
/**
|
|
14
|
+
* Computes the `http:1` binding for an HTTP request.
|
|
15
|
+
*
|
|
16
|
+
* @param input - The actual request and the configured bound headers
|
|
17
|
+
* @returns The binding, including the expected `PaymentRequired.resource.url`
|
|
18
|
+
* @throws LnbtcError `invalid_exact_lnbtc_request_binding` on malformed input
|
|
19
|
+
*/
|
|
20
|
+
export function httpRequestBinding(input) {
|
|
21
|
+
const params = { headers: [...input.boundHeaders] };
|
|
22
|
+
validateHttpParams(params);
|
|
23
|
+
if (typeof input.method !== "string" || !TOKEN.test(input.method))
|
|
24
|
+
fail();
|
|
25
|
+
validateAbsoluteUri(input.url, true);
|
|
26
|
+
if (input.body !== undefined && !(input.body instanceof Uint8Array))
|
|
27
|
+
fail();
|
|
28
|
+
const headers = params.headers.map(name => ({
|
|
29
|
+
name,
|
|
30
|
+
valueHash: headerValueHash(input.getHeader(name)),
|
|
31
|
+
}));
|
|
32
|
+
const binding = {
|
|
33
|
+
domain: `${BINDING_DOMAIN_PREFIX}${HTTP_PROFILE}`,
|
|
34
|
+
method: input.method,
|
|
35
|
+
url: input.url,
|
|
36
|
+
bodyHash: bytesToHex(sha256(input.body ?? new Uint8Array())),
|
|
37
|
+
headers,
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
requestHash: hashBinding(binding),
|
|
41
|
+
requestBindingProfile: HTTP_PROFILE,
|
|
42
|
+
requestBindingParams: params,
|
|
43
|
+
resourceUrl: input.url,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Computes the `mcp:1` binding for an MCP `tools/call`.
|
|
48
|
+
*
|
|
49
|
+
* @param input - The actual tool call and the configured server and metadata names
|
|
50
|
+
* @returns The binding
|
|
51
|
+
* @throws LnbtcError `invalid_exact_lnbtc_request_binding` on malformed input
|
|
52
|
+
*/
|
|
53
|
+
export function mcpToolCallBinding(input) {
|
|
54
|
+
const params = { server: input.server, metadata: [...input.boundMetadata] };
|
|
55
|
+
validateMcpParams(params);
|
|
56
|
+
if (typeof input.name !== "string" || input.name.length === 0)
|
|
57
|
+
fail();
|
|
58
|
+
const args = input.arguments === undefined ? {} : input.arguments;
|
|
59
|
+
if (!isPlainObject(args))
|
|
60
|
+
fail();
|
|
61
|
+
const meta = input.meta === undefined ? {} : input.meta;
|
|
62
|
+
if (!isPlainObject(meta))
|
|
63
|
+
fail();
|
|
64
|
+
const metadata = params.metadata.map(name => ({
|
|
65
|
+
name,
|
|
66
|
+
valueHash: Object.prototype.hasOwnProperty.call(meta, name)
|
|
67
|
+
? hashPresent(new TextEncoder().encode(jcs(meta[name])))
|
|
68
|
+
: ABSENT_HASH,
|
|
69
|
+
}));
|
|
70
|
+
const binding = {
|
|
71
|
+
domain: `${BINDING_DOMAIN_PREFIX}${MCP_PROFILE}`,
|
|
72
|
+
server: params.server,
|
|
73
|
+
method: "tools/call",
|
|
74
|
+
name: input.name,
|
|
75
|
+
arguments: args,
|
|
76
|
+
metadata,
|
|
77
|
+
};
|
|
78
|
+
return {
|
|
79
|
+
requestHash: hashBinding(binding),
|
|
80
|
+
requestBindingProfile: MCP_PROFILE,
|
|
81
|
+
requestBindingParams: params,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Validates the binding fields of a requirements `extra` object.
|
|
86
|
+
*
|
|
87
|
+
* @param extra - `PaymentRequirements.extra`
|
|
88
|
+
* @returns The validated binding fields
|
|
89
|
+
* @throws LnbtcError `invalid_exact_lnbtc_request_binding` when missing or malformed
|
|
90
|
+
*/
|
|
91
|
+
export function parseBindingExtra(extra) {
|
|
92
|
+
const requestHash = extra?.requestHash;
|
|
93
|
+
const profile = extra?.requestBindingProfile;
|
|
94
|
+
const params = extra?.requestBindingParams;
|
|
95
|
+
if (typeof requestHash !== "string" || !HEX64.test(requestHash))
|
|
96
|
+
fail();
|
|
97
|
+
if (!isPlainObject(params))
|
|
98
|
+
fail();
|
|
99
|
+
if (profile === HTTP_PROFILE)
|
|
100
|
+
validateHttpParams(params);
|
|
101
|
+
else if (profile === MCP_PROFILE)
|
|
102
|
+
validateMcpParams(params);
|
|
103
|
+
else
|
|
104
|
+
fail();
|
|
105
|
+
return {
|
|
106
|
+
requestHash,
|
|
107
|
+
requestBindingProfile: profile,
|
|
108
|
+
requestBindingParams: params,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Compares two validated bindings: hash, profile, and JCS-equal parameters.
|
|
113
|
+
*
|
|
114
|
+
* @param a - First binding
|
|
115
|
+
* @param b - Second binding
|
|
116
|
+
* @returns Whether they are equal
|
|
117
|
+
*/
|
|
118
|
+
export function bindingsEqual(a, b) {
|
|
119
|
+
return (a.requestHash === b.requestHash &&
|
|
120
|
+
a.requestBindingProfile === b.requestBindingProfile &&
|
|
121
|
+
jcs(a.requestBindingParams) === jcs(b.requestBindingParams));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Validates `http:1` parameters: exactly `headers`, lowercase tokens, strictly
|
|
125
|
+
* ascending, excluding `payment-signature`.
|
|
126
|
+
*
|
|
127
|
+
* @param params - Candidate parameters
|
|
128
|
+
*/
|
|
129
|
+
function validateHttpParams(params) {
|
|
130
|
+
if (Object.keys(params).length !== 1 || !Array.isArray(params.headers))
|
|
131
|
+
fail();
|
|
132
|
+
validateSortedNames(params.headers, name => LOWER_TOKEN.test(name));
|
|
133
|
+
if (params.headers.includes("payment-signature"))
|
|
134
|
+
fail();
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Validates `mcp:1` parameters: exactly `server` and `metadata`.
|
|
138
|
+
*
|
|
139
|
+
* @param params - Candidate parameters
|
|
140
|
+
*/
|
|
141
|
+
function validateMcpParams(params) {
|
|
142
|
+
const keys = Object.keys(params).sort();
|
|
143
|
+
if (keys.length !== 2 || keys[0] !== "metadata" || keys[1] !== "server")
|
|
144
|
+
fail();
|
|
145
|
+
if (typeof params.server !== "string")
|
|
146
|
+
fail();
|
|
147
|
+
validateAbsoluteUri(params.server, false);
|
|
148
|
+
if (!Array.isArray(params.metadata))
|
|
149
|
+
fail();
|
|
150
|
+
validateSortedNames(params.metadata, name => name.length > 0 && isWellFormed(name) && !EXCLUDED_METADATA.has(name));
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Requires a strictly ascending list of valid names.
|
|
154
|
+
*
|
|
155
|
+
* @param names - Candidate names
|
|
156
|
+
* @param valid - Per-name validity check
|
|
157
|
+
*/
|
|
158
|
+
function validateSortedNames(names, valid) {
|
|
159
|
+
for (let i = 0; i < names.length; i++) {
|
|
160
|
+
const name = names[i];
|
|
161
|
+
if (typeof name !== "string" || !valid(name))
|
|
162
|
+
fail();
|
|
163
|
+
// JS string comparison orders by UTF-16 code units: ASCII order for header
|
|
164
|
+
// names, JCS property order for metadata names.
|
|
165
|
+
if (i > 0 && names[i - 1] >= name)
|
|
166
|
+
fail();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Validates an absolute URI in RFC 3986 ASCII syntax with no userinfo or
|
|
171
|
+
* fragment, without normalizing it. `http` and `https` URIs need an authority
|
|
172
|
+
* with a host (`scheme://host...`).
|
|
173
|
+
*
|
|
174
|
+
* @param uri - Candidate URI
|
|
175
|
+
* @param httpOnly - Require the `http` or `https` scheme
|
|
176
|
+
*/
|
|
177
|
+
function validateAbsoluteUri(uri, httpOnly) {
|
|
178
|
+
if (typeof uri !== "string" || !URI_SYNTAX.test(uri))
|
|
179
|
+
fail();
|
|
180
|
+
let parsed;
|
|
181
|
+
try {
|
|
182
|
+
parsed = new URL(uri);
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
fail();
|
|
186
|
+
}
|
|
187
|
+
if (parsed.username || parsed.password || /^[a-z][a-z0-9+.-]*:\/\/[^/?]*@/i.test(uri))
|
|
188
|
+
fail();
|
|
189
|
+
const isHttp = parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
190
|
+
if (httpOnly && !isHttp)
|
|
191
|
+
fail();
|
|
192
|
+
if (isHttp && (!/^https?:\/\/[^/?]/i.test(uri) || parsed.hostname === ""))
|
|
193
|
+
fail();
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Hashes a header per RFC 9421 section 2.1 default field-component rules.
|
|
197
|
+
*
|
|
198
|
+
* @param value - Header value(s), or `undefined` when absent
|
|
199
|
+
* @returns The value hash, lowercase hex
|
|
200
|
+
*/
|
|
201
|
+
function headerValueHash(value) {
|
|
202
|
+
// No field lines (undefined or an empty list) means the header is absent.
|
|
203
|
+
if (value === undefined || (Array.isArray(value) && value.length === 0))
|
|
204
|
+
return ABSENT_HASH;
|
|
205
|
+
const lines = typeof value === "string" ? [value] : value;
|
|
206
|
+
const parts = lines.map(line => {
|
|
207
|
+
if (typeof line !== "string" || !/^[\t\x20-\x7e]*$/.test(line))
|
|
208
|
+
fail();
|
|
209
|
+
return line.replace(/^[\t ]+|[\t ]+$/g, "");
|
|
210
|
+
});
|
|
211
|
+
return hashPresent(new TextEncoder().encode(parts.join(", ")));
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Hashes a present value as SHA-256 of `0x01 || bytes`.
|
|
215
|
+
*
|
|
216
|
+
* @param bytes - Value bytes
|
|
217
|
+
* @returns Lowercase hex digest
|
|
218
|
+
*/
|
|
219
|
+
function hashPresent(bytes) {
|
|
220
|
+
const input = new Uint8Array(bytes.length + 1);
|
|
221
|
+
input[0] = 0x01;
|
|
222
|
+
input.set(bytes, 1);
|
|
223
|
+
return bytesToHex(sha256(input));
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Hashes a binding object: SHA-256 of UTF-8 JCS.
|
|
227
|
+
*
|
|
228
|
+
* @param binding - The binding object
|
|
229
|
+
* @returns Lowercase hex request hash
|
|
230
|
+
*/
|
|
231
|
+
function hashBinding(binding) {
|
|
232
|
+
return bytesToHex(sha256(new TextEncoder().encode(jcs(binding))));
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Canonicalizes, mapping serialization errors to the binding error.
|
|
236
|
+
*
|
|
237
|
+
* @param value - Value to canonicalize
|
|
238
|
+
* @returns JCS text
|
|
239
|
+
*/
|
|
240
|
+
function jcs(value) {
|
|
241
|
+
try {
|
|
242
|
+
return canonicalize(value);
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
fail();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Checks for a plain (non-array, non-null) object.
|
|
250
|
+
*
|
|
251
|
+
* @param value - Candidate value
|
|
252
|
+
* @returns Whether it is a plain object
|
|
253
|
+
*/
|
|
254
|
+
function isPlainObject(value) {
|
|
255
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
256
|
+
return false;
|
|
257
|
+
const proto = Object.getPrototypeOf(value);
|
|
258
|
+
return proto === Object.prototype || proto === null;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Throws the request-binding error.
|
|
262
|
+
*
|
|
263
|
+
* @returns Never returns
|
|
264
|
+
*/
|
|
265
|
+
function fail() {
|
|
266
|
+
throw new LnbtcError(Errors.requestBinding);
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=binding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binding.js","sourceRoot":"","sources":["../../../../src/node/vendor/x402-lnbtc/binding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strictly decoded BOLT11 invoice fields used by the lnbtc scheme.
|
|
3
|
+
*/
|
|
4
|
+
export interface DecodedInvoice {
|
|
5
|
+
/** BOLT11 currency prefix (e.g. `bc`, `tb`). */
|
|
6
|
+
currency: string;
|
|
7
|
+
/** Invoice amount in millisatoshis. */
|
|
8
|
+
amountMsat: bigint;
|
|
9
|
+
/** Creation time, Unix seconds. */
|
|
10
|
+
timestamp: number;
|
|
11
|
+
/** Expiry in seconds (BOLT11 default 3600 when the `x` field is absent). */
|
|
12
|
+
expirySeconds: number;
|
|
13
|
+
/** Payment hash, 64 lowercase hex characters. */
|
|
14
|
+
paymentHash: string;
|
|
15
|
+
/** Every valid `h` (description hash) field, lowercase hex. */
|
|
16
|
+
descriptionHashes: string[];
|
|
17
|
+
/** Number of `d` (inline description) fields. */
|
|
18
|
+
inlineDescriptionCount: number;
|
|
19
|
+
/** Signing node public key (compressed, lowercase hex), from `n` or recovered. */
|
|
20
|
+
payee: string;
|
|
21
|
+
/** Whether the invoice carried an explicit `n` field. */
|
|
22
|
+
hasPayeeField: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Decodes a BOLT11 invoice and verifies its signature.
|
|
26
|
+
*
|
|
27
|
+
* Strict: rejects mixed case, a `lightning:` prefix, a missing or zero amount,
|
|
28
|
+
* sub-millisatoshi amounts, amounts with leading zeros, fixed-length fields of
|
|
29
|
+
* the wrong length or with non-zero padding, duplicated payment hash, payment
|
|
30
|
+
* secret, payee, expiry, CLTV, or feature fields, non-minimal integer fields,
|
|
31
|
+
* a missing payment secret, a high-S signature verified against an `n` field,
|
|
32
|
+
* and an invalid signature.
|
|
33
|
+
*
|
|
34
|
+
* @param invoice - BOLT11 invoice text
|
|
35
|
+
* @returns The decoded invoice
|
|
36
|
+
* @throws Error when the invoice is malformed or its signature is invalid
|
|
37
|
+
*/
|
|
38
|
+
export declare function decodeInvoice(invoice: string): DecodedInvoice;
|
|
39
|
+
//# sourceMappingURL=bolt11.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bolt11.d.ts","sourceRoot":"","sources":["../../../../src/node/vendor/x402-lnbtc/bolt11.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,aAAa,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,iDAAiD;IACjD,sBAAsB,EAAE,MAAM,CAAC;IAC/B,kFAAkF;IAClF,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,aAAa,EAAE,OAAO,CAAC;CACxB;AAoCD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CA+B7D"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { secp256k1 } from "@noble/curves/secp256k1.js";
|
|
2
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
3
|
+
import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
|
|
4
|
+
import { bech32, utils as scure } from "@scure/base";
|
|
5
|
+
const SIGNATURE_WORDS = 104;
|
|
6
|
+
const TIMESTAMP_WORDS = 7;
|
|
7
|
+
const DEFAULT_EXPIRY_SECONDS = 3600;
|
|
8
|
+
const MSAT_PER_BTC = 100000000000n;
|
|
9
|
+
// Multiplier → divisor of the BTC amount in msat.
|
|
10
|
+
const MULTIPLIERS = {
|
|
11
|
+
m: 1000n, // milli: 1e-3 BTC = 1e8 msat
|
|
12
|
+
u: 1000000n,
|
|
13
|
+
n: 1000000000n,
|
|
14
|
+
p: 1000000000000n,
|
|
15
|
+
};
|
|
16
|
+
const TAG = { p: 1, s: 16, d: 13, h: 23, x: 6, n: 19, c: 24, features: 5 };
|
|
17
|
+
// BOLT11: a reader MUST fail when a fixed-length field has another length.
|
|
18
|
+
const FIXED_LENGTHS = new Map([
|
|
19
|
+
[TAG.p, 52],
|
|
20
|
+
[TAG.s, 52],
|
|
21
|
+
[TAG.h, 52],
|
|
22
|
+
[TAG.n, 53],
|
|
23
|
+
]);
|
|
24
|
+
// Fields that may appear at most once; BOLT11 asks for minimal integer encodings.
|
|
25
|
+
const SINGLETON_TAGS = new Set([
|
|
26
|
+
TAG.p,
|
|
27
|
+
TAG.s,
|
|
28
|
+
TAG.n,
|
|
29
|
+
TAG.x,
|
|
30
|
+
TAG.c,
|
|
31
|
+
TAG.features,
|
|
32
|
+
]);
|
|
33
|
+
const MINIMAL_TAGS = new Set([TAG.x, TAG.c, TAG.features]);
|
|
34
|
+
/**
|
|
35
|
+
* Decodes a BOLT11 invoice and verifies its signature.
|
|
36
|
+
*
|
|
37
|
+
* Strict: rejects mixed case, a `lightning:` prefix, a missing or zero amount,
|
|
38
|
+
* sub-millisatoshi amounts, amounts with leading zeros, fixed-length fields of
|
|
39
|
+
* the wrong length or with non-zero padding, duplicated payment hash, payment
|
|
40
|
+
* secret, payee, expiry, CLTV, or feature fields, non-minimal integer fields,
|
|
41
|
+
* a missing payment secret, a high-S signature verified against an `n` field,
|
|
42
|
+
* and an invalid signature.
|
|
43
|
+
*
|
|
44
|
+
* @param invoice - BOLT11 invoice text
|
|
45
|
+
* @returns The decoded invoice
|
|
46
|
+
* @throws Error when the invoice is malformed or its signature is invalid
|
|
47
|
+
*/
|
|
48
|
+
export function decodeInvoice(invoice) {
|
|
49
|
+
if (typeof invoice !== "string" || invoice.length === 0)
|
|
50
|
+
throw new Error("empty invoice");
|
|
51
|
+
const { prefix, words } = bech32.decode(invoice, false);
|
|
52
|
+
const { currency, amountMsat } = parseHrp(prefix);
|
|
53
|
+
if (words.length < TIMESTAMP_WORDS + SIGNATURE_WORDS)
|
|
54
|
+
throw new Error("invoice too short");
|
|
55
|
+
const signed = words.slice(0, words.length - SIGNATURE_WORDS);
|
|
56
|
+
const sigBytes = bech32.fromWords(words.slice(words.length - SIGNATURE_WORDS));
|
|
57
|
+
const timestamp = wordsToNumber(signed.slice(0, TIMESTAMP_WORDS));
|
|
58
|
+
const fields = parseTaggedFields(signed.slice(TIMESTAMP_WORDS));
|
|
59
|
+
if (fields.paymentHash === undefined)
|
|
60
|
+
throw new Error("invoice has no payment hash");
|
|
61
|
+
if (!fields.hasPaymentSecret)
|
|
62
|
+
throw new Error("invoice has no payment secret");
|
|
63
|
+
const prefixBytes = new TextEncoder().encode(prefix);
|
|
64
|
+
const dataBytes = Uint8Array.from(scure.convertRadix2(signed, 5, 8, true));
|
|
65
|
+
const message = new Uint8Array(prefixBytes.length + dataBytes.length);
|
|
66
|
+
message.set(prefixBytes);
|
|
67
|
+
message.set(dataBytes, prefixBytes.length);
|
|
68
|
+
return {
|
|
69
|
+
currency,
|
|
70
|
+
amountMsat,
|
|
71
|
+
timestamp,
|
|
72
|
+
expirySeconds: fields.expiry ?? DEFAULT_EXPIRY_SECONDS,
|
|
73
|
+
paymentHash: fields.paymentHash,
|
|
74
|
+
descriptionHashes: fields.descriptionHashes,
|
|
75
|
+
inlineDescriptionCount: fields.inlineDescriptions,
|
|
76
|
+
payee: verifySignature(sigBytes, sha256(message), fields.payee),
|
|
77
|
+
hasPayeeField: fields.payee !== undefined,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Parses the human-readable part into currency and millisatoshi amount.
|
|
82
|
+
*
|
|
83
|
+
* @param prefix - The bech32 human-readable part
|
|
84
|
+
* @returns Currency prefix and amount in millisatoshis
|
|
85
|
+
*/
|
|
86
|
+
function parseHrp(prefix) {
|
|
87
|
+
const match = /^ln([a-z]+?)([0-9]+)?([munp])?$/.exec(prefix);
|
|
88
|
+
if (!match)
|
|
89
|
+
throw new Error("invalid invoice prefix");
|
|
90
|
+
const [, currency, digits, multiplier] = match;
|
|
91
|
+
if (!digits)
|
|
92
|
+
throw new Error("invoice has no amount");
|
|
93
|
+
if (digits.length > 1 && digits.startsWith("0"))
|
|
94
|
+
throw new Error("amount has leading zeros");
|
|
95
|
+
const value = BigInt(digits);
|
|
96
|
+
if (value === 0n)
|
|
97
|
+
throw new Error("invoice amount is zero");
|
|
98
|
+
const scaled = value * MSAT_PER_BTC;
|
|
99
|
+
if (!multiplier)
|
|
100
|
+
return { currency, amountMsat: scaled };
|
|
101
|
+
const divisor = MULTIPLIERS[multiplier];
|
|
102
|
+
if (scaled % divisor !== 0n)
|
|
103
|
+
throw new Error("amount is not an integral millisatoshi");
|
|
104
|
+
return { currency, amountMsat: scaled / divisor };
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Reads BOLT11 tagged fields, skipping unknown fields.
|
|
108
|
+
*
|
|
109
|
+
* @param words - 5-bit words after the timestamp, before the signature
|
|
110
|
+
* @returns The fields the scheme consumes
|
|
111
|
+
*/
|
|
112
|
+
function parseTaggedFields(words) {
|
|
113
|
+
const out = {
|
|
114
|
+
hasPaymentSecret: false,
|
|
115
|
+
descriptionHashes: [],
|
|
116
|
+
inlineDescriptions: 0,
|
|
117
|
+
};
|
|
118
|
+
const seen = new Set();
|
|
119
|
+
let i = 0;
|
|
120
|
+
while (i < words.length) {
|
|
121
|
+
if (i + 3 > words.length)
|
|
122
|
+
throw new Error("truncated tagged field");
|
|
123
|
+
const tag = words[i];
|
|
124
|
+
const length = words[i + 1] * 32 + words[i + 2];
|
|
125
|
+
const data = words.slice(i + 3, i + 3 + length);
|
|
126
|
+
if (data.length !== length)
|
|
127
|
+
throw new Error("truncated tagged field");
|
|
128
|
+
i += 3 + length;
|
|
129
|
+
const fixedLength = FIXED_LENGTHS.get(tag);
|
|
130
|
+
if (fixedLength !== undefined && length !== fixedLength) {
|
|
131
|
+
throw new Error("tagged field has the wrong length");
|
|
132
|
+
}
|
|
133
|
+
if (SINGLETON_TAGS.has(tag)) {
|
|
134
|
+
if (seen.has(tag))
|
|
135
|
+
throw new Error("duplicate tagged field");
|
|
136
|
+
seen.add(tag);
|
|
137
|
+
}
|
|
138
|
+
if (MINIMAL_TAGS.has(tag) && data[0] === 0)
|
|
139
|
+
throw new Error("non-minimal integer field");
|
|
140
|
+
switch (tag) {
|
|
141
|
+
case TAG.p:
|
|
142
|
+
out.paymentHash = bytesToHex(bech32.fromWords(data));
|
|
143
|
+
break;
|
|
144
|
+
case TAG.s:
|
|
145
|
+
bech32.fromWords(data); // rejects non-zero padding
|
|
146
|
+
out.hasPaymentSecret = true;
|
|
147
|
+
break;
|
|
148
|
+
case TAG.h:
|
|
149
|
+
out.descriptionHashes.push(bytesToHex(bech32.fromWords(data)));
|
|
150
|
+
break;
|
|
151
|
+
case TAG.d:
|
|
152
|
+
out.inlineDescriptions += 1;
|
|
153
|
+
break;
|
|
154
|
+
case TAG.n:
|
|
155
|
+
out.payee = bytesToHex(bech32.fromWords(data));
|
|
156
|
+
break;
|
|
157
|
+
case TAG.x:
|
|
158
|
+
out.expiry = wordsToNumber(data);
|
|
159
|
+
break;
|
|
160
|
+
default:
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Verifies the invoice signature against `n` when present (low-S required, as
|
|
168
|
+
* BOLT11 demands), otherwise recovers the signing key (either S form accepted).
|
|
169
|
+
*
|
|
170
|
+
* @param sigBytes - 65 bytes: compact signature followed by the recovery id
|
|
171
|
+
* @param digest - SHA-256 of the signed invoice bytes
|
|
172
|
+
* @param payeeField - Public key from the `n` field, if present
|
|
173
|
+
* @returns The signing public key, compressed lowercase hex
|
|
174
|
+
*/
|
|
175
|
+
function verifySignature(sigBytes, digest, payeeField) {
|
|
176
|
+
const recovery = sigBytes[64];
|
|
177
|
+
if (recovery > 3)
|
|
178
|
+
throw new Error("invalid recovery id");
|
|
179
|
+
const compact = sigBytes.subarray(0, 64);
|
|
180
|
+
if (payeeField !== undefined) {
|
|
181
|
+
const valid = secp256k1.verify(compact, digest, hexToBytes(payeeField), {
|
|
182
|
+
lowS: true,
|
|
183
|
+
format: "compact",
|
|
184
|
+
prehash: false,
|
|
185
|
+
});
|
|
186
|
+
if (!valid)
|
|
187
|
+
throw new Error("invalid invoice signature");
|
|
188
|
+
return payeeField;
|
|
189
|
+
}
|
|
190
|
+
// Recovery yields the unique key for which this signature verifies.
|
|
191
|
+
const signature = secp256k1.Signature.fromBytes(compact, "compact").addRecoveryBit(recovery);
|
|
192
|
+
return signature.recoverPublicKey(digest).toHex(true);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Interprets 5-bit words as a big-endian unsigned integer.
|
|
196
|
+
*
|
|
197
|
+
* @param words - 5-bit words
|
|
198
|
+
* @returns The integer value
|
|
199
|
+
*/
|
|
200
|
+
function wordsToNumber(words) {
|
|
201
|
+
let value = 0;
|
|
202
|
+
for (const word of words) {
|
|
203
|
+
value = value * 32 + word;
|
|
204
|
+
if (!Number.isSafeInteger(value))
|
|
205
|
+
throw new Error("integer field too large");
|
|
206
|
+
}
|
|
207
|
+
return value;
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=bolt11.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bolt11.js","sourceRoot":"","sources":["../../../../src/node/vendor/x402-lnbtc/bolt11.ts"],"names":[],"mappings":"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"}
|