--- a/proposals/request-feature/Overview.html Thu May 26 17:06:37 2011 +0200
+++ b/proposals/request-feature/Overview.html Thu May 26 18:14:35 2011 +0200
@@ -38,28 +38,6 @@
backing implied or otherwise from any other party.
</p>
</section>
- <!--
- - this is for XSS mitigation
- - can bring in capabilities listing
- - maybe use CommonJS exporting
-
- BASIC
- - just a container, like a CommonJS transport
-
- var contained = new Container("wicked-cool-app.js");
-
- CAPABLE
- - add support for pre-declaration of capabilities similar to Feature Permissions
-
- var contained = new Container("even-cooler.js", { geolocation: true,
- contacts: true,
- fileStorage: { quota: "5Mo" }
- });
-
- COMMUNICATING
- - like a CommonJS module (at least have exports)
-
- -->
<section>
<h2>Introduction</h2>
<p>
@@ -136,7 +114,101 @@
<section>
<h2>Example: FRAC</h2>
<p>
-
+ We will now show how to implement the very same functionality using FRAC. You can
+ <a href='frac-unicorner/index.html'>try the example</a> but it will only work in a FRAC-enabled browser and
+ as of this writing those are few and far apart. We can look at the code however to see how it has been modified.
+ </p>
+ <p>
+ The first thing to note is that the changes required to the entire code are extremely minimal:
+ </p>
+ <pre class='example'>
+ diff -wU 1 xss-pwnd/index.html frac-unicorner/index.html
+ --- xss-pwnd/index.html 2011-05-26 16:58:10.000000000 +0200
+ +++ frac-unicorner/index.html 2011-05-26 17:26:50.000000000 +0200
+ @@ -18,6 +18,5 @@
+ <script src='http://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js'></script>
+ <span style='color:red'>- <script src='unicorner.js'></script></span>
+ <script>
+ <span style='color:red'>- jQuery(function () { </span>
+ <span style='color:red'>- UI.loadEverything();</span>
+ <span style='color:green'>+ requestFeatures(["geolocation", "indexeddb"], ["unicorner.js"], function (unicorner) {</span>
+ <span style='color:green'>+ unicorner.UI.loadEverything(jQuery);</span>
+ });
+ diff -wU 1 xss-pwnd/unicorner.js frac-unicorner/unicorner.js
+ --- xss-pwnd/unicorner.js 2011-05-26 17:12:03.000000000 +0200
+ +++ frac-unicorner/unicorner.js 2011-05-26 17:27:16.000000000 +0200
+ @@ -1,6 +1,6 @@
+ <span style='color:red'>-(function (exports, $) {</span>
+ <span style='color:red'>- var curLocation = null, db, store;</span>
+ <span style='color:green'>+var curLocation = null, db, store, $;</span>
+
+ exports.UI = {
+ <span style='color:red'>- loadEverything: function () {</span>
+ <span style='color:green'>+ loadEverything: function (jq) {</span>
+ <span style='color:green'>+ $ = jq;</span>
+ Messaging.watchLocation();
+ @@ -55,2 +55 @@
+ };
+ <span style='color:red'>-})(window, jQuery);</span>
+ </pre>
+ <p>
+ We have simply: 1) removed the direct loading of the application script, 2) replaced the jQuery <code>onload</code>
+ handler with a call to <code>requestFeatures</code>, and 3) unwrapped the script from its self-calling
+ anonymous function since we don't need that protection anymore.
+ </p>
+ <p>
+ Loading the script is performed with the following code:
+ </p>
+ <pre class='example highlight'>
+ requestFeatures(["geolocation", "indexeddb"], ["unicorner.js"], function (unicorner) {
+ unicorner.UI.loadEverything(jQuery);
+ });
+ </pre>
+ <p>
+ This simple call takes three parameters. The first is a list of capabilities required for the application
+ to execute (in this case geolocation and access to the IndexedDB local storage). By bundling these in a
+ single array the user agent is able to display a user interface that requests permission for all the
+ capabilities at once, thereby making the user experience more fluid (An example of a potential user
+ interface for such an approach can be seen in the
+ <a href='http://dev.w3.org/2009/dap/docs/feat-perms/feat-perms.html'>Feature Permissions Playground</a>.).
+ </p>
+ <p>
+ Second is a list of the scripts that we wish to load and provide with these capabilities (in this case
+ there is only one, <code>unicorner.js</code>). Those are regular Javascript pieces of code, except that
+ instead of sharing the same execution scope as the main one, they are encapsulated in a manner similar
+ to that of CommonJS [[!COMMONJS]]. They have access to the same host objects that are exposed in the main
+ scope (<code>navigator</code>, <code>document</code>, etc.) but global variables defined there in Javascript
+ are invisible to them. Conversely, their own globals are not available to the main scope. The way in which
+ such scripts expose their functionality is by assigning to an <code>exports</code> variable. Users of
+ CommonJS will be familiar with the approach.
+ </p>
+ <p>
+ Finally is a callback, which is called when the capabilities are accepted and the scripts have loaded.
+ It gets called with a list of objects, each of which corresponds to the <code>exports</code>
+ variable for each script. Therefore, the following code in <code>unicorner.js</code>:
+ </p>
+ <pre class='example highlight'>
+ exports.UI = {
+ loadEverything: function (jq) {
+ // ...
+ }
+ };
+ </pre>
+ <p>
+ makes it possible to call <code class='highlight'>unicorner.UI.loadEverything(jq)</code> in the previous
+ example.
+ </p>
+ <p>
+ You will note that the XSS vulnerability is still present. However, calling <code>requestFeatures</code>
+ tells the user agent that the author has decided to use elevated privileges only in code loaded
+ through <code>requestFeatures</code> and therefore the injected code's attempt to use Geolocation
+ will fail. Code could be injected that calls <code>requestFeatures</code> directly, but it is strictly
+ limited to loading from the same origin, which also precludes this attack.
+ </p>
+ <p>
+ In conclusion, with the addition of a simple API and a subset of the familiar CommonJS modules, we have
+ both improved the user experience for web applications accessing multiple capabilities, and provided
+ additional protection against XSS attacks.
</p>
</section>
</section>
--- a/proposals/request-feature/frac-unicorner/index.html Thu May 26 17:06:37 2011 +0200
+++ b/proposals/request-feature/frac-unicorner/index.html Thu May 26 18:14:35 2011 +0200
@@ -18,7 +18,7 @@
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js'></script>
<script>
requestFeatures(["geolocation", "indexeddb"], ["unicorner.js"], function (unicorner) {
- unicorner.UI.loadEverything();
+ unicorner.UI.loadEverything(jQuery);
});
</script>
</html>
--- a/proposals/request-feature/frac-unicorner/unicorner.js Thu May 26 17:06:37 2011 +0200
+++ b/proposals/request-feature/frac-unicorner/unicorner.js Thu May 26 18:14:35 2011 +0200
@@ -1,7 +1,8 @@
-var curLocation = null, db, store;
+var curLocation = null, db, store, $;
exports.UI = {
- loadEverything: function () {
+ loadEverything: function (jq) {
+ $ = jq;
Messaging.watchLocation();
var idxdb = window.IndexedDB || window.mozIndexedDB || window.webkitIndexedDB,
dbReq = idxdb.open("Unicorner");
--- a/proposals/request-feature/xss-pwnd/unicorner.js Thu May 26 17:06:37 2011 +0200
+++ b/proposals/request-feature/xss-pwnd/unicorner.js Thu May 26 18:14:35 2011 +0200
@@ -1,4 +1,3 @@
-
(function (exports, $) {
var curLocation = null, db, store;