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.
- package/cjs/bin_to_str.js +44 -0
- package/cjs/collect-body-keys.js +470 -0
- package/cjs/encode-array-item.js +110 -0
- package/cjs/encode-utils.js +236 -0
- package/cjs/encode.js +1318 -0
- package/cjs/erl_json.js +317 -0
- package/cjs/erl_str.js +1037 -0
- package/cjs/flat.js +222 -0
- package/cjs/http-message-signatures/httpbis.js +489 -0
- package/cjs/http-message-signatures/index.js +25 -0
- package/cjs/http-message-signatures/structured-header.js +129 -0
- package/cjs/httpsig.js +716 -0
- package/cjs/httpsig2.js +1160 -0
- package/cjs/id.js +470 -0
- package/cjs/index.js +63 -0
- package/cjs/send.js +194 -0
- package/cjs/signer-utils.js +617 -0
- package/cjs/signer.js +606 -0
- package/cjs/structured.js +296 -0
- package/cjs/test.js +27 -0
- package/cjs/utils.js +42 -0
- package/esm/bin_to_str.js +46 -0
- package/esm/collect-body-keys.js +436 -0
- package/esm/encode-array-item.js +112 -0
- package/esm/encode-utils.js +185 -0
- package/esm/encode.js +1219 -0
- package/esm/erl_json.js +289 -0
- package/esm/erl_str.js +1139 -0
- package/esm/flat.js +196 -0
- package/esm/http-message-signatures/httpbis.js +438 -0
- package/esm/http-message-signatures/index.js +4 -0
- package/esm/http-message-signatures/structured-header.js +105 -0
- package/esm/httpsig.js +658 -0
- package/esm/httpsig2.js +1097 -0
- package/esm/id.js +459 -0
- package/esm/index.js +4 -0
- package/esm/package.json +3 -0
- package/esm/send.js +124 -0
- package/esm/signer-utils.js +494 -0
- package/esm/signer.js +452 -0
- package/esm/structured.js +269 -0
- package/esm/test.js +6 -0
- package/esm/utils.js +28 -0
- package/package.json +28 -0
package/cjs/httpsig.js
ADDED
|
@@ -0,0 +1,716 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.httpsig_from = httpsig_from;
|
|
7
|
+
exports.httpsig_to = httpsig_to;
|
|
8
|
+
var _crypto = _interopRequireDefault(require("crypto"));
|
|
9
|
+
var _flat = require("./flat.js");
|
|
10
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
|
|
11
|
+
function _toArray(r) { return _arrayWithHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableRest(); }
|
|
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 _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); }
|
|
17
|
+
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; }
|
|
18
|
+
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; }
|
|
19
|
+
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; }
|
|
20
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
|
21
|
+
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); }
|
|
22
|
+
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; } } }; }
|
|
23
|
+
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
|
24
|
+
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."); }
|
|
25
|
+
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; } }
|
|
26
|
+
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; }
|
|
27
|
+
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; } }
|
|
28
|
+
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } // httpsig.js - JavaScript implementation of HTTP Signature codec
|
|
29
|
+
var CRLF = "\r\n";
|
|
30
|
+
var DOUBLE_CRLF = CRLF + CRLF;
|
|
31
|
+
var MAX_HEADER_LENGTH = 4096;
|
|
32
|
+
|
|
33
|
+
// Helper to normalize keys (lowercase only, no underscore conversion)
|
|
34
|
+
function normalizeKey(key) {
|
|
35
|
+
if (typeof key === "string") {
|
|
36
|
+
return key.toLowerCase();
|
|
37
|
+
}
|
|
38
|
+
return String(key).toLowerCase();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Helper to check if a value is an ID (43 character base64url string)
|
|
42
|
+
function isId(value) {
|
|
43
|
+
return typeof value === "string" && value.length === 43 && /^[A-Za-z0-9_-]+$/.test(value);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Helper to encode structured field dictionary
|
|
47
|
+
function encodeSfDict(dict) {
|
|
48
|
+
var items = [];
|
|
49
|
+
for (var _i = 0, _Object$entries = Object.entries(dict); _i < _Object$entries.length; _i++) {
|
|
50
|
+
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
51
|
+
key = _Object$entries$_i[0],
|
|
52
|
+
value = _Object$entries$_i[1];
|
|
53
|
+
if (typeof value === "string") {
|
|
54
|
+
items.push("".concat(key, "=\"").concat(value, "\""));
|
|
55
|
+
} else {
|
|
56
|
+
items.push("".concat(key, "=").concat(value));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return items.join(", ");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Helper to parse structured field dictionary
|
|
63
|
+
function parseSfDict(str) {
|
|
64
|
+
var dict = {};
|
|
65
|
+
if (!str) return dict;
|
|
66
|
+
var parts = str.split(/,\s*/);
|
|
67
|
+
var _iterator = _createForOfIteratorHelper(parts),
|
|
68
|
+
_step;
|
|
69
|
+
try {
|
|
70
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
71
|
+
var part = _step.value;
|
|
72
|
+
var match = part.match(/^([^=]+)=(.+)$/);
|
|
73
|
+
if (match) {
|
|
74
|
+
var key = match[1].trim();
|
|
75
|
+
var value = match[2].trim();
|
|
76
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
77
|
+
value = value.slice(1, -1);
|
|
78
|
+
}
|
|
79
|
+
dict[key] = value;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} catch (err) {
|
|
83
|
+
_iterator.e(err);
|
|
84
|
+
} finally {
|
|
85
|
+
_iterator.f();
|
|
86
|
+
}
|
|
87
|
+
return dict;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Helper to generate boundary from parts
|
|
91
|
+
function boundaryFromParts(parts) {
|
|
92
|
+
var bodyBin = parts.map(function (p) {
|
|
93
|
+
return p.body;
|
|
94
|
+
}).join(CRLF);
|
|
95
|
+
var hash = _crypto["default"].createHash("sha256");
|
|
96
|
+
hash.update(bodyBin);
|
|
97
|
+
return hash.digest("base64url");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Helper to determine inline key
|
|
101
|
+
function inlineKey(msg) {
|
|
102
|
+
var inlineBodyKey = msg["inline-body-key"];
|
|
103
|
+
if (inlineBodyKey) {
|
|
104
|
+
return [{}, inlineBodyKey];
|
|
105
|
+
}
|
|
106
|
+
if ("body" in msg) {
|
|
107
|
+
return [{}, "body"];
|
|
108
|
+
}
|
|
109
|
+
if ("data" in msg) {
|
|
110
|
+
return [{
|
|
111
|
+
"inline-body-key": "data"
|
|
112
|
+
}, "data"];
|
|
113
|
+
}
|
|
114
|
+
return [{}, "body"];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Group IDs into ao-ids field
|
|
118
|
+
function groupIds(map) {
|
|
119
|
+
var idDict = {};
|
|
120
|
+
var stripped = {};
|
|
121
|
+
for (var _i2 = 0, _Object$entries2 = Object.entries(map); _i2 < _Object$entries2.length; _i2++) {
|
|
122
|
+
var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
|
|
123
|
+
key = _Object$entries2$_i[0],
|
|
124
|
+
value = _Object$entries2$_i[1];
|
|
125
|
+
if (isId(key) && typeof value === "string") {
|
|
126
|
+
// Store with lowercase key as in Erlang
|
|
127
|
+
idDict[key.toLowerCase()] = value;
|
|
128
|
+
} else {
|
|
129
|
+
stripped[key] = value;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (Object.keys(idDict).length > 0) {
|
|
133
|
+
var items = [];
|
|
134
|
+
for (var _i3 = 0, _Object$entries3 = Object.entries(idDict); _i3 < _Object$entries3.length; _i3++) {
|
|
135
|
+
var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
|
|
136
|
+
k = _Object$entries3$_i[0],
|
|
137
|
+
v = _Object$entries3$_i[1];
|
|
138
|
+
items.push("".concat(k, "=\"").concat(v, "\""));
|
|
139
|
+
}
|
|
140
|
+
stripped["ao-ids"] = items.join(", ");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Return IDs as lowercase in the result since they will be normalized
|
|
144
|
+
// when processed as headers
|
|
145
|
+
for (var _i4 = 0, _Object$entries4 = Object.entries(idDict); _i4 < _Object$entries4.length; _i4++) {
|
|
146
|
+
var _Object$entries4$_i = _slicedToArray(_Object$entries4[_i4], 2),
|
|
147
|
+
_k = _Object$entries4$_i[0],
|
|
148
|
+
_v = _Object$entries4$_i[1];
|
|
149
|
+
stripped[_k] = _v;
|
|
150
|
+
}
|
|
151
|
+
return stripped;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Ungroup IDs from ao-ids field
|
|
155
|
+
function ungroupIds(msg) {
|
|
156
|
+
if (!msg["ao-ids"]) return msg;
|
|
157
|
+
var result = _objectSpread({}, msg);
|
|
158
|
+
delete result["ao-ids"];
|
|
159
|
+
var dict = parseSfDict(msg["ao-ids"]);
|
|
160
|
+
for (var _i5 = 0, _Object$entries5 = Object.entries(dict); _i5 < _Object$entries5.length; _i5++) {
|
|
161
|
+
var _Object$entries5$_i = _slicedToArray(_Object$entries5[_i5], 2),
|
|
162
|
+
key = _Object$entries5$_i[0],
|
|
163
|
+
value = _Object$entries5$_i[1];
|
|
164
|
+
// ao-ids keys are lowercase, use them as-is
|
|
165
|
+
result[key] = value;
|
|
166
|
+
}
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Group maps for body encoding - following Erlang logic exactly
|
|
171
|
+
function groupMaps(map) {
|
|
172
|
+
var parent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
|
|
173
|
+
var top = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
174
|
+
if (_typeof(map) !== "object" || map === null || Array.isArray(map) || Buffer.isBuffer(map)) {
|
|
175
|
+
return top;
|
|
176
|
+
}
|
|
177
|
+
var flattened = {};
|
|
178
|
+
var newTop = _objectSpread({}, top);
|
|
179
|
+
|
|
180
|
+
// Process entries in sorted order for consistency
|
|
181
|
+
var entries = Object.entries(map).sort(function (_ref, _ref2) {
|
|
182
|
+
var _ref3 = _slicedToArray(_ref, 1),
|
|
183
|
+
a = _ref3[0];
|
|
184
|
+
var _ref4 = _slicedToArray(_ref2, 1),
|
|
185
|
+
b = _ref4[0];
|
|
186
|
+
return a.localeCompare(b);
|
|
187
|
+
});
|
|
188
|
+
var _iterator2 = _createForOfIteratorHelper(entries),
|
|
189
|
+
_step2;
|
|
190
|
+
try {
|
|
191
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
192
|
+
var _step2$value = _slicedToArray(_step2.value, 2),
|
|
193
|
+
key = _step2$value[0],
|
|
194
|
+
value = _step2$value[1];
|
|
195
|
+
// Normalize keys to lowercase
|
|
196
|
+
var normKey = normalizeKey(key);
|
|
197
|
+
var flatK = parent ? "".concat(parent, "/").concat(normKey) : normKey;
|
|
198
|
+
if (_typeof(value) === "object" && value !== null && !Array.isArray(value) && !Buffer.isBuffer(value)) {
|
|
199
|
+
// Recursively process nested objects
|
|
200
|
+
newTop = groupMaps(value, flatK, newTop);
|
|
201
|
+
} else if (typeof value === "string" && value.length > MAX_HEADER_LENGTH) {
|
|
202
|
+
// Value too large for header, lift to top level
|
|
203
|
+
newTop[flatK] = value;
|
|
204
|
+
} else if (Buffer.isBuffer(value) && value.length > MAX_HEADER_LENGTH) {
|
|
205
|
+
// Large buffers also get lifted to top level
|
|
206
|
+
newTop[flatK] = value;
|
|
207
|
+
} else {
|
|
208
|
+
// Keep in current flattened map
|
|
209
|
+
flattened[normKey] = value;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} catch (err) {
|
|
213
|
+
_iterator2.e(err);
|
|
214
|
+
} finally {
|
|
215
|
+
_iterator2.f();
|
|
216
|
+
}
|
|
217
|
+
if (Object.keys(flattened).length === 0) {
|
|
218
|
+
return newTop;
|
|
219
|
+
} else if (parent) {
|
|
220
|
+
// Add flattened map under parent key
|
|
221
|
+
return _objectSpread(_objectSpread({}, newTop), {}, _defineProperty({}, parent, flattened));
|
|
222
|
+
} else {
|
|
223
|
+
// Merge flattened with top level
|
|
224
|
+
return _objectSpread(_objectSpread({}, newTop), flattened);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Encode multipart body part
|
|
229
|
+
function encodeBodyPart(partName, bodyPart, inlineKey) {
|
|
230
|
+
var disposition = partName === inlineKey ? "inline" : "form-data;name=\"".concat(partName, "\"");
|
|
231
|
+
var isInline = partName === inlineKey;
|
|
232
|
+
if (_typeof(bodyPart) === "object" && bodyPart !== null && !Array.isArray(bodyPart) && !Buffer.isBuffer(bodyPart)) {
|
|
233
|
+
// Check if this part has ao-types
|
|
234
|
+
var hasAoTypes = "ao-types" in bodyPart;
|
|
235
|
+
if (hasAoTypes) {
|
|
236
|
+
// For parts WITH ao-types: sort all entries alphabetically
|
|
237
|
+
var allEntries = [];
|
|
238
|
+
|
|
239
|
+
// Collect all entries except body
|
|
240
|
+
for (var _i6 = 0, _Object$entries6 = Object.entries(bodyPart); _i6 < _Object$entries6.length; _i6++) {
|
|
241
|
+
var _Object$entries6$_i = _slicedToArray(_Object$entries6[_i6], 2),
|
|
242
|
+
key = _Object$entries6$_i[0],
|
|
243
|
+
value = _Object$entries6$_i[1];
|
|
244
|
+
if (key === "body") continue;
|
|
245
|
+
if (key === "ao-types") {
|
|
246
|
+
allEntries.push({
|
|
247
|
+
key: "ao-types",
|
|
248
|
+
line: "ao-types: ".concat(value)
|
|
249
|
+
});
|
|
250
|
+
} else {
|
|
251
|
+
// Handle Buffer values properly
|
|
252
|
+
var valueStr = value;
|
|
253
|
+
if (Buffer.isBuffer(value)) {
|
|
254
|
+
// Use binary/latin1 encoding to preserve all byte values 0-255
|
|
255
|
+
valueStr = value.toString("binary");
|
|
256
|
+
}
|
|
257
|
+
allEntries.push({
|
|
258
|
+
key: key,
|
|
259
|
+
line: "".concat(key, ": ").concat(valueStr)
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Add content-disposition
|
|
265
|
+
allEntries.push({
|
|
266
|
+
key: "content-disposition",
|
|
267
|
+
line: "content-disposition: ".concat(disposition)
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Sort alphabetically by key
|
|
271
|
+
allEntries.sort(function (a, b) {
|
|
272
|
+
return a.key.localeCompare(b.key);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// Build the lines
|
|
276
|
+
var lines = allEntries.map(function (entry) {
|
|
277
|
+
return entry.line;
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// Body handling
|
|
281
|
+
var body = bodyPart.body || "";
|
|
282
|
+
if (body) {
|
|
283
|
+
lines.push(""); // Always add empty line before body
|
|
284
|
+
lines.push(body);
|
|
285
|
+
}
|
|
286
|
+
return lines.join(CRLF);
|
|
287
|
+
} else {
|
|
288
|
+
// For parts WITHOUT ao-types
|
|
289
|
+
var _allEntries = [];
|
|
290
|
+
for (var _i7 = 0, _Object$entries7 = Object.entries(bodyPart); _i7 < _Object$entries7.length; _i7++) {
|
|
291
|
+
var _Object$entries7$_i = _slicedToArray(_Object$entries7[_i7], 2),
|
|
292
|
+
_key = _Object$entries7$_i[0],
|
|
293
|
+
_value = _Object$entries7$_i[1];
|
|
294
|
+
if (_key === "body") continue;
|
|
295
|
+
// Handle Buffer values properly
|
|
296
|
+
var _valueStr = _value;
|
|
297
|
+
if (Buffer.isBuffer(_value)) {
|
|
298
|
+
// Use binary/latin1 encoding to preserve all byte values 0-255
|
|
299
|
+
_valueStr = _value.toString("binary");
|
|
300
|
+
}
|
|
301
|
+
_allEntries.push({
|
|
302
|
+
key: _key,
|
|
303
|
+
line: "".concat(_key, ": ").concat(_valueStr)
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
var _lines = [];
|
|
307
|
+
if (isInline) {
|
|
308
|
+
// Inline parts without ao-types: sort ALL fields alphabetically including content-disposition
|
|
309
|
+
_allEntries.push({
|
|
310
|
+
key: "content-disposition",
|
|
311
|
+
line: "content-disposition: ".concat(disposition)
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// Sort by key
|
|
315
|
+
_allEntries.sort(function (a, b) {
|
|
316
|
+
return a.key.localeCompare(b.key);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// Extract the lines
|
|
320
|
+
_lines.push.apply(_lines, _toConsumableArray(_allEntries.map(function (entry) {
|
|
321
|
+
return entry.line;
|
|
322
|
+
})));
|
|
323
|
+
} else {
|
|
324
|
+
// Regular parts: content-disposition first, then fields
|
|
325
|
+
_lines.push("content-disposition: ".concat(disposition));
|
|
326
|
+
_lines.push.apply(_lines, _toConsumableArray(_allEntries.map(function (entry) {
|
|
327
|
+
return entry.line;
|
|
328
|
+
})));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Body handling
|
|
332
|
+
var _body = bodyPart.body || "";
|
|
333
|
+
if (_body) {
|
|
334
|
+
_lines.push(""); // Always add empty line before body
|
|
335
|
+
_lines.push(_body);
|
|
336
|
+
}
|
|
337
|
+
return _lines.join(CRLF);
|
|
338
|
+
}
|
|
339
|
+
} else if (typeof bodyPart === "string" || Buffer.isBuffer(bodyPart)) {
|
|
340
|
+
return "content-disposition: ".concat(disposition).concat(DOUBLE_CRLF).concat(bodyPart);
|
|
341
|
+
}
|
|
342
|
+
return "";
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Parse multipart body
|
|
346
|
+
function parseMultipart(contentType, body) {
|
|
347
|
+
var boundaryMatch = contentType.match(/boundary="?([^";\s]+)"?/);
|
|
348
|
+
if (!boundaryMatch) return {};
|
|
349
|
+
var boundary = boundaryMatch[1];
|
|
350
|
+
var boundaryDelim = "--".concat(boundary);
|
|
351
|
+
var endBoundary = "--".concat(boundary, "--");
|
|
352
|
+
|
|
353
|
+
// Remove the final boundary terminator if present
|
|
354
|
+
var bodyContent = body;
|
|
355
|
+
if (bodyContent.endsWith(endBoundary)) {
|
|
356
|
+
bodyContent = bodyContent.substring(0, bodyContent.lastIndexOf(endBoundary));
|
|
357
|
+
}
|
|
358
|
+
var parts = bodyContent.split(new RegExp("\\r?\\n?".concat(boundaryDelim, "\\r?\\n"))).filter(function (p) {
|
|
359
|
+
return p && p.trim() && !p.startsWith("--");
|
|
360
|
+
});
|
|
361
|
+
var result = {};
|
|
362
|
+
var bodyKeysList = [];
|
|
363
|
+
var _iterator3 = _createForOfIteratorHelper(parts),
|
|
364
|
+
_step3;
|
|
365
|
+
try {
|
|
366
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
367
|
+
var part = _step3.value;
|
|
368
|
+
var _part$split = part.split(DOUBLE_CRLF),
|
|
369
|
+
_part$split2 = _toArray(_part$split),
|
|
370
|
+
headerBlock = _part$split2[0],
|
|
371
|
+
bodyParts = _part$split2.slice(1);
|
|
372
|
+
var partBody = bodyParts.join(DOUBLE_CRLF);
|
|
373
|
+
|
|
374
|
+
// Remove trailing CRLF
|
|
375
|
+
partBody = partBody.replace(/\r?\n?$/, "");
|
|
376
|
+
var headers = {};
|
|
377
|
+
var headerLines = headerBlock.split(/\r?\n/);
|
|
378
|
+
var _iterator4 = _createForOfIteratorHelper(headerLines),
|
|
379
|
+
_step4;
|
|
380
|
+
try {
|
|
381
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
382
|
+
var line = _step4.value;
|
|
383
|
+
var colonIndex = line.indexOf(": ");
|
|
384
|
+
if (colonIndex > 0) {
|
|
385
|
+
var name = line.substring(0, colonIndex).toLowerCase();
|
|
386
|
+
var value = line.substring(colonIndex + 2);
|
|
387
|
+
headers[name] = value;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
} catch (err) {
|
|
391
|
+
_iterator4.e(err);
|
|
392
|
+
} finally {
|
|
393
|
+
_iterator4.f();
|
|
394
|
+
}
|
|
395
|
+
var disposition = headers["content-disposition"];
|
|
396
|
+
if (!disposition) continue;
|
|
397
|
+
var partName = void 0;
|
|
398
|
+
if (disposition === "inline") {
|
|
399
|
+
partName = "body";
|
|
400
|
+
bodyKeysList.push("body");
|
|
401
|
+
} else {
|
|
402
|
+
var nameMatch = disposition.match(/name="([^"]+)"/);
|
|
403
|
+
partName = nameMatch ? nameMatch[1] : null;
|
|
404
|
+
if (partName) {
|
|
405
|
+
// Add the top-level key for this part
|
|
406
|
+
var topLevelKey = partName.split("/")[0];
|
|
407
|
+
bodyKeysList.push(topLevelKey);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (!partName) continue;
|
|
411
|
+
var restHeaders = _objectSpread({}, headers);
|
|
412
|
+
delete restHeaders["content-disposition"];
|
|
413
|
+
if (Object.keys(restHeaders).length === 0) {
|
|
414
|
+
result[partName] = partBody;
|
|
415
|
+
} else if (!partBody) {
|
|
416
|
+
result[partName] = restHeaders;
|
|
417
|
+
} else {
|
|
418
|
+
result[partName] = _objectSpread(_objectSpread({}, restHeaders), {}, {
|
|
419
|
+
body: partBody
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
} catch (err) {
|
|
424
|
+
_iterator3.e(err);
|
|
425
|
+
} finally {
|
|
426
|
+
_iterator3.f();
|
|
427
|
+
}
|
|
428
|
+
if (bodyKeysList.length > 0) {
|
|
429
|
+
// Format as structured field list, preserving order and duplicates
|
|
430
|
+
result["body-keys"] = bodyKeysList.map(function (k) {
|
|
431
|
+
return "\"".concat(k, "\"");
|
|
432
|
+
}).join(", ");
|
|
433
|
+
}
|
|
434
|
+
return result;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Add content-digest header
|
|
438
|
+
function addContentDigest(msg) {
|
|
439
|
+
if (!msg.body) return msg;
|
|
440
|
+
var hash = _crypto["default"].createHash("sha256");
|
|
441
|
+
|
|
442
|
+
// Handle both string and Buffer bodies
|
|
443
|
+
if (Buffer.isBuffer(msg.body)) {
|
|
444
|
+
hash.update(msg.body);
|
|
445
|
+
} else {
|
|
446
|
+
// For strings, use binary encoding to match how the multipart body is encoded
|
|
447
|
+
hash.update(msg.body, "binary");
|
|
448
|
+
}
|
|
449
|
+
var digest = hash.digest("base64");
|
|
450
|
+
return _objectSpread(_objectSpread({}, msg), {}, {
|
|
451
|
+
"content-digest": "sha-256=:".concat(digest, ":")
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Convert HTTP message to TABM
|
|
457
|
+
*/
|
|
458
|
+
function httpsig_from(http) {
|
|
459
|
+
if (typeof http === "string") return http;
|
|
460
|
+
var body = http.body || "";
|
|
461
|
+
var _inlineKey = inlineKey(http),
|
|
462
|
+
_inlineKey2 = _slicedToArray(_inlineKey, 2),
|
|
463
|
+
inlinedFieldHdrs = _inlineKey2[0],
|
|
464
|
+
inlinedKey = _inlineKey2[1];
|
|
465
|
+
var headers = _objectSpread({}, http);
|
|
466
|
+
delete headers.body;
|
|
467
|
+
delete headers["body-keys"];
|
|
468
|
+
var contentType = headers["content-type"];
|
|
469
|
+
var withBodyKeys = headers;
|
|
470
|
+
|
|
471
|
+
// Parse multipart body if present
|
|
472
|
+
if (body && contentType && contentType.includes("multipart")) {
|
|
473
|
+
var parsed = parseMultipart(contentType, body);
|
|
474
|
+
|
|
475
|
+
// Handle the body-keys from the original HTTP message
|
|
476
|
+
if (http["body-keys"]) {
|
|
477
|
+
// Parse the existing body-keys and ensure they're in quoted format
|
|
478
|
+
var bodyKeys = http["body-keys"];
|
|
479
|
+
if (typeof bodyKeys === "string") {
|
|
480
|
+
if (!bodyKeys.includes('"')) {
|
|
481
|
+
// Convert unquoted format to quoted format
|
|
482
|
+
parsed["body-keys"] = bodyKeys.split(/,\s*/).map(function (k) {
|
|
483
|
+
return "\"".concat(k.trim(), "\"");
|
|
484
|
+
}).join(", ");
|
|
485
|
+
} else {
|
|
486
|
+
// Already quoted, use as-is
|
|
487
|
+
parsed["body-keys"] = bodyKeys;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
withBodyKeys = _objectSpread(_objectSpread({}, headers), parsed);
|
|
492
|
+
|
|
493
|
+
// Convert flat structure to nested using flat.js
|
|
494
|
+
var flat = {};
|
|
495
|
+
for (var _i8 = 0, _Object$entries8 = Object.entries(withBodyKeys); _i8 < _Object$entries8.length; _i8++) {
|
|
496
|
+
var _Object$entries8$_i = _slicedToArray(_Object$entries8[_i8], 2),
|
|
497
|
+
key = _Object$entries8$_i[0],
|
|
498
|
+
value = _Object$entries8$_i[1];
|
|
499
|
+
if (key.includes("/")) {
|
|
500
|
+
flat[key] = value;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
if (Object.keys(flat).length > 0) {
|
|
504
|
+
// Use flat_from to convert flat structure to nested
|
|
505
|
+
var nested = (0, _flat.flat_from)(flat);
|
|
506
|
+
for (var _i9 = 0, _Object$entries9 = Object.entries(nested); _i9 < _Object$entries9.length; _i9++) {
|
|
507
|
+
var _Object$entries9$_i = _slicedToArray(_Object$entries9[_i9], 2),
|
|
508
|
+
_key2 = _Object$entries9$_i[0],
|
|
509
|
+
_value2 = _Object$entries9$_i[1];
|
|
510
|
+
withBodyKeys[_key2] = _value2;
|
|
511
|
+
}
|
|
512
|
+
for (var _i0 = 0, _Object$keys = Object.keys(flat); _i0 < _Object$keys.length; _i0++) {
|
|
513
|
+
var _key3 = _Object$keys[_i0];
|
|
514
|
+
delete withBodyKeys[_key3];
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
} else if (body) {
|
|
518
|
+
withBodyKeys[inlinedKey] = body;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Ungroup IDs
|
|
522
|
+
var withIds = ungroupIds(withBodyKeys);
|
|
523
|
+
|
|
524
|
+
// Remove signature-related headers and content-digest
|
|
525
|
+
var result = _objectSpread({}, withIds);
|
|
526
|
+
delete result.signature;
|
|
527
|
+
delete result["signature-input"];
|
|
528
|
+
delete result.commitments;
|
|
529
|
+
delete result["content-digest"];
|
|
530
|
+
|
|
531
|
+
// Extract hashpaths if any
|
|
532
|
+
for (var _i1 = 0, _Object$keys2 = Object.keys(result); _i1 < _Object$keys2.length; _i1++) {
|
|
533
|
+
var _key4 = _Object$keys2[_i1];
|
|
534
|
+
if (_key4.startsWith("hashpath")) {
|
|
535
|
+
delete result[_key4];
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return result;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Convert TABM to HTTP message
|
|
543
|
+
*/
|
|
544
|
+
function httpsig_to(tabm) {
|
|
545
|
+
if (typeof tabm === "string") return tabm;
|
|
546
|
+
|
|
547
|
+
// Group IDs
|
|
548
|
+
var withGroupedIds = groupIds(tabm);
|
|
549
|
+
|
|
550
|
+
// Remove private and signature-related keys
|
|
551
|
+
var stripped = _objectSpread({}, withGroupedIds);
|
|
552
|
+
delete stripped.commitments;
|
|
553
|
+
delete stripped.signature;
|
|
554
|
+
delete stripped["signature-input"];
|
|
555
|
+
delete stripped.priv;
|
|
556
|
+
var _inlineKey3 = inlineKey(tabm),
|
|
557
|
+
_inlineKey4 = _slicedToArray(_inlineKey3, 2),
|
|
558
|
+
inlineFieldHdrs = _inlineKey4[0],
|
|
559
|
+
inlineKeyVal = _inlineKey4[1];
|
|
560
|
+
|
|
561
|
+
// Check if this is a flat structure that should stay as headers
|
|
562
|
+
// A flat structure has no nested objects (maps)
|
|
563
|
+
var hasNestedMaps = Object.values(stripped).some(function (value) {
|
|
564
|
+
return _typeof(value) === "object" && value !== null && !Array.isArray(value) && !Buffer.isBuffer(value);
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
// If it's just a flat map with strings/primitives, keep as headers
|
|
568
|
+
// This matches Erlang's behavior where flat maps don't become multipart
|
|
569
|
+
if (!hasNestedMaps) {
|
|
570
|
+
// For flat structures, just return with normalized keys
|
|
571
|
+
// This matches Erlang which returns the map unchanged
|
|
572
|
+
var result = _objectSpread({}, inlineFieldHdrs);
|
|
573
|
+
for (var _i10 = 0, _Object$entries0 = Object.entries(stripped); _i10 < _Object$entries0.length; _i10++) {
|
|
574
|
+
var _Object$entries0$_i = _slicedToArray(_Object$entries0[_i10], 2),
|
|
575
|
+
key = _Object$entries0$_i[0],
|
|
576
|
+
value = _Object$entries0$_i[1];
|
|
577
|
+
// Convert Buffers to strings if they're UTF-8 text
|
|
578
|
+
if (Buffer.isBuffer(value)) {
|
|
579
|
+
try {
|
|
580
|
+
var str = value.toString("utf8");
|
|
581
|
+
// Check if it's valid UTF-8 that can be safely converted
|
|
582
|
+
if (Buffer.from(str, "utf8").equals(value)) {
|
|
583
|
+
// Check if all characters are printable
|
|
584
|
+
var isPrintable = true;
|
|
585
|
+
for (var i = 0; i < str.length; i++) {
|
|
586
|
+
var code = str.charCodeAt(i);
|
|
587
|
+
if (!(code >= 32 && code <= 126) && code !== 9 && code !== 10 && code !== 13) {
|
|
588
|
+
isPrintable = false;
|
|
589
|
+
break;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
if (isPrintable) {
|
|
593
|
+
result[key] = str;
|
|
594
|
+
} else {
|
|
595
|
+
result[key] = value;
|
|
596
|
+
}
|
|
597
|
+
} else {
|
|
598
|
+
result[key] = value;
|
|
599
|
+
}
|
|
600
|
+
} catch (e) {
|
|
601
|
+
result[key] = value;
|
|
602
|
+
}
|
|
603
|
+
} else {
|
|
604
|
+
result[key] = value;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// Handle inline body key - move data from inline key to body
|
|
609
|
+
if (inlineKeyVal && inlineKeyVal !== "body" && result[inlineKeyVal]) {
|
|
610
|
+
result.body = result[inlineKeyVal];
|
|
611
|
+
delete result[inlineKeyVal];
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// If there's a body, add content-digest
|
|
615
|
+
if (result.body) {
|
|
616
|
+
return addContentDigest(result);
|
|
617
|
+
}
|
|
618
|
+
return result;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// Original multipart logic for nested structures
|
|
622
|
+
var bodyMap = {};
|
|
623
|
+
var headers = _objectSpread({}, inlineFieldHdrs);
|
|
624
|
+
|
|
625
|
+
// Process each field - ao-types at top level should go to headers
|
|
626
|
+
for (var _i11 = 0, _Object$entries1 = Object.entries(stripped); _i11 < _Object$entries1.length; _i11++) {
|
|
627
|
+
var _Object$entries1$_i = _slicedToArray(_Object$entries1[_i11], 2),
|
|
628
|
+
_key5 = _Object$entries1$_i[0],
|
|
629
|
+
_value3 = _Object$entries1$_i[1];
|
|
630
|
+
if (_key5 === "ao-types") {
|
|
631
|
+
// Top-level ao-types goes to headers only
|
|
632
|
+
// Convert Buffer to string if needed
|
|
633
|
+
if (Buffer.isBuffer(_value3)) {
|
|
634
|
+
headers[_key5] = _value3.toString("utf8");
|
|
635
|
+
} else {
|
|
636
|
+
headers[_key5] = _value3;
|
|
637
|
+
}
|
|
638
|
+
} else if (_key5 === "body" || _key5 === inlineKeyVal) {
|
|
639
|
+
bodyMap[_key5 === inlineKeyVal ? inlineKeyVal : "body"] = _value3;
|
|
640
|
+
} else if (_typeof(_value3) === "object" && _value3 !== null && !Array.isArray(_value3) && !Buffer.isBuffer(_value3)) {
|
|
641
|
+
bodyMap[_key5] = _value3;
|
|
642
|
+
} else if (typeof _value3 === "string" && _value3.length <= MAX_HEADER_LENGTH && _key5 !== "ao-types") {
|
|
643
|
+
headers[normalizeKey(_key5)] = _value3;
|
|
644
|
+
} else if (Buffer.isBuffer(_value3) && _value3.length <= MAX_HEADER_LENGTH && _key5 !== "ao-types") {
|
|
645
|
+
// Convert Buffers to strings for headers
|
|
646
|
+
var _str = _value3.toString("utf8");
|
|
647
|
+
headers[normalizeKey(_key5)] = _str;
|
|
648
|
+
} else if (_key5 !== "ao-types") {
|
|
649
|
+
// Only add to bodyMap if it's not ao-types
|
|
650
|
+
bodyMap[_key5] = _value3;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// Handle body encoding
|
|
655
|
+
var groupedBodyMap = groupMaps(bodyMap);
|
|
656
|
+
if (Object.keys(groupedBodyMap).length === 0) {
|
|
657
|
+
return headers;
|
|
658
|
+
} else if (Object.keys(groupedBodyMap).length === 1 && groupedBodyMap[inlineKeyVal] && typeof groupedBodyMap[inlineKeyVal] === "string") {
|
|
659
|
+
var _result = _objectSpread(_objectSpread({}, headers), {}, {
|
|
660
|
+
body: groupedBodyMap[inlineKeyVal]
|
|
661
|
+
});
|
|
662
|
+
return addContentDigest(_result);
|
|
663
|
+
} else {
|
|
664
|
+
// Multipart body
|
|
665
|
+
var parts = [];
|
|
666
|
+
var bodyKeysList = [];
|
|
667
|
+
var sortedEntries = Object.entries(groupedBodyMap).sort(function (_ref5, _ref6) {
|
|
668
|
+
var _ref7 = _slicedToArray(_ref5, 1),
|
|
669
|
+
a = _ref7[0];
|
|
670
|
+
var _ref8 = _slicedToArray(_ref6, 1),
|
|
671
|
+
b = _ref8[0];
|
|
672
|
+
return a.localeCompare(b);
|
|
673
|
+
});
|
|
674
|
+
var _iterator5 = _createForOfIteratorHelper(sortedEntries),
|
|
675
|
+
_step5;
|
|
676
|
+
try {
|
|
677
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
678
|
+
var _step5$value = _slicedToArray(_step5.value, 2),
|
|
679
|
+
_key6 = _step5$value[0],
|
|
680
|
+
_value4 = _step5$value[1];
|
|
681
|
+
if (_typeof(_value4) === "object" && _value4 !== null && Object.keys(_value4).length === 1 && "body" in _value4) {
|
|
682
|
+
var encoded = encodeBodyPart("".concat(_key6, "/body"), _value4, "body");
|
|
683
|
+
parts.push({
|
|
684
|
+
name: "".concat(_key6, "/body"),
|
|
685
|
+
body: encoded
|
|
686
|
+
});
|
|
687
|
+
bodyKeysList.push(_key6);
|
|
688
|
+
} else {
|
|
689
|
+
var _encoded = encodeBodyPart(_key6, _value4, inlineKeyVal);
|
|
690
|
+
parts.push({
|
|
691
|
+
name: _key6,
|
|
692
|
+
body: _encoded
|
|
693
|
+
});
|
|
694
|
+
bodyKeysList.push(_key6);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
} catch (err) {
|
|
698
|
+
_iterator5.e(err);
|
|
699
|
+
} finally {
|
|
700
|
+
_iterator5.f();
|
|
701
|
+
}
|
|
702
|
+
var boundary = boundaryFromParts(parts);
|
|
703
|
+
var bodyParts = parts.map(function (p) {
|
|
704
|
+
return "--".concat(boundary).concat(CRLF).concat(p.body);
|
|
705
|
+
});
|
|
706
|
+
var finalBody = bodyParts.join(CRLF) + "".concat(CRLF, "--").concat(boundary, "--");
|
|
707
|
+
var _result2 = _objectSpread(_objectSpread({}, headers), {}, {
|
|
708
|
+
"body-keys": bodyKeysList.map(function (k) {
|
|
709
|
+
return "\"".concat(k, "\"");
|
|
710
|
+
}).join(", "),
|
|
711
|
+
"content-type": "multipart/form-data; boundary=\"".concat(boundary, "\""),
|
|
712
|
+
body: finalBody
|
|
713
|
+
});
|
|
714
|
+
return addContentDigest(_result2);
|
|
715
|
+
}
|
|
716
|
+
}
|