зеркало из https://github.com/mozilla/gecko-dev.git
bug 786417 - filter the hsts preload list to sites that actually send the header r=bsmith, mayhemer
This commit is contained in:
Родитель
bcd437d0de
Коммит
27d5157e2b
|
@ -1249,6 +1249,9 @@ pref("network.proxy.autoconfig_url", "");
|
|||
pref("network.proxy.autoconfig_retry_interval_min", 5); // 5 seconds
|
||||
pref("network.proxy.autoconfig_retry_interval_max", 300); // 5 minutes
|
||||
|
||||
// Use the HSTS preload list by default
|
||||
pref("network.stricttransportsecurity.preloadlist", true);
|
||||
|
||||
pref("converter.html2txt.structs", true); // Output structured phrases (strong, em, code, sub, sup, b, i, u)
|
||||
pref("converter.html2txt.header_strategy", 1); // 0 = no indention; 1 = indention, increased with header level; 2 = numbering and slight indention
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ interface nsIURI;
|
|||
interface nsIObserver;
|
||||
interface nsIHttpChannel;
|
||||
|
||||
[scriptable, uuid(16955eee-6c48-4152-9309-c42a465138a1)]
|
||||
[scriptable, uuid(aee925d1-2bc9-469e-9582-b27b1d6b5192)]
|
||||
interface nsIStrictTransportSecurityService : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -20,13 +20,17 @@ interface nsIStrictTransportSecurityService : nsISupports
|
|||
*
|
||||
* @param aSourceURI the URI of the resource with the HTTP header.
|
||||
* @param aHeader the HTTP response header specifying STS data.
|
||||
* @param aMaxAge the parsed max-age directive of the header.
|
||||
* @param aIncludeSubdomains the parsed includeSubdomains directive.
|
||||
* @return NS_OK if it succeeds
|
||||
* NS_ERROR_FAILURE if it can't be parsed
|
||||
* NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA
|
||||
* if there are unrecognized tokens in the header.
|
||||
*/
|
||||
void processStsHeader(in nsIURI aSourceURI,
|
||||
in string aHeader);
|
||||
in string aHeader,
|
||||
[optional] out unsigned long long aMaxAge,
|
||||
[optional] out boolean aIncludeSubdomains);
|
||||
|
||||
/**
|
||||
* Removes the STS state of a host, including the includeSubdomains state
|
||||
|
|
|
@ -1149,7 +1149,7 @@ nsHttpChannel::ProcessSTSHeader()
|
|||
// All other failures are fatal.
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = stss->ProcessStsHeader(mURI, stsHeader.get());
|
||||
rv = stss->ProcessStsHeader(mURI, stsHeader.get(), NULL, NULL);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("STS: Failed to parse STS header, continuing load.\n"));
|
||||
return NS_OK;
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
|
||||
bool
|
||||
TestSuccess(const char* hdr, bool extraTokens,
|
||||
uint64_t expectedMaxAge, bool expectedIncludeSubdomains,
|
||||
nsIStrictTransportSecurityService* stss,
|
||||
nsIPermissionManager* pm)
|
||||
{
|
||||
|
@ -46,9 +47,14 @@ TestSuccess(const char* hdr, bool extraTokens,
|
|||
nsresult rv = NS_NewURI(getter_AddRefs(dummyUri), "https://foo.com/bar.html");
|
||||
EXPECT_SUCCESS(rv, "Failed to create URI");
|
||||
|
||||
rv = stss->ProcessStsHeader(dummyUri, hdr);
|
||||
uint64_t maxAge = 0;
|
||||
bool includeSubdomains = false;
|
||||
rv = stss->ProcessStsHeader(dummyUri, hdr, &maxAge, &includeSubdomains);
|
||||
EXPECT_SUCCESS(rv, "Failed to process valid header: %s", hdr);
|
||||
|
||||
REQUIRE_EQUAL(maxAge, expectedMaxAge, "Did not correctly parse maxAge");
|
||||
REQUIRE_EQUAL(includeSubdomains, expectedIncludeSubdomains, "Did not correctly parse presence/absence of includeSubdomains");
|
||||
|
||||
if (extraTokens) {
|
||||
REQUIRE_EQUAL(rv, NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA,
|
||||
"Extra tokens were expected when parsing, but were not encountered.");
|
||||
|
@ -68,7 +74,7 @@ bool TestFailure(const char* hdr,
|
|||
nsresult rv = NS_NewURI(getter_AddRefs(dummyUri), "https://foo.com/bar.html");
|
||||
EXPECT_SUCCESS(rv, "Failed to create URI");
|
||||
|
||||
rv = stss->ProcessStsHeader(dummyUri, hdr);
|
||||
rv = stss->ProcessStsHeader(dummyUri, hdr, NULL, NULL);
|
||||
EXPECT_FAILURE(rv, "Parsed invalid header: %s", hdr);
|
||||
passed(hdr);
|
||||
return true;
|
||||
|
@ -106,36 +112,36 @@ main(int32_t argc, char *argv[])
|
|||
printf("*** Attempting to parse valid STS headers ...\n");
|
||||
|
||||
// SHOULD SUCCEED:
|
||||
rvs.AppendElement(TestSuccess("max-age=100", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age =100", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess(" max-age=100", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age = 100 ", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age = 100 ", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age=100", false, 100, false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age =100", false, 100, false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess(" max-age=100", false, 100, false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age = 100 ", false, 100, false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age = 100 ", false, 100, false, stss, pm));
|
||||
|
||||
rvs.AppendElement(TestSuccess("maX-aGe=100", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("MAX-age =100", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-AGE=100", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("Max-Age = 100 ", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("MAX-AGE = 100 ", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("maX-aGe=100", false, 100, false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("MAX-age =100", false, 100, false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-AGE=100", false, 100, false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("Max-Age = 100 ", false, 100, false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("MAX-AGE = 100 ", false, 100, false, stss, pm));
|
||||
|
||||
rvs.AppendElement(TestSuccess("max-age=100;includeSubdomains", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age=100; includeSubdomains", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess(" max-age=100; includeSubdomains", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age = 100 ; includeSubdomains", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age = 100 ; includeSubdomains", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age=100;includeSubdomains", false, 100, true, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age=100; includeSubdomains", false, 100, true, stss, pm));
|
||||
rvs.AppendElement(TestSuccess(" max-age=100; includeSubdomains", false, 100, true, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age = 100 ; includeSubdomains", false, 100, true, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age = 100 ; includeSubdomains", false, 100, true, stss, pm));
|
||||
|
||||
rvs.AppendElement(TestSuccess("maX-aGe=100; includeSUBDOMAINS", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("MAX-age =100; includeSubDomains", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-AGE=100; iNcLuDeSuBdoMaInS", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("Max-Age = 100; includesubdomains ", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("INCLUDESUBDOMAINS;MaX-AgE = 100 ", false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("maX-aGe=100; includeSUBDOMAINS", false, 100, true, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("MAX-age =100; includeSubDomains", false, 100, true, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-AGE=100; iNcLuDeSuBdoMaInS", false, 100, true, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("Max-Age = 100; includesubdomains ", false, 100, true, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("INCLUDESUBDOMAINS;MaX-AgE = 100 ", false, 100, true, stss, pm));
|
||||
|
||||
// these are weird tests, but are testing that some extended syntax is
|
||||
// still allowed (but it is ignored)
|
||||
rvs.AppendElement(TestSuccess("max-age=100randomstuffhere", true, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age=100 includesubdomains", true, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age=100 bar foo", true, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age=100 ; includesubdomainsSomeStuff", true, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age=100randomstuffhere", true, 100, false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age=100 includesubdomains", true, 100, false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age=100 bar foo", true, 100, false, stss, pm));
|
||||
rvs.AppendElement(TestSuccess("max-age=100 ; includesubdomainsSomeStuff", true, 100, false, stss, pm));
|
||||
|
||||
rv0 = rvs.Contains(false) ? 1 : 0;
|
||||
if (rv0 == 0)
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
accounts.google.com: max-age too low: 2592000
|
||||
aladdinschools.appspot.com: did not receive HSTS header
|
||||
api.recurly.com: did not receive HSTS header
|
||||
apis.google.com: did not receive HSTS header
|
||||
appengine.google.com: did not receive HSTS header
|
||||
betnet.fr: could not connect to host
|
||||
bigshinylock.minazo.net: could not connect to host
|
||||
braintreegateway.com: could not connect to host
|
||||
braintreepayments.com: did not receive HSTS header
|
||||
browserid.org: did not receive HSTS header
|
||||
cert.se: did not receive HSTS header
|
||||
checkout.google.com: did not receive HSTS header
|
||||
chrome.google.com: did not receive HSTS header
|
||||
chromiumcodereview.appspot.com: did not receive HSTS header
|
||||
codereview.appspot.com: did not receive HSTS header
|
||||
docs.google.com: did not receive HSTS header
|
||||
download.jitsi.org: did not receive HSTS header
|
||||
drive.google.com: did not receive HSTS header
|
||||
dropcam.com: did not receive HSTS header
|
||||
emailprivacytester.com: max-age too low: 8640000
|
||||
encrypted.google.com: did not receive HSTS header
|
||||
entropia.de: max-age too low: 2678402
|
||||
epoxate.com: max-age too low: 259200
|
||||
fatzebra.com.au: did not receive HSTS header
|
||||
gmail.com: did not receive HSTS header
|
||||
googlemail.com: did not receive HSTS header
|
||||
googleplex.com: could not connect to host
|
||||
greplin.com: did not receive HSTS header
|
||||
grepular.com: max-age too low: 8640000
|
||||
groups.google.com: did not receive HSTS header
|
||||
health.google.com: did not receive HSTS header
|
||||
hostedtalkgadget.google.com: did not receive HSTS header
|
||||
howrandom.org: max-age too low: 2592000
|
||||
iop.intuit.com: did not receive HSTS header
|
||||
irccloud.com: did not receive HSTS header
|
||||
jitsi.org: did not receive HSTS header
|
||||
jottit.com: could not connect to host
|
||||
kyps.net: did not receive HSTS header
|
||||
lastpass.com: max-age too low: 8640000
|
||||
ledgerscope.net: max-age too low: 86400
|
||||
linx.net: could not connect to host
|
||||
lists.mayfirst.org: did not receive HSTS header
|
||||
login.persona.org: max-age too low: 2592000
|
||||
lookout.com: did not receive HSTS header
|
||||
mail.google.com: did not receive HSTS header
|
||||
market.android.com: did not receive HSTS header
|
||||
mydigipass.com: did not receive HSTS header
|
||||
mylookout.com: did not receive HSTS header
|
||||
neonisi.com: could not connect to host
|
||||
ottospora.nl: could not connect to host
|
||||
packagist.org: max-age too low: 2592000
|
||||
plus.google.com: did not receive HSTS header
|
||||
profiles.google.com: did not receive HSTS header
|
||||
romab.com: max-age too low: 2628000
|
||||
script.google.com: did not receive HSTS header
|
||||
shops.neonisi.com: could not connect to host
|
||||
simon.butcher.name: max-age too low: 2629743
|
||||
sites.google.com: did not receive HSTS header
|
||||
sol.io: could not connect to host
|
||||
spreadsheets.google.com: did not receive HSTS header
|
||||
squareup.com: max-age too low: 1296000
|
||||
ssl.google-analytics.com: did not receive HSTS header
|
||||
sunshinepress.org: could not connect to host
|
||||
talk.google.com: did not receive HSTS header
|
||||
talkgadget.google.com: did not receive HSTS header
|
||||
torproject.org: did not receive HSTS header
|
||||
uprotect.it: could not connect to host
|
||||
www.developer.mydigipass.com: did not receive HSTS header
|
||||
www.dropcam.com: max-age too low: 2592000
|
||||
www.entropia.de: max-age too low: 2678402
|
||||
www.gmail.com: did not receive HSTS header
|
||||
www.googlemail.com: did not receive HSTS header
|
||||
www.greplin.com: did not receive HSTS header
|
||||
www.irccloud.com: did not receive HSTS header
|
||||
www.jitsi.org: did not receive HSTS header
|
||||
www.kyps.net: did not receive HSTS header
|
||||
www.lastpass.com: did not receive HSTS header
|
||||
www.ledgerscope.net: max-age too low: 86400
|
||||
www.logentries.com: did not receive HSTS header
|
||||
www.makeyourlaws.org: did not receive HSTS header
|
||||
www.moneybookers.com: did not receive HSTS header
|
||||
www.neonisi.com: could not connect to host
|
||||
www.paycheckrecords.com: did not receive HSTS header
|
||||
www.paypal.com: max-age too low: 14400
|
||||
www.sandbox.mydigipass.com: did not receive HSTS header
|
|
@ -7,8 +7,6 @@
|
|||
/* nsStrictTransportSecurityService.cpp, you shouldn't be #including it. */
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <prtypes.h>
|
||||
|
||||
class nsSTSPreload
|
||||
{
|
||||
public:
|
||||
|
@ -17,119 +15,51 @@ class nsSTSPreload
|
|||
};
|
||||
|
||||
static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "accounts.google.com", true },
|
||||
{ "aladdinschools.appspot.com", false },
|
||||
{ "alpha.irccloud.com", false },
|
||||
{ "api.recurly.com", true },
|
||||
{ "apis.google.com", true },
|
||||
{ "app.recurly.com", true },
|
||||
{ "appengine.google.com", false },
|
||||
{ "api.intercom.io", false },
|
||||
{ "app.recurly.com", false },
|
||||
{ "arivo.com.br", true },
|
||||
{ "betnet.fr", true },
|
||||
{ "bigshinylock.minazo.net", true },
|
||||
{ "blog.torproject.org", true },
|
||||
{ "braintreegateway.com", true },
|
||||
{ "braintreepayments.com", false },
|
||||
{ "browserid.org", true },
|
||||
{ "blog.torproject.org", false },
|
||||
{ "business.medbank.com.mt", true },
|
||||
{ "cert.se", true },
|
||||
{ "check.torproject.org", true },
|
||||
{ "checkout.google.com", true },
|
||||
{ "chrome.google.com", true },
|
||||
{ "chromiumcodereview.appspot.com", true },
|
||||
{ "cloudsecurityalliance.org", true },
|
||||
{ "codereview.appspot.com", true },
|
||||
{ "check.torproject.org", false },
|
||||
{ "cloudsecurityalliance.org", false },
|
||||
{ "crate.io", true },
|
||||
{ "crypto.cat", true },
|
||||
{ "crypto.is", true },
|
||||
{ "csawctf.poly.edu", true },
|
||||
{ "developer.mydigipass.com", false },
|
||||
{ "docs.google.com", true },
|
||||
{ "download.jitsi.org", false },
|
||||
{ "drive.google.com", true },
|
||||
{ "dropcam.com", false },
|
||||
{ "ebanking.indovinabank.com.vn", true },
|
||||
{ "emailprivacytester.com", false },
|
||||
{ "encrypted.google.com", true },
|
||||
{ "entropia.de", false },
|
||||
{ "epoxate.com", false },
|
||||
{ "dm.lookout.com", false },
|
||||
{ "dm.mylookout.com", false },
|
||||
{ "ebanking.indovinabank.com.vn", false },
|
||||
{ "factor.cc", false },
|
||||
{ "gmail.com", false },
|
||||
{ "googlemail.com", false },
|
||||
{ "googleplex.com", true },
|
||||
{ "greplin.com", false },
|
||||
{ "grepular.com", true },
|
||||
{ "groups.google.com", true },
|
||||
{ "health.google.com", true },
|
||||
{ "hostedtalkgadget.google.com", true },
|
||||
{ "howrandom.org", true },
|
||||
{ "id.mayfirst.org", false },
|
||||
{ "irccloud.com", false },
|
||||
{ "jitsi.org", false },
|
||||
{ "jottit.com", true },
|
||||
{ "intercom.io", false },
|
||||
{ "keyerror.com", true },
|
||||
{ "kyps.net", false },
|
||||
{ "lastpass.com", false },
|
||||
{ "ledgerscope.net", false },
|
||||
{ "linx.net", true },
|
||||
{ "lists.mayfirst.org", false },
|
||||
{ "logentries.com", false },
|
||||
{ "login.persona.org", true },
|
||||
{ "login.sapo.pt", true },
|
||||
{ "luneta.nearbuysystems.com", true },
|
||||
{ "mail.google.com", true },
|
||||
{ "market.android.com", true },
|
||||
{ "luneta.nearbuysystems.com", false },
|
||||
{ "makeyourlaws.org", false },
|
||||
{ "mattmccutchen.net", true },
|
||||
{ "members.mayfirst.org", false },
|
||||
{ "mydigipass.com", false },
|
||||
{ "neg9.org", false },
|
||||
{ "neonisi.com", false },
|
||||
{ "ottospora.nl", true },
|
||||
{ "passwd.io", true },
|
||||
{ "piratenlogin.de", true },
|
||||
{ "pixi.me", true },
|
||||
{ "plus.google.com", true },
|
||||
{ "profiles.google.com", true },
|
||||
{ "riseup.net", true },
|
||||
{ "romab.com", true },
|
||||
{ "sandbox.mydigipass.com", false },
|
||||
{ "script.google.com", true },
|
||||
{ "shops.neonisi.com", true },
|
||||
{ "simon.butcher.name", true },
|
||||
{ "sites.google.com", true },
|
||||
{ "sol.io", true },
|
||||
{ "spreadsheets.google.com", true },
|
||||
{ "squareup.com", false },
|
||||
{ "ssl.google-analytics.com", true },
|
||||
{ "stripe.com", true },
|
||||
{ "sunshinepress.org", true },
|
||||
{ "support.mayfirst.org", false },
|
||||
{ "talk.google.com", true },
|
||||
{ "talkgadget.google.com", true },
|
||||
{ "torproject.org", false },
|
||||
{ "surfeasy.com", false },
|
||||
{ "ubertt.org", true },
|
||||
{ "uprotect.it", true },
|
||||
{ "www.apollo-auto.com", true },
|
||||
{ "www.braintreepayments.com", false },
|
||||
{ "www.cueup.com", true },
|
||||
{ "www.developer.mydigipass.com", false },
|
||||
{ "www.dropcam.com", false },
|
||||
{ "www.cueup.com", false },
|
||||
{ "www.elanex.biz", false },
|
||||
{ "www.entropia.de", false },
|
||||
{ "www.gmail.com", false },
|
||||
{ "www.googlemail.com", false },
|
||||
{ "www.greplin.com", false },
|
||||
{ "www.irccloud.com", false },
|
||||
{ "www.jitsi.org", false },
|
||||
{ "www.kyps.net", false },
|
||||
{ "www.lastpass.com", false },
|
||||
{ "www.ledgerscope.net", false },
|
||||
{ "www.logentries.com", false },
|
||||
{ "www.moneybookers.com", true },
|
||||
{ "www.intercom.io", false },
|
||||
{ "www.lookout.com", false },
|
||||
{ "www.mydigipass.com", false },
|
||||
{ "www.neonisi.com", true },
|
||||
{ "www.mylookout.com", false },
|
||||
{ "www.noisebridge.net", false },
|
||||
{ "www.paycheckrecords.com", false },
|
||||
{ "www.paypal.com", false },
|
||||
{ "www.sandbox.mydigipass.com", false },
|
||||
{ "www.torproject.org", true },
|
||||
{ "www.surfeasy.com", false },
|
||||
{ "www.torproject.org", false },
|
||||
};
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "nsThreadUtils.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
// A note about the preload list:
|
||||
// When a site specifically disables sts by sending a header with
|
||||
|
@ -67,7 +68,7 @@ nsSTSHostEntry::nsSTSHostEntry(const nsSTSHostEntry& toCopy)
|
|||
|
||||
|
||||
nsStrictTransportSecurityService::nsStrictTransportSecurityService()
|
||||
: mInPrivateMode(false)
|
||||
: mInPrivateMode(false), mUsePreloadList(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -93,6 +94,8 @@ nsStrictTransportSecurityService::Init()
|
|||
if (pbs)
|
||||
pbs->GetPrivateBrowsingEnabled(&mInPrivateMode);
|
||||
|
||||
mUsePreloadList = mozilla::Preferences::GetBool("network.stricttransportsecurity.preloadlist", true);
|
||||
mozilla::Preferences::AddStrongObserver(this, "network.stricttransportsecurity.preloadlist");
|
||||
mObserverService = mozilla::services::GetObserverService();
|
||||
if (mObserverService)
|
||||
mObserverService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, false);
|
||||
|
@ -209,22 +212,35 @@ nsStrictTransportSecurityService::RemoveStsState(nsIURI* aURI)
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsStrictTransportSecurityService::ProcessStsHeader(nsIURI* aSourceURI,
|
||||
const char* aHeader)
|
||||
const char* aHeader,
|
||||
uint64_t *aMaxAge,
|
||||
bool *aIncludeSubdomains)
|
||||
{
|
||||
// Should be called on the main thread (or via proxy) since the permission
|
||||
// manager is used and it's not threadsafe.
|
||||
NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_UNEXPECTED);
|
||||
|
||||
if (aMaxAge != nullptr) {
|
||||
*aMaxAge = 0;
|
||||
}
|
||||
|
||||
if (aIncludeSubdomains != nullptr) {
|
||||
*aIncludeSubdomains = false;
|
||||
}
|
||||
|
||||
char * header = NS_strdup(aHeader);
|
||||
if (!header) return NS_ERROR_OUT_OF_MEMORY;
|
||||
nsresult rv = ProcessStsHeaderMutating(aSourceURI, header);
|
||||
nsresult rv = ProcessStsHeaderMutating(aSourceURI, header, aMaxAge,
|
||||
aIncludeSubdomains);
|
||||
NS_Free(header);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStrictTransportSecurityService::ProcessStsHeaderMutating(nsIURI* aSourceURI,
|
||||
char* aHeader)
|
||||
char* aHeader,
|
||||
uint64_t *aMaxAge,
|
||||
bool *aIncludeSubdomains)
|
||||
{
|
||||
STSLOG(("STS: ProcessStrictTransportHeader(%s)\n", aHeader));
|
||||
|
||||
|
@ -317,6 +333,14 @@ nsStrictTransportSecurityService::ProcessStsHeaderMutating(nsIURI* aSourceURI,
|
|||
// record the successfully parsed header data.
|
||||
SetStsState(aSourceURI, maxAge, includeSubdomains);
|
||||
|
||||
if (aMaxAge != nullptr) {
|
||||
*aMaxAge = (uint64_t)maxAge;
|
||||
}
|
||||
|
||||
if (aIncludeSubdomains != nullptr) {
|
||||
*aIncludeSubdomains = includeSubdomains;
|
||||
}
|
||||
|
||||
return foundUnrecognizedTokens ?
|
||||
NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA :
|
||||
NS_OK;
|
||||
|
@ -350,11 +374,16 @@ int STSPreloadCompare(const void *key, const void *entry)
|
|||
const nsSTSPreload *
|
||||
nsStrictTransportSecurityService::GetPreloadListEntry(const char *aHost)
|
||||
{
|
||||
return (const nsSTSPreload *) bsearch(aHost,
|
||||
kSTSPreloadList,
|
||||
PR_ARRAY_SIZE(kSTSPreloadList),
|
||||
sizeof(nsSTSPreload),
|
||||
STSPreloadCompare);
|
||||
if (mUsePreloadList) {
|
||||
return (const nsSTSPreload *) bsearch(aHost,
|
||||
kSTSPreloadList,
|
||||
PR_ARRAY_SIZE(kSTSPreloadList),
|
||||
sizeof(nsSTSPreload),
|
||||
STSPreloadCompare);
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -552,6 +581,9 @@ nsStrictTransportSecurityService::Observe(nsISupports *subject,
|
|||
mInPrivateMode = false;
|
||||
}
|
||||
}
|
||||
else if (strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
|
||||
mUsePreloadList = mozilla::Preferences::GetBool("network.stricttransportsecurity.preloadlist", true);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -136,7 +136,8 @@ private:
|
|||
nsresult GetHost(nsIURI *aURI, nsACString &aResult);
|
||||
nsresult GetPrincipalForURI(nsIURI *aURI, nsIPrincipal **aPrincipal);
|
||||
nsresult SetStsState(nsIURI* aSourceURI, int64_t maxage, bool includeSubdomains);
|
||||
nsresult ProcessStsHeaderMutating(nsIURI* aSourceURI, char* aHeader);
|
||||
nsresult ProcessStsHeaderMutating(nsIURI* aSourceURI, char* aHeader,
|
||||
uint64_t *aMaxAge, bool *aIncludeSubdomains);
|
||||
const nsSTSPreload *GetPreloadListEntry(const char *aHost);
|
||||
|
||||
// private-mode-preserving permission manager overlay functions
|
||||
|
@ -154,6 +155,7 @@ private:
|
|||
|
||||
bool mInPrivateMode;
|
||||
nsTHashtable<nsSTSHostEntry> mPrivateModeHostTable;
|
||||
bool mUsePreloadList;
|
||||
};
|
||||
|
||||
#endif // __nsStrictTransportSecurityService_h__
|
||||
|
|
|
@ -35,9 +35,9 @@ var gObserver = new Observer();
|
|||
// This is a list of every host we call processStsHeader with
|
||||
// (we have to remove any state added to the sts service so as to not muck
|
||||
// with other tests).
|
||||
var hosts = ["http://keyerror.com", "http://subdomain.kyps.net",
|
||||
"http://subdomain.cert.se", "http://crypto.cat",
|
||||
"http://www.logentries.com"];
|
||||
var hosts = ["http://keyerror.com", "http://subdomain.intercom.io",
|
||||
"http://subdomain.pixi.me", "http://crypto.cat",
|
||||
"http://logentries.com"];
|
||||
|
||||
function cleanup() {
|
||||
Services.obs.removeObserver(gObserver, "private-browsing-transition-complete");
|
||||
|
@ -72,27 +72,33 @@ function test_part1() {
|
|||
do_check_false(gSTSService.isStsHost("com"));
|
||||
|
||||
// Note: the following were taken from the STS preload list
|
||||
// as of June 2012. If the list changes, this test will need to be modified.
|
||||
// as of Sept. 2012. If the list changes, this test will need to be modified.
|
||||
// check that the pref to toggle using the preload list works
|
||||
Services.prefs.setBoolPref("network.stricttransportsecurity.preloadlist", false);
|
||||
do_check_false(gSTSService.isStsHost("factor.cc"));
|
||||
Services.prefs.setBoolPref("network.stricttransportsecurity.preloadlist", true);
|
||||
do_check_true(gSTSService.isStsHost("factor.cc"));
|
||||
|
||||
// check that an entry at the beginning of the list is an sts host
|
||||
do_check_true(gSTSService.isStsHost("health.google.com"));
|
||||
do_check_true(gSTSService.isStsHost("arivo.com.br"));
|
||||
|
||||
// check that a subdomain is an sts host (includeSubdomains is set)
|
||||
do_check_true(gSTSService.isStsHost("subdomain.health.google.com"));
|
||||
do_check_true(gSTSService.isStsHost("subdomain.arivo.com.br"));
|
||||
|
||||
// check that another subdomain is an sts host (includeSubdomains is set)
|
||||
do_check_true(gSTSService.isStsHost("a.b.c.subdomain.health.google.com"));
|
||||
do_check_true(gSTSService.isStsHost("a.b.c.subdomain.arivo.com.br"));
|
||||
|
||||
// check that an entry in the middle of the list is an sts host
|
||||
do_check_true(gSTSService.isStsHost("epoxate.com"));
|
||||
do_check_true(gSTSService.isStsHost("neg9.org"));
|
||||
|
||||
// check that a subdomain is not an sts host (includeSubdomains is not set)
|
||||
do_check_false(gSTSService.isStsHost("subdomain.epoxate.com"));
|
||||
do_check_false(gSTSService.isStsHost("subdomain.neg9.org"));
|
||||
|
||||
// check that an entry at the end of the list is an sts host
|
||||
do_check_true(gSTSService.isStsHost("www.googlemail.com"));
|
||||
do_check_true(gSTSService.isStsHost("www.noisebridge.net"));
|
||||
|
||||
// check that a subdomain is not an sts host (includeSubdomains is not set)
|
||||
do_check_false(gSTSService.isStsHost("a.subdomain.www.googlemail.com"));
|
||||
do_check_false(gSTSService.isStsHost("a.subdomain.www.noisebridge.net"));
|
||||
|
||||
// check that a host with a dot on the end won't break anything
|
||||
do_check_false(gSTSService.isStsHost("notsts.nonexistent.mozilla.com."));
|
||||
|
@ -112,35 +118,35 @@ function test_part1() {
|
|||
|
||||
// check that processing a header with max-age: 0 from a subdomain of a site
|
||||
// will not remove that (ancestor) site from the list
|
||||
var uri = Services.io.newURI("http://subdomain.kyps.net", null, null);
|
||||
var uri = Services.io.newURI("http://subdomain.intercom.io", null, null);
|
||||
gSTSService.processStsHeader(uri, "max-age=0");
|
||||
do_check_true(gSTSService.isStsHost("kyps.net"));
|
||||
do_check_false(gSTSService.isStsHost("subdomain.kyps.net"));
|
||||
do_check_true(gSTSService.isStsHost("intercom.io"));
|
||||
do_check_false(gSTSService.isStsHost("subdomain.intercom.io"));
|
||||
|
||||
var uri = Services.io.newURI("http://subdomain.cert.se", null, null);
|
||||
var uri = Services.io.newURI("http://subdomain.pixi.me", null, null);
|
||||
gSTSService.processStsHeader(uri, "max-age=0");
|
||||
// we received a header with "max-age=0", so we have "no information"
|
||||
// regarding the sts state of subdomain.cert.se specifically, but
|
||||
// it is actually still an STS host, because of the preloaded cert.se
|
||||
// regarding the sts state of subdomain.pixi.me specifically, but
|
||||
// it is actually still an STS host, because of the preloaded pixi.me
|
||||
// including subdomains.
|
||||
// Here's a drawing:
|
||||
// |-- cert.se (in preload list, includes subdomains) IS sts host
|
||||
// |-- subdomain.cert.se IS sts host
|
||||
// | `-- another.subdomain.cert.se IS sts host
|
||||
// `-- sibling.cert.se IS sts host
|
||||
do_check_true(gSTSService.isStsHost("subdomain.cert.se"));
|
||||
do_check_true(gSTSService.isStsHost("sibling.cert.se"));
|
||||
do_check_true(gSTSService.isStsHost("another.subdomain.cert.se"));
|
||||
// |-- pixi.me (in preload list, includes subdomains) IS sts host
|
||||
// |-- subdomain.pixi.me IS sts host
|
||||
// | `-- another.subdomain.pixi.me IS sts host
|
||||
// `-- sibling.pixi.me IS sts host
|
||||
do_check_true(gSTSService.isStsHost("subdomain.pixi.me"));
|
||||
do_check_true(gSTSService.isStsHost("sibling.pixi.me"));
|
||||
do_check_true(gSTSService.isStsHost("another.subdomain.pixi.me"));
|
||||
|
||||
gSTSService.processStsHeader(uri, "max-age=1000");
|
||||
// Here's what we have now:
|
||||
// |-- cert.se (in preload list, includes subdomains) IS sts host
|
||||
// |-- subdomain.cert.se (include subdomains is false) IS sts host
|
||||
// | `-- another.subdomain.cert.se IS NOT sts host
|
||||
// `-- sibling.cert.se IS sts host
|
||||
do_check_true(gSTSService.isStsHost("subdomain.cert.se"));
|
||||
do_check_true(gSTSService.isStsHost("sibling.cert.se"));
|
||||
do_check_false(gSTSService.isStsHost("another.subdomain.cert.se"));
|
||||
// |-- pixi.me (in preload list, includes subdomains) IS sts host
|
||||
// |-- subdomain.pixi.me (include subdomains is false) IS sts host
|
||||
// | `-- another.subdomain.pixi.me IS NOT sts host
|
||||
// `-- sibling.pixi.me IS sts host
|
||||
do_check_true(gSTSService.isStsHost("subdomain.pixi.me"));
|
||||
do_check_true(gSTSService.isStsHost("sibling.pixi.me"));
|
||||
do_check_false(gSTSService.isStsHost("another.subdomain.pixi.me"));
|
||||
|
||||
// Test private browsing correctly interacts with removing preloaded sites.
|
||||
// If we don't have the private browsing service, don't run those tests
|
||||
|
@ -183,12 +189,12 @@ function test_private_browsing1() {
|
|||
// a site on the preload list, and that header later expires. We need to
|
||||
// then treat that host as no longer an sts host.)
|
||||
// (sanity check first - this should be in the preload list)
|
||||
do_check_true(gSTSService.isStsHost("www.logentries.com"));
|
||||
var uri = Services.io.newURI("http://www.logentries.com", null, null);
|
||||
do_check_true(gSTSService.isStsHost("logentries.com"));
|
||||
var uri = Services.io.newURI("http://logentries.com", null, null);
|
||||
// according to the rfc, max-age can't be negative, but this is a great
|
||||
// way to test an expired entry
|
||||
gSTSService.processStsHeader(uri, "max-age=-1000");
|
||||
do_check_false(gSTSService.isStsHost("www.logentries.com"));
|
||||
do_check_false(gSTSService.isStsHost("logentries.com"));
|
||||
|
||||
// if this test gets this far, it means there's a private browsing service
|
||||
getPBSvc().privateBrowsingEnabled = false;
|
||||
|
@ -202,7 +208,7 @@ function test_private_browsing2() {
|
|||
|
||||
// Now that we're out of private browsing mode, we need to make sure
|
||||
// we've "forgotten" that we "forgot" this site's sts status.
|
||||
do_check_true(gSTSService.isStsHost("www.logentries.com"));
|
||||
do_check_true(gSTSService.isStsHost("logentries.com"));
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
/* 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/. */
|
||||
|
||||
// <https://developer.mozilla.org/en/XPConnect/xpcshell/HOWTO>
|
||||
// <https://bugzilla.mozilla.org/show_bug.cgi?id=546628>
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
// Register resource://app/ URI
|
||||
let ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
let resHandler = ios.getProtocolHandler("resource")
|
||||
.QueryInterface(Ci.nsIResProtocolHandler);
|
||||
let mozDir = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIProperties)
|
||||
.get("CurProcD", Ci.nsILocalFile);
|
||||
let mozDirURI = ios.newFileURI(mozDir);
|
||||
resHandler.setSubstitution("app", mozDirURI);
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
Cu.import("resource:///modules/XPCOMUtils.jsm");
|
||||
|
||||
const SOURCE = "https://src.chromium.org/viewvc/chrome/trunk/src/net/base/transport_security_state_static.json";
|
||||
const OUTPUT = "nsSTSPreloadList.inc";
|
||||
const ERROR_OUTPUT = "nsSTSPreloadList.errors";
|
||||
const MINIMUM_REQUIRED_MAX_AGE = 60 * 60 * 24 * 7 * 18;
|
||||
const PREFIX = "/* This Source Code Form is subject to the terms of the Mozilla Public\n" +
|
||||
" * License, v. 2.0. If a copy of the MPL was not distributed with this\n" +
|
||||
" * file, You can obtain one at http://mozilla.org/MPL/2.0/. */\n" +
|
||||
"\n" +
|
||||
"/*****************************************************************************/\n" +
|
||||
"/* This is an automatically generated file. If you're not */\n" +
|
||||
"/* nsStrictTransportSecurityService.cpp, you shouldn't be #including it. */\n" +
|
||||
"/*****************************************************************************/\n" +
|
||||
"\n" +
|
||||
"class nsSTSPreload\n" +
|
||||
"{\n" +
|
||||
" public:\n" +
|
||||
" const char *mHost;\n" +
|
||||
" const bool mIncludeSubdomains;\n" +
|
||||
"};\n" +
|
||||
"\n" +
|
||||
"static const nsSTSPreload kSTSPreloadList[] = {\n";
|
||||
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;
|
||||
}
|
||||
|
||||
if (req.status != 200) {
|
||||
throw "ERROR: problem downloading '" + SOURCE + "': status " + req.status;
|
||||
}
|
||||
|
||||
// we have to filter out '//' comments
|
||||
var result = req.responseText.replace(/\/\/[^\n]*\n/g, "");
|
||||
var data = null;
|
||||
try {
|
||||
data = JSON.parse(result);
|
||||
}
|
||||
catch (e) {
|
||||
throw "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";
|
||||
}
|
||||
|
||||
for (entry of rawdata.entries) {
|
||||
if (entry.mode && entry.mode == "force-https") {
|
||||
if (entry.name) {
|
||||
hosts.push(entry);
|
||||
} else {
|
||||
throw "ERROR: entry not formatted correctly: no name found";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hosts;
|
||||
}
|
||||
|
||||
var gSTSService = Cc["@mozilla.org/stsservice;1"]
|
||||
.getService(Ci.nsIStrictTransportSecurityService);
|
||||
|
||||
function processStsHeader(hostname, header, status) {
|
||||
var maxAge = { value: 0 };
|
||||
var includeSubdomains = { value: false };
|
||||
var error = "no error";
|
||||
if (header != null) {
|
||||
try {
|
||||
var uri = Services.io.newURI("https://" + host.name, null, null);
|
||||
gSTSService.processStsHeader(uri, header, maxAge, includeSubdomains);
|
||||
}
|
||||
catch (e) {
|
||||
dump("ERROR: could not process header '" + header + "' from " + hostname +
|
||||
": " + e + "\n");
|
||||
error = e;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (status == 0) {
|
||||
error = "could not connect to host";
|
||||
} else {
|
||||
error = "did not receive HSTS header";
|
||||
}
|
||||
}
|
||||
|
||||
return { hostname: hostname,
|
||||
maxAge: maxAge.value,
|
||||
includeSubdomains: includeSubdomains.value,
|
||||
error: error };
|
||||
}
|
||||
|
||||
function RedirectStopper() {};
|
||||
|
||||
RedirectStopper.prototype = {
|
||||
// nsIChannelEventSink
|
||||
asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) {
|
||||
throw Cr.NS_ERROR_ENTITY_CHANGED;
|
||||
},
|
||||
|
||||
getInterface: function(iid) {
|
||||
return this.QueryInterface(iid);
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannelEventSink])
|
||||
};
|
||||
|
||||
function getHSTSStatus(host, resultList) {
|
||||
var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Ci.nsIXMLHttpRequest);
|
||||
var inResultList = false;
|
||||
var uri = "https://" + host.name + "/";
|
||||
req.open("GET", uri, true);
|
||||
req.channel.notificationCallbacks = new RedirectStopper();
|
||||
req.onreadystatechange = function(event) {
|
||||
if (!inResultList && req.readyState == 4) {
|
||||
inResultList = true;
|
||||
var header = req.getResponseHeader("strict-transport-security");
|
||||
resultList.push(processStsHeader(host.name, header, req.status));
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
req.send();
|
||||
}
|
||||
catch (e) {
|
||||
dump("ERROR: exception making request to " + host.name + ": " + e + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
function compareHSTSStatus(a, b) {
|
||||
return (a.hostname > b.hostname ? 1 : (a.hostname < b.hostname ? -1 : 0));
|
||||
}
|
||||
|
||||
function writeTo(string, fos) {
|
||||
fos.write(string, string.length);
|
||||
}
|
||||
|
||||
function output(sortedStatuses) {
|
||||
try {
|
||||
var file = FileUtils.getFile("CurWorkD", [OUTPUT]);
|
||||
var errorFile = FileUtils.getFile("CurWorkD", [ERROR_OUTPUT]);
|
||||
var fos = FileUtils.openSafeFileOutputStream(file);
|
||||
var eos = FileUtils.openSafeFileOutputStream(errorFile);
|
||||
writeTo(PREFIX, fos);
|
||||
for (var status of hstsStatuses) {
|
||||
if (status.maxAge >= MINIMUM_REQUIRED_MAX_AGE) {
|
||||
writeTo(" { \"" + status.hostname + "\", " +
|
||||
(status.includeSubdomains ? "true" : "false") + " },\n", fos);
|
||||
dump("INFO: " + status.hostname + " ON the preload list\n");
|
||||
}
|
||||
else {
|
||||
dump("INFO: " + status.hostname + " NOT ON the preload list\n");
|
||||
if (status.maxAge != 0) {
|
||||
status.error = "max-age too low: " + status.maxAge;
|
||||
}
|
||||
writeTo(status.hostname + ": " + status.error + "\n", eos);
|
||||
}
|
||||
}
|
||||
writeTo(POSTFIX, fos);
|
||||
FileUtils.closeSafeFileOutputStream(fos);
|
||||
FileUtils.closeSafeFileOutputStream(eos);
|
||||
}
|
||||
catch (e) {
|
||||
dump("ERROR: problem writing output to '" + OUTPUT + "': " + e + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
// The idea is the output list will be the same size as the input list
|
||||
// when we've received all responses (or timed out).
|
||||
// Since all events are processed on the main thread, and since event
|
||||
// handlers are not preemptible, there shouldn't be any concurrency issues.
|
||||
function waitForResponses(inputList, outputList) {
|
||||
// From <https://developer.mozilla.org/en/XPConnect/xpcshell/HOWTO>
|
||||
var threadManager = Cc["@mozilla.org/thread-manager;1"]
|
||||
.getService(Ci.nsIThreadManager);
|
||||
var mainThread = threadManager.currentThread;
|
||||
while (inputList.length != outputList.length) {
|
||||
mainThread.processNextEvent(true);
|
||||
}
|
||||
while (mainThread.hasPendingEvents()) {
|
||||
mainThread.processNextEvent(true);
|
||||
}
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// This is where the action happens:
|
||||
// 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"
|
||||
var hosts = getHosts(rawdata);
|
||||
// spin off a request to each host
|
||||
var hstsStatuses = [];
|
||||
for (var host of hosts) {
|
||||
getHSTSStatus(host, hstsStatuses);
|
||||
}
|
||||
// wait for those responses to come back
|
||||
waitForResponses(hosts, hstsStatuses);
|
||||
// sort the hosts alphabetically
|
||||
hstsStatuses.sort(compareHSTSStatus);
|
||||
// write the results to a file (this is where we filter out hosts that we
|
||||
// either couldn't connect to, didn't receive an HSTS header from, couldn't
|
||||
// parse the header, or had a header with too short a max-age)
|
||||
output(hstsStatuses);
|
||||
// ****************************************************************************
|
|
@ -1,115 +0,0 @@
|
|||
#!/usr/bin/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/.
|
||||
|
||||
import sys, subprocess, json, argparse
|
||||
|
||||
SOURCE = "https://src.chromium.org/viewvc/chrome/trunk/src/net/base/transport_security_state_static.json"
|
||||
OUTPUT = "nsSTSPreloadList.inc"
|
||||
PREFIX = """/* 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 is an automatically generated file. If you're not */
|
||||
/* nsStrictTransportSecurityService.cpp, you shouldn't be #including it. */
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <prtypes.h>
|
||||
|
||||
class nsSTSPreload
|
||||
{
|
||||
public:
|
||||
const char *mHost;
|
||||
const bool mIncludeSubdomains;
|
||||
};
|
||||
|
||||
static const nsSTSPreload kSTSPreloadList[] = {
|
||||
"""
|
||||
POSTFIX = """};
|
||||
"""
|
||||
|
||||
def filterComments(stream):
|
||||
lines = []
|
||||
for line in stream:
|
||||
# each line still has '\n' at the end, so if find returns -1,
|
||||
# the newline gets chopped off like we want
|
||||
# (and otherwise, comments are filtered out like we want)
|
||||
lines.append(line[0:line.find("//")])
|
||||
return "".join(lines)
|
||||
|
||||
def readFile(source):
|
||||
if source != "-":
|
||||
f = open(source, 'r')
|
||||
else:
|
||||
f = sys.stdin
|
||||
return filterComments(f)
|
||||
|
||||
def download(source):
|
||||
download = subprocess.Popen(["wget", "-O", "-", source], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
|
||||
contents = filterComments(download.stdout)
|
||||
download.wait()
|
||||
if download.returncode != 0:
|
||||
raise Exception()
|
||||
return contents
|
||||
|
||||
def output(filename, jsonblob):
|
||||
if filename != "-":
|
||||
outstream = open(filename, 'w')
|
||||
else:
|
||||
outstream = sys.stdout
|
||||
if not 'entries' in jsonblob:
|
||||
raise Exception()
|
||||
else:
|
||||
outstream.write(PREFIX)
|
||||
# use a dictionary to prevent duplicates
|
||||
lines = {}
|
||||
for entry in jsonblob['entries']:
|
||||
if 'name' in entry and 'mode' in entry and entry['mode'] == "force-https":
|
||||
line = " { \"" + entry['name'] + "\", "
|
||||
if 'include_subdomains' in entry and entry['include_subdomains']:
|
||||
line = line + "true },\n"
|
||||
else:
|
||||
line = line + "false },\n"
|
||||
lines[line] = True
|
||||
# The data must be sorted by domain name because we do a binary search to
|
||||
# determine if a host is in the preload list.
|
||||
keys = lines.keys()
|
||||
keys.sort()
|
||||
for line in keys:
|
||||
outstream.write(line)
|
||||
outstream.write(POSTFIX);
|
||||
outstream.close()
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Download Chrome's STS preload list and format it for Firefox")
|
||||
parser.add_argument("-s", "--source", default=SOURCE, help="Specify source for input list (can be a file, url, or '-' for stdin)")
|
||||
parser.add_argument("-o", "--output", default=OUTPUT, help="Specify output file ('-' for stdout)")
|
||||
args = parser.parse_args()
|
||||
contents = None
|
||||
try:
|
||||
contents = readFile(args.source)
|
||||
except:
|
||||
pass
|
||||
if not contents:
|
||||
try:
|
||||
contents = download(args.source)
|
||||
except:
|
||||
print >> sys.stderr, "Could not read source '%s'" % args.source
|
||||
return 1
|
||||
try:
|
||||
jsonblob = json.loads(contents)
|
||||
except:
|
||||
print >> sys.stderr, "Could not parse contents of file '%s'" % args.source
|
||||
return 1
|
||||
try:
|
||||
output(args.output, jsonblob)
|
||||
except:
|
||||
print >> sys.stderr, "Could not write to '%s'" % args.output
|
||||
return 1
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
Загрузка…
Ссылка в новой задаче