msgpackr 1.10.0 → 1.10.2

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
@@ -858,7 +858,7 @@
858
858
  return readFixedString(length)
859
859
  } else { // not cacheable, go back and do a standard read
860
860
  position$1--;
861
- return read().toString()
861
+ return asSafeString(read())
862
862
  }
863
863
  let key = ((length << 5) ^ (length > 1 ? dataView.getUint16(position$1) : length > 0 ? src[position$1] : 0)) & 0xfff;
864
864
  let entry = keyCache[key];
@@ -910,9 +910,17 @@
910
910
  return entry.string = readFixedString(length)
911
911
  }
912
912
 
913
+ function asSafeString(property) {
914
+ // protect against expensive (DoS) string conversions
915
+ if (typeof property === 'string') return property;
916
+ if (typeof property === 'number' || typeof property === 'boolean' || typeof property === 'bigint') return property.toString();
917
+ if (property == null) return property + '';
918
+ throw new Error('Invalid property type for record', typeof property);
919
+ }
913
920
  // the registration of the record definition extension (as "r")
914
921
  const recordDefinition = (id, highByte) => {
915
- let structure = read().map(property => property.toString()); // ensure that all keys are strings and that the array is mutable
922
+ let structure = read().map(asSafeString); // ensure that all keys are strings and
923
+ // that the array is mutable
916
924
  let firstByte = id;
917
925
  if (highByte !== undefined) {
918
926
  id = id < 32 ? -((highByte << 5) + id) : ((highByte << 5) + id);
@@ -946,11 +954,12 @@
946
954
  let errors = { Error, TypeError, ReferenceError };
947
955
  currentExtensions[0x65] = () => {
948
956
  let data = read();
949
- return (errors[data[0]] || Error)(data[1])
957
+ return (errors[data[0]] || Error)(data[1], { cause: data[2] })
950
958
  };
951
959
 
952
960
  currentExtensions[0x69] = (data) => {
953
961
  // id extension (for structured clones)
962
+ if (currentUnpackr.structuredClone === false) throw new Error('Structured clone extension is disabled')
954
963
  let id = dataView.getUint32(position$1 - 4);
955
964
  if (!referenceMap)
956
965
  referenceMap = new Map();
@@ -974,6 +983,7 @@
974
983
 
975
984
  currentExtensions[0x70] = (data) => {
976
985
  // pointer extension (for structured clones)
986
+ if (currentUnpackr.structuredClone === false) throw new Error('Structured clone extension is disabled')
977
987
  let id = dataView.getUint32(position$1 - 4);
978
988
  let refEntry = referenceMap.get(id);
979
989
  refEntry.used = true;
@@ -988,8 +998,15 @@
988
998
  currentExtensions[0x74] = (data) => {
989
999
  let typeCode = data[0];
990
1000
  let typedArrayName = typedArrays[typeCode];
991
- if (!typedArrayName)
1001
+ if (!typedArrayName) {
1002
+ if (typeCode === 16) {
1003
+ let ab = new ArrayBuffer(data.length - 1);
1004
+ let u8 = new Uint8Array(ab);
1005
+ u8.set(data.subarray(1));
1006
+ return ab;
1007
+ }
992
1008
  throw new Error('Could not find typed array for code ' + typeCode)
1009
+ }
993
1010
  // we have to always slice/copy here to get a new ArrayBuffer that is word/byte aligned
994
1011
  return new glbl[typedArrayName](Uint8Array.prototype.slice.call(data, 1).buffer)
995
1012
  };
@@ -1285,10 +1302,14 @@
1285
1302
  return packr.pack(value, encodeOptions)
1286
1303
  }
1287
1304
  packr.lastNamedStructuresLength = sharedLength;
1305
+ // don't keep large buffers around
1306
+ if (target.length > 0x40000000) target = null;
1288
1307
  return returnBuffer
1289
1308
  }
1290
1309
  }
1291
1310
  }
1311
+ // don't keep large buffers around, they take too much memory and cause problems (limit at 1GB)
1312
+ if (target.length > 0x40000000) target = null;
1292
1313
  if (encodeOptions & RESET_BUFFER_MODE)
1293
1314
  position = start;
1294
1315
  }
@@ -1511,7 +1532,7 @@
1511
1532
  }
1512
1533
  let constructor = value.constructor;
1513
1534
  if (constructor === Object) {
1514
- writeObject(value, true);
1535
+ writeObject(value);
1515
1536
  } else if (constructor === Array) {
1516
1537
  packArray(value);
1517
1538
  } else if (constructor === Map) {
@@ -1607,8 +1628,8 @@
1607
1628
  if (type === 'function')
1608
1629
  return pack(this.writeFunction && this.writeFunction(value));
1609
1630
 
1610
- // no extension found, write as object
1611
- writeObject(value, !value.hasOwnProperty); // if it doesn't have hasOwnProperty, don't do hasOwnProperty checks
1631
+ // no extension found, write as plain object
1632
+ writeObject(value);
1612
1633
  }
