ecma-evaluator 2.0.8 → 2.0.10

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.
@@ -185,8 +185,6 @@ var mutableMethods = [
185
185
  "DataView.prototype.setFloat64",
186
186
  "DataView.prototype.setBigInt64",
187
187
  "DataView.prototype.setBigUint64",
188
- "Promise.prototype.catch",
189
- "Promise.prototype.finally",
190
188
  "Generator.prototype.next",
191
189
  "Generator.prototype.return",
192
190
  "Generator.prototype.throw",
@@ -221,7 +219,8 @@ var dangerousMethods = [
221
219
  "Object.getOwnPropertyDescriptors",
222
220
  "Object.getOwnPropertyNames",
223
221
  "Object.getOwnPropertySymbols",
224
- "Object.getOwnPropertyDescriptors"
222
+ "Error.captureStackTrace",
223
+ "Error.prepareStackTrace"
225
224
  ];
226
225
  mutableMethods.push("Object.prototype.__proto__");
227
226
  var blockedMethods = _to_consumable_array(mutableMethods).concat(_to_consumable_array(dangerousMethods));
@@ -268,6 +267,10 @@ var blockedGlobalBuiltIns = [
268
267
  "Reflect",
269
268
  "Atomics",
270
269
  "WebAssembly",
270
+ "SharedArrayBuffer",
271
+ "queueMicrotask",
272
+ "AbortSignal",
273
+ "Promise",
271
274
  "console",
272
275
  "Intl",
273
276
  "Deno"
@@ -363,14 +366,127 @@ var ERROR_MESSAGES = {
363
366
  IS_INVALID_SYNTAX: "{0} is not a valid syntax",
364
367
  IS_NOT_FUNCTION: "{0} is not a function",
365
368
  IS_NOT_DEFINED: "{0} is not defined",
366
- IS_NOT_ALLOWED: "{0} is not allowed"
369
+ IS_NOT_ALLOWED: "{0} is not allowed",
370
+ EXPRESSION_TOO_LONG: "Expression exceeds the maximum length of {0} characters"
367
371
  };
372
+ var DEFAULT_MAX_INPUT_LENGTH = 10000;
373
+ var MAX_CONFIGURABLE_INPUT_LENGTH = 100000;
374
+ var DEFAULT_MAX_EVALUATION_STEPS = 10000;
375
+ var MAX_CONFIGURABLE_EVALUATION_STEPS = 100000;
376
+ var MAX_ARRAY_LENGTH = 10000;
377
+ var MAX_BUFFER_BYTES = 1000000;
378
+ var MAX_STRING_LENGTH = 100000;
379
+ var MAX_DATA_NODES = 100000;
380
+ var MAX_BIGINT_EXPONENT = 256n;
381
+ var MAX_BIGINT_BITS = 65536;
382
+ var TYPED_ARRAY_CONSTRUCTORS = new Set([
383
+ Int8Array,
384
+ Uint8Array,
385
+ Uint8ClampedArray,
386
+ Int16Array,
387
+ Uint16Array,
388
+ Int32Array,
389
+ Uint32Array,
390
+ Float32Array,
391
+ Float64Array,
392
+ "function" == typeof BigInt64Array ? BigInt64Array : null,
393
+ "function" == typeof BigUint64Array ? BigUint64Array : null
394
+ ].filter(function(constructor) {
395
+ return "function" == typeof constructor;
396
+ }));
397
+ var NO_OBJECT = Symbol("no-object");
368
398
  var renderErrorMessage = function(template) {
369
399
  var context = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
370
400
  return template.replace(/{(\w+)}/g, function(_, key) {
371
401
  return String(context[key]);
372
402
  });
373
403
  };
404
+ function validateLimit(value, name, defaultValue, maximum) {
405
+ if (void 0 === value) return defaultValue;
406
+ if (!Number.isSafeInteger(value) || value < 1 || value > maximum) throw new RangeError("".concat(name, " must be an integer between 1 and ").concat(maximum));
407
+ return value;
408
+ }
409
+ function countLiteralMatches(value, search, all) {
410
+ if ("" === search) return all ? value.length + 1 : 1;
411
+ var count = 0;
412
+ var position = 0;
413
+ while(-1 !== (position = value.indexOf(search, position))){
414
+ count++;
415
+ if (!all) break;
416
+ position += search.length;
417
+ }
418
+ return count;
419
+ }
420
+ function assertBoundedData(value, label) {
421
+ var pending = [
422
+ value
423
+ ];
424
+ var seen = new WeakSet();
425
+ var dataSize = 0;
426
+ var dataNodes = 0;
427
+ var enqueueProperties = function(object) {
428
+ var keys = Object.keys(object);
429
+ if (pending.length + keys.length > MAX_DATA_NODES) throw new RangeError("".concat(label, " exceeds the maximum data node count"));
430
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
431
+ try {
432
+ for(var _iterator = keys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
433
+ var key = _step.value;
434
+ dataSize += key.length;
435
+ var descriptor = Object.getOwnPropertyDescriptor(object, key);
436
+ if (!descriptor || !Object.hasOwn(descriptor, "value")) throw new TypeError("".concat(label, " cannot contain accessor properties"));
437
+ pending.push(descriptor.value);
438
+ }
439
+ } catch (err) {
440
+ _didIteratorError = true;
441
+ _iteratorError = err;
442
+ } finally{
443
+ try {
444
+ if (!_iteratorNormalCompletion && null != _iterator.return) _iterator.return();
445
+ } finally{
446
+ if (_didIteratorError) throw _iteratorError;
447
+ }
448
+ }
449
+ };
450
+ while(pending.length > 0){
451
+ var current = pending.pop();
452
+ dataNodes++;
453
+ if (dataNodes > MAX_DATA_NODES) throw new RangeError("".concat(label, " exceeds the maximum data node count"));
454
+ if ("string" == typeof current) {
455
+ if (current.length > MAX_STRING_LENGTH) throw new RangeError("".concat(label, " contains a string that exceeds the maximum length"));
456
+ dataSize += current.length + 8;
457
+ } else if (null === current || (void 0 === current ? "undefined" : _type_of(current)) !== "object" && "function" != typeof current) {
458
+ dataSize += 8;
459
+ continue;
460
+ } else {
461
+ if ("function" == typeof current || seen.has(current)) continue;
462
+ seen.add(current);
463
+ dataSize += 16;
464
+ if (_instanceof(current, ArrayBuffer) || ArrayBuffer.isView(current)) dataSize += current.byteLength;
465
+ else if (Array.isArray(current)) {
466
+ if (current.length > MAX_ARRAY_LENGTH) throw new RangeError("".concat(label, " contains an array that exceeds the maximum length"));
467
+ dataSize += 8 * current.length;
468
+ enqueueProperties(current);
469
+ } else if (_instanceof(current, Map)) {
470
+ if (current.size > MAX_ARRAY_LENGTH) throw new RangeError("".concat(label, " contains a map that exceeds the maximum size"));
471
+ dataSize += 16 * current.size;
472
+ Map.prototype.forEach.call(current, function(item, key) {
473
+ return pending.push(key, item);
474
+ });
475
+ } else if (_instanceof(current, Set)) {
476
+ if (current.size > MAX_ARRAY_LENGTH) throw new RangeError("".concat(label, " contains a set that exceeds the maximum size"));
477
+ dataSize += 8 * current.size;
478
+ Set.prototype.forEach.call(current, function(item) {
479
+ return pending.push(item);
480
+ });
481
+ } else enqueueProperties(current);
482
+ }
483
+ if (dataSize > MAX_BUFFER_BYTES) throw new RangeError("".concat(label, " exceeds the maximum data size"));
484
+ }
485
+ return {
486
+ dataSize: dataSize,
487
+ dataNodes: dataNodes
488
+ };
489
+ }
374
490
  var BINARY_OPERATION_MAP = {
375
491
  "+": function(a, b) {
376
492
  return a + b;
@@ -509,21 +625,35 @@ var getBlockedMethods = function() {
509
625
  var Evaluator_Evaluator = /*#__PURE__*/ function() {
510
626
  "use strict";
511
627
  function Evaluator() {
512
- var variables = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : Object.create(null);
628
+ var variables = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : Object.create(null), options = arguments.length > 1 ? arguments[1] : void 0;
513
629
  _class_call_check(this, Evaluator);
630
+ this.maxInputLength = validateLimit(null == options ? void 0 : options.maxInputLength, "maxInputLength", DEFAULT_MAX_INPUT_LENGTH, MAX_CONFIGURABLE_INPUT_LENGTH);
631
+ this.maxEvaluationSteps = validateLimit(null == options ? void 0 : options.maxEvaluationSteps, "maxEvaluationSteps", DEFAULT_MAX_EVALUATION_STEPS, MAX_CONFIGURABLE_EVALUATION_STEPS);
632
+ assertBoundedData(variables, "Evaluation context");
633
+ var clonedVariables = structuredClone(variables);
514
634
  this.scopes = [
515
- structuredClone(variables),
635
+ clonedVariables,
516
636
  createGlobalScope()
517
637
  ].filter(function(scope) {
518
638
  return null != scope;
519
639
  });
520
640
  this.source = void 0;
641
+ this.remainingEvaluationSteps = 0;
642
+ this.remainingDataSize = MAX_BUFFER_BYTES;
643
+ this.remainingDataNodes = MAX_DATA_NODES;
521
644
  }
522
645
  _create_class(Evaluator, [
523
646
  {
524
647
  key: "evaluate",
525
648
  value: function(expression) {
649
+ if ("string" != typeof expression) throw new TypeError("Expression must be a string");
650
+ if (expression.length > this.maxInputLength) throw new SyntaxError(renderErrorMessage(ERROR_MESSAGES.EXPRESSION_TOO_LONG, [
651
+ this.maxInputLength
652
+ ]));
526
653
  this.source = expression;
654
+ this.remainingEvaluationSteps = this.maxEvaluationSteps;
655
+ this.remainingDataSize = MAX_BUFFER_BYTES;
656
+ this.remainingDataNodes = MAX_DATA_NODES;
527
657
  var ast = external_acorn_namespaceObject.parse(expression, {
528
658
  ecmaVersion: "latest"
529
659
  });
@@ -537,6 +667,11 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
537
667
  {
538
668
  key: "execute",
539
669
  value: function(body) {
670
+ if (0 === this.remainingEvaluationSteps) {
671
+ this.remainingEvaluationSteps = this.maxEvaluationSteps;
672
+ this.remainingDataSize = MAX_BUFFER_BYTES;
673
+ this.remainingDataNodes = MAX_DATA_NODES;
674
+ }
540
675
  var result;
541
676
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
542
677
  try {
@@ -557,13 +692,26 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
557
692
  if ("function" == typeof result) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
558
693
  "Returning functions from expressions"
559
694
  ]));
560
- return result;
695
+ assertBoundedData(result, "Evaluation result");
696
+ if (_instanceof(result, Promise)) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
697
+ "Returning promises from expressions"
698
+ ]));
699
+ try {
700
+ return structuredClone(result);
701
+ } catch (error) {
702
+ if (error && "DataCloneError" === error.name) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
703
+ "Returning non-cloneable values from expressions"
704
+ ]));
705
+ throw error;
706
+ }
561
707
  }
562
708
  },
563
709
  {
564
710
  key: "visit",
565
711
  value: function(node) {
566
712
  var _this = this;
713
+ this.remainingEvaluationSteps--;
714
+ if (this.remainingEvaluationSteps < 0) throw new RangeError("Evaluation step limit exceeded");
567
715
  switch(node.type){
568
716
  case "ExpressionStatement":
569
717
  return this.visit(node.expression);
@@ -600,10 +748,14 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
600
748
  if ("Function" === node.callee.name) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
601
749
  "new Function() constructor"
602
750
  ]));
751
+ if ("Promise" === node.callee.name) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
752
+ "Promise constructor"
753
+ ]));
603
754
  var Constructor = this.visit(node.callee);
