From 11f8af54313c64e070122d39b4a105e371fc5c8e Mon Sep 17 00:00:00 2001 From: "jonathandicarlo@jonathan-dicarlos-macbook-pro.local" Date: Fri, 6 Jun 2008 17:33:44 -0700 Subject: [PATCH 1/2] Moved _createShare and _share() from engines.js to BookmarkEngine class in engines/bookmarks.js. The identity of the folder to be shared is now passed from the share dialog box (share.xul) into BookmarkEngine._share(). --- services/sync/modules/engines.js | 92 ++--------------- services/sync/modules/engines/bookmarks.js | 112 ++++++++++++++++++++- services/sync/modules/service.js | 33 ++++-- 3 files changed, 145 insertions(+), 92 deletions(-) diff --git a/services/sync/modules/engines.js b/services/sync/modules/engines.js index 20beb82a05aa..a8895ad628d7 100644 --- a/services/sync/modules/engines.js +++ b/services/sync/modules/engines.js @@ -649,97 +649,21 @@ Engine.prototype = { self.done(ret); }, - _share: function Engine__share(username) { - let self = yield; - let prefix = DAV.defaultPrefix; - - this._log.debug("Sharing bookmarks with " + username); - - this._getSymKey.async(this, self.cb); - yield; - - // copied from getSymKey - DAV.GET(this.keysFile, self.cb); - let ret = yield; - Utils.ensureStatus(ret.status, "Could not get keys file."); - let keys = this._json.decode(ret.responseText); - - // get the other user's pubkey - let hash = Utils.sha1(username); - let serverURL = Utils.prefs.getCharPref("serverURL"); - - try { - DAV.defaultPrefix = "user/" + hash + "/"; //FIXME: very ugly! - DAV.GET("public/pubkey", self.cb); - ret = yield; - } - catch (e) { throw e; } - finally { DAV.defaultPrefix = prefix; } - - Utils.ensureStatus(ret.status, "Could not get public key for " + username); - - let id = new Identity(); - id.pubkey = ret.responseText; - - // now encrypt the symkey with their pubkey and upload the new keyring - Crypto.RSAencrypt.async(Crypto, self.cb, this._engineId.password, id); - let enckey = yield; - if (!enckey) - throw "Could not encrypt symmetric encryption key"; - - keys.ring[hash] = enckey; - DAV.PUT(this.keysFile, this._json.encode(keys), self.cb); - ret = yield; - Utils.ensureStatus(ret.status, "Could not upload keyring file."); - - this._createShare(username, username); - - this._log.debug("All done sharing!"); - - self.done(true); + _share: function Engine__share(guid, username) { + /* This should be overridden by the engine subclass for each datatype. + Implementation should share the data node identified by guid, + and all its children, if any, with the user identified by username. */ + return; }, - // FIXME: EEK bookmarks specific - _createShare: function Engine__createShare(id, title) { - let bms = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. - getService(Ci.nsINavBookmarksService); - let ans = Cc["@mozilla.org/browser/annotation-service;1"]. - getService(Ci.nsIAnnotationService); - - let root; - let a = ans.getItemsWithAnnotation("weave/mounted-shares-folder", {}); - if (a.length == 1) - root = a[0]; - - if (!root) { - root = bms.createFolder(bms.toolbarFolder, "Shared Folders", - bms.DEFAULT_INDEX); - ans.setItemAnnotation(root, "weave/mounted-shares-folder", true, 0, - ans.EXPIRE_NEVER); - } - - let item; - a = ans.getItemsWithAnnotation("weave/mounted-share-id", {}); - for (let i = 0; i < a.length; i++) { - if (ans.getItemAnnotation(a[i], "weave/mounted-share-id") == id) { - item = a[i]; - break; - } - } - - if (!item) { - let newId = bms.createFolder(root, title, bms.DEFAULT_INDEX); - ans.setItemAnnotation(newId, "weave/mounted-share-id", id, 0, - ans.EXPIRE_NEVER); - } - }, + // TODO need a "stop sharing" function. sync: function Engine_sync(onComplete) { return this._sync.async(this, onComplete); }, - share: function Engine_share(onComplete, username) { - return this._share.async(this, onComplete, username); + share: function Engine_share(onComplete, guid, username) { + return this._share.async(this, onComplete, guid, username); }, resetServer: function Engine_resetServer(onComplete) { diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index 5f3226f80520..3d58c4199f22 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -63,6 +63,108 @@ BookmarksEngine.prototype = { } }, + // TODO modify this as neccessary since I just moved it from the engine + // superclass into BookmarkEngine. + _share: function BookmarkEngine__share(guid, username) { + let self = yield; + let prefix = DAV.defaultPrefix; + + this._log.debug("Sharing bookmarks with " + username); + + this._getSymKey.async(this, self.cb); + yield; + + // copied from getSymKey + DAV.GET(this.keysFile, self.cb); + let ret = yield; + Utils.ensureStatus(ret.status, "Could not get keys file."); + let keys = this._json.decode(ret.responseText); + + // get the other user's pubkey + let serverURL = Utils.prefs.getCharPref("serverURL"); + + try { + DAV.defaultPrefix = "user/" + username + "/"; + DAV.GET("public/pubkey", self.cb); + ret = yield; + } + catch (e) { throw e; } + finally { DAV.defaultPrefix = prefix; } + + Utils.ensureStatus(ret.status, "Could not get public key for " + username); + + let id = new Identity(); + id.pubkey = ret.responseText; + + // now encrypt the symkey with their pubkey and upload the new keyring + Crypto.RSAencrypt.async(Crypto, self.cb, this._engineId.password, id); + let enckey = yield; + if (!enckey) + throw "Could not encrypt symmetric encryption key"; + + keys.ring[username] = enckey; + DAV.PUT(this.keysFile, this._json.encode(keys), self.cb); + ret = yield; + Utils.ensureStatus(ret.status, "Could not upload keyring file."); + + this._createShare(guid, username, username); + + this._log.debug("All done sharing!"); + + self.done(true); + }, + + _createShare: function BookmarkEngine__createShare(guid, id, title) { + /* the bookmark item identified by guid, and the whole subtree under it, + must be copied out from the main file into a separate file which is + put into the new directory and encrypted with the key in the keychain. + id is the userid of the user we're sharing with. + */ + + /* TODO it appears that this just creates the folder and puts the + annotation on it; the mechanics of sharing must be done when syncing? + + Or has that not been done yet at all? + Do we have to create a new Mount? + */ + let bms = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. + getService(Ci.nsINavBookmarksService); + let ans = Cc["@mozilla.org/browser/annotation-service;1"]. + getService(Ci.nsIAnnotationService); + + let root; + let a = ans.getItemsWithAnnotation("weave/mounted-shares-folder", {}); + if (a.length == 1) + root = a[0]; + + if (!root) { + root = bms.createFolder(bms.toolbarFolder, "Shared Folders", + bms.DEFAULT_INDEX); + ans.setItemAnnotation(root, "weave/mounted-shares-folder", true, 0, + ans.EXPIRE_NEVER); + } + + let item; + a = ans.getItemsWithAnnotation("weave/mounted-share-id", {}); + for (let i = 0; i < a.length; i++) { + if (ans.getItemAnnotation(a[i], "weave/mounted-share-id") == id) { + item = a[i]; + break; + } + } + + if (!item) { + let newId = bms.createFolder(root, title, bms.DEFAULT_INDEX); + ans.setItemAnnotation(newId, "weave/mounted-share-id", id, 0, + ans.EXPIRE_NEVER); + } + }, + + _stopShare: function BookmarkeEngine__stopShare( guid, username) { + // TODO implement this; also give a way to call it from outside + // the service. + }, + _syncOneMount: function BmkEngine__syncOneMount(mountData) { let self = yield; let user = mountData.userid; @@ -70,11 +172,11 @@ BookmarksEngine.prototype = { let serverURL = Utils.prefs.getCharPref("serverURL"); let snap = new SnapshotStore(); + // TODO this is obviously what we want. this._log.debug("Syncing shared folder from user " + user); try { - let hash = Utils.sha1(user); - DAV.defaultPrefix = "user/" + hash + "/"; //FIXME: very ugly! + DAV.defaultPrefix = "user/" + user + "/"; this._getSymKey.async(this, self.cb); yield; @@ -355,6 +457,9 @@ BookmarksStore.prototype = { command.data.index); break; case "mounted-share": + // TODO this is to create the shared-items folder on another machine + // to duplicate the one that's on the first machine; we don't need that + // anymore. OR is it to create the folder on the sharee's computer? this._log.debug(" -> creating share mountpoint \"" + command.data.title + "\""); newId = this._bms.createFolder(parentId, command.data.title, @@ -519,6 +624,8 @@ BookmarksStore.prototype = { } else if (this._ans.itemHasAnnotation(node.itemId, "weave/mounted-share-id")) { + /* TODO this is for wrapping the special shared folder created by + the old-style share command. */ item.type = "mounted-share"; item.title = node.title; item.mountId = this._ans.getItemAnnotation(node.itemId, @@ -609,6 +716,7 @@ BookmarksStore.prototype = { // remove any share mountpoints for (let guid in ret.snapshot) { + // TODO decide what to do with this... if (ret.snapshot[guid].type == "mounted-share") delete ret.snapshot[guid]; } diff --git a/services/sync/modules/service.js b/services/sync/modules/service.js index 36911ed47c56..dfd679e2d8a4 100644 --- a/services/sync/modules/service.js +++ b/services/sync/modules/service.js @@ -561,16 +561,37 @@ WeaveSvc.prototype = { } }, - shareBookmarks: function WeaveSync_shareBookmarks(onComplete, username) { - this._lock(this._notify("share-bookmarks", - this._shareBookmarks, + shareData: function WeaveSync_shareData(dataType, + onComplete, + guid, + username) { + /* Shares data of the specified datatype (which must correspond to + one of the registered engines) with the user specified by username. + The data node indicated by guid will be shared, along with all its + children, if it has any. onComplete is a function that will be called + when sharing is done; it takes an argument that will be true or false + to indicate whether sharing succeeded or failed. + Implementation, as well as the interpretation of what 'guid' means, + is left up to the engine for the specific dataType. */ + + // TODO who is listening for the share-bookmarks message? + let messageName = "share-" + dataType; + // so for instance, if dataType is "bookmarks" then a message + // "share-bookmarks" will be sent out to any observers who are listening + // for it. + this._lock(this._notify(messageName, + this._shareData, + dataType, + guid, username)).async(this, onComplete); }, - _shareBookmarks: function WeaveSync__shareBookmarks(username) { + _shareBookmarks: function WeaveSync__shareBookmarks(dataType, + guid, + username) { let self = yield; - if (Engines.get("bookmarks").enabled) + if (Engines.get(dataType).enabled) return; - Engines.get("bookmarks").share(self.cb, username); + Engines.get(dataType).share(self.cb, guid, username); let ret = yield; self.done(ret); } From cdffb0e77e5515a3044d6952fee18b7cccc32e08 Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Fri, 6 Jun 2008 17:46:34 -0700 Subject: [PATCH 2/2] In async.js, renamed 'object' to 'thisArg', which makes the code clearer and easier to understand. --- services/sync/modules/async.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/services/sync/modules/async.js b/services/sync/modules/async.js index 45b9c3d14658..93e9f2f0a4d0 100644 --- a/services/sync/modules/async.js +++ b/services/sync/modules/async.js @@ -68,11 +68,11 @@ AsyncException.prototype = { } }; -function Generator(object, method, onComplete, args) { +function Generator(thisArg, method, onComplete, args) { this._log = Log4Moz.Service.getLogger("Async.Generator"); this._log.level = Log4Moz.Level[Utils.prefs.getCharPref("log.logger.async")]; - this._object = object; + this._thisArg = thisArg; this._method = method; this.onComplete = onComplete; this._args = args; @@ -93,11 +93,11 @@ Generator.prototype = { }, get listener() { return new Utils.EventListener(this.cb); }, - get _object() { return this.__object; }, - set _object(value) { + get _thisArg() { return this.__thisArg; }, + set _thisArg(value) { if (typeof value != "object") throw "Generator: expected type 'object', got type '" + typeof(value) + "'"; - this.__object = value; + this.__thisArg = value; }, get _method() { return this.__method; }, @@ -161,7 +161,7 @@ Generator.prototype = { run: function AsyncGen_run() { this._continued = false; try { - this._generator = this._method.apply(this._object, this._args); + this._generator = this._method.apply(this._thisArg, this._args); this.generator.next(); // must initialize before sending this.generator.send(this); } catch (e) { @@ -267,9 +267,9 @@ Async = { // where fooGen is a generator function, and gen is a Generator instance // ret is whatever the generator 'returns' via Generator.done(). - run: function Async_run(object, method, onComplete /* , arg1, arg2, ... */) { + run: function Async_run(thisArg, method, onComplete /* , arg1, arg2, ... */) { let args = Array.prototype.slice.call(arguments, 3); - let gen = new Generator(object, method, onComplete, args); + let gen = new Generator(thisArg, method, onComplete, args); gen.run(); return gen; }, @@ -287,9 +287,9 @@ Async = { // Note that 'this' refers to the method being called, not the // Async object. - sugar: function Async_sugar(object, onComplete /* , arg1, arg2, ... */) { + sugar: function Async_sugar(thisArg, onComplete /* , arg1, arg2, ... */) { let args = Array.prototype.slice.call(arguments, 1); - args.unshift(object, this); + args.unshift(thisArg, this); Async.run.apply(Async, args); },