cbor-x 1.6.4 → 1.6.6
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/README.md +5 -3
- package/decode.d.ts +1 -1
- package/decode.js +50 -33
- package/dist/decode-no-eval.cjs +50 -33
- package/dist/decode-no-eval.cjs.map +1 -1
- package/dist/index-no-eval.cjs +50 -33
- package/dist/index-no-eval.cjs.map +1 -1
- package/dist/index-no-eval.min.js +1 -1
- package/dist/index-no-eval.min.js.map +1 -1
- package/dist/index.js +50 -33
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/node.cjs +52 -34
- package/dist/node.cjs.map +1 -1
- package/dist/test.js +53 -35
- package/dist/test.js.map +1 -1
- package/index.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -230,17 +230,19 @@ Note, that the performance is decreased with decimal rounding by about 20-25%, a
|
|
|
230
230
|
In addition, msgpackr exports a `roundFloat32(number)` function that can be used to round floating point numbers to the maximum significant decimal digits that can be stored in 32-bit float, just as DECIMAL_ROUND does when decoding. This can be useful for determining how a number will be decoded prior to encoding it.
|
|
231
231
|
|
|
232
232
|
### Setting Size Limits
|
|
233
|
-
You can set size limits on objects, arrays, and maps to prevent resource exhaustion when decoding. This can be done by calling the
|
|
233
|
+
You can set size limits on objects, arrays, and maps to prevent resource exhaustion when decoding. This can be done by calling the setSizeLimits export. Each of the properties are optional (only provide
|
|
234
234
|
the properties you want to change), for example (with the defaults):
|
|
235
235
|
```JavaScript
|
|
236
|
-
import {
|
|
237
|
-
|
|
236
|
+
import { setSizeLimits } from 'cbor-x';
|
|
237
|
+
setSizeLimits({
|
|
238
238
|
maxArraySize: 112810000,
|
|
239
239
|
maxMapSize: 16810000,
|
|
240
240
|
maxObjectSize : 16710000
|
|
241
241
|
});
|
|
242
242
|
```
|
|
243
243
|
|
|
244
|
+
Declared array and map lengths are also always validated against the number of bytes remaining in the source, so truncated or malformed input is rejected immediately instead of allocating for the length it claims. These limits are for bounding legitimately encoded (but unwanted) large data.
|
|
245
|
+
|
|
244
246
|
## Performance
|
|
245
247
|
Cbor-x is fast. Really fast. Here is comparison with the next fastest JS projects using the benchmark tool from `msgpack-lite` (and the sample data is from some clinical research data we use that has a good mix of different value types and structures). It also includes comparison to V8 native JSON functionality, and JavaScript Avro (`avsc`, a very optimized Avro implementation):
|
|
246
248
|
|
package/decode.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { decode, decodeMultiple, Decoder, addExtension, clearSource,roundFloat32, isNativeAccelerationEnabled,
|
|
2
|
-
Extension, Options, FLOAT32_OPTIONS,
|
|
2
|
+
Extension, Options, FLOAT32_OPTIONS, setSizeLimits, SizeLimitOptions } from '.'
|
package/decode.js
CHANGED
|
@@ -243,13 +243,22 @@ export function checkedRead() {
|
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
+
function endOfCBORError() {
|
|
247
|
+
let error = new Error('Unexpected end of CBOR data')
|
|
248
|
+
error.incomplete = true
|
|
249
|
+
return error
|
|
250
|
+
}
|
|
251
|
+
|
|
246
252
|
export function read() {
|
|
253
|
+
// compared as < so that a NaN position (from a corrupt length) also throws instead of reading undefined
|
|
254
|
+
if (!(position < srcEnd)) throw endOfCBORError()
|
|
247
255
|
let token = src[position++]
|
|
248
256
|
let majorType = token >> 5
|
|
249
257
|
token = token & 0x1f
|
|
250
258
|
if (token > 0x17) {
|
|
251
259
|
switch (token) {
|
|
252
260
|
case 0x18:
|
|
261
|
+
if (position >= srcEnd) throw endOfCBORError()
|
|
253
262
|
token = src[position++]
|
|
254
263
|
break
|
|
255
264
|
case 0x19:
|
|
@@ -378,6 +387,9 @@ export function read() {
|
|
|
378
387
|
return readFixedString(token)
|
|
379
388
|
case 4: // array
|
|
380
389
|
if (token >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
|
|
390
|
+
// every element occupies at least one byte, so a length beyond what remains in the source can
|
|
391
|
+
// never be satisfied; check before allocating so a tiny header can not force a huge allocation
|
|
392
|
+
if (token > srcEnd - position) throw endOfCBORError()
|
|
381
393
|
let array = new Array(token)
|
|
382
394
|
//if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())
|
|
383
395
|
//else
|
|
@@ -385,6 +397,7 @@ export function read() {
|
|
|
385
397
|
return array
|
|
386
398
|
case 5: // map
|
|
387
399
|
if (token >= maxMapSize) throw new Error(`Map size exceeds ${maxArraySize}`)
|
|
400
|
+
if (token > (srcEnd - position) / 2) throw endOfCBORError() // each entry needs at least two bytes
|
|
388
401
|
if (currentDecoder.mapsAsObjects) {
|
|
389
402
|
let object = {}
|
|
390
403
|
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read()
|
|
@@ -476,11 +489,7 @@ export function read() {
|
|
|
476
489
|
throw new Error('Unknown token ' + token)
|
|
477
490
|
}
|
|
478
491
|
default: // negative int
|
|
479
|
-
if (isNaN(token))
|
|
480
|
-
let error = new Error('Unexpected end of CBOR data')
|
|
481
|
-
error.incomplete = true
|
|
482
|
-
throw error
|
|
483
|
-
}
|
|
492
|
+
if (isNaN(token)) throw endOfCBORError()
|
|
484
493
|
throw new Error('Unknown CBOR token ' + token)
|
|
485
494
|
}
|
|
486
495
|
}
|
|
@@ -610,43 +619,49 @@ function readStringJS(length) {
|
|
|
610
619
|
units.push(byte1)
|
|
611
620
|
} else if ((byte1 & 0xe0) === 0xc0) {
|
|
612
621
|
// 2 bytes
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
// Reject overlong encoding: 2-byte sequences must encode values >= 0x80
|
|
616
|
-
if (codePoint < 0x80) {
|
|
617
|
-
units.push(0xFFFD) // replacement character
|
|
622
|
+
if (byte1 < 0xc2 || position >= end || (src[position] & 0xc0) !== 0x80) {
|
|
623
|
+
units.push(0xFFFD)
|
|
618
624
|
} else {
|
|
619
|
-
|
|
625
|
+
const byte2 = src[position++] & 0x3f
|
|
626
|
+
units.push(((byte1 & 0x1f) << 6) | byte2)
|
|
620
627
|
}
|
|
621
628
|
} else if ((byte1 & 0xf0) === 0xe0) {
|
|
622
629
|
// 3 bytes
|
|
623
|
-
const byte2 = src[position
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
// Also reject surrogates (0xD800-0xDFFF)
|
|
628
|
-
if (codePoint < 0x800 || (codePoint >= 0xD800 && codePoint <= 0xDFFF)) {
|
|
629
|
-
units.push(0xFFFD) // replacement character
|
|
630
|
+
const byte2 = position < end ? src[position] : 0
|
|
631
|
+
if (position >= end || (byte2 & 0xc0) !== 0x80 ||
|
|
632
|
+
(byte1 === 0xe0 && byte2 < 0xa0) || (byte1 === 0xed && byte2 >= 0xa0)) {
|
|
633
|
+
units.push(0xFFFD)
|
|
630
634
|
} else {
|
|
631
|
-
|
|
635
|
+
position++
|
|
636
|
+
if (position >= end || (src[position] & 0xc0) !== 0x80) {
|
|
637
|
+
units.push(0xFFFD)
|
|
638
|
+
} else {
|
|
639
|
+
const byte3 = src[position++] & 0x3f
|
|
640
|
+
units.push(((byte1 & 0x1f) << 12) | ((byte2 & 0x3f) << 6) | byte3)
|
|
641
|
+
}
|
|
632
642
|
}
|
|
633
643
|
} else if ((byte1 & 0xf8) === 0xf0) {
|
|
634
644
|
// 4 bytes
|
|
635
|
-
const byte2 = src[position
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
// Reject overlong encoding: 4-byte sequences must encode values >= 0x10000
|
|
640
|
-
// Also reject values > 0x10FFFF (maximum valid Unicode)
|
|
641
|
-
if (unit < 0x10000 || unit > 0x10FFFF) {
|
|
642
|
-
units.push(0xFFFD) // replacement character
|
|
643
|
-
} else if (unit > 0xffff) {
|
|
644
|
-
unit -= 0x10000
|
|
645
|
-
units.push(((unit >>> 10) & 0x3ff) | 0xd800)
|
|
646
|
-
unit = 0xdc00 | (unit & 0x3ff)
|
|
647
|
-
units.push(unit)
|
|
645
|
+
const byte2 = position < end ? src[position] : 0
|
|
646
|
+
if (byte1 > 0xf4 || position >= end || (byte2 & 0xc0) !== 0x80 ||
|
|
647
|
+
(byte1 === 0xf0 && byte2 < 0x90) || (byte1 === 0xf4 && byte2 >= 0x90)) {
|
|
648
|
+
units.push(0xFFFD)
|
|
648
649
|
} else {
|
|
649
|
-
|
|
650
|
+
position++
|
|
651
|
+
if (position >= end || (src[position] & 0xc0) !== 0x80) {
|
|
652
|
+
units.push(0xFFFD)
|
|
653
|
+
} else {
|
|
654
|
+
const byte3 = src[position++] & 0x3f
|
|
655
|
+
if (position >= end || (src[position] & 0xc0) !== 0x80) {
|
|
656
|
+
units.push(0xFFFD)
|
|
657
|
+
} else {
|
|
658
|
+
const byte4 = src[position++] & 0x3f
|
|
659
|
+
let unit = ((byte1 & 0x07) << 0x12) | ((byte2 & 0x3f) << 0x0c) | (byte3 << 0x06) | byte4
|
|
660
|
+
unit -= 0x10000
|
|
661
|
+
units.push(((unit >>> 10) & 0x3ff) | 0xd800)
|
|
662
|
+
units.push(0xdc00 | (unit & 0x3ff))
|
|
663
|
+
}
|
|
664
|
+
}
|
|
650
665
|
}
|
|
651
666
|
} else {
|
|
652
667
|
units.push(0xFFFD) // replacement character for invalid lead byte
|
|
@@ -1214,10 +1229,12 @@ function readBundleExt() {
|
|
|
1214
1229
|
}
|
|
1215
1230
|
|
|
1216
1231
|
function readJustLength() {
|
|
1232
|
+
if (!(position < srcEnd)) throw endOfCBORError()
|
|
1217
1233
|
let token = src[position++] & 0x1f
|
|
1218
1234
|
if (token > 0x17) {
|
|
1219
1235
|
switch (token) {
|
|
1220
1236
|
case 0x18:
|
|
1237
|
+
if (position >= srcEnd) throw endOfCBORError()
|
|
1221
1238
|
token = src[position++]
|
|
1222
1239
|
break
|
|
1223
1240
|
case 0x19:
|
package/dist/decode-no-eval.cjs
CHANGED
|
@@ -244,13 +244,22 @@
|
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
+
function endOfCBORError() {
|
|
248
|
+
let error = new Error('Unexpected end of CBOR data');
|
|
249
|
+
error.incomplete = true;
|
|
250
|
+
return error
|
|
251
|
+
}
|
|
252
|
+
|
|
247
253
|
function read() {
|
|
254
|
+
// compared as < so that a NaN position (from a corrupt length) also throws instead of reading undefined
|
|
255
|
+
if (!(position < srcEnd)) throw endOfCBORError()
|
|
248
256
|
let token = src[position++];
|
|
249
257
|
let majorType = token >> 5;
|
|
250
258
|
token = token & 0x1f;
|
|
251
259
|
if (token > 0x17) {
|
|
252
260
|
switch (token) {
|
|
253
261
|
case 0x18:
|
|
262
|
+
if (position >= srcEnd) throw endOfCBORError()
|
|
254
263
|
token = src[position++];
|
|
255
264
|
break
|
|
256
265
|
case 0x19:
|
|
@@ -379,6 +388,9 @@
|
|
|
379
388
|
return readFixedString(token)
|
|
380
389
|
case 4: // array
|
|
381
390
|
if (token >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
|
|
391
|
+
// every element occupies at least one byte, so a length beyond what remains in the source can
|
|
392
|
+
// never be satisfied; check before allocating so a tiny header can not force a huge allocation
|
|
393
|
+
if (token > srcEnd - position) throw endOfCBORError()
|
|
382
394
|
let array = new Array(token);
|
|
383
395
|
//if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())
|
|
384
396
|
//else
|
|
@@ -386,6 +398,7 @@
|
|
|
386
398
|
return array
|
|
387
399
|
case 5: // map
|
|
388
400
|
if (token >= maxMapSize) throw new Error(`Map size exceeds ${maxArraySize}`)
|
|
401
|
+
if (token > (srcEnd - position) / 2) throw endOfCBORError() // each entry needs at least two bytes
|
|
389
402
|
if (currentDecoder.mapsAsObjects) {
|
|
390
403
|
let object = {};
|
|
391
404
|
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read();
|
|
@@ -477,11 +490,7 @@
|
|
|
477
490
|
throw new Error('Unknown token ' + token)
|
|
478
491
|
}
|
|
479
492
|
default: // negative int
|
|
480
|
-
if (isNaN(token))
|
|
481
|
-
let error = new Error('Unexpected end of CBOR data');
|
|
482
|
-
error.incomplete = true;
|
|
483
|
-
throw error
|
|
484
|
-
}
|
|
493
|
+
if (isNaN(token)) throw endOfCBORError()
|
|
485
494
|
throw new Error('Unknown CBOR token ' + token)
|
|
486
495
|
}
|
|
487
496
|
}
|
|
@@ -605,43 +614,49 @@
|
|
|
605
614
|
units.push(byte1);
|
|
606
615
|
} else if ((byte1 & 0xe0) === 0xc0) {
|
|
607
616
|
// 2 bytes
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
// Reject overlong encoding: 2-byte sequences must encode values >= 0x80
|
|
611
|
-
if (codePoint < 0x80) {
|
|
612
|
-
units.push(0xFFFD); // replacement character
|
|
617
|
+
if (byte1 < 0xc2 || position >= end || (src[position] & 0xc0) !== 0x80) {
|
|
618
|
+
units.push(0xFFFD);
|
|
613
619
|
} else {
|
|
614
|
-
|
|
620
|
+
const byte2 = src[position++] & 0x3f;
|
|
621
|
+
units.push(((byte1 & 0x1f) << 6) | byte2);
|
|
615
622
|
}
|
|
616
623
|
} else if ((byte1 & 0xf0) === 0xe0) {
|
|
617
624
|
// 3 bytes
|
|
618
|
-
const byte2 = src[position
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
// Also reject surrogates (0xD800-0xDFFF)
|
|
623
|
-
if (codePoint < 0x800 || (codePoint >= 0xD800 && codePoint <= 0xDFFF)) {
|
|
624
|
-
units.push(0xFFFD); // replacement character
|
|
625
|
+
const byte2 = position < end ? src[position] : 0;
|
|
626
|
+
if (position >= end || (byte2 & 0xc0) !== 0x80 ||
|
|
627
|
+
(byte1 === 0xe0 && byte2 < 0xa0) || (byte1 === 0xed && byte2 >= 0xa0)) {
|
|
628
|
+
units.push(0xFFFD);
|
|
625
629
|
} else {
|
|
626
|
-
|
|
630
|
+
position++;
|
|
631
|
+
if (position >= end || (src[position] & 0xc0) !== 0x80) {
|
|
632
|
+
units.push(0xFFFD);
|
|
633
|
+
} else {
|
|
634
|
+
const byte3 = src[position++] & 0x3f;
|
|
635
|
+
units.push(((byte1 & 0x1f) << 12) | ((byte2 & 0x3f) << 6) | byte3);
|
|
636
|
+
}
|
|
627
637
|
}
|
|
628
638
|
} else if ((byte1 & 0xf8) === 0xf0) {
|
|
629
639
|
// 4 bytes
|
|
630
|
-
const byte2 = src[position
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
// Reject overlong encoding: 4-byte sequences must encode values >= 0x10000
|
|
635
|
-
// Also reject values > 0x10FFFF (maximum valid Unicode)
|
|
636
|
-
if (unit < 0x10000 || unit > 0x10FFFF) {
|
|
637
|
-
units.push(0xFFFD); // replacement character
|
|
638
|
-
} else if (unit > 0xffff) {
|
|
639
|
-
unit -= 0x10000;
|
|
640
|
-
units.push(((unit >>> 10) & 0x3ff) | 0xd800);
|
|
641
|
-
unit = 0xdc00 | (unit & 0x3ff);
|
|
642
|
-
units.push(unit);
|
|
640
|
+
const byte2 = position < end ? src[position] : 0;
|
|
641
|
+
if (byte1 > 0xf4 || position >= end || (byte2 & 0xc0) !== 0x80 ||
|
|
642
|
+
(byte1 === 0xf0 && byte2 < 0x90) || (byte1 === 0xf4 && byte2 >= 0x90)) {
|
|
643
|
+
units.push(0xFFFD);
|
|
643
644
|
} else {
|
|
644
|
-
|
|
645
|
+
position++;
|
|
646
|
+
if (position >= end || (src[position] & 0xc0) !== 0x80) {
|
|
647
|
+
units.push(0xFFFD);
|
|
648
|
+
} else {
|
|
649
|
+
const byte3 = src[position++] & 0x3f;
|
|
650
|
+
if (position >= end || (src[position] & 0xc0) !== 0x80) {
|
|
651
|
+
units.push(0xFFFD);
|
|
652
|
+
} else {
|
|
653
|
+
const byte4 = src[position++] & 0x3f;
|
|
654
|
+
let unit = ((byte1 & 0x07) << 0x12) | ((byte2 & 0x3f) << 0x0c) | (byte3 << 0x06) | byte4;
|
|
655
|
+
unit -= 0x10000;
|
|
656
|
+
units.push(((unit >>> 10) & 0x3ff) | 0xd800);
|
|
657
|
+
units.push(0xdc00 | (unit & 0x3ff));
|
|
658
|
+
}
|
|
659
|
+
}
|
|
645
660
|
}
|
|
646
661
|
} else {
|
|
647
662
|
units.push(0xFFFD); // replacement character for invalid lead byte
|
|
@@ -1139,10 +1154,12 @@
|
|
|
1139
1154
|
}
|
|
1140
1155
|
|
|
1141
1156
|
function readJustLength() {
|
|
1157
|
+
if (!(position < srcEnd)) throw endOfCBORError()
|
|
1142
1158
|
let token = src[position++] & 0x1f;
|
|
1143
1159
|
if (token > 0x17) {
|
|
1144
1160
|
switch (token) {
|
|
1145
1161
|
case 0x18:
|
|
1162
|
+
if (position >= srcEnd) throw endOfCBORError()
|
|
1146
1163
|
token = src[position++];
|
|
1147
1164
|
break
|
|
1148
1165
|
case 0x19:
|