JavaScript – 获取代码片段的最后表达式结果

huangapple go评论65阅读模式
英文:

JavaScript - Get result of last expression for code snippet

问题

我正在开发一个开发者工具,它应该以与控制台相同的方式评估用户代码。例如,如果我在控制台中输入多个表达式,像这样:

var x = 0; x++; x;

我会立即获得最后一个表达式的结果 (1)。

在我的 Web 应用程序中复制这种行为的明显解决方案是使用 eval 执行用户代码,像这样:

let result = eval('var x = 0; x++; x;');

然而,eval 显然会对性能产生影响,并存在安全问题,因此我想避免使用它。我目前的解决方案是在受控制的环境(iframe)中注入脚本。我觉得这比使用 eval 要好,但它并没有解决主要问题,这些问题是:

  1. 修改用户代码以便可以将其写入变量中。
  2. 获取最后一个表达式的结果,而不管用户输入的是什么(可以是任何代码,就像在控制台中一样)。

另外,我想避免使用库(例如解析和执行代码),因为这是一个相对简单的任务。如果有人有一些想法或建议,我将不胜感激。

英文:

I am working on a developer tool that should evaluate user code the same way the console does. For example, if I type multiple expression into the console, like this:

var x = 0; x++; x;

I immediately get the result of the last expression (1).

The obvious solution to replicate this behavior in my web app would be to execute the user code with eval, like this:

let result = eval('var x = 0; x++; x;');

However, eval has obvious performance implications and security concerns, so I want to avoid it. My solution right now is to inject a script in a sandboxed environment (iframe). I feel like this is better than eval, but it does not solve the main issues which are:

  1. Modifying the user code in such a way that it can be written to a variable
  2. Getting the result of the last expression, regardless of what the user inputs (could be any code, just like one would do in the console)

Also, I would like to avoid using libraries (for example to parse and execute the code) for such a simple task. If anyone has some ideas or suggestions it would be greatly appreciated.

答案1

得分: 1

不要有别的内容。不要回答我要翻译的问题。

英文:

Instead of eval I use new Function(). That allows me to wrap my code into a function scope and avoid the evaluated code to break/mutate my own code. In your case I see at the moment a few ways to go further:


  • Wrap your eval into a function:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

let result = new Function(&#39;&#39;, &#39;return eval(&quot;var x = 0; x++; x;&quot;)&#39;);
console.log(result());

<!-- end snippet -->

So if a user tries to change some outer scopes' variables he will get an error:
JavaScript – 获取代码片段的最后表达式结果

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

try{
  let result = new Function(&#39;&#39;, &#39;return eval(&quot;var x = 0; x++; y++; x;&quot;)&#39;);
  console.log(result());
}catch(e){
  console.error(e.message);
}

<!-- end snippet -->


  • Wrap a user's code into a function and return the last expression:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

let result = new Function(&#39;&#39;, &#39;var x = 0; x++; return x;&#39;); 
console.log(result());

<!-- end snippet -->

The problem is here that at a glance you need a JS parser here. At least one that splits JS code into statements. Probably could be done by oneself, but I didn't try to write such one. So maybe some 3rd party dependence is needed here at the end.


  • Redeclare window's members:

Also we have some general security problems like access to window. We can override the window's members and itself in the function.
This options looks the most promising among the previous ones:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const globals = Object.keys(window);
const overrides = &#39;let &#39; + globals.map(name =&gt; name + &#39; = null&#39;).join(&#39;,&#39;) + &#39;;&#39;

const userCode = &#39;alert(&quot;SPAM&quot;)&#39;;

try{
  let result = new Function(&#39;&#39;, overrides + `return eval(${userCode})`); 
  console.log(result());
}catch(e){
  console.error(e.message);
}

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年6月5日 22:21:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76407397.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定