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.
@@ -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,20 +237,36 @@
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
235
251
  }
236
252
  }
237
253
 
254
+ function endOfCBORError() {
255
+ let error = new Error('Unexpected end of CBOR data');
256
+ error.incomplete = true;
257
+ return error
258
+ }
259
+
238
260
  function read() {
261
+ // compared as < so that a NaN position (from a corrupt length) also throws instead of reading undefined
262
+ if (!(position$1 < srcEnd)) throw endOfCBORError()
239
263
  let token = src[position$1++];
240
264
  let majorType = token >> 5;
241
265
  token = token & 0x1f;
242
266
  if (token > 0x17) {
243
267
  switch (token) {
244
268
  case 0x18:
269
+ if (position$1 >= srcEnd) throw endOfCBORError()
245
270
  token = src[position$1++];
246
271
  break
247
272
  case 0x19:
@@ -304,13 +329,13 @@
304
329
  let i = 0;
305
330
  if (currentDecoder.keyMap) {
306
331
  while((key = read()) != STOP_CODE) {
307
- if (i++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)
332
+ if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
308
333
  object[safeKey(currentDecoder.decodeKey(key))] = read();
309
334
  }
310
335
  }
311
336
  else {
312
337
  while ((key = read()) != STOP_CODE) {
313
- if (i++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)
338
+ if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
314
339
  object[safeKey(key)] = read();
315
340
  }
316
341
  }
@@ -356,11 +381,13 @@
356
381
  case 1: // negative int
357
382
  return ~token
358
383
  case 2: // buffer
384
+ if (token > srcEnd - position$1) throw endOfCBORError()
359
385
  return readBin(token)
360
386
  case 3: // string
361
- if (srcStringEnd >= position$1) {
387
+ if (srcStringEnd >= position$1) { // already extracted, which only covers complete strings
362
388
  return srcString.slice(position$1 - srcStringStart, (position$1 += token) - srcStringStart)
363
389
  }
390
+ if (token > srcEnd - position$1) throw endOfCBORError()
364
391
  if (srcStringEnd == 0 && srcEnd < 140 && token < 32) {
365
392
  // for small blocks, avoiding the overhead of the extract call is helpful
366
393
  let string = token < 16 ? shortStringInJS(token) : longStringInJS(token);
@@ -369,15 +396,19 @@
369
396
  }
370
397
  return readFixedString(token)
371
398
  case 4: // array
372
- if (token >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
399
+ if (token > maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
400
+ // every element occupies at least one byte, so a length beyond what remains in the source can
401
+ // never be satisfied; check before allocating so a tiny header can not force a huge allocation
402
+ if (token > srcEnd - position$1) throw endOfCBORError()
373
403
  let array = new Array(token);
374
404
  //if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())
375
405
  //else
376
406
  for (let i = 0; i < token; i++) array[i] = read();
377
407
  return array
378
408
  case 5: // map
379
- if (token >= maxMapSize) throw new Error(`Map size exceeds ${maxArraySize}`)
380
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
381
412
  let object = {};
382
413
  if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read();
383
414
  else for (let i = 0; i < token; i++) object[safeKey(read())] = read();
@@ -387,6 +418,8 @@
387
418
  currentDecoder.mapsAsObjects = true;
388
419
  restoreMapsAsObject = false;
389
420
  }
421
+ if (token > maxMapSize) throw new Error(`Map size exceeds ${maxMapSize}`)
422
+ if (token > (srcEnd - position$1) / 2) throw endOfCBORError()
390
423
  let map = new Map();
391
424
  if (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()),read());
392
425
  else for (let i = 0; i < token; i++) map.set(read(), read());
@@ -468,11 +501,7 @@
468
501
  throw new Error('Unknown token ' + token)
469
502
  }
470
503
  default: // negative int
471
- if (isNaN(token)) {
472
- let error = new Error('Unexpected end of CBOR data');
473
- error.incomplete = true;
474
- throw error
475
- }
504
+ if (isNaN(token)) throw endOfCBORError()
476
505
  throw new Error('Unknown CBOR token ' + token)
477
506
  }
478
507
  }
@@ -886,18 +915,12 @@
886
915
  return (glbl[data[0]] || Error)(data[1], data[2])
887
916
  };
888
917
  const packedTable = (read) => {
889
- if (src[position$1++] != 0x84) {
890
- let error = new Error('Packed values structure must be followed by a 4 element array');
891
- if (src.length < position$1)
892
- error.incomplete = true;
893
- throw error
894
- }
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')
895
921
  let newPackedValues = read(); // packed values
896
- if (!newPackedValues || !newPackedValues.length) {
897
- let error = new Error('Packed values structure must be followed by a 4 element array');
898
- error.incomplete = true;
899
- throw error
900
- }
922
+ if (!Array.isArray(newPackedValues) || !newPackedValues.length)
923
+ throw new Error('Packed values structure must be followed by a 4 element array')
901
924
  packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues;
902
925
  packedValues.prefixes = read();
903
926
  packedValues.suffixes = read();
@@ -915,10 +938,7 @@
915
938
  }
916
939
  if (typeof data == 'number')
917
940
  return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
918
- let error = new Error('No support for non-integer packed references yet');
919
- if (data === undefined)
920
- error.incomplete = true;
921
- throw error
941
+ throw new Error('No support for non-integer packed references yet')
922
942
  };
