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