@getalby/lightning-tools 8.0.0 → 8.1.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.
@@ -1,5 +1,10 @@
1
1
  'use strict';
2
2
 
3
+ /**
4
+ * Client: parse "www-authenticate" header from server response
5
+ * @param input
6
+ * @returns details from the header value (token or macaroon, invoice)
7
+ */
3
8
  const parseL402 = (input) => {
4
9
  // Remove the L402 and LSAT identifiers
5
10
  const string = input.replace("L402", "").replace("LSAT", "").trim();
@@ -14,6 +19,19 @@ const parseL402 = (input) => {
14
19
  // Value is either match[3] (double-quoted), match[4] (single-quoted), or match[5] (unquoted)
15
20
  keyValuePairs[match[1]] = match[3] || match[4] || match[5];
16
21
  }
22
+ if (!keyValuePairs["token"] && keyValuePairs["macaroon"]) {
23
+ // fallback to old naming
24
+ keyValuePairs["token"] = keyValuePairs["macaroon"];
25
+ delete keyValuePairs["macaroon"];
26
+ }
27
+ if (!("token" in keyValuePairs) ||
28
+ typeof keyValuePairs["token"] !== "string") {
29
+ throw new Error("No macaroon or token found in www-authenticate header");
30
+ }
31
+ if (!("invoice" in keyValuePairs) ||
32
+ typeof keyValuePairs["invoice"] !== "string") {
33
+ throw new Error("No invoice found in www-authenticate header");
34
+ }
17
35
  return keyValuePairs;
18
36
  };
19
37
 
@@ -51,5 +69,89 @@ const fetchWithL402 = async (url, fetchArgs, options) => {
51
69
  return handleL402Payment(header, url, fetchArgs, headers, wallet);
52
70
  };
53
71
 
72
+ async function issueL402Macaroon(secret, paymentHash, params) {
73
+ if (params !== undefined &&
74
+ Object.prototype.hasOwnProperty.call(params, "paymentHash")) {
75
+ throw new Error("paymentHash is reserved");
76
+ }
77
+ const payload = { ...params, paymentHash };
78
+ const encoded = Buffer.from(JSON.stringify(payload)).toString("base64url");
79
+ const mac = await sign(secret, encoded);
80
+ return `${encoded}.${mac}`;
81
+ }
82
+ async function verifyL402Macaroon(secret, token) {
83
+ const { timingSafeEqual } = await import('crypto');
84
+ const dotIndex = token.lastIndexOf(".");
85
+ if (dotIndex === -1)
86
+ throw new Error("Invalid macaroon token");
87
+ const encoded = token.slice(0, dotIndex);
88
+ const mac = token.slice(dotIndex + 1);
89
+ // Constant-time comparison to prevent timing attacks
90
+ const expectedMac = await sign(secret, encoded);
91
+ try {
92
+ if (!timingSafeEqual(Buffer.from(mac, "hex"), Buffer.from(expectedMac, "hex"))) {
93
+ throw new Error("Invalid macaroon token");
94
+ }
95
+ }
96
+ catch (e) {
97
+ throw new Error("Invalid macaroon token");
98
+ }
99
+ try {
100
+ const parsed = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
101
+ if (parsed === null ||
102
+ typeof parsed !== "object" ||
103
+ Array.isArray(parsed) ||
104
+ typeof parsed.paymentHash !== "string") {
105
+ throw new Error("Invalid macaroon payload");
106
+ }
107
+ return parsed;
108
+ }
109
+ catch {
110
+ throw new Error("Invalid macaroon token");
111
+ }
112
+ }
113
+ async function sign(secret, payload) {
114
+ const { createHmac } = await import('crypto');
115
+ return createHmac("sha256", secret).update(payload).digest("hex");
116
+ }
117
+
118
+ /**
119
+ * Server: create a WWW-Authenticate header for a given macaroon and invoice
120
+ * @param args the macaroon/token and invoice generated for the client's request
121
+ * @returns the header value
122
+ */
123
+ const makeL402AuthenticateHeader = (args) => {
124
+ if (!args.token) {
125
+ throw new Error("token must be provided");
126
+ }
127
+ return `L402 version="0" token="${args.token}", invoice="${args.invoice}"`;
128
+ };
129
+ /**
130
+ * Server: parse "authorization" header sent from client
131
+ * @param input value from authorization header
132
+ * @returns the macaroon and preimage
133
+ */
134
+ function parseL402Authorization(input) {
135
+ // Backwards compat: LSAT was the former name of L402
136
+ const normalized = input.replace(/^LSAT /, "L402 ");
137
+ const prefix = "L402 ";
138
+ if (!normalized.startsWith(prefix))
139
+ return null;
140
+ const credentials = normalized.slice(prefix.length);
141
+ const colonIndex = credentials.indexOf(":");
142
+ if (colonIndex === -1) {
143
+ throw new Error("Invalid authorization header value");
144
+ }
145
+ return {
146
+ token: credentials.slice(0, colonIndex),
147
+ preimage: credentials.slice(colonIndex + 1),
148
+ };
149
+ }
150
+
54
151
  exports.fetchWithL402 = fetchWithL402;
