cbor-x 1.6.6 → 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.
@@ -20,6 +20,11 @@
20
20
  let maxArraySize = 112810000; // This is the maximum array size in V8. We would potentially detect and set it higher
21
21
  // for JSC, but this is pretty large and should be sufficient for most use cases
22
22
  let maxMapSize = 16810000; // JavaScript has a fixed maximum map size of about 16710000, but JS itself enforces this,
23
+ // so we don't need to
24
+
25
+ let maxObjectSize = 16710000; // It takes over a minute to create this many keys in an object, so this is probably a
26
+ // reasonable choice.
27
+ let objectSizeLimit = maxObjectSize; // objects are limited by both maxObjectSize and maxMapSize
23
28
  let currentDecoder = {};
24
29
  let currentStructures;
25
30
  let srcString;
@@ -121,7 +126,13 @@
121
126
  // re-entrant execution, save the state and restore it after we do this decode
122
127
  return saveState(() => {
123
128
  clearSource();
124
- 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
+ }
125
136
  })
126
137
  }
127
138
  srcEnd = end > -1 ? end : source.length;
@@ -196,15 +207,13 @@
196
207
  }
197
208
  }
198
209
  }
210
+ const nestedDecodeErrors = new WeakSet();
199
211
  function checkedRead() {
200
212
  try {
201
213
  let result = read();
202
214
  if (bundledStrings$1) {
203
- if (position$1 >= bundledStrings$1.postBundlePosition) {
204
- let error = new Error('Unexpected bundle position');
205
- error.incomplete = true;
206
- throw error
207
- }
215
+ if (position$1 >= bundledStrings$1.postBundlePosition)
216
+ throw new Error('Unexpected bundle position')
208
217
  // bundled strings to skip past
209
218
  position$1 = bundledStrings$1.postBundlePosition;
210
219
  bundledStrings$1 = null;
@@ -228,7 +237,14 @@
228
237
  return result
229
238
  } catch(error) {
230
239
  clearSource();
231
- if (error instanceof RangeError || error.message.startsWith('Unexpected end of buffer')) {
240
+ if (nestedDecodeErrors.has(error)) {
241
+ // from a nested decode of embedded data (by an extension), which was complete in this source
242
+ if (error.incomplete)
243
+ error.incomplete = false;
244
+ } else if (error instanceof RangeError && position$1 + 8 > srcEnd ||
245
+ error && typeof error.message == 'string' && error.message.startsWith('Unexpected end of buffer')) {
246
+ // a DataView read past the end of the source; these read at most 8 bytes and precede advancing position.
247
+ // Any other RangeError (such as a stack overflow from deeply nested input) is fatal.
232
248
  error.incomplete = true;
233
249
  }
234
250
  throw error
@@ -313,13 +329,13 @@
313
329
  let i = 0;
314
330
  if (currentDecoder.keyMap) {
315
331
  while((key = read()) != STOP_CODE) {
316
- if (i++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)
332
+ if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
317
333
  object[safeKey(currentDecoder.decodeKey(key))] = read();
318
334
  }
319
335
  }
320
336
  else {
321
337
  while ((key = read()) != STOP_CODE) {
322
- if (i++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)
338
+ if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
323
339
  object[safeKey(key)] = read();
324
340
  }
325
341
  }
@@ -365,11 +381,13 @@
365
381
  case 1: // negative int
366
382
  return ~token
367
383
  case 2: // buffer
384
+ if (token > srcEnd - position$1) throw endOfCBORError()
368
385
  return readBin(token)
369
386
  case 3: // string
370
- if (srcStringEnd >= position$1) {
387
+ if (srcStringEnd >= position$1) { // already extracted, which only covers complete strings
371
388
  return srcString.slice(position$1 - srcStringStart, (position$1 += token) - srcStringStart)
372
389
  }
390
+ if (token > srcEnd - position$1) throw endOfCBORError()
373
391
  if (srcStringEnd == 0 && srcEnd < 140 && token < 32) {
374
392
  // for small blocks, avoiding the overhead of the extract call is helpful
375
393
  let string = token < 16 ? shortStringInJS(token) : longStringInJS(token);
@@ -378,7 +396,7 @@
378
396
  }
379
397
  return readFixedString(token)
380
398
  case 4: // array
381
- if (token >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
399
+ if (token > maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
382
400
  // every element occupies at least one byte, so a length beyond what remains in the source can
383
401
  // never be satisfied; check before allocating so a tiny header can not force a huge allocation
384
402
  if (token > srcEnd - position$1) throw endOfCBORError()
@@ -388,9 +406,9 @@
388
406
  for (let i = 0; i < token; i++) array[i] = read();
389
407
  return array
390
408
  case 5: // map
391
- if (token >= maxMapSize) throw new Error(`Map size exceeds ${maxArraySize}`)
392
- if (token > (srcEnd - position$1) / 2) throw endOfCBORError() // each entry needs at least two bytes
393
409
  if (currentDecoder.mapsAsObjects) {
410
+ if (token > objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
411
+ if (token > (srcEnd - position$1) / 2) throw endOfCBORError() // each entry needs at least two bytes
394
412
  let object = {};
395
413
  if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read();
396
414
  else for (let i = 0; i < token; i++) object[safeKey(read())] = read();
@@ -400,6 +418,8 @@
400
418
  currentDecoder.mapsAsObjects = true;
401
419
  restoreMapsAsObject = false;
402
420
  }
421
+ if (token > maxMapSize) throw new Error(`Map size exceeds ${maxMapSize}`)
422
+ if (token > (srcEnd - position$1) / 2) throw endOfCBORError()
403
423
  let map = new Map();
404
424
  if (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()),read());
405
425
  else for (let i = 0; i < token; i++) map.set(read(), read());
@@ -895,18 +915,12 @@
895
915
  return (glbl[data[0]] || Error)(data[1], data[2])
896
916
  };
897
917
  const packedTable = (read) => {
898
- if (src[position$1++] != 0x84) {
899
- let error = new Error('Packed values structure must be followed by a 4 element array');
900
- if (src.length < position$1)
901
- error.incomplete = true;
902
- throw error
903
- }
918
+ if (!(position$1 < srcEnd)) throw endOfCBORError()
919
+ if (src[position$1++] != 0x84)
920
+ throw new Error('Packed values structure must be followed by a 4 element array')
904
921
  let newPackedValues = read(); // packed values
905
- if (!newPackedValues || !newPackedValues.length) {
906
- let error = new Error('Packed values structure must be followed by a 4 element array');
907
- error.incomplete = true;
908
- throw error
909
- }
922
+ if (!Array.isArray(newPackedValues) || !newPackedValues.length)
923
+ throw new Error('Packed values structure must be followed by a 4 element array')
910
924
  packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues;
911
925
  packedValues.prefixes = read();
912
926
  packedValues.suffixes = read();
@@ -924,10 +938,7 @@
924
938
  }
925
939
  if (typeof data == 'number')
926
940
  return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
927
- let error = new Error('No support for non-integer packed references yet');
928
- if (data === undefined)
929
- error.incomplete = true;
930
- throw error
941
+ throw new Error('No support for non-integer packed references yet')
931
942
  };
932
943
 
933
944
  // The following code is an incomplete implementation of http://cbor.schmorp.de/stringref
@@ -997,9 +1008,19 @@
997
1008
  (currentExtensions[259] = (read) => {
998
1009
  // https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec
999
1010
  // for decoding as a standard Map
1000
- if (currentDecoder.mapsAsObjects) {
1001
- currentDecoder.mapsAsObjects = false;
1011
+ let decoder = currentDecoder;
1012
+ if (decoder.mapsAsObjects) {
1013
+ decoder.mapsAsObjects = false;
1002
1014
  restoreMapsAsObject = true;
1015
+ try {
1016
+ return read()
1017
+ } finally {
1018
+ // normally restored by the map header, but not if the tagged value is not a map or the read fails
1019
+ if (restoreMapsAsObject) {
1020
+ decoder.mapsAsObjects = true;
1021
+ restoreMapsAsObject = false;
1022
+ }
1023
+ }
1003
1024
  }
1004
1025
  return read()
1005
1026
  }).handlesRead = true;
@@ -1119,10 +1140,12 @@
1119
1140
  token = src[position$1++];
1120
1141
  break
1121
1142
  case 0x19:
1143
+ if (position$1 + 2 > srcEnd) throw endOfCBORError()
1122
1144
  token = dataView.getUint16(position$1);
1123
1145
  position$1 += 2;
1124
1146
  break
1125
1147
  case 0x1a:
1148
+ if (position$1 + 4 > srcEnd) throw endOfCBORError()
1126
1149
  token = dataView.getUint32(position$1);
1127
1150
  position$1 += 4;
1128
1151
  break
@@ -1162,20 +1185,25 @@
1162
1185
  let savedStructures = currentStructures;
1163
1186
  let savedDecoder = currentDecoder;
1164
1187
  let savedSequentialMode = sequentialMode;
1165
- let value = callback();
1166
- srcEnd = savedSrcEnd;
1167
- position$1 = savedPosition;
1168
- srcStringStart = savedSrcStringStart;
1169
- srcStringEnd = savedSrcStringEnd;
1170
- srcString = savedSrcString;
1171
- referenceMap = savedReferenceMap;
1172
- bundledStrings$1 = savedBundledStrings;
1173
- src = savedSrc;
1174
- sequentialMode = savedSequentialMode;
1175
- currentStructures = savedStructures;
1176
- currentDecoder = savedDecoder;
1177
- dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
1178
- return value
1188
+ let savedRestoreMapsAsObject = restoreMapsAsObject;
1189
+ restoreMapsAsObject = false;
1190
+ try {
1191
+ return callback()
1192
+ } finally {
1193
+ srcEnd = savedSrcEnd;
1194
+ position$1 = savedPosition;
1195
+ srcStringStart = savedSrcStringStart;
1196
+ srcStringEnd = savedSrcStringEnd;
1197
+ srcString = savedSrcString;
1198
+ referenceMap = savedReferenceMap;
1199
+ bundledStrings$1 = savedBundledStrings;
1200
+ src = savedSrc;
1201
+ sequentialMode = savedSequentialMode;
1202
+ currentStructures = savedStructures;
1203
+ currentDecoder = savedDecoder;
1204
+ restoreMapsAsObject = savedRestoreMapsAsObject;
1205
+ dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
1206
+ }
1179
1207
  }
1180
1208
  function clearSource() {
1181
1209
  src = null;
@@ -1190,7 +1218,8 @@
1190
1218
  function setSizeLimits(limits) {
1191
1219
  if (limits.maxMapSize) maxMapSize = limits.maxMapSize;
1192
1220
  if (limits.maxArraySize) maxArraySize = limits.maxArraySize;
1193
- if (limits.maxObjectSize) limits.maxObjectSize;
1221
+ if (limits.maxObjectSize) maxObjectSize = limits.maxObjectSize;
1222
+ objectSizeLimit = Math.min(maxObjectSize, maxMapSize);
1194
1223
  }
1195
1224
 
1196
1225
  const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
@@ -1392,7 +1421,7 @@
1392
1421
  if (throwOnIterable)
1393
1422
  return;
1394
1423
  encode(value);
1395
- if (bundledStrings) {
1424
+ if (bundledStrings && bundledStrings.position) { // position is only set once a bundle has been started
1396
1425
  writeBundles(start, encode);
1397
1426
  }
1398
1427
  encoder.offset = position; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
@@ -2490,7 +2519,7 @@
2490
2519
  }
2491
2520
 
2492
2521
  const decoder = new Decoder(options);
2493
- let incomplete;
2522
+ let incomplete, fatalError;
2494
2523
  const parser = (chunk) => {
2495
2524
  let yields;
2496
2525
  // if there's incomplete data from previous chunk, concatinate and try again
@@ -2502,26 +2531,28 @@
2502
2531
  try {
2503
2532
  yields = decoder.decodeMultiple(chunk);
2504
2533
  } catch (err) {
2534
+ yields = err.values;
2505
2535
  if (err.incomplete) {
2506
2536
  incomplete = chunk.slice(err.lastPosition);
2507
- yields = err.values;
2508
2537
  } else {
2509
- throw err
2538
+ fatalError = err;
2510
2539
  }
2511
2540
  }
2512
- return yields
2541
+ return yields || []
2513
2542
  };
2514
2543
 
2515
2544
  if (typeof bufferIterator[Symbol.iterator] === 'function') {
2516
2545
  return (function * iter () {
2517
2546
  for (const value of bufferIterator) {
2518
2547
  yield * parser(value);
2548
+ if (fatalError) throw fatalError
2519
2549
  }
2520
2550
  })()
2521
2551
  } else if (typeof bufferIterator[Symbol.asyncIterator] === 'function') {
2522
2552
  return (async function * iter () {
2523
2553
  for await (const value of bufferIterator) {
2524
2554
  yield * parser(value);
2555
+ if (fatalError) throw fatalError
2525
2556
  }
2526
2557
  })()
2527
2558
  }