bug 1341734 - remove the disableSHA1rollout addon r=jcj
authorDavid Keeler <dkeeler@mozilla.com>
Wed, 22 Feb 2017 13:37:12 -0800
changeset 344343 4799fdd232958d83efc92b36d5b384bf0503972a
parent 344342 5d1d3f47d4f73b7974e8f83b79f896c5b9534ae7
child 344344 e4f1979be0d7e681b6ee68ebf4812b1e68c0f9d8
push id37818
push userdkeeler@mozilla.com
push dateWed, 22 Feb 2017 23:29:05 +0000
treeherderautoland@4799fdd23295 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjcj
bugs1341734
milestone54.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 1341734 - remove the disableSHA1rollout addon r=jcj MozReview-Commit-ID: 5PUT6csFK5H
browser/extensions/disableSHA1rollout/README.md
browser/extensions/disableSHA1rollout/bootstrap.js
browser/extensions/disableSHA1rollout/install.rdf.in
browser/extensions/disableSHA1rollout/moz.build
browser/extensions/moz.build
testing/talos/talos/xtalos/xperf_whitelist.json
deleted file mode 100644
--- a/browser/extensions/disableSHA1rollout/README.md
+++ /dev/null
@@ -1,99 +0,0 @@
-This system add-on is a follow-up to the MITM prevalence experiment. The purpose
-is to facilitate rolling out the disabling of SHA-1 in signatures on
-certificates issued by publicly-trusted roots. When installed, this add-on will
-perform a number of checks to determine if it should change the preference that
-controls the SHA-1 policy. First, this should only apply to users on the beta
-update channel. It should also only apply to users who have not otherwise
-changed the policy to always allow or always forbid SHA-1. Additionally, it
-must double-check that the user is not affected by a TLS intercepting proxy
-using a publicly-trusted root. If these checks pass, the add-on will divide the
-population into a test group and a control group (starting on a 10%/90% split).
-The test group will have the policy changed. After doing this, a telemetry
-payload is reported with the following values:
-
-* cohortName -- the name of the group this user is in:
-  1. "notSafeToDisableSHA1" if the user is behind a MITM proxy using a
-     publicly-trusted root
-  2. "optedOut" if the user already set the SHA-1 policy to always allow or
-     always forbid
-  3. "optedIn" if the user already set the SHA-1 policy to only allow for
-     non-built-in roots
-  4. "test" if the user is in the test cohort (and SHA-1 will be disabled)
-  5. "control" if the user is not in the test cohort
-* errorCode -- 0 for successful connections, some PR error code otherwise
-* error -- a short description of one of four error conditions encountered, if
-  applicable, and an empty string otherwise:
-  1. "timeout" if the connection to telemetry.mozilla.org timed out
-  2. "user override" if the user has stored a permanent certificate exception
-     override for telemetry.mozilla.org (due to technical limitations, we can't
-     gather much information in this situation)
-  3. "certificate reverification" if re-building the certificate chain after
-     connecting failed for some reason (unfortunately this step is necessary
-     due to technical limitations)
-  4. "connection error" if the connection to telemetry.mozilla.org failed for
-     another reason
-* chain -- a list of dictionaries each corresponding to a certificate in the
-  verified certificate chain, if it was successfully constructed. The first
-  entry is the end-entity certificate. The last entry is the root certificate.
-  This will be empty if the connection failed or if reverification failed. Each
-  element in the list contains the following values:
-  * sha256Fingerprint -- a hex string representing the SHA-256 hash of the
-    certificate
-  * isBuiltInRoot -- true if the certificate is a trust anchor in the web PKI,
-    false otherwise
-  * signatureAlgorithm -- a description of the algorithm used to sign the
-    certificate. Will be one of "md2WithRSAEncryption", "md5WithRSAEncryption",
-    "sha1WithRSAEncryption", "sha256WithRSAEncryption",
-    "sha384WithRSAEncryption", "sha512WithRSAEncryption", "ecdsaWithSHA1",
-    "ecdsaWithSHA224", "ecdsaWithSHA256", "ecdsaWithSHA384", "ecdsaWithSHA512",
-    or "unknown".
-* disabledSHA1 -- true if SHA-1 was disabled, false otherwise
-* didNotDisableSHA1Because -- a short string describing why SHA-1 could not be
-    disabled, if applicable. Reasons are limited to:
-    1. "MITM" if the user is behind a TLS intercepting proxy using a
-       publicly-trusted root
-    2. "connection error" if there was an error connecting to
-       telemetry.mozilla.org
-    3. "code error" if some inconsistent state was detected, and it was
-       determined that the experiment should not attempt to change the
-       preference
-    4. "preference:userReset" if the user reset the SHA-1 policy after it had
-       been changed by this add-on
-    5. "preference:allow" if the user had already configured Firefox to always
-       accept SHA-1 signatures
-    6. "preference:forbid" if the user had already configured Firefox to always
-       forbid SHA-1 signatures
-
-For a connection not intercepted by a TLS proxy and where the user is in the
-test cohort, the expected result will be:
-
-    { "cohortName": "test",
-      "errorCode": 0,
-      "error": "",
-      "chain": [
-        { "sha256Fingerprint": "197feaf3faa0f0ad637a89c97cb91336bfc114b6b3018203cbd9c3d10c7fa86c",
-          "isBuiltInRoot": false,
-          "signatureAlgorithm": "sha256WithRSAEncryption"
-        },
-        { "sha256Fingerprint": "154c433c491929c5ef686e838e323664a00e6a0d822ccc958fb4dab03e49a08f",
-          "isBuiltInRoot": false,
-          "signatureAlgorithm": "sha256WithRSAEncryption"
-        },
-        { "sha256Fingerprint": "4348a0e9444c78cb265e058d5e8944b4d84f9662bd26db257f8934a443c70161",
-          "isBuiltInRoot": true,
-          "signatureAlgorithm": "sha1WithRSAEncryption"
-        }
-      ],
-      "disabledSHA1": true,
-      "didNotDisableSHA1Because": ""
-    }
-
-When this result is encountered, the user's preferences are updated to disable
-SHA-1 in signatures on certificates issued by publicly-trusted roots.
-Similarly, if the user is behind a TLS intercepting proxy but the root
-certificate is not part of the public web PKI, we can also disable SHA-1 in
-signatures on certificates issued by publicly-trusted roots.
-
-If the user has already indicated in their preferences that they will always
-accept SHA-1 in signatures or that they will never accept SHA-1 in signatures,
-then the preference is not changed.
deleted file mode 100644
--- a/browser/extensions/disableSHA1rollout/bootstrap.js
+++ /dev/null
@@ -1,306 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* 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/. */
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/Preferences.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/UpdateUtils.jsm");
-Cu.import("resource://gre/modules/TelemetryController.jsm");
-
- // Percentage of the population to attempt to disable SHA-1 for, by channel.
-const TEST_THRESHOLD = {
-  beta: 0.1, // 10%
-};
-
-const PREF_COHORT_SAMPLE = "disableSHA1.rollout.cohortSample";
-const PREF_COHORT_NAME = "disableSHA1.rollout.cohort";
-const PREF_SHA1_POLICY = "security.pki.sha1_enforcement_level";
-const PREF_SHA1_POLICY_SET_BY_ADDON = "disableSHA1.rollout.policySetByAddOn";
-const PREF_SHA1_POLICY_RESET_BY_USER = "disableSHA1.rollout.userResetPref";
-
-const SHA1_MODE_ALLOW = 0;
-const SHA1_MODE_FORBID = 1;
-const SHA1_MODE_IMPORTED_ROOTS_ONLY = 3;
-const SHA1_MODE_CURRENT_DEFAULT = 4;
-
-function startup() {
-  Preferences.observe(PREF_SHA1_POLICY, policyPreferenceChanged);
-}
-
-function install() {
-  let updateChannel = UpdateUtils.getUpdateChannel(false);
-  if (updateChannel in TEST_THRESHOLD) {
-    makeRequest().then(defineCohort).catch((e) => console.error(e));
-  }
-}
-
-function policyPreferenceChanged() {
-  let currentPrefValue = Preferences.get(PREF_SHA1_POLICY,
-                                         SHA1_MODE_CURRENT_DEFAULT);
-  Preferences.reset(PREF_SHA1_POLICY_RESET_BY_USER);
-  if (currentPrefValue == SHA1_MODE_CURRENT_DEFAULT) {
-    Preferences.set(PREF_SHA1_POLICY_RESET_BY_USER, true);
-  }
-}
-
-function defineCohort(result) {
-  let userOptedOut = optedOut();
-  let userOptedIn = optedIn();
-  let shouldNotDisableSHA1Because = reasonToNotDisableSHA1(result);
-  let safeToDisableSHA1 = shouldNotDisableSHA1Because.length == 0;
-  let updateChannel = UpdateUtils.getUpdateChannel(false);
-  let testGroup = getUserSample() < TEST_THRESHOLD[updateChannel];
-
-  let cohortName;
-  if (!safeToDisableSHA1) {
-    cohortName = "notSafeToDisableSHA1";
-  } else if (userOptedOut) {
-    cohortName = "optedOut";
-  } else if (userOptedIn) {
-    cohortName = "optedIn";
-  } else if (testGroup) {
-    cohortName = "test";
-    Preferences.ignore(PREF_SHA1_POLICY, policyPreferenceChanged);
-    Preferences.set(PREF_SHA1_POLICY, SHA1_MODE_IMPORTED_ROOTS_ONLY);
-    Preferences.observe(PREF_SHA1_POLICY, policyPreferenceChanged);
-    Preferences.set(PREF_SHA1_POLICY_SET_BY_ADDON, true);
-  } else {
-    cohortName = "control";
-  }
-  Preferences.set(PREF_COHORT_NAME, cohortName);
-  reportTelemetry(result, cohortName, shouldNotDisableSHA1Because,
-                  cohortName == "test");
-}
-
-function shutdown(data, reason) {
-  Preferences.ignore(PREF_SHA1_POLICY, policyPreferenceChanged);
-}
-
-function uninstall() {
-}
-
-function getUserSample() {
-  let prefValue = Preferences.get(PREF_COHORT_SAMPLE, undefined);
-  let value = 0.0;
-
-  if (typeof(prefValue) == "string") {
-    value = parseFloat(prefValue, 10);
-    return value;
-  }
-
-  value = Math.random();
-
-  Preferences.set(PREF_COHORT_SAMPLE, value.toString().substr(0, 8));
-  return value;
-}
-
-function reportTelemetry(result, cohortName, didNotDisableSHA1Because,
-                         disabledSHA1) {
-  result.cohortName = cohortName;
-  result.disabledSHA1 = disabledSHA1;
-  if (cohortName == "optedOut") {
-    let userResetPref = Preferences.get(PREF_SHA1_POLICY_RESET_BY_USER, false);
-    let currentPrefValue = Preferences.get(PREF_SHA1_POLICY,
-                                           SHA1_MODE_CURRENT_DEFAULT);
-    if (userResetPref) {
-      didNotDisableSHA1Because = "preference:userReset";
-    } else if (currentPrefValue == SHA1_MODE_ALLOW) {
-      didNotDisableSHA1Because = "preference:allow";
-    } else {
-      didNotDisableSHA1Because = "preference:forbid";
-    }
-  }
-  result.didNotDisableSHA1Because = didNotDisableSHA1Because;
-  return TelemetryController.submitExternalPing("disableSHA1rollout", result,
-                                                {});
-}
-
-function optedIn() {
-  let policySetByAddOn = Preferences.get(PREF_SHA1_POLICY_SET_BY_ADDON, false);
-  let currentPrefValue = Preferences.get(PREF_SHA1_POLICY,
-                                         SHA1_MODE_CURRENT_DEFAULT);
-  return currentPrefValue == SHA1_MODE_IMPORTED_ROOTS_ONLY && !policySetByAddOn;
-}
-
-function optedOut() {
-  // Users can also opt-out by setting the policy to always allow or always
-  // forbid SHA-1, or by resetting the preference after this add-on has changed
-  // it (in that case, this will be reported the next time this add-on is
-  // updated).
-  let currentPrefValue = Preferences.get(PREF_SHA1_POLICY,
-                                         SHA1_MODE_CURRENT_DEFAULT);
-  let userResetPref = Preferences.get(PREF_SHA1_POLICY_RESET_BY_USER, false);
-  return currentPrefValue == SHA1_MODE_ALLOW ||
-         currentPrefValue == SHA1_MODE_FORBID ||
-         userResetPref;
-}
-
-function delocalizeAlgorithm(localizedString) {
-  let bundle = Services.strings.createBundle(
-    "chrome://pipnss/locale/pipnss.properties");
-  let algorithmStringIdsToOIDDescriptionMap = {
-    "CertDumpMD2WithRSA":                       "md2WithRSAEncryption",
-    "CertDumpMD5WithRSA":                       "md5WithRSAEncryption",
-    "CertDumpSHA1WithRSA":                      "sha1WithRSAEncryption",
-    "CertDumpSHA256WithRSA":                    "sha256WithRSAEncryption",
-    "CertDumpSHA384WithRSA":                    "sha384WithRSAEncryption",
-    "CertDumpSHA512WithRSA":                    "sha512WithRSAEncryption",
-    "CertDumpAnsiX962ECDsaSignatureWithSha1":   "ecdsaWithSHA1",
-    "CertDumpAnsiX962ECDsaSignatureWithSha224": "ecdsaWithSHA224",
-    "CertDumpAnsiX962ECDsaSignatureWithSha256": "ecdsaWithSHA256",
-    "CertDumpAnsiX962ECDsaSignatureWithSha384": "ecdsaWithSHA384",
-    "CertDumpAnsiX962ECDsaSignatureWithSha512": "ecdsaWithSHA512",
-  };
-
-  let description;
-  Object.keys(algorithmStringIdsToOIDDescriptionMap).forEach((l10nID) => {
-    let candidateLocalizedString = bundle.GetStringFromName(l10nID);
-    if (localizedString == candidateLocalizedString) {
-      description = algorithmStringIdsToOIDDescriptionMap[l10nID];
-    }
-  });
-  if (!description) {
-    return "unknown";
-  }
-  return description;
-}
-
-function getSignatureAlgorithm(cert) {
-  // Certificate  ::=  SEQUENCE  {
-  //      tbsCertificate       TBSCertificate,
-  //      signatureAlgorithm   AlgorithmIdentifier,
-  //      signatureValue       BIT STRING  }
-  let certificate = cert.ASN1Structure.QueryInterface(Ci.nsIASN1Sequence);
-  let signatureAlgorithm = certificate.ASN1Objects
-                                      .queryElementAt(1, Ci.nsIASN1Sequence);
-  // AlgorithmIdentifier  ::=  SEQUENCE  {
-  //      algorithm               OBJECT IDENTIFIER,
-  //      parameters              ANY DEFINED BY algorithm OPTIONAL  }
-
-  // If parameters is NULL (or empty), signatureAlgorithm won't be a container
-  // under this implementation. Just get its displayValue.
-  if (!signatureAlgorithm.isValidContainer) {
-    return signatureAlgorithm.displayValue;
-  }
-  let oid = signatureAlgorithm.ASN1Objects.queryElementAt(0, Ci.nsIASN1Object);
-  return oid.displayValue;
-}
-
-function processCertChain(chain) {
-  let output = [];
-  let enumerator = chain.getEnumerator();
-  while (enumerator.hasMoreElements()) {
-    let cert = enumerator.getNext().QueryInterface(Ci.nsIX509Cert);
-    output.push({
-      sha256Fingerprint: cert.sha256Fingerprint.replace(/:/g, "").toLowerCase(),
-      isBuiltInRoot: cert.isBuiltInRoot,
-      signatureAlgorithm: delocalizeAlgorithm(getSignatureAlgorithm(cert)),
-    });
-  }
-  return output;
-}
-
-class CertificateVerificationResult {
-  constructor(resolve) {
-    this.resolve = resolve;
-  }
-
-  verifyCertFinished(aPRErrorCode, aVerifiedChain, aEVStatus) {
-    let result = { errorCode: aPRErrorCode, error: "", chain: [] };
-    if (aPRErrorCode == 0) {
-      result.chain = processCertChain(aVerifiedChain);
-    } else {
-      result.error = "certificate reverification";
-    }
-    this.resolve(result);
-  }
-}
-
-function makeRequest() {
-  return new Promise((resolve) => {
-    let hostname = "telemetry.mozilla.org";
-    let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
-                .createInstance(Ci.nsIXMLHttpRequest);
-    req.open("GET", "https://" + hostname);
-    req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
-    req.timeout = 30000;
-    req.addEventListener("error", (evt) => {
-      // If we can't connect to telemetry.mozilla.org, then how did we even
-      // download the experiment? In any case, we may still be able to get some
-      // information.
-      let result = { error: "connection error" };
-      if (evt.target.channel && evt.target.channel.securityInfo) {
-        let securityInfo = evt.target.channel.securityInfo
-                             .QueryInterface(Ci.nsITransportSecurityInfo);
-        if (securityInfo) {
-          result.errorCode = securityInfo.errorCode;
-        }
-        if (securityInfo && securityInfo.failedCertChain) {
-          result.chain = processCertChain(securityInfo.failedCertChain);
-        }
-      }
-      resolve(result);
-    });
-    req.addEventListener("timeout", (evt) => {
-      resolve({ error: "timeout" });
-    });
-    req.addEventListener("load", (evt) => {
-      let securityInfo = evt.target.channel.securityInfo
-                           .QueryInterface(Ci.nsITransportSecurityInfo);
-      if (securityInfo.securityState &
-          Ci.nsIWebProgressListener.STATE_CERT_USER_OVERRIDDEN) {
-        resolve({ error: "user override" });
-        return;
-      }
-      let sslStatus = securityInfo.QueryInterface(Ci.nsISSLStatusProvider)
-                        .SSLStatus;
-      let certdb = Cc["@mozilla.org/security/x509certdb;1"]
-                     .getService(Ci.nsIX509CertDB);
-      let result = new CertificateVerificationResult(resolve);
-      // Unfortunately, we don't have direct access to the verified certificate
-      // chain as built by the AuthCertificate hook, so we have to re-build it
-      // here. In theory we are likely to get the same result.
-      certdb.asyncVerifyCertAtTime(sslStatus.serverCert,
-                                   2, // certificateUsageSSLServer
-                                   0, // flags
-                                   hostname,
-                                   Date.now() / 1000,
-                                   result);
-    });
-    req.send();
-  });
-}
-
-// As best we know, it is safe to disable SHA1 if the connection was successful
-// and either the connection was MITM'd by a root not in the public PKI or the
-// chain is part of the public PKI and is the one served by the real
-// telemetry.mozilla.org.
-// This will return a short string description of why it might not be safe to
-// disable SHA1 or an empty string if it is safe to disable SHA1.
-function reasonToNotDisableSHA1(result) {
-  if (!("errorCode" in result) || result.errorCode != 0) {
-    return "connection error";
-  }
-  if (!("chain" in result)) {
-    return "code error";
-  }
-  if (!result.chain[result.chain.length - 1].isBuiltInRoot) {
-    return "";
-  }
-  if (result.chain.length != 3) {
-    return "MITM";
-  }
-  const kEndEntityFingerprint = "197feaf3faa0f0ad637a89c97cb91336bfc114b6b3018203cbd9c3d10c7fa86c";
-  const kIntermediateFingerprint = "154c433c491929c5ef686e838e323664a00e6a0d822ccc958fb4dab03e49a08f";
-  const kRootFingerprint = "4348a0e9444c78cb265e058d5e8944b4d84f9662bd26db257f8934a443c70161";
-  if (result.chain[0].sha256Fingerprint != kEndEntityFingerprint ||
-      result.chain[1].sha256Fingerprint != kIntermediateFingerprint ||
-      result.chain[2].sha256Fingerprint != kRootFingerprint) {
-    return "MITM";
-  }
-  return "";
-}
deleted file mode 100644
--- a/browser/extensions/disableSHA1rollout/install.rdf.in
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0"?>
-<!-- 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/. -->
-
-#filter substitution
-
-<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
-
-  <Description about="urn:mozilla:install-manifest">
-    <em:id>disableSHA1rollout@mozilla.org</em:id>
-    <em:version>1.0</em:version>
-    <em:type>2</em:type>
-    <em:bootstrap>true</em:bootstrap>
-    <em:multiprocessCompatible>true</em:multiprocessCompatible>
-
-    <!-- Target Application this theme can install into,
-        with minimum and maximum supported versions. -->
-    <em:targetApplication>
-      <Description>
-        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
-        <em:minVersion>@MOZ_APP_VERSION@</em:minVersion>
-        <em:maxVersion>@MOZ_APP_MAXVERSION@</em:maxVersion>
-      </Description>
-    </em:targetApplication>
-
-    <!-- Front End MetaData -->
-    <em:name>SHA-1 deprecation staged rollout</em:name>
-    <em:description>Staged rollout deprecating SHA-1 in certificate signatures.</em:description>
-  </Description>
-</RDF>
deleted file mode 100644
--- a/browser/extensions/disableSHA1rollout/moz.build
+++ /dev/null
@@ -1,16 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
-DEFINES['MOZ_APP_MAXVERSION'] = CONFIG['MOZ_APP_MAXVERSION']
-
-FINAL_TARGET_FILES.features['disableSHA1rollout@mozilla.org'] += [
-  'bootstrap.js'
-]
-
-FINAL_TARGET_PP_FILES.features['disableSHA1rollout@mozilla.org'] += [
-  'install.rdf.in'
-]
--- a/browser/extensions/moz.build
+++ b/browser/extensions/moz.build
@@ -1,17 +1,16 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 DIRS += [
     'aushelper',
-    'disableSHA1rollout',
     'e10srollout',
     'pdfjs',
     'pocket',
     'webcompat',
     'shield-recipe-client',
 ]
 
 # Only include the following system add-ons if building Aurora or Nightly
