Bug 1368560 part 2 - Move Svc.Crypto to Weave.Crypto. r=markh
authorEdouard Oger <eoger@fastmail.com>
Mon, 29 May 2017 13:24:01 -0400
changeset 361926 d71442ad6f31e3b5053e64adf5ed5765cb4bc025
parent 361925 732d5e2ec5d77c829d22f40669b8927b7a257d25
child 361927 bf5e8ffae40db7b2c2afcb1851fb8eb80b98e5b6
push id31952
push usercbook@mozilla.com
push dateFri, 02 Jun 2017 12:17:25 +0000
treeherdermozilla-central@194c009d6295 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmarkh
bugs1368560
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1368560 part 2 - Move Svc.Crypto to Weave.Crypto. r=markh MozReview-Commit-ID: 74IFsVjZSgz
services/sync/modules-testing/fakeservices.js
services/sync/modules/keys.js
services/sync/modules/main.js
services/sync/modules/record.js
services/sync/modules/service.js
services/sync/modules/util.js
services/sync/tests/unit/test_bookmark_order.js
services/sync/tests/unit/test_corrupt_keys.js
services/sync/tests/unit/test_keys.js
services/sync/tests/unit/test_syncengine_sync.js
toolkit/components/extensions/ExtensionStorageSync.jsm
--- a/services/sync/modules-testing/fakeservices.js
+++ b/services/sync/modules-testing/fakeservices.js
@@ -8,16 +8,17 @@ this.EXPORTED_SYMBOLS = [
   "FakeCryptoService",
   "FakeFilesystemService",
   "FakeGUIDService",
   "fakeSHA256HMAC",
 ];
 
 var {utils: Cu} = Components;
 
