cbor-x 1.5.8 → 1.6.0

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.
@@ -17,6 +17,9 @@
17
17
  const BUNDLED_STRINGS_ID = 0xdff9;
18
18
  const PACKED_REFERENCE_TAG_ID = 6;
19
19
  const STOP_CODE = {};
20
+ let maxArraySize = 112810000; // This is the maximum array size in V8. We would potentially detect and set it higher
21
+ // for JSC, but this is pretty large and should be sufficient for most use cases
22
+ let maxMapSize = 16810000; // JavaScript has a fixed maximum map size of about 16710000, but JS itself enforces this,
20
23
  let currentDecoder = {};
21
24
  let currentStructures;
22
25
  let srcString;
@@ -290,6 +293,7 @@
290
293
  let array = [];
291
294
  let value, i = 0;
292
295
  while ((value = read()) != STOP_CODE) {
296
+ if (i >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
293
297
  array[i++] = value;
294
298
  }
295
299
  return majorType == 4 ? array : majorType == 3 ? array.join('') : Buffer.concat(array)
@@ -297,8 +301,19 @@
297
301
  let key;
298
302
  if (currentDecoder.mapsAsObjects) {
299
303
  let object = {};
300
- if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) object[safeKey(currentDecoder.decodeKey(key))] = read();
301
- else while ((key = read()) != STOP_CODE) object[safeKey(key)] = read();
304
+ let i = 0;
305
+ if (currentDecoder.keyMap) {
306
+ while((key = read()) != STOP_CODE) {
307
+ if (i++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)
308
+ object[safeKey(currentDecoder.decodeKey(key))] = read();
309
+ }
310
+ }
311
+ else {
312
+ while ((key = read()) != STOP_CODE) {
313
+ if (i++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)
314
+ object[safeKey(key)] = read();
315
+ }
316
+ }
302
317
  return object
303
318
  } else {
304
319
  if (restoreMapsAsObject) {
@@ -306,8 +321,24 @@
306
321
  restoreMapsAsObject = false;
307
322
  }
308
323
  let map = new Map();
309
- if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) map.set(currentDecoder.decodeKey(key), read());
310
- else while ((key = read()) != STOP_CODE) map.set(key, read());
324
+ if (currentDecoder.keyMap) {
325
+ let i = 0;
326
+ while((key = read()) != STOP_CODE) {
327
+ if (i++ >= maxMapSize) {
328
+ throw new Error(`Map size exceeds ${maxMapSize}`);
329
+ }
330
+ map.set(currentDecoder.decodeKey(key), read());
331
+ }
332
+ }
333
+ else {
334
+ let i = 0;
335
+ while ((key = read()) != STOP_CODE) {
336
+ if (i++ >= maxMapSize) {
337
+ throw new Error(`Map size exceeds ${maxMapSize}`);
338
+ }
339
+ map.set(key, read());
340
+ }
341
+ }
311
342
  return map
312
343
  }
313
344
  case 7:
@@ -338,12 +369,14 @@
338
369
  }
339
370
  return readFixedString(token)
340
371
  case 4: // array
372
+ if (token >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
341
373
  let array = new Array(token);
342
374
  //if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())
343
375
  //else
344
376
  for (let i = 0; i < token; i++) array[i] = read();
345
377
  return array
346
378
  case 5: // map
379
+ if (token >= maxMapSize) throw new Error(`Map size exceeds ${maxArraySize}`)
347
380
  if (currentDecoder.mapsAsObjects) {
348
381
  let object = {};
349
382
  if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read();
@@ -445,6 +478,7 @@
445
478
  }
446
479
  const validName = /^[a-zA-Z_$][a-zA-Z\d_$]*$/;
447
480
  function createStructureReader(structure) {
481
+ if (!structure) throw new Error('Structure is required in record definition');
448
482
  function readObject() {
449
483
  // get the array size from the header
450
484
  let length = src[position$1++];
@@ -500,7 +534,8 @@
500
534
  function safeKey(key) {
501
535
  // protect against prototype pollution
502
536
  if (typeof key === 'string') return key === '__proto__' ? '__proto_' : key
503
- if (typeof key !== 'object') return key.toString()
537
+ if (typeof key === 'number' || typeof key === 'boolean' || typeof key === 'bigint') return key.toString();
538
+ if (key == null) return key + '';
504
539
  // protect against expensive (DoS) string conversions
505
540
  throw new Error('Invalid property name type ' + typeof key);
506
541
  }
@@ -770,7 +805,7 @@
770
805
  // bigint extension
771
806
  let value = BigInt(0);
772
807
  for (let i = 0, l = buffer.byteLength; i < l; i++) {
773
- value = BigInt(buffer[i]) + value << BigInt(8);
808
+ value = BigInt(buffer[i]) + (value << BigInt(8));
774
809
  }
775
810
  return value
776
811
  };
@@ -885,6 +920,7 @@
885
920
  referenceMap.id = 0;
886
921
  }
887
922
  let id = referenceMap.id++;
923
+ let startingPosition = position$1;
888
924
  let token = src[position$1];
889
925
  let target;
890
926
  // TODO: handle Maps, Sets, and other types that can cycle; this is complicated, because you potentially need to read
@@ -897,8 +933,20 @@
897
933
  let refEntry = { target }; // a placeholder object
898
934
  referenceMap.set(id, refEntry);
899
935
  let targetProperties = read(); // read the next value as the target object to id
900
- if (refEntry.used) // there is a cycle, so we have to assign properties to original target
936
+ if (refEntry.used) {// there is a cycle, so we have to assign properties to original target
937
+ if (Object.getPrototypeOf(target) !== Object.getPrototypeOf(targetProperties)) {
938
+ // this means that the returned target does not match the targetProperties, so we need rerun the read to
939
+ // have the correctly create instance be assigned as a reference, then we do the copy the properties back to the
940
+ // target
941
+ // reset the position so that the read can be repeated
942
+ position$1 = startingPosition;
943
+ // the returned instance is our new target for references
944
+ target = targetProperties;
945
+ referenceMap.set(id, { target });
946
+ targetProperties = read();
947
+ }
901
948
  return Object.assign(target, targetProperties)
949
+ }
902
950
  refEntry.target = targetProperties; // the placeholder wasn't used, replace with the deserialized one
903
951
  return targetProperties // no cycle, can just use the returned read object
904
952
  };
