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/index.js
CHANGED
|
@@ -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;
|
|
@@ -120,7 +125,13 @@
|
|
|
120
125
|
// re-entrant execution, save the state and restore it after we do this decode
|
|
121
126
|
return saveState(() => {
|
|
122
127
|
clearSource();
|
|
123
|
-
|
|
128
|
+
try {
|
|
129
|
+
return this ? this.decode(source, end) : Decoder.prototype.decode.call(defaultOptions, source, end)
|
|
130
|
+
} catch (error) {
|
|
131
|
+
if (error && typeof error == 'object')
|
|
132
|
+
nestedDecodeErrors.add(error);
|
|
133
|
+
throw error
|
|
134
|
+
}
|
|
124
135
|
})
|
|
125
136
|
}
|
|
126
137
|
srcEnd = end > -1 ? end : source.length;
|
|
@@ -195,15 +206,13 @@
|
|
|
195
206
|
}
|
|
196
207
|
}
|
|
197
208
|
}
|
|
209
|
+
const nestedDecodeErrors = new WeakSet();
|
|
198
210
|
function checkedRead() {
|
|
199
211
|
try {
|
|
200
212
|
let result = read();
|
|
201
213
|
if (bundledStrings$1) {
|
|
202
|
-
if (position$1 >= bundledStrings$1.postBundlePosition)
|
|
203
|
-
|
|
204
|
-
error.incomplete = true;
|
|
205
|
-
throw error
|
|
206
|
-
}
|
|
214
|
+
if (position$1 >= bundledStrings$1.postBundlePosition)
|
|
215
|
+
throw new Error('Unexpected bundle position')
|
|
207
216
|
// bundled strings to skip past
|
|
208
217
|
position$1 = bundledStrings$1.postBundlePosition;
|
|
209
218
|
bundledStrings$1 = null;
|
|
@@ -227,20 +236,36 @@
|
|
|
227
236
|
return result
|
|
228
237
|
} catch(error) {
|
|
229
238
|
clearSource();
|
|
230
|
-
if (
|
|
239
|
+
if (nestedDecodeErrors.has(error)) {
|
|
240
|
+
// from a nested decode of embedded data (by an extension), which was complete in this source
|
|
241
|
+
if (error.incomplete)
|
|
242
|
+
error.incomplete = false;
|
|
243
|
+
} else if (error instanceof RangeError && position$1 + 8 > srcEnd ||
|
|
244
|
+
error && typeof error.message == 'string' && error.message.startsWith('Unexpected end of buffer')) {
|
|
245
|
+
// a DataView read past the end of the source; these read at most 8 bytes and precede advancing position.
|
|
246
|
+
// Any other RangeError (such as a stack overflow from deeply nested input) is fatal.
|
|
231
247
|
error.incomplete = true;
|
|
232
248
|
}
|
|
233
249
|
throw error
|
|
234
250
|
}
|
|
235
251
|
}
|
|
236
252
|
|
|
253
|
+
function endOfCBORError() {
|
|
254
|
+
let error = new Error('Unexpected end of CBOR data');
|
|
255
|
+
error.incomplete = true;
|
|
256
|
+
return error
|
|
257
|
+
}
|
|
258
|
+
|
|
237
259
|
function read() {
|
|
260
|
+
// compared as < so that a NaN position (from a corrupt length) also throws instead of reading undefined
|
|
261
|
+
if (!(position$1 < srcEnd)) throw endOfCBORError()
|
|
238
262
|
let token = src[position$1++];
|
|
239
263
|
let majorType = token >> 5;
|
|
240
264
|
token = token & 0x1f;
|
|
241
265
|
if (token > 0x17) {
|
|
242
266
|
switch (token) {
|
|
243
267
|
case 0x18:
|
|
268
|
+
if (position$1 >= srcEnd) throw endOfCBORError()
|
|
244
269
|
token = src[position$1++];
|
|
245
270
|
break
|
|
246
271
|
case 0x19:
|
|
@@ -303,13 +328,13 @@
|
|
|
303
328
|
let i = 0;
|
|
304
329
|
if (currentDecoder.keyMap) {
|
|
305
330
|
while((key = read()) != STOP_CODE) {
|
|
306
|
-
if (i++ >=
|
|
331
|
+
if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
307
332
|
object[safeKey(currentDecoder.decodeKey(key))] = read();
|
|
308
333
|
}
|
|
309
334
|
}
|
|
310
335
|
else {
|
|
311
336
|
while ((key = read()) != STOP_CODE) {
|
|
312
|
-
if (i++ >=
|
|
337
|
+
if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
313
338
|
object[safeKey(key)] = read();
|
|
314
339
|
}
|
|
315
340
|
}
|
|
@@ -355,11 +380,13 @@
|
|
|
355
380
|
case 1: // negative int
|
|
356
381
|
return ~token
|
|
357
382
|
case 2: // buffer
|
|
383
|
+
if (token > srcEnd - position$1) throw endOfCBORError()
|
|
358
384
|
return readBin(token)
|
|
359
385
|
case 3: // string
|
|
360
|
-
if (srcStringEnd >= position$1) {
|
|
386
|
+
if (srcStringEnd >= position$1) { // already extracted, which only covers complete strings
|
|
361
387
|
return srcString.slice(position$1 - srcStringStart, (position$1 += token) - srcStringStart)
|
|
362
388
|
}
|
|
389
|
+
if (token > srcEnd - position$1) throw endOfCBORError()
|
|
363
390
|
if (srcStringEnd == 0 && srcEnd < 140 && token < 32) {
|
|
364
391
|
// for small blocks, avoiding the overhead of the extract call is helpful
|
|
365
392
|
let string = token < 16 ? shortStringInJS(token) : longStringInJS(token);
|
|
@@ -368,15 +395,19 @@
|
|
|
368
395
|
}
|
|
369
396
|
return readFixedString(token)
|
|
370
397
|
case 4: // array
|
|
371
|
-
if (token
|
|
398
|
+
if (token > maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
|
|
399
|
+
// every element occupies at least one byte, so a length beyond what remains in the source can
|
|
400
|
+
// never be satisfied; check before allocating so a tiny header can not force a huge allocation
|
|
401
|
+
if (token > srcEnd - position$1) throw endOfCBORError()
|
|
372
402
|
let array = new Array(token);
|
|
373
403
|
//if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())
|
|
374
404
|
//else
|
|
375
405
|
for (let i = 0; i < token; i++) array[i] = read();
|
|
376
406
|
return array
|
|
377
407
|
case 5: // map
|
|
378
|
-
if (token >= maxMapSize) throw new Error(`Map size exceeds ${maxArraySize}`)
|
|
379
408
|
if (currentDecoder.mapsAsObjects) {
|
|
409
|
+
if (token > objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
410
|
+
if (token > (srcEnd - position$1) / 2) throw endOfCBORError() // each entry needs at least two bytes
|
|
380
411
|
let object = {};
|
|
381
412
|
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read();
|
|
382
413
|
else for (let i = 0; i < token; i++) object[safeKey(read())] = read();
|
|
@@ -386,6 +417,8 @@
|
|
|
386
417
|
currentDecoder.mapsAsObjects = true;
|
|
387
418
|
restoreMapsAsObject = false;
|
|
388
419
|
}
|
|
420
|
+
if (token > maxMapSize) throw new Error(`Map size exceeds ${maxMapSize}`)
|
|
421
|
+
if (token > (srcEnd - position$1) / 2) throw endOfCBORError()
|
|
389
422
|
let map = new Map();
|
|
390
423
|
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()),read());
|
|
391
424
|
else for (let i = 0; i < token; i++) map.set(read(), read());
|
|
@@ -467,11 +500,7 @@
|
|
|
467
500
|
throw new Error('Unknown token ' + token)
|
|
468
501
|
}
|
|
469
502
|
default: // negative int
|
|
470
|
-
if (isNaN(token))
|
|
471
|
-
let error = new Error('Unexpected end of CBOR data');
|
|
472
|
-
error.incomplete = true;
|
|
473
|
-
throw error
|
|
474
|
-
}
|
|
503
|
+
if (isNaN(token)) throw endOfCBORError()
|
|
475
504
|
throw new Error('Unknown CBOR token ' + token)
|
|
476
505
|
}
|
|
477
506
|
}
|
|
@@ -885,18 +914,12 @@
|
|
|
885
914
|
return (glbl[data[0]] || Error)(data[1], data[2])
|
|
886
915
|
};
|
|
887
916
|
const packedTable = (read) => {
|
|
888
|
-
if (
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
error.incomplete = true;
|
|
892
|
-
throw error
|
|
893
|
-
}
|
|
917
|
+
if (!(position$1 < srcEnd)) throw endOfCBORError()
|
|
918
|
+
if (src[position$1++] != 0x84)
|
|
919
|
+
throw new Error('Packed values structure must be followed by a 4 element array')
|
|
894
920
|
let newPackedValues = read(); // packed values
|
|
895
|
-
if (!newPackedValues || !newPackedValues.length)
|
|
896
|
-
|
|
897
|
-
error.incomplete = true;
|
|
898
|
-
throw error
|
|
899
|
-
}
|
|
921
|
+
if (!Array.isArray(newPackedValues) || !newPackedValues.length)
|
|
922
|
+
throw new Error('Packed values structure must be followed by a 4 element array')
|
|
900
923
|
packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues;
|
|
901
924
|
packedValues.prefixes = read();
|
|
902
925
|
packedValues.suffixes = read();
|
|
@@ -914,10 +937,7 @@
|
|
|
914
937
|
}
|
|
915
938
|
if (typeof data == 'number')
|
|
916
939
|
return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
|
|
917
|
-
|
|
918
|
-
if (data === undefined)
|
|
919
|
-
error.incomplete = true;
|
|
920
|
-
throw error
|
|
940
|
+
throw new Error('No support for non-integer packed references yet')
|
|
921
941
|
};
|
|
922
942
|
|
|
923
943
|
// The following code is an incomplete implementation of http://cbor.schmorp.de/stringref
|
|
@@ -987,9 +1007,19 @@
|
|
|
987
1007
|
(currentExtensions[259] = (read) => {
|
|
988
1008
|
// https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec
|
|
989
1009
|
// for decoding as a standard Map
|
|
990
|
-
|
|
991
|
-
|
|
1010
|
+
let decoder = currentDecoder;
|
|
1011
|
+
if (decoder.mapsAsObjects) {
|
|
1012
|
+
decoder.mapsAsObjects = false;
|
|
992
1013
|
restoreMapsAsObject = true;
|
|
1014
|
+
try {
|
|
1015
|
+
return read()
|
|
1016
|
+
} finally {
|
|
1017
|
+
// normally restored by the map header, but not if the tagged value is not a map or the read fails
|
|
1018
|
+
if (restoreMapsAsObject) {
|
|
1019
|
+
decoder.mapsAsObjects = true;
|
|
1020
|
+
restoreMapsAsObject = false;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
993
1023
|
}
|
|
994
1024
|
return read()
|
|
995
1025
|
}).handlesRead = true;
|
|
@@ -1100,17 +1130,21 @@
|
|
|
1100
1130
|
}
|
|
1101
1131
|
|
|
1102
1132
|
function readJustLength() {
|
|
1133
|
+
if (!(position$1 < srcEnd)) throw endOfCBORError()
|
|
1103
1134
|
let token = src[position$1++] & 0x1f;
|
|
1104
1135
|
if (token > 0x17) {
|
|
1105
1136
|
switch (token) {
|
|
1106
1137
|
case 0x18:
|
|
1138
|
+
if (position$1 >= srcEnd) throw endOfCBORError()
|
|
1107
1139
|
token = src[position$1++];
|
|
1108
1140
|
break
|
|
1109
1141
|
case 0x19:
|
|
1142
|
+
if (position$1 + 2 > srcEnd) throw endOfCBORError()
|
|
1110
1143
|
token = dataView.getUint16(position$1);
|
|
1111
1144
|
position$1 += 2;
|
|
1112
1145
|
break
|
|
1113
1146
|
case 0x1a:
|
|
1147
|
+
if (position$1 + 4 > srcEnd) throw endOfCBORError()
|
|
1114
1148
|
token = dataView.getUint32(position$1);
|
|
1115
1149
|
position$1 += 4;
|
|
1116
1150
|
break
|
|
@@ -1150,20 +1184,25 @@
|
|
|
1150
1184
|
let savedStructures = currentStructures;
|
|
1151
1185
|
let savedDecoder = currentDecoder;
|
|
1152
1186
|
let savedSequentialMode = sequentialMode;
|
|
1153
|
-
let
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1187
|
+
let savedRestoreMapsAsObject = restoreMapsAsObject;
|
|
1188
|
+
restoreMapsAsObject = false;
|
|
1189
|
+
try {
|
|
1190
|
+
return callback()
|
|
1191
|
+
} finally {
|
|
1192
|
+
srcEnd = savedSrcEnd;
|
|
1193
|
+
position$1 = savedPosition;
|
|
1194
|
+
srcStringStart = savedSrcStringStart;
|
|
1195
|
+
srcStringEnd = savedSrcStringEnd;
|
|
1196
|
+
srcString = savedSrcString;
|
|
1197
|
+
referenceMap = savedReferenceMap;
|
|
1198
|
+
bundledStrings$1 = savedBundledStrings;
|
|
1199
|
+
src = savedSrc;
|
|
1200
|
+
sequentialMode = savedSequentialMode;
|
|
1201
|
+
currentStructures = savedStructures;
|
|
1202
|
+
currentDecoder = savedDecoder;
|
|
1203
|
+
restoreMapsAsObject = savedRestoreMapsAsObject;
|
|
1204
|
+
dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
|
|
1205
|
+
}
|
|
1167
1206
|
}
|
|
1168
1207
|
function clearSource() {
|
|
1169
1208
|
src = null;
|
|
@@ -1178,7 +1217,8 @@
|
|
|
1178
1217
|
function setSizeLimits(limits) {
|
|
1179
1218
|
if (limits.maxMapSize) maxMapSize = limits.maxMapSize;
|
|
1180
1219
|
if (limits.maxArraySize) maxArraySize = limits.maxArraySize;
|
|
1181
|
-
if (limits.maxObjectSize) limits.maxObjectSize;
|
|
1220
|
+
if (limits.maxObjectSize) maxObjectSize = limits.maxObjectSize;
|
|
1221
|
+
objectSizeLimit = Math.min(maxObjectSize, maxMapSize);
|
|
1182
1222
|
}
|
|
1183
1223
|
|
|
1184
1224
|
const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
|
|
@@ -1380,7 +1420,7 @@
|
|
|
1380
1420
|
if (throwOnIterable)
|
|
1381
1421
|
return;
|
|
1382
1422
|
encode(value);
|
|
1383
|
-
if (bundledStrings) {
|
|
1423
|
+
if (bundledStrings && bundledStrings.position) { // position is only set once a bundle has been started
|
|
1384
1424
|
writeBundles(start, encode);
|
|
1385
1425
|
}
|
|
1386
1426
|
encoder.offset = position; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
|
|
@@ -2478,7 +2518,7 @@
|
|
|
2478
2518
|
}
|
|
2479
2519
|
|
|
2480
2520
|
const decoder = new Decoder(options);
|
|
2481
|
-
let incomplete;
|
|
2521
|
+
let incomplete, fatalError;
|
|
2482
2522
|
const parser = (chunk) => {
|
|
2483
2523
|
let yields;
|
|
2484
2524
|
// if there's incomplete data from previous chunk, concatinate and try again
|
|
@@ -2490,26 +2530,28 @@
|
|
|
2490
2530
|
try {
|
|
2491
2531
|
yields = decoder.decodeMultiple(chunk);
|
|
2492
2532
|
} catch (err) {
|
|
2533
|
+
yields = err.values;
|
|
2493
2534
|
if (err.incomplete) {
|
|
2494
2535
|
incomplete = chunk.slice(err.lastPosition);
|
|
2495
|
-
yields = err.values;
|
|
2496
2536
|
} else {
|
|
2497
|
-
|
|
2537
|
+
fatalError = err;
|
|
2498
2538
|
}
|
|
2499
2539
|
}
|
|
2500
|
-
return yields
|
|
2540
|
+
return yields || []
|
|
2501
2541
|
};
|
|
2502
2542
|
|
|
2503
2543
|
if (typeof bufferIterator[Symbol.iterator] === 'function') {
|
|
2504
2544
|
return (function * iter () {
|
|
2505
2545
|
for (const value of bufferIterator) {
|
|
2506
2546
|
yield * parser(value);
|
|
2547
|
+
if (fatalError) throw fatalError
|
|
2507
2548
|
}
|
|
2508
2549
|
})()
|
|
2509
2550
|
} else if (typeof bufferIterator[Symbol.asyncIterator] === 'function') {
|
|
2510
2551
|
return (async function * iter () {
|
|
2511
2552
|
for await (const value of bufferIterator) {
|
|
2512
2553
|
yield * parser(value);
|
|
2554
|
+
if (fatalError) throw fatalError
|
|
2513
2555
|
}
|
|
2514
2556
|
})()
|
|
2515
2557
|
}
|