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/test.js CHANGED
@@ -910,7 +910,7 @@
910
910
  return readFixedString(length)
911
911
  } else { // not cacheable, go back and do a standard read
912
912
  position$1--;
913
- return read().toString()
913
+ return asSafeString(read())
914
914
  }
915
915
  let key = ((length << 5) ^ (length > 1 ? dataView.getUint16(position$1) : length > 0 ? src[position$1] : 0)) & 0xfff;
916
916
  let entry = keyCache[key];
@@ -962,9 +962,17 @@
962
962
  return entry.string = readFixedString(length)
963
963
  }
964
964
 
965
+ function asSafeString(property) {
966
+ // protect against expensive (DoS) string conversions
967
+ if (typeof property === 'string') return property;
968
+ if (typeof property === 'number' || typeof property === 'boolean' || typeof property === 'bigint') return property.toString();
969
+ if (property == null) return property + '';
970
+ throw new Error('Invalid property type for record', typeof property);
971
+ }
965
972
  // the registration of the record definition extension (as "r")
966
973
  const recordDefinition = (id, highByte) => {
967
- let structure = read().map(property => property.toString()); // ensure that all keys are strings and that the array is mutable
974
+ let structure = read().map(asSafeString); // ensure that all keys are strings and
975
+ // that the array is mutable
968
976
  let firstByte = id;
969
977
  if (highByte !== undefined) {
970
978
  id = id < 32 ? -((highByte << 5) + id) : ((highByte << 5) + id);
@@ -998,11 +1006,12 @@
998
1006
  let errors = { Error, TypeError, ReferenceError };
999
1007
  currentExtensions[0x65] = () => {
1000
1008
  let data = read();
1001
- return (errors[data[0]] || Error)(data[1])
1009
+ return (errors[data[0]] || Error)(data[1], { cause: data[2] })
1002
1010
  };
1003
1011
 
1004
1012
  currentExtensions[0x69] = (data) => {
1005
1013
  // id extension (for structured clones)
1014
+ if (currentUnpackr.structuredClone === false) throw new Error('Structured clone extension is disabled')
1006
1015
  let id = dataView.getUint32(position$1 - 4);
1007
1016
  if (!referenceMap)
1008
1017
  referenceMap = new Map();
@@ -1026,6 +1035,7 @@
1026
1035
 
1027
1036
  currentExtensions[0x70] = (data) => {
1028
1037
  // pointer extension (for structured clones)
1038
+ if (currentUnpackr.structuredClone === false) throw new Error('Structured clone extension is disabled')
1029
1039
  let id = dataView.getUint32(position$1 - 4);
1030
1040
  let refEntry = referenceMap.get(id);
1031
1041
  refEntry.used = true;
@@ -1040,8 +1050,15 @@
1040
1050
  currentExtensions[0x74] = (data) => {
1041
1051
  let typeCode = data[0];
1042
1052
  let typedArrayName = typedArrays[typeCode];
1043
- if (!typedArrayName)
1053
+ if (!typedArrayName) {
1054
+ if (typeCode === 16) {
1055
+ let ab = new ArrayBuffer(data.length - 1);
1056
+ let u8 = new Uint8Array(ab);
1057
+ u8.set(data.subarray(1));
1058
+ return ab;
1059
+ }
1044
1060
  throw new Error('Could not find typed array for code ' + typeCode)
1061
+ }
1045
1062
  // we have to always slice/copy here to get a new ArrayBuffer that is word/byte aligned
1046
1063
  return new glbl[typedArrayName](Uint8Array.prototype.slice.call(data, 1).buffer)
1047
1064
  };
@@ -1347,10 +1364,14 @@
1347
1364
  return packr.pack(value, encodeOptions)
1348
1365
  }
1349
1366
  packr.lastNamedStructuresLength = sharedLength;
1367
+ // don't keep large buffers around
1368
+ if (target.length > 0x40000000) target = null;
1350
1369
  return returnBuffer
1351
1370
  }
1352
1371
  }
1353
1372
  }
1373
+ // don't keep large buffers around, they take too much memory and cause problems (limit at 1GB)
1374
+ if (target.length > 0x40000000) target = null;
1354
1375
  if (encodeOptions & RESET_BUFFER_MODE)