604
755
  var args = node.arguments.length ? node.arguments.map(function(arg) {
605
756
  return _this.visit(arg);
606
757
  }) : [];
758
+ this.assertBoundedConstruction(Constructor, args);
607
759
  return _construct(Constructor, Evaluator_to_consumable_array(args));
608
760
  case "ChainExpression":
609
761
  return this.visit(node.expression);
@@ -632,10 +784,49 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
632
784
  var op = node.operator;
633
785
  var left = this.visit(node.left);
634
786
  var right = this.visit(node.right);
787
+ if ("+" === op && ("string" == typeof left || "string" == typeof right)) {
788
+ if (String(left).length + String(right).length > MAX_STRING_LENGTH) throw new RangeError("String result exceeds the maximum allowed length");
789
+ }
790
+ if ((void 0 === left ? "undefined" : _type_of(left)) === "bigint" && (void 0 === right ? "undefined" : _type_of(right)) === "bigint") {
791
+ if ("**" === op && (right > MAX_BIGINT_EXPONENT || right < 0n)) throw new RangeError("BigInt exponent must be between 0 and ".concat(MAX_BIGINT_EXPONENT));
792
+ var leftBits = left.toString(2).length;
793
+ var rightBits = right.toString(2).length;
794
+ 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");
795
+ }
635
796
  if (BINARY_OPERATION_MAP.hasOwnProperty(op)) return BINARY_OPERATION_MAP[op](left, right);