152
+ exports.issueL402Macaroon = issueL402Macaroon;
153
+ exports.makeL402AuthenticateHeader = makeL402AuthenticateHeader;
154
+ exports.parseL402 = parseL402;
155
+ exports.parseL402Authorization = parseL402Authorization;
156
+ exports.verifyL402Macaroon = verifyL402Macaroon;
55
157
  //# sourceMappingURL=l402.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"l402.cjs","sources":["../../../src/402/l402/utils.ts","../../../src/402/l402/l402.ts"],"sourcesContent":["export const parseL402 = (input: string): Record<string, string> => {\n // Remove the L402 and LSAT identifiers\n const string = input.replace(\"L402\", \"\").replace(\"LSAT\", \"\").trim();\n\n // Initialize an object to store the key-value pairs\n const keyValuePairs = {};\n\n // Regular expression to match key and (quoted or unquoted) value\n const regex = /(\\w+)=(\"([^\"]*)\"|'([^']*)'|([^,]*))/g;\n let match;\n\n // Use regex to find all key-value pairs\n while ((match = regex.exec(string)) !== null) {\n // Key is always match[1]\n // Value is either match[3] (double-quoted), match[4] (single-quoted), or match[5] (unquoted)\n keyValuePairs[match[1]] = match[3] || match[4] || match[5];\n }\n\n return keyValuePairs;\n};\n\nexport const makeL402AuthenticateHeader = (args: {\n macaroon?: string;\n token?: string;\n invoice: string;\n}) => {\n if (args.macaroon) {\n return `L402 version=\"0\" macaroon=\"${args.macaroon}\", invoice=\"${args.invoice}\"`;\n } else {\n return `L402 version=\"0\" token=\"${args.token}\", invoice=\"${args.invoice}\"`;\n }\n};\n","import { Wallet } from \"../utils\";\nimport { parseL402 } from \"./utils\";\n\nexport const handleL402Payment = async (\n l402Header: string,\n url: string,\n fetchArgs: RequestInit,\n headers: Headers,\n wallet: Wallet,\n): Promise<Response> => {\n const details = parseL402(l402Header);\n const token = details.token || details.macaroon;\n const invoice = details.invoice;\n\n if (!token) {\n throw new Error(\"L402: missing token/macaroon in WWW-Authenticate header\");\n }\n if (!invoice) {\n throw new Error(\"L402: missing invoice in WWW-Authenticate header\");\n }\n\n const invResp = await wallet.payInvoice({ invoice });\n headers.set(\"Authorization\", `L402 ${token}:${invResp.preimage}`);\n return fetch(url, fetchArgs);\n};\n\nexport const fetchWithL402 = async (\n url: string,\n fetchArgs: RequestInit,\n options: {\n wallet: Wallet;\n },\n) => {\n const wallet = options.wallet;\n if (!wallet) {\n throw new Error(\"wallet is missing\");\n }\n if (!fetchArgs) {\n fetchArgs = {};\n }\n fetchArgs.cache = \"no-store\";\n fetchArgs.mode = \"cors\";\n const headers = new Headers(fetchArgs.headers ?? undefined);\n fetchArgs.headers = headers;\n\n const initResp = await fetch(url, fetchArgs);\n const header = initResp.headers.get(\"www-authenticate\");\n if (!header) {\n return initResp;\n }\n\n return handleL402Payment(header, url, fetchArgs, headers, wallet);\n};\n"],"names":[],"mappings":";;AAAO,MAAM,SAAS,GAAG,CAAC,KAAa,KAA4B;;IAEjE,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE;;IAGnE,MAAM,aAAa,GAAG,EAAE;;IAGxB,MAAM,KAAK,GAAG,sCAAsC;AACpD,IAAA,IAAI,KAAK;;AAGT,IAAA,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE;;;QAG5C,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;IAC5D;AAEA,IAAA,OAAO,aAAa;AACtB,CAAC;;AChBM,MAAM,iBAAiB,GAAG,OAC/B,UAAkB,EAClB,GAAW,EACX,SAAsB,EACtB,OAAgB,EAChB,MAAc,KACO;AACrB,IAAA,MAAM,OAAO,GAAG,SAAS,CAAC,UAAU,CAAC;IACrC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,QAAQ;AAC/C,IAAA,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO;IAE/B,IAAI,CAAC,KAAK,EAAE;AACV,QAAA,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC;IAC5E;IACA,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC;IACrE;IAEA,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;AACpD,IAAA,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,CAAA,KAAA,EAAQ,KAAK,CAAA,CAAA,EAAI,OAAO,CAAC,QAAQ,CAAA,CAAE,CAAC;AACjE,IAAA,OAAO,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC;AAC9B,CAAC;AAEM,MAAM,aAAa,GAAG,OAC3B,GAAW,EACX,SAAsB,EACtB,OAEC,KACC;AACF,IAAA,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM;IAC7B,IAAI,CAAC,MAAM,EAAE;AACX,QAAA,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC;IACtC;IACA,IAAI,CAAC,SAAS,EAAE;QACd,SAAS,GAAG,EAAE;IAChB;AACA,IAAA,SAAS,CAAC,KAAK,GAAG,UAAU;AAC5B,IAAA,SAAS,CAAC,IAAI,GAAG,MAAM;IACvB,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC;AAC3D,IAAA,SAAS,CAAC,OAAO,GAAG,OAAO;IAE3B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC;IAC5C,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IACvD,IAAI,CAAC,MAAM,EAAE;AACX,QAAA,OAAO,QAAQ;IACjB;AAEA,IAAA,OAAO,iBAAiB,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC;AACnE;;;;"}
