Make {en,de}cryption asynchronous so as to not block the UI; fix 'xxxtea' typos (it's xxtea); fix auth header suppression
authorDan Mills <thunder@mozilla.com>
Wed, 26 Dec 2007 17:40:46 -0800
changeset 44339 0ffb5145ded73ff8c9d6cb97d1e98778131b5d76
parent 44338 ac29ea114a9600b5d0737730b017399db4b89d66
child 44340 baffd3772813aaba726a24415f63af559c909e4a
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)
Make {en,de}cryption asynchronous so as to not block the UI; fix 'xxxtea' typos (it's xxtea); fix auth header suppression
services/sync/modules/crypto.js
services/sync/modules/dav.js
services/sync/modules/engines.js
services/sync/modules/syncCores.js
services/sync/services-sync.js
--- a/services/sync/modules/crypto.js
+++ b/services/sync/modules/crypto.js
@@ -41,38 +41,40 @@ const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://weave/log4moz.js");
 Cu.import("resource://weave/constants.js");
 Cu.import("resource://weave/util.js");
 
+Function.prototype.async = generatorAsync;
+
 function WeaveCrypto() {
   this._init();
 }
 WeaveCrypto.prototype = {
   _logName: "Crypto",
 
   __os: null,
   get _os() {
     if (!this.__os)
       this.__os = Cc["@mozilla.org/observer-service;1"]
         .getService(Ci.nsIObserverService);
     return this.__os;
   },
 
-  __xxxtea: {},
-  __xxxteaLoaded: false,
-  get _xxxtea() {
-    if (!this.__xxxteaLoaded) {
-      Cu.import("resource://weave/xxxtea.js", this.__xxxtea);
-      this.__xxxteaLoaded = true;
+  __xxtea: {},
+  __xxteaLoaded: false,
+  get _xxtea() {
+    if (!this.__xxteaLoaded) {
+      Cu.import("resource://weave/xxtea.js", this.__xxtea);
+      this.__xxteaLoaded = true;
     }
-    return this.__xxxtea;
+    return this.__xxtea;
   },
 
   get defaultAlgorithm() {
     let branch = Cc["@mozilla.org/preferences-service;1"]
       .getService(Ci.nsIPrefBranch);
     return branch.getCharPref("extensions.weave.encryption");
   },
   set defaultAlgorithm(value) {
@@ -103,82 +105,109 @@ WeaveCrypto.prototype = {
       let cur = branch.getCharPref("extensions.weave.encryption");
       if (cur == data)
 	return;
 
       switch (data) {
       case "none":
         this._log.info("Encryption disabled");
         break;
-      case "XXXTEA":
+      case "XXTEA":
+      case "XXXTEA": // Weave 0.1 had this typo
         this._log.info("Using encryption algorithm: " + data);
         break;
       default:
 	this._log.warn("Unknown encryption algorithm, resetting");
-	branch.setCharPref("extensions.weave.encryption", "XXXTEA");
+	branch.setCharPref("extensions.weave.encryption", "XXTEA");
 	return; // otherwise we'll send the alg changed event twice
       }
       // FIXME: listen to this bad boy somewhere
       this._os.notifyObservers(null, "weave:encryption:algorithm-changed", "");
       break;
     default:
       this._log.warn("Unknown encryption preference changed - ignoring");
     }
   },
 
   // Crypto
 
-  PBEencrypt: function Crypto_PBEencrypt(data, identity, algorithm) {
-    if (!algorithm)
-      algorithm = this.defaultAlgorithm;
+  PBEencrypt: function Crypto_PBEencrypt(onComplete, data, identity, algorithm) {
+    let [self, cont] = yield;
+    let listener = new EventListener(cont);
+    let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    let ret;
 
-    if (algorithm == "none") // check to skip the 'encrypting data' log msgs
-      return data;
-
-    let out;
     try {
-      this._log.debug("Encrypting data");
+      if (!algorithm)
+        algorithm = this.defaultAlgorithm;
 
       switch (algorithm) {
-      case "XXXTEA":
-        out = this._xxxtea.encrypt(data, identity.password);
+      case "none":
+        ret = data;
+      case "XXTEA":
+      case "XXXTEA": // Weave 0.1.12.10 and below had this typo
+        this._log.debug("Encrypting data");
+        let gen = this._xxtea.encrypt(data, identity.password);
+        ret = gen.next();
+        while (typeof(ret) == "object") {
+          timer.initWithCallback(listener, 0, timer.TYPE_ONE_SHOT);
+          yield; // Yield to main loop
+          ret = gen.next();
+        }
+        gen.close();
+        this._log.debug("Done encrypting data");
         break;
       default:
         throw "Unknown encryption algorithm: " + algorithm;
       }
 
-      this._log.debug("Done encrypting data");
+    } catch (e) {
+      this._log.error("Exception caught: " + (e.message? e.message : e));
 
-    } catch (e) {
-      this._log.error("Data encryption failed: " + e);
-      throw 'encrypt failed';
+    } finally {
+      timer = null;
+      generatorDone(this, self, onComplete, ret);
+      yield; // onComplete is responsible for closing the generator
     }
-    return out;
+    this._log.warn("generator not properly closed");
   },
 
-  PBEdecrypt: function Crypto_PBEdecrypt(data, identity, algorithm) {
-    if (!algorithm)
-      algorithm = this.defaultAlgorithm;
+  PBEdecrypt: function Crypto_PBEdecrypt(onComplete, data, identity, algorithm) {
+    let [self, cont] = yield;
+    let listener = new EventListener(cont);
+    let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    let ret;
 
-    if (algorithm == "none") // check to skip the 'decrypting data' log msgs
-      return data;
-
-    let out;
     try {
-      this._log.debug("Decrypting data");
+      if (!algorithm)
+        algorithm = this.defaultAlgorithm;
 
       switch (algorithm) {
-      case "XXXTEA":
-        out = this._xxxtea.decrypt(data, identity.password);
+      case "none":
+        ret = data;
+      case "XXTEA":
+      case "XXXTEA": // Weave 0.1.12.10 and below had this typo
+        this._log.debug("Decrypting data");
+        let gen = this._xxtea.decrypt(data, identity.password);
+        ret = gen.next();
+        while (typeof(ret) == "object") {
+          timer.initWithCallback(listener, 0, timer.TYPE_ONE_SHOT);
+          yield; // Yield to main loop
+          ret = gen.next();
+        }
+        gen.close();
+        this._log.debug("Done decrypting data");
         break;
       default:
         throw "Unknown encryption algorithm: " + algorithm;
       }
 
-      this._log.debug("Done decrypting data");
+    } catch (e) {
+      this._log.error("Exception caught: " + (e.message? e.message : e));
 
-    } catch (e) {
-      this._log.error("Data decryption failed: " + e);
-      throw 'decrypt failed';
+    } finally {
+      timer = null;
+      generatorDone(this, self, onComplete, ret);
+      yield; // onComplete is responsible for closing the generator
     }
-    return out;
+    this._log.warn("generator not properly closed");
   }
 };
--- a/services/sync/modules/dav.js
+++ b/services/sync/modules/dav.js
@@ -100,17 +100,17 @@ DAVCollection.prototype = {
       let channel = request.channel;
       channel = channel.QueryInterface(Ci.nsIRequest);
       let loadFlags = channel.loadFlags;
       loadFlags |= Ci.nsIRequest.VALIDATE_ALWAYS;
       channel.loadFlags = loadFlags;
 
       let key;
       for (key in headers) {
-        if (key == 'Authentication')
+        if (key == 'Authorization')
           this._log.debug("HTTP Header " + key + ": ***** (suppressed)");
         else
           this._log.debug("HTTP Header " + key + ": " + headers[key]);
         request.setRequestHeader(key, headers[key]);
       }
   
       this._authProvider._authFailed = false;
       request.channel.notificationCallbacks = this._authProvider;
--- a/services/sync/modules/engines.js
+++ b/services/sync/modules/engines.js
@@ -382,18 +382,20 @@ Engine.prototype = {
         if (server.formatVersion != STORAGE_FORMAT_VERSION ||
             this._encryptionChanged) {
           this._fullUpload.async(this, cont);
           let status = yield;
           if (!status)
             this._log.error("Could not upload files to server"); // eep?
 
         } else {
-	  let data = Crypto.PBEencrypt(serializeCommands(server.deltas),
-				       this._cryptoId);
+	  Crypto.PBEencrypt.async(Crypto, cont,
+                                  serializeCommands(server.deltas),
+				  this._cryptoId);
+          let data = yield;
           this._dav.PUT(this.deltasFile, data, cont);
           let deltasPut = yield;
 
           let c = 0;
           for (GUID in this._snapshot.data)
             c++;
 
           this._dav.PUT(this.statusFile,
@@ -514,56 +516,64 @@ Engine.prototype = {
         if (this._snapshot.version < status.snapVersion) {
           if (this._snapshot.version >= 0)
             this._log.info("Local snapshot is out of date");
   
           this._log.info("Downloading server snapshot");
           this._dav.GET(this.snapshotFile, cont);
           resp = yield;
           this._checkStatus(resp.status, "Could not download snapshot.");
-          let data = Crypto.PBEdecrypt(resp.responseText,
-				       this._cryptoId,
-				       status.snapEncryption);
+          Crypto.PBEdecrypt.async(Crypto, cont,
+                                  resp.responseText,
+				  this._cryptoId,
+				  status.snapEncryption);
+          let data = yield;
           snap.data = eval(data);
 
           this._log.info("Downloading server deltas");
           this._dav.GET(this.deltasFile, cont);
           resp = yield;
           this._checkStatus(resp.status, "Could not download deltas.");
-          data = Crypto.PBEdecrypt(resp.responseText,
-				   this._cryptoId,
-				   status.deltasEncryption);
+          Crypto.PBEdecrypt.async(Crypto, cont,
+                                  resp.responseText,
+				  this._cryptoId,
+				  status.deltasEncryption);
+          data = yield;
           allDeltas = eval(data);
           deltas = eval(data);
   
         } else if (this._snapshot.version >= status.snapVersion &&
                    this._snapshot.version < status.maxVersion) {
           snap.data = eval(uneval(this._snapshot.data));
   
           this._log.info("Downloading server deltas");
           this._dav.GET(this.deltasFile, cont);
           resp = yield;
           this._checkStatus(resp.status, "Could not download deltas.");
-          let data = Crypto.PBEdecrypt(resp.responseText,
-				       this._cryptoId,
-				       status.deltasEncryption);
+          Crypto.PBEdecrypt.async(Crypto, cont,
+                                  resp.responseText,
+				  this._cryptoId,
+				  status.deltasEncryption);
+          let data = yield;
           allDeltas = eval(data);
           deltas = allDeltas.slice(this._snapshot.version - status.snapVersion);
   
         } else if (this._snapshot.version == status.maxVersion) {
           snap.data = eval(uneval(this._snapshot.data));
   
           // FIXME: could optimize this case by caching deltas file
           this._log.info("Downloading server deltas");
           this._dav.GET(this.deltasFile, cont);
           resp = yield;
           this._checkStatus(resp.status, "Could not download deltas.");
-          let data = Crypto.PBEdecrypt(resp.responseText,
-				       this._cryptoId,
-				       status.deltasEncryption);
+          Crypto.PBEdecrypt.async(Crypto, cont,
+                                  resp.responseText,
+				  this._cryptoId,
+				  status.deltasEncryption);
+          let data = yield;
           allDeltas = eval(data);
           deltas = [];
   
         } else { // this._snapshot.version > status.maxVersion
           this._log.error("Server snapshot is older than local snapshot");
           return;
         }
   
@@ -627,18 +637,20 @@ Engine.prototype = {
     this._log.warn("generator not properly closed");
   },
 
   _fullUpload: function Engine__fullUpload(onComplete) {
     let [self, cont] = yield;
     let ret = false;
 
     try {
-      let data = Crypto.PBEencrypt(this._snapshot.serialize(),
-				   this._cryptoId);
+      Crypto.PBEencrypt.async(Crypto, cont,
+                              this._snapshot.serialize(),
+			      this._cryptoId);
+      let data = yield;
       this._dav.PUT(this.snapshotFile, data, cont);
       resp = yield;
       this._checkStatus(resp.status, "Could not upload snapshot.");
 
       this._dav.PUT(this.deltasFile, uneval([]), cont);
       resp = yield;
       this._checkStatus(resp.status, "Could not upload deltas.");
 
--- a/services/sync/modules/syncCores.js
+++ b/services/sync/modules/syncCores.js
@@ -136,17 +136,17 @@ SyncCore.prototype = {
         if (a.index > b.index)
           return -1;
         if (a.index < b.index)
           return 1;
         return 0; // should never happen, but not a big deal if it does
       });
 
     } catch (e) {
-      this._log.error("Exception caught: " + e.message);
+      this._log.error("Exception caught: " + (e.message? e.message : e));
 
     } finally {
       timer = null;
       generatorDone(this, self, onComplete, cmds);
       yield; // onComplete is responsible for closing the generator
     }
     this._log.warn("generator not properly closed");
   },
@@ -292,17 +292,17 @@ SyncCore.prototype = {
   
       timer.initWithCallback(listener, 0, timer.TYPE_ONE_SHOT);
       yield; // Yield to main loop
   
       this._getPropagations(listB, conflicts[1], propagations[0]);
       ret = {propagations: propagations, conflicts: conflicts};
 
     } catch (e) {
-      this._log.error("Exception caught: " + e.message);
+      this._log.error("Exception caught: " + (e.message? e.message : e));
 
     } finally {
       timer = null;
       generatorDone(this, self, onComplete, ret);
       yield; // onComplete is responsible for closing the generator
     }
     this._log.warn("generator not properly closed");
   },
--- a/services/sync/services-sync.js
+++ b/services/sync/services-sync.js
@@ -3,9 +3,9 @@ pref("extensions.weave.username", "nobod
 pref("extensions.weave.lastversion", "firstrun");
 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.schedule", 1);
 pref("extensions.weave.lastsync", "0");
-pref("extensions.weave.encryption", "XXXTEA");
+pref("extensions.weave.encryption", "XXTEA");