cbor-x 1.6.5 → 1.6.7

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
@@ -19,7 +19,11 @@
19
19
  let maxArraySize = 112810000; // This is the maximum array size in V8. We would potentially detect and set it higher
20
20
  // for JSC, but this is pretty large and should be sufficient for most use cases
21
21
  let maxMapSize = 16810000; // JavaScript has a fixed maximum map size of about 16710000, but JS itself enforces this,
22
- // many keys in an object, so also probably a reasonable choice there.
22
+ // so we don't need to
23
+
24
+ let maxObjectSize = 16710000; // It takes over a minute to create this many keys in an object, so this is probably a
25
+ // reasonable choice.
26
+ let objectSizeLimit = maxObjectSize; // objects are limited by both maxObjectSize and maxMapSize
23
27
  let strings = EMPTY_ARRAY;
24
28
  let stringPosition = 0;
25
29
  let currentDecoder = {};
@@ -122,7 +126,13 @@
122
126
  // re-entrant execution, save the state and restore it after we do this decode
123
127
  return saveState(() => {
124
128
  clearSource();
125
- return this ? this.decode(source, end) : Decoder.prototype.decode.call(defaultOptions, source, end)
129
+ try {
130
+ return this ? this.decode(source, end) : Decoder.prototype.decode.call(defaultOptions, source, end)
131
+ } catch (error) {
132
+ if (error && typeof error == 'object')
133
+ nestedDecodeErrors.add(error);
134
+ throw error
135
+ }
126
136
  })
127
137
  }
128
138
  srcEnd = end > -1 ? end : source.length;
@@ -199,15 +209,13 @@
199
209
  }
200
210
  }
201
211
  }
