My changes to weave to enable cookie synchronization. So far untested and still missing a thing or two.
authorjono@jono-gibbon-laptop
Tue, 11 Mar 2008 12:08:38 -0500
changeset 44408 6e80624828e7d0c019eae6e2a7be6218bda8ee58
parent 44367 e206c07082431b6b405c96462b6a0149a1c000fe
child 44409 1564929af459f80ed65c5655bc45726bb0d1a46a
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
My changes to weave to enable cookie synchronization. So far untested and still missing a thing or two.
services/sync/locales/en-US/preferences.dtd
services/sync/modules/engines.js
services/sync/modules/service.js
services/sync/modules/stores.js
services/sync/modules/syncCores.js
services/sync/services-sync.js
--- a/services/sync/locales/en-US/preferences.dtd
+++ b/services/sync/locales/en-US/preferences.dtd
@@ -16,16 +16,17 @@
 <!ENTITY accountSettings.label              "Settings">
 
 <!ENTITY backUpCheckbox.label               "Back up and synchronize my data to a Weave server">
 <!ENTITY encryptOnServerCheckbox.label      "Encrypt my data on the server">
 <!ENTITY syncNowButton.label                "Sync Now">
 <!ENTITY syncItemsList.label                "Synchronize these items:">
 <!ENTITY bookmarksCheckbox.label            "Bookmarks">
 <!ENTITY historyCheckbox.label              "Browsing History">
+<!ENTITY cookiesCheckbox.label              "Cookies (Not recommended!)">
 
 <!ENTITY addonsGroupbox.description         "This is where you will find, install, and manage Weave add-ons.">
 
 <!ENTITY serverSettingsCaption.label        "Server Settings">
 <!ENTITY serverLocation.label               "Server Location:">
 <!ENTITY encryption.label                   "Encryption:">
 <!ENTITY teaAlgorithmItem.label             "Placeholder Algorithm">
 <!ENTITY noEncryptionItem.label             "No encryption">
--- a/services/sync/modules/engines.js
+++ b/services/sync/modules/engines.js
@@ -748,8 +748,34 @@ HistoryEngine.prototype = {
   __store: null,
   get _store() {
     if (!this.__store)
       this.__store = new HistoryStore();
     return this.__store;
   }
 };
 HistoryEngine.prototype.__proto__ = new Engine();
