зеркало из https://github.com/mozilla/gecko-dev.git
add status notification to sharing dialog; fix async generators in the case where an async method is missing a yield (better error, continue execution in parent); add guts of demo sharing code to engine & store (for bookmarks, with some spillage)
This commit is contained in:
Родитель
38ed71b0a2
Коммит
26713b0184
|
@ -2,6 +2,5 @@
|
||||||
<!ENTITY close.button.label "Close">
|
<!ENTITY close.button.label "Close">
|
||||||
<!ENTITY share.button.label "Share">
|
<!ENTITY share.button.label "Share">
|
||||||
<!ENTITY description.top "Enter a the ID of the user you wish to share your bookmarks with:">
|
<!ENTITY description.top "Enter a the ID of the user you wish to share your bookmarks with:">
|
||||||
<!ENTITY description.ok "Weave sharing complete!">
|
|
||||||
<!ENTITY description.error "Error. Please check the Weave ID and try again.">
|
|
||||||
<!ENTITY username.label "Weave ID (Email):">
|
<!ENTITY username.label "Weave ID (Email):">
|
||||||
|
<!ENTITY status.waiting "Waiting...">
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
status.ok = Weave sharing complete!
|
||||||
|
status.error = Error. Please check the Weave ID and try again.
|
||||||
|
status.working = Working...
|
|
@ -219,11 +219,12 @@ Generator.prototype = {
|
||||||
|
|
||||||
_done: function AsyncGen__done(retval) {
|
_done: function AsyncGen__done(retval) {
|
||||||
if (!this._generator) {
|
if (!this._generator) {
|
||||||
this._log.error("Generator '" + this.name + "' called 'done' after it's finalized");
|
this._log.error("Async method '" + this.name + "' is missing a 'yield' call " +
|
||||||
|
"(or called done() after being finalized)");
|
||||||
this._log.trace("Initial stack trace:\n" + this.trace);
|
this._log.trace("Initial stack trace:\n" + this.trace);
|
||||||
return;
|
} else {
|
||||||
|
this._generator.close();
|
||||||
}
|
}
|
||||||
this._generator.close();
|
|
||||||
this._generator = null;
|
this._generator = null;
|
||||||
this._timer = null;
|
this._timer = null;
|
||||||
|
|
||||||
|
|
|
@ -685,56 +685,83 @@ Engine.prototype = {
|
||||||
|
|
||||||
this._log.debug("Sharing bookmarks with " + username);
|
this._log.debug("Sharing bookmarks with " + username);
|
||||||
|
|
||||||
|
this._getSymKey.async(this, self.cb);
|
||||||
|
yield;
|
||||||
|
|
||||||
|
// copied from getSymKey
|
||||||
|
this._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 {
|
try {
|
||||||
this._getSymKey.async(this, self.cb);
|
|
||||||
yield;
|
|
||||||
|
|
||||||
// copied from getSymKey
|
|
||||||
this._log.debug("Getting keyring from server");
|
|
||||||
this._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
|
|
||||||
this._log.debug("Constructing other user's URL");
|
|
||||||
let hash = Utils.sha1(username);
|
|
||||||
let serverURL = Utils.prefs.getCharPref("serverURL");
|
|
||||||
this._dav.baseURL = serverURL + "user/" + hash + "/"; //FIXME: very ugly!
|
this._dav.baseURL = serverURL + "user/" + hash + "/"; //FIXME: very ugly!
|
||||||
|
|
||||||
this._log.debug("Getting other user's public key");
|
|
||||||
this._dav.GET("public/pubkey", self.cb);
|
this._dav.GET("public/pubkey", self.cb);
|
||||||
ret = yield;
|
ret = yield;
|
||||||
Utils.ensureStatus(ret.status,
|
}
|
||||||
"Could not get public key for user" + username);
|
catch (e) { throw e; }
|
||||||
let id = new Identity();
|
finally { this._dav.baseURL = base; }
|
||||||
id.pubkey = ret.responseText;
|
|
||||||
|
|
||||||
this._dav.baseURL = base;
|
Utils.ensureStatus(ret.status, "Could not get public key for " + username);
|
||||||
|
|
||||||
// now encrypt the symkey with their pubkey and upload the new keyring
|
let id = new Identity();
|
||||||
this._log.debug("Encrypting symmetric key with other user's public key");
|
id.pubkey = ret.responseText;
|
||||||
Crypto.RSAencrypt.async(Crypto, self.cb, this._engineId.password, id);
|
|
||||||
let enckey = yield;
|
|
||||||
if (!enckey)
|
|
||||||
throw "Could not encrypt symmetric encryption key";
|
|
||||||
|
|
||||||
this._log.debug("Uploading new keyring");
|
// now encrypt the symkey with their pubkey and upload the new keyring
|
||||||
keys.ring[hash] = enckey;
|
Crypto.RSAencrypt.async(Crypto, self.cb, this._engineId.password, id);
|
||||||
this._dav.PUT(this.keysFile, this._json.encode(keys), self.cb);
|
let enckey = yield;
|
||||||
ret = yield;
|
if (!enckey)
|
||||||
Utils.ensureStatus(ret.status, "Could not upload keyring file.");
|
throw "Could not encrypt symmetric encryption key";
|
||||||
|
|
||||||
this._log.debug("All done sharing!");
|
keys.ring[hash] = enckey;
|
||||||
|
this._dav.PUT(this.keysFile, this._json.encode(keys), self.cb);
|
||||||
|
ret = yield;
|
||||||
|
Utils.ensureStatus(ret.status, "Could not upload keyring file.");
|
||||||
|
|
||||||
} catch (e) {
|
this._createShare(username, username);
|
||||||
throw e;
|
|
||||||
|
|
||||||
} finally {
|
this._log.debug("All done sharing!");
|
||||||
this._dav.baseURL = base;
|
|
||||||
|
self.done(true);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.done();
|
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);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
sync: function Engine_sync(onComplete) {
|
sync: function Engine_sync(onComplete) {
|
||||||
|
@ -774,6 +801,93 @@ BookmarksEngine.prototype = {
|
||||||
if (!this.__store)
|
if (!this.__store)
|
||||||
this.__store = new BookmarksStore();
|
this.__store = new BookmarksStore();
|
||||||
return this.__store;
|
return this.__store;
|
||||||
|
},
|
||||||
|
|
||||||
|
syncMounts: function BmkEngine_syncMounts(onComplete) {
|
||||||
|
this._syncMounts.async(this, onComplete);
|
||||||
|
},
|
||||||
|
_syncMounts: function BmkEngine__syncMounts() {
|
||||||
|
let self = yield;
|
||||||
|
let mounts = this._store.findMounts();
|
||||||
|
|
||||||
|
for (i = 0; i < mounts.length; i++) {
|
||||||
|
try {
|
||||||
|
this._syncOneMount.async(this, self.cb, mounts[i]);
|
||||||
|
yield;
|
||||||
|
} catch (e) {
|
||||||
|
this._log.warn("Could not sync shared folder from " + mounts[i].userid);
|
||||||
|
this._log.trace(Utils.stackTrace(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_syncOneMount: function BmkEngine__syncOneMount(mountData) {
|
||||||
|
let self = yield;
|
||||||
|
let user = mountData.userid;
|
||||||
|
let base = this._dav.baseURL;
|
||||||
|
let serverURL = Utils.prefs.getCharPref("serverURL");
|
||||||
|
let snap = new SnapshotStore();
|
||||||
|
|
||||||
|
this._log.debug("Syncing shared folder from user " + user);
|
||||||
|
|
||||||
|
try {
|
||||||
|
let hash = Utils.sha1(user);
|
||||||
|
this._dav.baseURL = serverURL + "user/" + hash + "/"; //FIXME: very ugly!
|
||||||
|
|
||||||
|
this._getSymKey.async(this, self.cb);
|
||||||
|
yield;
|
||||||
|
|
||||||
|
this._log.trace("Getting status file for " + user);
|
||||||
|
this._dav.GET(this.statusFile, self.cb);
|
||||||
|
let resp = yield;
|
||||||
|
Utils.ensureStatus(resp.status, "Could not download status file.");
|
||||||
|
let status = this._json.decode(resp.responseText);
|
||||||
|
|
||||||
|
this._log.trace("Downloading server snapshot for " + user);
|
||||||
|
this._dav.GET(this.snapshotFile, self.cb);
|
||||||
|
resp = yield;
|
||||||
|
Utils.ensureStatus(resp.status, "Could not download snapshot.");
|
||||||
|
Crypto.PBEdecrypt.async(Crypto, self.cb, resp.responseText,
|
||||||
|
this._engineId, status.snapEncryption);
|
||||||
|
let data = yield;
|
||||||
|
snap.data = this._json.decode(data);
|
||||||
|
|
||||||
|
this._log.trace("Downloading server deltas for " + user);
|
||||||
|
this._dav.GET(this.deltasFile, self.cb);
|
||||||
|
resp = yield;
|
||||||
|
Utils.ensureStatus(resp.status, "Could not download deltas.");
|
||||||
|
Crypto.PBEdecrypt.async(Crypto, self.cb, resp.responseText,
|
||||||
|
this._engineId, status.deltasEncryption);
|
||||||
|
data = yield;
|
||||||
|
deltas = this._json.decode(data);
|
||||||
|
}
|
||||||
|
catch (e) { throw e; }
|
||||||
|
finally { this._dav.baseURL = base; }
|
||||||
|
|
||||||
|
// apply deltas to get current snapshot
|
||||||
|
for (var i = 0; i < deltas.length; i++) {
|
||||||
|
snap.applyCommands.async(snap, self.cb, deltas[i]);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prune tree / get what we want
|
||||||
|
for (let guid in snap.data) {
|
||||||
|
if (snap.data[guid].type != "bookmark")
|
||||||
|
delete snap.data[guid];
|
||||||
|
else
|
||||||
|
snap.data[guid].parentGUID = mountData.rootGUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._log.trace("Got bookmarks fror " + user + ", comparing with local copy");
|
||||||
|
this._core.detectUpdates(self.cb, mountData.snapshot, snap.data);
|
||||||
|
let diff = yield;
|
||||||
|
|
||||||
|
// FIXME: should make sure all GUIDs here live under the mountpoint
|
||||||
|
this._log.trace("Applying changes to folder from " + user);
|
||||||
|
this._store.applyCommands.async(this._store, self.cb, diff);
|
||||||
|
yield;
|
||||||
|
|
||||||
|
this._log.trace("Shared folder from " + user + " successfully synced!");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BookmarksEngine.prototype.__proto__ = new Engine();
|
BookmarksEngine.prototype.__proto__ = new Engine();
|
||||||
|
|
|
@ -512,6 +512,8 @@ WeaveSvc.prototype = {
|
||||||
this._notify(this._bmkEngine.name + ":sync",
|
this._notify(this._bmkEngine.name + ":sync",
|
||||||
engineCb, this._bmkEngine).async(this, innerSelf.cb);
|
engineCb, this._bmkEngine).async(this, innerSelf.cb);
|
||||||
yield;
|
yield;
|
||||||
|
this._bmkEngine.syncMounts(innerSelf.cb);
|
||||||
|
yield;
|
||||||
}
|
}
|
||||||
if (Utils.prefs.getBoolPref("history")) {
|
if (Utils.prefs.getBoolPref("history")) {
|
||||||
this._notify(this._histEngine.name + ":sync",
|
this._notify(this._histEngine.name + ":sync",
|
||||||
|
@ -569,11 +571,13 @@ WeaveSvc.prototype = {
|
||||||
let cb = function Weave_shareBookmarks() {
|
let cb = function Weave_shareBookmarks() {
|
||||||
let innerSelf = yield;
|
let innerSelf = yield;
|
||||||
this._bmkEngine.share(innerSelf.cb, username);
|
this._bmkEngine.share(innerSelf.cb, username);
|
||||||
yield;
|
let ret = yield;
|
||||||
|
innerSelf.done(ret);
|
||||||
};
|
};
|
||||||
|
|
||||||
this._lock(this._notify("share-bookmarks", cb)).async(this, self.cb);
|
this._lock(this._notify("share-bookmarks", cb)).async(this, self.cb);
|
||||||
yield;
|
let ret = yield;
|
||||||
|
self.done(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -385,6 +385,15 @@ BookmarksStore.prototype = {
|
||||||
Utils.makeURI(command.data.feedURI),
|
Utils.makeURI(command.data.feedURI),
|
||||||
command.data.index);
|
command.data.index);
|
||||||
break;
|
break;
|
||||||
|
case "mounted-share":
|
||||||
|
this._log.debug(" -> creating share mountpoint \"" + command.data.title + "\"");
|
||||||
|
newId = this._bms.createFolder(parentId,
|
||||||
|
command.data.title,
|
||||||
|
command.data.index);
|
||||||
|
|
||||||
|
this._ans.setItemAnnotation(newId, "weave/mounted-share-id",
|
||||||
|
command.data.mountId, 0, this._ans.EXPIRE_NEVER);
|
||||||
|
break;
|
||||||
case "separator":
|
case "separator":
|
||||||
this._log.debug(" -> creating separator");
|
this._log.debug(" -> creating separator");
|
||||||
newId = this._bms.insertSeparator(parentId, command.data.index);
|
newId = this._bms.insertSeparator(parentId, command.data.index);
|
||||||
|
@ -508,7 +517,7 @@ BookmarksStore.prototype = {
|
||||||
return this._hsvc.executeQuery(query, this._hsvc.getNewQueryOptions()).root;
|
return this._hsvc.executeQuery(query, this._hsvc.getNewQueryOptions()).root;
|
||||||
},
|
},
|
||||||
|
|
||||||
__wrap: function BSS__wrap(node, items, parentGUID, index, guidOverride) {
|
__wrap: function BSS___wrap(node, items, parentGUID, index, guidOverride) {
|
||||||
let GUID, item;
|
let GUID, item;
|
||||||
|
|
||||||
// we override the guid for the root items, "menu", "toolbar", etc.
|
// we override the guid for the root items, "menu", "toolbar", etc.
|
||||||
|
@ -527,6 +536,14 @@ BookmarksStore.prototype = {
|
||||||
let feedURI = this._ls.getFeedURI(node.itemId);
|
let feedURI = this._ls.getFeedURI(node.itemId);
|
||||||
item.siteURI = siteURI? siteURI.spec : "";
|
item.siteURI = siteURI? siteURI.spec : "";
|
||||||
item.feedURI = feedURI? feedURI.spec : "";
|
item.feedURI = feedURI? feedURI.spec : "";
|
||||||
|
|
||||||
|
} else if (this._ans.itemHasAnnotation(node.itemId,
|
||||||
|
"weave/mounted-share-id")) {
|
||||||
|
item.type = "mounted-share";
|
||||||
|
item.title = node.title;
|
||||||
|
item.mountId = this._ans.getItemAnnotation(node.itemId,
|
||||||
|
"weave/mounted-share-id");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
item.type = "folder";
|
item.type = "folder";
|
||||||
node.QueryInterface(Ci.nsINavHistoryQueryResultNode);
|
node.QueryInterface(Ci.nsINavHistoryQueryResultNode);
|
||||||
|
@ -567,10 +584,32 @@ BookmarksStore.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
// helper
|
// helper
|
||||||
_wrap: function BStore_wrap(node, items, rootName) {
|
_wrap: function BStore__wrap(node, items, rootName) {
|
||||||
return this.__wrap(node, items, null, null, rootName);
|
return this.__wrap(node, items, null, null, rootName);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_wrapMount: function BStore__wrapMount(node, id) {
|
||||||
|
if (node.type != node.RESULT_TYPE_FOLDER)
|
||||||
|
throw "Trying to wrap a non-folder mounted share";
|
||||||
|
|
||||||
|
let GUID = this._bms.getItemGUID(node.itemId);
|
||||||
|
let ret = {rootGUID: GUID, userid: id, snapshot: {}};
|
||||||
|
|
||||||
|
node.QueryInterface(Ci.nsINavHistoryQueryResultNode);
|
||||||
|
node.containerOpen = true;
|
||||||
|
for (var i = 0; i < node.childCount; i++) {
|
||||||
|
this.__wrap(node.getChild(i), ret.snapshot, GUID, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove any share mountpoints
|
||||||
|
for (let guid in ret.snapshot) {
|
||||||
|
if (ret.snapshot[guid].type == "mounted-share")
|
||||||
|
delete ret.snapshot[guid];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
|
||||||
_resetGUIDs: function BSS__resetGUIDs(node) {
|
_resetGUIDs: function BSS__resetGUIDs(node) {
|
||||||
if (this._ans.itemHasAnnotation(node.itemId, "placesInternal/GUID"))
|
if (this._ans.itemHasAnnotation(node.itemId, "placesInternal/GUID"))
|
||||||
this._ans.removeItemAnnotation(node.itemId, "placesInternal/GUID");
|
this._ans.removeItemAnnotation(node.itemId, "placesInternal/GUID");
|
||||||
|
@ -585,6 +624,16 @@ BookmarksStore.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
findMounts: function BStore_findMounts() {
|
||||||
|
let ret = [];
|
||||||
|
let a = this._ans.getItemsWithAnnotation("weave/mounted-share-id", {});
|
||||||
|
for (let i = 0; i < a.length; i++) {
|
||||||
|
let id = this._ans.getItemAnnotation(a[i], "weave/mounted-share-id");
|
||||||
|
ret.push(this._wrapMount(this._getNode(a[i]), id));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
|
||||||
wrap: function BStore_wrap() {
|
wrap: function BStore_wrap() {
|
||||||
var items = {};
|
var items = {};
|
||||||
this._wrap(this._getNode(this._bms.bookmarksMenuFolder), items, "menu");
|
this._wrap(this._getNode(this._bms.bookmarksMenuFolder), items, "menu");
|
||||||
|
|
Загрузка…
Ссылка в новой задаче