Bug 1250254 - Enable ESLint "no-throw-literal" rule for PSM. r=dkeeler
authorCykesiopka <cykesiopka.bmo@gmail.com>
Mon, 29 Feb 2016 20:05:55 -0800
changeset 322983 b670d8ff99cac57c38e8894f5d232ff389e9db89
parent 322982 6b33413601b004af5f66c5e74df137f2e1acfa6c
child 322984 8b0b020feaf6c2bfc5ddaaf030f3c107121ed568
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdkeeler
bugs1250254
milestone47.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 1250254 - Enable ESLint "no-throw-literal" rule for PSM. r=dkeeler MozReview-Commit-ID: LZcitO0FTWH
security/manager/.eslintrc
security/manager/.eslintrc.json
security/manager/pki/resources/content/exceptionDialog.js
security/manager/pki/resources/content/viewCertDetails.js
security/manager/ssl/tests/mochitest/browser/browser_bug627234_perwindowpb.js
security/manager/ssl/tests/mochitest/mixedcontent/mixedContentTest.js
security/manager/ssl/tests/unit/head_psm.js
security/manager/ssl/tests/unit/test_cert_blocklist.js
security/manager/ssl/tests/unit/test_pkcs11_safe_mode.js
security/manager/ssl/tests/unit/test_signed_apps.js
security/manager/tools/dumpGoogleRoots.js
security/manager/tools/genHPKPStaticPins.js
security/manager/tools/genRootCAHashes.js
security/manager/tools/getHSTSPreloadList.js
security/manager/tools/makeCNNICHashes.js
rename from security/manager/.eslintrc
rename to security/manager/.eslintrc.json
--- a/security/manager/.eslintrc
+++ b/security/manager/.eslintrc.json
@@ -123,16 +123,20 @@
     "no-self-compare": 2,
 
     // No declaring variables that hide things like arguments
     "no-shadow-restricted-names": 2,
 
     // No spaces between function name and parentheses
     "no-spaced-func": 2,
 
+    // Disallow throwing literals (eg. |throw "error"| instead of
+    // |throw new Error("error")|)
+    "no-throw-literal": 2,
+
     // No trailing whitespace
     "no-trailing-spaces": 2,
 
     // Error on newline where a semicolon is needed
     "no-unexpected-multiline": 2,
 
     // No unreachable statements
     "no-unreachable": 2,
@@ -169,11 +173,11 @@
 
     // ++ and -- should not need spacing
     "space-unary-ops": [2, { "words": true, "nonwords": false }],
 
     // No comparisons to NaN
     "use-isnan": 2,
 
     // Only check typeof against valid results
-    "valid-typeof": 2,
+    "valid-typeof": 2
   }
 }
