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