636
797
  throw new SyntaxError("Unsupported operator: ".concat(node.operator));
637
798
  }
638
799
  },
800
+ {
801
+ key: "assertBoundedConstruction",
802
+ value: function(Constructor, args) {
803
+ var _args_;
804
+ var size = args[0];
805
+ if (Constructor === Array && 1 === args.length && "number" == typeof size && size > MAX_ARRAY_LENGTH) throw new RangeError("Array length exceeds the maximum allowed length");
806
+ 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");
807
+ if (Constructor === DataView && _instanceof(size, ArrayBuffer) && size.byteLength > MAX_BUFFER_BYTES) throw new RangeError("DataView size exceeds the maximum allowed size");
808
+ if (Constructor === Map || Constructor === Set) {
809
+ var _size_size;
810
+ 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;
811
+ if ("number" == typeof collectionSize && collectionSize > MAX_ARRAY_LENGTH) throw new RangeError("Collection source exceeds the maximum allowed size");
812
+ }
813
+ if (TYPED_ARRAY_CONSTRUCTORS.has(Constructor)) {
814
+ var byteLength;
815
+ if (_instanceof(size, ArrayBuffer)) {
816
+ var _args_1;
817
+ var offset = null != (_args_1 = args[1]) ? _args_1 : 0;
818
+ var _args_2;
819
+ var elementCount = null != (_args_2 = args[2]) ? _args_2 : Math.floor((size.byteLength - offset) / Constructor.BYTES_PER_ELEMENT);
820
+ byteLength = elementCount * Constructor.BYTES_PER_ELEMENT;
821
+ } else {
822
+ var _size_length;
823
+ var elementCount1 = "number" == typeof size ? size : null != (_size_length = null == size ? void 0 : size.length) ? _size_length : 0;
824
+ byteLength = elementCount1 * Constructor.BYTES_PER_ELEMENT;
825
+ }
826
+ if (byteLength > MAX_BUFFER_BYTES) throw new RangeError("Typed array size exceeds the maximum allowed size");
827
+ }
828
+ }
829
+ },
639
830
  {
640
831
  key: "handleLogicalExpression",
641
832
  value: function(node) {
@@ -707,9 +898,13 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
707
898
  {
708
899
  key: "handleMemberExpression",
709
900
  value: function(node) {
710
- var object = this.visit(node.object);
901
+ var objectValue = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : NO_OBJECT;
902
+ var object = objectValue === NO_OBJECT ? this.visit(node.object) : objectValue;
711
903
  var isStaticProperty = "Identifier" === node.property.type && !node.computed;
712
904
  var property = isStaticProperty ? node.property.name : this.visit(node.property);
905
+ if ("stack" === property && _instanceof(object, Error)) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
906
+ "Accessing error stack"
907
+ ]));
713
908
  if (null != object && object[property] === (null == object ? void 0 : object.__proto__)) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
714
909
  "Accessing prototype properties"
715
910
  ]));