--- a/security/manager/pki/resources/content/exceptionDialog.js
+++ b/security/manager/pki/resources/content/exceptionDialog.js
@@ -23,17 +23,17 @@ badCertListener.prototype = {
   },
   QueryInterface: function(aIID) {
     if (aIID.equals(Components.interfaces.nsIBadCertListener2) ||
         aIID.equals(Components.interfaces.nsIInterfaceRequestor) ||
         aIID.equals(Components.interfaces.nsISupports)) {
       return this;
     }
 
-    throw Components.results.NS_ERROR_NO_INTERFACE;
+    throw new Error(Components.results.NS_ERROR_NO_INTERFACE);
   },
   handle_test_result: function () {
     if (gSSLStatus) {
       gCert = gSSLStatus.QueryInterface(Components.interfaces.nsISSLStatus).serverCert;
     }
   },
   notifyCertProblem: function MSR_notifyCertProblem(socketInfo, sslStatus, targetHost) {
     gBroken = true;
--- a/security/manager/pki/resources/content/viewCertDetails.js
+++ b/security/manager/pki/resources/content/viewCertDetails.js
@@ -160,17 +160,17 @@ function listener() {
 
 listener.prototype.QueryInterface =
   function(iid) {
     if (iid.equals(Components.interfaces.nsISupports) ||
         iid.equals(Components.interfaces.nsICertVerificationListener)) {
       return this;
     }
 
-    throw Components.results.NS_ERROR_NO_INTERFACE;
+    throw new Error(Components.results.NS_ERROR_NO_INTERFACE);
   };
 
 listener.prototype.notify =
   function(cert, result) {
     DisplayVerificationData(cert, result);
   };
 
 function DisplayVerificationData(cert, result)
--- a/security/manager/ssl/tests/mochitest/browser/browser_bug627234_perwindowpb.js
+++ b/security/manager/ssl/tests/mochitest/browser/browser_bug627234_perwindowpb.js
@@ -16,17 +16,17 @@ FakeSSLStatus.prototype = {
   getInterface: function(aIID) {
     return this.QueryInterface(aIID);
   },
   QueryInterface: function(aIID) {
     if (aIID.equals(Ci.nsISSLStatus) ||
         aIID.equals(Ci.nsISupports)) {
       return this;
     }
-    throw Components.results.NS_ERROR_NO_INTERFACE;
+    throw new Error(Cr.NS_ERROR_NO_INTERFACE);
   },
 };
 
 // This is a template to help porting global private browsing tests
 // to per-window private browsing tests
 function test() {
   // initialization
   waitForExplicitFinish();
--- a/security/manager/ssl/tests/mochitest/mixedcontent/mixedContentTest.js
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/mixedContentTest.js
@@ -175,17 +175,17 @@ function isSecurityState(expectedState, 
       break;
     case "secure":
       test(ui && !isInsecure && !isBroken && !isEV, "for 'secure' expected flags [0,0,0], " + (message || ""));
       break;
     case "EV":
       test(ui && !isInsecure && !isBroken && isEV, "for 'EV' expected flags [0,0,1], " + (message || ""));
       break;
     default:
-      throw "Invalid isSecurityState state";
+      throw new Error("Invalid isSecurityState state");
   }
 }
 
 function waitForSecurityState(expectedState, callback)
 {
   var roundsLeft = 200; // Wait for 20 seconds (=200*100ms)
   var interval =
   window.setInterval(function() {
--- a/security/manager/ssl/tests/unit/head_psm.js
+++ b/security/manager/ssl/tests/unit/head_psm.js
@@ -224,17 +224,17 @@ function clearSessionCache() {
     SSL_ClearSessionCache =
       _getLibraryFunctionWithNoArguments("SSL_ClearSessionCache", "ssl3");
   } catch (e) {
     // On Windows, this is actually in the nss3 library.
     SSL_ClearSessionCache =
       _getLibraryFunctionWithNoArguments("SSL_ClearSessionCache", "nss3");
   }
   if (!SSL_ClearSessionCache || SSL_ClearSessionCache() != 0) {
-    throw "Failed to clear SSL session cache";
+    throw new Error("Failed to clear SSL session cache");
   }
 }
 
 // Set up a TLS testing environment that has a TLS server running and
 // ready to accept connections. This async function starts the server and
 // waits for the server to indicate that it is ready.
 //
 // Each test should have its own subdomain of example.com, for example
@@ -629,17 +629,17 @@ FakeSSLStatus.prototype = {
   getInterface: function(aIID) {
     return this.QueryInterface(aIID);
   },
   QueryInterface: function(aIID) {
     if (aIID.equals(Ci.nsISSLStatus) ||
         aIID.equals(Ci.nsISupports)) {
       return this;
     }
-    throw Components.results.NS_ERROR_NO_INTERFACE;
+    throw new Error(Cr.NS_ERROR_NO_INTERFACE);
   },
 };
 
 // Utility functions for adding tests relating to certificate error overrides
 
 // Helper function for add_cert_override_test. Probably doesn't need to be
 // called directly.
 function add_cert_override(aHost, aExpectedBits, aSecurityInfo) {
--- a/security/manager/ssl/tests/unit/test_cert_blocklist.js
+++ b/security/manager/ssl/tests/unit/test_cert_blocklist.js
@@ -47,17 +47,17 @@ var appInfo = {
                                          Ci.nsICrashReporter,
                                          Ci.nsISupports])
 };
 
 var XULAppInfoFactory = {
   createInstance: function (outer, iid) {
     appInfo.QueryInterface(iid);
     if (outer != null) {
-      throw Cr.NS_ERROR_NO_AGGREGATION;
+      throw new Error(Cr.NS_ERROR_NO_AGGREGATION);
     }
     return appInfo.QueryInterface(iid);
   }
 };
 
 // we need to ensure we setup revocation data before certDB, or we'll start with
 // no revocation.txt in the profile
 var profile = do_get_profile();
--- a/security/manager/ssl/tests/unit/test_pkcs11_safe_mode.js
+++ b/security/manager/ssl/tests/unit/test_pkcs11_safe_mode.js
@@ -20,17 +20,17 @@ function run_test() {
       // Do nothing
     },
     QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULRuntime])
   };
 
   let xulRuntimeFactory = {
     createInstance: function (outer, iid) {
       if (outer != null) {
-        throw Cr.NS_ERROR_NO_AGGREGATION;
+        throw new Error(Cr.NS_ERROR_NO_AGGREGATION);
       }
       return xulRuntime.QueryInterface(iid);
     }
   };
 
   let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
   const XULRUNTIME_CONTRACTID = "@mozilla.org/xre/runtime;1";
   const XULRUNTIME_CID = Components.ID("{f0f0b230-5525-4127-98dc-7bca39059e70}");
