[or-cvs] [torbutton/master] Added more UI elements on Cookie Protector and functionality to almost all the elements (except for the default cookie protection radio and filtering the protected/deleted cookies on toggle).

mikeperry at seul.org mikeperry at seul.org
Wed Sep 23 23:49:11 UTC 2009


Author: Kory Kork <kory at korykirk.com>
Date: Sat, 15 Aug 2009 20:28:00 +0000
Subject: Added more UI elements on Cookie Protector and functionality to almost all the elements (except for the default cookie protection radio and filtering the protected/deleted cookies on toggle).
Commit: e71edaf86631a23f872a45fe8d201fe30b549975

svn:r20316
---
 src/chrome/content/popup.xul           |    4 +-
 src/chrome/content/torcookie.js        |  342 +++++++++++++++++++++++++++++++-
 src/chrome/content/torcookiedialog.xul |   33 +++-
 src/components/cookie-jar-selector.js  |   92 ++++++++-
 4 files changed, 452 insertions(+), 19 deletions(-)

diff --git a/src/chrome/content/popup.xul b/src/chrome/content/popup.xul
index 7691cf5..db576ca 100644
--- a/src/chrome/content/popup.xul
+++ b/src/chrome/content/popup.xul
@@ -23,10 +23,10 @@
                   insertafter="context-stop"
                   oncommand="torbutton_open_prefs_dialog()"/>
         <menuitem  id="torbutton-cookies" 
-                  label="Cookie Manager"
+                  label="Cookie Protections"
                   accesskey="C"
                   insertafter="context-stop"
-                  oncommand="window.openDialog('chrome://torbutton/content/torcookiedialog.xul','Cookie Manager',
+                  oncommand="window.openDialog('chrome://torbutton/content/torcookiedialog.xul','Cookie Protections',
                                    'centerscreen,chrome,dialog,modal,resizable')"/>
         <menuitem id="torbutton-about"
                   label="&torbutton.context_menu.about;"
diff --git a/src/chrome/content/torcookie.js b/src/chrome/content/torcookie.js
index b9e286a..5bdef57 100644
--- a/src/chrome/content/torcookie.js
+++ b/src/chrome/content/torcookie.js
@@ -1,7 +1,12 @@
 var cookiesTree = null;
 var prefs = null;
 var cookies = [];
