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/README.md +9 -3
- package/decode.d.ts +1 -1
- package/decode.js +89 -52
- package/dist/decode-no-eval.cjs +91 -52
- package/dist/decode-no-eval.cjs.map +1 -1
- package/dist/index-no-eval.cjs +96 -54
- package/dist/index-no-eval.cjs.map +1 -1
- package/dist/index-no-eval.min.js +1 -1
- package/dist/index-no-eval.min.js.map +1 -1
- package/dist/index.js +96 -54
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/node.cjs +109 -70
- package/dist/node.cjs.map +1 -1
- package/dist/test.js +90 -52
- package/dist/test.js.map +1 -1
- package/encode.js +1 -1
- package/index.d.ts +1 -1
- package/iterators.js +6 -4
- package/package.json +1 -1
- package/stream.js +11 -13
package/dist/node.cjs
CHANGED
|
@@ -21,7 +21,11 @@ const STOP_CODE = {};
|
|
|
21
21
|
let maxArraySize = 112810000; // This is the maximum array size in V8. We would potentially detect and set it higher
|
|
22
22
|
// for JSC, but this is pretty large and should be sufficient for most use cases
|
|
23
23
|
let maxMapSize = 16810000; // JavaScript has a fixed maximum map size of about 16710000, but JS itself enforces this,
|
|
24
|
-
//
|
|
24
|
+
// so we don't need to
|
|
25
|
+
|
|
26
|
+
let maxObjectSize = 16710000; // It takes over a minute to create this many keys in an object, so this is probably a
|
|
27
|
+
// reasonable choice.
|
|
28
|
+
let objectSizeLimit = maxObjectSize; // objects are limited by both maxObjectSize and maxMapSize
|
|
25
29
|
let strings = EMPTY_ARRAY;
|
|
26
30
|
let stringPosition = 0;
|
|
27
31
|
let currentDecoder = {};
|
|
@@ -124,7 +128,13 @@ class Decoder {
|
|
|
124
128
|
// re-entrant execution, save the state and restore it after we do this decode
|
|
125
129
|
return saveState(() => {
|
|
126
130
|
clearSource();
|
|
127
|
-
|
|
131
|
+
try {
|
|
132
|
+
return this ? this.decode(source, end) : Decoder.prototype.decode.call(defaultOptions, source, end)
|
|
133
|
+
} catch (error) {
|
|
134
|
+
if (error && typeof error == 'object')
|
|
135
|
+
nestedDecodeErrors.add(error);
|
|
136
|
+
throw error
|
|
137
|
+
}
|
|
128
138
|
})
|
|
129
139
|
}
|
|
130
140
|
srcEnd = end > -1 ? end : source.length;
|
|
@@ -201,15 +211,13 @@ class Decoder {
|
|
|
201
211
|
}
|
|
202
212
|
}
|
|
203
213
|
}
|
|
214
|
+
const nestedDecodeErrors = new WeakSet();
|
|
204
215
|
function checkedRead() {
|
|
205
216
|
try {
|
|
206
217
|
let result = read();
|
|
207
218
|
if (bundledStrings$1) {
|
|
208
|
-
if (position$1 >= bundledStrings$1.postBundlePosition)
|
|
209
|
-
|
|
210
|
-
error.incomplete = true;
|
|
211
|
-
throw error
|
|
212
|
-
}
|
|
219
|
+
if (position$1 >= bundledStrings$1.postBundlePosition)
|
|
220
|
+
throw new Error('Unexpected bundle position')
|
|
213
221
|
// bundled strings to skip past
|
|
214
222
|
position$1 = bundledStrings$1.postBundlePosition;
|
|
215
223
|
bundledStrings$1 = null;
|
|
@@ -233,20 +241,36 @@ function checkedRead() {
|
|
|
233
241
|
return result
|
|
234
242
|
} catch(error) {
|
|
235
243
|
clearSource();
|
|
236
|
-
if (
|
|
244
|
+
if (nestedDecodeErrors.has(error)) {
|
|
245
|
+
// from a nested decode of embedded data (by an extension), which was complete in this source
|
|
246
|
+
if (error.incomplete)
|
|
247
|
+
error.incomplete = false;
|
|
248
|
+
} else if (error instanceof RangeError && position$1 + 8 > srcEnd ||
|
|
249
|
+
error && typeof error.message == 'string' && error.message.startsWith('Unexpected end of buffer')) {
|
|
250
|
+
// a DataView read past the end of the source; these read at most 8 bytes and precede advancing position.
|
|
251
|
+
// Any other RangeError (such as a stack overflow from deeply nested input) is fatal.
|
|
237
252
|
error.incomplete = true;
|
|
238
253
|
}
|
|
239
254
|
throw error
|
|
240
255
|
}
|
|
241
256
|
}
|
|
242
257
|
|
|
258
|
+
function endOfCBORError() {
|
|
259
|
+
let error = new Error('Unexpected end of CBOR data');
|
|
260
|
+
error.incomplete = true;
|
|
261
|
+
return error
|
|
262
|
+
}
|
|
263
|
+
|
|
243
264
|
function read() {
|
|
265
|
+
// compared as < so that a NaN position (from a corrupt length) also throws instead of reading undefined
|
|
266
|
+
if (!(position$1 < srcEnd)) throw endOfCBORError()
|
|
244
267
|
let token = src[position$1++];
|
|
245
268
|
let majorType = token >> 5;
|
|
246
269
|
token = token & 0x1f;
|
|
247
270
|
if (token > 0x17) {
|
|
248
271
|
switch (token) {
|
|
249
272
|
case 0x18:
|
|
273
|
+
if (position$1 >= srcEnd) throw endOfCBORError()
|
|
250
274
|
token = src[position$1++];
|
|
251
275
|
break
|
|
252
276
|
case 0x19:
|
|
@@ -309,13 +333,13 @@ function read() {
|
|
|
309
333
|
let i = 0;
|
|
310
334
|
if (currentDecoder.keyMap) {
|
|
311
335
|
while((key = read()) != STOP_CODE) {
|
|
312
|
-
if (i++ >=
|
|
336
|
+
if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
313
337
|
object[safeKey(currentDecoder.decodeKey(key))] = read();
|
|
314
338
|
}
|
|
315
339
|
}
|
|
316
340
|
else {
|
|
317
341
|
while ((key = read()) != STOP_CODE) {
|
|
318
|
-
if (i++ >=
|
|
342
|
+
if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
319
343
|
object[safeKey(key)] = read();
|
|
320
344
|
}
|
|
321
345
|
}
|
|
@@ -361,11 +385,13 @@ function read() {
|
|
|
361
385
|
case 1: // negative int
|
|
362
386
|
return ~token
|
|
363
387
|
case 2: // buffer
|
|
388
|
+
if (token > srcEnd - position$1) throw endOfCBORError()
|
|
364
389
|
return readBin(token)
|
|
365
390
|
case 3: // string
|
|
366
|
-
if (srcStringEnd >= position$1) {
|
|
391
|
+
if (srcStringEnd >= position$1) { // already extracted, which only covers complete strings
|
|
367
392
|
return srcString.slice(position$1 - srcStringStart, (position$1 += token) - srcStringStart)
|
|
368
393
|
}
|
|
394
|
+
if (token > srcEnd - position$1) throw endOfCBORError()
|
|
369
395
|
if (srcStringEnd == 0 && srcEnd < 140 && token < 32) {
|
|
370
396
|
// for small blocks, avoiding the overhead of the extract call is helpful
|
|
371
397
|
let string = token < 16 ? shortStringInJS(token) : longStringInJS(token);
|
|
@@ -374,15 +400,19 @@ function read() {
|
|
|
374
400
|
}
|
|
375
401
|
return readFixedString(token)
|
|
376
402
|
case 4: // array
|
|
377
|
-
if (token
|
|
403
|
+
if (token > maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
|
|
404
|
+
// every element occupies at least one byte, so a length beyond what remains in the source can
|
|
405
|
+
// never be satisfied; check before allocating so a tiny header can not force a huge allocation
|
|
406
|
+
if (token > srcEnd - position$1) throw endOfCBORError()
|
|
378
407
|
let array = new Array(token);
|
|
379
408
|
//if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())
|
|
380
409
|
//else
|
|
381
410
|
for (let i = 0; i < token; i++) array[i] = read();
|
|
382
411
|
return array
|
|
383
412
|
case 5: // map
|
|
384
|
-
if (token >= maxMapSize) throw new Error(`Map size exceeds ${maxArraySize}`)
|
|
385
413
|
if (currentDecoder.mapsAsObjects) {
|
|
414
|
+
if (token > objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
415
|
+
if (token > (srcEnd - position$1) / 2) throw endOfCBORError() // each entry needs at least two bytes
|
|
386
416
|
let object = {};
|
|
387
417
|
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read();
|
|
388
418
|
else for (let i = 0; i < token; i++) object[safeKey(read())] = read();
|
|
@@ -392,6 +422,8 @@ function read() {
|
|
|
392
422
|
currentDecoder.mapsAsObjects = true;
|
|
393
423
|
restoreMapsAsObject = false;
|
|
394
424
|
}
|
|
425
|
+
if (token > maxMapSize) throw new Error(`Map size exceeds ${maxMapSize}`)
|
|
426
|
+
if (token > (srcEnd - position$1) / 2) throw endOfCBORError()
|
|
395
427
|
let map = new Map();
|
|
396
428
|
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()),read());
|
|
397
429
|
else for (let i = 0; i < token; i++) map.set(read(), read());
|
|
@@ -473,11 +505,7 @@ function read() {
|
|
|
473
505
|
throw new Error('Unknown token ' + token)
|
|
474
506
|
}
|
|
475
507
|
default: // negative int
|
|
476
|
-
if (isNaN(token))
|
|
477
|
-
let error = new Error('Unexpected end of CBOR data');
|
|
478
|
-
error.incomplete = true;
|
|
479
|
-
throw error
|
|
480
|
-
}
|
|
508
|
+
if (isNaN(token)) throw endOfCBORError()
|
|
481
509
|
throw new Error('Unknown CBOR token ' + token)
|
|
482
510
|
}
|
|
483
511
|
}
|
|
@@ -926,18 +954,12 @@ currentExtensions[27] = (data) => { // http://cbor.schmorp.de/generic-object
|
|
|
926
954
|
return (glbl[data[0]] || Error)(data[1], data[2])
|
|
927
955
|
};
|
|
928
956
|
const packedTable = (read) => {
|
|
929
|
-
if (
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
error.incomplete = true;
|
|
933
|
-
throw error
|
|
934
|
-
}
|
|
957
|
+
if (!(position$1 < srcEnd)) throw endOfCBORError()
|
|
958
|
+
if (src[position$1++] != 0x84)
|
|
959
|
+
throw new Error('Packed values structure must be followed by a 4 element array')
|
|
935
960
|
let newPackedValues = read(); // packed values
|
|
936
|
-
if (!newPackedValues || !newPackedValues.length)
|
|
937
|
-
|
|
938
|
-
error.incomplete = true;
|
|
939
|
-
throw error
|
|
940
|
-
}
|
|
961
|
+
if (!Array.isArray(newPackedValues) || !newPackedValues.length)
|
|
962
|
+
throw new Error('Packed values structure must be followed by a 4 element array')
|
|
941
963
|
packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues;
|
|
942
964
|
packedValues.prefixes = read();
|
|
943
965
|
packedValues.suffixes = read();
|
|
@@ -955,10 +977,7 @@ currentExtensions[PACKED_REFERENCE_TAG_ID] = (data) => { // packed reference
|
|
|
955
977
|
}
|
|
956
978
|
if (typeof data == 'number')
|
|
957
979
|
return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
|
|
958
|
-
|
|
959
|
-
if (data === undefined)
|
|
960
|
-
error.incomplete = true;
|
|
961
|
-
throw error
|
|
980
|
+
throw new Error('No support for non-integer packed references yet')
|
|
962
981
|
};
|
|
963
982
|
|
|
964
983
|
// The following code is an incomplete implementation of http://cbor.schmorp.de/stringref
|
|
@@ -1028,9 +1047,19 @@ currentExtensions[258] = (array) => new Set(array); // https://github.com/input-
|
|
|
1028
1047
|
(currentExtensions[259] = (read) => {
|
|
1029
1048
|
// https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec
|
|
1030
1049
|
// for decoding as a standard Map
|
|
1031
|
-
|
|
1032
|
-
|
|
1050
|
+
let decoder = currentDecoder;
|
|
1051
|
+
if (decoder.mapsAsObjects) {
|
|
1052
|
+
decoder.mapsAsObjects = false;
|
|
1033
1053
|
restoreMapsAsObject = true;
|
|
1054
|
+
try {
|
|
1055
|
+
return read()
|
|
1056
|
+
} finally {
|
|
1057
|
+
// normally restored by the map header, but not if the tagged value is not a map or the read fails
|
|
1058
|
+
if (restoreMapsAsObject) {
|
|
1059
|
+
decoder.mapsAsObjects = true;
|
|
1060
|
+
restoreMapsAsObject = false;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1034
1063
|
}
|
|
1035
1064
|
return read()
|
|
1036
1065
|
}).handlesRead = true;
|
|
@@ -1141,17 +1170,21 @@ function readBundleExt() {
|
|
|
1141
1170
|
}
|
|
1142
1171
|
|
|
1143
1172
|
function readJustLength() {
|
|
1173
|
+
if (!(position$1 < srcEnd)) throw endOfCBORError()
|
|
1144
1174
|
let token = src[position$1++] & 0x1f;
|
|
1145
1175
|
if (token > 0x17) {
|
|
1146
1176
|
switch (token) {
|
|
1147
1177
|
case 0x18:
|
|
1178
|
+
if (position$1 >= srcEnd) throw endOfCBORError()
|
|
1148
1179
|
token = src[position$1++];
|
|
1149
1180
|
break
|
|
1150
1181
|
case 0x19:
|
|
1182
|
+
if (position$1 + 2 > srcEnd) throw endOfCBORError()
|
|
1151
1183
|
token = dataView.getUint16(position$1);
|
|
1152
1184
|
position$1 += 2;
|
|
1153
1185
|
break
|
|
1154
1186
|
case 0x1a:
|
|
1187
|
+
if (position$1 + 4 > srcEnd) throw endOfCBORError()
|
|
1155
1188
|
token = dataView.getUint32(position$1);
|
|
1156
1189
|
position$1 += 4;
|
|
1157
1190
|
break
|
|
@@ -1193,22 +1226,27 @@ function saveState(callback) {
|
|
|
1193
1226
|
let savedStructures = currentStructures;
|
|
1194
1227
|
let savedDecoder = currentDecoder;
|
|
1195
1228
|
let savedSequentialMode = sequentialMode;
|
|
1196
|
-
let
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1229
|
+
let savedRestoreMapsAsObject = restoreMapsAsObject;
|
|
1230
|
+
restoreMapsAsObject = false;
|
|
1231
|
+
try {
|
|
1232
|
+
return callback()
|
|
1233
|
+
} finally {
|
|
1234
|
+
srcEnd = savedSrcEnd;
|
|
1235
|
+
position$1 = savedPosition;
|
|
1236
|
+
stringPosition = savedStringPosition;
|
|
1237
|
+
srcStringStart = savedSrcStringStart;
|
|
1238
|
+
srcStringEnd = savedSrcStringEnd;
|
|
1239
|
+
srcString = savedSrcString;
|
|
1240
|
+
strings = savedStrings;
|
|
1241
|
+
referenceMap = savedReferenceMap;
|
|
1242
|
+
bundledStrings$1 = savedBundledStrings;
|
|
1243
|
+
src = savedSrc;
|
|
1244
|
+
sequentialMode = savedSequentialMode;
|
|
1245
|
+
currentStructures = savedStructures;
|
|
1246
|
+
currentDecoder = savedDecoder;
|
|
1247
|
+
restoreMapsAsObject = savedRestoreMapsAsObject;
|
|
1248
|
+
dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
|
|
1249
|
+
}
|
|
1212
1250
|
}
|
|
1213
1251
|
function clearSource() {
|
|
1214
1252
|
src = null;
|
|
@@ -1223,7 +1261,8 @@ function addExtension$1(extension) {
|
|
|
1223
1261
|
function setSizeLimits(limits) {
|
|
1224
1262
|
if (limits.maxMapSize) maxMapSize = limits.maxMapSize;
|
|
1225
1263
|
if (limits.maxArraySize) maxArraySize = limits.maxArraySize;
|
|
1226
|
-
if (limits.maxObjectSize) limits.maxObjectSize;
|
|
1264
|
+
if (limits.maxObjectSize) maxObjectSize = limits.maxObjectSize;
|
|
1265
|
+
objectSizeLimit = Math.min(maxObjectSize, maxMapSize);
|
|
1227
1266
|
}
|
|
1228
1267
|
|
|
1229
1268
|
const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
|
|
@@ -1425,7 +1464,7 @@ class Encoder extends Decoder {
|
|
|
1425
1464
|
if (throwOnIterable)
|
|
1426
1465
|
return;
|
|
1427
1466
|
encode(value);
|
|
1428
|
-
if (bundledStrings) {
|
|
1467
|
+
if (bundledStrings && bundledStrings.position) { // position is only set once a bundle has been started
|
|
1429
1468
|
writeBundles(start, encode);
|
|
1430
1469
|
}
|
|
1431
1470
|
encoder.offset = position; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
|
|
@@ -2510,24 +2549,22 @@ class DecoderStream extends stream.Transform {
|
|
|
2510
2549
|
chunk = Buffer.concat([this.incompleteBuffer, chunk]);
|
|
2511
2550
|
this.incompleteBuffer = null;
|
|
2512
2551
|
}
|
|
2513
|
-
let values;
|
|
2552
|
+
let values, fatalError;
|
|
2514
2553
|
try {
|
|
2515
2554
|
values = this.decoder.decodeMultiple(chunk);
|
|
2516
2555
|
} catch(error) {
|
|
2517
|
-
|
|
2556
|
+
values = error.values;
|
|
2557
|
+
if (error.incomplete)
|
|
2518
2558
|
this.incompleteBuffer = chunk.slice(error.lastPosition);
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
value = this.getNullValue();
|
|
2527
|
-
this.push(value);
|
|
2528
|
-
}
|
|
2559
|
+
else
|
|
2560
|
+
fatalError = error;
|
|
2561
|
+
}
|
|
2562
|
+
for (let value of values || []) {
|
|
2563
|
+
if (value === null)
|
|
2564
|
+
value = this.getNullValue();
|
|
2565
|
+
this.push(value);
|
|
2529
2566
|
}
|
|
2530
|
-
callback();
|
|
2567
|
+
callback(fatalError);
|
|
2531
2568
|
}
|
|
2532
2569
|
getNullValue() {
|
|
2533
2570
|
return Symbol.for(null)
|
|
@@ -2580,7 +2617,7 @@ function decodeIter (bufferIterator, options = {}) {
|
|
|
2580
2617
|
}
|
|
2581
2618
|
|
|
2582
2619
|
const decoder = new Decoder(options);
|
|
2583
|
-
let incomplete;
|
|
2620
|
+
let incomplete, fatalError;
|
|
2584
2621
|
const parser = (chunk) => {
|
|
2585
2622
|
let yields;
|
|
2586
2623
|
// if there's incomplete data from previous chunk, concatinate and try again
|
|
@@ -2592,26 +2629,28 @@ function decodeIter (bufferIterator, options = {}) {
|
|
|
2592
2629
|
try {
|
|
2593
2630
|
yields = decoder.decodeMultiple(chunk);
|
|
2594
2631
|
} catch (err) {
|
|
2632
|
+
yields = err.values;
|
|
2595
2633
|
if (err.incomplete) {
|
|
2596
2634
|
incomplete = chunk.slice(err.lastPosition);
|
|
2597
|
-
yields = err.values;
|
|
2598
2635
|
} else {
|
|
2599
|
-
|
|
2636
|
+
fatalError = err;
|
|
2600
2637
|
}
|
|
2601
2638
|
}
|
|
2602
|
-
return yields
|
|
2639
|
+
return yields || []
|
|
2603
2640
|
};
|
|
2604
2641
|
|
|
2605
2642
|
if (typeof bufferIterator[Symbol.iterator] === 'function') {
|
|
2606
2643
|
return (function * iter () {
|
|
2607
2644
|
for (const value of bufferIterator) {
|
|
2608
2645
|
yield * parser(value);
|
|
2646
|
+
if (fatalError) throw fatalError
|
|
2609
2647
|
}
|
|
2610
2648
|
})()
|
|
2611
2649
|
} else if (typeof bufferIterator[Symbol.asyncIterator] === 'function') {
|
|
2612
2650
|
return (async function * iter () {
|
|
2613
2651
|
for await (const value of bufferIterator) {
|
|
2614
2652
|
yield * parser(value);
|
|
2653
|
+
if (fatalError) throw fatalError
|
|
2615
2654
|
}
|
|
2616
2655
|
})()
|
|
2617
2656
|
}
|