+Cu.import("resource://services-sync/main.js");
 Cu.import("resource://services-sync/record.js");
 Cu.import("resource://services-sync/util.js");
 
 var btoa = Cu.import("resource://gre/modules/Log.jsm").btoa;
 
 this.FakeFilesystemService = function FakeFilesystemService(contents) {
   this.fakeContents = contents;
   let self = this;
@@ -90,18 +91,18 @@ this.FakeGUIDService = function FakeGUID
 
 /*
  * Mock implementation of WeaveCrypto. It does not encrypt or
  * decrypt, merely returning the input verbatim.
  */
 this.FakeCryptoService = function FakeCryptoService() {
   this.counter = 0;
 
-  delete Svc.Crypto;  // get rid of the getter first
-  Svc.Crypto = this;
+  delete Weave.Crypto;  // get rid of the getter first
+  Weave.Crypto = this;
 
   CryptoWrapper.prototype.ciphertextHMAC = function ciphertextHMAC(keyBundle) {
     return fakeSHA256HMAC(this.ciphertext);
   };
 }
 FakeCryptoService.prototype = {
 
   encrypt: function encrypt(clearText, symmetricKey, iv) {
--- a/services/sync/modules/keys.js
+++ b/services/sync/modules/keys.js
@@ -8,16 +8,17 @@ this.EXPORTED_SYMBOLS = [
   "BulkKeyBundle",
   "SyncKeyBundle"
 ];
 
 var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://gre/modules/Log.jsm");
+Cu.import("resource://services-sync/main.js");
 Cu.import("resource://services-sync/util.js");
 
 /**
  * Represents a pair of keys.
  *
  * Each key stored in a key bundle is 256 bits. One key is used for symmetric
  * encryption. The other is used for HMAC.
  *
@@ -102,18 +103,18 @@ KeyBundle.prototype = {
   get sha256HMACHasher() {
     return this._sha256HMACHasher;
   },
 
   /**
    * Populate this key pair with 2 new, randomly generated keys.
    */
   generateRandom: function generateRandom() {
-    let generatedHMAC = Svc.Crypto.generateRandomKey();
-    let generatedEncr = Svc.Crypto.generateRandomKey();
+    let generatedHMAC = Weave.Crypto.generateRandomKey();
+    let generatedEncr = Weave.Crypto.generateRandomKey();
     this.keyPairB64 = [generatedEncr, generatedHMAC];
   },
 
 };
 
 /**
  * Represents a KeyBundle associated with a collection.
  *
--- a/services/sync/modules/main.js
+++ b/services/sync/modules/main.js
@@ -1,29 +1,38 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 this.EXPORTED_SYMBOLS = ["Weave"];
 
+const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
 this.Weave = {};
-Components.utils.import("resource://services-sync/constants.js", Weave);
+Cu.import("resource://services-sync/constants.js", Weave);
 var lazies = {
   "service.js":           ["Service"],
   "status.js":            ["Status"],
   "util.js":              ["Utils", "Svc"]
 };
 
 function lazyImport(module, dest, props) {
   function getter(prop) {
     return function() {
       let ns = {};
-      Components.utils.import(module, ns);
+      Cu.import(module, ns);
       delete dest[prop];
       return dest[prop] = ns[prop];
     };
   }
   props.forEach(function(prop) { dest.__defineGetter__(prop, getter(prop)); });
 }
 
 for (let mod in lazies) {
   lazyImport("resource://services-sync/" + mod, Weave, lazies[mod]);
 }
+
+XPCOMUtils.defineLazyGetter(Weave, "Crypto", function() {
+  let { WeaveCrypto } = Cu.import("resource://services-crypto/WeaveCrypto.js", {});
+  return new WeaveCrypto();
+});
--- a/services/sync/modules/record.js
+++ b/services/sync/modules/record.js
@@ -16,16 +16,17 @@ var Cr = Components.results;
 var Cu = Components.utils;
 
 const CRYPTO_COLLECTION = "crypto";
 const KEYS_WBO = "keys";
 
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/keys.js");
+Cu.import("resource://services-sync/main.js");
 Cu.import("resource://services-sync/resource.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-common/async.js");
 
 this.WBORecord = function WBORecord(collection, id) {
   this.data = {};
   this.payload = {};
   this.collection = collection;      // Optional.
@@ -134,19 +135,19 @@ CryptoWrapper.prototype = {
    *
    * Optional key bundle overrides the collection key lookup.
    */
   encrypt: function encrypt(keyBundle) {
     if (!keyBundle) {
       throw new Error("A key bundle must be supplied to encrypt.");
     }
 
-    this.IV = Svc.Crypto.generateRandomIV();
-    this.ciphertext = Svc.Crypto.encrypt(JSON.stringify(this.cleartext),
-                                         keyBundle.encryptionKeyB64, this.IV);
+    this.IV = Weave.Crypto.generateRandomIV();
+    this.ciphertext = Weave.Crypto.encrypt(JSON.stringify(this.cleartext),
+                                           keyBundle.encryptionKeyB64, this.IV);
     this.hmac = this.ciphertextHMAC(keyBundle);
     this.cleartext = null;
   },
 
   // Optional key bundle.
   decrypt: function decrypt(keyBundle) {
     if (!this.ciphertext) {
       throw "No ciphertext: nothing to decrypt?";
@@ -159,18 +160,18 @@ CryptoWrapper.prototype = {
     // Authenticate the encrypted blob with the expected HMAC
     let computedHMAC = this.ciphertextHMAC(keyBundle);
 
     if (computedHMAC != this.hmac) {
       Utils.throwHMACMismatch(this.hmac, computedHMAC);
     }
 
     // Handle invalid data here. Elsewhere we assume that cleartext is an object.
-    let cleartext = Svc.Crypto.decrypt(this.ciphertext,
-                                       keyBundle.encryptionKeyB64, this.IV);
+    let cleartext = Weave.Crypto.decrypt(this.ciphertext,
+                                         keyBundle.encryptionKeyB64, this.IV);
     let json_result = JSON.parse(cleartext);
 
     if (json_result && (json_result instanceof Object)) {
       this.cleartext = json_result;
       this.ciphertext = null;
     } else {
       throw "Decryption failed: result is <" + json_result + ">, not an object.";
     }
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -20,16 +20,17 @@ const KEYS_WBO = "keys";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://services-common/async.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/engines/clients.js");
+Cu.import("resource://services-sync/main.js");
 Cu.import("resource://services-sync/policies.js");
 Cu.import("resource://services-sync/record.js");
 Cu.import("resource://services-sync/resource.js");
 Cu.import("resource://services-sync/rest.js");
 Cu.import("resource://services-sync/stages/enginesync.js");
 Cu.import("resource://services-sync/stages/declined.js");
 Cu.import("resource://services-sync/status.js");
 Cu.import("resource://services-sync/telemetry.js");
@@ -148,17 +149,17 @@ Sync11Service.prototype = {
     this.metaURL = this.storageURL + "meta/global";
     this.cryptoKeysURL = this.storageURL + CRYPTO_COLLECTION + "/" + KEYS_WBO;
   },
 
   _checkCrypto: function _checkCrypto() {
     let ok = false;
 
     try {
-      let iv = Svc.Crypto.generateRandomIV();
+      let iv = Weave.Crypto.generateRandomIV();
       if (iv.length == 24)
         ok = true;
 
     } catch (e) {
       this._log.debug("Crypto check failed: " + e);
     }
 
     return ok;
--- a/services/sync/modules/util.js
+++ b/services/sync/modules/util.js
@@ -636,21 +636,12 @@ XPCOMUtils.defineLazyGetter(Utils, "_utf
 
 /*
  * Commonly-used services
  */
 this.Svc = {};
 Svc.Prefs = new Preferences(PREFS_BRANCH);
 Svc.Obs = Observers;
 
-Svc.__defineGetter__("Crypto", function() {
-  let cryptoSvc;
-  let ns = {};
-  Cu.import("resource://services-crypto/WeaveCrypto.js", ns);
-  cryptoSvc = new ns.WeaveCrypto();
-  delete Svc.Crypto;
-  return Svc.Crypto = cryptoSvc;
-});
-
 Svc.Obs.add("xpcom-shutdown", function() {
   for (let name in Svc)
     delete Svc[name];
 });
--- a/services/sync/tests/unit/test_bookmark_order.js
+++ b/services/sync/tests/unit/test_bookmark_order.js
@@ -1,14 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 _("Making sure after processing incoming bookmarks, they show up in the right order");
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://services-sync/engines/bookmarks.js");
+Cu.import("resource://services-sync/main.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
 
 function run_test() {
   Svc.Prefs.set("log.logger.engine.bookmarks", "Trace");
   initTestLogging("Trace");
   Log.repository.getLogger("Sqlite").level = Log.Level.Info;
@@ -38,18 +39,18 @@ function serverForFoo(engine) {
       },
     },
     crypto: {
       keys: encryptPayload({
         id: "keys",
         // Generate a fake default key bundle to avoid resetting the client
         // before the first sync.
         default: [
-          Svc.Crypto.generateRandomKey(),
-          Svc.Crypto.generateRandomKey(),
+          Weave.Crypto.generateRandomKey(),
+          Weave.Crypto.generateRandomKey(),
         ],
       }),
     },
     [engine.name]: {},
   });
 }
 
 async function resolveConflict(engine, collection, timestamp, buildTree,
--- a/services/sync/tests/unit/test_corrupt_keys.js
+++ b/services/sync/tests/unit/test_corrupt_keys.js
@@ -1,14 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/engines.js");
+Cu.import("resource://services-sync/main.js");
 Cu.import("resource://services-sync/engines/tabs.js");
 Cu.import("resource://services-sync/engines/history.js");
 Cu.import("resource://services-sync/record.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/status.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
 
@@ -40,18 +41,18 @@ add_task(async function test_locally_cha
     await configureIdentity({ username: "johndoe" }, server);
     // We aren't doing a .login yet, so fudge the cluster URL.
     Service.clusterURL = Service.identity._token.endpoint;
 
     Service.engineManager.register(HistoryEngine);
     Service.engineManager.unregister("addons");
 
     function corrupt_local_keys() {
-      Service.collectionKeys._default.keyPair = [Svc.Crypto.generateRandomKey(),
-                                                 Svc.Crypto.generateRandomKey()];
+      Service.collectionKeys._default.keyPair = [Weave.Crypto.generateRandomKey(),
+                                                 Weave.Crypto.generateRandomKey()];
     }
 
     _("Setting meta.");
 
     // Bump version on the server.
     let m = new WBORecord("meta", "global");
     m.payload = {"syncID": "foooooooooooooooooooooooooo",
                  "storageVersion": STORAGE_VERSION};
--- a/services/sync/tests/unit/test_keys.js
+++ b/services/sync/tests/unit/test_keys.js
@@ -1,13 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/keys.js");
+Cu.import("resource://services-sync/main.js");
 Cu.import("resource://services-sync/record.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-sync/browserid_identity.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
 
 var collectionKeys = new CollectionKeyManager();
 
 function sha256HMAC(message, key) {
@@ -178,20 +179,20 @@ add_task(async function test_ensureLogge
   /*
    * Build a test version of storage/crypto/keys.
    * Encrypt it with the sync key.
    * Pass it into the CollectionKeyManager.
    */
 
   log.info("Building storage keys...");
   let storage_keys = new CryptoWrapper("crypto", "keys");
-  let default_key64 = Svc.Crypto.generateRandomKey();
-  let default_hmac64 = Svc.Crypto.generateRandomKey();
-  let bookmarks_key64 = Svc.Crypto.generateRandomKey();
-  let bookmarks_hmac64 = Svc.Crypto.generateRandomKey();
+  let default_key64 = Weave.Crypto.generateRandomKey();
+  let default_hmac64 = Weave.Crypto.generateRandomKey();
+  let bookmarks_key64 = Weave.Crypto.generateRandomKey();
+  let bookmarks_hmac64 = Weave.Crypto.generateRandomKey();
 
   storage_keys.cleartext = {
     "default": [default_key64, default_hmac64],
     "collections": {"bookmarks": [bookmarks_key64, bookmarks_hmac64]},
   };
   storage_keys.modified = Date.now() / 1000;
   storage_keys.id = "keys";
 
--- a/services/sync/tests/unit/test_syncengine_sync.js
+++ b/services/sync/tests/unit/test_syncengine_sync.js
@@ -1,13 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/engines.js");
+Cu.import("resource://services-sync/main.js");
 Cu.import("resource://services-sync/policies.js");
 Cu.import("resource://services-sync/record.js");
 Cu.import("resource://services-sync/resource.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://testing-common/services/sync/rotaryengine.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
 
@@ -1082,18 +1083,18 @@ add_task(async function test_processInco
   collection._wbos.nojson2 = new ServerWBO("nojson2", "This is invalid JSON");
   collection._wbos.scotsman = new ServerWBO(
       "scotsman", encryptPayload({id: "scotsman",
                                   denomination: "Flying Scotsman"}));
   collection._wbos.nodecrypt = new ServerWBO("nodecrypt", "Decrypt this!");
   collection._wbos.nodecrypt2 = new ServerWBO("nodecrypt2", "Decrypt this!");
 
   // Patch the fake crypto service to throw on the record above.
-  Svc.Crypto._decrypt = Svc.Crypto.decrypt;
-  Svc.Crypto.decrypt = function(ciphertext) {
+  Weave.Crypto._decrypt = Weave.Crypto.decrypt;
+  Weave.Crypto.decrypt = function(ciphertext) {
     if (ciphertext == "Decrypt this!") {
       throw "Derp! Cipher finalized failed. Im ur crypto destroyin ur recordz.";
     }
     return this._decrypt.apply(this, arguments);
   };
 
   // Some broken records also exist locally.
   let engine = makeRotaryEngine();
--- a/toolkit/components/extensions/ExtensionStorageSync.jsm
+++ b/toolkit/components/extensions/ExtensionStorageSync.jsm
@@ -68,25 +68,28 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "Log",
                                   "resource://gre/modules/Log.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Observers",
                                   "resource://services-common/observers.js");
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Sqlite",
                                   "resource://gre/modules/Sqlite.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Svc",
-                                  "resource://services-sync/util.js");
 XPCOMUtils.defineLazyModuleGetter(this, "Utils",
                                   "resource://services-sync/util.js");
 XPCOMUtils.defineLazyPreferenceGetter(this, "prefPermitsStorageSync",
                                       STORAGE_SYNC_ENABLED_PREF, true);
 XPCOMUtils.defineLazyPreferenceGetter(this, "prefStorageSyncServerURL",
                                       STORAGE_SYNC_SERVER_URL_PREF,
                                       KINTO_DEFAULT_SERVER_URL);
+XPCOMUtils.defineLazyGetter(this, "WeaveCrypto", function() {
+  let {WeaveCrypto} = Cu.import("resource://services-crypto/WeaveCrypto.js", {});
+  return new WeaveCrypto();
+});
+
 const {
   runSafeSyncWithoutClone,
 } = ExtensionUtils;
 
 // Map of Extensions to Set<Contexts> to track contexts that are still
 // "live" and use storage.sync.
 const extensionContexts = new Map();
 // Borrow logger from Sync.
@@ -175,19 +178,19 @@ class EncryptionRemoteTransformer {
     if (record.ciphertext) {
       throw new Error("Attempt to reencrypt??");
     }
     let id = await this.getEncodedRecordId(record);
     if (!id) {
       throw new Error("Record ID is missing or invalid");
     }
 
-    let IV = Svc.Crypto.generateRandomIV();
-    let ciphertext = Svc.Crypto.encrypt(JSON.stringify(record),
-                                        keyBundle.encryptionKeyB64, IV);
+    let IV = WeaveCrypto.generateRandomIV();
+    let ciphertext = WeaveCrypto.encrypt(JSON.stringify(record),
+                                         keyBundle.encryptionKeyB64, IV);
     let hmac = ciphertextHMAC(keyBundle, id, IV, ciphertext);
     const encryptedResult = {ciphertext, IV, hmac, id};
 
     // Copy over the _status field, so that we handle concurrency
     // headers (If-Match, If-None-Match) correctly.
     // DON'T copy over "deleted" status, because then we'd leak
     // plaintext deletes.
     encryptedResult._status = record._status == "deleted" ? "updated" : record._status;
@@ -210,18 +213,18 @@ class EncryptionRemoteTransformer {
     // Authenticate the encrypted blob with the expected HMAC
     let computedHMAC = ciphertextHMAC(keyBundle, record.id, record.IV, record.ciphertext);
 
     if (computedHMAC != record.hmac) {
       Utils.throwHMACMismatch(record.hmac, computedHMAC);
     }
 
     // Handle invalid data here. Elsewhere we assume that cleartext is an object.
-    let cleartext = Svc.Crypto.decrypt(record.ciphertext,
-                                       keyBundle.encryptionKeyB64, record.IV);
+    let cleartext = WeaveCrypto.decrypt(record.ciphertext,
+                                        keyBundle.encryptionKeyB64, record.IV);
     let jsonResult = JSON.parse(cleartext);
     if (!jsonResult || typeof jsonResult !== "object") {
       throw new Error("Decryption failed: result is <" + jsonResult + ">, not an object.");
     }
 
     if (record.hasOwnProperty("last_modified")) {
       jsonResult.last_modified = record.last_modified;
     }