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/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
- // many keys in an object, so also probably a reasonable choice there.
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
- return this ? this.decode(source, end) : Decoder.prototype.decode.call(defaultOptions, source, end)
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
- let error = new Error('Unexpected bundle position');
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 (error instanceof RangeError || error.message.startsWith('Unexpected end of buffer')) {
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++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)
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++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)
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 >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
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 (src[position$1++] != 0x84) {
939
- let error = new Error('Packed values structure must be followed by a 4 element array');
940
- if (src.length < position$1)
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
- let error = new Error('Packed values structure must be followed by a 4 element array');
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
- let error = new Error('No support for non-integer packed references yet');
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
- if (currentDecoder.mapsAsObjects) {
1041
- currentDecoder.mapsAsObjects = false;
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 value = callback();
1208
- srcEnd = savedSrcEnd;
1209
- position$1 = savedPosition;
1210
- stringPosition = savedStringPosition;
1211
- srcStringStart = savedSrcStringStart;
1212
- srcStringEnd = savedSrcStringEnd;
1213
- srcString = savedSrcString;
1214
- strings = savedStrings;
1215
- referenceMap = savedReferenceMap;
1216
- bundledStrings$1 = savedBundledStrings;
1217
- src = savedSrc;
1218
- sequentialMode = savedSequentialMode;
1219
- currentStructures = savedStructures;
1220
- currentDecoder = savedDecoder;
1221
- dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
1222
- return value
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
- if (error.incomplete) {
2556
+ values = error.values;
2557
+ if (error.incomplete)
2529
2558
  this.incompleteBuffer = chunk.slice(error.lastPosition);
2530
- values = error.values;
2531
- } else {
2532
- return callback(error)
2533
- }
2534
- } finally {
2535
- for (let value of values || []) {
2536
- if (value === null)
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
- throw err
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
  }