Bug 1380094 - services/sync changes to support formautofill r?markh draft
authorThom Chiovoloni <tchiovoloni@mozilla.com>
Tue, 11 Jul 2017 15:15:37 -0400
changeset 607638 d7ebb0d27a2b598f0f49624d78bb4daa9cc6bcce
parent 607637 bf68dcdb77730cab02023941ab4acc7b91df4cdd
child 637100 0bcebcc0fd4cc44bba736aae37f1205c01037f2c
push id68059
push userbmo:tchiovoloni@mozilla.com
push dateWed, 12 Jul 2017 16:16:36 +0000
reviewersmarkh
bugs1380094
milestone56.0a1
Bug 1380094 - services/sync changes to support formautofill r?markh MozReview-Commit-ID: BdsrrFOU5ec
services/sync/modules/record.js
services/sync/modules/service.js
services/sync/modules/telemetry.js
services/sync/services-sync.js
services/sync/tests/unit/head_helpers.js
--- a/services/sync/modules/record.js
+++ b/services/sync/modules/record.js
@@ -178,18 +178,22 @@ CryptoWrapper.prototype = {
 
     // Verify that the encrypted id matches the requested record's id.
     if (this.cleartext.id != this.id)
       throw "Record id mismatch: " + this.cleartext.id + " != " + this.id;
 
     return this.cleartext;
   },
 