1
+ {"version":3,"file":"l402.cjs","sources":["../../../src/402/l402/utils.ts","../../../src/402/l402/l402.ts","../../../src/402/l402/server/l402.ts","../../../src/402/l402/server/utils.ts"],"sourcesContent":["interface WwwAuthenticatePayload {\n token: string;\n invoice: string;\n [key: string]: string; // Allows any other string properties\n}\n\n/**\n * Client: parse \"www-authenticate\" header from server response\n * @param input\n * @returns details from the header value (token or macaroon, invoice)\n */\nexport const parseL402 = (input: string): WwwAuthenticatePayload => {\n // Remove the L402 and LSAT identifiers\n const string = input.replace(\"L402\", \"\").replace(\"LSAT\", \"\").trim();\n\n // Initialize an object to store the key-value pairs\n const keyValuePairs: Record<string, string> = {};\n\n // Regular expression to match key and (quoted or unquoted) value\n const regex = /(\\w+)=(\"([^\"]*)\"|'([^']*)'|([^,]*))/g;\n let match;\n\n // Use regex to find all key-value pairs\n while ((match = regex.exec(string)) !== null) {\n // Key is always match[1]\n // Value is either match[3] (double-quoted), match[4] (single-quoted), or match[5] (unquoted)\n keyValuePairs[match[1]] = match[3] || match[4] || match[5];\n }\n\n if (!keyValuePairs[\"token\"] && keyValuePairs[\"macaroon\"]) {\n // fallback to old naming\n keyValuePairs[\"token\"] = keyValuePairs[\"macaroon\"];\n delete keyValuePairs[\"macaroon\"];\n }\n\n if (\n !(\"token\" in keyValuePairs) ||\n typeof keyValuePairs[\"token\"] !== \"string\"\n ) {\n throw new Error(\"No macaroon or token found in www-authenticate header\");\n }\n if (\n !(\"invoice\" in keyValuePairs) ||\n typeof keyValuePairs[\"invoice\"] !== \"string\"\n ) {\n throw new Error(\"No invoice found in www-authenticate header\");\n }\n\n return keyValuePairs as WwwAuthenticatePayload;\n};\n","import { Wallet } from \"../utils\";\nimport { parseL402 } from \"./utils\";\n\nexport const handleL402Payment = async (\n l402Header: string,\n url: string,\n fetchArgs: RequestInit,\n headers: Headers,\n wallet: Wallet,\n): Promise<Response> => {\n const details = parseL402(l402Header);\n const token = details.token || details.macaroon;\n const invoice = details.invoice;\n\n if (!token) {\n throw new Error(\"L402: missing token/macaroon in WWW-Authenticate header\");\n }\n if (!invoice) {\n throw new Error(\"L402: missing invoice in WWW-Authenticate header\");\n }\n\n const invResp = await wallet.payInvoice({ invoice });\n headers.set(\"Authorization\", `L402 ${token}:${invResp.preimage}`);\n return fetch(url, fetchArgs);\n};\n\nexport const fetchWithL402 = async (\n url: string,\n fetchArgs: RequestInit,\n options: {\n wallet: Wallet;\n },\n) => {\n const wallet = options.wallet;\n if (!wallet) {\n throw new Error(\"wallet is missing\");\n }\n if (!fetchArgs) {\n fetchArgs = {};\n }\n fetchArgs.cache = \"no-store\";\n fetchArgs.mode = \"cors\";\n const headers = new Headers(fetchArgs.headers ?? undefined);\n fetchArgs.headers = headers;\n\n const initResp = await fetch(url, fetchArgs);\n const header = initResp.headers.get(\"www-authenticate\");\n if (!header) {\n return initResp;\n }\n\n return handleL402Payment(header, url, fetchArgs, headers, wallet);\n};\n","export type MacaroonPayload<T> = T & {\n paymentHash: string; // hex — SHA256 of the preimage\n};\n\nexport async function issueL402Macaroon<T extends Record<string, unknown>>(\n secret: string,\n paymentHash: string,\n params?: T,\n): Promise<string> {\n if (\n params !== undefined &&\n Object.prototype.hasOwnProperty.call(params, \"paymentHash\")\n ) {\n throw new Error(\"paymentHash is reserved\");\n }\n const payload = { ...params, paymentHash } as MacaroonPayload<T>;\n const encoded = Buffer.from(JSON.stringify(payload)).toString(\"base64url\");\n const mac = await sign(secret, encoded);\n return `${encoded}.${mac}`;\n}\n\nexport async function verifyL402Macaroon<T = unknown>(\n secret: string,\n token: string,\n): Promise<MacaroonPayload<T>> {\n const { timingSafeEqual } = await import(\"crypto\");\n const dotIndex = token.lastIndexOf(\".\");\n if (dotIndex === -1) throw new Error(\"Invalid macaroon token\");\n\n const encoded = token.slice(0, dotIndex);\n const mac = token.slice(dotIndex + 1);\n\n // Constant-time comparison to prevent timing attacks\n const expectedMac = await sign(secret, encoded);\n try {\n if (\n !timingSafeEqual(Buffer.from(mac, \"hex\"), Buffer.from(expectedMac, \"hex\"))\n ) {\n throw new Error(\"Invalid macaroon token\");\n }\n } catch (e) {\n throw new Error(\"Invalid macaroon token\");\n }\n\n try {\n const parsed: unknown = JSON.parse(\n Buffer.from(encoded, \"base64url\").toString(\"utf8\"),\n );\n if (\n parsed === null ||\n typeof parsed !== \"object\" ||\n Array.isArray(parsed) ||\n typeof (parsed as Record<string, unknown>).paymentHash !== \"string\"\n ) {\n throw new Error(\"Invalid macaroon payload\");\n }\n return parsed as MacaroonPayload<T>;\n } catch {\n throw new Error(\"Invalid macaroon token\");\n }\n}\n\nasync function sign(secret: string, payload: string): Promise<string> {\n const { createHmac } = await import(\"crypto\");\n return createHmac(\"sha256\", secret).update(payload).digest(\"hex\");\n}\n","/**\n * Server: create a WWW-Authenticate header for a given macaroon and invoice\n * @param args the macaroon/token and invoice generated for the client's request\n * @returns the header value\n */\nexport const makeL402AuthenticateHeader = (args: {\n token?: string;\n invoice: string;\n}) => {\n if (!args.token) {\n throw new Error(\"token must be provided\");\n }\n\n return `L402 version=\"0\" token=\"${args.token}\", invoice=\"${args.invoice}\"`;\n};\n\n/**\n * Server: parse \"authorization\" header sent from client\n * @param input value from authorization header\n * @returns the macaroon and preimage\n */\nexport function parseL402Authorization(\n input: string,\n): { token: string; preimage: string } | null {\n // Backwards compat: LSAT was the former name of L402\n const normalized = input.replace(/^LSAT /, \"L402 \");\n const prefix = \"L402 \";\n if (!normalized.startsWith(prefix)) return null;\n const credentials = normalized.slice(prefix.length);\n const colonIndex = credentials.indexOf(\":\");\n if (colonIndex === -1) {\n throw new Error(\"Invalid authorization header value\");\n }\n return {\n token: credentials.slice(0, colonIndex),\n preimage: credentials.slice(colonIndex + 1),\n };\n}\n"],"names":[],"mappings":"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"}