ecma-evaluator 2.0.9 → 2.1.0

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.
@@ -76,6 +76,7 @@ var mutableMethods = [
76
76
  "Array.prototype.sort",
77
77
  "Array.prototype.fill",
78
78
  "Array.prototype.copyWithin",
79
+ "Object.create",
79
80
  "Object.defineProperty",
80
81
  "Object.defineProperties",
81
82
  "Object.preventExtensions",
@@ -185,8 +186,6 @@ var mutableMethods = [
185
186
  "DataView.prototype.setFloat64",
186
187
  "DataView.prototype.setBigInt64",
187
188
  "DataView.prototype.setBigUint64",
188
- "Promise.prototype.catch",
189
- "Promise.prototype.finally",
190
189
  "Generator.prototype.next",
191
190
  "Generator.prototype.return",
192
191
  "Generator.prototype.throw",
@@ -221,7 +220,8 @@ var dangerousMethods = [
221
220
  "Object.getOwnPropertyDescriptors",
222
221
  "Object.getOwnPropertyNames",
223
222
  "Object.getOwnPropertySymbols",
224
- "Object.getOwnPropertyDescriptors"
223
+ "Error.captureStackTrace",
224
+ "Error.prepareStackTrace"
225
225
  ];
226
226
  mutableMethods.push("Object.prototype.__proto__");
227
227
  var blockedMethods = _to_consumable_array(mutableMethods).concat(_to_consumable_array(dangerousMethods));
@@ -268,6 +268,10 @@ var blockedGlobalBuiltIns = [
268
268
  "Reflect",
269
269
  "Atomics",
270
270
  "WebAssembly",
271
+ "SharedArrayBuffer",
272
+ "queueMicrotask",
273
+ "AbortSignal",
274
+ "Promise",
271
275
  "console",
272
276
  "Intl",
273
277
  "Deno"
@@ -363,14 +367,173 @@ var ERROR_MESSAGES = {
363
367
  IS_INVALID_SYNTAX: "{0} is not a valid syntax",
364
368
  IS_NOT_FUNCTION: "{0} is not a function",
365
369
  IS_NOT_DEFINED: "{0} is not defined",
366
- IS_NOT_ALLOWED: "{0} is not allowed"
370
+ IS_NOT_ALLOWED: "{0} is not allowed",
371
+ EXPRESSION_TOO_LONG: "Expression exceeds the maximum length of {0} characters"
367
372
  };
373
+ var DEFAULT_MAX_INPUT_LENGTH = 10000;
374
+ var MAX_CONFIGURABLE_INPUT_LENGTH = 100000;
375
+ var DEFAULT_MAX_EVALUATION_STEPS = 10000;
376
+ var MAX_CONFIGURABLE_EVALUATION_STEPS = 100000;
377
+ var MAX_ARRAY_LENGTH = 10000;
378
+ var MAX_BUFFER_BYTES = 1000000;
379
+ var MAX_STRING_LENGTH = 100000;
380
+ var MAX_DATA_NODES = 100000;
381
+ var MAX_BIGINT_EXPONENT = 256n;
382
+ var MAX_BIGINT_BITS = 65536;
383
+ var DEFAULT_MAX_DEPTH = 1000;
384
+ var MAX_CONFIGURABLE_DEPTH = 2000;
385
+ var MAX_REGEXP_SOURCE_LENGTH = 1000;
386
+ var MAX_REGEXP_FLAGS_LENGTH = 32;
387
+ var NON_SANDBOX_GLOBALS = new Set([
388
+ "WeakRef",
389
+ "FinalizationRegistry",
390
+ "Iterator",
391
+ "SharedArrayBuffer",
392
+ "escape",
393
+ "unescape"
394
+ ]);
395
+ var TYPED_ARRAY_CONSTRUCTORS = new Set([
396
+ Int8Array,
397
+ Uint8Array,
398
+ Uint8ClampedArray,
399
+ Int16Array,
400
+ Uint16Array,
401
+ Int32Array,
402
+ Uint32Array,
403
+ "function" == typeof Float16Array ? Float16Array : null,
404
+ Float32Array,
405
+ Float64Array,
406
+ "function" == typeof BigInt64Array ? BigInt64Array : null,
407
+ "function" == typeof BigUint64Array ? BigUint64Array : null
408
+ ].filter(function(constructor) {
409
+ return "function" == typeof constructor;
410
+ }));
411
+ function isTypedArrayConstructor(value) {
412
+ return TYPED_ARRAY_CONSTRUCTORS.has(value) || "function" == typeof value && "number" == typeof value.BYTES_PER_ELEMENT;
413
+ }
414
+ var TYPED_ARRAY_MUTATORS = function() {
415
+ var map = new Map();
416
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
417
+ try {
418
+ for(var _iterator = TYPED_ARRAY_CONSTRUCTORS[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
419
+ var constructor = _step.value;
420
+ for(var _i = 0, _iter = [
421
+ "set",
422
+ "fill",
423
+ "reverse",
424
+ "sort",
425
+ "copyWithin"
426
+ ]; _i < _iter.length; _i++){
427
+ var name = _iter[_i];
428
+ var method = constructor.prototype[name];
429
+ if ("function" == typeof method && !map.has(method)) map.set(method, name);
430
+ }
431
+ }
432
+ } catch (err) {
433
+ _didIteratorError = true;
434
+ _iteratorError = err;
435
+ } finally{
436
+ try {
437
+ if (!_iteratorNormalCompletion && null != _iterator.return) _iterator.return();
438
+ } finally{
439
+ if (_didIteratorError) throw _iteratorError;
440
+ }
441
+ }
442
+ return map;
443
+ }();
444
+ var NO_OBJECT = Symbol("no-object");
368
445
  var renderErrorMessage = function(template) {
369
446
  var context = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
370
447
  return template.replace(/{(\w+)}/g, function(_, key) {
371
448
  return String(context[key]);
372
449
  });
373
450
  };
451
+ function validateLimit(value, name, defaultValue, maximum) {
452
+ if (void 0 === value) return defaultValue;
453
+ if (!Number.isSafeInteger(value) || value < 1 || value > maximum) throw new RangeError("".concat(name, " must be an integer between 1 and ").concat(maximum));
454
+ return value;
455
+ }
456
+ function countLiteralMatches(value, search, all) {
457
+ if ("" === search) return all ? value.length + 1 : 1;
458
+ var count = 0;
459
+ var position = 0;
460
+ while(-1 !== (position = value.indexOf(search, position))){
461
+ count++;
462
+ if (!all) break;
463
+ position += search.length;
464
+ }
465
+ return count;
466
+ }
467
+ function assertBoundedData(value, label) {
468
+ var pending = [
469
+ value
470
+ ];
471
+ var seen = new WeakSet();
472
+ var dataSize = 0;
473
+ var dataNodes = 0;
474
+ var enqueueProperties = function(object) {
475
+ var keys = Object.keys(object);
476
+ if (pending.length + keys.length > MAX_DATA_NODES) throw new RangeError("".concat(label, " exceeds the maximum data node count"));
477
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
478
+ try {
479
+ for(var _iterator = keys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
480
+ var key = _step.value;
481
+ dataSize += key.length;
482
+ var descriptor = Object.getOwnPropertyDescriptor(object, key);
483
+ if (!descriptor || !Object.hasOwn(descriptor, "value")) throw new TypeError("".concat(label, " cannot contain accessor properties"));
484
+ pending.push(descriptor.value);
485
+ }
486
+ } catch (err) {
487
+ _didIteratorError = true;
488
+ _iteratorError = err;
489
+ } finally{
490
+ try {
491
+ if (!_iteratorNormalCompletion && null != _iterator.return) _iterator.return();
492
+ } finally{
493
+ if (_didIteratorError) throw _iteratorError;
494
+ }
495
+ }
496
+ };
497
+ while(pending.length > 0){
498
+ var current = pending.pop();
499
+ dataNodes++;
500
+ if (dataNodes > MAX_DATA_NODES) throw new RangeError("".concat(label, " exceeds the maximum data node count"));
501
+ if ("string" == typeof current) {
502
+ if (current.length > MAX_STRING_LENGTH) throw new RangeError("".concat(label, " contains a string that exceeds the maximum length"));
503
+ dataSize += current.length + 8;
504
+ } else if (null === current || (void 0 === current ? "undefined" : _type_of(current)) !== "object" && "function" != typeof current) {
505
+ dataSize += 8;
506
+ continue;
507
+ } else {
508
+ if ("function" == typeof current || seen.has(current)) continue;
509
+ seen.add(current);
510
+ dataSize += 16;
511
+ if (_instanceof(current, ArrayBuffer) || ArrayBuffer.isView(current)) dataSize += current.byteLength;
512
+ else if (Array.isArray(current)) {
513
+ if (current.length > MAX_ARRAY_LENGTH) throw new RangeError("".concat(label, " contains an array that exceeds the maximum length"));
514
+ dataSize += 8 * current.length;
515
+ enqueueProperties(current);
516
+ } else if (_instanceof(current, Map)) {
517
+ if (current.size > MAX_ARRAY_LENGTH) throw new RangeError("".concat(label, " contains a map that exceeds the maximum size"));
518
+ dataSize += 16 * current.size;
519
+ Map.prototype.forEach.call(current, function(item, key) {
520
+ return pending.push(key, item);
521
+ });
522
+ } else if (_instanceof(current, Set)) {
523
+ if (current.size > MAX_ARRAY_LENGTH) throw new RangeError("".concat(label, " contains a set that exceeds the maximum size"));
524
+ dataSize += 8 * current.size;
525
+ Set.prototype.forEach.call(current, function(item) {
526
+ return pending.push(item);
527
+ });
528
+ } else enqueueProperties(current);
529
+ }
530
+ if (dataSize > MAX_BUFFER_BYTES) throw new RangeError("".concat(label, " exceeds the maximum data size"));
531
+ }
532
+ return {
533
+ dataSize: dataSize,
534
+ dataNodes: dataNodes
535
+ };
536
+ }
374
537
  var BINARY_OPERATION_MAP = {
375
538
  "+": function(a, b) {
376
539
  return a + b;
@@ -442,14 +605,20 @@ var BINARY_OPERATION_MAP = {
442
605
  function createGlobalScope() {
443
606
  var scope = Object.create(null);
444
607
  var builtin = external_globals_namespaceObject.builtin;
445
- for(var key in builtin)if (!blockedGlobalBuiltIns.includes(key)) {
446
- var isWritable = builtin[key];
447
- Object.defineProperty(scope, key, {
448
- value: globalThis[key],
449
- writable: isWritable,
450
- enumerable: false,
451
- configurable: false
452
- });
608
+ for(var key in builtin){
609
+ if (!blockedGlobalBuiltIns.includes(key)) {
610
+ if (!NON_SANDBOX_GLOBALS.has(key)) {
611
+ if (Object.hasOwn(globalThis, key)) {
612
+ var isWritable = builtin[key];
613
+ Object.defineProperty(scope, key, {
614
+ value: globalThis[key],
615
+ writable: isWritable,
616
+ enumerable: false,
617
+ configurable: false
618
+ });
619
+ }
620
+ }
621
+ }
453
622
  }
454
623
  Object.defineProperty(scope, "globalThis", {
455
624
  value: scope,
@@ -459,6 +628,7 @@ function createGlobalScope() {
459
628
  });
460
629
  return scope;
461
630
  }
631
+ var GLOBAL_SCOPE = createGlobalScope();
462
632
  var getBlockedMethods = function() {
463
633
  var BLOCKED_METHODS = null;
464
634
  return function() {
@@ -509,24 +679,47 @@ var getBlockedMethods = function() {
509
679
  var Evaluator_Evaluator = /*#__PURE__*/ function() {
510
680
  "use strict";
511
681
  function Evaluator() {
512
- var variables = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : Object.create(null);
682
+ var variables = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : Object.create(null), options = arguments.length > 1 ? arguments[1] : void 0;
513
683
  _class_call_check(this, Evaluator);
684
+ this.maxInputLength = validateLimit(null == options ? void 0 : options.maxInputLength, "maxInputLength", DEFAULT_MAX_INPUT_LENGTH, MAX_CONFIGURABLE_INPUT_LENGTH);
685
+ this.maxEvaluationSteps = validateLimit(null == options ? void 0 : options.maxEvaluationSteps, "maxEvaluationSteps", DEFAULT_MAX_EVALUATION_STEPS, MAX_CONFIGURABLE_EVALUATION_STEPS);
686
+ this.maxDepth = validateLimit(null == options ? void 0 : options.maxDepth, "maxDepth", DEFAULT_MAX_DEPTH, MAX_CONFIGURABLE_DEPTH);
687
+ assertBoundedData(variables, "Evaluation context");
688
+ var clonedVariables = structuredClone(variables);
514
689
  this.scopes = [
515
- structuredClone(variables),
516
- createGlobalScope()
690
+ clonedVariables,
691
+ GLOBAL_SCOPE
517
692
  ].filter(function(scope) {
518
693
  return null != scope;
519
694
  });
520
695
  this.source = void 0;
696
+ this.remainingEvaluationSteps = 0;
697
+ this.remainingDataSize = MAX_BUFFER_BYTES;
698
+ this.remainingDataNodes = MAX_DATA_NODES;
699
+ this.evaluationDepth = 0;
521
700
  }
522
701
  _create_class(Evaluator, [
523
702
  {
524
703
  key: "evaluate",
525
704
  value: function(expression) {
705
+ if ("string" != typeof expression) throw new TypeError("Expression must be a string");
706
+ if (expression.length > this.maxInputLength) throw new SyntaxError(renderErrorMessage(ERROR_MESSAGES.EXPRESSION_TOO_LONG, [
707
+ this.maxInputLength
708
+ ]));
526
709
  this.source = expression;
527
- var ast = external_acorn_namespaceObject.parse(expression, {
528
- ecmaVersion: "latest"
529
- });
710
+ this.remainingEvaluationSteps = this.maxEvaluationSteps;
711
+ this.remainingDataSize = MAX_BUFFER_BYTES;
712
+ this.remainingDataNodes = MAX_DATA_NODES;
713
+ this.evaluationDepth = 0;
714
+ var ast;
715
+ try {
716
+ ast = external_acorn_namespaceObject.parse(expression, {
717
+ ecmaVersion: "latest"
718
+ });
719
+ } catch (error) {
720
+ if (_instanceof(error, RangeError) && /call stack/i.test(error.message)) throw new SyntaxError("Expression nesting is too deep to parse");
721
+ throw error;
722
+ }
530
723
  try {
531
724
  return this.execute(ast.body);
532
725
  } finally{
@@ -537,6 +730,11 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
537
730
  {
538
731
  key: "execute",
539
732
  value: function(body) {
733
+ if (0 === this.remainingEvaluationSteps) {
734
+ this.remainingEvaluationSteps = this.maxEvaluationSteps;
735
+ this.remainingDataSize = MAX_BUFFER_BYTES;
736
+ this.remainingDataNodes = MAX_DATA_NODES;
737
+ }
540
738
  var result;
541
739
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
542
740
  try {
@@ -557,11 +755,39 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
557
755
  if ("function" == typeof result) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
558
756
  "Returning functions from expressions"
559
757
  ]));
560
- return result;
758
+ assertBoundedData(result, "Evaluation result");
759
+ if (_instanceof(result, Promise)) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
760
+ "Returning promises from expressions"
761
+ ]));
762
+ try {
763
+ return structuredClone(result);
764
+ } catch (error) {
765
+ if (error && "DataCloneError" === error.name) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
766
+ "Returning non-cloneable values from expressions"
767
+ ]));
768
+ throw error;
769
+ }
561
770
  }
562
771
  },
563
772
  {
564
773
  key: "visit",
774
+ value: function(node) {
775
+ this.remainingEvaluationSteps--;
776
+ if (this.remainingEvaluationSteps < 0) throw new RangeError("Evaluation step limit exceeded");
777
+ this.evaluationDepth++;
778
+ if (this.evaluationDepth > this.maxDepth) {
779
+ this.evaluationDepth--;
780
+ throw new RangeError("Maximum evaluation depth exceeded");
781
+ }
782
+ try {
783
+ return this.visitNode(node);
784
+ } finally{
785
+ this.evaluationDepth--;
786
+ }
787
+ }
788
+ },
789
+ {
790
+ key: "visitNode",
565
791
  value: function(node) {
566
792
  var _this = this;
567
793
  switch(node.type){
@@ -600,10 +826,14 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
600
826
  if ("Function" === node.callee.name) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
601
827
  "new Function() constructor"
602
828
  ]));
829
+ if ("Promise" === node.callee.name) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
830
+ "Promise constructor"
831
+ ]));
603
832
  var Constructor = this.visit(node.callee);
604
833
  var args = node.arguments.length ? node.arguments.map(function(arg) {
605
834
  return _this.visit(arg);
606
835
  }) : [];
836
+ this.assertBoundedConstruction(Constructor, args);
607
837
  return _construct(Constructor, Evaluator_to_consumable_array(args));
608
838
  case "ChainExpression":
609
839
  return this.visit(node.expression);
@@ -632,10 +862,57 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
632
862
  var op = node.operator;
633
863
  var left = this.visit(node.left);
634
864
  var right = this.visit(node.right);
865
+ if ("+" === op && ("string" == typeof left || "string" == typeof right)) {
866
+ if (String(left).length + String(right).length > MAX_STRING_LENGTH) throw new RangeError("String result exceeds the maximum allowed length");
867
+ }
868
+ if ((void 0 === left ? "undefined" : _type_of(left)) === "bigint" && (void 0 === right ? "undefined" : _type_of(right)) === "bigint") {
869
+ if ("**" === op && (right > MAX_BIGINT_EXPONENT || right < 0n)) throw new RangeError("BigInt exponent must be between 0 and ".concat(MAX_BIGINT_EXPONENT));
870
+ var leftBits = left.toString(2).length;
871
+ var rightBits = right.toString(2).length;
872
+ if ("**" === op && leftBits * Number(right) > MAX_BIGINT_BITS || "<<" === op && right > BigInt(MAX_BIGINT_BITS) || "<<" === op && right >= 0n && leftBits + Number(right) > MAX_BIGINT_BITS || "*" === op && leftBits + rightBits > MAX_BIGINT_BITS || ("+" === op || "-" === op) && Math.max(leftBits, rightBits) + 1 > MAX_BIGINT_BITS) throw new RangeError("BigInt result exceeds the maximum allowed size");
873
+ }
635
874
  if (BINARY_OPERATION_MAP.hasOwnProperty(op)) return BINARY_OPERATION_MAP[op](left, right);
636
875
  throw new SyntaxError("Unsupported operator: ".concat(node.operator));
637
876
  }
638
877
  },
878
+ {
879
+ key: "assertBoundedRegExp",
880
+ value: function(args) {
881
+ if ("string" == typeof args[0] && args[0].length > MAX_REGEXP_SOURCE_LENGTH) throw new RangeError("RegExp source exceeds the maximum allowed length");
882
+ if ("string" == typeof args[1] && args[1].length > MAX_REGEXP_FLAGS_LENGTH) throw new RangeError("RegExp flags exceed the maximum allowed length");
883
+ }
884
+ },
885
+ {
886
+ key: "assertBoundedConstruction",
887
+ value: function(Constructor, args) {
888
+ var _args_;
889
+ if (Constructor === RegExp) this.assertBoundedRegExp(args);
890
+ var size = args[0];
891
+ if (Constructor === Array && 1 === args.length && "number" == typeof size && size > MAX_ARRAY_LENGTH) throw new RangeError("Array length exceeds the maximum allowed length");
892
+ if (Constructor === ArrayBuffer && (size > MAX_BUFFER_BYTES || (null == (_args_ = args[1]) ? void 0 : _args_.maxByteLength) > MAX_BUFFER_BYTES)) throw new RangeError("ArrayBuffer size exceeds the maximum allowed size");
893
+ if (Constructor === DataView && _instanceof(size, ArrayBuffer) && size.byteLength > MAX_BUFFER_BYTES) throw new RangeError("DataView size exceeds the maximum allowed size");
894
+ if (Constructor === Map || Constructor === Set) {
895
+ var _size_size;
896
+ var collectionSize = "string" == typeof size || Array.isArray(size) ? size.length : null != (_size_size = null == size ? void 0 : size.size) ? _size_size : null == size ? void 0 : size.length;
897
+ if ("number" == typeof collectionSize && collectionSize > MAX_ARRAY_LENGTH) throw new RangeError("Collection source exceeds the maximum allowed size");
898
+ }
899
+ if (isTypedArrayConstructor(Constructor)) {
900
+ var byteLength;
901
+ if (_instanceof(size, ArrayBuffer)) {
902
+ var _args_1;
903
+ var offset = null != (_args_1 = args[1]) ? _args_1 : 0;
904
+ var _args_2;
905
+ var elementCount = null != (_args_2 = args[2]) ? _args_2 : Math.floor((size.byteLength - offset) / Constructor.BYTES_PER_ELEMENT);
906
+ byteLength = elementCount * Constructor.BYTES_PER_ELEMENT;
907
+ } else {
908
+ var _size_length;
909
+ var elementCount1 = "number" == typeof size ? size : null != (_size_length = null == size ? void 0 : size.length) ? _size_length : 0;
910
+ byteLength = elementCount1 * Constructor.BYTES_PER_ELEMENT;
911
+ }
912
+ if (byteLength > MAX_BUFFER_BYTES) throw new RangeError("Typed array size exceeds the maximum allowed size");
913
+ }
914
+ }
915
+ },
639
916
  {
640
917
  key: "handleLogicalExpression",
641
918
  value: function(node) {
@@ -707,10 +984,14 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
707
984
  {
708
985
  key: "handleMemberExpression",
709
986
  value: function(node) {
710
- var object = this.visit(node.object);
987
+ var objectValue = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : NO_OBJECT;
988
+ var object = objectValue === NO_OBJECT ? this.visit(node.object) : objectValue;
711
989
  var isStaticProperty = "Identifier" === node.property.type && !node.computed;
712
990
  var property = isStaticProperty ? node.property.name : this.visit(node.property);
713
- if (null != object && object[property] === (null == object ? void 0 : object.__proto__)) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
991
+ if ("stack" === property && _instanceof(object, Error)) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
992
+ "Accessing error stack"
993
+ ]));
994
+ if (null != object && void 0 !== object.__proto__ && object[property] === object.__proto__) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
714
995
  "Accessing prototype properties"
715
996
  ]));
716
997
  if (null == object) {
@@ -733,30 +1014,52 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
733
1014
  var result = [];
734
1015
  for(var i = 0; i < node.elements.length; i++){
735
1016
  var element = node.elements.at(i);
1017
+ if (null === element) {
1018
+ result.length++;
1019
+ continue;
1020
+ }
736
1021
  var value = this.visit(element);
737
1022
  if ("SpreadElement" === element.type) {
738
1023
  var _result;
1024
+ this.assertBoundedSpread(result.length, value);
739
1025
  (_result = result).push.apply(_result, Evaluator_to_consumable_array(value));
740
1026
  } else result.push(value);
741
1027
  }
742
1028
  return result;
743
1029
  }
744
1030
  },
1031
+ {
1032
+ key: "assertBoundedSpread",
1033
+ value: function(currentLength, value) {
1034
+ var size = "string" == typeof value || Array.isArray(value) ? value.length : null == value ? void 0 : value.size;
1035
+ if ("number" == typeof size && currentLength + size > MAX_ARRAY_LENGTH) throw new RangeError("Spread value exceeds the maximum allowed length");
1036
+ }
1037
+ },
745
1038
  {
746
1039
  key: "handleObjectExpression",
747
1040
  value: function(node) {
748
1041
  var obj = {};
1042
+ var spreadPropertyCount = 0;
749
1043
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
750
1044
  try {
751
1045
  for(var _iterator = node.properties[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
752
1046
  var prop = _step.value;
753
1047
  if ("SpreadElement" === prop.type) {
754
- Object.assign(obj, this.visit(prop.argument));
1048
+ var spreadValue = this.visit(prop.argument);
1049
+ spreadPropertyCount += Object.keys(spreadValue).length;
1050
+ if (spreadPropertyCount > MAX_ARRAY_LENGTH) throw new RangeError("Object spread exceeds the maximum allowed property count");
1051
+ Object.assign(obj, spreadValue);
755
1052
  continue;
756
1053
  }
757
- var key = prop.key.name || prop.key.value;
1054
+ var key = prop.computed ? this.visit(prop.key) : prop.key.name || prop.key.value;
758
1055
  var value = this.visit(prop.value);
759
- obj[key] = value;
1056
+ if (prop.computed) Object.defineProperty(obj, key, {
1057
+ value: value,
1058
+ writable: true,
1059
+ enumerable: true,
1060
+ configurable: true
1061
+ });
1062
+ else obj[key] = value;
760
1063
  }
761
1064
  } catch (err) {
762
1065
  _didIteratorError = true;
@@ -787,28 +1090,52 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
787
1090
  var paramCount = node.params.length;
788
1091
  for(var i = 0; i < paramCount; i++)newScope[node.params[i].name] = args[i];
789
1092
  _this.scopes.unshift(newScope);
790
- var result = _this.visit(node.body);
791
- _this.scopes.shift();
792
- return result;
1093
+ try {
1094
+ var result = _this.visit(node.body);
1095
+ _this.consumeEvaluationValue(result);
1096
+ return result;
1097
+ } finally{
1098
+ _this.scopes.shift();
1099
+ }
793
1100
  };
794
1101
  }
795
1102
  },
1103
+ {
1104
+ key: "consumeEvaluationValue",
1105
+ value: function(value) {
1106
+ var _assertBoundedData = assertBoundedData(value, "Intermediate evaluation result"), dataSize = _assertBoundedData.dataSize, dataNodes = _assertBoundedData.dataNodes;
1107
+ this.remainingDataSize -= dataSize;
1108
+ this.remainingDataNodes -= dataNodes;
1109
+ if (this.remainingDataSize < 0 || this.remainingDataNodes < 0) throw new RangeError("Evaluation allocation budget exceeded");
1110
+ }
1111
+ },
796
1112
  {
797
1113
  key: "handleCallExpression",
798
1114
  value: function(node) {
799
1115
  var _this = this;
800
- var func = this.visit(node.callee);
801
- var isOptional = node.optional || node.callee.optional;
1116
+ var isOptional = node.optional || "MemberExpression" === node.callee.type && node.callee.optional;
1117
+ var func;
1118
+ var target = null;
1119
+ if ("MemberExpression" === node.callee.type) {
1120
+ target = this.visit(node.callee.object);
1121
+ func = this.handleMemberExpression(node.callee, target);
1122
+ } else func = this.visit(node.callee);
802
1123
  if (null == func && isOptional) return;
803
1124
  if (func === Function) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
804
1125
  "Function constructor"
805
1126
  ]));
1127
+ if (func === Error.prepareStackTrace) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
1128
+ "Error.prepareStackTrace"
1129
+ ]));
806
1130
  if (getBlockedMethods().has(func)) {
807
1131
  var path = getBlockedMethods().get(func);
808
1132
  throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
809
1133
  path
810
1134
  ]));
