diff --git a/src/expression/Parser.js b/src/expression/Parser.js index e39b53d82a..712fc91729 100644 --- a/src/expression/Parser.js +++ b/src/expression/Parser.js @@ -2,9 +2,9 @@ import { factory } from '../utils/factory.js' import { createEmptyMap, toObject } from '../utils/map.js' const name = 'Parser' -const dependencies = ['evaluate'] +const dependencies = ['evaluate', 'parse'] -export const createParserClass = /* #__PURE__ */ factory(name, dependencies, ({ evaluate }) => { +export const createParserClass = /* #__PURE__ */ factory(name, dependencies, ({ evaluate, parse }) => { /** * @constructor Parser * Parser contains methods to evaluate or parse expressions, and has a number @@ -112,12 +112,32 @@ export const createParserClass = /* #__PURE__ */ factory(name, dependencies, ({ return this.scope } + function isValidVariableName (name) { + if (name.length === 0) { return false } + + for (let i = 0; i < name.length; i++) { + const cPrev = name.charAt(i - 1) + const c = name.charAt(i) + const cNext = name.charAt(i + 1) + const valid = parse.isAlpha(c, cPrev, cNext) || (i > 0 && parse.isDigit(c)) + + if (!valid) { + return false + } + } + + return true + } + /** * Set a symbol (a function or variable) by name from the parsers scope. * @param {string} name * @param {* | undefined} value */ Parser.prototype.set = function (name, value) { + if (!isValidVariableName(name)) { + throw new Error(`Invalid variable name: '${name}'. Variable names must follow the specified rules.`) + } this.scope.set(name, value) return value } diff --git a/test/unit-tests/expression/Parser.test.js b/test/unit-tests/expression/Parser.test.js index 1916ca9291..bee8932b1a 100644 --- a/test/unit-tests/expression/Parser.test.js +++ b/test/unit-tests/expression/Parser.test.js @@ -128,6 +128,24 @@ describe('parser', function () { assert.strictEqual(parser.evaluate('pi'), Math.PI) }) + it('should validate variable names', function () { + const parser = new Parser() + + // Valid variable names + assert.strictEqual(parser.set('validVar', 42), 42) + assert.strictEqual(parser.evaluate('validVar'), 42) + assert.strictEqual(parser.set('_underscoreVar', 10), 10) + assert.strictEqual(parser.evaluate('_underscoreVar'), 10) + assert.strictEqual(parser.set('var123', 100), 100) + assert.strictEqual(parser.evaluate('var123'), 100) + + // Invalid variable names + assert.throws(() => parser.set('123var', 5), /Invalid variable name/) + assert.throws(() => parser.set('var-with-hyphen', 5), /Invalid variable name/) + assert.throws(() => parser.set('var with space', 5), /Invalid variable name/) + assert.throws(() => parser.set('@specialChar', 5), /Invalid variable name/) + }) + describe('security', function () { it('should return undefined when accessing what appears to be inherited properties', function () { try {