cbor-x 1.5.7 → 1.5.9

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
@@ -497,7 +497,12 @@
497
497
  }
498
498
 
499
499
  function safeKey(key) {
500
- return key === '__proto__' ? '__proto_' : key
500
+ // protect against prototype pollution
501
+ if (typeof key === 'string') return key === '__proto__' ? '__proto_' : key
502
+ if (typeof key === 'number' || typeof key === 'boolean' || typeof key === 'bigint') return key.toString();
503
+ if (key == null) return key + '';
504
+ // protect against expensive (DoS) string conversions
505
+ throw new Error('Invalid property name type ' + typeof key);
501
506
  }
502
507
 
503
508
  let readFixedString = readStringJS;
@@ -880,6 +885,7 @@
880
885
  referenceMap.id = 0;
881
886
  }
882
887
  let id = referenceMap.id++;
888
+ let startingPosition = position$1;
883
889
  let token = src[position$1];
884
890
  let target;
885
891
  // TODO: handle Maps, Sets, and other types that can cycle; this is complicated, because you potentially need to read
@@ -892,8 +898,20 @@
892
898
  let refEntry = { target }; // a placeholder object
893
899
  referenceMap.set(id, refEntry);
894
900
  let targetProperties = read(); // read the next value as the target object to id
895
- if (refEntry.used) // there is a cycle, so we have to assign properties to original target
901
+ if (refEntry.used) {// there is a cycle, so we have to assign properties to original target
902
+ if (Object.getPrototypeOf(target) !== Object.getPrototypeOf(targetProperties)) {
903
+ // this means that the returned target does not match the targetProperties, so we need rerun the read to
904
+ // have the correctly create instance be assigned as a reference, then we do the copy the properties back to the
905
+ // target
906
+ // reset the position so that the read can be repeated
907
+ position$1 = startingPosition;
908
+ // the returned instance is our new target for references
909
+ target = targetProperties;
910
+ referenceMap.set(id, { target });
911
+ targetProperties = read();
912
+ }
896
913
  return Object.assign(target, targetProperties)
914
+ }
897
915
  refEntry.target = targetProperties; // the placeholder wasn't used, replace with the deserialized one
898
916
  return targetProperties // no cycle, can just use the returned read object
899
917
  };
@@ -975,7 +993,7 @@
975
993
  for (let littleEndian = 0; littleEndian < 2; littleEndian++) {
976
994
  if (!littleEndian && bytesPerElement == 1)
977
995
  continue
978
- let sizeShift = bytesPerElement == 2 ? 1 : bytesPerElement == 4 ? 2 : 3;
996
+ let sizeShift = bytesPerElement == 2 ? 1 : bytesPerElement == 4 ? 2 : bytesPerElement == 8 ? 3 : 0;
979
997
  currentExtensions[littleEndian ? tag : (tag - 4)] = (bytesPerElement == 1 || littleEndian == isLittleEndianMachine$1) ? (buffer) => {
980
998
  if (!TypedArray)
981
999
  throw new Error('Could not find typed array for code ' + tag)
@@ -985,7 +1003,7 @@
985
1003
  bytesPerElement === 2 && !(buffer.byteOffset & 1) ||
986
1004
  bytesPerElement === 4 && !(buffer.byteOffset & 3) ||
987
1005
  bytesPerElement === 8 && !(buffer.byteOffset & 7))
988
- return new TypedArray(buffer.buffer, buffer.byteOffset, buffer.byteLength);
1006
+ return new TypedArray(buffer.buffer, buffer.byteOffset, buffer.byteLength >> sizeShift);
989
1007
  }
990
1008
  // we have to slice/copy here to get a new ArrayBuffer, if we are not word/byte aligned
991
1009
  return new TypedArray(Uint8Array.prototype.slice.call(buffer, 0).buffer)
@@ -1585,7 +1603,7 @@
1585
1603
  }
1586
1604
  let constructor = value.constructor;
1587
1605
  if (constructor === Object) {
1588
- writeObject(value, true);
1606
+ writeObject(value);
1589
1607
  } else if (constructor === Array) {
1590
1608
  length = value.length;
1591
1609
  if (length < 0x18) {
@@ -1680,8 +1698,8 @@
1680
1698
  return encode(json)
1681
1699
  }
1682
1700
 
1683
- // no extension found, write as object
1684
- writeObject(value, !value.hasOwnProperty); // if it doesn't have hasOwnProperty, don't do hasOwnProperty checks
1701
+ // no extension found, write as a plain object
1702
+ writeObject(value);
1685
1703
  }
1686
1704
  }
1687
1705
  } else if (type === 'boolean') {
@@ -1743,19 +1761,19 @@
1743
1761
  }
1744
1762
  }
1745
1763
  } :
1746
- (object, safePrototype) => {
1764
+ (object) => {
1747
1765
  target[position++] = 0xb9; // always use map 16, so we can preallocate and set the length afterwards
1748
1766
  let objectOffset = position - start;
1749
1767
  position += 2;
1750
1768
  let size = 0;
1751
1769
  if (encoder.keyMap) {
1752
- for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1770
+ for (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1753
1771
  encode(encoder.encodeKey(key));
1754
1772
  encode(object[key]);
1755
1773
  size++;
1756
1774
  }
1757
1775
  } else {
1758
- for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1776
+ for (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1759
1777
  encode(key);
1760
1778
  encode(object[key]);
1761
1779
  size++;
@@ -1764,7 +1782,7 @@
1764
1782
  target[objectOffset++ + start] = size >> 8;
1765
1783
  target[objectOffset + start] = size & 0xff;
1766
1784
  } :
1767
- (object, safePrototype) => {
1785
+ (object, skipValues) => {
1768
1786
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1769
1787
  let newTransitions = 0;
1770
1788
  let length = 0;
@@ -1783,7 +1801,7 @@
1783
1801
  transition = nextTransition;
1784
1802
  }
1785
1803
  } else {
1786
- for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1804
+ for (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1787
1805
  nextTransition = transition[key];
1788
1806
  if (!nextTransition) {
1789
1807
  if (transition[RECORD_SYMBOL] & 0x100000) {// this indicates it is a brancheable/extendable terminal node, so we will use this record id and extend it
@@ -1843,9 +1861,9 @@
1843
1861
  writeArrayHeader(length + 2);
1844
1862
  encode(0xe000 + recordId);
1845
1863
  encode(keys);
1846
- if (safePrototype === null) return; // special exit for iterator
1864
+ if (skipValues) return; // special exit for iterator
1847
1865
  for (let key in object)
1848
- if (safePrototype || object.hasOwnProperty(key))
1866
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key))
1849
1867
  encode(object[key]);
1850
1868
  return
1851
1869
  }
@@ -1855,9 +1873,9 @@
1855
1873
  } else {
1856
1874
  writeArrayHeader(length);
1857
1875
  }
1858
- if (safePrototype === null) return; // special exit for iterator
1876
+ if (skipValues) return; // special exit for iterator
1859
1877
  for (let key in object)
1860
- if (safePrototype || object.hasOwnProperty(key))
1878
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key))
1861
1879
  encode(object[key]);
1862
1880
  };
1863
1881
  const makeRoom = (end) => {
@@ -1895,7 +1913,7 @@
1895
1913
  if (constructor === Object) {
1896
1914
  let useRecords = encoder.useRecords !== false;
1897
1915
  if (useRecords)
1898
- writeObject(object, null); // write the record identifier
1916
+ writeObject(object, true); // write the record identifier
1899
1917
  else
1900
1918
  writeEntityLength(Object.keys(object).length, 0xa0);
1901
1919
  for (let key in object) {