intro done
authorRobin Berjon <robin@berjon.com>
Thu, 26 May 2011 18:14:35 +0200
changeset 18 997b3750dcd1
parent 17 d86e235b145f
child 19 ce0453cecb74
intro done
proposals/request-feature/Overview.html
proposals/request-feature/frac-unicorner/index.html
proposals/request-feature/frac-unicorner/unicorner.js
proposals/request-feature/xss-pwnd/unicorner.js
--- 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 @@
+             &lt;script src='http://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js'>&lt;/script>
+          <span style='color:red'>-  &lt;script src='unicorner.js'>&lt;/script></span>
+             &lt;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;