hbsig 0.2.4 → 0.2.5
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 +47 -61
- package/esm/httpsig.js +42 -51
- package/package.json +1 -1
package/cjs/httpsig.js
CHANGED
|
@@ -348,48 +348,36 @@ function encodeBodyPart(partName, bodyPart, inlineKey) {
|
|
|
348
348
|
return "";
|
|
349
349
|
}
|
|
350
350
|
|
|
351
|
-
//
|
|
352
|
-
function isBinaryData(
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
buf
|
|
359
|
-
} else {
|
|
360
|
-
return false;
|
|
351
|
+
// Helper to detect if a Buffer contains binary data
|
|
352
|
+
function isBinaryData(buf) {
|
|
353
|
+
// Check first 512 bytes for binary indicators
|
|
354
|
+
var checkLength = Math.min(buf.length, 512);
|
|
355
|
+
|
|
356
|
+
// Any null byte means binary
|
|
357
|
+
for (var i = 0; i < checkLength; i++) {
|
|
358
|
+
if (buf[i] === 0) return true;
|
|
361
359
|
}
|
|
362
360
|
|
|
363
|
-
//
|
|
364
|
-
var sampleSize = Math.min(buf.length, 1024);
|
|
365
|
-
var nullCount = 0;
|
|
361
|
+
// Count non-text bytes
|
|
366
362
|
var controlCount = 0;
|
|
367
363
|
var highByteCount = 0;
|
|
368
|
-
for (var
|
|
369
|
-
var _byte = buf[
|
|
370
|
-
|
|
371
|
-
// Null bytes are a strong indicator of binary
|
|
372
|
-
if (_byte === 0) {
|
|
373
|
-
nullCount++;
|
|
374
|
-
if (nullCount > 0) return true; // Even one null byte indicates binary
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// Control characters (except common text ones: TAB, LF, CR)
|
|
364
|
+
for (var _i8 = 0; _i8 < checkLength; _i8++) {
|
|
365
|
+
var _byte = buf[_i8];
|
|
366
|
+
// Non-printable chars (except CR/LF/TAB)
|
|
378
367
|
if (_byte < 32 && _byte !== 9 && _byte !== 10 && _byte !== 13) {
|
|
379
368
|
controlCount++;
|
|
380
369
|
}
|
|
381
|
-
|
|
382
|
-
// High byte values that aren't valid UTF-8 continuation bytes
|
|
370
|
+
// High byte range
|
|
383
371
|
if (_byte > 127) {
|
|
384
372
|
highByteCount++;
|
|
385
373
|
}
|
|
386
374
|
}
|
|
387
375
|
|
|
388
|
-
// If more than
|
|
389
|
-
if (controlCount /
|
|
376
|
+
// If more than 5% are control chars, likely binary
|
|
377
|
+
if (controlCount / checkLength > 0.05) return true;
|
|
390
378
|
|
|
391
|
-
// If more than
|
|
392
|
-
if (highByteCount /
|
|
379
|
+
// If more than 20% are high bytes, likely binary
|
|
380
|
+
if (highByteCount / checkLength > 0.2) return true;
|
|
393
381
|
return false;
|
|
394
382
|
}
|
|
395
383
|
|
|
@@ -488,32 +476,30 @@ function parseMultipart(contentType, body) {
|
|
|
488
476
|
searchPos = nextNewline + 1;
|
|
489
477
|
}
|
|
490
478
|
|
|
491
|
-
// Extract the value
|
|
479
|
+
// Extract the value - valueEnd points to \n which is NOT part of the value
|
|
492
480
|
var value = headerBlock.substring(valueStart, valueEnd);
|
|
493
481
|
|
|
494
|
-
//
|
|
495
|
-
|
|
496
|
-
if (
|
|
497
|
-
//
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
} else if (value.endsWith("\n")) {
|
|
501
|
-
value = value.substring(0, value.length - 1);
|
|
502
|
-
} else if (value.endsWith("\r")) {
|
|
482
|
+
// Determine if this is binary data FIRST (before trimming)
|
|
483
|
+
var isBinary = value.length > 0 && isBinaryData(Buffer.from(value, "binary"));
|
|
484
|
+
if (isBinary) {
|
|
485
|
+
// Binary data: only remove trailing \r if it's part of CRLF separator
|
|
486
|
+
// (when valueEnd points to \n and value ends with \r)
|
|
487
|
+
if (valueEnd < headerBlock.length && headerBlock[valueEnd] === "\n" && value.endsWith("\r")) {
|
|
503
488
|
value = value.substring(0, value.length - 1);
|
|
504
489
|
}
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
// Determine if this is binary data
|
|
508
|
-
if (value.length > 0 && isBinaryData(value)) {
|
|
509
490
|
headers[name] = Buffer.from(value, "binary");
|
|
510
491
|
} else {
|
|
492
|
+
// Text data: remove all trailing CRLF/LF (these are line separators, not data)
|
|
493
|
+
value = value.replace(/[\r\n]+$/, "");
|
|
511
494
|
headers[name] = value;
|
|
512
495
|
}
|
|
513
496
|
|
|
514
497
|
// Move to the end of this header's value
|
|
515
|
-
currentPos = valueEnd
|
|
516
|
-
if (headerBlock[
|
|
498
|
+
currentPos = valueEnd;
|
|
499
|
+
if (currentPos < headerBlock.length && headerBlock[currentPos] === "\n") {
|
|
500
|
+
currentPos++;
|
|
501
|
+
}
|
|
502
|
+
if (currentPos < headerBlock.length && headerBlock[currentPos] === "\r") {
|
|
517
503
|
currentPos++;
|
|
518
504
|
}
|
|
519
505
|
}
|
|
@@ -530,8 +516,8 @@ function parseMultipart(contentType, body) {
|
|
|
530
516
|
delete restHeaders["content-disposition"];
|
|
531
517
|
|
|
532
518
|
// Add each header from the inline part to the top level of result
|
|
533
|
-
for (var
|
|
534
|
-
var _Object$entries8$_i = _slicedToArray(_Object$entries8[
|
|
519
|
+
for (var _i9 = 0, _Object$entries8 = Object.entries(restHeaders); _i9 < _Object$entries8.length; _i9++) {
|
|
520
|
+
var _Object$entries8$_i = _slicedToArray(_Object$entries8[_i9], 2),
|
|
535
521
|
key = _Object$entries8$_i[0],
|
|
536
522
|
_value2 = _Object$entries8$_i[1];
|
|
537
523
|
result[key] = _value2;
|
|
@@ -539,8 +525,8 @@ function parseMultipart(contentType, body) {
|
|
|
539
525
|
|
|
540
526
|
// If there's body content in the inline part, add it as 'body'
|
|
541
527
|
if (partBody) {
|
|
542
|
-
// Keep as
|
|
543
|
-
result[partName] = isBinaryData(partBody) ? Buffer.from(partBody, "binary") : partBody;
|
|
528
|
+
// Keep as string unless it's binary data
|
|
529
|
+
result[partName] = isBinaryData(Buffer.from(partBody, "binary")) ? Buffer.from(partBody, "binary") : partBody;
|
|
544
530
|
}
|
|
545
531
|
} else {
|
|
546
532
|
// Handle named form-data parts
|
|
@@ -554,15 +540,15 @@ function parseMultipart(contentType, body) {
|
|
|
554
540
|
var _restHeaders = _objectSpread({}, headers);
|
|
555
541
|
delete _restHeaders["content-disposition"];
|
|
556
542
|
if (Object.keys(_restHeaders).length === 0) {
|
|
557
|
-
// Keep as
|
|
558
|
-
result[partName] = isBinaryData(partBody) ? Buffer.from(partBody, "binary") : partBody;
|
|
543
|
+
// Keep as string unless it's binary data
|
|
544
|
+
result[partName] = isBinaryData(Buffer.from(partBody, "binary")) ? Buffer.from(partBody, "binary") : partBody;
|
|
559
545
|
} else if (!partBody) {
|
|
560
546
|
// ao-types should stay with this part, not be extracted
|
|
561
547
|
result[partName] = _restHeaders;
|
|
562
548
|
} else {
|
|
563
|
-
// Keep as
|
|
549
|
+
// Keep as string unless it's binary data
|
|
564
550
|
result[partName] = _objectSpread(_objectSpread({}, _restHeaders), {}, {
|
|
565
|
-
body: isBinaryData(partBody) ? Buffer.from(partBody, "binary") : partBody
|
|
551
|
+
body: isBinaryData(Buffer.from(partBody, "binary")) ? Buffer.from(partBody, "binary") : partBody
|
|
566
552
|
});
|
|
567
553
|
}
|
|
568
554
|
}
|
|
@@ -639,8 +625,8 @@ function httpsig_from(http) {
|
|
|
639
625
|
// Convert flat structure to nested using flat.js
|
|
640
626
|
var flat = {};
|
|
641
627
|
var nonFlat = {};
|
|
642
|
-
for (var
|
|
643
|
-
var _Object$entries9$_i = _slicedToArray(_Object$entries9[
|
|
628
|
+
for (var _i0 = 0, _Object$entries9 = Object.entries(withBodyKeys); _i0 < _Object$entries9.length; _i0++) {
|
|
629
|
+
var _Object$entries9$_i = _slicedToArray(_Object$entries9[_i0], 2),
|
|
644
630
|
key = _Object$entries9$_i[0],
|
|
645
631
|
value = _Object$entries9$_i[1];
|
|
646
632
|
if (key.includes("/")) {
|
|
@@ -675,8 +661,8 @@ function httpsig_from(http) {
|
|
|
675
661
|
delete result["content-digest"];
|
|
676
662
|
|
|
677
663
|
// Extract hashpaths if any
|
|
678
|
-
for (var
|
|
679
|
-
var _key2 = _Object$keys[
|
|
664
|
+
for (var _i1 = 0, _Object$keys = Object.keys(result); _i1 < _Object$keys.length; _i1++) {
|
|
665
|
+
var _key2 = _Object$keys[_i1];
|
|
680
666
|
if (_key2.startsWith("hashpath")) {
|
|
681
667
|
delete result[_key2];
|
|
682
668
|
}
|
|
@@ -716,8 +702,8 @@ function httpsig_to(tabm) {
|
|
|
716
702
|
// For flat structures, just return with normalized keys
|
|
717
703
|
// This matches Erlang which returns the map unchanged
|
|
718
704
|
var result = _objectSpread({}, inlineFieldHdrs);
|
|
719
|
-
for (var
|
|
720
|
-
var _Object$entries0$_i = _slicedToArray(_Object$entries0[
|
|
705
|
+
for (var _i10 = 0, _Object$entries0 = Object.entries(stripped); _i10 < _Object$entries0.length; _i10++) {
|
|
706
|
+
var _Object$entries0$_i = _slicedToArray(_Object$entries0[_i10], 2),
|
|
721
707
|
key = _Object$entries0$_i[0],
|
|
722
708
|
value = _Object$entries0$_i[1];
|
|
723
709
|
// Keep Buffers as Buffers - don't convert to strings
|
|
@@ -742,8 +728,8 @@ function httpsig_to(tabm) {
|
|
|
742
728
|
var headers = _objectSpread({}, inlineFieldHdrs);
|
|
743
729
|
|
|
744
730
|
// Process each field - ao-types at top level should go to headers
|
|
745
|
-
for (var
|
|
746
|
-
var _Object$entries1$_i = _slicedToArray(_Object$entries1[
|
|
731
|
+
for (var _i11 = 0, _Object$entries1 = Object.entries(stripped); _i11 < _Object$entries1.length; _i11++) {
|
|
732
|
+
var _Object$entries1$_i = _slicedToArray(_Object$entries1[_i11], 2),
|
|
747
733
|
_key3 = _Object$entries1$_i[0],
|
|
748
734
|
_value3 = _Object$entries1$_i[1];
|
|
749
735
|
if (_key3 === "ao-types") {
|
package/esm/httpsig.js
CHANGED
|
@@ -291,50 +291,37 @@ function encodeBodyPart(partName, bodyPart, inlineKey) {
|
|
|
291
291
|
return ""
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
-
//
|
|
295
|
-
function isBinaryData(
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
buf = data
|
|
303
|
-
} else {
|
|
304
|
-
return false
|
|
294
|
+
// Helper to detect if a Buffer contains binary data
|
|
295
|
+
function isBinaryData(buf) {
|
|
296
|
+
// Check first 512 bytes for binary indicators
|
|
297
|
+
const checkLength = Math.min(buf.length, 512)
|
|
298
|
+
|
|
299
|
+
// Any null byte means binary
|
|
300
|
+
for (let i = 0; i < checkLength; i++) {
|
|
301
|
+
if (buf[i] === 0) return true
|
|
305
302
|
}
|
|
306
303
|
|
|
307
|
-
//
|
|
308
|
-
const sampleSize = Math.min(buf.length, 1024)
|
|
309
|
-
let nullCount = 0
|
|
304
|
+
// Count non-text bytes
|
|
310
305
|
let controlCount = 0
|
|
311
306
|
let highByteCount = 0
|
|
312
307
|
|
|
313
|
-
for (let i = 0; i <
|
|
308
|
+
for (let i = 0; i < checkLength; i++) {
|
|
314
309
|
const byte = buf[i]
|
|
315
|
-
|
|
316
|
-
// Null bytes are a strong indicator of binary
|
|
317
|
-
if (byte === 0) {
|
|
318
|
-
nullCount++
|
|
319
|
-
if (nullCount > 0) return true // Even one null byte indicates binary
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Control characters (except common text ones: TAB, LF, CR)
|
|
310
|
+
// Non-printable chars (except CR/LF/TAB)
|
|
323
311
|
if (byte < 32 && byte !== 9 && byte !== 10 && byte !== 13) {
|
|
324
312
|
controlCount++
|
|
325
313
|
}
|
|
326
|
-
|
|
327
|
-
// High byte values that aren't valid UTF-8 continuation bytes
|
|
314
|
+
// High byte range
|
|
328
315
|
if (byte > 127) {
|
|
329
316
|
highByteCount++
|
|
330
317
|
}
|
|
331
318
|
}
|
|
332
319
|
|
|
333
|
-
// If more than
|
|
334
|
-
if (controlCount /
|
|
320
|
+
// If more than 5% are control chars, likely binary
|
|
321
|
+
if (controlCount / checkLength > 0.05) return true
|
|
335
322
|
|
|
336
|
-
// If more than
|
|
337
|
-
if (highByteCount /
|
|
323
|
+
// If more than 20% are high bytes, likely binary
|
|
324
|
+
if (highByteCount / checkLength > 0.2) return true
|
|
338
325
|
|
|
339
326
|
return false
|
|
340
327
|
}
|
|
@@ -445,32 +432,36 @@ function parseMultipart(contentType, body) {
|
|
|
445
432
|
searchPos = nextNewline + 1
|
|
446
433
|
}
|
|
447
434
|
|
|
448
|
-
// Extract the value
|
|
435
|
+
// Extract the value - valueEnd points to \n which is NOT part of the value
|
|
449
436
|
let value = headerBlock.substring(valueStart, valueEnd)
|
|
450
437
|
|
|
451
|
-
//
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
438
|
+
// Determine if this is binary data FIRST (before trimming)
|
|
439
|
+
const isBinary =
|
|
440
|
+
value.length > 0 && isBinaryData(Buffer.from(value, "binary"))
|
|
441
|
+
|
|
442
|
+
if (isBinary) {
|
|
443
|
+
// Binary data: only remove trailing \r if it's part of CRLF separator
|
|
444
|
+
// (when valueEnd points to \n and value ends with \r)
|
|
445
|
+
if (
|
|
446
|
+
valueEnd < headerBlock.length &&
|
|
447
|
+
headerBlock[valueEnd] === "\n" &&
|
|
448
|
+
value.endsWith("\r")
|
|
449
|
+
) {
|
|
460
450
|
value = value.substring(0, value.length - 1)
|
|
461
451
|
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
// Determine if this is binary data
|
|
465
|
-
if (value.length > 0 && isBinaryData(value)) {
|
|
466
452
|
headers[name] = Buffer.from(value, "binary")
|
|
467
453
|
} else {
|
|
454
|
+
// Text data: remove all trailing CRLF/LF (these are line separators, not data)
|
|
455
|
+
value = value.replace(/[\r\n]+$/, "")
|
|
468
456
|
headers[name] = value
|
|
469
457
|
}
|
|
470
458
|
|
|
471
459
|
// Move to the end of this header's value
|
|
472
|
-
currentPos = valueEnd
|
|
473
|
-
if (headerBlock[
|
|
460
|
+
currentPos = valueEnd
|
|
461
|
+
if (currentPos < headerBlock.length && headerBlock[currentPos] === "\n") {
|
|
462
|
+
currentPos++
|
|
463
|
+
}
|
|
464
|
+
if (currentPos < headerBlock.length && headerBlock[currentPos] === "\r") {
|
|
474
465
|
currentPos++
|
|
475
466
|
}
|
|
476
467
|
}
|
|
@@ -495,8 +486,8 @@ function parseMultipart(contentType, body) {
|
|
|
495
486
|
|
|
496
487
|
// If there's body content in the inline part, add it as 'body'
|
|
497
488
|
if (partBody) {
|
|
498
|
-
// Keep as
|
|
499
|
-
result[partName] = isBinaryData(partBody)
|
|
489
|
+
// Keep as string unless it's binary data
|
|
490
|
+
result[partName] = isBinaryData(Buffer.from(partBody, "binary"))
|
|
500
491
|
? Buffer.from(partBody, "binary")
|
|
501
492
|
: partBody
|
|
502
493
|
}
|
|
@@ -515,18 +506,18 @@ function parseMultipart(contentType, body) {
|
|
|
515
506
|
delete restHeaders["content-disposition"]
|
|
516
507
|
|
|
517
508
|
if (Object.keys(restHeaders).length === 0) {
|
|
518
|
-
// Keep as
|
|
519
|
-
result[partName] = isBinaryData(partBody)
|
|
509
|
+
// Keep as string unless it's binary data
|
|
510
|
+
result[partName] = isBinaryData(Buffer.from(partBody, "binary"))
|
|
520
511
|
? Buffer.from(partBody, "binary")
|
|
521
512
|
: partBody
|
|
522
513
|
} else if (!partBody) {
|
|
523
514
|
// ao-types should stay with this part, not be extracted
|
|
524
515
|
result[partName] = restHeaders
|
|
525
516
|
} else {
|
|
526
|
-
// Keep as
|
|
517
|
+
// Keep as string unless it's binary data
|
|
527
518
|
result[partName] = {
|
|
528
519
|
...restHeaders,
|
|
529
|
-
body: isBinaryData(partBody)
|
|
520
|
+
body: isBinaryData(Buffer.from(partBody, "binary"))
|
|
530
521
|
? Buffer.from(partBody, "binary")
|
|
531
522
|
: partBody,
|
|
532
523
|
}
|