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-no-eval.cjs
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;
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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 (
|
|
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++ >=
|
|
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++ >=
|
|
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
|
|
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 (
|
|
890
|
-
|
|
891
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
992
|
-
|
|
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
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
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
|
-
|
|
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
|
}
|