212
+ const nestedDecodeErrors = new WeakSet();
202
213
  function checkedRead() {
203
214
  try {
204
215
  let result = read();
205
216
  if (bundledStrings$1) {
206
- if (position$1 >= bundledStrings$1.postBundlePosition) {
207
- let error = new Error('Unexpected bundle position');
208
- error.incomplete = true;
209
- throw error
210
- }
217
+ if (position$1 >= bundledStrings$1.postBundlePosition)
218
+ throw new Error('Unexpected bundle position')
211
219
  // bundled strings to skip past
212
220
  position$1 = bundledStrings$1.postBundlePosition;
213
221
  bundledStrings$1 = null;
@@ -231,20 +239,36 @@
231
239
  return result
232
240
  } catch(error) {
233
241
  clearSource();
234
- if (error instanceof RangeError || error.message.startsWith('Unexpected end of buffer')) {
242
+ if (nestedDecodeErrors.has(error)) {
243
+ // from a nested decode of embedded data (by an extension), which was complete in this source
244
+ if (error.incomplete)
245
+ error.incomplete = false;
246
+ } else if (error instanceof RangeError && position$1 + 8 > srcEnd ||
247
+ error && typeof error.message == 'string' && error.message.startsWith('Unexpected end of buffer')) {
248
+ // a DataView read past the end of the source; these read at most 8 bytes and precede advancing position.
249
+ // Any other RangeError (such as a stack overflow from deeply nested input) is fatal.
235
250
  error.incomplete = true;
236
251
  }
237
252
  throw error
238
253
  }
239
254
  }
240
255
 
256
+ function endOfCBORError() {
257
+ let error = new Error('Unexpected end of CBOR data');
258
+ error.incomplete = true;
259
+ return error
260
+ }
261
+
241
262
  function read() {
263
+ // compared as < so that a NaN position (from a corrupt length) also throws instead of reading undefined
264
+ if (!(position$1 < srcEnd)) throw endOfCBORError()
242
265
  let token = src[position$1++];
243
266
  let majorType = token >> 5;
244
267
  token = token & 0x1f;
245
268
  if (token > 0x17) {
246
269
  switch (token) {
247
270
  case 0x18:
271
+ if (position$1 >= srcEnd) throw endOfCBORError()
248
272
  token = src[position$1++];
249
273
  break
250
274
  case 0x19:
@@ -307,13 +331,13 @@
307
331
  let i = 0;
308
332
  if (currentDecoder.keyMap) {
309
333
  while((key = read()) != STOP_CODE) {
310
- if (i++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)
334
+ if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
311
335
  object[safeKey(currentDecoder.decodeKey(key))] = read();
312
336
  }
313
337
  }
314
338
  else {
315
339
  while ((key = read()) != STOP_CODE) {
316
- if (i++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)
340
+ if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
317
341
  object[safeKey(key)] = read();
318
342
  }
319
343
  }
@@ -359,11 +383,13 @@
359
383
  case 1: // negative int
360
384
  return ~token
361
385
  case 2: // buffer
386
+ if (token > srcEnd - position$1) throw endOfCBORError()
362
387
  return readBin(token)
363
388
  case 3: // string
364
- if (srcStringEnd >= position$1) {
389
+ if (srcStringEnd >= position$1) { // already extracted, which only covers complete strings
365
390
  return srcString.slice(position$1 - srcStringStart, (position$1 += token) - srcStringStart)
366
391
  }
392
+ if (token > srcEnd - position$1) throw endOfCBORError()
367
393
  if (srcStringEnd == 0 && srcEnd < 140 && token < 32) {
368
394
  // for small blocks, avoiding the overhead of the extract call is helpful
369
395
  let string = token < 16 ? shortStringInJS(token) : longStringInJS(token);
@@ -372,15 +398,19 @@
372
398
  }
373
399
  return readFixedString(token)
374
400
  case 4: // array
375
- if (token >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
401
+ if (token > maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
402
+ // every element occupies at least one byte, so a length beyond what remains in the source can
403
+ // never be satisfied; check before allocating so a tiny header can not force a huge allocation
404
+ if (token > srcEnd - position$1) throw endOfCBORError()
376
405
  let array = new Array(token);
377
406
  //if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())
378
407
  //else
379
408
  for (let i = 0; i < token; i++) array[i] = read();
380
409
  return array
381
410
  case 5: // map
382
- if (token >= maxMapSize) throw new Error(`Map size exceeds ${maxArraySize}`)
383
411
  if (currentDecoder.mapsAsObjects) {
412
+ if (token > objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
413
+ if (token > (srcEnd - position$1) / 2) throw endOfCBORError() // each entry needs at least two bytes
384
414
  let object = {};
385
415
  if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read();
386
416
  else for (let i = 0; i < token; i++) object[safeKey(read())] = read();
@@ -390,6 +420,8 @@
390
420
  currentDecoder.mapsAsObjects = true;
391
421
  restoreMapsAsObject = false;
392
422
  }
423
+ if (token > maxMapSize) throw new Error(`Map size exceeds ${maxMapSize}`)
424
+ if (token > (srcEnd - position$1) / 2) throw endOfCBORError()
393
425
  let map = new Map();
394
426
  if (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()),read());
395
427
  else for (let i = 0; i < token; i++) map.set(read(), read());
@@ -471,11 +503,7 @@
471
503
  throw new Error('Unknown token ' + token)
472
504
  }
473
505
  default: // negative int
474
- if (isNaN(token)) {
475
- let error = new Error('Unexpected end of CBOR data');
476
- error.incomplete = true;
477
- throw error
478
- }
506
+ if (isNaN(token)) throw endOfCBORError()
479
507
  throw new Error('Unknown CBOR token ' + token)
480
508
  }
481
509
  }
@@ -921,18 +949,12 @@
921
949
  return (glbl[data[0]] || Error)(data[1], data[2])
922
950
  };
923
951
  const packedTable = (read) => {
924
- if (src[position$1++] != 0x84) {
925
- let error = new Error('Packed values structure must be followed by a 4 element array');
926
- if (src.length < position$1)
927
- error.incomplete = true;
928
- throw error
929
- }
952
+ if (!(position$1 < srcEnd)) throw endOfCBORError()
953
+ if (src[position$1++] != 0x84)
954
+ throw new Error('Packed values structure must be followed by a 4 element array')
930
955
  let newPackedValues = read(); // packed values
931
- if (!newPackedValues || !newPackedValues.length) {
932
- let error = new Error('Packed values structure must be followed by a 4 element array');
933
- error.incomplete = true;
934
- throw error
935
- }
956
+ if (!Array.isArray(newPackedValues) || !newPackedValues.length)
957
+ throw new Error('Packed values structure must be followed by a 4 element array')
936
958
  packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues;
937
959
  packedValues.prefixes = read();
938
960
  packedValues.suffixes = read();
@@ -950,10 +972,7 @@
950
972
  }
951
973
  if (typeof data == 'number')
952
974
  return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
953
- let error = new Error('No support for non-integer packed references yet');
954
- if (data === undefined)
955
- error.incomplete = true;
956
- throw error
975
+ throw new Error('No support for non-integer packed references yet')
957
976
  };
958
977
 
959
978
  // The following code is an incomplete implementation of http://cbor.schmorp.de/stringref
@@ -1023,9 +1042,19 @@
1023
1042
  (currentExtensions[259] = (read) => {
1024
1043
  // https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec
1025
1044
  // for decoding as a standard Map
1026
- if (currentDecoder.mapsAsObjects) {
1027
- currentDecoder.mapsAsObjects = false;
1045
+ let decoder = currentDecoder;
1046
+ if (decoder.mapsAsObjects) {
1047
+ decoder.mapsAsObjects = false;
1028
1048
  restoreMapsAsObject = true;
1049
+ try {
1050
+ return read()
1051
+ } finally {
1052
+ // normally restored by the map header, but not if the tagged value is not a map or the read fails
1053
+ if (restoreMapsAsObject) {
1054
+ decoder.mapsAsObjects = true;
1055
+ restoreMapsAsObject = false;
1056
+ }
1057
+ }
1029
1058
  }
1030
1059
  return read()
1031
1060
  }).handlesRead = true;
@@ -1136,17 +1165,21 @@
1136
1165
  }
1137
1166
 
1138
1167
  function readJustLength() {
1168
+ if (!(position$1 < srcEnd)) throw endOfCBORError()
1139
1169
  let token = src[position$1++] & 0x1f;
1140
1170
  if (token > 0x17) {
1141
1171
  switch (token) {
1142
1172
  case 0x18:
1173
+ if (position$1 >= srcEnd) throw endOfCBORError()
1143
1174
  token = src[position$1++];
1144
1175
  break
1145
1176
  case 0x19:
1177
+ if (position$1 + 2 > srcEnd) throw endOfCBORError()
1146
1178
  token = dataView.getUint16(position$1);
1147
1179
  position$1 += 2;
1148
1180
  break
1149
1181
  case 0x1a:
1182
+ if (position$1 + 4 > srcEnd) throw endOfCBORError()
1150
1183
  token = dataView.getUint32(position$1);
1151
1184
  position$1 += 4;
1152
1185
  break
@@ -1188,22 +1221,27 @@
1188
1221
  let savedStructures = currentStructures;
1189
1222
  let savedDecoder = currentDecoder;
1190
1223
  let savedSequentialMode = sequentialMode;
1191
- let value = callback();
1192
- srcEnd = savedSrcEnd;
1193
- position$1 = savedPosition;
1194
- stringPosition = savedStringPosition;
1195
- srcStringStart = savedSrcStringStart;
1196
- srcStringEnd = savedSrcStringEnd;
1197
- srcString = savedSrcString;
1198
- strings = savedStrings;
1199
- referenceMap = savedReferenceMap;
1200
- bundledStrings$1 = savedBundledStrings;
1201
- src = savedSrc;
1202
- sequentialMode = savedSequentialMode;
1203
- currentStructures = savedStructures;
1204
- currentDecoder = savedDecoder;
1205
- dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
1206
- return value
1224
+ let savedRestoreMapsAsObject = restoreMapsAsObject;
1225
+ restoreMapsAsObject = false;
1226
+ try {
1227
+ return callback()
1228
+ } finally {
1229
+ srcEnd = savedSrcEnd;
1230
+ position$1 = savedPosition;
1231
+ stringPosition = savedStringPosition;
1232
+ srcStringStart = savedSrcStringStart;
1233
+ srcStringEnd = savedSrcStringEnd;
1234
+ srcString = savedSrcString;
1235
+ strings = savedStrings;
1236
+ referenceMap = savedReferenceMap;
1237
+ bundledStrings$1 = savedBundledStrings;
1238
+ src = savedSrc;
1239
+ sequentialMode = savedSequentialMode;
1240
+ currentStructures = savedStructures;
1241
+ currentDecoder = savedDecoder;
1242
+ restoreMapsAsObject = savedRestoreMapsAsObject;
1243
+ dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
1244
+ }
1207
1245
  }
1208
1246
  function clearSource() {
1209
1247
  src = null;
@@ -1409,7 +1447,7 @@
1409
1447
  if (throwOnIterable)
1410
1448
  return;
1411
1449
  encode(value);
1412
- if (bundledStrings) {
1450
+ if (bundledStrings && bundledStrings.position) { // position is only set once a bundle has been started
1413
1451
  writeBundles(start, encode);
1414
1452
  }
1415
1453
  encoder.offset = position; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially