Bug 1224531 - Provide a mechanism for the updater to drive kinto collection sync r?rnewman,mossop draft
authorMark Goodwin <mgoodwin@mozilla.com>
Tue, 08 Mar 2016 08:14:31 +0000
changeset 338217 41346114c34671196eee54f2b6bbeb77b1f1b1c9
parent 337024 5a2e0878d6c258b36b0ee8712a2afcde6ad94c78
child 515763 78487686bace91cbc013ea6490264462d80ef5a2
push id12470
push usermgoodwin@mozilla.com
push dateTue, 08 Mar 2016 20:05:15 +0000
reviewersrnewman, mossop
bugs1224531
milestone47.0a1
Bug 1224531 - Provide a mechanism for the updater to drive kinto collection sync r?rnewman,mossop There are two parts to this change. The first is a module to drive kinto collection sync. This gives server-provided last-update times to each module managing collection information so that data is only fetched when updates are necessary. This also keeps track of when pings last took place (for future use) and any apparent difference between client and server clock (we need this later for the content signing work). Currently only one module (the kinto version of the OneCRL client) consumes this information, though more will follow. The second is a minor change to nsBlocklistService.js to ensure that this ping takes place whenever the existing blocklist ping happens. MozReview-Commit-ID: 7SN03AOJ4Wc
addon-sdk/source/test/preferences/no-connections.json
browser/app/profile/firefox.js
mobile/android/app/mobile.js
modules/libpref/init/all.js
security/manager/ssl/tests/unit/test_cert_blocklist.js
security/manager/ssl/tests/unit/test_ev_certs.js
services/common/kinto-updater.js
services/common/moz.build
services/common/tests/unit/test_kinto_updater.js
services/common/tests/unit/xpcshell.ini
testing/profiles/prefs_general.js
toolkit/mozapps/extensions/nsBlocklistService.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_metadata_filters.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_prefs.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js
toolkit/mozapps/extensions/test/xpcshell/test_bug393285.js
toolkit/mozapps/extensions/test/xpcshell/test_bug406118.js
toolkit/mozapps/extensions/test/xpcshell/test_bug430120.js
toolkit/mozapps/extensions/test/xpcshell/test_bug449027.js
toolkit/mozapps/extensions/test/xpcshell/test_bug455906.js
toolkit/mozapps/extensions/test/xpcshell/test_bug514327_3.js
toolkit/mozapps/extensions/test/xpcshell/test_bug619730.js
toolkit/mozapps/extensions/test/xpcshell/test_bug620837.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Device.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_DriverNew.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverNew.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverOld.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_OK.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_DriverOld.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_OK.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_No_Comparison.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OK.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OS.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Vendor.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Version.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_prefs.js
toolkit/mozapps/extensions/test/xpcshell/test_pluginBlocklistCtp.js
--- a/addon-sdk/source/test/preferences/no-connections.json
+++ b/addon-sdk/source/test/preferences/no-connections.json
@@ -23,16 +23,17 @@
   "browser.safebrowsing.provider.mozilla.updateURL": "http://localhost/safebrowsing-dummy/update",
   "browser.newtabpage.directory.source": "data:application/json,{'jetpack':1}",
   "browser.newtabpage.directory.ping": "",
   "extensions.update.url": "http://localhost/extensions-dummy/updateURL",
   "extensions.update.background.url": "http://localhost/extensions-dummy/updateBackgroundURL",
   "extensions.blocklist.url": "http://localhost/extensions-dummy/blocklistURL",
   "extensions.webservice.discoverURL": "http://localhost/extensions-dummy/discoveryURL",
   "extensions.getAddons.maxResults": 0,