811
1135
  }
1136
+ if (TYPED_ARRAY_MUTATORS.has(func)) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
1137
+ "TypedArray.prototype.".concat(TYPED_ARRAY_MUTATORS.get(func))
1138
+ ]));
812
1139
  var args = function() {
813
1140
  if (0 === node.arguments.length) return [];
814
1141
  var result = [];
@@ -817,24 +1144,57 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
817
1144
  var value = _this.visit(element);
818
1145
  if ("SpreadElement" === element.type) {
819
1146
  var _result;
1147
+ _this.assertBoundedSpread(result.length, value);
820
1148
  (_result = result).push.apply(_result, Evaluator_to_consumable_array(value));
821
1149
  } else result.push(value);
822
1150
  }
823
1151
  return result;
824
1152
  }();
825
- var target = "MemberExpression" === node.callee.type ? this.visit(node.callee.object) : null;
826
1153
  if (args.some(function(arg) {
827
1154
  return arg === Function;
828
1155
  })) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
829
1156
  "Function constructor"
830
1157
  ]));
1158
+ if ("string" == typeof target) {
1159
+ if (String.prototype.repeat && func === String.prototype.repeat && target.length * Number(args[0]) > MAX_STRING_LENGTH) throw new RangeError("String result exceeds the maximum allowed length");
1160
+ if ((String.prototype.padStart && func === String.prototype.padStart || func === String.prototype.padEnd) && Number(args[0]) > MAX_STRING_LENGTH) throw new RangeError("String result exceeds the maximum allowed length");
1161
+ if (String.prototype.concat && func === String.prototype.concat) {
1162
+ var resultLength = target.length + args.reduce(function(length, value) {
1163
+ return length + String(value).length;
1164
+ }, 0);
1165
+ if (resultLength > MAX_STRING_LENGTH) throw new RangeError("String result exceeds the maximum allowed length");
1166
+ }
1167
+ if (String.prototype.replace && func === String.prototype.replace || String.prototype.replaceAll && func === String.prototype.replaceAll) {
1168
+ if ("string" == typeof args[0]) {
1169
+ if ("function" == typeof args[1] || "string" == typeof args[1] && RegExp("\\$(?:[$&'`])", "u").test(args[1])) throw new Error("Only literal string replacements are allowed");
1170
+ if (target.length * Math.max(1, args[0].length) > 10000000) throw new RangeError("String operation exceeds the maximum work limit");
1171
+ var matchCount = countLiteralMatches(target, args[0], func === String.prototype.replaceAll);
1172
+ if (target.length + matchCount * String(args[1]).length > MAX_STRING_LENGTH) throw new RangeError("String result exceeds the maximum allowed length");
1173
+ }
1174
+ }
1175
+ if (func === String.prototype.split) {
1176
+ if ("" === args[0] && target.length > MAX_ARRAY_LENGTH) throw new RangeError("Split result exceeds the maximum allowed length");
1177
+ if ("string" == typeof args[0] && "" !== args[0] && countLiteralMatches(target, args[0], true) >= MAX_ARRAY_LENGTH) throw new RangeError("Split result exceeds the maximum allowed length");
1178
+ }
1179
+ }
1180
+ if (func === RegExp) this.assertBoundedRegExp(args);
1181
+ if ((target === Array || isTypedArrayConstructor(target)) && func === target.from) {
1182
+ var source = args[0];
1183
+ var _source_size;
1184
+ var size = "string" == typeof source || Array.isArray(source) ? source.length : null != (_source_size = null == source ? void 0 : source.size) ? _source_size : null == source ? void 0 : source.length;
1185
+ if ("number" == typeof size && size > MAX_ARRAY_LENGTH) throw new RangeError("Array.from source exceeds the maximum allowed length");
1186
+ }
831
1187
  if ("function" != typeof func) {
832
1188
  var calledString = getNodeString(node.callee);
833
1189
  throw new TypeError(renderErrorMessage(ERROR_MESSAGES.IS_NOT_FUNCTION, [
834
1190
  calledString
835
1191
  ]));
836
1192
  }