923
943
 
924
944
  // The following code is an incomplete implementation of http://cbor.schmorp.de/stringref
@@ -988,9 +1008,19 @@
988
1008
  (currentExtensions[259] = (read) => {
989
1009
  // https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec
990
1010
  // for decoding as a standard Map
991
- if (currentDecoder.mapsAsObjects) {
992
- currentDecoder.mapsAsObjects = false;
1011
+ let decoder = currentDecoder;
1012
+ if (decoder.mapsAsObjects) {
1013
+ decoder.mapsAsObjects = false;
993
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
+ }
994
1024
  }
995
1025
  return read()
996
1026
  }).handlesRead = true;
@@ -1101,17 +1131,21 @@
1101
1131
  }
1102
1132
 
1103
1133
  function readJustLength() {
1134
+ if (!(position$1 < srcEnd)) throw endOfCBORError()
1104
1135
  let token = src[position$1++] & 0x1f;
1105
1136
  if (token > 0x17) {
1106
1137
  switch (token) {
1107
1138
  case 0x18:
1139
+ if (position$1 >= srcEnd) throw endOfCBORError()
1108
1140
  token = src[position$1++];
1109
1141
  break
1110
1142
  case 0x19:
1143
+ if (position$1 + 2 > srcEnd) throw endOfCBORError()
1111
1144
  token = dataView.getUint16(position$1);
1112
1145
  position$1 += 2;
1113
1146
  break
1114
1147
  case 0x1a:
1148
+ if (position$1 + 4 > srcEnd) throw endOfCBORError()
1115
1149
  token = dataView.getUint32(position$1);
1116
1150
  position$1 += 4;
1117
1151
  break
@@ -1151,20 +1185,25 @@
1151
1185
  let savedStructures = currentStructures;
1152
1186
  let savedDecoder = currentDecoder;
1153
1187
  let savedSequentialMode = sequentialMode;
1154
- let value = callback();
1155
- srcEnd = savedSrcEnd;
1156
- position$1 = savedPosition;
1157
- srcStringStart = savedSrcStringStart;
1158
- srcStringEnd = savedSrcStringEnd;
1159
- srcString = savedSrcString;
1160
- referenceMap = savedReferenceMap;
1161
- bundledStrings$1 = savedBundledStrings;
1162
- src = savedSrc;
1163
- sequentialMode = savedSequentialMode;
1164
- currentStructures = savedStructures;
1165
- currentDecoder = savedDecoder;
1166
- dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
1167
- 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
+ }
1168
1207
  }
1169
1208
  function clearSource() {
1170
1209
  src = null;
@@ -1179,7 +1218,8 @@
1179
1218
  function setSizeLimits(limits) {
1180
1219
  if (limits.maxMapSize) maxMapSize = limits.maxMapSize;
1181
1220
  if (limits.maxArraySize) maxArraySize = limits.maxArraySize;
1182
- if (limits.maxObjectSize) limits.maxObjectSize;
1221
+ if (limits.maxObjectSize) maxObjectSize = limits.maxObjectSize;
1222
+ objectSizeLimit = Math.min(maxObjectSize, maxMapSize);
1183
1223
  }
1184
1224
 
1185
1225
  const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
@@ -1381,7 +1421,7 @@
1381
1421
  if (throwOnIterable)
1382
1422
  return;
1383
1423
  encode(value);
1384
- if (bundledStrings) {
1424
+ if (bundledStrings && bundledStrings.position) { // position is only set once a bundle has been started
1385
1425
  writeBundles(start, encode);
1386
1426
  }
1387
1427
  encoder.offset = position; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
@@ -2479,7 +2519,7 @@
2479
2519
  }
2480
2520
 
2481
2521
  const decoder = new Decoder(options);
2482
- let incomplete;
2522
+ let incomplete, fatalError;
2483
2523
  const parser = (chunk) => {
2484
2524
  let yields;
2485
2525
  // if there's incomplete data from previous chunk, concatinate and try again
@@ -2491,26 +2531,28 @@
2491
2531
  try {
2492
2532
  yields = decoder.decodeMultiple(chunk);
2493
2533
  } catch (err) {
2534
+ yields = err.values;
2494
2535
  if (err.incomplete) {
2495
2536
  incomplete = chunk.slice(err.lastPosition);
2496
- yields = err.values;
2497
2537
  } else {
2498
- throw err
2538
+ fatalError = err;
2499
2539
  }
2500
2540
  }
2501
- return yields
2541
+ return yields || []
2502
2542
  };
2503
2543
 
2504
2544
  if (typeof bufferIterator[Symbol.iterator] === 'function') {
2505
2545
  return (function * iter () {
2506
2546
  for (const value of bufferIterator) {
2507
2547
  yield * parser(value);
2548
+ if (fatalError) throw fatalError
2508
2549
  }
2509
2550
  })()
2510
2551
  } else if (typeof bufferIterator[Symbol.asyncIterator] === 'function') {
2511
2552
  return (async function * iter () {
2512
2553
  for await (const value of bufferIterator) {
2513
2554
  yield * parser(value);
2555
+ if (fatalError) throw fatalError
2514
2556
  }
2515
2557
  })()
2516
2558
  }