-var protectedcookies = [];
+var protectedCookies = [];
+var deletedCookies       = [];
+var lastCookieSortColumn = "";
+var lastCookieSortAscending = false;
+var cookiemanager = null;
+var selector = null;
 //custom tree view, this is how we dynamically add the cookies
 var cookiesTreeView = {
   rowCount : 0,
@@ -14,7 +19,8 @@ var cookiesTreeView = {
     switch (column.id) {
       case "domainCol" : rv = cookies[row].rawHost; break;
       case "nameCol"   : rv = cookies[row].name; break;
-      case "lockCol"   : rv = cookies[row].isProtected;
+      case "lockCol"   : rv = cookies[row].isProtected; break;
+      case "pathCol"   : rv = cookies[row].path; break;
     }
     return rv;
   },
@@ -27,16 +33,18 @@ var cookiesTreeView = {
   getCellProperties : function(row,column,prop) {}
  };
  
-function Cookie(number,name,value,isDomain,host,rawHost,path,isSecure,expires,
-                isProtected) {
+function Cookie(number,name,value,isDomain,host,rawHost,HttpOnly,path,isSecure,isSession,
+                expires,isProtected) {
   this.number = number;
   this.name = name;
   this.value = value;
   this.isDomain = isDomain;
   this.host = host;
   this.rawHost = rawHost;
+  this.isHttpOnly = HttpOnly;
   this.path = path;
   this.isSecure = isSecure;
+  this.isSession = isSession;
   this.expires = expires;
   this.isProtected = isProtected;
 }
@@ -45,12 +53,16 @@ function initDialog() {
   cookiesTree = document.getElementById("cookiesTree");
   prefs =Components.classes["@mozilla.org/preferences-service;1"]
         .getService(Components.interfaces.nsIPrefBranch);
+  selector = Components.classes["@stanford.edu/cookie-jar-selector;1"]
+                    .getService(Components.interfaces.nsISupports)
+                    .wrappedJSObject;
   var tor_enabled = prefs.getBoolPref("extensions.torbutton.tor_enabled");
   //init cookie manager
-  var cookiemanager = Components.classes["@mozilla.org/cookiemanager;1"].getService();
+  cookiemanager = Components.classes["@mozilla.org/cookiemanager;1"].getService();
     cookiemanager = cookiemanager.QueryInterface(Components.interfaces.nsICookieManager);
   var enumerator = cookiemanager.enumerator;
   var count = 0;
+  getProtectedCookies();
   while (enumerator.hasMoreElements()) {
     var nextCookie = enumerator.getNext();
     if (!nextCookie) break;
@@ -60,8 +72,8 @@ function initDialog() {
     //populate list
     cookies[count] =
       new Cookie(count++, nextCookie.name, nextCookie.value, nextCookie.isDomain, host,
-                   (host.charAt(0)==".") ? host.substring(1,host.length) : host,
-                   nextCookie.path, nextCookie.isSecure, nextCookie.expires,
+                   (host.charAt(0)==".") ? host.substring(1,host.length) : host, nextCookie.isHttpOnly,
+                   nextCookie.path, nextCookie.isSecure, nextCookie.isSession, nextCookie.expires,
                    isProt);
   }
   //apply custom view
@@ -71,12 +83,324 @@ function initDialog() {
   //grab data from xml files
   //add protected tag
 }
+function protectCookie()
+{
+  ProtectInTree(cookiesTree, cookiesTreeView,
+                        cookies, "protectCookie", "unprotectCookie", "removeCookie");
+}
+function unprotectCookie() {
+  UnProtectInTree(cookiesTree, cookiesTreeView,
+                        cookies, "protectCookie", "unprotectCookie", "removeCookie");
+}
 function checkIfProtected(name, host, path)
 {
-  
+  for (var i = 0; i < protectedCookies.length; i++)
+  {
+    var cookie = protectedCookies[i];
+    if (cookie.name == name && cookie.host == host && cookie.path == path)
+      return true;
+  }
   return false;
 }
 function itemSelected() {
-  var item = document.getElementById("cookiesTree").selectedItemIndex;
+  var selections = getTreeSelections(cookiesTree);
+  if (selections.length) {
+
+//DY - check if (the last in list) selection is protected/unprotected, set buttons
+    if (cookies[selections[(selections.length)-1]].isProtected) {
+        document.getElementById("removeCookie").disabled = true;
+        document.getElementById("unprotectCookie").disabled = false;
+        document.getElementById("protectCookie").disabled = true;
+    } else {
+        document.getElementById("removeCookie").disabled = false;
+        document.getElementById("unprotectCookie").disabled = true;
+        document.getElementById("protectCookie").disabled = false;
+    }
+
+  }
+}
+function acceptDialog() {
+  
+  FinalizeCookieDeletions();
+  var protectedcount = 0;
+  var protcookies = [];
+  for (var i = 0; i < cookies.length; i++)
+  {
+    if (cookies[i].isProtected)
+    {
+      protcookies[protectedcount] = cookies[i];
+      protectedcount++;
+    }
+  }
+  selector.protectCookies(protcookies);
+  //output protected cookies
+}
+function CookieColumnSort(column) {
+  lastCookieSortAscending =
+    SortTree(cookiesTree, cookiesTreeView, cookies,
+                 column, lastCookieSortColumn, lastCookieSortAscending);
+  lastCookieSortColumn = column;
+}
+function DeleteCookie() {
+//DY - check if any selection is protected
+  var selections = getTreeSelections(cookiesTree);
+  var protect = false;
+  var i;
+  for (i=0; i<selections.length; i++) {
+    if (cookies[selections[i]].isProtected) {
+      protect = true;
+    }
+  }
+  if (!protect && i>0 ) {
+    DeleteSelectedItemFromTree(cookiesTree, cookiesTreeView,
+                               cookies, deletedCookies,
+                               "removeCookie", "removeAllCookies",
+                               "protectCookie", "unprotectCookie");
+    if (!cookies.length) {
+      ;//ClearCookieProperties();
+    }
+
+  }
+}
+
+function getProtectedCookies()
+{
+  var tor_enabled = prefs.getBoolPref("extensions.torbutton.tor_enabled");                
+  var cookiesAsXml = selector.getProtectedCookies(tor_enabled? "tor" : "nontor");
+  
+  for (var i = 0; i < cookiesAsXml.cookie.length(); i++) {
+            var xml = cookiesAsXml.cookie[i];
+            var value = xml.toString();
+            var cname = xml. at name; 
+            var host = xml. at host;
+            var path = xml. at path;
+            var expiry = xml. at expiry;
+            var isSecure = (xml. at isSecure == 1);
+            var isSession = (xml. at isSession == 1);
+            var isHttpOnly = (xml. at isHttpOnly == 1);
+            //this.logger.log(2, "Loading cookie: "+host+":"+cname+" until: "+expiry);
+            protectedCookies[i] = new Cookie(i,cname,value,true,host,(host.charAt(0)=="."),isHttpOnly, path, isSecure, isSession,
+                expiry, true)
+        }                  
+}
+
+//Tree Utils
+
+function SortTree(tree, view, table, column, lastSortColumn, lastSortAscending, updateSelection) {
+
+  // remember which item was selected so we can restore it after the sort
+  var selections = getTreeSelections(tree);
+  var selectedNumber = selections.length ? table[selections[0]].number : -1;
+
+  // determine if sort is to be ascending or descending
+  var ascending = (column == lastSortColumn) ? !lastSortAscending : true;
+
+  // do the sort or re-sort
+  var compareFunc = function compare(first, second) {
+    if (column=="isProtected") {
+       return second[column].toString().localeCompare(first[column].toString());
+    } else {
+       return first[column].toLowerCase().localeCompare(second[column].toLowerCase());
+    }
+  }
+  table.sort(compareFunc);
+  if (!ascending)
+    table.reverse();
+
+  // restore the selection
+  var selectedRow = -1;
+  if (selectedNumber>=0 && updateSelection) {
+    for (var s=0; s<table.length; s++) {
+      if (table[s].number == selectedNumber) {
+        // update selection
+        // note: we need to deselect before reselecting in order to trigger ...Selected()
+        if (oldTreeCode) {
+        	tree.treeBoxObject.view.selection.select(-1);
+        	tree.treeBoxObject.view.selection.select(s);
+        } else {
+        	tree.view.selection.select(-1);
+        	tree.view.selection.select(s);
+        }
+        selectedRow = s;
+        break;
+      }
+    }
+  }
+
+  // display the results
+  tree.treeBoxObject.invalidate();
+  if (selectedRow >= 0) {
+    tree.treeBoxObject.ensureRowIsVisible(selectedRow)
+  }
+
+  return ascending;
+}
+function FinalizeCookieDeletions() {
+  for (var c=0; c<deletedCookies.length; c++) {
+    cookiemanager.remove(deletedCookies[c].host,
+                         deletedCookies[c].name,
+                         deletedCookies[c].path,
+                         false);
+  }
+  deletedCookies.length = 0;
+}
+function getTreeSelections(tree) {
+  var selections = [];
+  var select;
+  
+  select = tree.view.selection;
+  if (select) {
+    var count = select.getRangeCount();
+    var min = new Object();
+    var max = new Object();
+    for (var i=0; i<count; i++) {
+      select.getRangeAt(i, min, max);
+      for (var k=min.value; k<=max.value; k++) {
+        if (k != -1) {
+          selections[selections.length] = k;
+        }
+      }
+    }
+  }
+  return selections;
+}
+function ProtectInTree
+    (tree, view, table, protButton, unprotButton, removeButton) {
+
+  var selections = getTreeSelections(tree);
+  for (var s=selections.length-1; s>= 0; s--) {
+    var i = selections[s];
+    table[i].isProtected = true;
+  }
+
+  //update tree view
+  tree.treeBoxObject.invalidate();
+//DY - Update selections
+  tree.treeBoxObject.ensureRowIsVisible(selections[0]);
+  // disable/enable buttons
+  document.getElementById(unprotButton).disabled = false;
+  document.getElementById(protButton).disabled = true;
+  document.getElementById(removeButton).disabled = true;
+}
+function UnProtectInTree
+    (tree, view, table, protButton, unprotButton, removeButton) {
+
+  var selections = getTreeSelections(tree);
+  for (var s=selections.length-1; s>= 0; s--) {
+    var i = selections[s];
+    table[i].isProtected = false;
+  }
+
+  //update tree view
+  tree.treeBoxObject.invalidate();
+//DY - Update selections
+  tree.treeBoxObject.ensureRowIsVisible(selections[0]);
+  // disable/enable buttons
+  document.getElementById(unprotButton).disabled = true;
+  document.getElementById(protButton).disabled = false;
+  document.getElementById(removeButton).disabled = false;
+}
+function DeleteAllCookies() {
+
+  DeleteAllFromTree(cookiesTree, cookiesTreeView,
+                        cookies, deletedCookies,
+                        "removeCookie", "removeAllCookies",
+                        "protectCookie", "unprotectCookie");
+
+}
+function DeleteSelectedItemFromTree
+    (tree, view, table, deletedTable, removeButton, removeAllButton, protButton, unprotButton) {
+
+  var selections = getTreeSelections(tree);
+
+  tree.view.selection.clearSelection();
   
+
+  // remove selected items from list (by setting them to null) and place in deleted list
+  for (var s=selections.length-1; s>= 0; s--) {
+    var i = selections[s];
+    deletedTable[deletedTable.length] = table[i];
+    table[i] = null;
+  }
+  // collapse list by removing all the null entries
+  for (var j=0; j<table.length; j++) {
+    if (table[j] == null) {
+      var k = j;
+      while ((k < table.length) && (table[k] == null)) {
+        k++;
+      }
+      table.splice(j, k-j);
+      view.rowCount -= k - j;
+      tree.treeBoxObject.rowCountChanged(j, j - k);
+    }
+  }
+//DY - update selection and/or buttons
+  if (table.length) {
+
+//DY - update selection to previous (first of) selected position or bottom
+    var nextSelection = (selections[0] < table.length) ? selections[0] : table.length-1;
+
+   	tree.view.selection.select(nextSelection);
+    tree.treeBoxObject.ensureRowIsVisible(nextSelection);
+    if (table[nextSelection].isProtected) {
+        document.getElementById(unprotButton).disabled = false;
+        document.getElementById(protButton).disabled = true;
+    } else {
+        document.getElementById(unprotButton).disabled = true;
+        document.getElementById(protButton).disabled = false;
+    }
+  } else {
+    // disable buttons
+    document.getElementById(removeButton).disabled = true;
+    document.getElementById(removeAllButton).disabled = true;
+    document.getElementById(unprotButton).disabled = true;
+    document.getElementById(protButton).disabled = true;
+  }
+}
+function DeleteAllFromTree
+    (tree, view, table, deletedTable, removeButton, removeAllButton, protButton, unprotButton) {
+
+  // remove items from table and place in deleted table
+  for (var i=0; i<table.length; i++) {
+//DY - only if unprotected
+    if (!table[i].isProtected) {
+      deletedTable[deletedTable.length] = table[i];
+      table[i] = null;
+    }
+  }
+  
+	tree.view.selection.clearSelection();
+  
+//DY - fix up tree
+  // collapse list by removing all the null entries
+  for (var j=0; j<table.length; j++) {
+    if (table[j] == null) {
+      var k = j;
+      while ((k < table.length) && (table[k] == null)) {
+        k++;
+      }
+      table.splice(j, k-j);
+      view.rowCount -= k - j;
+      tree.treeBoxObject.rowCountChanged(j, j - k);
+    }
+  }
+  // update selection and/or buttons
+  if (table.length) {
+    // update selection to top
+    if (oldTreeCode) {
+    	tree.treeBoxObject.view.selection.select(0);
+    } else {
+    	tree.view.selection.select(0);
+    }
+    tree.treeBoxObject.ensureRowIsVisible(0);
+    //if it exists is must already be protected
+        document.getElementById(unprotButton).disabled = false;
+        document.getElementById(protButton).disabled = true;
+  } else {
+    // disable all buttons
+    document.getElementById(removeButton).disabled = true;
+    document.getElementById(removeAllButton).disabled = true;
+    document.getElementById(unprotButton).disabled = true;
+    document.getElementById(protButton).disabled = true;
+  }
 }
\ No newline at end of file
diff --git a/src/chrome/content/torcookiedialog.xul b/src/chrome/content/torcookiedialog.xul
index 3f39780..64ccc99 100644
--- a/src/chrome/content/torcookiedialog.xul
+++ b/src/chrome/content/torcookiedialog.xul
@@ -10,7 +10,7 @@
         buttons="accept,cancel"
         style="width: 30em;"
         onload="initDialog();"
-        ondialogaccept="return;"
+        ondialogaccept="acceptDialog();"
         persist="screenX screenY width height">
   <script src="chrome://torbutton/content/torbutton.js" type="application/x-javascript"/>
   <script src="chrome://torbutton/content/torcookie.js" type="application/x-javascript"/>
@@ -34,8 +34,39 @@
           <splitter class="tree-splitter"/>
           <treecol id="nameCol" label="Name" flex="1"
                        onclick="CookieColumnSort('name', true);" persist="width"/>
+          <treecol id="pathCol" label="Path" flex="1"
+                       onclick="CookieColumnSort('path', true);" persist="width"/>
+          
         </treecols>
         <treechildren/>
       </tree>
   </vbox>
+  <groupbox>
+    <hbox>
+        <vbox>
+          <button id="protectCookie" disabled="true"
+                      label="Protect Cookie"
+                      oncommand="protectCookie();"/>
+          <button id="removeCookie" disabled="true"
+                      label="Remove Cookie"
+                      oncommand="DeleteCookie();"/>
+        </vbox>
+        <vbox>
+          <button id="unprotectCookie" disabled="true"
+                      label="Unprotect Cookie"
+                      oncommand="unprotectCookie();"/>
+          <button id="removeAllCookies"
+                      label="Remove All But Protected"
+                      oncommand="DeleteAllCookies();"/>
+        </vbox>
+      </hbox>
+      <hbox>
+        <radiogroup id="defaultCookieGroup">
+          <radio id="saveAllCookies" label="Protect All New Cookies" />
+          <radio id="donnotsaveCookies" label="Do Not Protect New Cookies" />
+        </radiogroup>
+      </hbox>
+  </groupbox>
+  
 </dialog>
+
diff --git a/src/components/cookie-jar-selector.js b/src/components/cookie-jar-selector.js
index f3d7c07..8ffe895 100644
--- a/src/components/cookie-jar-selector.js
+++ b/src/components/cookie-jar-selector.js
@@ -153,15 +153,93 @@ function CookieJarSelector() {
   }
 
   this._cookiesToFile = function(name) {
-      var file = getProfileFile("cookies-" + name + ".xml");
-      var foStream = Cc["@mozilla.org/network/file-output-stream;1"]
-            .createInstance(Ci.nsIFileOutputStream);
-      foStream.init(file, 0x02 | 0x08 | 0x20, 0666, 0); 
-      var data = this["cookiesobj-" + name].toString();
-      foStream.write(data, data.length);
-      foStream.close();
+    var file = getProfileFile("cookies-" + name + ".xml");
+    var foStream = Cc["@mozilla.org/network/file-output-stream;1"]
+          .createInstance(Ci.nsIFileOutputStream);
+    foStream.init(file, 0x02 | 0x08 | 0x20, 0666, 0); 
+    var data = this["cookiesobj-" + name].toString();
+    foStream.write(data, data.length);
+    foStream.close();
+  }
+  this._protectedCookiesToFile = function(name) {
+    var file = getProfileFile("protected-" + name + ".xml");
+    var foStream = Cc["@mozilla.org/network/file-output-stream;1"]
+        .createInstance(Ci.nsIFileOutputStream);
+    foStream.init(file, 0x02 | 0x08 | 0x20, 0666, 0); 
+    var data = this["protected-" + name].toString();
+    foStream.write(data, data.length);
+    foStream.close();
+  }
+  this.getProtectedCookies = function(name) {
+      var file = getProfileFile("protected-" + name + ".xml");
+      if (!file.exists())
+          return null;
+      var data = "";
+      var fstream = Cc["@mozilla.org/network/file-input-stream;1"]
+          .createInstance(Ci.nsIFileInputStream);
+      var sstream = Cc["@mozilla.org/scriptableinputstream;1"]
+          .createInstance(Ci.nsIScriptableInputStream);
+      fstream.init(file, -1, 0, 0);
+      sstream.init(fstream); 
+
+      var str = sstream.read(4096);
+      while (str.length > 0) {
+          data += str;
+          str = sstream.read(4096);
+      }
+
+      sstream.close();
+      fstream.close();
+      try {
+          var ret = XML(data);
+      } catch(e) { // file has been corrupted; XXX: handle error differently
+          this.logger.log(5, "Cookies corrupted: "+e);
+          try {
+              file.remove(false); //XXX: is it necessary to remove it ?
+              var ret = null;
+          } catch(e2) {
+              this.logger.log(5, "Can't remove file "+e);
+          }
+      }
+      return ret;
   }
+  this.protectCookies = function(cookies) {
+    var tor_enabled = this.prefs.getBoolPref("extensions.torbutton.tor_enabled");
+    var protname = tor_enabled? "tor" : "nontor";
+    this._writeProtectCookies(cookies,protname);
+    this._protectedCookiesToFile(protname);  
+  }
+  this._writeProtectCookies = function(cookies, name) {
+    var cookieManager =
+      Cc["@mozilla.org/cookiemanager;1"]
+      .getService(Ci.nsICookieManager);
+    var cookiesEnum = cookieManager.enumerator;
+    var cookiesAsXml = new XML('<cookies/>');
+    for (var i = 0; i < cookies.length; i++) {
+        var cookie = cookies[i];
+        var xml = <cookie>{cookie.value}</cookie>;
+        //this.logger.log(2, "Saving cookie: "+cookie.host+":"+cookie.name+" until: "+cookie.expiry);
+        xml. at name = cookie.name;
+        xml. at host = cookie.host;
+        xml. at path = cookie.path;
+        if (cookie.isSecure)
+            xml. at isSecure = 1;
+        if (cookie.isSession) {
+            xml. at isSession = 1;
+            // session cookies get fucked up expiry. Give it 1yr if
+            // the user wants to save their session cookies
+            xml. at expiry = Date.now()/1000 + 365*24*60*60;
+        } else {
+            xml. at expiry = cookie.expires; 
+        }
+        if (cookie.isHttpOnly)
+            xml. at isHttpOnly = 1;
 
+        // Save either session or non-session cookies this time around:
+        cookiesAsXml.appendChild(xml);
+    }
+    this["protected-" + name] = cookiesAsXml;
+  }
   this._cookiesFromFile = function(name) {
       var file = getProfileFile("cookies-" + name + ".xml");
       if (!file.exists())
-- 
1.5.6.5




More information about the tor-commits mailing list