@@ -980,7 +1028,7 @@
980
1028
  for (let littleEndian = 0; littleEndian < 2; littleEndian++) {
981
1029
  if (!littleEndian && bytesPerElement == 1)
982
1030
  continue
983
- let sizeShift = bytesPerElement == 2 ? 1 : bytesPerElement == 4 ? 2 : 3;
1031
+ let sizeShift = bytesPerElement == 2 ? 1 : bytesPerElement == 4 ? 2 : bytesPerElement == 8 ? 3 : 0;
984
1032
  currentExtensions[littleEndian ? tag : (tag - 4)] = (bytesPerElement == 1 || littleEndian == isLittleEndianMachine$1) ? (buffer) => {
985
1033
  if (!TypedArray)
986
1034
  throw new Error('Could not find typed array for code ' + tag)
@@ -990,7 +1038,7 @@
990
1038
  bytesPerElement === 2 && !(buffer.byteOffset & 1) ||
991
1039
  bytesPerElement === 4 && !(buffer.byteOffset & 3) ||
992
1040
  bytesPerElement === 8 && !(buffer.byteOffset & 7))
993
- return new TypedArray(buffer.buffer, buffer.byteOffset, buffer.byteLength);
1041
+ return new TypedArray(buffer.buffer, buffer.byteOffset, buffer.byteLength >> sizeShift);
994
1042
  }
995
1043
  // we have to slice/copy here to get a new ArrayBuffer, if we are not word/byte aligned
996
1044
  return new TypedArray(Uint8Array.prototype.slice.call(buffer, 0).buffer)
@@ -1103,6 +1151,12 @@
1103
1151
  currentExtensions[extension.tag] = extension.decode;
1104
1152
  }
1105
1153
 
1154
+ function setSizeLimits(limits) {
1155
+ if (limits.maxMapSize) maxMapSize = limits.maxMapSize;
1156
+ if (limits.maxArraySize) maxArraySize = limits.maxArraySize;
1157
+ if (limits.maxObjectSize) limits.maxObjectSize;
1158
+ }
1159
+
1106
1160
  const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
1107
1161
  for (let i = 0; i < 256; i++) {
1108
1162
  mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103));
@@ -1590,7 +1644,7 @@
1590
1644
  }
1591
1645
  let constructor = value.constructor;
1592
1646
  if (constructor === Object) {
1593
- writeObject(value, true);
1647
+ writeObject(value);
1594
1648
  } else if (constructor === Array) {
1595
1649
  length = value.length;
1596
1650
  if (length < 0x18) {
@@ -1685,8 +1739,8 @@
1685
1739
  return encode(json)
1686
1740
  }
1687
1741
 
1688
- // no extension found, write as object
1689
- writeObject(value, !value.hasOwnProperty); // if it doesn't have hasOwnProperty, don't do hasOwnProperty checks
1742
+ // no extension found, write as a plain object
1743
+ writeObject(value);
1690
1744
  }
1691
1745
  }
