Google Chrome extensions using manifest_version: 2 are restricted from using eval or new Function. All of the JavaScript templating libraries I checked (mustachejs, underscorejs, jQuery template, hoganjs, etc) use new Function. Are there any that are fairly mature and supported that don't use either?
Info about the security restrictions.
It turns out that mustachejs added new Function recently and using tag 0.4.2 doesn't have it. It the API is slightly different with Mustache.to_html instead of Mustache.render and there are likely some performance reduction.
I opened an issue to potentially get new Function removed in a future release.
It doesn't appear that Pure uses either eval or new Function.
The answers here are outdated so I post an update.
Since September, Google changed their policy and allowed unsafe-eval in manifest 2 extensions. See this thread and this page.
So libraries using eval(), new Function() etc. can be used if unsafe-eval is turned on for your extensions.
Closure Templates is a templating library that does not use eval. Templates are compiled to JavaScript ahead of time, so that what gets included in your app is a plain .js file that should not run into CSP issues.
Distal template doesn't use eval.
It really depends on what you mean by "template library". If you just want string interpolation, there's no need for eval or new Function, when you start needing embedded looping structures, things get more complicated.
A few months ago I wrote a String.prototype.tmpl.js script that I've used a couple times here and there in places where I don't mind overriding String.prototype. As a static function, you can use:
tmpl.js:
function tmpl(tmpl, o) {
return tmpl.replace(/<%=(?:"([^"]*)"|(.*?))%>/g, function (item, qparam, param) {
return o[qparam] || o[param];
});
}
An example template:
<div id="bar"></div>
<script type="text/x-tmpl" id="foo">
<h1><%=title%></h1>
<p><%=body%></p>
</script>
<script>
(function () {
var foo,
bar;
foo = document.getElementById('foo');
bar = document.getElementById('bar');
bar.innerHTML = tmpl(foo.innerHTML, {
title: 'foo bar baz',
body: 'lorem ipsum dolor sit amet'
});
}());
</script>
The base tmpl script can of course be modified to take advantage of document fragments to actually build out DOM elements, but as-is I'm not sure whether it counts as a "template library".
The best solution to this problem is to pre-compile your templates before you deploy your extension. Both handlebarsjs and eco offer pre-compilation as a feature. I actually wrote a blog post that goes into more depth.
Maybe you can write a function eval1:
function eval1(blah) {
var s = document.createElement("script");
s.src = blah;
document.head.appendChild(s);
document.head.removeChild(s);
}
and do a find/replace in the library you want, but that'd be cheating, right?
I recently run into the same problem. After updating manifest version my extension stopped working. I tried Mustache but it unable to render index of the array and names of the object properties. So I had to create my own simple but effective templating library Ashe which is free of eval and new Function. Hope it will help someone.
https://developer.chrome.com/extensions/sandboxingEval
Not sure when it was added, but you can do Firefox style sandboxing in Chrome now. I'm porting my Firefox extension, so I need this (since I don't have evalInSandbox :P)
Related
I am writing an extension to override a web page's JS function, and started from this question, but the answer does not appear to work in Firefox 42 on Linux.
Next, I tried to use exportFunction as described in the documentation, but that also silently failed.
Inside package.json, I have added the following sesction.
"permissions": {
"unsafe-content-script": true
}
Here is my index.js file.
var self = require('sdk/self');
require("sdk/tabs").on("ready", fixGoogle);
function fixGoogle(tab) {
if (tab.url.indexOf("google.com") > -1) {
tab.attach({
contentScriptFile: self.data.url("google-script.js")
});
}
}
Here is my current data/google-script.js.
unsafeWindow.rwt=function(){};
Note that manually typing in rwt=function(){}; to the browser's console achieves the desired effect, as does using a bookmarklet (which requires clicking) but I am writing the plugin to get this automatically every time I use Google.
Is it possible to override the rwt page function using a Firefox extension? If so, what is the correct API to use?
read the documentation you've linked to, specifically the chapter titled Expose functions to page scripts - which links to exportFunction
function blah() {}
exportFunction(blah, unsafeWindow, {defineAs: 'rwt'});
It turns out that the issue is that the redefinition of the function rwt is racing against the original definition and winning. The original runs after and overrides the function I defined, thereby making it look like my redefinition had silently failed.
Once I realized that this was the problem, the easiest hack around it was to add a timeout to the redefinition inside data/google-script.js.
setTimeout(function() {
unsafeWindow.rwt=function(){};
}, 1000);
Thus, the orignal answer is still correct but simply failed to address the race condition.
Even though content scripts share the DOM, they are otherwise isolated from page scripts. As you correctly surmised, one can use unsafeWindow in Firefox to bypass this isolation.
Personally, I don't like the name of unsafeWindow for some reason ;)
Therefore I propose another way to do this: make use of the thing that's shared between these scopes, i. e. DOM.
You can create a page script from a content script:
var script = 'rwt=function()();';
document.addEventListener('DOMContentLoaded', function() {
var scriptEl = document.createElement('script');
scriptEl.textContent = script;
document.head.appendChild(scriptEl);
});
The benefit of this approach is that you can use it in environments without unsafeWindow, e. g. chrome extensions.
I have created a couple of scripted dashboards for Grafana. I'm about to create another. There are all kinds of utility functions that I created and copied from script to script. I would much rather employ good programming practice and import the code rather than copy-paste.
Can that be done? If so, how would one do it?
Yes, this can be done.
This link suggests that SystemJS.import() can be used, although I have not tried it.
This github repo provides a detailed example using a different technique.
Although its not mentioned in the slim Grafana scripted dashboard doc, some version of lodash.com (commit to include lodash) and jquery seem to be available to all scripted dashboards.
The owner of this repo, anryko, has figured out how to use these two libraries to reference your own utility scripts like you're talking about.
All scripted dashboards have a main script; getdash.sh is anryko's main script, as seen by the dash URL on the README.md:
http://grafanaIP/dashboard/script/getdash.js
If you look at the end of getdash.sh, you'll see this line that references code in other user(you)-provided scripts:
var dash = getDashApp(datasources, getDashConf());
For example:
the code for getDashConf() is in this separate .js file
the code for getDashApp() is in this other separate .js file.
Here is the part where getdash.js uses jquery and lodash to load the source files:
// loadScripts :: [scriptSourceStr] -> Promise([jQuery.getScript Result])
var loadScripts = function loadScripts (scriptSrcs) {
var gettingScripts = _.map(scriptSrcs, function (src) {
return $.getScript(src);
});
return Promise.all(gettingScripts);
};
Here is the lodash doc for the above _.map.
The function scriptedDashboard() (also in getdash.js) calls the above loadScripts(), passing it the paths to the source files like this:
loadScripts([
'public/app/getdash/getdash.app.js',
'public/app/getdash/getdash.conf.js'
]).then(function () {
To be honest, I haven't yet looked further under the covers to see how all this makes the utility code 'reference-able.'
I would like to execute javascript in pages which I load via Ext.Ajax.request. To do this, I have to load the scripts and eval() them like this:
Ext.Ajax.request({
url: 'content/view_application.php',
success: function(objServerResponse) {
var responseText = objServerResponse.responseText;
regionContent.update(responseText);
var scripts, scriptsFinder=/<script[^>]*>([\s\S]+)<\/script>/gi;
while(scripts=scriptsFinder.exec(responseText)) {
eval(scripts[1]);
}
}
});
With JQuery, however, I can have Javascript executed in pages which are called via AJAX without resorting to eval() like this:
function replaceContentOnClick(id, pageToLoad) {
$('body').delegate(('#' + id), 'click', function(){
$.get('content/' + pageToLoad, function(data) {
$('#regionContent .x-panel-body').html(data);
});
});
}
How is it that JQuery manages to execute the javascript in the loaded page without eval()? Is there a way to load the javascript without resorting to eval() in ExtJS as well?
Personally, I wouldn't worry about the eval statement. I am aware that Douglas Crockford counsels against its use:
eval is evil
The eval function (and its relatives,
Function, setTimeout, and setInterval)
provide access to the JavaScript
compiler. This is sometimes necessary,
but in most cases it indicates the
presence of extremely bad coding. The
eval function is the most misused
feature of JavaScript.
(from http://www.jslint.com/lint.html)
Here he states that "This is sometimes necessary", and I would argue that your use is a valid one.
The JSON2.js library (http://www.json.org) uses this command, and flags to JSLint that this is intended:
/*jslint evil: true */
Is there a particular reason that you would like to avoid its use?
Well, go to the jQuery source (http://code.jquery.com/jquery-latest.js) and Ctrl+F for globalEval: function. This is the function which runs JavaScript. You'll see it actually adds script tags into the DOM. As for extJS, I don't know. Try searching in their source code for "script" or 'script' to see if they insert script tags anywhere in a similar way. Or you could just implement your own globalEval.
At the risk of sounding like a broken record, please see my other answer regarding the loadScripts config. You should consider sticking to the same question when it's just a follow-up to what you've already asked, rather than starting brand new questions.
i've been playing with MVC for a while now, but since the project i'm on is starting to get wind in its sails more and more people are added to it. Since i'm in charge of hacking around to find out some "best practice", i'm especially wary about the possible misuses of javascript and would like to find out what would be the best way to have our views and partial views play nicely with javascript.
For the moment, we're having code that looks like this (only simplified for example's sake)
<script type="text/javascript">
function DisableInputsForSubmit() {
if ($('#IsDisabled').is(':checked')) {
$('#Parameters :input').attr('disabled', true);
} else {
$('#Parameters :input').removeAttr('disabled');
}
}
</script>
<%=Html.SubmitButton("submit", Html.ResourceText("submit"), New With {.class = "button", .onclick = "DisableInputsForSubmit(); if ($('#EditParameters').validate().form()) {SetContentArea(GetHtmlDisplay('SaveParameters', 'Area', 'Controller'), $('#Parameters').serialize());} return false;"})%><%=Html.ResourceIcon("Save")%>
Here, we're saving a form and posting it to the server, but we disable inputs we don't want to validate if a checkbox is checked.
a bit of context
Please ignore the Html.Resource* bits, it's the resource management
helpers
The SetContentArea method wraps ajax calls, and GetHtmlDisplay
resolves url regarding an area,
controller and action
We've got combres installed that takes care of compressing, minifying
and serving third-parties libraries and what i've clearly identified as reusable javascript
My problem is that if somebody else defines a function DisableInputsForSubmit at another level (let's say the master page, or in another javascript file), problems may arise.
Lots of videos on the web (Resig on the design of jQuery, or Douglas Crockford for his talk at Google about the good parts of javascript) talk about using the namespaces in your libraries/frameworks.
So far so good, but in this case, it looks a bit overkill. What is the recommended way to go? Should i:
Create a whole framework inside a namespace, and reference it globally in the application? Looks like a lot of work for something so tiny as this method
Create a skeleton framework, and use local javascript in my views/partials, eventually promoting parts of the inline javascript to framework status, depending on the usage we have? In this case, how can i cleanly isolate the inline javascript from other views/partials?
Don't worry and rely on UI testing to catch the problem if it ever happens?
As a matter of fact, i think that even the JS code i've written that is in a separate file will benefit from your answers :)
As a matter of safety/best practice, you should always use the module pattern. If you also use event handlers rather than shoving javascript into the onclick attribute, you don't have to worry about naming conflicts and your js is easier to read:
<script type="text/javascript">
(function() {
// your button selector may be different
$("input[type='submit'].button").click(function(ev) {
DisableInputsForSubmit();
if ($('#EditParameters').validate().form()) {
SetContentArea(GetHtmlDisplay('SaveParameters', 'Area','Controller'), $('#Parameters').serialize());
}
ev.preventDefault();
});
function DisableInputsForSubmit() {
if ($('#IsDisabled').is(':checked')) {
$('#Parameters :input').attr('disabled', true);
} else {
$('#Parameters :input').removeAttr('disabled');
}
}
})();
</script>
This is trivially easy to extract into an external file if you decide to.
Edit in response to comment:
To make a function re-usable, I would just use a namespace, yes. Something like this:
(function() {
MyNS = MyNS || {};
MyNS.DisableInputsForSubmit = function() {
//yada yada
}
})();
Suppose we need to embed a widget in third party page. This widget might use jquery for instance so widget carries a jquery library with itself.
Suppose third party page also uses jquery but a different version.
How to prevent clash between them when embedding widgets? jquery.noConflict is not an option because it's required to call this method for the first jquery library which is loaded in the page and this means that third party website should call it. The idea is that third party site should not amend or do anything aside putting tag with a src to the widget in order to use it.
Also this is not the problem with jquery in particular - google closure library (even compiled) might be taken as an example.
What solutions are exist to isolate different javascript libraries aside from obvious iframe?
Maybe loading javascript as string and then eval (by using Function('code to eval'), not the eval('code to eval')) it in anonymous function might do the trick?
Actually, I think jQuery.noConflict is precisely what you want to use. If I understand its implementation correctly, your code should look like this:
(function () {
var my$;
// your copy of the minified jQuery source
my$ = jQuery.noConflict(true);
// your widget code, which should use my$ instead of $
}());
The call to noConflict will restore the global jQuery and $ objects to their former values.
Function(...) makes an eval inside your function, it isn't any better.
Why not use the iframe they provide a default sandboxing for third party content.
And for friendly ones you can share text data, between them and your page, using parent.postMessage for modern browser or the window.name hack for the olders.
I built a library to solve this very problem. I am not sure if it will help you of course, because the code still has to be aware of the problem and use the library in the first place, so it will help only if you are able to change your code to use the library.
The library in question is called Packages JS and can be downloaded and used for free as it is Open Source under a Creative Commons license.
It basically works by packaging code inside functions. From those functions you export those objects you want to expose to other packages. In the consumer packages you import these objects into your local namespace. It doesn't matter if someone else or indeed even you yourself use the same name multiple times because you can resolve the ambiguity.
Here is an example:
(file example/greeting.js)
Package("example.greeting", function() {
// Create a function hello...
function hello() {
return "Hello world!";
};
// ...then export it for use by other packages
Export(hello);
// You need to supply a name for anonymous functions...
Export("goodbye", function() {
return "Goodbye cruel world!";
});
});
(file example/ambiguity.js)
Package("example.ambiguity", function() {
// functions hello and goodbye are also in example.greeting, making it ambiguous which
// one is intended when using the unqualified name.
function hello() {
return "Hello ambiguity!";
};
function goodbye() {
return "Goodbye ambiguity!";
};
// export for use by other packages
Export(hello);
Export(goodbye);
});
(file example/ambiguitytest.js)
Package("example.ambiguitytest", ["example.ambiguity", "example.greeting"], function(hello, log) {
// Which hello did we get? The one from example.ambiguity or from example.greeting?
log().info(hello());
// We will get the first one found, so the one from example.ambiguity in this case.
// Use fully qualified names to resolve any ambiguities.
var goodbye1 = Import("example.greeting.goodbye");
var goodbye2 = Import("example.ambiguity.goodbye");
log().info(goodbye1());
log().info(goodbye2());
});
example/ambiguitytest.js uses two libraries that both export a function goodbye, but it can explicitly import the correct ones and assign them to local aliases to disambiguate between them.
To use jQuery in this way would mean 'packaging' jQuery by wrapping it's code in a call to Package and Exporting the objects that it now exposes to the global scope. It means changing the library a bit which may not be what you want but alas there is no way around that that I can see without resorting to iframes.
I am planning on including 'packaged' versions of popular libraries along in the download and jQuery is definitely on the list, but at the moment I only have a packaged version of Sizzle, jQuery's selector engine.
Instead of looking for methods like no conflict, you can very well call full URL of the Google API on jQuery so that it can work in the application.
<script src="myjquery.min.js"></script>
<script>window.myjQuery = window.jQuery.noConflict();</script>
...
<script src='...'></script> //another widget using an old versioned jquery
<script>
(function($){
//...
//now you can access your own jquery here, without conflict
})(window.myjQuery);
delete window.myjQuery;
</script>
Most important points:
call jQuery.noConflict() method IMMEDIATELY AFTER your own jquery and related plugins tags
store the result jquery to a global variable, with a name that has little chance to conflict or confuse
load your widget using the old versioned jquery;
followed up is your logic codes. using a closure to obtain a private $ for convience. The private $ will not conflict with other jquerys.
You'd better not forget to delete the global temp var.