зеркало из https://github.com/mozilla/pjs.git
bug 557598 - Support strict-transport-security (STS) in private browsing mode; r=ehsan,dveditz a=blocking-betaN+
This commit is contained in:
Родитель
90e8b49655
Коммит
deaa531dcc
|
@ -38,6 +38,7 @@
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
interface nsIURI;
|
interface nsIURI;
|
||||||
|
interface nsIObserver;
|
||||||
interface nsIHttpChannel;
|
interface nsIHttpChannel;
|
||||||
|
|
||||||
[scriptable, uuid(16955eee-6c48-4152-9309-c42a465138a1)]
|
[scriptable, uuid(16955eee-6c48-4152-9309-c42a465138a1)]
|
||||||
|
|
|
@ -910,13 +910,6 @@ nsresult
|
||||||
nsHttpChannel::ProcessSTSHeader()
|
nsHttpChannel::ProcessSTSHeader()
|
||||||
{
|
{
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
|
||||||
// We need to check private browsing mode here since some permissions are
|
|
||||||
// allowed to be tweaked when private browsing mode is enabled, but STS is
|
|
||||||
// not allowed to operate at all in PBM.
|
|
||||||
if (gHttpHandler->InPrivateBrowsingMode())
|
|
||||||
return NS_OK;
|
|
||||||
|
|
||||||
PRBool isHttps = PR_FALSE;
|
PRBool isHttps = PR_FALSE;
|
||||||
rv = mURI->SchemeIs("https", &isHttps);
|
rv = mURI->SchemeIs("https", &isHttps);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "prprf.h"
|
#include "prprf.h"
|
||||||
#include "nsCRTGlue.h"
|
#include "nsCRTGlue.h"
|
||||||
#include "nsIPermissionManager.h"
|
#include "nsIPermissionManager.h"
|
||||||
|
#include "nsIPrivateBrowsingService.h"
|
||||||
#include "nsISSLStatus.h"
|
#include "nsISSLStatus.h"
|
||||||
#include "nsISSLStatusProvider.h"
|
#include "nsISSLStatusProvider.h"
|
||||||
#include "nsStrictTransportSecurityService.h"
|
#include "nsStrictTransportSecurityService.h"
|
||||||
|
@ -61,7 +62,30 @@ PRLogModuleInfo *gSTSLog = PR_NewLogModule("nsSTSService");
|
||||||
return NS_ERROR_FAILURE; \
|
return NS_ERROR_FAILURE; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
nsSTSHostEntry::nsSTSHostEntry(const char* aHost)
|
||||||
|
: mHost(aHost)
|
||||||
|
, mExpireTime(0)
|
||||||
|
, mDeleted(PR_FALSE)
|
||||||
|
, mIncludeSubdomains(PR_FALSE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
nsSTSHostEntry::nsSTSHostEntry(const nsSTSHostEntry& toCopy)
|
||||||
|
: mHost(toCopy.mHost)
|
||||||
|
, mExpireTime(toCopy.mExpireTime)
|
||||||
|
, mDeleted(toCopy.mDeleted)
|
||||||
|
, mIncludeSubdomains(toCopy.mIncludeSubdomains)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
nsStrictTransportSecurityService::nsStrictTransportSecurityService()
|
nsStrictTransportSecurityService::nsStrictTransportSecurityService()
|
||||||
|
: mInPrivateMode(PR_FALSE)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +93,8 @@ nsStrictTransportSecurityService::~nsStrictTransportSecurityService()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsStrictTransportSecurityService,
|
NS_IMPL_THREADSAFE_ISUPPORTS2(nsStrictTransportSecurityService,
|
||||||
|
nsIObserver,
|
||||||
nsIStrictTransportSecurityService)
|
nsIStrictTransportSecurityService)
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -80,6 +105,19 @@ nsStrictTransportSecurityService::Init()
|
||||||
mPermMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
|
mPermMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// figure out if we're starting in private browsing mode
|
||||||
|
nsCOMPtr<nsIPrivateBrowsingService> pbs =
|
||||||
|
do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
|
||||||
|
if (pbs)
|
||||||
|
pbs->GetPrivateBrowsingEnabled(&mInPrivateMode);
|
||||||
|
|
||||||
|
mObserverService = mozilla::services::GetObserverService();
|
||||||
|
if (mObserverService)
|
||||||
|
mObserverService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, PR_FALSE);
|
||||||
|
|
||||||
|
if (mInPrivateMode && !mPrivateModeHostTable.Init())
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,25 +150,31 @@ nsStrictTransportSecurityService::SetStsState(nsIURI* aSourceURI,
|
||||||
PRInt64 expiretime = (PR_Now() / 1000) + (maxage * 1000);
|
PRInt64 expiretime = (PR_Now() / 1000) + (maxage * 1000);
|
||||||
|
|
||||||
// record entry for this host with max-age in the permissions manager
|
// record entry for this host with max-age in the permissions manager
|
||||||
mPermMgr->Add(aSourceURI, STS_PERMISSION,
|
STSLOG(("STS: maxage permission SET, adding permission\n"));
|
||||||
|
nsresult rv = AddPermission(aSourceURI,
|
||||||
|
STS_PERMISSION,
|
||||||
(PRUint32) nsIPermissionManager::ALLOW_ACTION,
|
(PRUint32) nsIPermissionManager::ALLOW_ACTION,
|
||||||
(PRUint32) nsIPermissionManager::EXPIRE_TIME,
|
(PRUint32) nsIPermissionManager::EXPIRE_TIME,
|
||||||
expiretime);
|
expiretime);
|
||||||
STSLOG(("STS: set maxage permission\n"));
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (includeSubdomains) {
|
if (includeSubdomains) {
|
||||||
// record entry for this host with include subdomains in the permissions manager
|
// record entry for this host with include subdomains in the permissions manager
|
||||||
mPermMgr->Add(aSourceURI, STS_SUBDOMAIN_PERMISSION,
|
STSLOG(("STS: subdomains permission SET, adding permission\n"));
|
||||||
(PRUint32) nsIPermissionManager::ALLOW_ACTION,
|
rv = AddPermission(aSourceURI,
|
||||||
(PRUint32) nsIPermissionManager::EXPIRE_TIME,
|
STS_SUBDOMAIN_PERMISSION,
|
||||||
expiretime);
|
(PRUint32) nsIPermissionManager::ALLOW_ACTION,
|
||||||
STSLOG(("STS: set subdomains permission\n"));
|
(PRUint32) nsIPermissionManager::EXPIRE_TIME,
|
||||||
|
expiretime);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
} else { // !includeSubdomains
|
} else { // !includeSubdomains
|
||||||
nsCAutoString hostname;
|
nsCAutoString hostname;
|
||||||
nsresult rv = GetHost(aSourceURI, hostname);
|
rv = GetHost(aSourceURI, hostname);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
mPermMgr->Remove(hostname, STS_SUBDOMAIN_PERMISSION);
|
STSLOG(("STS: subdomains permission UNSET, removing any existing ones\n"));
|
||||||
|
rv = RemovePermission(hostname, STS_SUBDOMAIN_PERMISSION);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -146,10 +190,12 @@ nsStrictTransportSecurityService::RemoveStsState(nsIURI* aURI)
|
||||||
nsresult rv = GetHost(aURI, hostname);
|
nsresult rv = GetHost(aURI, hostname);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
mPermMgr->Remove(hostname, STS_PERMISSION);
|
rv = RemovePermission(hostname, STS_PERMISSION);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
STSLOG(("STS: deleted maxage permission\n"));
|
STSLOG(("STS: deleted maxage permission\n"));
|
||||||
|
|
||||||
mPermMgr->Remove(hostname, STS_SUBDOMAIN_PERMISSION);
|
rv = RemovePermission(hostname, STS_SUBDOMAIN_PERMISSION);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
STSLOG(("STS: deleted subdomains permission\n"));
|
STSLOG(("STS: deleted subdomains permission\n"));
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -295,11 +341,12 @@ nsStrictTransportSecurityService::IsStsURI(nsIURI* aURI, PRBool* aResult)
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
PRUint32 permExact, permGeneral;
|
PRUint32 permExact, permGeneral;
|
||||||
// If this domain has the forcehttps permission, this is an STS host.
|
// If this domain has the forcehttps permission, this is an STS host.
|
||||||
rv = mPermMgr->TestExactPermission(aURI, STS_PERMISSION, &permExact);
|
rv = TestPermission(aURI, STS_PERMISSION, &permExact, PR_TRUE);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// If any super-domain has the includeSubdomains permission, this is an
|
// If any super-domain has the includeSubdomains permission, this is an
|
||||||
// STS host.
|
// STS host.
|
||||||
rv = mPermMgr->TestPermission(aURI, STS_SUBDOMAIN_PERMISSION, &permGeneral);
|
rv = TestPermission(aURI, STS_SUBDOMAIN_PERMISSION, &permGeneral, PR_FALSE);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
*aResult = ((permExact == nsIPermissionManager::ALLOW_ACTION) ||
|
*aResult = ((permExact == nsIPermissionManager::ALLOW_ACTION) ||
|
||||||
|
@ -341,3 +388,239 @@ nsStrictTransportSecurityService::ShouldIgnoreStsHeader(nsISupports* aSecurityIn
|
||||||
*aResult = tlsIsBroken;
|
*aResult = tlsIsBroken;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------
|
||||||
|
// nsStrictTransportSecurityService::nsIObserver
|
||||||
|
//------------------------------------------------------------
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsStrictTransportSecurityService::Observe(nsISupports *subject,
|
||||||
|
const char *topic,
|
||||||
|
const PRUnichar *data)
|
||||||
|
{
|
||||||
|
if (strcmp(topic, NS_PRIVATE_BROWSING_SWITCH_TOPIC) == 0) {
|
||||||
|
if(NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).Equals(data)) {
|
||||||
|
// Indication to start recording stuff locally and not writing changes
|
||||||
|
// out to the permission manager.
|
||||||
|
|
||||||
|
if (!mPrivateModeHostTable.IsInitialized()
|
||||||
|
&& !mPrivateModeHostTable.Init()) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
mInPrivateMode = PR_TRUE;
|
||||||
|
}
|
||||||
|
else if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).Equals(data)) {
|
||||||
|
mPrivateModeHostTable.Clear();
|
||||||
|
mInPrivateMode = PR_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------
|
||||||
|
// Functions to overlay the permission manager calls in case
|
||||||
|
// we're in private browsing mode.
|
||||||
|
//------------------------------------------------------------
|
||||||
|
nsresult
|
||||||
|
nsStrictTransportSecurityService::AddPermission(nsIURI *aURI,
|
||||||
|
const char *aType,
|
||||||
|
PRUint32 aPermission,
|
||||||
|
PRUint32 aExpireType,
|
||||||
|
PRInt64 aExpireTime)
|
||||||
|
{
|
||||||
|
// Private mode doesn't address user-set (EXPIRE_NEVER) permissions: let
|
||||||
|
// those be stored persistently.
|
||||||
|
if (!mInPrivateMode || aExpireType == nsIPermissionManager::EXPIRE_NEVER) {
|
||||||
|
// Not in private mode, or manually-set permission
|
||||||
|
return mPermMgr->Add(aURI, aType, aPermission, aExpireType, aExpireTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCAutoString host;
|
||||||
|
nsresult rv = GetHost(aURI, host);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
STSLOG(("AddPermission for entry for for %s", host.get()));
|
||||||
|
|
||||||
|
// Update in mPrivateModeHostTable only, so any changes will be rolled
|
||||||
|
// back when exiting private mode.
|
||||||
|
|
||||||
|
// Note: EXPIRE_NEVER permissions should trump anything that shows up in
|
||||||
|
// the HTTP header, so if there's an EXPIRE_NEVER permission already
|
||||||
|
// don't store anything new.
|
||||||
|
// Currently there's no way to get the type of expiry out of the
|
||||||
|
// permission manager, but that's okay since there's nothing that stores
|
||||||
|
// EXPIRE_NEVER permissions.
|
||||||
|
|
||||||
|
// PutEntry returns an existing entry if there already is one, or it
|
||||||
|
// creates a new one if there isn't.
|
||||||
|
nsSTSHostEntry* entry = mPrivateModeHostTable.PutEntry(host.get());
|
||||||
|
STSLOG(("Created private mode entry for for %s", host.get()));
|
||||||
|
|
||||||
|
// AddPermission() will be called twice if the STS header encountered has
|
||||||
|
// includeSubdomains (first for the main permission and second for the
|
||||||
|
// subdomains permission). If AddPermission() gets called a second time
|
||||||
|
// with the STS_SUBDOMAIN_PERMISSION, we just have to flip that bit in
|
||||||
|
// the nsSTSHostEntry.
|
||||||
|
if (strcmp(aType, STS_SUBDOMAIN_PERMISSION) == 0) {
|
||||||
|
entry->mIncludeSubdomains = PR_TRUE;
|
||||||
|
}
|
||||||
|
// for the case where PutEntry() returned an existing host entry, make
|
||||||
|
// sure it's not set as deleted (which might have happened in the past).
|
||||||
|
entry->mDeleted = PR_FALSE;
|
||||||
|
|
||||||
|
// Also refresh the expiration time.
|
||||||
|
entry->mExpireTime = aExpireTime;
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsStrictTransportSecurityService::RemovePermission(const nsCString &aHost,
|
||||||
|
const char *aType)
|
||||||
|
{
|
||||||
|
if (!mInPrivateMode) {
|
||||||
|
// Not in private mode: remove permissions persistently.
|
||||||
|
return mPermMgr->Remove(aHost, aType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make changes in mPrivateModeHostTable only, so any changes will be
|
||||||
|
// rolled back when exiting private mode.
|
||||||
|
nsSTSHostEntry* entry = mPrivateModeHostTable.GetEntry(aHost.get());
|
||||||
|
|
||||||
|
// Build up an nsIURI for use with the permission manager.
|
||||||
|
nsCOMPtr<nsIURI> uri;
|
||||||
|
nsresult rv = NS_NewURI(getter_AddRefs(uri),
|
||||||
|
NS_LITERAL_CSTRING("http://") + aHost);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// Check to see if there's STS data stored for this host in the
|
||||||
|
// permission manager (probably set outside private mode).
|
||||||
|
PRUint32 permmgrValue;
|
||||||
|
rv = mPermMgr->TestExactPermission(uri, aType, &permmgrValue);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// If there is STS data in the permission manager, store a "deleted" mask
|
||||||
|
// for the permission in mPrivateModeHostTable (either update
|
||||||
|
// mPrivateModeHostTable to have the deleted mask, or add one).
|
||||||
|
// This is because we don't want removals that happen in private mode to
|
||||||
|
// be reflected when private mode is exited -- but while in private mode
|
||||||
|
// we still want the effect of the removal.
|
||||||
|
if (permmgrValue != nsIPermissionManager::UNKNOWN_ACTION) {
|
||||||
|
// if there's no entry in mPrivateModeHostTable, we have to make one.
|
||||||
|
if (!entry) {
|
||||||
|
entry = mPrivateModeHostTable.PutEntry(aHost.get());
|
||||||
|
STSLOG(("Created private mode deleted mask for for %s", aHost.get()));
|
||||||
|
}
|
||||||
|
entry->mDeleted = PR_TRUE;
|
||||||
|
entry->mIncludeSubdomains = PR_FALSE;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, permission doesn't exist in the real permission manager, so
|
||||||
|
// there's nothing to "pretend" to delete. I'ts ok to delete any copy in
|
||||||
|
// mPrivateModeHostTable.
|
||||||
|
if (entry) mPrivateModeHostTable.RawRemoveEntry(entry);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsStrictTransportSecurityService::TestPermission(nsIURI *aURI,
|
||||||
|
const char *aType,
|
||||||
|
PRUint32 *aPermission,
|
||||||
|
PRBool testExact)
|
||||||
|
{
|
||||||
|
// set default for if we can't find any STS information
|
||||||
|
*aPermission = nsIPermissionManager::UNKNOWN_ACTION;
|
||||||
|
|
||||||
|
if (!mInPrivateMode) {
|
||||||
|
// if not in private mode, just delegate to the permission manager.
|
||||||
|
if (testExact)
|
||||||
|
return mPermMgr->TestExactPermission(aURI, aType, aPermission);
|
||||||
|
else
|
||||||
|
return mPermMgr->TestPermission(aURI, aType, aPermission);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCAutoString host;
|
||||||
|
nsresult rv = GetHost(aURI, host);
|
||||||
|
if (NS_FAILED(rv)) return NS_OK;
|
||||||
|
|
||||||
|
nsSTSHostEntry *entry;
|
||||||
|
PRUint32 actualExactPermission;
|
||||||
|
PRUint32 offset = 0;
|
||||||
|
PRInt64 now = PR_Now() / 1000;
|
||||||
|
|
||||||
|
// Used for testing permissions as we walk up the domain tree.
|
||||||
|
nsCOMPtr<nsIURI> domainWalkURI;
|
||||||
|
|
||||||
|
// In parallel, loop over private mode cache and also the real permission
|
||||||
|
// manager--ignoring any masked as "deleted" in the local cache. We have
|
||||||
|
// to do this here since the most specific permission in *either* the
|
||||||
|
// permission manager or mPrivateModeHostTable should be used.
|
||||||
|
do {
|
||||||
|
entry = mPrivateModeHostTable.GetEntry(host.get() + offset);
|
||||||
|
STSLOG(("Checking PM Table entry and permmgr for %s", host.get()+offset));
|
||||||
|
|
||||||
|
// flag as deleted any entries encountered that have expired. We only
|
||||||
|
// flag the nsSTSHostEntry because there could be some data in the
|
||||||
|
// permission manager that -- if not in private mode -- would have been
|
||||||
|
// overwritten by newly encountered STS data.
|
||||||
|
if (entry && (now > entry->mExpireTime)) {
|
||||||
|
STSLOG(("Deleting expired PM Table entry for %s", host.get()+offset));
|
||||||
|
entry->mDeleted = PR_TRUE;
|
||||||
|
entry->mIncludeSubdomains = PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = NS_NewURI(getter_AddRefs(domainWalkURI),
|
||||||
|
NS_LITERAL_CSTRING("http://") + Substring(host, offset));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
rv = mPermMgr->TestExactPermission(domainWalkURI,
|
||||||
|
aType,
|
||||||
|
&actualExactPermission);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// There are three cases as we walk up the hostname testing
|
||||||
|
// permissions:
|
||||||
|
// 1. There's no entry in mPrivateModeHostTable for this host; rely
|
||||||
|
// on data in the permission manager
|
||||||
|
if (!entry) {
|
||||||
|
if (actualExactPermission != nsIPermissionManager::UNKNOWN_ACTION) {
|
||||||
|
// no cached data but a permission in the permission manager so use
|
||||||
|
// it and stop looking.
|
||||||
|
*aPermission = actualExactPermission;
|
||||||
|
STSLOG(("no PM Table entry for %s, using permmgr", host.get()+offset));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2. There's a "deleted" mask in mPrivateModeHostTable for this host
|
||||||
|
// or we're looking for includeSubdomain information and it's not set:
|
||||||
|
// any data in the permission manager must be ignored, since the
|
||||||
|
// permission would have been deleted if not in private mode.
|
||||||
|
else if (entry->mDeleted || (strcmp(aType, STS_SUBDOMAIN_PERMISSION) == 0
|
||||||
|
&& !entry->mIncludeSubdomains)) {
|
||||||
|
STSLOG(("no entry at all for %s, walking up", host.get()+offset));
|
||||||
|
// keep looking
|
||||||
|
}
|
||||||
|
// 3. There's a non-deleted entry in mPrivateModeHostTable for this
|
||||||
|
// host, so it should be used.
|
||||||
|
else {
|
||||||
|
// All STS permissions' values are ALLOW_ACTION or they are not
|
||||||
|
// known (as in, not set or turned off).
|
||||||
|
*aPermission = nsIPermissionManager::ALLOW_ACTION;
|
||||||
|
STSLOG(("PM Table entry for %s: forcing", host.get()+offset));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't continue walking up the host segments if the test was for an
|
||||||
|
// exact match only.
|
||||||
|
if (testExact) break;
|
||||||
|
|
||||||
|
STSLOG(("no PM Table entry or permmgr data for %s, walking up domain",
|
||||||
|
host.get()+offset));
|
||||||
|
// walk up the host segments
|
||||||
|
offset = host.FindChar('.', offset) + 1;
|
||||||
|
} while (offset > 0);
|
||||||
|
|
||||||
|
// Use whatever we ended up with, which defaults to UNKNOWN_ACTION.
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
|
@ -43,20 +43,93 @@
|
||||||
#define __nsStrictTransportSecurityService_h__
|
#define __nsStrictTransportSecurityService_h__
|
||||||
|
|
||||||
#include "nsIStrictTransportSecurityService.h"
|
#include "nsIStrictTransportSecurityService.h"
|
||||||
|
#include "nsIObserver.h"
|
||||||
|
#include "nsIObserverService.h"
|
||||||
#include "nsIPermissionManager.h"
|
#include "nsIPermissionManager.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsIURI.h"
|
#include "nsIURI.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
|
#include "nsTHashtable.h"
|
||||||
|
|
||||||
// {16955eee-6c48-4152-9309-c42a465138a1}
|
// {16955eee-6c48-4152-9309-c42a465138a1}
|
||||||
#define NS_STRICT_TRANSPORT_SECURITY_CID \
|
#define NS_STRICT_TRANSPORT_SECURITY_CID \
|
||||||
{0x16955eee, 0x6c48, 0x4152, \
|
{0x16955eee, 0x6c48, 0x4152, \
|
||||||
{0x93, 0x09, 0xc4, 0x2a, 0x46, 0x51, 0x38, 0xa1} }
|
{0x93, 0x09, 0xc4, 0x2a, 0x46, 0x51, 0x38, 0xa1} }
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// nsSTSHostEntry - similar to the nsHostEntry class in
|
||||||
|
// nsPermissionManager.cpp, but specific to private-mode caching of STS
|
||||||
|
// permissions.
|
||||||
|
//
|
||||||
|
// Each nsSTSHostEntry contains:
|
||||||
|
// - Expiry time
|
||||||
|
// - Deleted flag (boolean, default PR_FALSE)
|
||||||
|
// - Subdomains flag (boolean, default PR_FALSE)
|
||||||
|
//
|
||||||
|
// The existence of the nsSTSHostEntry implies STS state is set for the given
|
||||||
|
// host -- unless the deleted flag is set, in which case not only is the STS
|
||||||
|
// state not set for the host, but any permission actually present in the
|
||||||
|
// permission manager should be ignored.
|
||||||
|
//
|
||||||
|
// Note: Only one expiry time is stored since the subdomains and STS
|
||||||
|
// permissions are both encountered at the same time in the HTTP header; if the
|
||||||
|
// includeSubdomains directive isn't present in the header, it means to delete
|
||||||
|
// the permission, so the subdomains flag in the nsSTSHostEntry means both that
|
||||||
|
// the permission doesn't exist and any permission in the real permission
|
||||||
|
// manager should be ignored since newer information about it has been
|
||||||
|
// encountered in private browsing mode.
|
||||||
|
//
|
||||||
|
// Note: If there's a permission set by the user (EXPIRE_NEVER), STS is not set
|
||||||
|
// for the host (including the subdomains permission) when the header is
|
||||||
|
// encountered. Furthermore, any user-set permissions are stored persistently
|
||||||
|
// and can't be shadowed.
|
||||||
|
|
||||||
|
class nsSTSHostEntry : public PLDHashEntryHdr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit nsSTSHostEntry(const char* aHost);
|
||||||
|
explicit nsSTSHostEntry(const nsSTSHostEntry& toCopy);
|
||||||
|
|
||||||
|
nsCString mHost;
|
||||||
|
PRInt64 mExpireTime;
|
||||||
|
PRPackedBool mDeleted;
|
||||||
|
PRPackedBool mIncludeSubdomains;
|
||||||
|
|
||||||
|
// Hash methods
|
||||||
|
typedef const char* KeyType;
|
||||||
|
typedef const char* KeyTypePointer;
|
||||||
|
|
||||||
|
KeyType GetKey() const
|
||||||
|
{
|
||||||
|
return mHost.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool KeyEquals(KeyTypePointer aKey) const
|
||||||
|
{
|
||||||
|
return !strcmp(mHost.get(), aKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
static KeyTypePointer KeyToPointer(KeyType aKey)
|
||||||
|
{
|
||||||
|
return aKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PLDHashNumber HashKey(KeyTypePointer aKey)
|
||||||
|
{
|
||||||
|
return PL_DHashStringKey(nsnull, aKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// force the hashtable to use the copy constructor.
|
||||||
|
enum { ALLOW_MEMMOVE = PR_FALSE };
|
||||||
|
};
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class nsStrictTransportSecurityService : public nsIStrictTransportSecurityService
|
class nsStrictTransportSecurityService : public nsIStrictTransportSecurityService
|
||||||
|
, public nsIObserver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_DECL_NSIOBSERVER
|
||||||
NS_DECL_NSISTRICTTRANSPORTSECURITYSERVICE
|
NS_DECL_NSISTRICTTRANSPORTSECURITYSERVICE
|
||||||
|
|
||||||
nsStrictTransportSecurityService();
|
nsStrictTransportSecurityService();
|
||||||
|
@ -67,7 +140,26 @@ private:
|
||||||
nsresult GetHost(nsIURI *aURI, nsACString &aResult);
|
nsresult GetHost(nsIURI *aURI, nsACString &aResult);
|
||||||
nsresult SetStsState(nsIURI* aSourceURI, PRInt64 maxage, PRBool includeSubdomains);
|
nsresult SetStsState(nsIURI* aSourceURI, PRInt64 maxage, PRBool includeSubdomains);
|
||||||
nsresult ProcessStsHeaderMutating(nsIURI* aSourceURI, char* aHeader);
|
nsresult ProcessStsHeaderMutating(nsIURI* aSourceURI, char* aHeader);
|
||||||
|
|
||||||
|
// private-mode-preserving permission manager overlay functions
|
||||||
|
nsresult AddPermission(nsIURI *aURI,
|
||||||
|
const char *aType,
|
||||||
|
PRUint32 aPermission,
|
||||||
|
PRUint32 aExpireType,
|
||||||
|
PRInt64 aExpireTime);
|
||||||
|
nsresult RemovePermission(const nsCString &aHost,
|
||||||
|
const char *aType);
|
||||||
|
nsresult TestPermission(nsIURI *aURI,
|
||||||
|
const char *aType,
|
||||||
|
PRUint32 *aPermission,
|
||||||
|
PRBool testExact);
|
||||||
|
|
||||||
|
// cached services
|
||||||
nsCOMPtr<nsIPermissionManager> mPermMgr;
|
nsCOMPtr<nsIPermissionManager> mPermMgr;
|
||||||
|
nsCOMPtr<nsIObserverService> mObserverService;
|
||||||
|
|
||||||
|
PRBool mInPrivateMode;
|
||||||
|
nsTHashtable<nsSTSHostEntry> mPrivateModeHostTable;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __nsStrictTransportSecurityService_h__
|
#endif // __nsStrictTransportSecurityService_h__
|
||||||
|
|
|
@ -49,8 +49,11 @@ _TEST_FILES = \
|
||||||
plain_bootstrap.html^headers^ \
|
plain_bootstrap.html^headers^ \
|
||||||
subdom_bootstrap.html \
|
subdom_bootstrap.html \
|
||||||
subdom_bootstrap.html^headers^ \
|
subdom_bootstrap.html^headers^ \
|
||||||
|
nosts_bootstrap.html \
|
||||||
|
nosts_bootstrap.html^headers^ \
|
||||||
verify.sjs \
|
verify.sjs \
|
||||||
test_stricttransportsecurity.html \
|
test_stricttransportsecurity.html \
|
||||||
|
test_sts_privatebrowsing.html \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
libs:: $(_TEST_FILES)
|
libs:: $(_TEST_FILES)
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||||
|
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
-
|
||||||
|
- The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
- 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
- the License. You may obtain a copy of the License at
|
||||||
|
- http://www.mozilla.org/MPL/
|
||||||
|
-
|
||||||
|
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
- for the specific language governing rights and limitations under the
|
||||||
|
- License.
|
||||||
|
-
|
||||||
|
- The Original Code is Strict-Transport-Security.
|
||||||
|
-
|
||||||
|
- The Initial Developer of the Original Code is
|
||||||
|
- Mozilla Foundation.
|
||||||
|
- Portions created by the Initial Developer are Copyright (C) 2010
|
||||||
|
- the Initial Developer. All Rights Reserved.
|
||||||
|
-
|
||||||
|
- Contributor(s):
|
||||||
|
- Sid Stamm <sid@mozilla.com>
|
||||||
|
-
|
||||||
|
- Alternatively, the contents of this file may be used under the terms of
|
||||||
|
- either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
- in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
- of those above. If you wish to allow use of your version of this file only
|
||||||
|
- under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
- use your version of this file under the terms of the MPL, indicate your
|
||||||
|
- decision by deleting the provisions above and replace them with the notice
|
||||||
|
- and other provisions required by the LGPL or the GPL. If you do not delete
|
||||||
|
- the provisions above, a recipient may use your version of this file under
|
||||||
|
- the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
-
|
||||||
|
- ***** END LICENSE BLOCK ***** -->
|
||||||
|
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>STS test iframe</title>
|
||||||
|
<script>
|
||||||
|
var self = window;
|
||||||
|
window.addEventListener("load", function() {
|
||||||
|
self.parent.postMessage("BOOTSTRAP plain", "http://mochi.test:8888");
|
||||||
|
}, false);
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- This frame should be loaded over HTTPS to set the STS header. -->
|
||||||
|
This frame was loaded using
|
||||||
|
<script>
|
||||||
|
document.write(document.location.protocol);
|
||||||
|
</script>
|
||||||
|
and set the STS header to force this site and allow subdomain upgrading.
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1 @@
|
||||||
|
Cache-Control: no-cache
|
|
@ -0,0 +1,269 @@
|
||||||
|
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||||
|
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
-
|
||||||
|
- The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
- 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
- the License. You may obtain a copy of the License at
|
||||||
|
- http://www.mozilla.org/MPL/
|
||||||
|
-
|
||||||
|
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
- for the specific language governing rights and limitations under the
|
||||||
|
- License.
|
||||||
|
-
|
||||||
|
- The Original Code is Strict-Transport-Security.
|
||||||
|
-
|
||||||
|
- The Initial Developer of the Original Code is
|
||||||
|
- Mozilla Foundation.
|
||||||
|
- Portions created by the Initial Developer are Copyright (C) 2010
|
||||||
|
- the Initial Developer. All Rights Reserved.
|
||||||
|
-
|
||||||
|
- Contributor(s):
|
||||||
|
- Sid Stamm <sid@mozilla.com>
|
||||||
|
-
|
||||||
|
- Alternatively, the contents of this file may be used under the terms of
|
||||||
|
- either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
- in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
- of those above. If you wish to allow use of your version of this file only
|
||||||
|
- under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
- use your version of this file under the terms of the MPL, indicate your
|
||||||
|
- decision by deleting the provisions above and replace them with the notice
|
||||||
|
- and other provisions required by the LGPL or the GPL. If you do not delete
|
||||||
|
- the provisions above, a recipient may use your version of this file under
|
||||||
|
- the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
-
|
||||||
|
- ***** END LICENSE BLOCK ***** -->
|
||||||
|
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>opens additional content that should be converted to https</title>
|
||||||
|
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||||
|
|
||||||
|
<script class="testbody" type="text/javascript">
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
const STSPATH = "/tests/security/ssl/stricttransportsecurity";
|
||||||
|
|
||||||
|
const NUM_TEST_FRAMES = 4;
|
||||||
|
var testframes = {
|
||||||
|
'samedom':
|
||||||
|
{'url': "http://example.com" + STSPATH + "/verify.sjs",
|
||||||
|
'expected': {'plain': 'SECURE',
|
||||||
|
'subdom': 'SECURE',
|
||||||
|
'nosts': 'INSECURE'}},
|
||||||
|
'subdom':
|
||||||
|
{'url': "http://test1.example.com" + STSPATH + "/verify.sjs",
|
||||||
|
'expected': {'plain': 'INSECURE',
|
||||||
|
'subdom': 'SECURE',
|
||||||
|
'nosts': 'INSECURE'}},
|
||||||
|
'otherdom':
|
||||||
|
{'url': "http://example.org" + STSPATH + "/verify.sjs",
|
||||||
|
'expected': {'plain': 'INSECURE',
|
||||||
|
'subdom': 'INSECURE',
|
||||||
|
'nosts': 'INSECURE'}},
|
||||||
|
'alreadysecure':
|
||||||
|
{'url': "https://test2.example.com" + STSPATH + "/verify.sjs",
|
||||||
|
'expected': {'plain': 'SECURE',
|
||||||
|
'subdom': 'SECURE',
|
||||||
|
'nosts': 'SECURE'}},
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is how many sub-tests (testframes) in each round.
|
||||||
|
// When the round begins, this will be initialized.
|
||||||
|
var testsleftinround = 0;
|
||||||
|
var currentround = "";
|
||||||
|
|
||||||
|
var _PBSvc = null;
|
||||||
|
var _PrefSvc = null;
|
||||||
|
|
||||||
|
function _getPBService() {
|
||||||
|
if (_PBSvc)
|
||||||
|
return _PBSvc;
|
||||||
|
|
||||||
|
// not all apps will have the private browsing service.
|
||||||
|
try {
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||||
|
_PBSvc = Components.classes["@mozilla.org/privatebrowsing;1"]
|
||||||
|
.getService(Components.interfaces.nsIPrivateBrowsingService);
|
||||||
|
return _PBSvc;
|
||||||
|
} catch (e) {}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
function _getPrefService() {
|
||||||
|
if (_PrefSvc)
|
||||||
|
return _PrefSvc;
|
||||||
|
|
||||||
|
// not all apps will have the private browsing service.
|
||||||
|
try {
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||||
|
_PrefSvc = Components.classes["@mozilla.org/preferences-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIPrefService)
|
||||||
|
.QueryInterface(Components.interfaces.nsIPrefBranch2);
|
||||||
|
return _PrefSvc;
|
||||||
|
} catch (e) {}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function startRound(round) {
|
||||||
|
currentround = round;
|
||||||
|
testsleftinround = NUM_TEST_FRAMES;
|
||||||
|
dump("TESTS LEFT IN ROUND: " + testsleftinround + "\n");
|
||||||
|
var frame = document.createElement("iframe");
|
||||||
|
frame.setAttribute('id', 'ifr_bootstrap');
|
||||||
|
frame.setAttribute('src', "https://example.com" + STSPATH +
|
||||||
|
"/" + round + "_bootstrap.html");
|
||||||
|
document.body.appendChild(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadVerifyFrames(round) {
|
||||||
|
for (var test in testframes) {
|
||||||
|
var frame = document.createElement("iframe");
|
||||||
|
frame.setAttribute('id', 'ifr_' + test);
|
||||||
|
frame.setAttribute('src', testframes[test].url + '?id=' + test);
|
||||||
|
document.body.appendChild(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Messages received are in this format:
|
||||||
|
* (BOOTSTRAP|SECURE|INSECURE) testid
|
||||||
|
* For example: "BOOTSTRAP subdom"
|
||||||
|
* or: "INSECURE otherdom"
|
||||||
|
*/
|
||||||
|
function onMessageReceived(event) {
|
||||||
|
|
||||||
|
// otherwise, it's a test result
|
||||||
|
var result = event.data.split(/\s+/);
|
||||||
|
if (result.length != 2) {
|
||||||
|
SimpleTest.ok(false, event.data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result[0] === "BOOTSTRAP") {
|
||||||
|
loadVerifyFrames(currentround);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the result (SECURE/INSECURE) is expected for this round/test
|
||||||
|
// combo
|
||||||
|
dump_STSState();
|
||||||
|
dump( "*** in ROUND " + currentround +
|
||||||
|
", test " + result[1] +
|
||||||
|
" is " + result[0] + "\n");
|
||||||
|
SimpleTest.is(result[0], testframes[result[1]].expected[currentround],
|
||||||
|
"in ROUND " + currentround +
|
||||||
|
", test " + result[1]);
|
||||||
|
testsleftinround--;
|
||||||
|
|
||||||
|
// if this round is complete...
|
||||||
|
if (testsleftinround < 1) {
|
||||||
|
dump("DONE WITH ROUND " + currentround + "\n");
|
||||||
|
// remove all the iframes in the document
|
||||||
|
document.body.removeChild(document.getElementById('ifr_bootstrap'));
|
||||||
|
for (var test in testframes)
|
||||||
|
document.body.removeChild(document.getElementById('ifr_' + test));
|
||||||
|
currentround = "";
|
||||||
|
|
||||||
|
// And advance to the next test.
|
||||||
|
// Defer this so it doesn't muck with the stack too much.
|
||||||
|
SimpleTest.executeSoon(nextTest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_sts_before_private_mode() {
|
||||||
|
dump_STSState();
|
||||||
|
dump("*** not in private browsing mode\n");
|
||||||
|
startRound('plain');
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_sts_in_private_mode() {
|
||||||
|
dump_STSState();
|
||||||
|
dump("*** Entering private browsing mode\n");
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||||
|
_getPrefService().setBoolPref("browser.privatebrowsing.keep_current_session",
|
||||||
|
true);
|
||||||
|
_getPBService().privateBrowsingEnabled = true;
|
||||||
|
dump("*** ... done\n");
|
||||||
|
dump_STSState();
|
||||||
|
startRound('subdom');
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_sts_after_exiting_private_mode() {
|
||||||
|
dump_STSState();
|
||||||
|
dump("*** Exiting private browsing mode\n");
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||||
|
_getPBService().privateBrowsingEnabled = false;
|
||||||
|
_getPrefService().clearUserPref("browser.privatebrowsing.keep_current_session");
|
||||||
|
dump("*** ... done\n");
|
||||||
|
dump_STSState();
|
||||||
|
startRound('nosts');
|
||||||
|
}
|
||||||
|
|
||||||
|
function clean_up_sts_state() {
|
||||||
|
// erase all signs that this test ran.
|
||||||
|
dump("*** Cleaning up STS data.\n");
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||||
|
const Cc = Components.classes;
|
||||||
|
const Ci = Components.interfaces;
|
||||||
|
var ios = Cc["@mozilla.org/network/io-service;1"]
|
||||||
|
.getService(Ci.nsIIOService);
|
||||||
|
var thehost = ios.newURI("http://example.com", null, null);
|
||||||
|
var stss = Cc["@mozilla.org/stsservice;1"]
|
||||||
|
.getService(Ci.nsIStrictTransportSecurityService);
|
||||||
|
stss.removeStsState(thehost);
|
||||||
|
dump_STSState();
|
||||||
|
SimpleTest.executeSoon(nextTest);
|
||||||
|
}
|
||||||
|
|
||||||
|
function dump_STSState() {
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||||
|
var stss = Components.classes["@mozilla.org/stsservice;1"]
|
||||||
|
.getService(Components.interfaces.nsIStrictTransportSecurityService);
|
||||||
|
dump("*** State of example.com: " + stss.isStsHost("example.com") + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// these are executed in the order presented.
|
||||||
|
// 0. test that STS works before entering private browsing mode.
|
||||||
|
// (load sts-bootstrapped "plain" tests)
|
||||||
|
// ... clear any STS data ...
|
||||||
|
// 1. test that STS works in private browsing mode
|
||||||
|
// (load sts-bootstrapped "subdomain" tests)
|
||||||
|
// 2. test that after exiting private browsing, STS data is forgotten
|
||||||
|
// (verified with non-sts-bootstrapped pages)
|
||||||
|
var tests = [];
|
||||||
|
{ // skip these tests if there's no private mode support
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||||
|
if ("@mozilla.org/privatebrowsing;1" in Components.classes) {
|
||||||
|
tests = [
|
||||||
|
test_sts_before_private_mode,
|
||||||
|
clean_up_sts_state,
|
||||||
|
test_sts_in_private_mode,
|
||||||
|
test_sts_after_exiting_private_mode,
|
||||||
|
clean_up_sts_state,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextTest() {
|
||||||
|
if (tests.length)
|
||||||
|
SimpleTest.executeSoon(tests.shift());
|
||||||
|
else
|
||||||
|
SimpleTest.executeSoon(SimpleTest.finish);
|
||||||
|
}
|
||||||
|
|
||||||
|
// listen for calls back from the sts-setting iframe and then
|
||||||
|
// the verification frames.
|
||||||
|
window.addEventListener("message", onMessageReceived, false);
|
||||||
|
window.addEventListener('load', nextTest, false);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
This test will load some iframes and do some tests.
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
Загрузка…
Ссылка в новой задаче