@@ -720,7 +915,11 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
720
915
  property
721
916
  ]));
722
917
  }
723
- return object[property];
918
+ var result = object[property];
919
+ if (result === Function || result === Function.prototype) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
920
+ "Function constructor"
921
+ ]));
922
+ return result;
724
923
  }
725
924
  },
726
925
  {
@@ -729,30 +928,52 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
729
928
  var result = [];
730
929
  for(var i = 0; i < node.elements.length; i++){
731
930
  var element = node.elements.at(i);
931
+ if (null === element) {
932
+ result.length++;
933
+ continue;
934
+ }
732
935
  var value = this.visit(element);
733
936
  if ("SpreadElement" === element.type) {
734
937
  var _result;
938
+ this.assertBoundedSpread(result.length, value);
735
939
  (_result = result).push.apply(_result, Evaluator_to_consumable_array(value));
736
940
  } else result.push(value);
737
941
  }
738
942
  return result;
739
943
  }
740
944
  },
945
+ {
946
+ key: "assertBoundedSpread",
947
+ value: function(currentLength, value) {
948
+ var size = "string" == typeof value || Array.isArray(value) ? value.length : null == value ? void 0 : value.size;
949
+ if ("number" == typeof size && currentLength + size > MAX_ARRAY_LENGTH) throw new RangeError("Spread value exceeds the maximum allowed length");
950
+ }
951
+ },
741
952
  {
742
953
  key: "handleObjectExpression",
743
954
  value: function(node) {
744
955
  var obj = {};
956
+ var spreadPropertyCount = 0;
745
957
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
746
958
  try {
747
959
  for(var _iterator = node.properties[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
748
960
  var prop = _step.value;
749
961
  if ("SpreadElement" === prop.type) {
750
- Object.assign(obj, this.visit(prop.argument));
962
+ var spreadValue = this.visit(prop.argument);
963
+ spreadPropertyCount += Object.keys(spreadValue).length;
964
+ if (spreadPropertyCount > MAX_ARRAY_LENGTH) throw new RangeError("Object spread exceeds the maximum allowed property count");
965
+ Object.assign(obj, spreadValue);
751
966
  continue;
752
967
  }
753
- var key = prop.key.name || prop.key.value;
968
+ var key = prop.computed ? this.visit(prop.key) : prop.key.name || prop.key.value;
754
969
  var value = this.visit(prop.value);
755
- obj[key] = value;
970
+ if (prop.computed) Object.defineProperty(obj, key, {
971
+ value: value,
972
+ writable: true,
973
+ enumerable: true,
974
+ configurable: true
975
+ });
976
+ else obj[key] = value;
756
977
  }
757
978
  } catch (err) {
758
979
  _didIteratorError = true;
@@ -783,22 +1004,43 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
783
1004
  var paramCount = node.params.length;
784
1005
  for(var i = 0; i < paramCount; i++)newScope[node.params[i].name] = args[i];
785
1006
  _this.scopes.unshift(newScope);
786
- var result = _this.visit(node.body);
787
- _this.scopes.shift();
788
- return result;
1007
+ try {
1008
+ var result = _this.visit(node.body);
1009
+ _this.consumeEvaluationValue(result);
1010
+ return result;
1011
+ } finally{
1012
+ _this.scopes.shift();
1013
+ }
789
1014
  };
790
1015
  }
791
1016
  },
1017
+ {
1018
+ key: "consumeEvaluationValue",
1019
+ value: function(value) {
1020
+ var _assertBoundedData = assertBoundedData(value, "Intermediate evaluation result"), dataSize = _assertBoundedData.dataSize, dataNodes = _assertBoundedData.dataNodes;
1021
+ this.remainingDataSize -= dataSize;
1022
+ this.remainingDataNodes -= dataNodes;
1023
+ if (this.remainingDataSize < 0 || this.remainingDataNodes < 0) throw new RangeError("Evaluation allocation budget exceeded");
1024
+ }
1025
+ },
792
1026
  {
793
1027
  key: "handleCallExpression",
794
1028
  value: function(node) {
795
1029
  var _this = this;
796
- var func = this.visit(node.callee);
797
- var isOptional = node.optional || node.callee.optional;
1030
+ var isOptional = node.optional || "MemberExpression" === node.callee.type && node.callee.optional;
1031
+ var func;
1032
+ var target = null;
1033
+ if ("MemberExpression" === node.callee.type) {
1034
+ target = this.visit(node.callee.object);
1035
+ func = this.handleMemberExpression(node.callee, target);
1036
+ } else func = this.visit(node.callee);
798
1037
  if (null == func && isOptional) return;
799
1038
  if (func === Function) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
800
1039
  "Function constructor"
801
1040
  ]));