1355
1376
  position = start;
1356
1377
  }
@@ -1573,7 +1594,7 @@
1573
1594
  }
1574
1595
  let constructor = value.constructor;
1575
1596
  if (constructor === Object) {
1576
- writeObject(value, true);
1597
+ writeObject(value);
1577
1598
  } else if (constructor === Array) {
1578
1599
  packArray(value);
1579
1600
  } else if (constructor === Map) {
@@ -1669,8 +1690,8 @@
1669
1690
  if (type === 'function')
1670
1691
  return pack(this.writeFunction && this.writeFunction(value));
1671
1692
 
1672
- // no extension found, write as object
1673
- writeObject(value, !value.hasOwnProperty); // if it doesn't have hasOwnProperty, don't do hasOwnProperty checks
1693
+ // no extension found, write as plain object
1694
+ writeObject(value);
1674
1695
  }
1675
1696
  }
1676
1697
  }
@@ -1757,13 +1778,13 @@
1757
1778
  }
1758
1779
  }
1759
1780
  } :
1760
- (object, safePrototype) => {
1781
+ (object) => {
1761
1782
  target[position++] = 0xde; // always using map 16, so we can preallocate and set the length afterwards
1762
1783
  let objectOffset = position - start;
1763
1784
  position += 2;
1764
1785
  let size = 0;
1765
1786
  for (let key in object) {
1766
- if (safePrototype || object.hasOwnProperty(key)) {
1787
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1767
1788
  pack(key);
1768
1789
  pack(object[key]);
1769
1790
  size++;
@@ -1775,12 +1796,12 @@
1775
1796
 
1776
1797
  const writeRecord = this.useRecords === false ? writePlainObject :
1777
1798
  (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)
1778
- (object, safePrototype) => {
1799
+ (object) => {
1779
1800
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1780
1801
  let objectOffset = position++ - start;
1781
1802
  let wroteKeys;
1782
1803
  for (let key in object) {
1783
- if (safePrototype || object.hasOwnProperty(key)) {
1804
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1784
1805
  nextTransition = transition[key];
1785
1806
  if (nextTransition)
1786
1807
  transition = nextTransition;
@@ -1819,10 +1840,10 @@
1819
1840
  insertNewRecord(transition, Object.keys(object), objectOffset, 0);
1820
1841
  }
1821
1842
  } :
1822
- (object, safePrototype) => {
1843
+ (object) => {
1823
1844
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1824
1845
  let newTransitions = 0;
1825
- for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1846
+ for (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1826
1847
  nextTransition = transition[key];
1827
1848
  if (!nextTransition) {
1828
1849
  nextTransition = transition[key] = Object.create(null);
@@ -1842,7 +1863,7 @@
1842
1863
  }
1843
1864
  // now write the values
1844
1865
  for (let key in object)
1845
- if (safePrototype || object.hasOwnProperty(key)) {
1866
+ if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {
1846
1867
  pack(object[key]);
1847
1868
  }
1848
1869
  };
@@ -1850,8 +1871,8 @@
1850
1871
  // craete reference to useRecords if useRecords is a function
1851
1872
  const checkUseRecords = typeof this.useRecords == 'function' && this.useRecords;
1852
1873
 
1853
- const writeObject = checkUseRecords ? (object, safePrototype) => {
1854
- checkUseRecords(object) ? writeRecord(object,safePrototype) : writePlainObject(object,safePrototype);
1874
+ const writeObject = checkUseRecords ? (object) => {
1875
+ checkUseRecords(object) ? writeRecord(object) : writePlainObject(object);
1855
1876
  } : writeRecord;
1856
1877
 
1857
1878
  const makeRoom = (end) => {
@@ -1956,7 +1977,7 @@
1956
1977
  target[insertionOffset + start] = keysTarget[0];
1957
1978
  }
1958
1979
  };
1959
- const writeStruct = (object, safePrototype) => {
1980
+ const writeStruct = (object) => {
1960
1981
  let newPosition = writeStructSlots(object, target, start, position, structures, makeRoom, (value, newPosition, notifySharedUpdate) => {
1961
1982
  if (notifySharedUpdate)
1962
1983
  return hasSharedUpdate = true;
@@ -1970,7 +1991,7 @@
1970
1991
  return position;
1971
1992
  }, this);
1972
1993
  if (newPosition === 0) // bail and go to a msgpack object
1973
- return writeObject(object, true);
1994
+ return writeObject(object);
1974
1995
  position = newPosition;
1975
1996
  };
1976
1997
  }
@@ -2048,7 +2069,7 @@
2048
2069
  target[position++] = 0x65; // 'e' for error
2049
2070
  target[position++] = 0;
2050
2071
  }
2051
- pack([ error.name, error.message ]);
2072
+ pack([ error.name, error.message, error.cause ]);
2052
2073
  }
2053
2074
  }, {
2054
2075
  pack(regex, allocateForWrite, pack) {
@@ -2101,6 +2122,7 @@
2101
2122
  }
2102
2123
  target[position++] = 0x74; // "t" for typed array
2103
2124
  target[position++] = type;
2125
+ if (!typedArray.buffer) typedArray = new Uint8Array(typedArray);
2104
2126
  target.set(new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength), position);
2105
2127
  }
2106
2128
  function writeBuffer(buffer, allocateForWrite) {
@@ -3703,13 +3725,35 @@
3703
3725
  }
3704
3726
  });
3705
3727
 
3728
+ test('moreTyesp: Error with causes', function() {
3729
+ const object = {
3730
+ error: new Error('test'),
3731
+ errorWithCause: new Error('test-1', { cause: new Error('test-2')}),
3732
+ };
3733
+ const packr = new Packr({
3734
+ moreTypes: true,
3735
+ });
3736
+
3737
+ const serialized = packr.pack(object);
3738
+ const deserialized = packr.unpack(serialized);
3739
+ assert.equal(deserialized.error.message, object.error.message);
3740
+ assert.equal(deserialized.error.cause, object.error.cause);
3741
+ assert.equal(deserialized.errorWithCause.message, object.errorWithCause.message);
3742
+ assert.equal(deserialized.errorWithCause.cause.message, object.errorWithCause.cause.message);
3743
+ assert.equal(deserialized.errorWithCause.cause.cause, object.errorWithCause.cause.cause);
3744
+ });
3745
+
3706
3746
  test('structured cloning: self reference', function() {
3707
3747
  let object = {
3708
3748
  test: 'string',
3709
3749
  children: [
3710
3750
  { name: 'child' }
3711
- ]
3751
+ ],
3752
+ value: new ArrayBuffer(10)
3712
3753
  };
3754
+ let u8 = new Uint8Array(object.value);
3755
+ u8[0] = 1;
3756
+ u8[1] = 2;
3713
3757
  object.self = object;
3714
3758
  object.children[1] = object;
3715
3759
  object.children[2] = object.children[0];
@@ -3725,6 +3769,10 @@
3725
3769
  assert.equal(deserialized.children[1], deserialized);
3726
3770
  assert.equal(deserialized.children[0], deserialized.children[2]);
3727
3771
  assert.equal(deserialized.children, deserialized.childrenAgain);
3772
+ assert.equal(deserialized.value.constructor.name, 'ArrayBuffer');
3773
+ u8 = new Uint8Array(deserialized.value);
3774
+ assert.equal(u8[0], 1);
3775
+ assert.equal(u8[1], 2);
3728
3776
  });
3729
3777
 
3730
3778
  test('structured cloning: types', function() {
@@ -3805,6 +3853,13 @@
3805
3853
  assert.deepEqual(deserialized, data);
3806
3854
  });
3807
3855
 
3856
+ test('object with __proto__', function(){
3857
+ const data = { foo: 'bar', __proto__: { isAdmin: true } };
3858
+ var serialized = pack(data);
3859
+ var deserialized = unpack(serialized);
3860
+ assert.deepEqual(deserialized, { foo: 'bar' });
3861
+ });
3862
+
3808
3863
  test('separate instances', function() {
3809
3864
  const packr = new Packr({
3810
3865
  structures: [['m', 'e'], ['action', 'share']]