+
+
+// Jono: the following is copy-and-paste code
+function CookieEngine(davCollection, cryptoId) {
+  this._init(davCollection, cryptoId);
+}
+CookieEngine.prototype = {
+  get name() { return "cookie-engine"; },
+  get logName() { return "CookieEngine"; },
+  get serverPrefix() { return "user-data/cookies/"; },
+
+  __core: null,
+  get _core() {
+    if (!this.__core)
+      this.__core = new CookieSyncCore();
+    return this.__core;
+  },
+
+  __store: null,
+  get _store() {
+    if (!this.__store)
+      this.__store = new CookieStore();
+    return this.__store;
+  }
+};
+CookieEngine.prototype.__proto__ = new Engine();
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -107,16 +107,23 @@ WeaveSyncService.prototype = {
 
   __histEngine: null,
   get _histEngine() {
     if (!this.__histEngine)
       this.__histEngine = new HistoryEngine(this._dav, this._cryptoId);
     return this.__histEngine;
   },
 
+  __cookieEngine: null,
+  get _cookieEngine() {
+    if (!this.__cookieEngine)
+      this.__cookieEngine = new CookieEngine(this._dav, this._cryptoId);
+    return this.__cookieEngine;
+  },
+
   // Logger object
   _log: null,
 
   // Timer object for automagically syncing
   _scheduleTimer: null,
 
   __mozId: null,
   get _mozId() {
@@ -431,17 +438,20 @@ WeaveSyncService.prototype = {
       if (this._prefs.getBoolPref("bookmarks")) {
         this._bmkEngine.sync(self.cb);
         yield;
       }
       if (this._prefs.getBoolPref("history")) {
         this._histEngine.sync(self.cb);
         yield;
       }
-
+      if (this._prefs.getBoolPref("cookies")) {
+        this._cookieEngine.sync(self.cb);
+        yield;
+      }
       success = true;
       this._unlock();
 
     } catch (e) {
       throw e;
 
     } finally {
       if (success)
--- a/services/sync/modules/stores.js
+++ b/services/sync/modules/stores.js
@@ -641,8 +641,139 @@ HistoryStore.prototype = {
     return items;
   },
 
   wipe: function HistStore_wipe() {
     this._browserHist.removeAllPages();
   }
 };
 HistoryStore.prototype.__proto__ = new Store();
+
+
+function CookieStore() {
+  this._init();
+}
+CookieStore.prototype = {
+  _logName: "CookieStore",
+
+
+  // Documentation of the nsICookie interface says:
+  // name 	ACString 	The name of the cookie. Read only.
+  // value 	ACString 	The cookie value. Read only.
+  // isDomain 	boolean 	True if the cookie is a domain cookie, false otherwise. Read only.
+  // host 	AUTF8String 	The host (possibly fully qualified) of the cookie. Read only.
+  // path 	AUTF8String 	The path pertaining to the cookie. Read only.
+  // isSecure 	boolean 	True if the cookie was transmitted over ssl, false otherwise. Read only.
+  // expires 	PRUint64 	Expiration time (local timezone) expressed as number of seconds since Jan 1, 1970. Read only.
+  // status 	nsCookieStatus 	Holds the P3P status of cookie. Read only.
+  // policy 	nsCookiePolicy 	Holds the site's compact policy value. Read only.
+  // nsICookie2 deprecates expires, status, and policy, and adds:
+  //rawHost 	AUTF8String 	The host (possibly fully qualified) of the cookie without a leading dot to represent if it is a domain cookie. Read only.
+  //isSession 	boolean 	True if the cookie is a session cookie. Read only.
+  //expiry 	PRInt64 	the actual expiry time of the cookie (where 0 does not represent a session cookie). Read only.
+  //isHttpOnly 	boolean 	True if the cookie is an http only cookie. Read only.
+
+
+  __cookieManager: null,
+  get _cookieManager() {
+    if (!this.__cookieManager)
+      this.__cookieManager = Cc["@mozilla.org/cookiemanager;1"].
+                             getService(Ci.nsICookieManager2);
+    // need the 2nd revision of the ICookieManager interface
+    // because it supports add() and the 1st one doesn't.
+    return this.__cookieManager
+  },
+
+  _createCommand: function HistStore__createCommand(command) {
+	// we got a command to create a cookie in the local browser
+        // in order to sync with the server.
+
+	this._log.info("CookieStore got createCommand: " + command );
+
+        // this assumes command.data fits the nsICookie2 interface
+	this.__cookieManager.add( command.data.host,
+				  command.data.path,
+				  command.data.name,
+				  command.data.value,
+				  command.data.isSecure,
+				  command.data.isSession,
+				  command.data.expiry );
+  },
+
+  _removeCommand: function CookieStore__removeCommand(command) {
+	// we got a command to remove a cookie from the local browser
+        // in order to sync with the server.
+        // command.data appears to be equivalent to what wrap() puts in
+        // the JSON dictionary.
+    
+        this._log.info("CookieStore got removeCommand: " + command );
+
+        // I think it goes like this, according to 
+        // http://developer.mozilla.org/en/docs/nsICookieManager
+        // the last argument is "always block cookies from this domain?"
+	// and the answer is "no".
+	this._cookieManager.remove( command.data.host,
+                                    command.data.name,
+				    command.data.path,
+                                    false );
+  },
+
+  _editCommand: function CookieStore__editCommand(command) {
+        // we got a command to change a cookie in the local browser
+        // in order to sync with the server.
+    
+	// TODO implement this!!
+        this._log.info("CookieStore got editCommand: " + command );
+  },
+
+
+  wrap: function CookieStore_wrap() {
+	// Return contents of this store, as JSON.
+        // A dictionary of cookies where the keys are GUIDs and the
+        // values are sub-dictionaries containing all cookie fields.
+
+	let items = {};
+	var iter = this.__cookieManager.enumerator;
+	while (iter.hasMoreElements()){
+	    var cookie = iter.getNext();
+	    if (cookie instanceof Ci.nsICookie){
+                // String used to identify cookies is
+		// host:path:name
+                let key = cookie.host + ":" + cookie.path + ":" + cookie.name
+		items[ key ] = { parentGUID: '',
+				 name: cookie.name,
+				 value: cookie.value,
+				 isDomain: cookie.isDomain,
+				 host: cookie.host,
+				 path: cookie.path,
+				 isSecure: cookie.isSecure,
+                                 // nsICookie2 values:
+				 rawHost: cookie.rawHost,
+				 isSession: cookie.isSession,
+				 expiry: cookie.expiry,
+				 isHttpOnly: cookie.isHttpOnly }
+
+		// http://developer.mozilla.org/en/docs/nsICookie
+		// Note: not syncing "expires", "status", or "policy"
+		// since they're deprecated.
+
+	    }
+    return items;
+  },
+
+  wipe: function CookieStore_wipe() {
+	// Remove everything from the store.  Return nothing.
+        // TODO are the semantics of this just wiping out an internal
+        // buffer, or am I supposed to wipe out all cookies from
+        // the browser itself for reals?
+
+        this.__cookieManager.removeAll()
+  },
+
+  resetGUIDs: function CookieStore_resetGUIDs() {
+      // called in the case where remote/local sync GUIDs do not
+      // match.  We do need to override this, but since we're deriving
+      // GUIDs from the cookie data itself and not generating them,
+      // there's basically no way they can get "out of sync" so there's
+      // nothing to do here.
+  }
+};
+CookieStore.prototype.__proto__ = new Store();
--- a/services/sync/modules/syncCores.js
+++ b/services/sync/modules/syncCores.js
@@ -410,8 +410,62 @@ HistorySyncCore.prototype = {
     // History commands never qualify for likeness.  We will always
     // take the union of all client/server items.  We use the URL as
     // the GUID, so the same sites will map to the same item (same
     // GUID), without our intervention.
     return false;
   }
 };
 HistorySyncCore.prototype.__proto__ = new SyncCore();
+
+
+
+
+function CookiesSyncCore() {
+  this._init();
+}
+CookiesSyncCore.prototype = {
+  _logName: "CookieSync",
+
+  __cookieManager: null,
+  get _cookieManager() {
+    if (!this.__cookieManager)
+      this.__cookieManager = Cc["@mozilla.org/cookiemanager;1"].
+                             getService(Ci.nsICookieManager2);
+    // need the 2nd revision of the ICookieManager interface
+    // because it supports add() and the 1st one doesn't.
+    return this.__cookieManager
+  },
+
+
+  _itemExists: function CSC__itemExists(GUID) {
+        // true if a cookie with the given GUID exists.
+	// The GUID that we are passed should correspond to the keys
+	// that we define in the JSON returned by CookieStore.wrap()
+	// That is, it will be a string of the form
+	// "host:path:name".
+
+	// TODO verify that colons can't normally appear in any of
+	// the fields -- if they did it then we can't rely on .split(":")
+	// to parse correctly.
+
+        let unused = 0; // for outparam from findMatchingCookie
+	let cookieArray = GUID.split( ":" );
+        // create a generic object to represent the cookie -- just has
+	// to implement nsICookie2 interface.
+	cookie = Object();
+	cookie.host = cookieArray[0]
+	cookie.path = cookieArray[1]
+	cookie.name = cookieArray[2];
+    	return this.__cookieManager.findMatchingCookie( cookie, unused );
+  },
+
+  _commandLike: function CSC_commandLike(a, b) {
+        // Method required to be overridden.
+        // a and b each have a .data and a .GUID
+	// If this function returns true, an editCommand will be
+	// generated to try to resolve the thing.
+	// but are a and b objects of the type in the Store or
+	// are they "commands"??
+        return false;
+  }
+};
+CookiesSyncCore.prototype.__proto__ = new SyncCore();
--- a/services/sync/services-sync.js
+++ b/services/sync/services-sync.js
@@ -6,16 +6,17 @@ pref("extensions.weave.encryption", "aes
 pref("extensions.weave.lastversion", "firstrun");
 pref("extensions.weave.lastsync", "0");
 
 pref("extensions.weave.rememberpassword", true);
 pref("extensions.weave.autoconnect", true);
 pref("extensions.weave.enabled", true);
 pref("extensions.weave.bookmarks", true);
 pref("extensions.weave.history", true);
+pref("extensions.weave.cookies", false );
 pref("extensions.weave.schedule", 1);
 
 
 pref("extensions.weave.log.rootLogger", "Config");
 pref("extensions.weave.log.appender.console", "Warn");
 pref("extensions.weave.log.appender.dump", "Error");
 pref("extensions.weave.log.appender.briefLog", "Info");
 pref("extensions.weave.log.appender.debugLog", "Config");