wao 0.28.0 → 0.29.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/cjs/httpsig.js ADDED
@@ -0,0 +1,1086 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.verifyContentDigest = exports.toBuffer = exports.hasValidSignature = exports.getSignatureNames = exports.from = exports.extractKeys = void 0;
7
+ var _ramda = require("ramda");
8
+ var _signerUtils = require("./signer-utils.js");
9
+ var _base64url = _interopRequireDefault(require("base64url"));
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
11
+ function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
12
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
13
+ function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
14
+ function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
15
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
16
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
17
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
18
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
19
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
20
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
21
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
22
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
23
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
24
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
25
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
26
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
27
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
28
+ /**
29
+ * Get multipart boundary from content-type header
30
+ */
31
+ var getBoundary = function getBoundary(http) {
32
+ var ctype = http.headers["content-type"];
33
+ if (ctype && /^multipart\/form-data;/.test((0, _ramda.trim)(ctype))) {
34
+ var _iterator = _createForOfIteratorHelper((0, _ramda.trim)(ctype).split(";").slice(1)),
35
+ _step;
36
+ try {
37
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
38
+ var v = _step.value;
39
+ var sp2 = v.split("=");
40
+ if ((0, _ramda.trim)(sp2[0]) === "boundary") return (0, _ramda.trim)(sp2[1]).replace(/"/g, "");
41
+ }
42
+ } catch (err) {
43
+ _iterator.e(err);
44
+ } finally {
45
+ _iterator.f();
46
+ }
47
+ }
48
+ return null;
49
+ };
50
+
51
+ /**
52
+ * Extract specified components from HTTP message
53
+ * @param {Object} http - HTTP message object with headers and optional body
54
+ * @param {Array} components - Array of component names to extract
55
+ * @returns {Object} Extracted components with their values
56
+ */
57
+ var extract = function extract(http, components) {
58
+ var extracted = {};
59
+ var needsBody = components.some(function (c) {
60
+ return c.replace(/"/g, "").toLowerCase() === "content-digest";
61
+ });
62
+
63
+ // First extract ao-types if it's signed
64
+ var hasAoTypes = components.some(function (c) {
65
+ return c.replace(/"/g, "").toLowerCase() === "ao-types";
66
+ });
67
+ if (hasAoTypes) {
68
+ var aoTypes = http.headers["ao-types"] || http.headers["Ao-Types"];
69
+ if (aoTypes) {
70
+ extracted["ao-types"] = aoTypes;
71
+ }
72
+ }
73
+ var _iterator2 = _createForOfIteratorHelper(components),
74
+ _step2;
75
+ try {
76
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
77
+ var component = _step2.value;
78
+ var cleanComponent = component.replace(/"/g, "");
79
+ if (cleanComponent.startsWith("@")) {
80
+ // Handle derived components
81
+ switch (cleanComponent) {
82
+ case "@method":
83
+ extracted[cleanComponent] = http.method || "GET";
84
+ break;
85
+ case "@target-uri":
86
+ extracted[cleanComponent] = http.url || "";
87
+ break;
88
+ case "@authority":
89
+ extracted[cleanComponent] = http.headers.host || "";
90
+ break;
91
+ case "@scheme":
92
+ if (http.url) {
93
+ var url = new URL(http.url);
94
+ extracted[cleanComponent] = url.protocol.replace(":", "");
95
+ }
96
+ break;
97
+ case "@request-target":
98
+ if (http.url) {
99
+ var _url = new URL(http.url);
100
+ extracted[cleanComponent] = _url.pathname + _url.search;
101
+ }
102
+ break;
103
+ case "@path":
104
+ if (http.url) {
105
+ var _url2 = new URL(http.url);
106
+ extracted[cleanComponent] = _url2.pathname;
107
+ }
108
+ break;
109
+ case "@query":
110
+ if (http.url) {
111
+ var _url3 = new URL(http.url);
112
+ extracted[cleanComponent] = _url3.search;
113
+ }
114
+ break;
115
+ case "@status":
116
+ extracted[cleanComponent] = String(http.status || http["@status"] || "");
117
+ break;
118
+ case "@query-param":
119
+ // This would need additional parsing logic for specific query parameters
120
+ break;
121
+ }
122
+ } else {
123
+ // Handle regular headers - try both exact case and lowercase
124
+ var headerValue = http.headers[cleanComponent] || http.headers[cleanComponent.toLowerCase()];
125
+ if (headerValue !== null && headerValue !== undefined) {
126
+ extracted[cleanComponent] = headerValue;
127
+ }
128
+ }
129
+ }
130
+
131
+ // If content-digest is signed, we need to include the body
132
+ } catch (err) {
133
+ _iterator2.e(err);
134
+ } finally {
135
+ _iterator2.f();
136
+ }
137
+ if (needsBody && http.body !== undefined) {
138
+ extracted["body"] = http.body;
139
+ }
140
+
141
+ // Add flag if body is needed but missing
142
+ if (needsBody && http.body === undefined) {
143
+ extracted["__bodyRequired__"] = true;
144
+ }
145
+ return extracted;
146
+ };
147
+
148
+ /**
149
+ * Convert body to Buffer from various sources
150
+ * @param {string|Buffer|ArrayBuffer} body - The body to convert
151
+ * @returns {Buffer} The body as a Buffer
152
+ */
153
+ var toBuffer = exports.toBuffer = function toBuffer(body) {
154
+ if (!body) {
155
+ return Buffer.alloc(0);
156
+ }
157
+
158
+ // If it's already a Buffer, return it
159
+ if (Buffer.isBuffer(body)) {
160
+ return body;
161
+ }
162
+
163
+ // If it's a string, convert to Buffer
164
+ if (typeof body === "string") {
165
+ return Buffer.from(body, "utf-8");
166
+ }
167
+
168
+ // If it's an ArrayBuffer or TypedArray
169
+ if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {
170
+ return Buffer.from(body);
171
+ }
172
+ throw new Error("Unsupported body type");
173
+ };
174
+
175
+ /**
176
+ * Convert message to JSON with proper type conversions
177
+ * Following the logic from dev_codec_structured, dev_codec_httpsig_conv, and dev_codec_flat
178
+ * @param {Object} msg - The message to convert
179
+ * @returns {Object} JSON representation
180
+ */
181
+ var _toJSON = function toJSON(msg) {
182
+ if (!msg || _typeof(msg) !== "object") {
183
+ return msg;
184
+ }
185
+ var result = _objectSpread({}, msg);
186
+
187
+ // First, handle the multipart body if present
188
+ var contentType = result["content-type"];
189
+ var body = result.body;
190
+ if (body && contentType && contentType.includes("multipart/form-data")) {
191
+ var boundary = getBoundary({
192
+ headers: {
193
+ "content-type": contentType
194
+ }
195
+ });
196
+ if (boundary) {
197
+ // Parse multipart body
198
+ var parts = parseMultipartBody(body, boundary);
199
+
200
+ // Remove the raw body since we've parsed it
201
+ delete result.body;
202
+
203
+ // Merge parsed parts into result
204
+ for (var _i = 0, _Object$entries = Object.entries(parts); _i < _Object$entries.length; _i++) {
205
+ var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
206
+ partName = _Object$entries$_i[0],
207
+ partData = _Object$entries$_i[1];
208
+ // Parse ao-types from part data if present
209
+ var partTypes = {};
210
+ if (partData["ao-types"]) {
211
+ // Updated regex to handle spaces and trim the key
212
+ var matches = _toConsumableArray(partData["ao-types"].matchAll(/([^=,]+)="([^"]+)"/g));
213
+ var _iterator3 = _createForOfIteratorHelper(matches),
214
+ _step3;
215
+ try {
216
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
217
+ var _step3$value = _slicedToArray(_step3.value, 3),
218
+ _ = _step3$value[0],
219
+ key = _step3$value[1],
220
+ type = _step3$value[2];
221
+ partTypes[key.trim()] = type;
222
+ }
223
+ } catch (err) {
224
+ _iterator3.e(err);
225
+ } finally {
226
+ _iterator3.f();
227
+ }
228
+ }
229
+
230
+ // Apply type conversions to part data
231
+ var convertedPartData = {};
232
+ for (var _i2 = 0, _Object$entries2 = Object.entries(partData); _i2 < _Object$entries2.length; _i2++) {
233
+ var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
234
+ _key = _Object$entries2$_i[0],
235
+ value = _Object$entries2$_i[1];
236
+ if (_key === "ao-types" || _key === "content-disposition") continue;
237
+ var _type = partTypes[_key];
238
+ if (_type && typeof value === "string") {
239
+ convertedPartData[_key] = convertByType(value, _type);
240
+ } else {
241
+ convertedPartData[_key] = value;
242
+ }
243
+ }
244
+
245
+ // Store the result
246
+ if (Object.keys(convertedPartData).length > 0) {
247
+ // Check if the part name suggests it's an array element (ends with /number)
248
+ var isArrayElement = /\/\d+$/.test(partName);
249
+
250
+ // For top-level parts (no slash in name) with objects, keep the structure
251
+ var isTopLevel = !partName.includes("/");
252
+
253
+ // Check if this is a nested path that will be unflattened
254
+ var isNestedPath = partName.includes("/") && !isArrayElement;
255
+ if (isArrayElement || isNestedPath) {
256
+ // Array elements and nested paths keep their structure
257
+ result[partName] = convertedPartData;
258
+ } else if (isTopLevel || Object.keys(convertedPartData).length > 1) {
259
+ // Top-level objects or multi-field objects keep their structure
260
+ result[partName] = convertedPartData;
261
+ } else {
262
+ // Only lift single values for simple cases
263
+ result[partName] = convertedPartData[Object.keys(convertedPartData)[0]];
264
+ }
265
+ }
266
+
267
+ // Store type information for nested fields
268
+ if (Object.keys(partTypes).length > 0) {
269
+ for (var _i3 = 0, _Object$entries3 = Object.entries(partTypes); _i3 < _Object$entries3.length; _i3++) {
270
+ var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
271
+ fieldKey = _Object$entries3$_i[0],
272
+ fieldType = _Object$entries3$_i[1];
273
+ if (fieldKey !== "ao-types" && fieldKey !== "content-disposition") {
274
+ // Add to global typeMap with the full path
275
+ var fullPath = partName + "/" + fieldKey;
276
+ // Store in the ao-types for later use
277
+ if (!result["__typeMap"]) result["__typeMap"] = {};
278
+ result["__typeMap"][fullPath] = fieldType;
279
+ }
280
+ }
281
+ }
282
+ }
283
+ }
284
+ }
285
+
286
+ // Parse global ao-types to get type information
287
+ var typeMap = {};
288
+ if (result["ao-types"]) {
289
+ // Updated regex to handle spaces and trim the key
290
+ var _matches = _toConsumableArray(result["ao-types"].matchAll(/([^=,]+)="([^"]+)"/g));
291
+ var _iterator4 = _createForOfIteratorHelper(_matches),
292
+ _step4;
293
+ try {
294
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
295
+ var _step4$value = _slicedToArray(_step4.value, 3),
296
+ _2 = _step4$value[0],
297
+ _key2 = _step4$value[1],
298
+ _type2 = _step4$value[2];
299
+ typeMap[_key2.trim()] = _type2;
300
+ }
301
+ } catch (err) {
302
+ _iterator4.e(err);
303
+ } finally {
304
+ _iterator4.f();
305
+ }
306
+ }
307
+
308
+ // Merge in types from multipart parsing
309
+ if (result["__typeMap"]) {
310
+ Object.assign(typeMap, result["__typeMap"]);
311
+ delete result["__typeMap"];
312
+ }
313
+
314
+ // Also collect types from multipart parts for nested fields
315
+ for (var _i4 = 0, _Object$entries4 = Object.entries(result); _i4 < _Object$entries4.length; _i4++) {
316
+ var _Object$entries4$_i = _slicedToArray(_Object$entries4[_i4], 2),
317
+ _key3 = _Object$entries4$_i[0],
318
+ _value = _Object$entries4$_i[1];
319
+ if (_key3.includes("/") && _typeof(_value) === "object" && _value !== null && _value.__partTypes) {
320
+ // This is a multipart part with type information
321
+ for (var _i5 = 0, _Object$entries5 = Object.entries(_value.__partTypes); _i5 < _Object$entries5.length; _i5++) {
322
+ var _Object$entries5$_i = _slicedToArray(_Object$entries5[_i5], 2),
323
+ _fieldKey = _Object$entries5$_i[0],
324
+ _fieldType = _Object$entries5$_i[1];
325
+ // Create the full path for the type
326
+ var _fullPath = "".concat(_key3, "/").concat(_fieldKey);
327
+ typeMap[_fullPath] = _fieldType;
328
+ }
329
+ // Remove the __partTypes after processing
330
+ delete _value.__partTypes;
331
+ }
332
+ }
333
+
334
+ // Add empty values for fields that are in ao-types but not in result
335
+ for (var _i6 = 0, _Object$entries6 = Object.entries(typeMap); _i6 < _Object$entries6.length; _i6++) {
336
+ var _Object$entries6$_i = _slicedToArray(_Object$entries6[_i6], 2),
337
+ _key4 = _Object$entries6$_i[0],
338
+ _type3 = _Object$entries6$_i[1];
339
+ if (!(_key4 in result) && _type3.startsWith("empty-")) {
340
+ result[_key4] = convertByType("", _type3);
341
+ }
342
+ }
343
+
344
+ // Apply type conversions and build final result
345
+ var finalResult = {};
346
+ for (var _i7 = 0, _Object$entries7 = Object.entries(result); _i7 < _Object$entries7.length; _i7++) {
347
+ var _Object$entries7$_i = _slicedToArray(_Object$entries7[_i7], 2),
348
+ _key5 = _Object$entries7$_i[0],
349
+ _value2 = _Object$entries7$_i[1];
350
+ // Skip internal keys and headers we don't want in the final result
351
+ if (_key5.startsWith("__")) continue;
352
+ if (_key5.startsWith("@")) continue; // Skip all @ fields
353
+ if (_key5 === "ao-types") continue;
354
+ if (_key5 === "content-type") continue;
355
+ if (_key5 === "content-digest") continue;
356
+ if (_key5 === "signature") continue;
357
+ if (_key5 === "signature-input") continue;
358
+ if (_key5 === "body-keys") continue;
359
+
360
+ // Get the type for this key
361
+ var _type4 = typeMap[_key5];
362
+
363
+ // Special handling for objects that should be lists
364
+ if (_type4 === "list" && _typeof(_value2) === "object" && _value2 !== null && !Array.isArray(_value2)) {
365
+ // This is an object that should be converted to a list
366
+ var converted = maybeConvertToArray(_value2);
367
+ finalResult[_key5] = converted;
368
+ } else if (_type4 && typeof _value2 === "string") {
369
+ // Convert based on type
370
+ finalResult[_key5] = convertByType(_value2, _type4);
371
+ } else if (_type4 && _value2 === undefined) {
372
+ // Handle empty types
373
+ finalResult[_key5] = convertByType("", _type4);
374
+ } else if (_typeof(_value2) === "object" && _value2 !== null && !Array.isArray(_value2)) {
375
+ // For objects without a specific type, keep them as objects
376
+ // Only recurse for processing nested values
377
+ var processedObj = {};
378
+ for (var _i8 = 0, _Object$entries8 = Object.entries(_value2); _i8 < _Object$entries8.length; _i8++) {
379
+ var _Object$entries8$_i = _slicedToArray(_Object$entries8[_i8], 2),
380
+ k = _Object$entries8$_i[0],
381
+ v = _Object$entries8$_i[1];
382
+ if (Array.isArray(v)) {
383
+ // Keep arrays as arrays
384
+ processedObj[k] = v;
385
+ } else if (_typeof(v) === "object" && v !== null) {
386
+ processedObj[k] = _toJSON(v);
387
+ } else {
388
+ processedObj[k] = v;
389
+ }
390
+ }
391
+ finalResult[_key5] = processedObj;
392
+ } else {
393
+ // Keep as-is (including arrays)
394
+ finalResult[_key5] = _value2;
395
+ }
396
+ }
397
+
398
+ // Handle flattened paths - pass typeMap for context
399
+ return unflattenPaths(finalResult, typeMap);
400
+ };
401
+
402
+ /**
403
+ * Convert objects with numeric keys to arrays
404
+ */
405
+ var maybeConvertToArray = function maybeConvertToArray(obj) {
406
+ if (Array.isArray(obj)) return obj;
407
+ var keys = Object.keys(obj);
408
+ var numericKeys = keys.filter(function (k) {
409
+ return /^\d+$/.test(k);
410
+ });
411
+
412
+ // If all keys are numeric and sequential starting from 1
413
+ if (numericKeys.length > 0 && numericKeys.length === keys.length) {
414
+ var sortedNumericKeys = numericKeys.map(Number).sort(function (a, b) {
415
+ return a - b;
416
+ });
417
+ var maxIndex = Math.max.apply(Math, _toConsumableArray(sortedNumericKeys));
418
+ var arr = [];
419
+
420
+ // Fill array based on numeric keys (1-based to 0-based)
421
+ for (var i = 1; i <= maxIndex; i++) {
422
+ if (obj[String(i)] !== undefined) {
423
+ arr[i - 1] = obj[String(i)];
424
+ }
425
+ }
426
+ return arr;
427
+ }
428
+ return obj;
429
+ };
430
+
431
+ /**
432
+ * Convert value based on its type
433
+ */
434
+ var convertByType = function convertByType(value, type) {
435
+ switch (type) {
436
+ case "integer":
437
+ // Handle structured field integer format
438
+ if (typeof value === "string" && value.match(/^"?\(ao-type-integer\)\s+(\d+)"?$/)) {
439
+ var match = value.match(/(\d+)/);
440
+ return parseInt(match[1], 10);
441
+ }
442
+ return parseInt(value, 10);
443
+ case "float":
444
+ case "decimal":
445
+ return parseFloat(value);
446
+ case "boolean":
447
+ return value === "true" || value === "?1";
448
+ case "atom":
449
+ // Remove quotes from atom values
450
+ var atomValue = value;
451
+
452
+ // Remove any surrounding quotes (single or double)
453
+ if (atomValue.startsWith('"') && atomValue.endsWith('"') || atomValue.startsWith("'") && atomValue.endsWith("'")) {
454
+ atomValue = atomValue.slice(1, -1);
455
+ }
456
+
457
+ // Also handle escaped quotes
458
+ atomValue = atomValue.replace(/\\"/g, '"').replace(/\\'/g, "'");
459
+
460
+ // Handle special atom values
461
+ if (atomValue === "true") return true;
462
+ if (atomValue === "false") return false;
463
+ if (atomValue === "null") return null;
464
+
465
+ // For other atoms, return as Symbol
466
+ return Symbol["for"](atomValue);
467
+ case "list":
468
+ // Handle case where list is a comma-separated string
469
+ if (typeof value === "string" && !value.startsWith("(")) {
470
+ var items = [];
471
+ var current = "";
472
+ var inQuotes = false;
473
+ var depth = 0;
474
+ for (var i = 0; i < value.length; i++) {
475
+ var _char = value[i];
476
+ var prevChar = value[i - 1];
477
+ if (_char === '"' && prevChar !== "\\") {
478
+ inQuotes = !inQuotes;
479
+ }
480
+ if (!inQuotes) {
481
+ if (_char === "(") {
482
+ depth++;
483
+ } else if (_char === ")") {
484
+ depth--;
485
+ } else if (_char === "," && depth === 0) {
486
+ if (current.trim()) {
487
+ // Parse the item to handle type annotations
488
+ items.push(parseStructuredItem(current.trim()));
489
+ }
490
+ current = "";
491
+ continue;
492
+ }
493
+ }
494
+ current += _char;
495
+ }
496
+ if (current.trim()) {
497
+ items.push(parseStructuredItem(current.trim()));
498
+ }
499
+ return items;
500
+ }
501
+ return parseStructuredList(value);
502
+ case "map":
503
+ case "dictionary":
504
+ return parseStructuredDict(value);
505
+ case "empty-binary":
506
+ return "";
507
+ case "empty-list":
508
+ return [];
509
+ case "empty-message":
510
+ return {};
511
+ default:
512
+ return value;
513
+ }
514
+ };
515
+
516
+ /**
517
+ * Parse structured field list
518
+ */
519
+ var parseStructuredList = function parseStructuredList(value) {
520
+ if (!value || value === "()") return [];
521
+
522
+ // Remove outer quotes if present
523
+ var content = value.trim();
524
+ if (content.startsWith('"') && content.endsWith('"')) {
525
+ content = content.slice(1, -1);
526
+ }
527
+ var items = [];
528
+ var current = "";
529
+ var inQuotes = false;
530
+ var depth = 0;
531
+ for (var i = 0; i < content.length; i++) {
532
+ var _char2 = content[i];
533
+ var prevChar = content[i - 1];
534
+ if (_char2 === '"' && prevChar !== "\\") {
535
+ inQuotes = !inQuotes;
536
+ current += _char2;
537
+ } else if (!inQuotes) {
538
+ if (_char2 === "(") {
539
+ depth++;
540
+ current += _char2;
541
+ } else if (_char2 === ")") {
542
+ depth--;
543
+ current += _char2;
544
+ } else if (_char2 === "," && depth === 0) {
545
+ if (current.trim()) {
546
+ items.push(parseStructuredItem(current.trim()));
547
+ }
548
+ current = "";
549
+ } else {
550
+ current += _char2;
551
+ }
552
+ } else {
553
+ current += _char2;
554
+ }
555
+ }
556
+ if (current.trim()) {
557
+ items.push(parseStructuredItem(current.trim()));
558
+ }
559
+ return items;
560
+ };
561
+
562
+ /**
563
+ * Parse structured field item
564
+ */
565
+ var parseStructuredItem = function parseStructuredItem(item) {
566
+ // Quoted string - handle first to properly process inner content
567
+ if (item.startsWith('"') && item.endsWith('"')) {
568
+ var inner = item.slice(1, -1).replace(/\\"/g, '"');
569
+
570
+ // Check if the inner content is ao-type encoded
571
+ var innerAoTypeMatch = inner.match(/^\(ao-type-(\w+)\)\s+(.+)$/);
572
+ if (innerAoTypeMatch) {
573
+ var _innerAoTypeMatch = _slicedToArray(innerAoTypeMatch, 3),
574
+ type = _innerAoTypeMatch[1],
575
+ value = _innerAoTypeMatch[2];
576
+ // The value here has already had escaped quotes converted to real quotes
577
+ // If it's wrapped in quotes, remove them
578
+ var cleanValue = value;
579
+ if (cleanValue.startsWith('"') && cleanValue.endsWith('"') || cleanValue.startsWith("'") && cleanValue.endsWith("'")) {
580
+ cleanValue = cleanValue.slice(1, -1);
581
+ }
582
+ return convertByType(cleanValue, type);
583
+ }
584
+ return inner;
585
+ }
586
+
587
+ // Handle ao-type encoded items without outer quotes
588
+ var aoTypeMatch = item.match(/^\(ao-type-(\w+)\)\s+(.+)$/);
589
+ if (aoTypeMatch) {
590
+ var _aoTypeMatch = _slicedToArray(aoTypeMatch, 3),
591
+ _type5 = _aoTypeMatch[1],
592
+ _value3 = _aoTypeMatch[2];
593
+ var _cleanValue = _value3;
594
+ // Handle escaped quotes
595
+ _cleanValue = _cleanValue.replace(/\\"/g, '"');
596
+ // If wrapped in quotes, remove them
597
+ if (_cleanValue.startsWith('"') && _cleanValue.endsWith('"') || _cleanValue.startsWith("'") && _cleanValue.endsWith("'")) {
598
+ _cleanValue = _cleanValue.slice(1, -1);
599
+ }
600
+ return convertByType(_cleanValue, _type5);
601
+ }
602
+
603
+ // Boolean
604
+ if (item === "?1") return true;
605
+ if (item === "?0") return false;
606
+
607
+ // Number
608
+ if (/^-?\d+$/.test(item)) {
609
+ return parseInt(item, 10);
610
+ }
611
+ if (/^-?\d+\.\d+$/.test(item)) {
612
+ return parseFloat(item);
613
+ }
614
+
615
+ // Nested list
616
+ if (item.startsWith("(") && item.endsWith(")")) {
617
+ return parseStructuredList(item);
618
+ }
619
+ return item;
620
+ };
621
+
622
+ /**
623
+ * Parse structured field dictionary
624
+ */
625
+ var parseStructuredDict = function parseStructuredDict(value) {
626
+ var decoded = (0, _signerUtils.decodeSigInput)(value);
627
+ var result = {};
628
+ for (var _i9 = 0, _Object$entries9 = Object.entries(decoded); _i9 < _Object$entries9.length; _i9++) {
629
+ var _Object$entries9$_i = _slicedToArray(_Object$entries9[_i9], 2),
630
+ key = _Object$entries9$_i[0],
631
+ info = _Object$entries9$_i[1];
632
+ if (info && info.components && info.components.length > 0) {
633
+ result[key] = parseStructuredItem(info.components[0]);
634
+ } else {
635
+ result[key] = true;
636
+ }
637
+ }
638
+ return result;
639
+ };
640
+
641
+ /**
642
+ * Parse body-keys list
643
+ */
644
+ var parseBodyKeysList = function parseBodyKeysList(value) {
645
+ var matches = _toConsumableArray(value.matchAll(/"([^"]+)"/g));
646
+ return matches.map(function (m) {
647
+ return m[1];
648
+ });
649
+ };
650
+
651
+ /**
652
+ * Parse multipart body
653
+ */
654
+ var parseMultipartBody = function parseMultipartBody(body, boundary) {
655
+ var result = {};
656
+
657
+ // Split by boundary lines
658
+ var parts = body.split("--".concat(boundary));
659
+ for (var i = 0; i < parts.length; i++) {
660
+ var part = parts[i];
661
+
662
+ // Skip empty parts and the terminating part
663
+ if (!part || part === "--" || part === "--\r\n" || part.trim() === "") continue;
664
+
665
+ // Remove leading \r\n if present
666
+ var content = part;
667
+ if (content.startsWith("\r\n")) {
668
+ content = content.substring(2);
669
+ }
670
+
671
+ // Remove trailing \r\n or -- if present
672
+ if (content.endsWith("\r\n")) {
673
+ content = content.substring(0, content.length - 2);
674
+ }
675
+ if (!content) continue;
676
+
677
+ // Parse all lines
678
+ var lines = content.split("\r\n");
679
+ var partData = {};
680
+ var partName = null;
681
+ var _iterator5 = _createForOfIteratorHelper(lines),
682
+ _step5;
683
+ try {
684
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
685
+ var line = _step5.value;
686
+ if (!line) continue;
687
+ var colonIndex = line.indexOf(": ");
688
+ if (colonIndex > -1) {
689
+ var name = line.substring(0, colonIndex);
690
+ var value = line.substring(colonIndex + 2);
691
+
692
+ // Check if this is content-disposition to extract part name
693
+ if (name.toLowerCase() === "content-disposition") {
694
+ var nameMatch = value.match(/name="([^"]+)"/);
695
+ if (nameMatch) {
696
+ partName = nameMatch[1];
697
+ }
698
+ } else {
699
+ // Store all other headers/fields
700
+ partData[name] = value;
701
+ }
702
+ }
703
+ }
704
+
705
+ // Store the part data under its name
706
+ } catch (err) {
707
+ _iterator5.e(err);
708
+ } finally {
709
+ _iterator5.f();
710
+ }
711
+ if (partName && Object.keys(partData).length > 0) {
712
+ result[partName] = partData;
713
+ }
714
+ }
715
+ return result;
716
+ };
717
+
718
+ /**
719
+ * Unflatten paths with '/'
720
+ */
721
+ var unflattenPaths = function unflattenPaths(obj) {
722
+ var typeMap = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
723
+ var result = {};
724
+
725
+ // Check if there are any paths to unflatten
726
+ var hasPathsToUnflatten = Object.keys(obj).some(function (key) {
727
+ return key.includes("/");
728
+ });
729
+
730
+ // If no paths to unflatten, return the object as-is
731
+ if (!hasPathsToUnflatten) {
732
+ return obj;
733
+ }
734
+
735
+ // First pass: collect all keys and sort them to process parents before children
736
+ var sortedKeys = Object.keys(obj).sort();
737
+ var _iterator6 = _createForOfIteratorHelper(sortedKeys),
738
+ _step6;
739
+ try {
740
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
741
+ var key = _step6.value;
742
+ var value = obj[key];
743
+ if (key.includes("/")) {
744
+ var parts = key.split("/");
745
+ var current = result;
746
+ var i = 0;
747
+ while (i < parts.length - 1) {
748
+ var part = parts[i];
749
+
750
+ // Check if we have consecutive empty parts (multiple slashes)
751
+ if (part === "" && i + 1 < parts.length && parts[i + 1] === "") {
752
+ // Skip empty parts until we find a non-empty one or reach the end
753
+ var j = i;
754
+ while (j < parts.length && parts[j] === "") {
755
+ j++;
756
+ }
757
+ // Use "/" as the key for multiple slashes
758
+ part = "/";
759
+ i = j - 1; // Will be incremented at the end of loop
760
+ } else if (part === "") {
761
+ // Single empty part at the beginning or middle, skip it
762
+ i++;
763
+ continue;
764
+ }
765
+ if (!current[part]) {
766
+ current[part] = {};
767
+ }
768
+ current = current[part];
769
+ i++;
770
+ }
771
+
772
+ // Handle the final part
773
+ var finalPart = parts[parts.length - 1];
774
+ current[finalPart] = value;
775
+ } else {
776
+ result[key] = value;
777
+ }
778
+ }
779
+
780
+ // Second pass: convert objects with numeric keys to arrays only if they have type="list"
781
+ } catch (err) {
782
+ _iterator6.e(err);
783
+ } finally {
784
+ _iterator6.f();
785
+ }
786
+ var _convertToArraysRecursive = function convertToArraysRecursive(obj) {
787
+ var parentKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
788
+ if (Array.isArray(obj)) {
789
+ return obj.map(function (item, index) {
790
+ return _convertToArraysRecursive(item, "".concat(parentKey, "/").concat(index + 1));
791
+ });
792
+ } else if (obj && _typeof(obj) === "object") {
793
+ // Check if this object has type="list" in typeMap
794
+ var hasListType = typeMap[parentKey] === "list";
795
+
796
+ // Only convert to array if it has numeric keys AND type="list"
797
+ if (hasListType) {
798
+ var converted = maybeConvertToArray(obj);
799
+ if (Array.isArray(converted)) {
800
+ return converted.map(function (item, index) {
801
+ return _convertToArraysRecursive(item, "".concat(parentKey, "/").concat(index + 1));
802
+ });
803
+ }
804
+ }
805
+
806
+ // Otherwise, keep as object and recurse
807
+ var _result = {};
808
+ for (var _i10 = 0, _Object$entries10 = Object.entries(obj); _i10 < _Object$entries10.length; _i10++) {
809
+ var _Object$entries10$_i = _slicedToArray(_Object$entries10[_i10], 2),
810
+ key = _Object$entries10$_i[0],
811
+ value = _Object$entries10$_i[1];
812
+ var childKey = parentKey ? "".concat(parentKey, "/").concat(key) : key;
813
+ _result[key] = _convertToArraysRecursive(value, childKey);
814
+ }
815
+ return _result;
816
+ }
817
+ return obj;
818
+ };
819
+ return _convertToArraysRecursive(result);
820
+ };
821
+
822
+ /**
823
+ * Helper to check if a key pattern suggests an array structure
824
+ */
825
+ var isArrayKey = function isArrayKey(obj, currentKey, partIndex) {
826
+ var parts = currentKey.split("/");
827
+ var prefix = parts.slice(0, partIndex + 1).join("/");
828
+
829
+ // Check if there are other keys with the same prefix but numeric suffixes
830
+ for (var _i11 = 0, _Object$keys = Object.keys(obj); _i11 < _Object$keys.length; _i11++) {
831
+ var key = _Object$keys[_i11];
832
+ if (key.startsWith(prefix + "/") && key !== currentKey) {
833
+ var otherParts = key.split("/");
834
+ if (otherParts.length > partIndex + 1 && /^\d+$/.test(otherParts[partIndex + 1])) {
835
+ return true;
836
+ }
837
+ }
838
+ }
839
+ return false;
840
+ };
841
+
842
+ /**
843
+ * Check if a string contains binary data (non-printable characters)
844
+ * @param {string} str - The string to check
845
+ * @returns {boolean} True if binary data detected
846
+ */
847
+ var isBinaryString = function isBinaryString(str) {
848
+ if (!str || typeof str !== "string") return false;
849
+
850
+ // Check for non-printable characters (excluding common whitespace)
851
+ for (var i = 0; i < str.length; i++) {
852
+ var code = str.charCodeAt(i);
853
+ // Allow tab (9), newline (10), carriage return (13), and printable ASCII (32-126)
854
+ if (code < 9 || code > 13 && code < 32 || code > 126) {
855
+ return true;
856
+ }
857
+ }
858
+ return false;
859
+ };
860
+
861
+ /**
862
+ * Convert binary string to Buffer
863
+ * @param {string} str - Binary string to convert
864
+ * @returns {Buffer} Buffer representation of the string
865
+ */
866
+ var stringToBuffer = function stringToBuffer(str) {
867
+ var buffer = Buffer.alloc(str.length);
868
+ for (var i = 0; i < str.length; i++) {
869
+ buffer[i] = str.charCodeAt(i);
870
+ }
871
+ return buffer;
872
+ };
873
+
874
+ /**
875
+ * Original from function - extracts and converts only signed components
876
+ * @param {Object} http - HTTP message object with headers, body, and status
877
+ * @returns {Object|null} Converted signed components or null if not signed
878
+ */
879
+ var from = exports.from = function from(http) {
880
+ var input = http.headers["signature-input"] || http.headers["Signature-Input"];
881
+ if (!input) {
882
+ return null;
883
+ }
884
+
885
+ // Decode signature inputs
886
+ var inputs = (0, _signerUtils.decodeSigInput)(input);
887
+
888
+ // Process the first signature (following the original logic)
889
+ for (var k in inputs) {
890
+ var sigData = inputs[k];
891
+
892
+ // Extract only the signed components
893
+ var extractedComponents = extract(http, sigData.components);
894
+
895
+ // Check if ao-result header is present and points to body
896
+ var aoResult = http.headers["ao-result"] || http.headers["Ao-Result"];
897
+ if (aoResult === "body" && extractedComponents.body) {
898
+ // Check if body is binary data
899
+ if (isBinaryString(extractedComponents.body)) {
900
+ return stringToBuffer(extractedComponents.body);
901
+ }
902
+ }
903
+
904
+ // Convert the extracted components to JSON format
905
+ var result = _toJSON(extractedComponents);
906
+
907
+ // Handle ao-result if present
908
+ if (aoResult && result[aoResult] !== undefined) {
909
+ // Return the value of the key specified by ao-result
910
+ return result[aoResult];
911
+ }
912
+ return result;
913
+ }
914
+ return null;
915
+ };
916
+
917
+ /**
918
+ * Extract all keys and signature information from HTTP signature message
919
+ * @param {Object} http - HTTP message object with headers and body
920
+ * @returns {Object} Object containing all extracted signature data
921
+ */
922
+ var extractKeys = exports.extractKeys = function extractKeys(http) {
923
+ var result = {
924
+ signatures: {},
925
+ keys: {},
926
+ boundary: null,
927
+ requiresBody: false,
928
+ body: http.body ? toBuffer(http.body) : null,
929
+ bodyText: typeof http.body === "string" ? http.body : null
930
+ };
931
+
932
+ // Get multipart boundary if present
933
+ result.boundary = getBoundary(http);
934
+
935
+ // Get signature header
936
+ var signatureHeader = http.headers.signature || http.headers.Signature;
937
+ if (!signatureHeader) {
938
+ return result;
939
+ }
940
+
941
+ // Get signature-input header
942
+ var signatureInput = http.headers["signature-input"] || http.headers["Signature-Input"];
943
+ if (!signatureInput) {
944
+ return result;
945
+ }
946
+
947
+ // Decode all signature inputs
948
+ var inputs = (0, _signerUtils.decodeSigInput)(signatureInput);
949
+
950
+ // Parse signature header to extract actual signatures
951
+ // Format: sig1=:base64signature:, sig2=:base64signature:
952
+ var signatures = {};
953
+ var sigPattern = /([a-zA-Z0-9-]+)=:([^:]+):/g;
954
+ var match;
955
+ while ((match = sigPattern.exec(signatureHeader)) !== null) {
956
+ signatures[match[1]] = match[2];
957
+ }
958
+
959
+ // Process each signature
960
+ for (var _i12 = 0, _Object$entries11 = Object.entries(inputs); _i12 < _Object$entries11.length; _i12++) {
961
+ var _Object$entries11$_i = _slicedToArray(_Object$entries11[_i12], 2),
962
+ sigName = _Object$entries11$_i[0],
963
+ sigData = _Object$entries11$_i[1];
964
+ var extractedValues = extract(http, sigData.components);
965
+
966
+ // Check if body is required
967
+ if (extractedValues.__bodyRequired__) {
968
+ result.requiresBody = true;
969
+ }
970
+ var signatureInfo = {
971
+ name: sigName,
972
+ signature: signatures[sigName] || null,
973
+ components: sigData.components,
974
+ params: sigData.params,
975
+ extractedValues: extractedValues,
976
+ hasContentDigest: sigData.components.some(function (c) {
977
+ return c.replace(/"/g, "").toLowerCase() === "content-digest";
978
+ })
979
+ };
980
+
981
+ // If has content-digest, verify it
982
+ if (signatureInfo.hasContentDigest && result.body) {
983
+ var contentDigest = http.headers["content-digest"] || http.headers["Content-Digest"];
984
+ if (contentDigest) {
985
+ signatureInfo.contentDigestVerification = verifyContentDigest(contentDigest, result.body);
986
+ }
987
+ }
988
+
989
+ // Extract key information from params
990
+ if (sigData.params.keyid) {
991
+ try {
992
+ var keyBuffer = _base64url["default"].toBuffer(sigData.params.keyid);
993
+ result.keys[sigName] = {
994
+ keyid: sigData.params.keyid,
995
+ keyBuffer: keyBuffer,
996
+ algorithm: sigData.params.alg || "unknown"
997
+ };
998
+ } catch (e) {
999
+ // If keyid is not base64url encoded, store as-is
1000
+ result.keys[sigName] = {
1001
+ keyid: sigData.params.keyid,
1002
+ algorithm: sigData.params.alg || "unknown"
1003
+ };
1004
+ }
1005
+ }
1006
+ result.signatures[sigName] = signatureInfo;
1007
+ }
1008
+ return result;
1009
+ };
1010
+
1011
+ /**
1012
+ * Verify if a message has valid HTTP signature structure
1013
+ * @param {Object} http - HTTP message object
1014
+ * @returns {boolean} True if message has valid signature structure
1015
+ */
1016
+ var hasValidSignature = exports.hasValidSignature = function hasValidSignature(http) {
1017
+ var hasSignature = (http.headers.signature || http.headers.Signature) !== undefined;
1018
+ var hasSignatureInput = (http.headers["signature-input"] || http.headers["Signature-Input"]) !== undefined;
1019
+ return hasSignature && hasSignatureInput;
1020
+ };
1021
+
1022
+ /**
1023
+ * Verify content-digest header against body
1024
+ * @param {string} contentDigest - Content-Digest header value
1025
+ * @param {string|Buffer} body - Request/response body
1026
+ * @returns {Object} Verification result with digest info
1027
+ */
1028
+ var verifyContentDigest = exports.verifyContentDigest = function verifyContentDigest(contentDigest, body) {
1029
+ // Parse content-digest header format: algorithm=:base64digest:
1030
+ var match = contentDigest.match(/([^=]+)=:([^:]+):/);
1031
+ if (!match) {
1032
+ return {
1033
+ valid: false,
1034
+ error: "Invalid content-digest format"
1035
+ };
1036
+ }
1037
+ var _match = _slicedToArray(match, 3),
1038
+ algorithm = _match[1],
1039
+ expectedDigest = _match[2];
1040
+ try {
1041
+ // Convert body to Buffer if needed
1042
+ var bodyBuffer = typeof body === "string" ? Buffer.from(body, "utf-8") : body;
1043
+
1044
+ // Calculate digest based on algorithm
1045
+ var actualDigest;
1046
+ var crypto = require("crypto");
1047
+ if (algorithm === "sha-256") {
1048
+ var hash = crypto.createHash("sha256");
1049
+ hash.update(bodyBuffer);
1050
+ actualDigest = hash.digest("base64");
1051
+ } else if (algorithm === "sha-512") {
1052
+ var _hash = crypto.createHash("sha512");
1053
+ _hash.update(bodyBuffer);
1054
+ actualDigest = _hash.digest("base64");
1055
+ } else {
1056
+ return {
1057
+ valid: false,
1058
+ error: "Unsupported algorithm: ".concat(algorithm)
1059
+ };
1060
+ }
1061
+ return {
1062
+ valid: actualDigest === expectedDigest,
1063
+ algorithm: algorithm,
1064
+ expectedDigest: expectedDigest,
1065
+ actualDigest: actualDigest,
1066
+ matches: actualDigest === expectedDigest
1067
+ };
1068
+ } catch (error) {
1069
+ return {
1070
+ valid: false,
1071
+ error: error.message
1072
+ };
1073
+ }
1074
+ };
1075
+
1076
+ /**
1077
+ * Get all signature names from a message
1078
+ * @param {Object} http - HTTP message object
1079
+ * @returns {Array} Array of signature names
1080
+ */
1081
+ var getSignatureNames = exports.getSignatureNames = function getSignatureNames(http) {
1082
+ var signatureInput = http.headers["signature-input"] || http.headers["Signature-Input"];
1083
+ if (!signatureInput) return [];
1084
+ var inputs = (0, _signerUtils.decodeSigInput)(signatureInput);
1085
+ return Object.keys(inputs);
1086
+ };