1613
1634
  }
1614
1635
  }
@@ -1695,13 +1716,13 @@
1695
1716
  }
1696
1717
  }
1697
1718
  } :
1698
- (object, safePrototype) => {
1719
+ (object) => {
1699
1720
  target[position++] = 0xde; // always using map 16, so we can preallocate and set the length afterwards
1700
1721
  let objectOffset = position - start;
1701
1722
  position += 2;
1702
1723
  let size = 0;
1703
1724
  for (let key in object) {
1704
- if (safePrototype || object.hasOwnProperty(key)) {
1725
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1705
1726
  pack(key);
1706
1727
  pack(object[key]);
1707
1728
  size++;
@@ -1713,12 +1734,12 @@
1713
1734
 
1714
1735
  const writeRecord = this.useRecords === false ? writePlainObject :
1715
1736
  (options.progressiveRecords && !useTwoByteRecords) ? // this is about 2% faster for highly stable structures, since it only requires one for-in loop (but much more expensive when new structure needs to be written)
1716
- (object, safePrototype) => {
1737
+ (object) => {
1717
1738
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1718
1739
  let objectOffset = position++ - start;
1719
1740
  let wroteKeys;
1720
1741
  for (let key in object) {
1721
- if (safePrototype || object.hasOwnProperty(key)) {
1742
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1722
1743
  nextTransition = transition[key];
1723
1744
  if (nextTransition)
1724
1745
  transition = nextTransition;
@@ -1757,10 +1778,10 @@
1757
1778
  insertNewRecord(transition, Object.keys(object), objectOffset, 0);
1758
1779
  }
1759
1780
  } :
1760
- (object, safePrototype) => {
1781
+ (object) => {
1761
1782
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1762
1783
  let newTransitions = 0;
1763
- for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1784
+ for (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1764
1785
  nextTransition = transition[key];
1765
1786
  if (!nextTransition) {
1766
1787
  nextTransition = transition[key] = Object.create(null);
@@ -1780,7 +1801,7 @@
1780
1801
  }
1781
1802
  // now write the values
1782
1803
  for (let key in object)
1783
- if (safePrototype || object.hasOwnProperty(key)) {
1804
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1784
1805
  pack(object[key]);
1785
1806
  }
1786
1807
  };
@@ -1788,8 +1809,8 @@
1788
1809
  // craete reference to useRecords if useRecords is a function
1789
1810
  const checkUseRecords = typeof this.useRecords == 'function' && this.useRecords;
1790
1811
 
1791
- const writeObject = checkUseRecords ? (object, safePrototype) => {
1792
- checkUseRecords(object) ? writeRecord(object,safePrototype) : writePlainObject(object,safePrototype);
1812
+ const writeObject = checkUseRecords ? (object) => {
1813
+ checkUseRecords(object) ? writeRecord(object) : writePlainObject(object);
1793
1814
  } : writeRecord;
1794
1815
 
1795
1816
  const makeRoom = (end) => {
@@ -1894,7 +1915,7 @@
1894
1915
  target[insertionOffset + start] = keysTarget[0];
1895
1916
  }
1896
1917
  };
1897
- const writeStruct = (object, safePrototype) => {
1918
+ const writeStruct = (object) => {
1898
1919
  let newPosition = writeStructSlots(object, target, start, position, structures, makeRoom, (value, newPosition, notifySharedUpdate) => {
1899
1920
  if (notifySharedUpdate)
1900
1921
  return hasSharedUpdate = true;
@@ -1908,7 +1929,7 @@
1908
1929
  return position;
1909
1930
  }, this);
1910
1931
  if (newPosition === 0) // bail and go to a msgpack object
1911
- return writeObject(object, true);
1932
+ return writeObject(object);
1912
1933
  position = newPosition;
1913
1934
  };
1914
1935
  }
@@ -1986,7 +2007,7 @@
1986
2007
  target[position++] = 0x65; // 'e' for error
1987
2008
  target[position++] = 0;
1988
2009
  }
1989
- pack([ error.name, error.message ]);
2010
+ pack([ error.name, error.message, error.cause ]);
1990
2011
  }
1991
2012
  }, {
1992
2013
  pack(regex, allocateForWrite, pack) {
@@ -2039,6 +2060,7 @@
2039
2060
  }
2040
2061
  target[position++] = 0x74; // "t" for typed array
2041
2062
  target[position++] = type;
2063
+ if (!typedArray.buffer) typedArray = new Uint8Array(typedArray);
2042
2064
  target.set(new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength), position);
2043
2065
  }
2044
2066
  function writeBuffer(buffer, allocateForWrite) {