1692
1746
  } else if (type === 'boolean') {
@@ -1706,7 +1760,19 @@
1706
1760
  target[position++] = 0xfb;
1707
1761
  targetView.setFloat64(position, Number(value));
1708
1762
  } else {
1709
- throw new RangeError(value + ' was too large to fit in CBOR 64-bit integer format, set largeBigIntToFloat to convert to float-64')
1763
+ if (value >= BigInt(0))
1764
+ target[position++] = 0xc2; // tag 2
1765
+ else {
1766
+ target[position++] = 0xc3; // tag 2
1767
+ value = BigInt(-1) - value;
1768
+ }
1769
+ let bytes = [];
1770
+ while (value) {
1771
+ bytes.push(Number(value & BigInt(0xff)));
1772
+ value >>= BigInt(8);
1773
+ }
1774
+ writeBuffer(new Uint8Array(bytes.reverse()), makeRoom);
1775
+ return;
1710
1776
  }
1711
1777
  }
1712
1778
  position += 8;
@@ -1748,19 +1814,19 @@
1748
1814
  }
1749
1815
  }
1750
1816
  } :
1751
- (object, safePrototype) => {
1817
+ (object) => {
1752
1818
  target[position++] = 0xb9; // always use map 16, so we can preallocate and set the length afterwards
1753
1819
  let objectOffset = position - start;
1754
1820
  position += 2;
1755
1821
  let size = 0;
1756
- if (encoder.keyMap) {
1757
- for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1822
+ if (encoder.keyMap) {
1823
+ for (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1758
1824
  encode(encoder.encodeKey(key));
1759
1825
  encode(object[key]);
1760
1826
  size++;
1761
1827
  }
1762
1828
  } else {
1763
- for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1829
+ for (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1764
1830
  encode(key);
1765
1831
  encode(object[key]);
1766
1832
  size++;
@@ -1769,7 +1835,7 @@
1769
1835
  target[objectOffset++ + start] = size >> 8;
1770
1836
  target[objectOffset + start] = size & 0xff;
1771
1837
  } :
1772
- (object, safePrototype) => {
1838
+ (object, skipValues) => {
1773
1839
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1774
1840
  let newTransitions = 0;
1775
1841
  let length = 0;
@@ -1788,7 +1854,7 @@
1788
1854
  transition = nextTransition;
1789
1855
  }
1790
1856
  } else {
1791
- for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1857
+ for (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1792
1858
  nextTransition = transition[key];
1793
1859
  if (!nextTransition) {
1794
1860
  if (transition[RECORD_SYMBOL] & 0x100000) {// this indicates it is a brancheable/extendable terminal node, so we will use this record id and extend it
@@ -1848,9 +1914,9 @@
1848
1914
  writeArrayHeader(length + 2);
1849
1915
  encode(0xe000 + recordId);
1850
1916
  encode(keys);
1851
- if (safePrototype === null) return; // special exit for iterator
1917
+ if (skipValues) return; // special exit for iterator
1852
1918
  for (let key in object)
1853
- if (safePrototype || object.hasOwnProperty(key))
1919
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key))
1854
1920
  encode(object[key]);
1855
1921
  return
1856
1922
  }
@@ -1860,9 +1926,9 @@
1860
1926
  } else {
1861
1927
  writeArrayHeader(length);
1862
1928
  }
1863
- if (safePrototype === null) return; // special exit for iterator
1929
+ if (skipValues) return; // special exit for iterator
1864
1930
  for (let key in object)
1865
- if (safePrototype || object.hasOwnProperty(key))
1931
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key))
1866
1932
  encode(object[key]);
1867
1933
  };
1868
1934
  const makeRoom = (end) => {
@@ -1900,7 +1966,7 @@
1900
1966
  if (constructor === Object) {
1901
1967
  let useRecords = encoder.useRecords !== false;
1902
1968
  if (useRecords)
1903
- writeObject(object, null); // write the record identifier
1969
+ writeObject(object, true); // write the record identifier
1904
1970
  else
1905
1971
  writeEntityLength(Object.keys(object).length, 0xa0);
1906
1972
  for (let key in object) {
@@ -1925,7 +1991,7 @@
1925
1991
  yield* tryEncode(value, iterateProperties, 'element');
1926
1992
  } else encode(value);
1927
1993
  }
1928
- } else if (object[Symbol.iterator]) {
1994
+ } else if (object[Symbol.iterator] && !object.buffer) { // iterator, but exclude typed arrays
1929
1995
  target[position++] = 0x9f; // start indefinite array
1930
1996
  for (let value of object) {
1931
1997
  if (value && (typeof value === 'object' || position - start > chunkThreshold)) {
@@ -2437,6 +2503,7 @@
2437
2503
  exports.encodeIter = encodeIter;
2438
2504
  exports.isNativeAccelerationEnabled = isNativeAccelerationEnabled;
2439
2505
  exports.roundFloat32 = roundFloat32;
2506
+ exports.setSizeLimits = setSizeLimits;
2440
2507
 
2441
2508
  }));
2442
2509
  //# sourceMappingURL=index-no-eval.cjs.map