1041
+ if (func === Error.prepareStackTrace) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
1042
+ "Error.prepareStackTrace"
1043
+ ]));
802
1044
  if (getBlockedMethods().has(func)) {
803
1045
  var path = getBlockedMethods().get(func);
804
1046
  throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
@@ -813,19 +1055,56 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
813
1055
  var value = _this.visit(element);
814
1056
  if ("SpreadElement" === element.type) {
815
1057
  var _result;
1058
+ _this.assertBoundedSpread(result.length, value);
816
1059
  (_result = result).push.apply(_result, Evaluator_to_consumable_array(value));
817
1060
  } else result.push(value);
818
1061
  }
819
1062
  return result;
820
1063
  }();
821
- var target = "MemberExpression" === node.callee.type ? this.visit(node.callee.object) : null;
1064
+ if (args.some(function(arg) {
1065
+ return arg === Function;
1066
+ })) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
1067
+ "Function constructor"
1068
+ ]));
1069
+ if ("string" == typeof target) {
1070
+ 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");
1071
+ 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");
1072
+ if (String.prototype.concat && func === String.prototype.concat) {
1073
+ var resultLength = target.length + args.reduce(function(length, value) {
1074
+ return length + String(value).length;
1075
+ }, 0);
1076
+ if (resultLength > MAX_STRING_LENGTH) throw new RangeError("String result exceeds the maximum allowed length");
1077
+ }
1078
+ if (String.prototype.replace && func === String.prototype.replace || String.prototype.replaceAll && func === String.prototype.replaceAll) {
1079
+ if ("string" == typeof args[0]) {
1080
+ if ("function" == typeof args[1] || "string" == typeof args[1] && RegExp("\\$(?:[$&'`])", "u").test(args[1])) throw new Error("Only literal string replacements are allowed");
1081
+ if (target.length * Math.max(1, args[0].length) > 10000000) throw new RangeError("String operation exceeds the maximum work limit");
1082
+ var matchCount = countLiteralMatches(target, args[0], func === String.prototype.replaceAll);
1083
+ if (target.length + matchCount * String(args[1]).length > MAX_STRING_LENGTH) throw new RangeError("String result exceeds the maximum allowed length");
1084
+ }
1085
+ }
1086
+ if (func === String.prototype.split) {
1087
+ if ("" === args[0] && target.length > MAX_ARRAY_LENGTH) throw new RangeError("Split result exceeds the maximum allowed length");
1088
+ 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");
1089
+ }
1090
+ }
1091
+ if ((target === Array || TYPED_ARRAY_CONSTRUCTORS.has(target)) && func === target.from) {
1092
+ var source = args[0];
1093
+ var _source_size;
1094
+ 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;
1095
+ if ("number" == typeof size && size > MAX_ARRAY_LENGTH) throw new RangeError("Array.from source exceeds the maximum allowed length");
1096
+ }
822
1097
  if ("function" != typeof func) {
823
1098
  var calledString = getNodeString(node.callee);
824
1099
  throw new TypeError(renderErrorMessage(ERROR_MESSAGES.IS_NOT_FUNCTION, [
825
1100
  calledString
826
1101
  ]));
827
1102
  }
