cbor-x 1.6.6 → 1.6.7
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 +74 -48
- package/dist/decode-no-eval.cjs +76 -48
- package/dist/decode-no-eval.cjs.map +1 -1
- package/dist/index-no-eval.cjs +81 -50
- 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 +81 -50
- 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 +94 -66
- package/dist/node.cjs.map +1 -1
- package/dist/test.js +75 -48
- 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,13 @@ class Decoder {
|
|
|
201
211
|
}
|
|
202
212
|
}
|
|
203
213
|
}
|
|
214
|
+
const nestedDecodeErrors = new WeakSet();
|
|
204
215
|
function checkedRead() {
|
|
205
216
|
try {
|
|
206
217
|
let result = read();
|
|
207
218
|
if (bundledStrings$1) {
|
|
208
|
-
if (position$1 >= bundledStrings$1.postBundlePosition)
|
|
209
|
-
|
|
210
|
-
error.incomplete = true;
|
|
211
|
-
throw error
|
|
212
|
-
}
|
|
219
|
+
if (position$1 >= bundledStrings$1.postBundlePosition)
|
|
220
|
+
throw new Error('Unexpected bundle position')
|
|
213
221
|
// bundled strings to skip past
|
|
214
222
|
position$1 = bundledStrings$1.postBundlePosition;
|
|
215
223
|
bundledStrings$1 = null;
|
|
@@ -233,7 +241,14 @@ function checkedRead() {
|
|
|
233
241
|
return result
|
|
234
242
|
} catch(error) {
|
|
235
243
|
clearSource();
|
|
236
|
-
if (
|
|
244
|
+
if (nestedDecodeErrors.has(error)) {
|
|
245
|
+
// from a nested decode of embedded data (by an extension), which was complete in this source
|
|
246
|
+
if (error.incomplete)
|
|
247
|
+
error.incomplete = false;
|
|
248
|
+
} else if (error instanceof RangeError && position$1 + 8 > srcEnd ||
|
|
249
|
+
error && typeof error.message == 'string' && error.message.startsWith('Unexpected end of buffer')) {
|
|
250
|
+
// a DataView read past the end of the source; these read at most 8 bytes and precede advancing position.
|
|
251
|
+
// Any other RangeError (such as a stack overflow from deeply nested input) is fatal.
|
|
237
252
|
error.incomplete = true;
|
|
238
253
|
}
|
|
239
254
|
throw error
|
|
@@ -318,13 +333,13 @@ function read() {
|
|
|
318
333
|
let i = 0;
|
|
319
334
|
if (currentDecoder.keyMap) {
|
|
320
335
|
while((key = read()) != STOP_CODE) {
|
|
321
|
-
if (i++ >=
|
|
336
|
+
if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
322
337
|
object[safeKey(currentDecoder.decodeKey(key))] = read();
|
|
323
338
|
}
|
|
324
339
|
}
|
|
325
340
|
else {
|
|
326
341
|
while ((key = read()) != STOP_CODE) {
|
|
327
|
-
if (i++ >=
|
|
342
|
+
if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
328
343
|
object[safeKey(key)] = read();
|
|
329
344
|
}
|
|
330
345
|
}
|
|
@@ -370,11 +385,13 @@ function read() {
|
|
|
370
385
|
case 1: // negative int
|
|
371
386
|
return ~token
|
|
372
387
|
case 2: // buffer
|
|
388
|
+
if (token > srcEnd - position$1) throw endOfCBORError()
|
|
373
389
|
return readBin(token)
|
|
374
390
|
case 3: // string
|
|
375
|
-
if (srcStringEnd >= position$1) {
|
|
391
|
+
if (srcStringEnd >= position$1) { // already extracted, which only covers complete strings
|
|
376
392
|
return srcString.slice(position$1 - srcStringStart, (position$1 += token) - srcStringStart)
|
|
377
393
|
}
|
|
394
|
+
if (token > srcEnd - position$1) throw endOfCBORError()
|
|
378
395
|
if (srcStringEnd == 0 && srcEnd < 140 && token < 32) {
|
|
379
396
|
// for small blocks, avoiding the overhead of the extract call is helpful
|
|
380
397
|
let string = token < 16 ? shortStringInJS(token) : longStringInJS(token);
|
|
@@ -383,7 +400,7 @@ function read() {
|
|
|
383
400
|
}
|
|
384
401
|
return readFixedString(token)
|
|
385
402
|
case 4: // array
|
|
386
|
-
if (token
|
|
403
|
+
if (token > maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
|
|
387
404
|
// every element occupies at least one byte, so a length beyond what remains in the source can
|
|
388
405
|
// never be satisfied; check before allocating so a tiny header can not force a huge allocation
|
|
389
406
|
if (token > srcEnd - position$1) throw endOfCBORError()
|
|
@@ -393,9 +410,9 @@ function read() {
|
|
|
393
410
|
for (let i = 0; i < token; i++) array[i] = read();
|
|
394
411
|
return array
|
|
395
412
|
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
413
|
if (currentDecoder.mapsAsObjects) {
|
|
414
|
+
if (token > objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
415
|
+
if (token > (srcEnd - position$1) / 2) throw endOfCBORError() // each entry needs at least two bytes
|
|
399
416
|
let object = {};
|
|
400
417
|
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read();
|
|
401
418
|
else for (let i = 0; i < token; i++) object[safeKey(read())] = read();
|
|
@@ -405,6 +422,8 @@ function read() {
|
|
|
405
422
|
currentDecoder.mapsAsObjects = true;
|
|
406
423
|
restoreMapsAsObject = false;
|
|
407
424
|
}
|
|
425
|
+
if (token > maxMapSize) throw new Error(`Map size exceeds ${maxMapSize}`)
|
|
426
|
+
if (token > (srcEnd - position$1) / 2) throw endOfCBORError()
|
|
408
427
|
let map = new Map();
|
|
409
428
|
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()),read());
|
|
410
429
|
else for (let i = 0; i < token; i++) map.set(read(), read());
|
|
@@ -935,18 +954,12 @@ currentExtensions[27] = (data) => { // http://cbor.schmorp.de/generic-object
|
|
|
935
954
|
return (glbl[data[0]] || Error)(data[1], data[2])
|
|
936
955
|
};
|
|
937
956
|
const packedTable = (read) => {
|
|
938
|
-
if (
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
error.incomplete = true;
|
|
942
|
-
throw error
|
|
943
|
-
}
|
|
957
|
+
if (!(position$1 < srcEnd)) throw endOfCBORError()
|
|
958
|
+
if (src[position$1++] != 0x84)
|
|
959
|
+
throw new Error('Packed values structure must be followed by a 4 element array')
|
|
944
960
|
let newPackedValues = read(); // packed values
|
|
945
|
-
if (!newPackedValues || !newPackedValues.length)
|
|
946
|
-
|
|
947
|
-
error.incomplete = true;
|
|
948
|
-
throw error
|
|
949
|
-
}
|
|
961
|
+
if (!Array.isArray(newPackedValues) || !newPackedValues.length)
|
|
962
|
+
throw new Error('Packed values structure must be followed by a 4 element array')
|
|
950
963
|
packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues;
|
|
951
964
|
packedValues.prefixes = read();
|
|
952
965
|
packedValues.suffixes = read();
|
|
@@ -964,10 +977,7 @@ currentExtensions[PACKED_REFERENCE_TAG_ID] = (data) => { // packed reference
|
|
|
964
977
|
}
|
|
965
978
|
if (typeof data == 'number')
|
|
966
979
|
return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
|
|
967
|
-
|
|
968
|
-
if (data === undefined)
|
|
969
|
-
error.incomplete = true;
|
|
970
|
-
throw error
|
|
980
|
+
throw new Error('No support for non-integer packed references yet')
|
|
971
981
|
};
|
|
972
982
|
|
|
973
983
|
// The following code is an incomplete implementation of http://cbor.schmorp.de/stringref
|
|
@@ -1037,9 +1047,19 @@ currentExtensions[258] = (array) => new Set(array); // https://github.com/input-
|
|
|
1037
1047
|
(currentExtensions[259] = (read) => {
|
|
1038
1048
|
// https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec
|
|
1039
1049
|
// for decoding as a standard Map
|
|
1040
|
-
|
|
1041
|
-
|
|
1050
|
+
let decoder = currentDecoder;
|
|
1051
|
+
if (decoder.mapsAsObjects) {
|
|
1052
|
+
decoder.mapsAsObjects = false;
|
|
1042
1053
|
restoreMapsAsObject = true;
|
|
1054
|
+
try {
|
|
1055
|
+
return read()
|
|
1056
|
+
} finally {
|
|
1057
|
+
// normally restored by the map header, but not if the tagged value is not a map or the read fails
|
|
1058
|
+
if (restoreMapsAsObject) {
|
|
1059
|
+
decoder.mapsAsObjects = true;
|
|
1060
|
+
restoreMapsAsObject = false;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1043
1063
|
}
|
|
1044
1064
|
return read()
|
|
1045
1065
|
}).handlesRead = true;
|
|
@@ -1159,10 +1179,12 @@ function readJustLength() {
|
|
|
1159
1179
|
token = src[position$1++];
|
|
1160
1180
|
break
|
|
1161
1181
|
case 0x19:
|
|
1182
|
+
if (position$1 + 2 > srcEnd) throw endOfCBORError()
|
|
1162
1183
|
token = dataView.getUint16(position$1);
|
|
1163
1184
|
position$1 += 2;
|
|
1164
1185
|
break
|
|
1165
1186
|
case 0x1a:
|
|
1187
|
+
if (position$1 + 4 > srcEnd) throw endOfCBORError()
|
|
1166
1188
|
token = dataView.getUint32(position$1);
|
|
1167
1189
|
position$1 += 4;
|
|
1168
1190
|
break
|
|
@@ -1204,22 +1226,27 @@ function saveState(callback) {
|
|
|
1204
1226
|
let savedStructures = currentStructures;
|
|
1205
1227
|
let savedDecoder = currentDecoder;
|
|
1206
1228
|
let savedSequentialMode = sequentialMode;
|
|
1207
|
-
let
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1229
|
+
let savedRestoreMapsAsObject = restoreMapsAsObject;
|
|
1230
|
+
restoreMapsAsObject = false;
|
|
1231
|
+
try {
|
|
1232
|
+
return callback()
|
|
1233
|
+
} finally {
|
|
1234
|
+
srcEnd = savedSrcEnd;
|
|
1235
|
+
position$1 = savedPosition;
|
|
1236
|
+
stringPosition = savedStringPosition;
|
|
1237
|
+
srcStringStart = savedSrcStringStart;
|
|
1238
|
+
srcStringEnd = savedSrcStringEnd;
|
|
1239
|
+
srcString = savedSrcString;
|
|
1240
|
+
strings = savedStrings;
|
|
1241
|
+
referenceMap = savedReferenceMap;
|
|
1242
|
+
bundledStrings$1 = savedBundledStrings;
|
|
1243
|
+
src = savedSrc;
|
|
1244
|
+
sequentialMode = savedSequentialMode;
|
|
1245
|
+
currentStructures = savedStructures;
|
|
1246
|
+
currentDecoder = savedDecoder;
|
|
1247
|
+
restoreMapsAsObject = savedRestoreMapsAsObject;
|
|
1248
|
+
dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
|
|
1249
|
+
}
|
|
1223
1250
|
}
|
|
1224
1251
|
function clearSource() {
|
|
1225
1252
|
src = null;
|
|
@@ -1234,7 +1261,8 @@ function addExtension$1(extension) {
|
|
|
1234
1261
|
function setSizeLimits(limits) {
|
|
1235
1262
|
if (limits.maxMapSize) maxMapSize = limits.maxMapSize;
|
|
1236
1263
|
if (limits.maxArraySize) maxArraySize = limits.maxArraySize;
|
|
1237
|
-
if (limits.maxObjectSize) limits.maxObjectSize;
|
|
1264
|
+
if (limits.maxObjectSize) maxObjectSize = limits.maxObjectSize;
|
|
1265
|
+
objectSizeLimit = Math.min(maxObjectSize, maxMapSize);
|
|
1238
1266
|
}
|
|
1239
1267
|
|
|
1240
1268
|
const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
|
|
@@ -1436,7 +1464,7 @@ class Encoder extends Decoder {
|
|
|
1436
1464
|
if (throwOnIterable)
|
|
1437
1465
|
return;
|
|
1438
1466
|
encode(value);
|
|
1439
|
-
if (bundledStrings) {
|
|
1467
|
+
if (bundledStrings && bundledStrings.position) { // position is only set once a bundle has been started
|
|
1440
1468
|
writeBundles(start, encode);
|
|
1441
1469
|
}
|
|
1442
1470
|
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 +2549,22 @@ class DecoderStream extends stream.Transform {
|
|
|
2521
2549
|
chunk = Buffer.concat([this.incompleteBuffer, chunk]);
|
|
2522
2550
|
this.incompleteBuffer = null;
|
|
2523
2551
|
}
|
|
2524
|
-
let values;
|
|
2552
|
+
let values, fatalError;
|
|
2525
2553
|
try {
|
|
2526
2554
|
values = this.decoder.decodeMultiple(chunk);
|
|
2527
2555
|
} catch(error) {
|
|
2528
|
-
|
|
2556
|
+
values = error.values;
|
|
2557
|
+
if (error.incomplete)
|
|
2529
2558
|
this.incompleteBuffer = chunk.slice(error.lastPosition);
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
value = this.getNullValue();
|
|
2538
|
-
this.push(value);
|
|
2539
|
-
}
|
|
2559
|
+
else
|
|
2560
|
+
fatalError = error;
|
|
2561
|
+
}
|
|
2562
|
+
for (let value of values || []) {
|
|
2563
|
+
if (value === null)
|
|
2564
|
+
value = this.getNullValue();
|
|
2565
|
+
this.push(value);
|
|
2540
2566
|
}
|
|
2541
|
-
callback();
|
|
2567
|
+
callback(fatalError);
|
|
2542
2568
|
}
|
|
2543
2569
|
getNullValue() {
|
|
2544
2570
|
return Symbol.for(null)
|
|
@@ -2591,7 +2617,7 @@ function decodeIter (bufferIterator, options = {}) {
|
|
|
2591
2617
|
}
|
|
2592
2618
|
|
|
2593
2619
|
const decoder = new Decoder(options);
|
|
2594
|
-
let incomplete;
|
|
2620
|
+
let incomplete, fatalError;
|
|
2595
2621
|
const parser = (chunk) => {
|
|
2596
2622
|
let yields;
|
|
2597
2623
|
// if there's incomplete data from previous chunk, concatinate and try again
|
|
@@ -2603,26 +2629,28 @@ function decodeIter (bufferIterator, options = {}) {
|
|
|
2603
2629
|
try {
|
|
2604
2630
|
yields = decoder.decodeMultiple(chunk);
|
|
2605
2631
|
} catch (err) {
|
|
2632
|
+
yields = err.values;
|
|
2606
2633
|
if (err.incomplete) {
|
|
2607
2634
|
incomplete = chunk.slice(err.lastPosition);
|
|
2608
|
-
yields = err.values;
|
|
2609
2635
|
} else {
|
|
2610
|
-
|
|
2636
|
+
fatalError = err;
|
|
2611
2637
|
}
|
|
2612
2638
|
}
|
|
2613
|
-
return yields
|
|
2639
|
+
return yields || []
|
|
2614
2640
|
};
|
|
2615
2641
|
|
|
2616
2642
|
if (typeof bufferIterator[Symbol.iterator] === 'function') {
|
|
2617
2643
|
return (function * iter () {
|
|
2618
2644
|
for (const value of bufferIterator) {
|
|
2619
2645
|
yield * parser(value);
|
|
2646
|
+
if (fatalError) throw fatalError
|
|
2620
2647
|
}
|
|
2621
2648
|
})()
|
|
2622
2649
|
} else if (typeof bufferIterator[Symbol.asyncIterator] === 'function') {
|
|
2623
2650
|
return (async function * iter () {
|
|
2624
2651
|
for await (const value of bufferIterator) {
|
|
2625
2652
|
yield * parser(value);
|
|
2653
|
+
if (fatalError) throw fatalError
|
|
2626
2654
|
}
|
|
2627
2655
|
})()
|
|
2628
2656
|
}
|