Reputation: 11778
I would like to create a package app chrome extension to allow the user to write and execute javascript code (like a javascript console).
I would like to use the eval()
function to execute the JS code.
The classic javascript eval
function throws an error when it's called from a chrome extension:
Uncaught Error: Code generation from strings disallowed for this context
To use eval
in a chrome extension people need to use a sandbox, but when I write the sandbox in the manifest I get this error:
There were warnings when trying to install this extension: 'sandbox' is not allowed for specified package type (theme, app, etc.).
UPDATE
According to this issue, sandboxes are not supported for package apps, so I have two questions:
Is there another method which I can use instead of eval()
?
Is it possible to use eval
without a sandbox? (I think probably not for security reasons?)
Upvotes: 27
Views: 14402
Reputation: 8410
I came to this answer after an Angular.js chrome app I was starting gave the same error. The author did not mention Angular.js but if anyone else comes across this you need to add an additional directive to your web page e.g.
<html ng-app ng-csp>
...
This puts angular in CSP-safe mode https://docs.angularjs.org/api/ng/directive/ngCsp
Upvotes: 1
Reputation: 4259
I suppose you are talking about the new packaged app (manifest version 2), right?
Sandboxes can be used in the new packaged apps, absolutely. Last week I just uploaded a sample which does exactly that: A window sends a message to a hidden sandboxed iframe, the iframe compiles a handlebar template (here it could use eval instead) and returns the compiled HTML to the hosting page, which shows the result.
You can also check this other sample, which does exactly what you want.
So, to directly answer your questions:
1) No, because of CSP restrictions. The only way to evaluate dynamic JavaScript in Chrome Packaged Apps is the sandboxed iframe. If that's not an option to your app, you could also send and evaluate the JavaScript content in your server and return only the results to the user (although this breaks the offline feature of Chrome Packaged Apps)
2) No, you can only use eval() in a sandboxed iframe.
Upvotes: 6
Reputation: 115950
UPDATE:
Since at least January 2013, Chrome now permits the unsafe-eval
Content Security Policy (CSP) directive, which allows eval
execution outside of a sandbox:
The policy against
eval()
and its relatives likesetTimeout(String)
,setInterval(String)
, andnew Function(String)
can be relaxed by adding'unsafe-eval'
to your policy
Add an appropriate CSP to you extension manifest, like:
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
The bug you refer to is now marked fixed
, and has been included since Chrome 22.
Prior to the introduction of 'unsafe-eval'
, there was no way to have the CSP of a manifest_version: 2
extension allow execution of arbitrary text as code. At the time, Google made it clear there was no way to remove this restriction (outside of sandboxing):
Inline JavaScript, as well as dangerous string-to-JavaScript methods like
eval
, will not be executed... There is no mechanism for relaxing the restriction against executing inline JavaScript. In particular, setting a script policy that includesunsafe-inline
will have no effect. This is intentional.
As mentioned above, this restriction can now be relaxed.
Upvotes: 32
Reputation: 94101
Here is an example of what will NOT work, as all strings with code will be rejected in Chrome packaged apps:
//To run some code from a string without `eval` just do this:
var code = new Function(yourCodeString);
code();
Upvotes: -1
Reputation: 2324
You could try...
function evalMe(code){
var script = document.createElement('script');
script.innerText = code;
document.querySelector('head').appendChild(script);
}
This should create the same effect, unless they have disabled it as well, but from my knowledge this is fine. Of course if the script errors
you will not hear about it unless you do some wrapping of the string
to eval
e.g.
function myHandler(err){
// handle errors.
}
function evalMe(code){
var script = document.createElement('script');
var wrapper = '(function(){ try{ @@ }catch(err){ myHandler(err); } })()';
// Make sure the string has an ending semicolon
code = code[code.length-1] === ';' ? code : code + ';';
script.innerText = wrapper.replace('@@', code);
document.querySelector('head').appendChild(script);
}
Alternately you could use the official mechanism
http://developer.chrome.com/beta/extensions/tabs.html#method-executeScript
However this would require you to have a background page and employ message passing between your app
page and the background page.
UPDATE: Working Method
You can create an eval
like method using an iframe and a base64
encoded dataURI
that handles message passing between the extension page and the <iframe>
. You can grab a working copy of the code on github. To use simply clone or download the repo, and install the 'client' dir
as an unpackaged extension in the chrome extension manager. The code driving the plugin resides in app.js
Use the iframeEval to test, the error notification is a little buggy but hey, the eval
works.
@appsillers In order to get your plugin working without any additional code, you could overwrite the eval
method on you extensions window
with the iframeEval
method in the code.
Upvotes: 1