837
- return func.apply(target, args);
1193
+ var result = func.apply(target, args);
1194
+ if (_instanceof(result, Promise)) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
1195
+ "Returning promises from expressions"
1196
+ ]));
1197
+ return result;
838
1198
  }
839
1199
  },
840
1200
  {
@@ -868,7 +1228,7 @@ function getNodeString(node) {
868
1228
  return node.raw;
869
1229
  case "ArrayExpression":
870
1230
  return "[".concat(node.elements.map(function(child) {
871
- return getNodeString(child);
1231
+ return null === child ? "" : getNodeString(child);
872
1232
  }).join(","), "]");
873
1233
  case "ObjectExpression":
874
1234
  if (0 === node.properties.length) return "{}";
@@ -899,11 +1259,25 @@ function TemplateParser_create_class(Constructor, protoProps, staticProps) {
899
1259
  if (staticProps) TemplateParser_defineProperties(Constructor, staticProps);
900
1260
  return Constructor;
901
1261
  }
1262
+ var DEFAULT_MAX_TEMPLATE_LENGTH = 100000;
1263
+ var MAX_CONFIGURABLE_TEMPLATE_LENGTH = 1000000;
1264
+ var DEFAULT_MAX_TOKENS = 1000;
1265
+ var MAX_CONFIGURABLE_TOKENS = 10000;
1266
+ function TemplateParser_validateLimit(value, name, defaultValue, maximum) {
1267
+ if (void 0 === value) return defaultValue;
1268
+ if (!Number.isSafeInteger(value) || value < 1 || value > maximum) throw new RangeError("".concat(name, " must be an integer between 1 and ").concat(maximum));
1269
+ return value;
1270
+ }
902
1271
  var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
903
1272
  "use strict";
904
1273
  function TemplateParser() {
905
1274
  var options = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
906
1275
  TemplateParser_class_call_check(this, TemplateParser);
1276
+ null != options || (options = {});
1277
+ this.maxTemplateLength = TemplateParser_validateLimit(options.maxTemplateLength, "maxTemplateLength", DEFAULT_MAX_TEMPLATE_LENGTH, MAX_CONFIGURABLE_TEMPLATE_LENGTH);
1278
+ this.maxTokens = TemplateParser_validateLimit(options.maxTokens, "maxTokens", DEFAULT_MAX_TOKENS, MAX_CONFIGURABLE_TOKENS);
1279
+ if (void 0 !== options.expressionStart && ("string" != typeof options.expressionStart || 0 === options.expressionStart.length || options.expressionStart.length > 128)) throw new TypeError("expressionStart must be a non-empty string of at most 128 characters");
1280
+ if (void 0 !== options.expressionEnd && ("string" != typeof options.expressionEnd || 0 === options.expressionEnd.length || options.expressionEnd.length > 128)) throw new TypeError("expressionEnd must be a non-empty string of at most 128 characters");
907
1281
  this.exprStart = options.expressionStart || "{{";
908
1282
  this.exprEnd = options.expressionEnd || "}}";
909
1283
  this.startLen = this.exprStart.length;
@@ -914,13 +1288,20 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
914
1288
  {
915
1289
  key: "parse",
916
1290
  value: function(template) {
1291
+ var _this = this;
917
1292
  if ("string" != typeof template) throw new TypeError("模板必须是字符串");
1293
+ if (template.length > this.maxTemplateLength) throw new RangeError("Template exceeds the maximum length of ".concat(this.maxTemplateLength, " characters"));
918
1294
  var tokens = [];
1295
+ var pushToken = function(token) {
1296
+ if (tokens.length >= _this.maxTokens) throw new RangeError("Template exceeds the maximum token count of ".concat(_this.maxTokens));
1297
+ tokens.push(token);
1298
+ };
919
1299
  var length = template.length;
920
1300
  var state = "TEXT";
921
1301
  var buffer = "";
922
1302
  var exprStartPos = 0;
923
1303
  var pos = 0;
1304
+ var prevExprChar = "";
924
1305
  while(pos < length){
925
1306
  var char = template[pos];
926
1307
  var nextChar = template[pos + 1];
@@ -928,7 +1309,7 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
928
1309
  case "TEXT":
929
1310
  if (this._isMatch(pos, template, this.exprStart)) {
930
1311
  if (buffer.length > 0) {
931
- tokens.push({
1312
+ pushToken({
932
1313
  type: "text",
933
1314
  value: buffer,
934
1315
  start: pos - buffer.length,
@@ -938,6 +1319,7 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
938
1319
  }
939
1320
  state = "EXPR";
940
1321
  exprStartPos = pos;
1322
+ prevExprChar = "";
941
1323
  pos += this.startLen;
942
1324
  continue;
943
1325
  }
@@ -947,10 +1329,11 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
947
1329
  if ("'" === char) state = "STRING_SQ";
948
1330
  else if ('"' === char) state = "STRING_DQ";
949
1331
  else if ("`" === char) state = "TEMPLATE";
1332
+ else if ("/" === char && this._isRegexPosition(prevExprChar)) state = "REGEX";
950
1333
  else if ("\\" === char) state = "'" === nextChar ? "ESCAPE_SQ" : '"' === nextChar ? "ESCAPE_DQ" : "`" === nextChar ? "ESCAPE_TEMPLATE" : "ESCAPE_EXPR";
951
1334
  else if (this._isMatch(pos, template, this.exprEnd)) {
952
1335
  var exprValue = this.preserveWhitespace ? buffer : buffer.trim();
953
- if (exprValue.length > 0) tokens.push({
1336
+ if (exprValue.length > 0) pushToken({
954
1337
  type: "expression",
955
1338
  value: exprValue,
956
1339
  start: exprStartPos,
@@ -963,6 +1346,7 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
963
1346
  pos += this.endLen;
964
1347
  continue;
965
1348
  }
1349
+ if (!RegExp("\\s", "u").test(char)) prevExprChar = char;
966
1350
  buffer += char;
967
1351
  break;
968
1352
  case "STRING_SQ":
@@ -980,6 +1364,17 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
980
1364
  else if ("`" === char) state = "EXPR";
981
1365
  buffer += char;
982
1366
  break;
1367
+ case "REGEX":
1368
+ if ("\\" === char) state = "ESCAPE_REGEX";
1369
+ else if ("[" === char) state = "REGEX_CLASS";
1370
+ else if ("/" === char) state = "EXPR";
1371
+ buffer += char;
1372
+ break;
1373
+ case "REGEX_CLASS":
1374
+ if ("\\" === char) state = "ESCAPE_REGEX";
1375
+ else if ("]" === char) state = "REGEX";
1376
+ buffer += char;
1377
+ break;
983
1378
  case "ESCAPE_SQ":
984
1379
  buffer += char;
985
1380
  state = "STRING_SQ";
@@ -992,6 +1387,10 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
992
1387
  buffer += char;
993
1388
  state = "TEMPLATE";
994
1389
  break;
1390
+ case "ESCAPE_REGEX":
1391
+ buffer += char;
1392
+ state = "REGEX";
1393
+ break;
995
1394
  case "ESCAPE_EXPR":
996
1395
  buffer += char;
997
1396
  state = "EXPR";
@@ -999,7 +1398,7 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
999
1398
  }
1000
1399
  pos++;
1001
1400
  }
1002
- if (buffer.length > 0) if ("TEXT" === state) tokens.push({
1401
+ if (buffer.length > 0) if ("TEXT" === state) pushToken({
1003
1402
  type: "text",
1004
1403
  value: buffer,
1005
1404
  start: pos - buffer.length,
@@ -1007,17 +1406,22 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
1007
1406
  });
1008
1407
  else {
1009
1408
  var incompleteExpr = this.exprStart + buffer;
1010
- tokens.push({
1409
+ pushToken({
1011
1410
  type: "text",
1012
1411
  value: incompleteExpr,
1013
1412
  start: exprStartPos,
1014
1413
  end: pos
1015
1414
  });
1016
- console.warn("警告:在位置 ".concat(exprStartPos, " 开始的表达式未正确结束"));
1017
1415
  }
1018
1416
  return tokens;
1019
1417
  }
1020
1418
  },
1419
+ {
1420
+ key: "_isRegexPosition",
1421
+ value: function(prev) {
1422
+ return "" === prev || "(,=:[!&|?{};+-*%^~<>".includes(prev);
1423
+ }
1424
+ },
1021
1425
  {
1022
1426
  key: "_isMatch",
1023
1427
  value: function(pos, template, sequence) {
@@ -1041,18 +1445,36 @@ function src_instanceof(left, right) {
1041
1445
  if (null != right && "undefined" != typeof Symbol && right[Symbol.hasInstance]) return !!right[Symbol.hasInstance](left);
1042
1446
  return left instanceof right;
1043
1447
  }
1448
+ var DEFAULT_MAX_TEMPLATE_EXPRESSIONS = 100;
1449
+ var MAX_TEMPLATE_EXPRESSIONS = 1000;
1450
+ var DEFAULT_MAX_TEMPLATE_OUTPUT_LENGTH = 100000;
1451
+ var MAX_TEMPLATE_OUTPUT_LENGTH = 1000000;
1452
+ function src_validateLimit(value, name, defaultValue, maximum) {
1453
+ if (void 0 === value) return defaultValue;
1454
+ if (!Number.isSafeInteger(value) || value < 1 || value > maximum) throw new RangeError("".concat(name, " must be an integer between 1 and ").concat(maximum));
1455
+ return value;
1456
+ }
1044
1457
  function evalExpression(expression, context) {
1045
1458
  return Evaluator_Evaluator.evaluate(expression, context);
1046
1459
  }
1047
1460
  function evalTemplate(template, context, templateParserOptions) {
1461
+ var options = null != templateParserOptions ? templateParserOptions : {};
1462
+ var maxExpressions = src_validateLimit(options.maxExpressions, "maxExpressions", DEFAULT_MAX_TEMPLATE_EXPRESSIONS, MAX_TEMPLATE_EXPRESSIONS);
1463
+ var maxOutputLength = src_validateLimit(options.maxOutputLength, "maxOutputLength", DEFAULT_MAX_TEMPLATE_OUTPUT_LENGTH, MAX_TEMPLATE_OUTPUT_LENGTH);
1464
+ var tokens = TemplateParser_TemplateParser.parse(template, options);
1048
1465
  var result = "";
1466
+ var expressionCount = 0;
1467
+ var evaluator = new Evaluator_Evaluator(context, {
1468
+ maxInputLength: options.maxExpressionLength,
1469
+ maxEvaluationSteps: options.maxEvaluationSteps
1470
+ });
1049
1471
  var typeHandler = {
1050
1472
  text: function(token) {
1051
1473
  return token.value;
1052
1474
  },
1053
1475
  expression: function(token) {
1054
1476
  try {
1055
- return Evaluator_Evaluator.evaluate(token.value, context);
1477
+ return evaluator.evaluate(token.value);
1056
1478
  } catch (error) {
1057
1479
  if (src_instanceof(error, ReferenceError) && error.message.endsWith("is not defined")) return "undefined";
1058
1480
  throw error;
@@ -1061,11 +1483,17 @@ function evalTemplate(template, context, templateParserOptions) {
1061
1483
  };
1062
1484
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
1063
1485
  try {
1064
- for(var _iterator = TemplateParser_TemplateParser.parse(template, templateParserOptions)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1486
+ for(var _iterator = tokens[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1065
1487
  var token = _step.value;
1066
1488
  var _typeHandler_token_type;
1067
1489
  var handler = null != (_typeHandler_token_type = typeHandler[token.type]) ? _typeHandler_token_type : typeHandler["text"];
1068
- result += handler(token);
1490
+ if ("expression" === token.type) {
1491
+ expressionCount++;
1492
+ if (expressionCount > maxExpressions) throw new RangeError("Template exceeds the maximum expression count of ".concat(maxExpressions));
1493
+ }
1494
+ var chunk = String(handler(token));
1495
+ if (result.length + chunk.length > maxOutputLength) throw new RangeError("Template output exceeds the maximum length of ".concat(maxOutputLength, " characters"));
1496
+ result += chunk;
1069
1497
  }
1070
1498
  } catch (err) {
1071
1499
  _didIteratorError = true;