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/node.cjs CHANGED
@@ -17,6 +17,10 @@ const RECORD_INLINE_ID = 0xdfff; // temporary first-come first-serve tag // prop
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,
23
+ // many keys in an object, so also probably a reasonable choice there.
20
24
  let strings = EMPTY_ARRAY;
21
25
  let stringPosition = 0;
22
26
  let currentDecoder = {};
@@ -293,6 +297,7 @@ function read() {
293
297
  let array = [];
294
298
  let value, i = 0;
295
299
  while ((value = read()) != STOP_CODE) {
300
+ if (i >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
296
301
  array[i++] = value;
297
302
  }
298
303
  return majorType == 4 ? array : majorType == 3 ? array.join('') : Buffer.concat(array)
@@ -300,8 +305,19 @@ function read() {
300
305
  let key;
301
306
  if (currentDecoder.mapsAsObjects) {
302
307
  let object = {};
303
- if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) object[safeKey(currentDecoder.decodeKey(key))] = read();
304
- else while ((key = read()) != STOP_CODE) object[safeKey(key)] = read();
308
+ let i = 0;
309
+ if (currentDecoder.keyMap) {
310
+ while((key = read()) != STOP_CODE) {
311
+ if (i++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)
312
+ object[safeKey(currentDecoder.decodeKey(key))] = read();
313
+ }
314
+ }
315
+ else {
316
+ while ((key = read()) != STOP_CODE) {
317
+ if (i++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)
318
+ object[safeKey(key)] = read();
319
+ }
320
+ }
305
321
  return object
306
322
  } else {
307
323
  if (restoreMapsAsObject) {
@@ -309,8 +325,24 @@ function read() {
309
325
  restoreMapsAsObject = false;
310
326
  }
311
327
  let map = new Map();
312
- if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) map.set(currentDecoder.decodeKey(key), read());
313
- else while ((key = read()) != STOP_CODE) map.set(key, read());
328
+ if (currentDecoder.keyMap) {
329
+ let i = 0;
330
+ while((key = read()) != STOP_CODE) {
331
+ if (i++ >= maxMapSize) {
332
+ throw new Error(`Map size exceeds ${maxMapSize}`);
333
+ }
334
+ map.set(currentDecoder.decodeKey(key), read());
335
+ }
336
+ }
337
+ else {
338
+ let i = 0;
339
+ while ((key = read()) != STOP_CODE) {
340
+ if (i++ >= maxMapSize) {
341
+ throw new Error(`Map size exceeds ${maxMapSize}`);
342
+ }
343
+ map.set(key, read());
344
+ }
345
+ }
314
346
  return map
315
347
  }
316
348
  case 7:
@@ -341,12 +373,14 @@ function read() {
341
373
  }
342
374
  return readFixedString(token)
343
375
  case 4: // array
376
+ if (token >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
344
377
  let array = new Array(token);
345
378
  //if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())
346
379
  //else
347
380
  for (let i = 0; i < token; i++) array[i] = read();
348
381
  return array
349
382
  case 5: // map
383
+ if (token >= maxMapSize) throw new Error(`Map size exceeds ${maxArraySize}`)
350
384
  if (currentDecoder.mapsAsObjects) {
351
385
  let object = {};
352
386
  if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read();
@@ -448,6 +482,7 @@ function read() {
448
482
  }
449
483
  const validName = /^[a-zA-Z_$][a-zA-Z\d_$]*$/;
450
484
  function createStructureReader(structure) {
485
+ if (!structure) throw new Error('Structure is required in record definition');
451
486
  function readObject() {
452
487
  // get the array size from the header
453
488
  let length = src[position$1++];
@@ -503,7 +538,8 @@ function createStructureReader(structure) {
503
538
  function safeKey(key) {
504
539
  // protect against prototype pollution
505
540
  if (typeof key === 'string') return key === '__proto__' ? '__proto_' : key
506
- if (typeof key !== 'object') return key.toString()
541
+ if (typeof key === 'number' || typeof key === 'boolean' || typeof key === 'bigint') return key.toString();
542
+ if (key == null) return key + '';
507
543
  // protect against expensive (DoS) string conversions
508
544
  throw new Error('Invalid property name type ' + typeof key);
509
545
  }
@@ -808,7 +844,7 @@ currentExtensions[2] = (buffer) => {
808
844
  // bigint extension
809
845
  let value = BigInt(0);
810
846
  for (let i = 0, l = buffer.byteLength; i < l; i++) {
811
- value = BigInt(buffer[i]) + value << BigInt(8);
847
+ value = BigInt(buffer[i]) + (value << BigInt(8));
812
848
  }
813
849
  return value
814
850
  };
@@ -923,6 +959,7 @@ currentExtensions[28] = (read) => {
923
959
  referenceMap.id = 0;
924
960
  }
925
961
  let id = referenceMap.id++;
962
+ let startingPosition = position$1;
926
963
  let token = src[position$1];
927
964
  let target;
928
965
  // TODO: handle Maps, Sets, and other types that can cycle; this is complicated, because you potentially need to read
@@ -935,8 +972,20 @@ currentExtensions[28] = (read) => {
935
972
  let refEntry = { target }; // a placeholder object
936
973
  referenceMap.set(id, refEntry);
937
974
  let targetProperties = read(); // read the next value as the target object to id
938
- if (refEntry.used) // there is a cycle, so we have to assign properties to original target
975
+ if (refEntry.used) {// there is a cycle, so we have to assign properties to original target
976
+ if (Object.getPrototypeOf(target) !== Object.getPrototypeOf(targetProperties)) {
977
+ // this means that the returned target does not match the targetProperties, so we need rerun the read to
978
+ // have the correctly create instance be assigned as a reference, then we do the copy the properties back to the
979
+ // target
980
+ // reset the position so that the read can be repeated
981
+ position$1 = startingPosition;
982
+ // the returned instance is our new target for references
983
+ target = targetProperties;
984
+ referenceMap.set(id, { target });
985
+ targetProperties = read();
986
+ }
939
987
  return Object.assign(target, targetProperties)
988
+ }
940
989
  refEntry.target = targetProperties; // the placeholder wasn't used, replace with the deserialized one
941
990
  return targetProperties // no cycle, can just use the returned read object
942
991
  };
@@ -1018,7 +1067,7 @@ function registerTypedArray(TypedArray, tag) {
1018
1067
  for (let littleEndian = 0; littleEndian < 2; littleEndian++) {
1019
1068
  if (!littleEndian && bytesPerElement == 1)
1020
1069
  continue
1021
- let sizeShift = bytesPerElement == 2 ? 1 : bytesPerElement == 4 ? 2 : 3;
1070
+ let sizeShift = bytesPerElement == 2 ? 1 : bytesPerElement == 4 ? 2 : bytesPerElement == 8 ? 3 : 0;
1022
1071
  currentExtensions[littleEndian ? tag : (tag - 4)] = (bytesPerElement == 1 || littleEndian == isLittleEndianMachine$1) ? (buffer) => {
1023
1072
  if (!TypedArray)
1024
1073
  throw new Error('Could not find typed array for code ' + tag)
@@ -1028,7 +1077,7 @@ function registerTypedArray(TypedArray, tag) {
1028
1077
  bytesPerElement === 2 && !(buffer.byteOffset & 1) ||
1029
1078
  bytesPerElement === 4 && !(buffer.byteOffset & 3) ||
1030
1079
  bytesPerElement === 8 && !(buffer.byteOffset & 7))
1031
- return new TypedArray(buffer.buffer, buffer.byteOffset, buffer.byteLength);
1080
+ return new TypedArray(buffer.buffer, buffer.byteOffset, buffer.byteLength >> sizeShift);
1032
1081
  }
1033
1082
  // we have to slice/copy here to get a new ArrayBuffer, if we are not word/byte aligned
1034
1083
  return new TypedArray(Uint8Array.prototype.slice.call(buffer, 0).buffer)
@@ -1145,6 +1194,12 @@ function addExtension$1(extension) {
1145
1194
  currentExtensions[extension.tag] = extension.decode;
1146
1195
  }
1147
1196
 
1197
+ function setSizeLimits(limits) {
1198
+ if (limits.maxMapSize) maxMapSize = limits.maxMapSize;
1199
+ if (limits.maxArraySize) maxArraySize = limits.maxArraySize;
1200
+ if (limits.maxObjectSize) limits.maxObjectSize;
1201
+ }
1202
+
1148
1203
  const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
1149
1204
  for (let i = 0; i < 256; i++) {
1150
1205
  mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103));
@@ -1632,7 +1687,7 @@ class Encoder extends Decoder {
1632
1687
  }
1633
1688
  let constructor = value.constructor;
1634
1689
  if (constructor === Object) {
1635
- writeObject(value, true);
1690
+ writeObject(value);
1636
1691
  } else if (constructor === Array) {
1637
1692
  length = value.length;
1638
1693
  if (length < 0x18) {
@@ -1727,8 +1782,8 @@ class Encoder extends Decoder {
1727
1782
  return encode(json)
1728
1783
  }
1729
1784
 
1730
- // no extension found, write as object
1731
- writeObject(value, !value.hasOwnProperty); // if it doesn't have hasOwnProperty, don't do hasOwnProperty checks
1785
+ // no extension found, write as a plain object
1786
+ writeObject(value);
1732
1787
  }
1733
1788
  }
1734
1789
  } else if (type === 'boolean') {
@@ -1748,7 +1803,19 @@ class Encoder extends Decoder {
1748
1803
  target[position++] = 0xfb;
1749
1804
  targetView.setFloat64(position, Number(value));
1750
1805
  } else {
1751
- throw new RangeError(value + ' was too large to fit in CBOR 64-bit integer format, set largeBigIntToFloat to convert to float-64')
1806
+ if (value >= BigInt(0))
1807
+ target[position++] = 0xc2; // tag 2
1808
+ else {
1809
+ target[position++] = 0xc3; // tag 2
1810
+ value = BigInt(-1) - value;
1811
+ }
1812
+ let bytes = [];
1813
+ while (value) {
1814
+ bytes.push(Number(value & BigInt(0xff)));
1815
+ value >>= BigInt(8);
1816
+ }
1817
+ writeBuffer(new Uint8Array(bytes.reverse()), makeRoom);
1818
+ return;
1752
1819
  }
1753
1820
  }
1754
1821
  position += 8;
@@ -1790,19 +1857,19 @@ class Encoder extends Decoder {
1790
1857
  }
1791
1858
  }
1792
1859
  } :
1793
- (object, safePrototype) => {
1860
+ (object) => {
1794
1861
  target[position++] = 0xb9; // always use map 16, so we can preallocate and set the length afterwards
1795
1862
  let objectOffset = position - start;
1796
1863
  position += 2;
1797
1864
  let size = 0;
1798
- if (encoder.keyMap) {
1799
- for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1865
+ if (encoder.keyMap) {
1866
+ for (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1800
1867
  encode(encoder.encodeKey(key));
1801
1868
  encode(object[key]);
1802
1869
  size++;
1803
1870
  }
1804
1871
  } else {
1805
- for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1872
+ for (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1806
1873
  encode(key);
1807
1874
  encode(object[key]);
1808
1875
  size++;
@@ -1811,7 +1878,7 @@ class Encoder extends Decoder {
1811
1878
  target[objectOffset++ + start] = size >> 8;
1812
1879
  target[objectOffset + start] = size & 0xff;
1813
1880
  } :
1814
- (object, safePrototype) => {
1881
+ (object, skipValues) => {
1815
1882
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1816
1883
  let newTransitions = 0;
1817
1884
  let length = 0;
@@ -1830,7 +1897,7 @@ class Encoder extends Decoder {
1830
1897
  transition = nextTransition;
1831
1898
  }
1832
1899
  } else {
1833
- for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1900
+ for (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1834
1901
  nextTransition = transition[key];
1835
1902
  if (!nextTransition) {
1836
1903
  if (transition[RECORD_SYMBOL] & 0x100000) {// this indicates it is a brancheable/extendable terminal node, so we will use this record id and extend it
@@ -1890,9 +1957,9 @@ class Encoder extends Decoder {
1890
1957
  writeArrayHeader(length + 2);
1891
1958
  encode(0xe000 + recordId);
1892
1959
  encode(keys);
1893
- if (safePrototype === null) return; // special exit for iterator
1960
+ if (skipValues) return; // special exit for iterator
1894
1961
  for (let key in object)
1895
- if (safePrototype || object.hasOwnProperty(key))
1962
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key))
1896
1963
  encode(object[key]);
1897
1964
  return
1898
1965
  }
@@ -1902,9 +1969,9 @@ class Encoder extends Decoder {
1902
1969
  } else {
1903
1970
  writeArrayHeader(length);
1904
1971
  }
1905
- if (safePrototype === null) return; // special exit for iterator
1972
+ if (skipValues) return; // special exit for iterator
1906
1973
  for (let key in object)
1907
- if (safePrototype || object.hasOwnProperty(key))
1974
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key))
1908
1975
  encode(object[key]);
1909
1976
  };
1910
1977
  const makeRoom = (end) => {
@@ -1942,7 +2009,7 @@ class Encoder extends Decoder {
1942
2009
  if (constructor === Object) {
1943
2010
  let useRecords = encoder.useRecords !== false;
1944
2011
  if (useRecords)
1945
- writeObject(object, null); // write the record identifier
2012
+ writeObject(object, true); // write the record identifier
1946
2013
  else
1947
2014
  writeEntityLength(Object.keys(object).length, 0xa0);
1948
2015
  for (let key in object) {
@@ -1967,7 +2034,7 @@ class Encoder extends Decoder {
1967
2034
  yield* tryEncode(value, iterateProperties, 'element');
1968
2035
  } else encode(value);
1969
2036
  }
1970
- } else if (object[Symbol.iterator]) {
2037
+ } else if (object[Symbol.iterator] && !object.buffer) { // iterator, but exclude typed arrays
1971
2038
  target[position++] = 0x9f; // start indefinite array
1972
2039
  for (let value of object) {
1973
2040
  if (value && (typeof value === 'object' || position - start > chunkThreshold)) {
@@ -2557,5 +2624,6 @@ exports.encodeAsIterable = encodeAsIterable;
2557
2624
  exports.encodeIter = encodeIter;
2558
2625
  exports.mapsAsObjects = mapsAsObjects;
2559
2626
  exports.roundFloat32 = roundFloat32;
2627
+ exports.setSizeLimits = setSizeLimits;
2560
2628
  exports.useRecords = useRecords;
2561
2629
  //# sourceMappingURL=node.cjs.map