828
- return func.apply(target, args);
1103
+ var result = func.apply(target, args);
1104
+ if (_instanceof(result, Promise)) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
1105
+ "Returning promises from expressions"
1106
+ ]));
1107
+ return result;
829
1108
  }
830
1109
  },
831
1110
  {
@@ -890,11 +1169,25 @@ function TemplateParser_create_class(Constructor, protoProps, staticProps) {
890
1169
  if (staticProps) TemplateParser_defineProperties(Constructor, staticProps);
891
1170
  return Constructor;
892
1171
  }
1172
+ var DEFAULT_MAX_TEMPLATE_LENGTH = 100000;
1173
+ var MAX_CONFIGURABLE_TEMPLATE_LENGTH = 1000000;
1174
+ var DEFAULT_MAX_TOKENS = 1000;
1175
+ var MAX_CONFIGURABLE_TOKENS = 10000;
1176
+ function TemplateParser_validateLimit(value, name, defaultValue, maximum) {
1177
+ if (void 0 === value) return defaultValue;
1178
+ if (!Number.isSafeInteger(value) || value < 1 || value > maximum) throw new RangeError("".concat(name, " must be an integer between 1 and ").concat(maximum));
1179
+ return value;
1180
+ }
893
1181
  var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
894
1182
  "use strict";
895
1183
  function TemplateParser() {
896
1184
  var options = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
897
1185
  TemplateParser_class_call_check(this, TemplateParser);
1186
+ null != options || (options = {});
1187
+ this.maxTemplateLength = TemplateParser_validateLimit(options.maxTemplateLength, "maxTemplateLength", DEFAULT_MAX_TEMPLATE_LENGTH, MAX_CONFIGURABLE_TEMPLATE_LENGTH);
1188
+ this.maxTokens = TemplateParser_validateLimit(options.maxTokens, "maxTokens", DEFAULT_MAX_TOKENS, MAX_CONFIGURABLE_TOKENS);
1189
+ 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");
1190
+ 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");
898
1191
  this.exprStart = options.expressionStart || "{{";
899
1192
  this.exprEnd = options.expressionEnd || "}}";
900
1193
  this.startLen = this.exprStart.length;
@@ -905,8 +1198,14 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
905
1198
  {
906
1199
  key: "parse",
907
1200
  value: function(template) {
1201
+ var _this = this;
908
1202
  if ("string" != typeof template) throw new TypeError("模板必须是字符串");
1203
+ if (template.length > this.maxTemplateLength) throw new RangeError("Template exceeds the maximum length of ".concat(this.maxTemplateLength, " characters"));
909
1204
  var tokens = [];
1205
+ var pushToken = function(token) {
1206
+ if (tokens.length >= _this.maxTokens) throw new RangeError("Template exceeds the maximum token count of ".concat(_this.maxTokens));
1207
+ tokens.push(token);
1208
+ };
910
1209
  var length = template.length;
911
1210
  var state = "TEXT";
912
1211
  var buffer = "";
@@ -919,7 +1218,7 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
919
1218
  case "TEXT":
920
1219
  if (this._isMatch(pos, template, this.exprStart)) {
921
1220
  if (buffer.length > 0) {
922
- tokens.push({
1221
+ pushToken({
923
1222
  type: "text",
924
1223
  value: buffer,
925
1224
  start: pos - buffer.length,
@@ -941,7 +1240,7 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
941
1240
  else if ("\\" === char) state = "'" === nextChar ? "ESCAPE_SQ" : '"' === nextChar ? "ESCAPE_DQ" : "`" === nextChar ? "ESCAPE_TEMPLATE" : "ESCAPE_EXPR";
942
1241
  else if (this._isMatch(pos, template, this.exprEnd)) {
943
1242
  var exprValue = this.preserveWhitespace ? buffer : buffer.trim();
944
- if (exprValue.length > 0) tokens.push({
1243
+ if (exprValue.length > 0) pushToken({
945
1244
  type: "expression",
946
1245
  value: exprValue,
947
1246
  start: exprStartPos,
@@ -990,7 +1289,7 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
990
1289
  }
991
1290
  pos++;
992
1291
  }
993
- if (buffer.length > 0) if ("TEXT" === state) tokens.push({
1292
+ if (buffer.length > 0) if ("TEXT" === state) pushToken({
994
1293
  type: "text",
995
1294
  value: buffer,
996
1295
  start: pos - buffer.length,
@@ -998,13 +1297,12 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
998
1297
  });
999
1298
  else {
1000
1299
  var incompleteExpr = this.exprStart + buffer;
1001
- tokens.push({
1300
+ pushToken({
1002
1301
  type: "text",
1003
1302
  value: incompleteExpr,
1004
1303
  start: exprStartPos,
1005
1304
  end: pos
1006
1305
  });
1007
- console.warn("警告:在位置 ".concat(exprStartPos, " 开始的表达式未正确结束"));
1008
1306
  }
1009
1307
  return tokens;
1010
1308
  }
@@ -1032,18 +1330,36 @@ function src_instanceof(left, right) {
1032
1330
  if (null != right && "undefined" != typeof Symbol && right[Symbol.hasInstance]) return !!right[Symbol.hasInstance](left);
1033
1331
  return left instanceof right;
1034
1332
  }
1333
+ var DEFAULT_MAX_TEMPLATE_EXPRESSIONS = 100;
1334
+ var MAX_TEMPLATE_EXPRESSIONS = 1000;
1335
+ var DEFAULT_MAX_TEMPLATE_OUTPUT_LENGTH = 100000;
1336
+ var MAX_TEMPLATE_OUTPUT_LENGTH = 1000000;
1337
+ function src_validateLimit(value, name, defaultValue, maximum) {
1338
+ if (void 0 === value) return defaultValue;
1339
+ if (!Number.isSafeInteger(value) || value < 1 || value > maximum) throw new RangeError("".concat(name, " must be an integer between 1 and ").concat(maximum));
1340
+ return value;
1341
+ }
1035
1342
  function evalExpression(expression, context) {
1036
1343
  return Evaluator_Evaluator.evaluate(expression, context);
1037
1344
  }
1038
1345
  function evalTemplate(template, context, templateParserOptions) {
1346
+ var options = null != templateParserOptions ? templateParserOptions : {};
1347
+ var maxExpressions = src_validateLimit(options.maxExpressions, "maxExpressions", DEFAULT_MAX_TEMPLATE_EXPRESSIONS, MAX_TEMPLATE_EXPRESSIONS);
1348
+ var maxOutputLength = src_validateLimit(options.maxOutputLength, "maxOutputLength", DEFAULT_MAX_TEMPLATE_OUTPUT_LENGTH, MAX_TEMPLATE_OUTPUT_LENGTH);
1349
+ var tokens = TemplateParser_TemplateParser.parse(template, options);
1039
1350
  var result = "";
1351
+ var expressionCount = 0;
1352
+ var evaluator = new Evaluator_Evaluator(context, {
1353
+ maxInputLength: options.maxExpressionLength,
1354
+ maxEvaluationSteps: options.maxEvaluationSteps
1355
+ });
1040
1356
  var typeHandler = {
1041
1357
  text: function(token) {
1042
1358
  return token.value;
1043
1359
  },
1044
1360
  expression: function(token) {
1045
1361
  try {
1046
- return Evaluator_Evaluator.evaluate(token.value, context);
1362
+ return evaluator.evaluate(token.value);
1047
1363
  } catch (error) {
1048
1364
  if (src_instanceof(error, ReferenceError) && error.message.endsWith("is not defined")) return "undefined";
1049
1365
  throw error;
@@ -1052,11 +1368,17 @@ function evalTemplate(template, context, templateParserOptions) {
1052
1368
  };
1053
1369
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
1054
1370
  try {
1055
- for(var _iterator = TemplateParser_TemplateParser.parse(template, templateParserOptions)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1371
+ for(var _iterator = tokens[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1056
1372
  var token = _step.value;
1057
1373
  var _typeHandler_token_type;
1058
1374
  var handler = null != (_typeHandler_token_type = typeHandler[token.type]) ? _typeHandler_token_type : typeHandler["text"];
1059
- result += handler(token);
1375
+ if ("expression" === token.type) {
1376
+ expressionCount++;
1377
+ if (expressionCount > maxExpressions) throw new RangeError("Template exceeds the maximum expression count of ".concat(maxExpressions));
1378
+ }
1379
+ var chunk = String(handler(token));
1380
+ if (result.length + chunk.length > maxOutputLength) throw new RangeError("Template output exceeds the maximum length of ".concat(maxOutputLength, " characters"));
1381
+ result += chunk;
1060
1382
  }
1061
1383
  } catch (err) {
1062
1384
  _didIteratorError = true;