cbor-x 1.6.6 → 1.6.8
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 +4 -0
- package/decode.js +81 -49
- package/dist/decode-no-eval.cjs +83 -49
- package/dist/decode-no-eval.cjs.map +1 -1
- package/dist/index-no-eval.cjs +88 -51
- 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 +88 -51
- 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 +101 -67
- package/dist/node.cjs.map +1 -1
- package/dist/test.js +82 -49
- package/dist/test.js.map +1 -1
- package/encode.js +1 -1
- package/iterators.js +6 -4
- package/package.json +1 -1
- package/stream.js +11 -13
package/dist/node.cjs
CHANGED
|
@@ -21,7 +21,11 @@ const STOP_CODE = {};
|
|
|
21
21
|
let maxArraySize = 112810000; // This is the maximum array size in V8. We would potentially detect and set it higher
|
|
22
22
|
// for JSC, but this is pretty large and should be sufficient for most use cases
|
|
23
23
|
let maxMapSize = 16810000; // JavaScript has a fixed maximum map size of about 16710000, but JS itself enforces this,
|
|
24
|
-
//
|
|
24
|
+
// so we don't need to
|
|
25
|
+
|
|
26
|
+
let maxObjectSize = 16710000; // It takes over a minute to create this many keys in an object, so this is probably a
|
|
27
|
+
// reasonable choice.
|
|
28
|
+
let objectSizeLimit = maxObjectSize; // objects are limited by both maxObjectSize and maxMapSize
|
|
25
29
|
let strings = EMPTY_ARRAY;
|
|
26
30
|
let stringPosition = 0;
|
|
27
31
|
let currentDecoder = {};
|
|
@@ -124,7 +128,13 @@ class Decoder {
|
|
|
124
128
|
// re-entrant execution, save the state and restore it after we do this decode
|
|
125
129
|
return saveState(() => {
|
|
126
130
|
clearSource();
|
|
127
|
-
|
|
131
|
+
try {
|
|
132
|
+
return this ? this.decode(source, end) : Decoder.prototype.decode.call(defaultOptions, source, end)
|
|
133
|
+
} catch (error) {
|
|
134
|
+
if (error && typeof error == 'object')
|
|
135
|
+
nestedDecodeErrors.add(error);
|
|
136
|
+
throw error
|
|
137
|
+
}
|
|
128
138
|
})
|
|
129
139
|
}
|
|
130
140
|
srcEnd = end > -1 ? end : source.length;
|
|
@@ -201,15 +211,15 @@ class Decoder {
|
|
|
201
211
|
}
|
|
202
212
|
}
|
|
203
213
|
}
|
|
214
|
+
const nestedDecodeErrors = new WeakSet();
|
|
215
|
+
let arrayAllocationBudget;
|
|
204
216
|
function checkedRead() {
|
|
205
217
|
try {
|
|
218
|
+
arrayAllocationBudget = srcEnd - position$1;
|
|
206
219
|
let result = read();
|
|
207
220
|
if (bundledStrings$1) {
|
|
208
|
-
if (position$1 >= bundledStrings$1.postBundlePosition)
|
|
209
|
-
|
|
210
|
-
error.incomplete = true;
|
|
211
|
-
throw error
|
|
212
|
-
}
|
|
221
|
+
if (position$1 >= bundledStrings$1.postBundlePosition)
|
|
222
|
+
throw new Error('Unexpected bundle position')
|
|
213
223
|
// bundled strings to skip past
|
|
214
224
|
position$1 = bundledStrings$1.postBundlePosition;
|
|
215
225
|
bundledStrings$1 = null;
|
|
@@ -233,7 +243,14 @@ function checkedRead() {
|
|
|
233
243
|
return result
|
|
234
244
|
} catch(error) {
|
|
235
245
|
clearSource();
|
|
236
|
-
if (
|
|
246
|
+
if (nestedDecodeErrors.has(error)) {
|
|
247
|
+
// from a nested decode of embedded data (by an extension), which was complete in this source
|
|
248
|
+
if (error.incomplete)
|
|
249
|
+
error.incomplete = false;
|
|
250
|
+
} else if (error instanceof RangeError && position$1 + 8 > srcEnd ||
|
|
251
|
+
error && typeof error.message == 'string' && error.message.startsWith('Unexpected end of buffer')) {
|
|
252
|
+
// a DataView read past the end of the source; these read at most 8 bytes and precede advancing position.
|
|
253
|
+
// Any other RangeError (such as a stack overflow from deeply nested input) is fatal.
|
|
237
254
|
error.incomplete = true;
|
|
238
255
|
}
|
|
239
256
|
throw error
|
|
@@ -318,13 +335,13 @@ function read() {
|
|
|
318
335
|
let i = 0;
|
|
319
336
|
if (currentDecoder.keyMap) {
|
|
320
337
|
while((key = read()) != STOP_CODE) {
|
|
321
|
-
if (i++ >=
|
|
338
|
+
if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
322
339
|
object[safeKey(currentDecoder.decodeKey(key))] = read();
|
|
323
340
|
}
|
|
324
341
|
}
|
|
325
342
|
else {
|
|
326
343
|
while ((key = read()) != STOP_CODE) {
|
|
327
|
-
if (i++ >=
|
|
344
|
+
if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
328
345
|
object[safeKey(key)] = read();
|
|
329
346
|
}
|
|
330
347
|
}
|
|
@@ -370,11 +387,13 @@ function read() {
|
|
|
370
387
|
case 1: // negative int
|
|
371
388
|
return ~token
|
|
372
389
|
case 2: // buffer
|
|
390
|
+
if (token > srcEnd - position$1) throw endOfCBORError()
|
|
373
391
|
return readBin(token)
|
|
374
392
|
case 3: // string
|
|
375
|
-
if (srcStringEnd >= position$1) {
|
|
393
|
+
if (srcStringEnd >= position$1) { // already extracted, which only covers complete strings
|
|
376
394
|
return srcString.slice(position$1 - srcStringStart, (position$1 += token) - srcStringStart)
|
|
377
395
|
}
|
|
396
|
+
if (token > srcEnd - position$1) throw endOfCBORError()
|
|
378
397
|
if (srcStringEnd == 0 && srcEnd < 140 && token < 32) {
|
|
379
398
|
// for small blocks, avoiding the overhead of the extract call is helpful
|
|
380
399
|
let string = token < 16 ? shortStringInJS(token) : longStringInJS(token);
|
|
@@ -383,19 +402,21 @@ function read() {
|
|
|
383
402
|
}
|
|
384
403
|
return readFixedString(token)
|
|
385
404
|
case 4: // array
|
|
386
|
-
if (token
|
|
405
|
+
if (token > maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
|
|
387
406
|
// every element occupies at least one byte, so a length beyond what remains in the source can
|
|
388
407
|
// never be satisfied; check before allocating so a tiny header can not force a huge allocation
|
|
389
|
-
|
|
408
|
+
// nested arrays each pass the check above yet still preallocate, so also spend from a
|
|
409
|
+
// per-decode budget of the remaining bytes; the summed lengths of any valid tree stay under it
|
|
410
|
+
if (token > srcEnd - position$1 || (arrayAllocationBudget -= token) < 0) throw endOfCBORError()
|
|
390
411
|
let array = new Array(token);
|
|
391
412
|
//if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())
|
|
392
413
|
//else
|
|
393
414
|
for (let i = 0; i < token; i++) array[i] = read();
|
|
394
415
|
return array
|
|
395
416
|
case 5: // map
|
|
396
|
-
if (token >= maxMapSize) throw new Error(`Map size exceeds ${maxArraySize}`)
|
|
397
|
-
if (token > (srcEnd - position$1) / 2) throw endOfCBORError() // each entry needs at least two bytes
|
|
398
417
|
if (currentDecoder.mapsAsObjects) {
|
|
418
|
+
if (token > objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
419
|
+
if (token > (srcEnd - position$1) / 2) throw endOfCBORError() // each entry needs at least two bytes
|
|
399
420
|
let object = {};
|
|
400
421
|
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read();
|
|
401
422
|
else for (let i = 0; i < token; i++) object[safeKey(read())] = read();
|
|
@@ -405,6 +426,8 @@ function read() {
|
|
|
405
426
|
currentDecoder.mapsAsObjects = true;
|
|
406
427
|
restoreMapsAsObject = false;
|
|
407
428
|
}
|
|
429
|
+
if (token > maxMapSize) throw new Error(`Map size exceeds ${maxMapSize}`)
|
|
430
|
+
if (token > (srcEnd - position$1) / 2) throw endOfCBORError()
|
|
408
431
|
let map = new Map();
|
|
409
432
|
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()),read());
|
|
410
433
|
else for (let i = 0; i < token; i++) map.set(read(), read());
|
|
@@ -935,18 +958,12 @@ currentExtensions[27] = (data) => { // http://cbor.schmorp.de/generic-object
|
|
|
935
958
|
return (glbl[data[0]] || Error)(data[1], data[2])
|
|
936
959
|
};
|
|
937
960
|
const packedTable = (read) => {
|
|
938
|
-
if (
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
error.incomplete = true;
|
|
942
|
-
throw error
|
|
943
|
-
}
|
|
961
|
+
if (!(position$1 < srcEnd)) throw endOfCBORError()
|
|
962
|
+
if (src[position$1++] != 0x84)
|
|
963
|
+
throw new Error('Packed values structure must be followed by a 4 element array')
|
|
944
964
|
let newPackedValues = read(); // packed values
|
|
945
|
-
if (!newPackedValues || !newPackedValues.length)
|
|
946
|
-
|
|
947
|
-
error.incomplete = true;
|
|
948
|
-
throw error
|
|
949
|
-
}
|
|
965
|
+
if (!Array.isArray(newPackedValues) || !newPackedValues.length)
|
|
966
|
+
throw new Error('Packed values structure must be followed by a 4 element array')
|
|
950
967
|
packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues;
|
|
951
968
|
packedValues.prefixes = read();
|
|
952
969
|
packedValues.suffixes = read();
|
|
@@ -964,10 +981,7 @@ currentExtensions[PACKED_REFERENCE_TAG_ID] = (data) => { // packed reference
|
|
|
964
981
|
}
|
|
965
982
|
if (typeof data == 'number')
|
|
966
983
|
return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
|
|
967
|
-
|
|
968
|
-
if (data === undefined)
|
|
969
|
-
error.incomplete = true;
|
|
970
|
-
throw error
|
|
984
|
+
throw new Error('No support for non-integer packed references yet')
|
|
971
985
|
};
|
|
972
986
|
|
|
973
987
|
// The following code is an incomplete implementation of http://cbor.schmorp.de/stringref
|
|
@@ -1037,9 +1051,19 @@ currentExtensions[258] = (array) => new Set(array); // https://github.com/input-
|
|
|
1037
1051
|
(currentExtensions[259] = (read) => {
|
|
1038
1052
|
// https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec
|
|
1039
1053
|
// for decoding as a standard Map
|
|
1040
|
-
|
|
1041
|
-
|
|
1054
|
+
let decoder = currentDecoder;
|
|
1055
|
+
if (decoder.mapsAsObjects) {
|
|
1056
|
+
decoder.mapsAsObjects = false;
|
|
1042
1057
|
restoreMapsAsObject = true;
|
|
1058
|
+
try {
|
|
1059
|
+
return read()
|
|
1060
|
+
} finally {
|
|
1061
|
+
// normally restored by the map header, but not if the tagged value is not a map or the read fails
|
|
1062
|
+
if (restoreMapsAsObject) {
|
|
1063
|
+
decoder.mapsAsObjects = true;
|
|
1064
|
+
restoreMapsAsObject = false;
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1043
1067
|
}
|
|
1044
1068
|
return read()
|
|
1045
1069
|
}).handlesRead = true;
|
|
@@ -1159,10 +1183,12 @@ function readJustLength() {
|
|
|
1159
1183
|
token = src[position$1++];
|
|
1160
1184
|
break
|
|
1161
1185
|
case 0x19:
|
|
1186
|
+
if (position$1 + 2 > srcEnd) throw endOfCBORError()
|
|
1162
1187
|
token = dataView.getUint16(position$1);
|
|
1163
1188
|
position$1 += 2;
|
|
1164
1189
|
break
|
|
1165
1190
|
case 0x1a:
|
|
1191
|
+
if (position$1 + 4 > srcEnd) throw endOfCBORError()
|
|
1166
1192
|
token = dataView.getUint32(position$1);
|
|
1167
1193
|
position$1 += 4;
|
|
1168
1194
|
break
|
|
@@ -1204,22 +1230,29 @@ function saveState(callback) {
|
|
|
1204
1230
|
let savedStructures = currentStructures;
|
|
1205
1231
|
let savedDecoder = currentDecoder;
|
|
1206
1232
|
let savedSequentialMode = sequentialMode;
|
|
1207
|
-
let
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1233
|
+
let savedRestoreMapsAsObject = restoreMapsAsObject;
|
|
1234
|
+
let savedArrayAllocationBudget = arrayAllocationBudget;
|
|
1235
|
+
restoreMapsAsObject = false;
|
|
1236
|
+
try {
|
|
1237
|
+
return callback()
|
|
1238
|
+
} finally {
|
|
1239
|
+
srcEnd = savedSrcEnd;
|
|
1240
|
+
position$1 = savedPosition;
|
|
1241
|
+
stringPosition = savedStringPosition;
|
|
1242
|
+
srcStringStart = savedSrcStringStart;
|
|
1243
|
+
srcStringEnd = savedSrcStringEnd;
|
|
1244
|
+
srcString = savedSrcString;
|
|
1245
|
+
strings = savedStrings;
|
|
1246
|
+
referenceMap = savedReferenceMap;
|
|
1247
|
+
bundledStrings$1 = savedBundledStrings;
|
|
1248
|
+
src = savedSrc;
|
|
1249
|
+
sequentialMode = savedSequentialMode;
|
|
1250
|
+
currentStructures = savedStructures;
|
|
1251
|
+
currentDecoder = savedDecoder;
|
|
1252
|
+
restoreMapsAsObject = savedRestoreMapsAsObject;
|
|
1253
|
+
arrayAllocationBudget = savedArrayAllocationBudget;
|
|
1254
|
+
dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
|
|
1255
|
+
}
|
|
1223
1256
|
}
|
|
1224
1257
|
function clearSource() {
|
|
1225
1258
|
src = null;
|
|
@@ -1234,7 +1267,8 @@ function addExtension$1(extension) {
|
|
|
1234
1267
|
function setSizeLimits(limits) {
|
|
1235
1268
|
if (limits.maxMapSize) maxMapSize = limits.maxMapSize;
|
|
1236
1269
|
if (limits.maxArraySize) maxArraySize = limits.maxArraySize;
|
|
1237
|
-
if (limits.maxObjectSize) limits.maxObjectSize;
|
|
1270
|
+
if (limits.maxObjectSize) maxObjectSize = limits.maxObjectSize;
|
|
1271
|
+
objectSizeLimit = Math.min(maxObjectSize, maxMapSize);
|
|
1238
1272
|
}
|
|
1239
1273
|
|
|
1240
1274
|
const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
|
|
@@ -1436,7 +1470,7 @@ class Encoder extends Decoder {
|
|
|
1436
1470
|
if (throwOnIterable)
|
|
1437
1471
|
return;
|
|
1438
1472
|
encode(value);
|
|
1439
|
-
if (bundledStrings) {
|
|
1473
|
+
if (bundledStrings && bundledStrings.position) { // position is only set once a bundle has been started
|
|
1440
1474
|
writeBundles(start, encode);
|
|
1441
1475
|
}
|
|
1442
1476
|
encoder.offset = position; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
|
|
@@ -2521,24 +2555,22 @@ class DecoderStream extends stream.Transform {
|
|
|
2521
2555
|
chunk = Buffer.concat([this.incompleteBuffer, chunk]);
|
|
2522
2556
|
this.incompleteBuffer = null;
|
|
2523
2557
|
}
|
|
2524
|
-
let values;
|
|
2558
|
+
let values, fatalError;
|
|
2525
2559
|
try {
|
|
2526
2560
|
values = this.decoder.decodeMultiple(chunk);
|
|
2527
2561
|
} catch(error) {
|
|
2528
|
-
|
|
2562
|
+
values = error.values;
|
|
2563
|
+
if (error.incomplete)
|
|
2529
2564
|
this.incompleteBuffer = chunk.slice(error.lastPosition);
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
value = this.getNullValue();
|
|
2538
|
-
this.push(value);
|
|
2539
|
-
}
|
|
2565
|
+
else
|
|
2566
|
+
fatalError = error;
|
|
2567
|
+
}
|
|
2568
|
+
for (let value of values || []) {
|
|
2569
|
+
if (value === null)
|
|
2570
|
+
value = this.getNullValue();
|
|
2571
|
+
this.push(value);
|
|
2540
2572
|
}
|
|
2541
|
-
callback();
|
|
2573
|
+
callback(fatalError);
|
|
2542
2574
|
}
|
|
2543
2575
|
getNullValue() {
|
|
2544
2576
|
return Symbol.for(null)
|
|
@@ -2591,7 +2623,7 @@ function decodeIter (bufferIterator, options = {}) {
|
|
|
2591
2623
|
}
|
|
2592
2624
|
|
|
2593
2625
|
const decoder = new Decoder(options);
|
|
2594
|
-
let incomplete;
|
|
2626
|
+
let incomplete, fatalError;
|
|
2595
2627
|
const parser = (chunk) => {
|
|
2596
2628
|
let yields;
|
|
2597
2629
|
// if there's incomplete data from previous chunk, concatinate and try again
|
|
@@ -2603,26 +2635,28 @@ function decodeIter (bufferIterator, options = {}) {
|
|
|
2603
2635
|
try {
|
|
2604
2636
|
yields = decoder.decodeMultiple(chunk);
|
|
2605
2637
|
} catch (err) {
|
|
2638
|
+
yields = err.values;
|
|
2606
2639
|
if (err.incomplete) {
|
|
2607
2640
|
incomplete = chunk.slice(err.lastPosition);
|
|
2608
|
-
yields = err.values;
|
|
2609
2641
|
} else {
|
|
2610
|
-
|
|
2642
|
+
fatalError = err;
|
|
2611
2643
|
}
|
|
2612
2644
|
}
|
|
2613
|
-
return yields
|
|
2645
|
+
return yields || []
|
|
2614
2646
|
};
|
|
2615
2647
|
|
|
2616
2648
|
if (typeof bufferIterator[Symbol.iterator] === 'function') {
|
|
2617
2649
|
return (function * iter () {
|
|
2618
2650
|
for (const value of bufferIterator) {
|
|
2619
2651
|
yield * parser(value);
|
|
2652
|
+
if (fatalError) throw fatalError
|
|
2620
2653
|
}
|
|
2621
2654
|
})()
|
|
2622
2655
|
} else if (typeof bufferIterator[Symbol.asyncIterator] === 'function') {
|
|
2623
2656
|
return (async function * iter () {
|
|
2624
2657
|
for await (const value of bufferIterator) {
|
|
2625
2658
|
yield * parser(value);
|
|
2659
|
+
if (fatalError) throw fatalError
|
|
2626
2660
|
}
|
|
2627
2661
|
})()
|
|
2628
2662
|
}
|