--- a/testing/talos/talos/xtalos/xperf_whitelist.json
+++ b/testing/talos/talos/xtalos/xperf_whitelist.json
@@ -2,17 +2,16 @@
  "C:\\$Mft": {"ignore": true},
  "C:\\$Extend\\$UsnJrnl:$J": {"ignore": true},
  "C:\\Windows\\Prefetch\\{prefetch}.pf": {"ignore": true},
  "C:\\$Secure": {"ignore": true},
  "C:\\$logfile": {"ignore": true},
  "{firefox}\\omni.ja": {"mincount": 0, "maxcount": 46, "minbytes": 0, "maxbytes": 3014656},
  "{firefox}\\browser\\omni.ja": {"mincount": 0, "maxcount": 28, "minbytes": 0, "maxbytes": 1835008},
  "{firefox}\\browser\\features\\aushelper@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
- "{firefox}\\browser\\features\\disableSHA1rollout@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
  "{firefox}\\browser\\features\\e10srollout@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
  "{firefox}\\browser\\features\\flyweb@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
  "{firefox}\\browser\\features\\formautofill@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
  "{firefox}\\browser\\features\\loop@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
  "{firefox}\\browser\\features\\firefox@getpocket.com.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
  "{firefox}\\browser\\features\\presentation@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
  "{firefox}\\browser\\features\\webcompat@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
  "{firefox}\\browser\\features\\webcompat-reporter@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},