--- a/security/manager/ssl/tests/unit/test_signed_apps.js
+++ b/security/manager/ssl/tests/unit/test_signed_apps.js
@@ -69,17 +69,17 @@ function tamper(inFilePath, outFilePath,
     } finally {
       reader.close();
     }
 
     // Any leftover modification means that we were expecting to modify an entry
     // in the input file that wasn't there.
     for (let name in modifications) {
       if (modifications.hasOwnProperty(name)) {
-        throw "input file was missing expected entries: " + name;
+        throw new Error("input file was missing expected entries: " + name);
       }
     }
 
     // Now, append any new entries to the end
     newEntries.forEach(function(newEntry) {
       var sis = Cc["@mozilla.org/io/string-input-stream;1"]
                   .createInstance(Ci.nsIStringInputStream);
       try {
@@ -97,17 +97,18 @@ function tamper(inFilePath, outFilePath,
     writer.close();
   }
 }
 
 function removeEntry(entry, entryInput) { return [null, null]; }
 
 function truncateEntry(entry, entryInput) {
   if (entryInput.available() == 0) {
-    throw "Truncating already-zero length entry will result in identical entry.";
+    throw new Error("Truncating already-zero length entry will result in " +
+                    "identical entry.");
   }
 
   var content = Cc["@mozilla.org/io/string-input-stream;1"]
                   .createInstance(Ci.nsIStringInputStream);
   content.data = "";
 
   return [entry, content];
 }
--- a/security/manager/tools/dumpGoogleRoots.js
+++ b/security/manager/tools/dumpGoogleRoots.js
@@ -20,21 +20,22 @@ var Ci = Components.interfaces;
 function downloadRoots() {
   let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
               .createInstance(Ci.nsIXMLHttpRequest);
   req.open("GET", "https://pki.google.com/roots.pem", false);
   try {
     req.send();
   }
   catch (e) {
-    throw "ERROR: problem downloading Google Root PEMs: " + e;
+    throw new Error("ERROR: problem downloading Google Root PEMs: " + e);
   }
 
   if (req.status != 200) {
-    throw "ERROR: problem downloading Google Root PEMs. Status: " + req.status;
+    throw new Error("ERROR: problem downloading Google Root PEMs. Status: " +
+                    req.status);
   }
 
   let pem = req.responseText;
   let roots = [];
   let currentPEM = "";
   let readingRoot = false;
   let certDB = Cc["@mozilla.org/security/x509certdb;1"]
                  .getService(Ci.nsIX509CertDB);
--- a/security/manager/tools/genHPKPStaticPins.js
+++ b/security/manager/tools/genHPKPStaticPins.js
@@ -8,20 +8,20 @@
 // 3. run `[path to]/run-mozilla.sh [path to]/xpcshell \
 //                                  [path to]/genHPKPStaticpins.js \
 //                                  [absolute path to]/PreloadedHPKPins.json \
 //                                  [an unused argument - see bug 1205406] \
 //                                  [absolute path to]/StaticHPKPins.h
 "use strict";
 
 if (arguments.length != 3) {
-  throw "Usage: genHPKPStaticPins.js " +
-        "<absolute path to PreloadedHPKPins.json> " +
-        "<an unused argument - see bug 1205406> " +
-        "<absolute path to StaticHPKPins.h>";
+  throw new Error("Usage: genHPKPStaticPins.js " +
+                  "<absolute path to PreloadedHPKPins.json> " +
+                  "<an unused argument - see bug 1205406> " +
+                  "<absolute path to StaticHPKPins.h>");
 }
 
 var { 'classes': Cc, 'interfaces': Ci, 'utils': Cu, 'results': Cr } = Components;
 
 var { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
 var { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {});
 var { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
 
@@ -117,42 +117,44 @@ function isCertBuiltIn(cert) {
 function download(filename) {
   let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
               .createInstance(Ci.nsIXMLHttpRequest);
   req.open("GET", filename, false); // doing the request synchronously
   try {
     req.send();
   }
   catch (e) {
-    throw "ERROR: problem downloading '" + filename + "': " + e;
+    throw new Error(`ERROR: problem downloading '${filename}': ${e}`);
   }
 
   if (req.status != 200) {
-    throw `ERROR: problem downloading '${filename}': status ${req.status}`;
+    throw new Error("ERROR: problem downloading '" + filename + "': status " +
+                    req.status);
   }
 
   let resultDecoded;
   try {
     resultDecoded = atob(req.responseText);
   }
   catch (e) {
-    throw "ERROR: could not decode data as base64 from '" + filename + "': " + e;
+    throw new Error("ERROR: could not decode data as base64 from '" + filename +
+                    "': " + e);
   }
   return resultDecoded;
 }
 
 function downloadAsJson(filename) {
   // we have to filter out '//' comments, while not mangling the json
   let result = download(filename).replace(/^(\s*)?\/\/[^\n]*\n/mg, "");
   let data = null;
   try {
     data = JSON.parse(result);
   }
   catch (e) {
-    throw "ERROR: could not parse data from '" + filename + "': " + e;
+    throw new Error("ERROR: could not parse data from '" + filename + "': " + e);
   }
   return data;
 }
 
 // Returns a Subject Public Key Digest from the given pem, if it exists.
 function getSKDFromPem(pem) {
   let cert = gCertDB.constructX509FromBase64(pem, pem.length);
   return cert.sha256SubjectPublicKeyInfoDigest;
@@ -166,17 +168,17 @@ function getSKDFromPem(pem) {
  * @returns {String} Base64 encoded SHA-256 hash.
  */
 function sha256Base64(input) {
   let decodedValue;
   try {
     decodedValue = atob(input);
   }
   catch (e) {
-    throw `ERROR: could not decode as base64: '${input}': ${e}`;
+    throw new Error(`ERROR: could not decode as base64: '${input}': ${e}`);
   }
 
   // Convert |decodedValue| to an array so that it can be hashed by the
   // nsICryptoHash instance below.
   // In most cases across the code base, convertToByteArray() of
   // nsIScriptableUnicodeConverter is used to do this, but the method doesn't
   // seem to work here.
   let data = [];
@@ -250,17 +252,18 @@ function downloadAndParseChromeCerts(fil
           certNameToSKD[chromeName] = hash;
           certSKDToName[hash] = chromeName;
           state = PRE_NAME;
         } else if (line.startsWith(BEGIN_CERT)) {
           state = IN_CERT;
         } else if (line.startsWith(BEGIN_PUB_KEY)) {
           state = IN_PUB_KEY;
         } else {
-          throw "ERROR: couldn't parse Chrome certificate file " + line;
+          throw new Error("ERROR: couldn't parse Chrome certificate file " +
+                          "line: " + line);
         }
         break;
       case IN_CERT:
         if (line.startsWith(END_CERT)) {
           state = PRE_NAME;
           hash = getSKDFromPem(pemCert);
           pemCert = "";
           let mozName;
@@ -288,17 +291,17 @@ function downloadAndParseChromeCerts(fil
           chromeNameToHash[chromeName] = hash;
           certNameToSKD[chromeName] = hash;
           certSKDToName[hash] = chromeName;
         } else {
           pemPubKey += line;
         }
         break;
       default:
-        throw "ERROR: couldn't parse Chrome certificate file " + line;
+        throw new Error("ERROR: couldn't parse Chrome certificate file " + line);
     }
   }
   return [ chromeNameToHash, chromeNameToMozName ];
 }
 
 // We can only import pinsets from chrome if for every name in the pinset:
 // - We have a hash from Chrome's static certificate file
 // - We have a builtin cert
@@ -330,17 +333,17 @@ function downloadAndParseChromePins(file
     pin.static_spki_hashes.forEach(function(name) {
       if (name in chromeNameToHash) {
         let hash = chromeNameToHash[name];
         pinset.sha256_hashes.push(certSKDToName[hash]);
 
         // We should have already added hashes for all of these when we
         // imported the certificate file.
         if (!certNameToSKD[name]) {
-          throw "No hash for name: " + name;
+          throw new Error("ERROR: No hash for name: " + name);
         }
       } else if (name in chromeNameToMozName) {
         pinset.sha256_hashes.push(chromeNameToMozName[name]);
       } else {
         dump("Skipping Chrome pinset " + pinset.name + ", couldn't find " +
              "builtin " + name + " from cert file\n");
         valid = false;
       }
@@ -444,29 +447,29 @@ function genExpirationTime() {
   let expirationMicros = expirationMillis * 1000;
   return "static const PRTime kPreloadPKPinsExpirationTime = INT64_C(" +
          expirationMicros + ");\n";
 }
 
 function writeFullPinset(certNameToSKD, certSKDToName, pinset) {
   let prefix = "kPinset_" + pinset.name;
   if (!pinset.sha256_hashes || pinset.sha256_hashes.length == 0) {
-    throw `ERROR: Pinset ${pinset.name} does not contain any hashes.`;
+    throw new Error(`ERROR: Pinset ${pinset.name} does not contain any hashes`);
   }
   writeFingerprints(certNameToSKD, certSKDToName, pinset.name,
                     pinset.sha256_hashes);
 }
 
 function writeFingerprints(certNameToSKD, certSKDToName, name, hashes) {
   let varPrefix = "kPinset_" + name;
   writeString("static const char* " + varPrefix + "_Data[] = {\n");
   let SKDList = [];
   for (let certName of hashes) {
     if (!(certName in certNameToSKD)) {
-      throw "Can't find " + certName + " in certNameToSKD";
+      throw new Error(`ERROR: Can't find '${certName}' in certNameToSKD`);
     }
     SKDList.push(certNameToSKD[certName]);
   }
   for (let skd of SKDList.sort()) {
     writeString("  " + nameToAlias(certSKDToName[skd]) + ",\n");
   }
   if (hashes.length == 0) {
     // ANSI C requires that an initialiser list be non-empty.
@@ -498,17 +501,17 @@ function writeEntry(entry) {
   if (entry.is_moz || (entry.pins.indexOf("mozilla") != -1 &&
                        entry.pins != "mozilla_test")) {
     printVal += "true, ";
   } else {
     printVal += "false, ";
   }
   if ("id" in entry) {
     if (entry.id >= 256) {
-      throw "Not enough buckets in histogram";
+      throw new Error("ERROR: Not enough buckets in histogram");
     }
     if (entry.id >= 0) {
       printVal += entry.id + ", ";
     }
   } else {
     printVal += "-1, ";
   }
   printVal += "&kPinset_" + entry.pins;
--- a/security/manager/tools/genRootCAHashes.js
+++ b/security/manager/tools/genRootCAHashes.js
@@ -210,18 +210,19 @@ function insertTrustAnchorsFromDatabase(
     }
   }
 }
 
 //
 //  PRIMARY LOGIC
 //
 
-if (arguments.length < 1) {
-  throw "Usage: genRootCAHashes.js <absolute path to current RootHashes.inc>";
+if (arguments.length != 1) {
+  throw new Error("Usage: genRootCAHashes.js " +
+                  "<absolute path to current RootHashes.inc>");
 }
 
 var trustAnchorsFile = FileUtils.getFile("CurWorkD", [FILENAME_TRUST_ANCHORS]);
 // let rootHashesFile = FileUtils.getFile("CurWorkD", arguments[0]);
 var rootHashesFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
 rootHashesFile.initWithPath(arguments[0]);
 
 // Open the known hashes file; this is to ensure stable bin numbers.
--- a/security/manager/tools/getHSTSPreloadList.js
+++ b/security/manager/tools/getHSTSPreloadList.js
@@ -55,58 +55,61 @@ const POSTFIX =  "};\n";
 function download() {
   var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
             .createInstance(Ci.nsIXMLHttpRequest);
   req.open("GET", SOURCE, false); // doing the request synchronously
   try {
     req.send();
   }
   catch (e) {
-    throw "ERROR: problem downloading '" + SOURCE + "': " + e;
+    throw new Error(`ERROR: problem downloading '${SOURCE}': ${e}`);
   }
 
   if (req.status != 200) {
-    throw "ERROR: problem downloading '" + SOURCE + "': status " + req.status;
+    throw new Error("ERROR: problem downloading '" + SOURCE + "': status " +
+                    req.status);
   }
 
   var resultDecoded;
   try {
     resultDecoded = atob(req.responseText);
   }
   catch (e) {
-    throw "ERROR: could not decode data as base64 from '" + SOURCE + "': " + e;
+    throw new Error("ERROR: could not decode data as base64 from '" + SOURCE +
+                    "': " + e);
   }
 
   // we have to filter out '//' comments, while not mangling the json
   var result = resultDecoded.replace(/^(\s*)?\/\/[^\n]*\n/mg, "");
   var data = null;
   try {
     data = JSON.parse(result);
   }
   catch (e) {
-    throw "ERROR: could not parse data from '" + SOURCE + "': " + e;
+    throw new Error(`ERROR: could not parse data from '${SOURCE}': ${e}`);
   }
   return data;
 }
 
 function getHosts(rawdata) {
   var hosts = [];
 
   if (!rawdata || !rawdata.entries) {
-    throw "ERROR: source data not formatted correctly: 'entries' not found";
+    throw new Error("ERROR: source data not formatted correctly: 'entries' " +
+                    "not found");
   }
 
   for (entry of rawdata.entries) {
     if (entry.mode && entry.mode == "force-https") {
       if (entry.name) {
         entry.retries = MAX_RETRIES;
         entry.originalIncludeSubdomains = entry.include_subdomains;
         hosts.push(entry);
       } else {
-        throw "ERROR: entry not formatted correctly: no name found";
+        throw new Error("ERROR: entry not formatted correctly: no name found");
       }
     }
   }
 
   return hosts;
 }
 
 var gSSService = Cc["@mozilla.org/ssservice;1"]
@@ -152,26 +155,26 @@ function processStsHeader(host, header, 
 }
 
 // RedirectAndAuthStopper prevents redirects and HTTP authentication
 function RedirectAndAuthStopper() {}
 
 RedirectAndAuthStopper.prototype = {
   // nsIChannelEventSink
   asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) {
-    throw Cr.NS_ERROR_ENTITY_CHANGED;
+    throw new Error(Cr.NS_ERROR_ENTITY_CHANGED);
   },
 
   // nsIAuthPrompt2
   promptAuth: function(channel, level, authInfo) {
     return false;
   },
 
   asyncPromptAuth: function(channel, callback, context, level, authInfo) {
-    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+    throw new Error(Cr.NS_ERROR_NOT_IMPLEMENTED);
   },
 
   getInterface: function(iid) {
     return this.QueryInterface(iid);
   },
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannelEventSink,
                                          Ci.nsIAuthPrompt2])
@@ -366,18 +369,19 @@ function combineLists(newHosts, currentH
     if (!found) {
       newHosts.push({ name: currentHost, retries: MAX_RETRIES });
     }
   }
 }
 
 // ****************************************************************************
 // This is where the action happens:
-if (arguments.length < 1) {
-  throw "Usage: getHSTSPreloadList.js <absolute path to current nsSTSPreloadList.inc>";
+if (arguments.length != 1) {
+  throw new Error("Usage: getHSTSPreloadList.js " +
+                  "<absolute path to current nsSTSPreloadList.inc>");
 }
 // get the current preload list
 var currentHosts = readCurrentList(arguments[0]);
 // disable the current preload list so it won't interfere with requests we make
 Services.prefs.setBoolPref("network.stricttransportsecurity.preloadlist", false);
 // download and parse the raw json file from the Chromium source
 var rawdata = download();
 // get just the hosts with mode: "force-https"
--- a/security/manager/tools/makeCNNICHashes.js
+++ b/security/manager/tools/makeCNNICHashes.js
@@ -2,17 +2,20 @@
  * 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/. */
 
 // How to run this file:
 // 1. [obtain CNNIC-issued certificates to be whitelisted]
 // 2. [obtain firefox source code]
 // 3. [build/obtain firefox binaries]
 // 4. run `[path to]/run-mozilla.sh [path to]/xpcshell makeCNNICHashes.js \
+//                                  [path to]/intermediatesFile
 //                                  [path to]/certlist'
+//    Where |intermediatesFile| is a file containing PEM encoded intermediate
+//    certificates that the certificates in |certlist| may be issued by.
 //    where certlist is a file containing a list of paths to certificates to
 //    be included in the whitelist
 
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 var Cu = Components.utils;
 
 var gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
@@ -227,17 +230,18 @@ function loadIntermediates(intermediates
   return intermediates;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 
 if (arguments.length != 2) {
-  throw "Usage: makeCNNICHashes.js <intermediates file> <path to list of certificates>";
+  throw new Error("Usage: makeCNNICHashes.js <PEM intermediates file> " +
+                  "<path to list of certificates>");
 }
 
 Services.prefs.setIntPref("security.OCSP.enabled", 0);
 var intermediatesFile = pathToFile(arguments[0]);
 var intermediates = loadIntermediates(intermediatesFile);
 var certFile = pathToFile(arguments[1]);
 var { certs, lastValidTime, invalidCerts } = loadCertificates(certFile);