+  cleartextToString() {
+    return JSON.stringify(this.cleartext);
+  },
+
   toString: function toString() {
-    let payload = this.deleted ? "DELETED" : JSON.stringify(this.cleartext);
+    let payload = this.deleted ? "DELETED" : this.cleartextToString();
 
     return "{ " +
       "id: " + this.id + "  " +
       "index: " + this.sortindex + "  " +
       "modified: " + this.modified + "  " +
       "ttl: " + this.ttl + "  " +
       "payload: " + payload + "  " +
       "collection: " + (this.collection || "undefined") +
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -31,26 +31,41 @@ Cu.import("resource://services-sync/reco
 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");
 Cu.import("resource://services-sync/util.js");
 
-const ENGINE_MODULES = {
-  Addons: {module: "addons.js", symbol: "AddonsEngine"},
-  Bookmarks: {module: "bookmarks.js", symbol: "BookmarksEngine"},
-  Form: {module: "forms.js", symbol: "FormEngine"},
-  History: {module: "history.js", symbol: "HistoryEngine"},
-  Password: {module: "passwords.js", symbol: "PasswordEngine"},
-  Prefs: {module: "prefs.js", symbol: "PrefsEngine"},
-  Tab: {module: "tabs.js", symbol: "TabEngine"},
-  ExtensionStorage: {module: "extension-storage.js", symbol: "ExtensionStorageEngine"},
-};
+function getEngineModules() {
+  let result = {
+    Addons: {module: "addons.js", symbol: "AddonsEngine"},
+    Bookmarks: {module: "bookmarks.js", symbol: "BookmarksEngine"},
+    Form: {module: "forms.js", symbol: "FormEngine"},
+    History: {module: "history.js", symbol: "HistoryEngine"},
+    Password: {module: "passwords.js", symbol: "PasswordEngine"},
+    Prefs: {module: "prefs.js", symbol: "PrefsEngine"},
+    Tab: {module: "tabs.js", symbol: "TabEngine"},
+    ExtensionStorage: {module: "extension-storage.js", symbol: "ExtensionStorageEngine"},
+  }
+  if (Svc.Prefs.get("engine.addresses.available", false)) {
+    result["Addresses"] = {
+      module: "resource://formautofill/FormAutofillSync.jsm",
+      symbol: "AddressesEngine",
+    };
+  }
+  if (Svc.Prefs.get("engine.creditcards.available", false)) {
+    result["CreditCards"] = {
+      module: "resource://formautofill/FormAutofillSync.jsm",
+      symbol: "CreditCardsEngine",
+    };
+  }
+  return result;
+}
 
 const STORAGE_INFO_TYPES = [INFO_COLLECTIONS,
                             INFO_COLLECTION_USAGE,
                             INFO_COLLECTION_COUNTS,
                             INFO_QUOTA];
 
 // A unique identifier for this browser session. Used for logging so
 // we can easily see whether 2 logs are in the same browser session or
@@ -350,45 +365,47 @@ Sync11Service.prototype = {
   },
 
   /**
    * Register the built-in engines for certain applications
    */
   async _registerEngines() {
     this.engineManager = new EngineManager(this);
 
+    let engineModules = getEngineModules();
+
     let engines = [];
     // We allow a pref, which has no default value, to limit the engines
     // which are registered. We expect only tests will use this.
     if (Svc.Prefs.has("registerEngines")) {
       engines = Svc.Prefs.get("registerEngines").split(",");
       this._log.info("Registering custom set of engines", engines);
     } else {
       // default is all engines.
-      engines = Object.keys(ENGINE_MODULES);
+      engines = Object.keys(engineModules);
     }
 
     let declined = [];
     let pref = Svc.Prefs.get("declinedEngines");
     if (pref) {
       declined = pref.split(",");
     }
 
     let clientsEngine = new ClientEngine(this);
     // Ideally clientsEngine should not exist
     // (or be a promise that calls initialize() before returning the engine)
     await clientsEngine.initialize();
     this.clientsEngine = clientsEngine;
 
     for (let name of engines) {
-      if (!(name in ENGINE_MODULES)) {
+      if (!(name in engineModules)) {
         this._log.info("Do not know about engine: " + name);
         continue;
       }
-      let {module, symbol} = ENGINE_MODULES[name];
+      let {module, symbol} = engineModules[name];
       if (!module.includes(":")) {
         module = "resource://services-sync/engines/" + module;
       }
       let ns = {};
       try {
         Cu.import(module, ns);
         if (!(symbol in ns)) {
           this._log.warn("Could not find exported engine instance: " + symbol);
--- a/services/sync/modules/telemetry.js
+++ b/services/sync/modules/telemetry.js
@@ -55,17 +55,18 @@ const TOPICS = [
 ];
 
 const PING_FORMAT_VERSION = 1;
 
 const EMPTY_UID = "0".repeat(32);
 
 // The set of engines we record telemetry for - any other engines are ignored.
 const ENGINES = new Set(["addons", "bookmarks", "clients", "forms", "history",
-                         "passwords", "prefs", "tabs", "extension-storage"]);
+                         "passwords", "prefs", "tabs", "extension-storage",
+                         "addresses", "creditcards"]);
 
 // A regex we can use to replace the profile dir in error messages. We use a
 // regexp so we can simply replace all case-insensitive occurences.
 // This escaping function is from:
 // https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions
 const reProfileDir = new RegExp(
         OS.Constants.Path.profileDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
         "gi");
--- a/services/sync/services-sync.js
+++ b/services/sync/services-sync.js
@@ -12,24 +12,35 @@ pref("services.sync.scheduler.idleInterv
 pref("services.sync.scheduler.activeInterval", 600);   // 10 minutes
 pref("services.sync.scheduler.immediateInterval", 90);    // 1.5 minutes
 pref("services.sync.scheduler.idleTime", 300);   // 5 minutes
 
 pref("services.sync.scheduler.fxa.singleDeviceInterval", 3600); // 1 hour
 
 pref("services.sync.errorhandler.networkFailureReportTimeout", 1209600); // 2 weeks
 
+// Note that new engines are typically added with a default of disabled, so
+// when an existing sync user gets the Firefox upgrade that supports the engine
+// it starts as disabled until the user has explicitly opted in.
+// The sync "create account" process typically *will* offer these engines, so
+// they may be flipped to enabled at that time.
 pref("services.sync.engine.addons", true);
+pref("services.sync.engine.addresses", false);
 pref("services.sync.engine.bookmarks", true);
+pref("services.sync.engine.creditcards", false);
 pref("services.sync.engine.history", true);
 pref("services.sync.engine.passwords", true);
 pref("services.sync.engine.prefs", true);
 pref("services.sync.engine.tabs", true);
 pref("services.sync.engine.tabs.filteredUrls", "^(about:.*|resource:.*|chrome:.*|wyciwyg:.*|file:.*|blob:.*)$");
 
+// The addresses and CC engines might not actually be available at all.
+pref("services.sync.engine.addresses.available", false);
+pref("services.sync.engine.creditcards.available", false);
+
 // If true, add-on sync ignores changes to the user-enabled flag. This
 // allows people to have the same set of add-ons installed across all
 // profiles while maintaining different enabled states.
 pref("services.sync.addons.ignoreUserEnabledChanges", false);
 
 // Comma-delimited list of hostnames to trust for add-on install.
 pref("services.sync.addons.trustedSourceHostnames", "addons.mozilla.org");
 
@@ -53,16 +64,18 @@ pref("services.sync.log.logger.network.r
 pref("services.sync.log.logger.engine.bookmarks", "Debug");
 pref("services.sync.log.logger.engine.clients", "Debug");
 pref("services.sync.log.logger.engine.forms", "Debug");
 pref("services.sync.log.logger.engine.history", "Debug");
 pref("services.sync.log.logger.engine.passwords", "Debug");
 pref("services.sync.log.logger.engine.prefs", "Debug");
 pref("services.sync.log.logger.engine.tabs", "Debug");
 pref("services.sync.log.logger.engine.addons", "Debug");
+pref("services.sync.log.logger.engine.addresses", "Debug");
+pref("services.sync.log.logger.engine.creditcards", "Debug");
 pref("services.sync.log.logger.engine.extension-storage", "Debug");
 pref("services.sync.log.logger.engine.apps", "Debug");
 pref("services.sync.log.logger.identity", "Debug");
 pref("services.sync.log.cryptoDebug", false);
 
 pref("services.sync.fxa.termsURL", "https://accounts.firefox.com/legal/terms");
 pref("services.sync.fxa.privacyURL", "https://accounts.firefox.com/legal/privacy");
 
--- a/services/sync/tests/unit/head_helpers.js
+++ b/services/sync/tests/unit/head_helpers.js
@@ -24,30 +24,30 @@ add_task(async function head_setup() {
     await this.Service.promiseInitialized;
   }
 });
 
 // ================================================
 // Load mocking/stubbing library, sinon
 // docs: http://sinonjs.org/releases/v2.3.2/
 Cu.import("resource://gre/modules/Timer.jsm");
-const {Loader} = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
-const loader = new Loader.Loader({
+var {Loader} = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
+var loader = new Loader.Loader({
   paths: {
     "": "resource://testing-common/",
   },
   globals: {
     setTimeout,
     setInterval,
     clearTimeout,
     clearInterval,
   },
 });
-const require = Loader.Require(loader, {id: ""});
-const sinon = require("sinon-2.3.2");
+var require = Loader.Require(loader, {id: ""});
+var sinon = require("sinon-2.3.2");
 // ================================================
 
 XPCOMUtils.defineLazyGetter(this, "SyncPingSchema", function() {
   let ns = {};
   Cu.import("resource://gre/modules/FileUtils.jsm", ns);
   let stream = Cc["@mozilla.org/network/file-input-stream;1"]
                .createInstance(Ci.nsIFileInputStream);
   let jsonReader = Cc["@mozilla.org/dom/json;1"]