My changes to weave to enable cookie synchronization. So far untested and still missing a thing or two.
My changes to weave to enable cookie synchronization. So far untested and still missing a thing or two.
--- 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");