hbsig 0.2.0 → 0.2.2
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 +38 -80
- package/esm/httpsig.js +36 -75
- package/package.json +1 -1
package/cjs/httpsig.js
CHANGED
|
@@ -244,20 +244,25 @@ function encodeBodyPart(partName, bodyPart, inlineKey) {
|
|
|
244
244
|
value = _Object$entries6$_i[1];
|
|
245
245
|
if (key === "body") continue;
|
|
246
246
|
if (key === "ao-types") {
|
|
247
|
+
// Keep ao-types as-is (Buffer or string)
|
|
248
|
+
var valueStr = value;
|
|
249
|
+
if (Buffer.isBuffer(value)) {
|
|
250
|
+
valueStr = value.toString("binary");
|
|
251
|
+
}
|
|
247
252
|
allEntries.push({
|
|
248
253
|
key: "ao-types",
|
|
249
|
-
line: "ao-types: ".concat(
|
|
254
|
+
line: "ao-types: ".concat(valueStr)
|
|
250
255
|
});
|
|
251
256
|
} else {
|
|
252
257
|
// Handle Buffer values properly
|
|
253
|
-
var
|
|
258
|
+
var _valueStr = value;
|
|
254
259
|
if (Buffer.isBuffer(value)) {
|
|
255
260
|
// Use binary/latin1 encoding to preserve all byte values 0-255
|
|
256
|
-
|
|
261
|
+
_valueStr = value.toString("binary");
|
|
257
262
|
}
|
|
258
263
|
allEntries.push({
|
|
259
264
|
key: key,
|
|
260
|
-
line: "".concat(key, ": ").concat(
|
|
265
|
+
line: "".concat(key, ": ").concat(_valueStr)
|
|
261
266
|
});
|
|
262
267
|
}
|
|
263
268
|
}
|
|
@@ -294,14 +299,14 @@ function encodeBodyPart(partName, bodyPart, inlineKey) {
|
|
|
294
299
|
_value = _Object$entries7$_i[1];
|
|
295
300
|
if (_key === "body") continue;
|
|
296
301
|
// Handle Buffer values properly
|
|
297
|
-
var
|
|
302
|
+
var _valueStr2 = _value;
|
|
298
303
|
if (Buffer.isBuffer(_value)) {
|
|
299
304
|
// Use binary/latin1 encoding to preserve all byte values 0-255
|
|
300
|
-
|
|
305
|
+
_valueStr2 = _value.toString("binary");
|
|
301
306
|
}
|
|
302
307
|
_allEntries.push({
|
|
303
308
|
key: _key,
|
|
304
|
-
line: "".concat(_key, ": ").concat(
|
|
309
|
+
line: "".concat(_key, ": ").concat(_valueStr2)
|
|
305
310
|
});
|
|
306
311
|
}
|
|
307
312
|
var _lines = [];
|
|
@@ -343,17 +348,17 @@ function encodeBodyPart(partName, bodyPart, inlineKey) {
|
|
|
343
348
|
return "";
|
|
344
349
|
}
|
|
345
350
|
|
|
346
|
-
// Helper to detect if a
|
|
347
|
-
function isBinaryData(
|
|
348
|
-
// Check first 100
|
|
349
|
-
for (var i = 0; i < Math.min(
|
|
350
|
-
var
|
|
351
|
+
// Helper to detect if a Buffer contains binary data
|
|
352
|
+
function isBinaryData(buf) {
|
|
353
|
+
// Check first 100 bytes for binary indicators
|
|
354
|
+
for (var i = 0; i < Math.min(buf.length, 100); i++) {
|
|
355
|
+
var _byte = buf[i];
|
|
351
356
|
// Non-printable chars (except CR/LF/TAB)
|
|
352
|
-
if (
|
|
357
|
+
if (_byte < 32 && _byte !== 9 && _byte !== 10 && _byte !== 13) return true;
|
|
353
358
|
// High byte range that's not valid text
|
|
354
|
-
if (
|
|
359
|
+
if (_byte > 126 && _byte < 160) return true;
|
|
355
360
|
// Null byte is definitely binary
|
|
356
|
-
if (
|
|
361
|
+
if (_byte === 0) return true;
|
|
357
362
|
}
|
|
358
363
|
return false;
|
|
359
364
|
}
|
|
@@ -409,14 +414,12 @@ function parseMultipart(contentType, body) {
|
|
|
409
414
|
var name = line.substring(0, colonIndex).toLowerCase();
|
|
410
415
|
var value = line.substring(colonIndex + 2);
|
|
411
416
|
|
|
412
|
-
//
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
417
|
+
// Check if this might be binary data by looking at the first part
|
|
418
|
+
var valueBuf = Buffer.from(value, "binary");
|
|
419
|
+
var mightBeBinary = isBinaryData(valueBuf);
|
|
420
|
+
if (mightBeBinary) {
|
|
421
|
+
// Binary data may contain embedded newlines, so read until next header
|
|
416
422
|
var valueStart = currentPos + colonIndex + 2;
|
|
417
|
-
|
|
418
|
-
// Look ahead to find where this field really ends
|
|
419
|
-
// The next header will start with a valid header name followed by ": "
|
|
420
423
|
var searchPos = valueStart;
|
|
421
424
|
var valueEnd = headerBlock.length;
|
|
422
425
|
|
|
@@ -424,43 +427,27 @@ function parseMultipart(contentType, body) {
|
|
|
424
427
|
while (searchPos < headerBlock.length) {
|
|
425
428
|
var nextNewline = headerBlock.indexOf("\n", searchPos);
|
|
426
429
|
if (nextNewline === -1) break;
|
|
427
|
-
|
|
428
|
-
// Check if what follows looks like a header
|
|
429
430
|
var nextLineStart = nextNewline + 1;
|
|
430
431
|
var nextColon = headerBlock.indexOf(":", nextLineStart);
|
|
431
|
-
|
|
432
|
-
// Valid header should have colon relatively close to line start
|
|
433
432
|
if (nextColon > nextLineStart && nextColon < nextLineStart + 50) {
|
|
434
|
-
// Check if the text before colon looks like a header name (ASCII text)
|
|
435
433
|
var possibleHeaderName = headerBlock.substring(nextLineStart, nextColon);
|
|
436
434
|
var looksLikeHeader = /^[a-zA-Z0-9-]+$/.test(possibleHeaderName);
|
|
437
435
|
if (looksLikeHeader) {
|
|
438
|
-
// Found the next header, value ends at the newline before it
|
|
439
436
|
valueEnd = nextNewline;
|
|
440
437
|
break;
|
|
441
438
|
}
|
|
442
439
|
}
|
|
443
440
|
searchPos = nextNewline + 1;
|
|
444
441
|
}
|
|
445
|
-
|
|
446
|
-
// Extract the full value, trimming any trailing whitespace
|
|
447
442
|
value = headerBlock.substring(valueStart, valueEnd);
|
|
448
|
-
|
|
449
|
-
// Remove trailing CR if present (since we found the LF)
|
|
450
443
|
if (value.endsWith("\r")) {
|
|
451
444
|
value = value.substring(0, value.length - 1);
|
|
452
445
|
}
|
|
453
|
-
|
|
454
|
-
// Convert to Buffer to preserve binary
|
|
455
446
|
headers[name] = Buffer.from(value, "binary");
|
|
456
447
|
currentPos = valueEnd + 1;
|
|
457
448
|
} else {
|
|
458
449
|
// Regular text field
|
|
459
|
-
|
|
460
|
-
headers[name] = Buffer.from(value, "binary");
|
|
461
|
-
} else {
|
|
462
|
-
headers[name] = value;
|
|
463
|
-
}
|
|
450
|
+
headers[name] = value;
|
|
464
451
|
currentPos = lineEnd + (headerBlock[lineEnd] === "\r" ? 2 : 1);
|
|
465
452
|
}
|
|
466
453
|
} else {
|
|
@@ -490,7 +477,8 @@ function parseMultipart(contentType, body) {
|
|
|
490
477
|
|
|
491
478
|
// If there's body content in the inline part, add it as 'body'
|
|
492
479
|
if (partBody) {
|
|
493
|
-
|
|
480
|
+
// Convert back to Buffer to preserve binary data
|
|
481
|
+
result[partName] = Buffer.from(partBody, "binary");
|
|
494
482
|
}
|
|
495
483
|
} else {
|
|
496
484
|
// Handle named form-data parts
|
|
@@ -504,12 +492,14 @@ function parseMultipart(contentType, body) {
|
|
|
504
492
|
var _restHeaders = _objectSpread({}, headers);
|
|
505
493
|
delete _restHeaders["content-disposition"];
|
|
506
494
|
if (Object.keys(_restHeaders).length === 0) {
|
|
507
|
-
|
|
495
|
+
// Convert body back to Buffer
|
|
496
|
+
result[partName] = Buffer.from(partBody, "binary");
|
|
508
497
|
} else if (!partBody) {
|
|
509
498
|
result[partName] = _restHeaders;
|
|
510
499
|
} else {
|
|
500
|
+
// Convert body back to Buffer
|
|
511
501
|
result[partName] = _objectSpread(_objectSpread({}, _restHeaders), {}, {
|
|
512
|
-
body: partBody
|
|
502
|
+
body: Buffer.from(partBody, "binary")
|
|
513
503
|
});
|
|
514
504
|
}
|
|
515
505
|
}
|
|
@@ -667,35 +657,8 @@ function httpsig_to(tabm) {
|
|
|
667
657
|
var _Object$entries1$_i = _slicedToArray(_Object$entries1[_i11], 2),
|
|
668
658
|
key = _Object$entries1$_i[0],
|
|
669
659
|
value = _Object$entries1$_i[1];
|
|
670
|
-
//
|
|
671
|
-
|
|
672
|
-
try {
|
|
673
|
-
var str = value.toString("utf8");
|
|
674
|
-
// Check if it's valid UTF-8 that can be safely converted
|
|
675
|
-
if (Buffer.from(str, "utf8").equals(value)) {
|
|
676
|
-
// Check if all characters are printable
|
|
677
|
-
var isPrintable = true;
|
|
678
|
-
for (var i = 0; i < str.length; i++) {
|
|
679
|
-
var code = str.charCodeAt(i);
|
|
680
|
-
if (!(code >= 32 && code <= 126) && code !== 9 && code !== 10 && code !== 13) {
|
|
681
|
-
isPrintable = false;
|
|
682
|
-
break;
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
if (isPrintable) {
|
|
686
|
-
result[key] = str;
|
|
687
|
-
} else {
|
|
688
|
-
result[key] = value;
|
|
689
|
-
}
|
|
690
|
-
} else {
|
|
691
|
-
result[key] = value;
|
|
692
|
-
}
|
|
693
|
-
} catch (e) {
|
|
694
|
-
result[key] = value;
|
|
695
|
-
}
|
|
696
|
-
} else {
|
|
697
|
-
result[key] = value;
|
|
698
|
-
}
|
|
660
|
+
// Keep Buffers as Buffers - don't convert to strings
|
|
661
|
+
result[key] = value;
|
|
699
662
|
}
|
|
700
663
|
|
|
701
664
|
// Handle inline body key - move data from inline key to body
|
|
@@ -722,12 +685,8 @@ function httpsig_to(tabm) {
|
|
|
722
685
|
_value4 = _Object$entries10$_i[1];
|
|
723
686
|
if (_key5 === "ao-types") {
|
|
724
687
|
// Top-level ao-types goes to headers only
|
|
725
|
-
//
|
|
726
|
-
|
|
727
|
-
headers[_key5] = _value4.toString("utf8");
|
|
728
|
-
} else {
|
|
729
|
-
headers[_key5] = _value4;
|
|
730
|
-
}
|
|
688
|
+
// Keep as Buffer if it's a Buffer, otherwise use as-is
|
|
689
|
+
headers[_key5] = _value4;
|
|
731
690
|
} else if (_key5 === "body" || _key5 === inlineKeyVal) {
|
|
732
691
|
bodyMap[_key5 === inlineKeyVal ? inlineKeyVal : "body"] = _value4;
|
|
733
692
|
} else if (_typeof(_value4) === "object" && _value4 !== null && !Array.isArray(_value4) && !Buffer.isBuffer(_value4)) {
|
|
@@ -735,9 +694,8 @@ function httpsig_to(tabm) {
|
|
|
735
694
|
} else if (typeof _value4 === "string" && _value4.length <= MAX_HEADER_LENGTH && _key5 !== "ao-types") {
|
|
736
695
|
headers[normalizeKey(_key5)] = _value4;
|
|
737
696
|
} else if (Buffer.isBuffer(_value4) && _value4.length <= MAX_HEADER_LENGTH && _key5 !== "ao-types") {
|
|
738
|
-
//
|
|
739
|
-
|
|
740
|
-
headers[normalizeKey(_key5)] = _str;
|
|
697
|
+
// Keep buffers as buffers for headers
|
|
698
|
+
headers[normalizeKey(_key5)] = _value4;
|
|
741
699
|
} else if (_key5 !== "ao-types") {
|
|
742
700
|
// Only add to bodyMap if it's not ao-types
|
|
743
701
|
bodyMap[_key5] = _value4;
|
package/esm/httpsig.js
CHANGED
|
@@ -204,7 +204,12 @@ function encodeBodyPart(partName, bodyPart, inlineKey) {
|
|
|
204
204
|
if (key === "body") continue
|
|
205
205
|
|
|
206
206
|
if (key === "ao-types") {
|
|
207
|
-
|
|
207
|
+
// Keep ao-types as-is (Buffer or string)
|
|
208
|
+
let valueStr = value
|
|
209
|
+
if (Buffer.isBuffer(value)) {
|
|
210
|
+
valueStr = value.toString("binary")
|
|
211
|
+
}
|
|
212
|
+
allEntries.push({ key: "ao-types", line: `ao-types: ${valueStr}` })
|
|
208
213
|
} else {
|
|
209
214
|
// Handle Buffer values properly
|
|
210
215
|
let valueStr = value
|
|
@@ -286,17 +291,17 @@ function encodeBodyPart(partName, bodyPart, inlineKey) {
|
|
|
286
291
|
return ""
|
|
287
292
|
}
|
|
288
293
|
|
|
289
|
-
// Helper to detect if a
|
|
290
|
-
function isBinaryData(
|
|
291
|
-
// Check first 100
|
|
292
|
-
for (let i = 0; i < Math.min(
|
|
293
|
-
const
|
|
294
|
+
// Helper to detect if a Buffer contains binary data
|
|
295
|
+
function isBinaryData(buf) {
|
|
296
|
+
// Check first 100 bytes for binary indicators
|
|
297
|
+
for (let i = 0; i < Math.min(buf.length, 100); i++) {
|
|
298
|
+
const byte = buf[i]
|
|
294
299
|
// Non-printable chars (except CR/LF/TAB)
|
|
295
|
-
if (
|
|
300
|
+
if (byte < 32 && byte !== 9 && byte !== 10 && byte !== 13) return true
|
|
296
301
|
// High byte range that's not valid text
|
|
297
|
-
if (
|
|
302
|
+
if (byte > 126 && byte < 160) return true
|
|
298
303
|
// Null byte is definitely binary
|
|
299
|
-
if (
|
|
304
|
+
if (byte === 0) return true
|
|
300
305
|
}
|
|
301
306
|
return false
|
|
302
307
|
}
|
|
@@ -355,14 +360,13 @@ function parseMultipart(contentType, body) {
|
|
|
355
360
|
const name = line.substring(0, colonIndex).toLowerCase()
|
|
356
361
|
let value = line.substring(colonIndex + 2)
|
|
357
362
|
|
|
358
|
-
//
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
// We need to read until we find the next header or end of headers
|
|
362
|
-
let valueStart = currentPos + colonIndex + 2
|
|
363
|
+
// Check if this might be binary data by looking at the first part
|
|
364
|
+
const valueBuf = Buffer.from(value, "binary")
|
|
365
|
+
const mightBeBinary = isBinaryData(valueBuf)
|
|
363
366
|
|
|
364
|
-
|
|
365
|
-
//
|
|
367
|
+
if (mightBeBinary) {
|
|
368
|
+
// Binary data may contain embedded newlines, so read until next header
|
|
369
|
+
let valueStart = currentPos + colonIndex + 2
|
|
366
370
|
let searchPos = valueStart
|
|
367
371
|
let valueEnd = headerBlock.length
|
|
368
372
|
|
|
@@ -371,13 +375,10 @@ function parseMultipart(contentType, body) {
|
|
|
371
375
|
let nextNewline = headerBlock.indexOf("\n", searchPos)
|
|
372
376
|
if (nextNewline === -1) break
|
|
373
377
|
|
|
374
|
-
// Check if what follows looks like a header
|
|
375
378
|
let nextLineStart = nextNewline + 1
|
|
376
379
|
let nextColon = headerBlock.indexOf(":", nextLineStart)
|
|
377
380
|
|
|
378
|
-
// Valid header should have colon relatively close to line start
|
|
379
381
|
if (nextColon > nextLineStart && nextColon < nextLineStart + 50) {
|
|
380
|
-
// Check if the text before colon looks like a header name (ASCII text)
|
|
381
382
|
let possibleHeaderName = headerBlock.substring(
|
|
382
383
|
nextLineStart,
|
|
383
384
|
nextColon
|
|
@@ -385,7 +386,6 @@ function parseMultipart(contentType, body) {
|
|
|
385
386
|
let looksLikeHeader = /^[a-zA-Z0-9-]+$/.test(possibleHeaderName)
|
|
386
387
|
|
|
387
388
|
if (looksLikeHeader) {
|
|
388
|
-
// Found the next header, value ends at the newline before it
|
|
389
389
|
valueEnd = nextNewline
|
|
390
390
|
break
|
|
391
391
|
}
|
|
@@ -393,24 +393,16 @@ function parseMultipart(contentType, body) {
|
|
|
393
393
|
searchPos = nextNewline + 1
|
|
394
394
|
}
|
|
395
395
|
|
|
396
|
-
// Extract the full value, trimming any trailing whitespace
|
|
397
396
|
value = headerBlock.substring(valueStart, valueEnd)
|
|
398
|
-
|
|
399
|
-
// Remove trailing CR if present (since we found the LF)
|
|
400
397
|
if (value.endsWith("\r")) {
|
|
401
398
|
value = value.substring(0, value.length - 1)
|
|
402
399
|
}
|
|
403
400
|
|
|
404
|
-
// Convert to Buffer to preserve binary
|
|
405
401
|
headers[name] = Buffer.from(value, "binary")
|
|
406
402
|
currentPos = valueEnd + 1
|
|
407
403
|
} else {
|
|
408
404
|
// Regular text field
|
|
409
|
-
|
|
410
|
-
headers[name] = Buffer.from(value, "binary")
|
|
411
|
-
} else {
|
|
412
|
-
headers[name] = value
|
|
413
|
-
}
|
|
405
|
+
headers[name] = value
|
|
414
406
|
currentPos = lineEnd + (headerBlock[lineEnd] === "\r" ? 2 : 1)
|
|
415
407
|
}
|
|
416
408
|
} else {
|
|
@@ -439,7 +431,8 @@ function parseMultipart(contentType, body) {
|
|
|
439
431
|
|
|
440
432
|
// If there's body content in the inline part, add it as 'body'
|
|
441
433
|
if (partBody) {
|
|
442
|
-
|
|
434
|
+
// Convert back to Buffer to preserve binary data
|
|
435
|
+
result[partName] = Buffer.from(partBody, "binary")
|
|
443
436
|
}
|
|
444
437
|
} else {
|
|
445
438
|
// Handle named form-data parts
|
|
@@ -456,11 +449,16 @@ function parseMultipart(contentType, body) {
|
|
|
456
449
|
delete restHeaders["content-disposition"]
|
|
457
450
|
|
|
458
451
|
if (Object.keys(restHeaders).length === 0) {
|
|
459
|
-
|
|
452
|
+
// Convert body back to Buffer
|
|
453
|
+
result[partName] = Buffer.from(partBody, "binary")
|
|
460
454
|
} else if (!partBody) {
|
|
461
455
|
result[partName] = restHeaders
|
|
462
456
|
} else {
|
|
463
|
-
|
|
457
|
+
// Convert body back to Buffer
|
|
458
|
+
result[partName] = {
|
|
459
|
+
...restHeaders,
|
|
460
|
+
body: Buffer.from(partBody, "binary"),
|
|
461
|
+
}
|
|
464
462
|
}
|
|
465
463
|
}
|
|
466
464
|
}
|
|
@@ -611,40 +609,8 @@ export function httpsig_to(tabm) {
|
|
|
611
609
|
const result = { ...inlineFieldHdrs }
|
|
612
610
|
|
|
613
611
|
for (const [key, value] of Object.entries(stripped)) {
|
|
614
|
-
//
|
|
615
|
-
|
|
616
|
-
try {
|
|
617
|
-
const str = value.toString("utf8")
|
|
618
|
-
// Check if it's valid UTF-8 that can be safely converted
|
|
619
|
-
if (Buffer.from(str, "utf8").equals(value)) {
|
|
620
|
-
// Check if all characters are printable
|
|
621
|
-
let isPrintable = true
|
|
622
|
-
for (let i = 0; i < str.length; i++) {
|
|
623
|
-
const code = str.charCodeAt(i)
|
|
624
|
-
if (
|
|
625
|
-
!(code >= 32 && code <= 126) &&
|
|
626
|
-
code !== 9 &&
|
|
627
|
-
code !== 10 &&
|
|
628
|
-
code !== 13
|
|
629
|
-
) {
|
|
630
|
-
isPrintable = false
|
|
631
|
-
break
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
if (isPrintable) {
|
|
635
|
-
result[key] = str
|
|
636
|
-
} else {
|
|
637
|
-
result[key] = value
|
|
638
|
-
}
|
|
639
|
-
} else {
|
|
640
|
-
result[key] = value
|
|
641
|
-
}
|
|
642
|
-
} catch (e) {
|
|
643
|
-
result[key] = value
|
|
644
|
-
}
|
|
645
|
-
} else {
|
|
646
|
-
result[key] = value
|
|
647
|
-
}
|
|
612
|
+
// Keep Buffers as Buffers - don't convert to strings
|
|
613
|
+
result[key] = value
|
|
648
614
|
}
|
|
649
615
|
|
|
650
616
|
// Handle inline body key - move data from inline key to body
|
|
@@ -669,12 +635,8 @@ export function httpsig_to(tabm) {
|
|
|
669
635
|
for (const [key, value] of Object.entries(stripped)) {
|
|
670
636
|
if (key === "ao-types") {
|
|
671
637
|
// Top-level ao-types goes to headers only
|
|
672
|
-
//
|
|
673
|
-
|
|
674
|
-
headers[key] = value.toString("utf8")
|
|
675
|
-
} else {
|
|
676
|
-
headers[key] = value
|
|
677
|
-
}
|
|
638
|
+
// Keep as Buffer if it's a Buffer, otherwise use as-is
|
|
639
|
+
headers[key] = value
|
|
678
640
|
} else if (key === "body" || key === inlineKeyVal) {
|
|
679
641
|
bodyMap[key === inlineKeyVal ? inlineKeyVal : "body"] = value
|
|
680
642
|
} else if (
|
|
@@ -695,9 +657,8 @@ export function httpsig_to(tabm) {
|
|
|
695
657
|
value.length <= MAX_HEADER_LENGTH &&
|
|
696
658
|
key !== "ao-types"
|
|
697
659
|
) {
|
|
698
|
-
//
|
|
699
|
-
|
|
700
|
-
headers[normalizeKey(key)] = str
|
|
660
|
+
// Keep buffers as buffers for headers
|
|
661
|
+
headers[normalizeKey(key)] = value
|
|
701
662
|
} else if (key !== "ao-types") {
|
|
702
663
|
// Only add to bodyMap if it's not ao-types
|
|
703
664
|
bodyMap[key] = value
|