+  "services.kinto.base": "http://localhost/dummy-kinto/v1",
   "geo.wifi.uri": "http://localhost/location-dummy/locationURL",
   "browser.search.geoip.url": "http://localhost/location-dummy/locationURL",
   "browser.search.isUS": true,
   "browser.search.countryCode": "US",
   "geo.wifi.uri": "http://localhost/extensions-dummy/geowifiURL",
   "geo.wifi.scan": false,
   "browser.webapps.checkForUpdates": 0,
   "identity.fxaccounts.auth.uri": "http://localhost/fxa-dummy/"
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -59,20 +59,28 @@ pref("extensions.blocklist.interval", 86
 // blocking them.
 pref("extensions.blocklist.level", 2);
 pref("extensions.blocklist.url", "https://blocklist.addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PING_COUNT%/%TOTAL_PING_COUNT%/%DAYS_SINCE_LAST_PING%/");
 pref("extensions.blocklist.detailsURL", "https://www.mozilla.org/%LOCALE%/blocklist/");
 pref("extensions.blocklist.itemURL", "https://blocklist.addons.mozilla.org/%LOCALE%/%APP%/blocked/%blockID%");
 
 // Kinto blocklist preferences
 pref("services.kinto.base", "https://firefox.settings.services.mozilla.com/v1");
+pref("services.kinto.changes.path", "/buckets/monitor/collections/changes/records");
 pref("services.kinto.bucket", "blocklists");
 pref("services.kinto.onecrl.collection", "certificates");
 pref("services.kinto.onecrl.checked", 0);
 
+// for now, let's keep kinto update out of the release channel
+#ifdef RELEASE_BUILD
+pref("services.kinto.update_enabled", false);
+#else
+pref("services.kinto.update_enabled", true);
+#endif
+
 pref("extensions.update.autoUpdateDefault", true);
 
 pref("extensions.hotfix.id", "firefox-hotfix@mozilla.org");
 pref("extensions.hotfix.cert.checkAttributes", true);
 pref("extensions.hotfix.certs.1.sha1Fingerprint", "91:53:98:0C:C1:86:DF:47:8F:35:22:9E:11:C9:A7:31:04:49:A1:AA");
 pref("extensions.hotfix.certs.2.sha1Fingerprint", "39:E7:2B:7A:5B:CF:37:78:F9:5D:4A:E0:53:2D:2F:3D:68:53:C5:60");
 
 // Check AUS for system add-on updates.
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -235,20 +235,29 @@ pref("extensions.blocklist.enabled", tru
 // OneCRL freshness checking depends on this value, so if you change it,
 // please also update security.onecrl.maximum_staleness_in_seconds.
 pref("extensions.blocklist.interval", 86400);
 pref("extensions.blocklist.url", "https://blocklist.addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PING_COUNT%/%TOTAL_PING_COUNT%/%DAYS_SINCE_LAST_PING%/");
 pref("extensions.blocklist.detailsURL", "https://www.mozilla.com/%LOCALE%/blocklist/");
 
 // Kinto blocklist preferences
 pref("services.kinto.base", "https://firefox.settings.services.mozilla.com/v1");
+pref("services.kinto.changes.path", "/buckets/monitor/collections/changes/records");
 pref("services.kinto.bucket", "blocklists");
 pref("services.kinto.onecrl.collection", "certificates");
 pref("services.kinto.onecrl.checked", 0);
 
+// for now, let's keep kinto update out of the release channel (pending
+// collection signatures)
+#ifdef RELEASE_BUILD
+pref("services.kinto.update_enabled", false);
+#else
+pref("services.kinto.update_enabled", true);
+#endif
+
 /* Don't let XPIProvider install distribution add-ons; we do our own thing on mobile. */
 pref("extensions.installDistroAddons", false);
 
 /* block popups by default, and notify the user about blocked popups */
 pref("dom.disable_open_during_load", true);
 pref("privacy.popups.showBrowserMessage", true);
 
 /* disable opening windows with the dialog feature */
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2029,16 +2029,23 @@ pref("security.cert_pinning.enforcement_
 // This is to prevent accidental pinning from MITM devices and is used
 // for tests.
 pref("security.cert_pinning.process_headers_from_non_builtin_roots", false);
 
 // If set to true, allow view-source URIs to be opened from URIs that share
 // their protocol with the inner URI of the view-source URI
 pref("security.view-source.reachable-from-inner-protocol", false);
 
+#ifdef RELEASE_BUILD
+pref("security.onecrl.via.amo", true);
+#else
+pref("security.onecrl.via.amo", false);
+#endif
+
+
 // Modifier key prefs: default to Windows settings,
 // menu access key = alt, accelerator key = control.
 // Use 17 for Ctrl, 18 for Alt, 224 for Meta, 91 for Win, 0 for none. Mac settings in macprefs.js
 pref("ui.key.accelKey", 17);
 pref("ui.key.menuAccessKey", 18);
 pref("ui.key.generalAccessKey", -1);
 
 // If generalAccessKey is -1, use the following two prefs instead.
--- a/security/manager/ssl/tests/unit/test_cert_blocklist.js
+++ b/security/manager/ssl/tests/unit/test_cert_blocklist.js
@@ -76,16 +76,18 @@ var data = "<?xml version=\"1.0\" encodi
            "<blocklist xmlns=\"http://www.mozilla.org/2006/addons-blocklist\">\n" +
            "</blocklist>\n";
 stream.write(data, data.length);
 stream.close();
 
 var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
 const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
 const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
+const PREF_KINTO_UPDATE_ENABLED = "services.kinto.update_enabled";
+const PREF_ONECRL_VIA_AMO = "security.onecrl.via.amo";
 registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
                           XULAPPINFO_CONTRACTID, XULAppInfoFactory);
 
 var revocations = profile.clone();
 revocations.append("revocations.txt");
 if (!revocations.exists()) {
   let existing = do_get_file("test_onecrl/sample_revocations.txt", false);
   existing.copyTo(profile, "revocations.txt");
@@ -253,16 +255,20 @@ function run_test() {
                  "MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=\n" +
                  " BVio/iQ21GCi2iUven8oJ/gae74=\n" +
                  "MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0E=\n" +
                  " exJUIJpq50jgqOwQluhVrAzTF74=\n" +
                  "YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy\n" +
                  " YW5vdGhlciBzZXJpYWwu\n" +
                  " c2VyaWFsMi4=";
 
+  // This test assumes OneCRL updates via AMO
+  Services.prefs.setBoolPref(PREF_KINTO_UPDATE_ENABLED, false);
+  Services.prefs.setBoolPref(PREF_ONECRL_VIA_AMO, true);
+
   add_test(function () {
     // check some existing items in revocations.txt are blocked. Since the
     // CertBlocklistItems don't know about the data they contain, we can use
     // arbitrary data (not necessarily DER) to test if items are revoked or not.
     // This test corresponds to:
     // issuer: c29tZSBpbWFnaW5hcnkgaXNzdWVy
     // serial: c2VyaWFsLg==
     ok(test_is_revoked(certList, "some imaginary issuer", "serial."),
--- a/security/manager/ssl/tests/unit/test_ev_certs.js
+++ b/security/manager/ssl/tests/unit/test_ev_certs.js
@@ -145,16 +145,18 @@ function run_test() {
     check_no_ocsp_requests("no-ocsp-url-cert", SEC_ERROR_POLICY_VALIDATION_FAILED);
   });
 
   // Check OneCRL OCSP request skipping works correctly
   add_test(function () {
     // enable OneCRL OCSP skipping - allow staleness of up to 30 hours
     Services.prefs.setIntPref("security.onecrl.maximum_staleness_in_seconds", 108000);
     // set the blocklist-background-update-timer value to the recent past
+    Services.prefs.setIntPref("services.kinto.onecrl.checked",
+                              Math.floor(Date.now() / 1000) - 1);
     Services.prefs.setIntPref("app.update.lastUpdateTime.blocklist-background-update-timer",
                               Math.floor(Date.now() / 1000) - 1);
     clearOCSPCache();
     // the intermediate should not have an associated OCSP request
     let ocspResponder = start_ocsp_responder(["ev-valid"]);
     check_ee_for_ev("ev-valid", gEVExpected);
     Services.prefs.clearUserPref("security.onecrl.maximum_staleness_in_seconds");
     ocspResponder.stop(run_next_test);
@@ -171,16 +173,18 @@ function run_test() {
     Services.prefs.clearUserPref("security.onecrl.maximum_staleness_in_seconds");
     ocspResponder.stop(run_next_test);
   });
 
   add_test(function () {
     // enable OneCRL OCSP skipping - allow staleness of up to 30 hours
     Services.prefs.setIntPref("security.onecrl.maximum_staleness_in_seconds", 108000);
     // set the blocklist-background-update-timer value to the more distant past
+    Services.prefs.setIntPref("services.kinto.onecrl.checked",
+                              Math.floor(Date.now() / 1000) - 108080);
     Services.prefs.setIntPref("app.update.lastUpdateTime.blocklist-background-update-timer",
                               Math.floor(Date.now() / 1000) - 108080);
     clearOCSPCache();
     let ocspResponder = start_ocsp_responder(
                           gEVExpected ? ["int-ev-valid", "ev-valid"]
                                       : ["ev-valid"]);
     check_ee_for_ev("ev-valid", gEVExpected);
     Services.prefs.clearUserPref("security.onecrl.maximum_staleness_in_seconds");
new file mode 100644
--- /dev/null
+++ b/services/common/kinto-updater.js
@@ -0,0 +1,80 @@
+/* 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 = ["checkVersions", "addTestKintoClient"];
+
+const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.importGlobalProperties(['fetch']);
+
+const PREF_KINTO_CHANGES_PATH = "services.kinto.changes.path";
+const PREF_KINTO_BASE = "services.kinto.base";
+const PREF_KINTO_LAST_UPDATE = "services.kinto.last_update_seconds";
+const PREF_KINTO_CLOCK_SKEW_SECONDS = "services.kinto.clock_skew_seconds";
+
+const kintoClients = {
+};
+
+// This is called by the ping mechanism.
+// returns a promise that rejects if something goes wrong
+this.checkVersions = function() {
+  return Task.spawn(function *() {
+    // Fetch a versionInfo object that looks like:
+    // {"data":[
+    //   {
+    //     "host":"kinto-ota.dev.mozaws.net",
+    //     "last_modified":1450717104423,
+    //     "bucket":"blocklists",
+    //     "collection":"certificates"
+    //    }]}
+    // Right now, we only use the collection name and the last modified info
+    let kintoBase = Services.prefs.getCharPref(PREF_KINTO_BASE);
+    let changesEndpoint = kintoBase + Services.prefs.getCharPref(PREF_KINTO_CHANGES_PATH);
+
+    let response = yield fetch(changesEndpoint);
+
+    // Record new update time and the difference between local and server time
+    let serverTimeMillis = Date.parse(response.headers.get("Date"));
+    let clockDifference = Math.abs(Date.now() - serverTimeMillis) / 1000;
+    Services.prefs.setIntPref(PREF_KINTO_LAST_UPDATE, serverTimeMillis / 1000);
+    Services.prefs.setIntPref(PREF_KINTO_CLOCK_SKEW_SECONDS, clockDifference);
+
+    let versionInfo = yield response.json();
+
+    let firstError;
+    for (let collectionInfo of versionInfo.data) {
+      let collection = collectionInfo.collection;
+      let kintoClient = kintoClients[collection];
+      if (kintoClient && kintoClient.maybeSync) {
+        let lastModified = 0;
+        if (collectionInfo.last_modified) {
+          lastModified = collectionInfo.last_modified
+        }
+        try {
+          yield kintoClient.maybeSync(lastModified, serverTimeMillis);
+        } catch (e) {
+          if (!firstError) {
+            firstError = e;
+          }
+        }
+      }
+    }
+    if (firstError) {
+      // cause the promise to reject by throwing the first observed error
+      throw firstError;
+    }
+  });
+};
+
+// Add a kintoClient for testing purposes. Do not use for any other purpose
+this.addTestKintoClient = function(name, kintoClient) {
+  kintoClients[name] = kintoClient;
+};
+
+// Add the various things that we know want updates
+kintoClients.certificates =
+  Cu.import("resource://services-common/KintoCertificateBlocklist.js", {})
+  .OneCRLClient;
--- a/services/common/moz.build
+++ b/services/common/moz.build
@@ -10,16 +10,17 @@ with Files('**'):
 TEST_DIRS += ['tests']
 
 EXTRA_COMPONENTS += [
     'servicesComponents.manifest',
 ]
 
 EXTRA_JS_MODULES['services-common'] += [
     'async.js',
+    'kinto-updater.js',
     'KintoCertificateBlocklist.js',
     'logmanager.js',
     'moz-kinto-client.js',
     'observers.js',
     'rest.js',
     'stringbundle.js',
     'utils.js',
 ]
new file mode 100644
--- /dev/null
+++ b/services/common/tests/unit/test_kinto_updater.js
@@ -0,0 +1,110 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Cu.import("resource://services-common/kinto-updater.js")
+Cu.import("resource://testing-common/httpd.js");
+
+var server;
+
+const PREF_KINTO_BASE = "services.kinto.base";
+const PREF_LAST_UPDATE = "services.kinto.last_update_seconds";
+const PREF_CLOCK_SKEW_SECONDS = "services.kinto.clock_skew_seconds";
+
+// Check to ensure maybeSync is called with correct values when a changes
+// document contains information on when a collection was last modified
+add_task(function* test_check_maybeSync(){
+  const changesPath = "/v1/buckets/monitor/collections/changes/records";
+
+  // register a handler
+  function handleResponse (request, response) {
+    try {
+      const sampled = getSampleResponse(request, server.identity.primaryPort);
+      if (!sampled) {
+        do_throw(`unexpected ${request.method} request for ${request.path}?${request.queryString}`);
+      }
+
+      response.setStatusLine(null, sampled.status.status,
+                             sampled.status.statusText);
+      // send the headers
+      for (let headerLine of sampled.sampleHeaders) {
+        let headerElements = headerLine.split(':');
+        response.setHeader(headerElements[0], headerElements[1].trimLeft());
+      }
+
+      // set the
+      response.setHeader("Date", (new Date(2000)).toUTCString());
+
+      response.write(sampled.responseBody);
+    } catch (e) {
+      dump(`${e}\n`);
+    }
+  }
+
+  server.registerPathHandler(changesPath, handleResponse);
+
+  // set up prefs so the kinto updater talks to the test server
+  Services.prefs.setCharPref(PREF_KINTO_BASE,
+    `http://localhost:${server.identity.primaryPort}/v1`);
+
+  // set some initial values so we can check these are updated appropriately
+  Services.prefs.setIntPref("services.kinto.last_update", 0);
+  Services.prefs.setIntPref("services.kinto.clock_difference", 0);
+
+
+  let startTime = Date.now();
+
+  let syncPromise = new Promise(function(resolve, reject) {
+    let updater = Cu.import("resource://services-common/kinto-updater.js");
+    // add a test kinto client that will respond to lastModified information
+    // for a collection called 'test-collection'
+    updater.addTestKintoClient("test-collection", {
+      "maybeSync": function(lastModified, serverTime){
+        // ensire the lastModified and serverTime values are as expected
+        do_check_eq(lastModified, 1000);
+        do_check_eq(serverTime, 2000);
+        resolve();
+      }
+    });
+    updater.checkVersions();
+  });
+
+  // ensure we get the maybeSync call
+  yield syncPromise;
+
+  // check the last_update is updated
+  do_check_eq(Services.prefs.getIntPref(PREF_LAST_UPDATE), 2);
+
+  // How does the clock difference look?
+  let endTime = Date.now();
+  let clockDifference = Services.prefs.getIntPref(PREF_CLOCK_SKEW_SECONDS);
+  // we previously set the serverTime to 2 (seconds past epoch)
+  do_check_eq(clockDifference <= endTime / 1000
+              && clockDifference >= Math.floor(startTime / 1000) - 2, true);
+});
+
+function run_test() {
+  // Set up an HTTP Server
+  server = new HttpServer();
+  server.start(-1);
+
+  run_next_test();
+
+  do_register_cleanup(function() {
+    server.stop(function() { });
+  });
+}
+
+// get a response for a given request from sample data
+function getSampleResponse(req, port) {
+  const responses = {
+    "GET:/v1/buckets/monitor/collections/changes/records?": {
+      "sampleHeaders": [
+        "Content-Type: application/json; charset=UTF-8"
+      ],
+      "status": {status: 200, statusText: "OK"},
+      "responseBody": JSON.stringify({"data":[{"host":"localhost","last_modified":1000,"bucket":"blocklists","id":"330a0c5f-fadf-ff0b-40c8-4eb0d924ff6a","collection":"test-collection"}]})
+    }
+  };
+  return responses[`${req.method}:${req.path}?${req.queryString}`] ||
+         responses[req.method];
+}
--- a/services/common/tests/unit/xpcshell.ini
+++ b/services/common/tests/unit/xpcshell.ini
@@ -5,16 +5,17 @@ firefox-appdir = browser
 skip-if = toolkit == 'gonk'
 support-files =
   test_storage_adapter/**
 
 # Test load modules first so syntax failures are caught early.
 [test_load_modules.js]
 
 [test_kinto.js]
+[test_kinto_updater.js]
 [test_kintoCertBlocklist.js]
 [test_storage_adapter.js]
 
 [test_utils_atob.js]
 [test_utils_convert_string.js]
 [test_utils_dateprefs.js]
 [test_utils_deepCopy.js]
 [test_utils_encodeBase32.js]
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -101,16 +101,18 @@ user_pref("extensions.pocket.enabled", f
 // Make sure opening about:addons won't hit the network
 user_pref("extensions.webservice.discoverURL", "http://%(server)s/extensions-dummy/discoveryURL");
 // Make sure AddonRepository won't hit the network
 user_pref("extensions.getAddons.maxResults", 0);
 user_pref("extensions.getAddons.get.url", "http://%(server)s/extensions-dummy/repositoryGetURL");
 user_pref("extensions.getAddons.getWithPerformance.url", "http://%(server)s/extensions-dummy/repositoryGetWithPerformanceURL");
 user_pref("extensions.getAddons.search.browseURL", "http://%(server)s/extensions-dummy/repositoryBrowseURL");
 user_pref("extensions.getAddons.search.url", "http://%(server)s/extensions-dummy/repositorySearchURL");
+// Ensure kinto updates don't hit the network
+user_pref("services.kinto.base", "http://%(server)s/dummy-kinto/v1");
 // Make sure that opening the plugins check page won't hit the network
 user_pref("plugins.update.url", "http://%(server)s/plugins-dummy/updateCheckURL");
 // Make sure SNTP requests don't hit the network
 user_pref("network.sntp.pools", "%(server)s");
 // We know the SNTP request will fail, since localhost isn't listening on
 // port 135. The default number of retries (10) is excessive, but retrying
 // at least once will mean that codepath is still tested in automation.
 user_pref("network.sntp.maxRetryCount", 1);
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ b/toolkit/mozapps/extensions/nsBlocklistService.js
@@ -43,16 +43,17 @@ const PREF_BLOCKLIST_URL              = 
 const PREF_BLOCKLIST_ITEM_URL         = "extensions.blocklist.itemURL";
 const PREF_BLOCKLIST_ENABLED          = "extensions.blocklist.enabled";
 const PREF_BLOCKLIST_INTERVAL         = "extensions.blocklist.interval";
 const PREF_BLOCKLIST_LEVEL            = "extensions.blocklist.level";
 const PREF_BLOCKLIST_PINGCOUNTTOTAL   = "extensions.blocklist.pingCountTotal";
 const PREF_BLOCKLIST_PINGCOUNTVERSION = "extensions.blocklist.pingCountVersion";
 const PREF_BLOCKLIST_SUPPRESSUI       = "extensions.blocklist.suppressUI";
 const PREF_ONECRL_VIA_AMO             = "security.onecrl.via.amo";
+const PREF_KINTO_UPDATE_ENABLED       = "services.kinto.update_enabled";
 const PREF_PLUGINS_NOTIFYUSER         = "plugins.update.notifyUser";
 const PREF_GENERAL_USERAGENT_LOCALE   = "general.useragent.locale";
 const PREF_APP_DISTRIBUTION           = "distribution.id";
 const PREF_APP_DISTRIBUTION_VERSION   = "distribution.version";
 const PREF_EM_LOGGING_ENABLED         = "extensions.logging.enabled";
 const XMLURI_BLOCKLIST                = "http://www.mozilla.org/2006/addons-blocklist";
 const XMLURI_PARSE_ERROR              = "http://www.mozilla.org/newlayout/xml/parsererror.xml"
 const UNKNOWN_XPCOM_ABI               = "unknownABI";
@@ -621,16 +622,27 @@ Blocklist.prototype = {
     request.addEventListener("error", event => this.onXMLError(event), false);
     request.addEventListener("load", event => this.onXMLLoad(event), false);
     request.send(null);
 
     // When the blocklist loads we need to compare it to the current copy so
     // make sure we have loaded it.
     if (!this._isBlocklistLoaded())
       this._loadBlocklist();
+
+    // If kinto update is enabled, do the kinto update
+    if (gPref.getBoolPref(PREF_KINTO_UPDATE_ENABLED)) {
+      let KintoUpdater =
+        Components.utils.import("resource://services-common/kinto-updater.js",
+                                {});
+      KintoUpdater.checkVersions().catch(() => {
+        // Before we enable this in release, we want to collect telemetry on
+        // failed kinto updates - see bug 1254099
+      });
+    }
   },
 
   onXMLLoad: Task.async(function*(aEvent) {
     let request = aEvent.target;
     try {
       gCertUtils.checkCert(request.channel);
     }
     catch (e) {
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_metadata_filters.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_metadata_filters.js
@@ -55,16 +55,18 @@ function load_blocklist(aFile, aCallback
   Services.obs.addObserver(function() {
     Services.obs.removeObserver(arguments.callee, "blocklist-updated");
 
     do_execute_soon(aCallback);
   }, "blocklist-updated", false);
 
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + aFile);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 
 function end_test() {
   testserver.stop(do_test_finished);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_prefs.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_prefs.js
@@ -61,16 +61,18 @@ function load_blocklist(aFile, aCallback
   Services.obs.addObserver(function() {
     Services.obs.removeObserver(arguments.callee, "blocklist-updated");
 
     do_execute_soon(aCallback);
   }, "blocklist-updated", false);
 
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + aFile);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 function end_test() {
   testserver.stop(do_test_finished);
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
@@ -57,18 +57,21 @@ function load_blocklist(aFile, aCallback
   Services.obs.addObserver(function() {
     Services.obs.removeObserver(arguments.callee, "blocklist-updated");
 
     do_execute_soon(aCallback);
   }, "blocklist-updated", false);
 
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + aFile);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
+  ok(Services.prefs.getBoolPref("services.kinto.update_enabled", false), "I thought this would be set!");
   blocklist.notify(null);
 }
 
 
 function end_test() {
   testserver.stop(do_test_finished);
 }
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js
@@ -398,16 +398,18 @@ function Pload_blocklist(aFile) {
     Services.obs.addObserver(function() {
       Services.obs.removeObserver(arguments.callee, "blocklist-updated");
 
       resolve();
     }, "blocklist-updated", false);
   });
 
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" + gPort + "/data/blocklistchange/" + aFile);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
   return blocklist_updated;
 }
 
 // Does a background update check for add-ons and returns a promise that
 // resolves when any started installs complete
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug393285.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug393285.js
@@ -69,16 +69,18 @@ function load_blocklist(aFile, aCallback
   Services.obs.addObserver(function() {
     Services.obs.removeObserver(arguments.callee, "blocklist-updated");
 
     do_execute_soon(aCallback);
   }, "blocklist-updated", false);
 
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + aFile);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 
 function end_test() {
   testserver.stop(do_test_finished);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug406118.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug406118.js
@@ -57,16 +57,18 @@ function load_blocklist(aFile, aCallback
   Services.obs.addObserver(function() {
     Services.obs.removeObserver(arguments.callee, "blocklist-updated");
 
     do_execute_soon(aCallback);
   }, "blocklist-updated", false);
 
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + aFile);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 
 function end_test() {
   testserver.stop(do_test_finished);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug430120.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug430120.js
@@ -1,15 +1,16 @@
 /* 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/.
  */
 
 const BLOCKLIST_TIMER                 = "blocklist-background-update-timer";
 const PREF_BLOCKLIST_URL              = "extensions.blocklist.url";
+const PREF_KINTO_BASE_URL             = "services.kinto.base";
 const PREF_BLOCKLIST_ENABLED          = "extensions.blocklist.enabled";
 const PREF_APP_DISTRIBUTION           = "distribution.id";
 const PREF_APP_DISTRIBUTION_VERSION   = "distribution.version";
 const PREF_APP_UPDATE_CHANNEL         = "app.update.channel";
 const PREF_GENERAL_USERAGENT_LOCALE   = "general.useragent.locale";
 const CATEGORY_UPDATE_TIMER           = "update-timer";
 
 // Get the HTTP server.
@@ -108,16 +109,17 @@ function run_test() {
   gBlocklist.observe(null, "profile-after-change", "");
 
   do_check_true(timerService.hasTimer(BLOCKLIST_TIMER));
 
   do_test_pending();
 
   // This should have no effect as the blocklist is disabled
   Services.prefs.setCharPref(PREF_BLOCKLIST_URL, "http://localhost:" + gPort + "/1");
+  Services.prefs.setCharPref(PREF_KINTO_BASE_URL, "http://localhost:" + gPort + "/dummy-kinto/v1")
   Services.prefs.setBoolPref(PREF_BLOCKLIST_ENABLED, false);
   timerService.fireTimer(BLOCKLIST_TIMER);
 
   // Some values have to be on the default branch to work
   var defaults = Services.prefs.QueryInterface(Components.interfaces.nsIPrefService)
                        .getDefaultBranch(null);
   defaults.setCharPref(PREF_APP_UPDATE_CHANNEL, "updatechannel");
   defaults.setCharPref(PREF_APP_DISTRIBUTION, "distribution");
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug449027.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug449027.js
@@ -350,16 +350,18 @@ function check_state(test, lastTest, cal
       do_check_eq(expected, gNewBlocks.length);
     }
     do_execute_soon(callback);
   });
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" + gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Components.classes["@mozilla.org/extensions/blocklist;1"]
                             .getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 function run_test() {
   // Setup for test
   dump("Setting up tests\n");
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug455906.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug455906.js
@@ -193,16 +193,18 @@ function create_addon(addon) {
               FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE,
               FileUtils.PERMS_FILE, 0);
   stream.write(installrdf, installrdf.length);
   stream.close();
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" + gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 function check_addon_state(addon) {
   return addon.userDisabled + "," + addon.softDisabled + "," + addon.appDisabled;
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug514327_3.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug514327_3.js
@@ -86,16 +86,18 @@ var WindowWatcher = {
 MockRegistrar.register("@mozilla.org/plugin/host;1", PluginHost);
 MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1", WindowWatcher);
 
 
 function do_update_blocklist(aDatafile, aNextPart) {
   gNextTestPart = aNextPart;
 
   gPrefs.setCharPref("extensions.blocklist.url", "http://localhost:" + gPort + "/data/" + aDatafile);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   gBlocklist.QueryInterface(Ci.nsITimerCallback).notify(null);
 }
 
 function run_test() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9");
 
   gTestserver = new HttpServer();
   gTestserver.registerDirectory("/data/", do_get_file("data"));
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug619730.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug619730.js
@@ -18,16 +18,18 @@ function load_blocklist(file, aCallback)
   Services.obs.addObserver(function() {
     Services.obs.removeObserver(arguments.callee, "blocklist-updated");
 
     do_execute_soon(aCallback);
   }, "blocklist-updated", false);
 
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 var gSawGFX = false;
 var gSawTest = false;
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug620837.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug620837.js
@@ -31,16 +31,18 @@ function run_test() {
   gTestserver = new HttpServer();
   gTestserver.registerPathHandler("/", pathHandler);
   gTestserver.start(-1);
   gPort = gTestserver.identity.primaryPort;
 
   Services.prefs.setCharPref("extensions.blocklist.url",
                              "http://localhost:" + gPort +
                              "/?%PING_COUNT%&%TOTAL_PING_COUNT%&%DAYS_SINCE_LAST_PING%");
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
 
   do_test_pending();
   test1();
 }
 
 function getNowInSeconds() {
   return Math.round(Date.now() / 1000);
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Device.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Device.js
@@ -20,16 +20,18 @@ function get_platform() {
   var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
                              .getService(Ci.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 // Performs the initial setup
 function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_DriverNew.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_DriverNew.js
@@ -20,16 +20,18 @@ function get_platform() {
   var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
                              .getService(Ci.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 // Performs the initial setup
 function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverNew.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverNew.js
@@ -20,16 +20,18 @@ function get_platform() {
   var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
                              .getService(Ci.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 // Performs the initial setup
 function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverOld.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverOld.js
@@ -20,16 +20,18 @@ function get_platform() {
   var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
                              .getService(Ci.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 // Performs the initial setup
 function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_OK.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_OK.js
@@ -20,16 +20,18 @@ function get_platform() {
   var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
                              .getService(Ci.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 // Performs the initial setup
 function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_DriverOld.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_DriverOld.js
@@ -20,16 +20,18 @@ function get_platform() {
   var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
                              .getService(Ci.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 // Performs the initial setup
 function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_OK.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_OK.js
@@ -20,16 +20,18 @@ function get_platform() {
   var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
                              .getService(Ci.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 // Performs the initial setup
 function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_No_Comparison.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_No_Comparison.js
@@ -20,16 +20,18 @@ function get_platform() {
   var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
                              .getService(Ci.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 // Performs the initial setup
 function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OK.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OK.js
@@ -20,16 +20,18 @@ function get_platform() {
   var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
                              .getService(Ci.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 // Performs the initial setup
 function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OS.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OS.js
@@ -20,16 +20,18 @@ function get_platform() {
   var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
                              .getService(Ci.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 // Performs the initial setup
 function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js
@@ -19,16 +19,18 @@ function get_platform() {
   var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
                              .getService(Ci.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 // Performs the initial setup
 function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js
@@ -20,16 +20,18 @@ function get_platform() {
   var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
                              .getService(Ci.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 // Performs the initial setup
 function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js
@@ -20,16 +20,18 @@ function get_platform() {
   var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
                              .getService(Ci.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 // Performs the initial setup
 function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Vendor.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Vendor.js
@@ -20,16 +20,18 @@ function get_platform() {
   var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
                              .getService(Ci.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 // Performs the initial setup
 function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Version.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Version.js
@@ -19,16 +19,18 @@ function get_platform() {
   var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
                              .getService(Ci.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 // Performs the initial setup
 function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_prefs.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_prefs.js
@@ -19,16 +19,18 @@ function get_platform() {
   var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"]
                              .getService(Components.interfaces.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
 function load_blocklist(file) {
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + file);
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
 }
 
 // Performs the initial setup
 function run_test() {
   try {
--- a/toolkit/mozapps/extensions/test/xpcshell/test_pluginBlocklistCtp.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_pluginBlocklistCtp.js
@@ -92,41 +92,47 @@ function get_test_plugin() {
 // so it shouldn't be click-to-play.
 function test_is_not_clicktoplay() {
   var plugin = get_test_plugin();
   var blocklistState = gBlocklistService.getPluginBlocklistState(plugin, "1", "1.9");
   do_check_neq(blocklistState, Components.interfaces.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE);
   do_check_neq(blocklistState, Components.interfaces.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE);
 
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" + gPort + "/data/test_pluginBlocklistCtpUndo.xml");
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   gNextTest = test_is_clicktoplay;
   gNotifier.notify(null);
 }
 
 // Here, we've updated the blocklist to have a block for the test plugin,
 // so it should be click-to-play.
 function test_is_clicktoplay() {
   var plugin = get_test_plugin();
   var blocklistState = gBlocklistService.getPluginBlocklistState(plugin, "1", "1.9");
   do_check_eq(blocklistState, Components.interfaces.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE);
 
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" + gPort + "/data/test_pluginBlocklistCtp.xml");
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   gNextTest = test_is_not_clicktoplay2;
   gNotifier.notify(null);
 }
 
 // But now we've removed that entry from the blocklist (really we've gone back
 // to the old one), so the plugin shouldn't be click-to-play any more.
 function test_is_not_clicktoplay2() {
   var plugin = get_test_plugin();
   var blocklistState = gBlocklistService.getPluginBlocklistState(plugin, "1", "1.9");
   do_check_neq(blocklistState, Components.interfaces.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE);
   do_check_neq(blocklistState, Components.interfaces.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE);
 
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" + gPort + "/data/test_pluginBlocklistCtpUndo.xml");
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   gNextTest = test_disable_blocklist;
   gNotifier.notify(null);
 }
 
 // Test that disabling the blocklist when a plugin is ctp-blocklisted will
 // result in the plugin not being click-to-play.
 function test_disable_blocklist() {
   var plugin = get_test_plugin();
@@ -156,25 +162,28 @@ function observer() {
   if (gNextTest)
     do_execute_soon(gNextTest);
 }
 
 function run_test() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9");
 
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" + gPort + "/data/test_pluginBlocklistCtp.xml");
+  Services.prefs.setCharPref("services.kinto.base",
+                             "http://localhost:" + gPort + "/dummy-kinto/v1");
   startupManager();
 
   gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
   gBlocklistService = Components.classes["@mozilla.org/extensions/blocklist;1"].getService(Components.interfaces.nsIBlocklistService);
   gNotifier = Components.classes["@mozilla.org/extensions/blocklist;1"].getService(Components.interfaces.nsITimerCallback);
   Services.obs.addObserver(observer, "blocklist-updated", false);
 
   do_register_cleanup(function() {
     Services.prefs.clearUserPref("extensions.blocklist.url");
+    Services.prefs.clearUserPref("services.kinto.base");
     Services.prefs.clearUserPref("extensions.blocklist.enabled");
     Services.prefs.clearUserPref("plugins.click_to_play");
     Services.obs.removeObserver(observer, "blocklist-updated");
   });
 
   gNextTest = test_basic;
   do_test_pending();
   gNotifier.notify(null);