зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 10 changesets (bug 1536411) for causing leaks in CondVar, MessagePortService, MessagePortServiceData.
Backed out changeset eda5854cd7e8 (bug 1536411) Backed out changeset f94dfbf2476c (bug 1536411) Backed out changeset c68dc3152faa (bug 1536411) Backed out changeset f67d157e8baf (bug 1536411) Backed out changeset 1107a9767f38 (bug 1536411) Backed out changeset ccbe1af00fb9 (bug 1536411) Backed out changeset 552c4b588524 (bug 1536411) Backed out changeset 2eb20578159b (bug 1536411) Backed out changeset 45708d22bb6d (bug 1536411) Backed out changeset 87601ef1d4d4 (bug 1536411)
This commit is contained in:
Родитель
2d1a0515d9
Коммит
af07021e88
|
@ -455,37 +455,6 @@ BasePrincipal::CloneStrippingUserContextIdAndFirstPartyDomain() {
|
|||
return BasePrincipal::CreateCodebasePrincipal(uri, attrs);
|
||||
}
|
||||
|
||||
already_AddRefed<BasePrincipal> BasePrincipal::CloneForcingFirstPartyDomain(
|
||||
nsIURI* aURI) {
|
||||
if (NS_WARN_IF(!IsCodebasePrincipal())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OriginAttributes attrs = OriginAttributesRef();
|
||||
// XXX this is slow. Maybe we should consider to make it faster.
|
||||
attrs.SetFirstPartyDomain(false, aURI, true /* aForced */);
|
||||
|
||||
return CloneForcingOriginAttributes(attrs);
|
||||
}
|
||||
|
||||
already_AddRefed<BasePrincipal> BasePrincipal::CloneForcingOriginAttributes(
|
||||
const OriginAttributes& aOriginAttributes) {
|
||||
if (NS_WARN_IF(!IsCodebasePrincipal())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoCString originNoSuffix;
|
||||
nsresult rv = GetOriginNoSuffix(originNoSuffix);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
nsIURI* uri = static_cast<ContentPrincipal*>(this)->mCodebase;
|
||||
RefPtr<ContentPrincipal> copy = new ContentPrincipal();
|
||||
rv = copy->Init(uri, aOriginAttributes, originNoSuffix);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
return copy.forget();
|
||||
}
|
||||
|
||||
extensions::WebExtensionPolicy* BasePrincipal::ContentScriptAddonPolicy() {
|
||||
if (!Is<ExpandedPrincipal>()) {
|
||||
return nullptr;
|
||||
|
|
|
@ -169,11 +169,6 @@ class BasePrincipal : public nsJSPrincipals {
|
|||
already_AddRefed<BasePrincipal>
|
||||
CloneStrippingUserContextIdAndFirstPartyDomain();
|
||||
|
||||
already_AddRefed<BasePrincipal> CloneForcingFirstPartyDomain(nsIURI* aURI);
|
||||
|
||||
already_AddRefed<BasePrincipal> CloneForcingOriginAttributes(
|
||||
const OriginAttributes& aOriginAttributes);
|
||||
|
||||
// If this is an add-on content script principal, returns its AddonPolicy.
|
||||
// Otherwise returns null.
|
||||
extensions::WebExtensionPolicy* ContentScriptAddonPolicy();
|
||||
|
|
|
@ -38,11 +38,11 @@ void OriginAttributes::InitPrefs() {
|
|||
}
|
||||
|
||||
void OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument,
|
||||
nsIURI* aURI, bool aForced) {
|
||||
nsIURI* aURI) {
|
||||
bool isFirstPartyEnabled = IsFirstPartyEnabled();
|
||||
|
||||
// If the prefs are off or this is not a top level load, bail out.
|
||||
if ((!isFirstPartyEnabled || !aIsTopLevelDocument) && !aForced) {
|
||||
// If the pref is off or this is not a top level load, bail out.
|
||||
if (!isFirstPartyEnabled || !aIsTopLevelDocument) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,7 @@ class OriginAttributes : public dom::OriginAttributesDictionary {
|
|||
explicit OriginAttributes(const OriginAttributesDictionary& aOther)
|
||||
: OriginAttributesDictionary(aOther) {}
|
||||
|
||||
void SetFirstPartyDomain(const bool aIsTopLevelDocument, nsIURI* aURI,
|
||||
bool aForced = false);
|
||||
void SetFirstPartyDomain(const bool aIsTopLevelDocument, nsIURI* aURI);
|
||||
void SetFirstPartyDomain(const bool aIsTopLevelDocument,
|
||||
const nsACString& aDomain);
|
||||
|
||||
|
|
|
@ -197,7 +197,6 @@ interface nsIScriptSecurityManager : nsISupports
|
|||
in nsIURI aTargetURI,
|
||||
in boolean reportError,
|
||||
in boolean fromPrivateWindow);
|
||||
|
||||
/**
|
||||
* Get the principal for the given channel. This will typically be the
|
||||
* channel owner if there is one, and the codebase principal for the
|
||||
|
@ -205,23 +204,6 @@ interface nsIScriptSecurityManager : nsISupports
|
|||
*/
|
||||
nsIPrincipal getChannelResultPrincipal(in nsIChannel aChannel);
|
||||
|
||||
/**
|
||||
* Get the storage principal for the given channel. This is basically the
|
||||
* same of getChannelResultPrincipal() execept for trackers, where we
|
||||
* return a principal with a different OriginAttributes.
|
||||
*/
|
||||
nsIPrincipal getChannelResultStoragePrincipal(in nsIChannel aChannel);
|
||||
|
||||
/**
|
||||
* This method does getChannelResultPrincipal() +
|
||||
* getChannelResultStoragePrincipal().
|
||||
* This method is mainly done for Document::Reset(). There are no other
|
||||
* reasons to use this method.
|
||||
*/
|
||||
void getChannelResultPrincipals(in nsIChannel aChannel,
|
||||
out nsIPrincipal aPrincipal,
|
||||
out nsIPrincipal aStoragePrincipal);
|
||||
|
||||
/**
|
||||
* Temporary API until bug 1220687 is fixed.
|
||||
*
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "nsScriptSecurityManager.h"
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/StoragePrincipalHelper.h"
|
||||
|
||||
#include "xpcpublic.h"
|
||||
#include "XPCWrapper.h"
|
||||
|
@ -246,33 +245,6 @@ nsresult nsScriptSecurityManager::GetChannelResultPrincipalIfNotSandboxed(
|
|||
/*aIgnoreSandboxing*/ true);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::GetChannelResultStoragePrincipal(
|
||||
nsIChannel* aChannel, nsIPrincipal** aPrincipal) {
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsresult rv = GetChannelResultPrincipal(aChannel, getter_AddRefs(principal),
|
||||
/*aIgnoreSandboxing*/ false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return StoragePrincipalHelper::Create(aChannel, principal, aPrincipal);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::GetChannelResultPrincipals(
|
||||
nsIChannel* aChannel, nsIPrincipal** aPrincipal,
|
||||
nsIPrincipal** aStoragePrincipal) {
|
||||
nsresult rv = GetChannelResultPrincipal(aChannel, aPrincipal,
|
||||
/*aIgnoreSandboxing*/ false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return StoragePrincipalHelper::Create(aChannel, *aPrincipal,
|
||||
aStoragePrincipal);
|
||||
}
|
||||
|
||||
static void InheritAndSetCSPOnPrincipalIfNeeded(nsIChannel* aChannel,
|
||||
nsIPrincipal* aPrincipal) {
|
||||
// loading a data: URI into an iframe, or loading frame[srcdoc] need
|
||||
|
|
|
@ -1923,32 +1923,23 @@ bool Document::IsVisibleConsideringAncestors() const {
|
|||
void Document::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsIPrincipal> storagePrincipal;
|
||||
if (aChannel) {
|
||||
// Note: this code is duplicated in XULDocument::StartDocumentLoad and
|
||||
// nsScriptSecurityManager::GetChannelResultPrincipals.
|
||||
// nsScriptSecurityManager::GetChannelResultPrincipal.
|
||||
// Note: this should match nsDocShell::OnLoadingSite
|
||||
NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
|
||||
|
||||
nsIScriptSecurityManager* securityManager =
|
||||
nsContentUtils::GetSecurityManager();
|
||||
if (securityManager) {
|
||||
securityManager->GetChannelResultPrincipals(
|
||||
aChannel, getter_AddRefs(principal),
|
||||
getter_AddRefs(storagePrincipal));
|
||||
securityManager->GetChannelResultPrincipal(aChannel,
|
||||
getter_AddRefs(principal));
|
||||
}
|
||||
}
|
||||
|
||||
bool equal = principal->Equals(storagePrincipal);
|
||||
|
||||
principal = MaybeDowngradePrincipal(principal);
|
||||
if (equal) {
|
||||
storagePrincipal = principal;
|
||||
} else {
|
||||
storagePrincipal = MaybeDowngradePrincipal(storagePrincipal);
|
||||
}
|
||||
|
||||
ResetToURI(uri, aLoadGroup, principal, storagePrincipal);
|
||||
ResetToURI(uri, aLoadGroup, principal);
|
||||
|
||||
// Note that, since mTiming does not change during a reset, the
|
||||
// navigationStart time remains unchanged and therefore any future new
|
||||
|
@ -2040,10 +2031,8 @@ void Document::DisconnectNodeTree() {
|
|||
}
|
||||
|
||||
void Document::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal* aStoragePrincipal) {
|
||||
nsIPrincipal* aPrincipal) {
|
||||
MOZ_ASSERT(aURI, "Null URI passed to ResetToURI");
|
||||
MOZ_ASSERT(!!aPrincipal == !!aStoragePrincipal);
|
||||
|
||||
MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug,
|
||||
("DOCUMENT %p ResetToURI %s", this, aURI->GetSpecOrDefault().get()));
|
||||
|
@ -2073,7 +2062,7 @@ void Document::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
|
|||
// This ensures that, during teardown, the document and the dying window
|
||||
// (which already nulled out its document pointer and cached the principal)
|
||||
// have matching principals.
|
||||
SetPrincipals(nullptr, nullptr);
|
||||
SetPrincipal(nullptr);
|
||||
|
||||
// Clear the original URI so SetDocumentURI sets it.
|
||||
mOriginalURI = nullptr;
|
||||
|
@ -2121,7 +2110,7 @@ void Document::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
|
|||
|
||||
// Now get our new principal
|
||||
if (aPrincipal) {
|
||||
SetPrincipals(aPrincipal, aStoragePrincipal);
|
||||
SetPrincipal(aPrincipal);
|
||||
} else {
|
||||
nsIScriptSecurityManager* securityManager =
|
||||
nsContentUtils::GetSecurityManager();
|
||||
|
@ -2141,7 +2130,7 @@ void Document::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
|
|||
nsresult rv = securityManager->GetLoadContextCodebasePrincipal(
|
||||
mDocumentURI, loadContext, getter_AddRefs(principal));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
SetPrincipals(principal, principal);
|
||||
SetPrincipal(principal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2804,7 +2793,7 @@ nsresult Document::InitCSP(nsIChannel* aChannel) {
|
|||
if (needNewNullPrincipal) {
|
||||
principal = NullPrincipal::CreateWithInheritedAttributes(principal);
|
||||
principal->SetCsp(csp);
|
||||
SetPrincipals(principal, principal);
|
||||
SetPrincipal(principal);
|
||||
}
|
||||
|
||||
// ----- Enforce frame-ancestor policy on any applied policies
|
||||
|
@ -3028,9 +3017,7 @@ void Document::RemoveFromIdTable(Element* aElement, nsAtom* aId) {
|
|||
}
|
||||
}
|
||||
|
||||
void Document::SetPrincipals(nsIPrincipal* aNewPrincipal,
|
||||
nsIPrincipal* aNewStoragePrincipal) {
|
||||
MOZ_ASSERT(!!aNewPrincipal == !!aNewStoragePrincipal);
|
||||
void Document::SetPrincipal(nsIPrincipal* aNewPrincipal) {
|
||||
if (aNewPrincipal && mAllowDNSPrefetch && sDisablePrefetchHTTPSPref) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
aNewPrincipal->GetURI(getter_AddRefs(uri));
|
||||
|
@ -3040,7 +3027,6 @@ void Document::SetPrincipals(nsIPrincipal* aNewPrincipal,
|
|||
}
|
||||
}
|
||||
mNodeInfoManager->SetDocumentPrincipal(aNewPrincipal);
|
||||
mIntrinsicStoragePrincipal = aNewStoragePrincipal;
|
||||
|
||||
#ifdef DEBUG
|
||||
// Validate that the docgroup is set correctly by calling its getter and
|
||||
|
@ -8207,8 +8193,7 @@ nsresult Document::CloneDocHelper(Document* clone) const {
|
|||
}
|
||||
clone->mChannel = channel;
|
||||
if (uri) {
|
||||
clone->ResetToURI(uri, loadGroup, NodePrincipal(),
|
||||
EffectiveStoragePrincipal());
|
||||
clone->ResetToURI(uri, loadGroup, NodePrincipal());
|
||||
}
|
||||
|
||||
clone->SetContainer(mDocumentContainer);
|
||||
|
@ -8222,7 +8207,7 @@ nsresult Document::CloneDocHelper(Document* clone) const {
|
|||
// them.
|
||||
clone->SetDocumentURI(Document::GetDocumentURI());
|
||||
clone->SetChromeXHRDocURI(mChromeXHRDocURI);
|
||||
clone->SetPrincipals(NodePrincipal(), EffectiveStoragePrincipal());
|
||||
clone->SetPrincipal(NodePrincipal());
|
||||
clone->mDocumentBaseURI = mDocumentBaseURI;
|
||||
clone->SetChromeXHRDocBaseURI(mChromeXHRDocBaseURI);
|
||||
|
||||
|
@ -12844,23 +12829,5 @@ nsICookieSettings* Document::CookieSettings() {
|
|||
return mCookieSettings;
|
||||
}
|
||||
|
||||
nsIPrincipal* Document::EffectiveStoragePrincipal() const {
|
||||
if (!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
|
||||
return NodePrincipal();
|
||||
}
|
||||
|
||||
nsContentUtils::StorageAccess access =
|
||||
nsContentUtils::StorageAllowedForDocument(this);
|
||||
|
||||
// Let's use the storage principal only if we need to partition the cookie
|
||||
// jar. When the permission is granted, access will be different and the
|
||||
// normal principal will be used.
|
||||
if (access != nsContentUtils::StorageAccess::ePartitionedOrDeny) {
|
||||
return NodePrincipal();
|
||||
}
|
||||
|
||||
return mIntrinsicStoragePrincipal;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -523,15 +523,9 @@ class Document : public nsINode,
|
|||
return DocumentOrShadowRoot::SetValueMissingState(aName, aValue);
|
||||
}
|
||||
|
||||
nsIPrincipal* EffectiveStoragePrincipal() const;
|
||||
|
||||
// nsIScriptObjectPrincipal
|
||||
nsIPrincipal* GetPrincipal() final { return NodePrincipal(); }
|
||||
|
||||
nsIPrincipal* GetEffectiveStoragePrincipal() final {
|
||||
return EffectiveStoragePrincipal();
|
||||
}
|
||||
|
||||
// EventTarget
|
||||
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
|
||||
EventListenerManager* GetOrCreateListenerManager() override;
|
||||
|
@ -731,10 +725,10 @@ class Document : public nsINode,
|
|||
void SetReferrer(const nsACString& aReferrer) { mReferrer = aReferrer; }
|
||||
|
||||
/**
|
||||
* Set the principals responsible for this document. Chances are, you do not
|
||||
* want to be using this.
|
||||
* Set the principal responsible for this document. Chances are,
|
||||
* you do not want to be using this.
|
||||
*/
|
||||
void SetPrincipals(nsIPrincipal* aPrincipal, nsIPrincipal* aStoragePrincipal);
|
||||
void SetPrincipal(nsIPrincipal* aPrincipal);
|
||||
|
||||
/**
|
||||
* Get the list of ancestor principals for a document. This is the same as
|
||||
|
@ -2092,13 +2086,12 @@ class Document : public nsINode,
|
|||
virtual void Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup);
|
||||
|
||||
/**
|
||||
* Reset this document to aURI, aLoadGroup, aPrincipal and aStoragePrincipal.
|
||||
* aURI must not be null. If aPrincipal is null, a codebase principal based
|
||||
* on aURI will be used.
|
||||
* Reset this document to aURI, aLoadGroup, and aPrincipal. aURI must not be
|
||||
* null. If aPrincipal is null, a codebase principal based on aURI will be
|
||||
* used.
|
||||
*/
|
||||
virtual void ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal* aStoragePrincipal);
|
||||
nsIPrincipal* aPrincipal);
|
||||
|
||||
/**
|
||||
* Set the container (docshell) for this document. Virtual so that
|
||||
|
@ -4741,9 +4734,6 @@ class Document : public nsINode,
|
|||
|
||||
bool mInRDMPane;
|
||||
|
||||
// The principal to use for the storage area of this document.
|
||||
nsCOMPtr<nsIPrincipal> mIntrinsicStoragePrincipal;
|
||||
|
||||
public:
|
||||
// Needs to be public because the bindings code pokes at it.
|
||||
js::ExpandoAndGeneration mExpandoAndGeneration;
|
||||
|
|
|
@ -8226,7 +8226,7 @@ nsContentUtils::StorageAccess nsContentUtils::StorageAllowedForWindow(
|
|||
|
||||
// static, public
|
||||
nsContentUtils::StorageAccess nsContentUtils::StorageAllowedForDocument(
|
||||
const Document* aDoc) {
|
||||
Document* aDoc) {
|
||||
MOZ_ASSERT(aDoc);
|
||||
|
||||
if (nsPIDOMWindowInner* inner = aDoc->GetInnerWindow()) {
|
||||
|
|
|
@ -2995,7 +2995,7 @@ class nsContentUtils {
|
|||
* the window's extant document has not been set yet. The code in
|
||||
* StorageAllowedForWindow(), however, will not work in these cases.
|
||||
*/
|
||||
static StorageAccess StorageAllowedForDocument(const Document* aDoc);
|
||||
static StorageAccess StorageAllowedForDocument(Document* aDoc);
|
||||
|
||||
/*
|
||||
* Checks if storage should be allowed for a new window with the given
|
||||
|
|
|
@ -1128,7 +1128,6 @@ void nsGlobalWindowInner::FreeInnerObjects() {
|
|||
if (mDoc) {
|
||||
// Remember the document's principal and URI.
|
||||
mDocumentPrincipal = mDoc->NodePrincipal();
|
||||
mDocumentStoragePrincipal = mDoc->EffectiveStoragePrincipal();
|
||||
mDocumentURI = mDoc->GetDocumentURI();
|
||||
mDocBaseURI = mDoc->GetDocBaseURI();
|
||||
|
||||
|
@ -1358,7 +1357,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowInner)
|
|||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplicationCache)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentStoragePrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChild)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
|
||||
|
||||
|
@ -1462,7 +1460,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner)
|
|||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentStoragePrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChild)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
|
||||
|
||||
|
@ -2051,29 +2048,6 @@ nsIPrincipal* nsGlobalWindowInner::GetPrincipal() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsIPrincipal* nsGlobalWindowInner::GetEffectiveStoragePrincipal() {
|
||||
if (mDoc) {
|
||||
// If we have a document, get the principal from the document
|
||||
return mDoc->EffectiveStoragePrincipal();
|
||||
}
|
||||
|
||||
if (mDocumentStoragePrincipal) {
|
||||
return mDocumentStoragePrincipal;
|
||||
}
|
||||
|
||||
// If we don't have a storage principal and we don't have a document we ask
|
||||
// the parent window for the storage principal.
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
|
||||
do_QueryInterface(GetParentInternal());
|
||||
|
||||
if (objPrincipal) {
|
||||
return objPrincipal->GetEffectiveStoragePrincipal();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// nsGlobalWindowInner::nsIDOMWindow
|
||||
//*****************************************************************************
|
||||
|
@ -2821,9 +2795,10 @@ bool nsGlobalWindowInner::MayResolve(jsid aId) {
|
|||
return WebIDLGlobalNameHash::MayResolve(aId);
|
||||
}
|
||||
|
||||
void nsGlobalWindowInner::GetOwnPropertyNames(
|
||||
JSContext* aCx, JS::MutableHandleVector<jsid> aNames, bool aEnumerableOnly,
|
||||
ErrorResult& aRv) {
|
||||
void nsGlobalWindowInner::GetOwnPropertyNames(JSContext* aCx,
|
||||
JS::MutableHandleVector<jsid> aNames,
|
||||
bool aEnumerableOnly,
|
||||
ErrorResult& aRv) {
|
||||
if (aEnumerableOnly) {
|
||||
// The names we would return from here get defined on the window via one of
|
||||
// two codepaths. The ones coming from the WebIDLGlobalNameHash will end up
|
||||
|
@ -6897,9 +6872,6 @@ void nsGlobalWindowInner::StorageAccessGranted() {
|
|||
object->EnsureObserver();
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the IndexedDB factory.
|
||||
mIndexedDB = nullptr;
|
||||
}
|
||||
|
||||
mozilla::dom::TabGroup* nsPIDOMWindowInner::TabGroup() {
|
||||
|
|
|
@ -260,8 +260,6 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
|
|||
// nsIScriptObjectPrincipal
|
||||
virtual nsIPrincipal* GetPrincipal() override;
|
||||
|
||||
virtual nsIPrincipal* GetEffectiveStoragePrincipal() override;
|
||||
|
||||
// nsIDOMWindow
|
||||
NS_DECL_NSIDOMWINDOW
|
||||
|
||||
|
@ -1296,8 +1294,6 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
|
|||
RefPtr<mozilla::dom::VisualViewport> mVisualViewport;
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
|
||||
nsCOMPtr<nsIPrincipal> mDocumentStoragePrincipal;
|
||||
|
||||
// mTabChild is only ever populated in the content process.
|
||||
nsCOMPtr<nsITabChild> mTabChild;
|
||||
|
||||
|
|
|
@ -476,9 +476,8 @@ class nsOuterWindowProxy : public MaybeCrossOriginObject<js::Wrapper> {
|
|||
* "proxy" is the WindowProxy object involved. It may not be same-compartment
|
||||
* with cx.
|
||||
*/
|
||||
bool getOwnEnumerablePropertyKeys(
|
||||
JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::MutableHandleVector<jsid> props) const override;
|
||||
bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::MutableHandleVector<jsid> props) const override;
|
||||
|
||||
/**
|
||||
* Hook used by SpiderMonkey to implement Object.prototype.toString.
|
||||
|
@ -734,9 +733,9 @@ bool nsOuterWindowProxy::definePropertySameOrigin(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool nsOuterWindowProxy::ownPropertyKeys(
|
||||
JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::MutableHandleVector<jsid> props) const {
|
||||
bool nsOuterWindowProxy::ownPropertyKeys(JSContext* cx,
|
||||
JS::Handle<JSObject*> proxy,
|
||||
JS::MutableHandleVector<jsid> props) const {
|
||||
// Just our indexed stuff followed by our "normal" own property names.
|
||||
if (!AppendIndexedPropertyNames(proxy, props)) {
|
||||
return false;
|
||||
|
@ -939,8 +938,7 @@ bool nsOuterWindowProxy::set(JSContext* cx, JS::Handle<JSObject*> proxy,
|
|||
}
|
||||
|
||||
bool nsOuterWindowProxy::getOwnEnumerablePropertyKeys(
|
||||
JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::MutableHandleVector<jsid> props) const {
|
||||
JSContext* cx, JS::Handle<JSObject*> proxy, JS::MutableHandleVector<jsid> props) const {
|
||||
// We could just stop overring getOwnEnumerablePropertyKeys and let our
|
||||
// superclasses deal (by falling back on the BaseProxyHandler implementation
|
||||
// that uses a combination of ownPropertyKeys and getOwnPropertyDescriptor to
|
||||
|
@ -1403,7 +1401,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowOuter)
|
|||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedDoc)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentStoragePrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
|
||||
|
||||
// Traverse stuff from nsPIDOMWindow
|
||||
|
@ -1430,7 +1427,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowOuter)
|
|||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedDoc)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentStoragePrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
|
||||
|
||||
// Unlink stuff from nsPIDOMWindow
|
||||
|
@ -1898,8 +1894,6 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
|
|||
bool aForceReuseInnerWindow) {
|
||||
MOZ_ASSERT(mDocumentPrincipal == nullptr,
|
||||
"mDocumentPrincipal prematurely set!");
|
||||
MOZ_ASSERT(mDocumentStoragePrincipal == nullptr,
|
||||
"mDocumentStoragePrincipal prematurely set!");
|
||||
MOZ_ASSERT(aDocument);
|
||||
|
||||
// Bail out early if we're in process of closing down the window.
|
||||
|
@ -2452,7 +2446,6 @@ void nsGlobalWindowOuter::DetachFromDocShell() {
|
|||
|
||||
// Remember the document's principal and URI.
|
||||
mDocumentPrincipal = mDoc->NodePrincipal();
|
||||
mDocumentStoragePrincipal = mDoc->EffectiveStoragePrincipal();
|
||||
mDocumentURI = mDoc->GetDocumentURI();
|
||||
|
||||
// Release our document reference
|
||||
|
@ -2768,29 +2761,6 @@ nsIPrincipal* nsGlobalWindowOuter::GetPrincipal() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsIPrincipal* nsGlobalWindowOuter::GetEffectiveStoragePrincipal() {
|
||||
if (mDoc) {
|
||||
// If we have a document, get the principal from the document
|
||||
return mDoc->EffectiveStoragePrincipal();
|
||||
}
|
||||
|
||||
if (mDocumentStoragePrincipal) {
|
||||
return mDocumentStoragePrincipal;
|
||||
}
|
||||
|
||||
// If we don't have a storage principal and we don't have a document we ask
|
||||
// the parent window for the storage principal.
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
|
||||
do_QueryInterface(GetParentInternal());
|
||||
|
||||
if (objPrincipal) {
|
||||
return objPrincipal->GetEffectiveStoragePrincipal();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// nsGlobalWindowOuter::nsIDOMWindow
|
||||
//*****************************************************************************
|
||||
|
|
|
@ -247,8 +247,6 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
|
|||
// nsIScriptObjectPrincipal
|
||||
virtual nsIPrincipal* GetPrincipal() override;
|
||||
|
||||
virtual nsIPrincipal* GetEffectiveStoragePrincipal() override;
|
||||
|
||||
// nsIDOMWindow
|
||||
NS_DECL_NSIDOMWINDOW
|
||||
|
||||
|
@ -1100,7 +1098,6 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
|
|||
RefPtr<mozilla::dom::Storage> mLocalStorage;
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
|
||||
nsCOMPtr<nsIPrincipal> mDocumentStoragePrincipal;
|
||||
|
||||
#ifdef DEBUG
|
||||
uint32_t mSerial;
|
||||
|
|
|
@ -26,8 +26,6 @@ class nsIScriptObjectPrincipal : public nsISupports {
|
|||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTOBJECTPRINCIPAL_IID)
|
||||
|
||||
virtual nsIPrincipal* GetPrincipal() = 0;
|
||||
|
||||
virtual nsIPrincipal* GetEffectiveStoragePrincipal() = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptObjectPrincipal,
|
||||
|
|
|
@ -48,12 +48,11 @@ class BroadcastChannelMessage final : public StructuredCloneDataNoTransfers {
|
|||
|
||||
namespace {
|
||||
|
||||
nsIPrincipal* GetStoragePrincipalFromThreadSafeWorkerRef(
|
||||
nsIPrincipal* GetPrincipalFromThreadSafeWorkerRef(
|
||||
ThreadSafeWorkerRef* aWorkerRef) {
|
||||
nsIPrincipal* storagePrincipal =
|
||||
aWorkerRef->Private()->GetEffectiveStoragePrincipal();
|
||||
if (storagePrincipal) {
|
||||
return storagePrincipal;
|
||||
nsIPrincipal* principal = aWorkerRef->Private()->GetPrincipal();
|
||||
if (principal) {
|
||||
return principal;
|
||||
}
|
||||
|
||||
// Walk up to our containing page
|
||||
|
@ -62,19 +61,19 @@ nsIPrincipal* GetStoragePrincipalFromThreadSafeWorkerRef(
|
|||
wp = wp->GetParent();
|
||||
}
|
||||
|
||||
return wp->GetEffectiveStoragePrincipal();
|
||||
return wp->GetPrincipal();
|
||||
}
|
||||
|
||||
class InitializeRunnable final : public WorkerMainThreadRunnable {
|
||||
public:
|
||||
InitializeRunnable(ThreadSafeWorkerRef* aWorkerRef, nsACString& aOrigin,
|
||||
PrincipalInfo& aStoragePrincipalInfo, ErrorResult& aRv)
|
||||
PrincipalInfo& aPrincipalInfo, ErrorResult& aRv)
|
||||
: WorkerMainThreadRunnable(
|
||||
aWorkerRef->Private(),
|
||||
NS_LITERAL_CSTRING("BroadcastChannel :: Initialize")),
|
||||
mWorkerRef(aWorkerRef),
|
||||
mOrigin(aOrigin),
|
||||
mStoragePrincipalInfo(aStoragePrincipalInfo),
|
||||
mPrincipalInfo(aPrincipalInfo),
|
||||
mRv(aRv) {
|
||||
MOZ_ASSERT(mWorkerRef);
|
||||
}
|
||||
|
@ -82,19 +81,18 @@ class InitializeRunnable final : public WorkerMainThreadRunnable {
|
|||
bool MainThreadRun() override {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsIPrincipal* storagePrincipal =
|
||||
GetStoragePrincipalFromThreadSafeWorkerRef(mWorkerRef);
|
||||
if (!storagePrincipal) {
|
||||
nsIPrincipal* principal = GetPrincipalFromThreadSafeWorkerRef(mWorkerRef);
|
||||
if (!principal) {
|
||||
mRv.Throw(NS_ERROR_FAILURE);
|
||||
return true;
|
||||
}
|
||||
|
||||
mRv = PrincipalToPrincipalInfo(storagePrincipal, &mStoragePrincipalInfo);
|
||||
mRv = PrincipalToPrincipalInfo(principal, &mPrincipalInfo);
|
||||
if (NS_WARN_IF(mRv.Failed())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
mRv = storagePrincipal->GetOrigin(mOrigin);
|
||||
mRv = principal->GetOrigin(mOrigin);
|
||||
if (NS_WARN_IF(mRv.Failed())) {
|
||||
return true;
|
||||
}
|
||||
|
@ -117,7 +115,7 @@ class InitializeRunnable final : public WorkerMainThreadRunnable {
|
|||
private:
|
||||
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
|
||||
nsACString& mOrigin;
|
||||
PrincipalInfo& mStoragePrincipalInfo;
|
||||
PrincipalInfo& mPrincipalInfo;
|
||||
ErrorResult& mRv;
|
||||
};
|
||||
|
||||
|
@ -229,9 +227,7 @@ already_AddRefed<BroadcastChannel> BroadcastChannel::Constructor(
|
|||
RefPtr<BroadcastChannel> bc = new BroadcastChannel(global, aChannel);
|
||||
|
||||
nsAutoCString origin;
|
||||
PrincipalInfo storagePrincipalInfo;
|
||||
|
||||
nsContentUtils::StorageAccess storageAccess;
|
||||
PrincipalInfo principalInfo;
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global);
|
||||
|
@ -247,29 +243,29 @@ already_AddRefed<BroadcastChannel> BroadcastChannel::Constructor(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(incumbent);
|
||||
if (NS_WARN_IF(!sop)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIPrincipal* storagePrincipal = sop->GetEffectiveStoragePrincipal();
|
||||
if (!storagePrincipal) {
|
||||
nsIPrincipal* principal = incumbent->PrincipalOrNull();
|
||||
if (!principal) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aRv = storagePrincipal->GetOrigin(origin);
|
||||
// We want to allow opaque origins.
|
||||
if (!principal->GetIsNullPrincipal() &&
|
||||
nsContentUtils::StorageAllowedForWindow(window) <=
|
||||
nsContentUtils::StorageAccess::eDeny) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aRv = principal->GetOrigin(origin);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aRv = PrincipalToPrincipalInfo(storagePrincipal, &storagePrincipalInfo);
|
||||
aRv = PrincipalToPrincipalInfo(principal, &principalInfo);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
storageAccess = nsContentUtils::StorageAllowedForWindow(window);
|
||||
} else {
|
||||
JSContext* cx = aGlobal.Context();
|
||||
|
||||
|
@ -288,23 +284,19 @@ already_AddRefed<BroadcastChannel> BroadcastChannel::Constructor(
|
|||
RefPtr<ThreadSafeWorkerRef> tsr = new ThreadSafeWorkerRef(workerRef);
|
||||
|
||||
RefPtr<InitializeRunnable> runnable =
|
||||
new InitializeRunnable(tsr, origin, storagePrincipalInfo, aRv);
|
||||
new InitializeRunnable(tsr, origin, principalInfo, aRv);
|
||||
runnable->Dispatch(Canceling, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
storageAccess = workerPrivate->StorageAccess();
|
||||
bc->mWorkerRef = workerRef;
|
||||
}
|
||||
if (principalInfo.type() != PrincipalInfo::TNullPrincipalInfo &&
|
||||
!workerPrivate->IsStorageAllowed()) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We want to allow opaque origins.
|
||||
if (storagePrincipalInfo.type() != PrincipalInfo::TNullPrincipalInfo &&
|
||||
(storageAccess == nsContentUtils::StorageAccess::eDeny ||
|
||||
(storageAccess == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
|
||||
!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()))) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return nullptr;
|
||||
bc->mWorkerRef = std::move(workerRef);
|
||||
}
|
||||
|
||||
// Register this component to PBackground.
|
||||
|
@ -316,7 +308,7 @@ already_AddRefed<BroadcastChannel> BroadcastChannel::Constructor(
|
|||
}
|
||||
|
||||
PBroadcastChannelChild* actor = actorChild->SendPBroadcastChannelConstructor(
|
||||
storagePrincipalInfo, origin, nsString(aChannel));
|
||||
principalInfo, origin, nsString(aChannel));
|
||||
|
||||
bc->mActor = static_cast<BroadcastChannelChild*>(actor);
|
||||
MOZ_ASSERT(bc->mActor);
|
||||
|
|
|
@ -567,23 +567,21 @@ OpenMode CacheStorage::GetOpenMode() const {
|
|||
bool CacheStorage::HasStorageAccess() const {
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||
|
||||
nsContentUtils::StorageAccess access;
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mGlobal);
|
||||
if (NS_WARN_IF(!window)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
access = nsContentUtils::StorageAllowedForWindow(window);
|
||||
} else {
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
access = workerPrivate->StorageAccess();
|
||||
nsContentUtils::StorageAccess access =
|
||||
nsContentUtils::StorageAllowedForWindow(window);
|
||||
return access > nsContentUtils::StorageAccess::ePrivateBrowsing;
|
||||
}
|
||||
|
||||
return access > nsContentUtils::StorageAccess::ePrivateBrowsing;
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
return workerPrivate->IsStorageAllowed();
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
|
|
|
@ -206,8 +206,7 @@ void ClientSource::WorkerExecutionReady(WorkerPrivate* aWorkerPrivate) {
|
|||
// execution ready. We can't reliably determine what our storage policy
|
||||
// is before execution ready, unfortunately.
|
||||
if (mController.isSome()) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate->StorageAccess() >
|
||||
nsContentUtils::StorageAccess::ePrivateBrowsing ||
|
||||
MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate->IsStorageAllowed() ||
|
||||
StringBeginsWith(aWorkerPrivate->ScriptURL(),
|
||||
NS_LITERAL_STRING("blob:")));
|
||||
}
|
||||
|
@ -381,8 +380,7 @@ void ClientSource::SetController(
|
|||
nsContentUtils::StorageAllowedForWindow(GetInnerWindow()) ==
|
||||
nsContentUtils::StorageAccess::eAllow);
|
||||
} else if (GetWorkerPrivate()) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(GetWorkerPrivate()->StorageAccess() >
|
||||
nsContentUtils::StorageAccess::ePrivateBrowsing ||
|
||||
MOZ_DIAGNOSTIC_ASSERT(GetWorkerPrivate()->IsStorageAllowed() ||
|
||||
StringBeginsWith(GetWorkerPrivate()->ScriptURL(),
|
||||
NS_LITERAL_STRING("blob:")));
|
||||
}
|
||||
|
@ -437,8 +435,7 @@ RefPtr<ClientOpPromise> ClientSource::Control(
|
|||
nsContentUtils::StorageAccess::eAllow;
|
||||
} else if (GetWorkerPrivate()) {
|
||||
// Local URL workers and workers with access to storage cna be controlled.
|
||||
controlAllowed = GetWorkerPrivate()->StorageAccess() >
|
||||
nsContentUtils::StorageAccess::ePrivateBrowsing ||
|
||||
controlAllowed = GetWorkerPrivate()->IsStorageAllowed() ||
|
||||
StringBeginsWith(GetWorkerPrivate()->ScriptURL(),
|
||||
NS_LITERAL_STRING("blob:"));
|
||||
}
|
||||
|
@ -651,7 +648,13 @@ nsresult ClientSource::SnapshotState(ClientState* aStateOut) {
|
|||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
*aStateOut = ClientState(ClientWorkerState(workerPrivate->StorageAccess()));
|
||||
// Workers only keep a boolean for storage access at the moment.
|
||||
// Map this back to eAllow or eDeny for now.
|
||||
nsContentUtils::StorageAccess storage =
|
||||
workerPrivate->IsStorageAllowed() ? nsContentUtils::StorageAccess::eAllow
|
||||
: nsContentUtils::StorageAccess::eDeny;
|
||||
|
||||
*aStateOut = ClientState(ClientWorkerState(storage));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -222,11 +222,10 @@ void nsHTMLDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) {
|
|||
}
|
||||
|
||||
void nsHTMLDocument::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal* aStoragePrincipal) {
|
||||
nsIPrincipal* aPrincipal) {
|
||||
mLoadFlags = nsIRequest::LOAD_NORMAL;
|
||||
|
||||
Document::ResetToURI(aURI, aLoadGroup, aPrincipal, aStoragePrincipal);
|
||||
Document::ResetToURI(aURI, aLoadGroup, aPrincipal);
|
||||
|
||||
mImages = nullptr;
|
||||
mApplets = nullptr;
|
||||
|
@ -1030,14 +1029,7 @@ void nsHTMLDocument::GetCookie(nsAString& aCookie, ErrorResult& rv) {
|
|||
return;
|
||||
}
|
||||
|
||||
nsContentUtils::StorageAccess storageAccess =
|
||||
nsContentUtils::StorageAllowedForDocument(this);
|
||||
if (storageAccess == nsContentUtils::StorageAccess::eDeny) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (storageAccess == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
|
||||
!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
|
||||
if (nsContentUtils::StorageDisabledByAntiTracking(this, nullptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1090,14 +1082,7 @@ void nsHTMLDocument::SetCookie(const nsAString& aCookie, ErrorResult& rv) {
|
|||
return;
|
||||
}
|
||||
|
||||
nsContentUtils::StorageAccess storageAccess =
|
||||
nsContentUtils::StorageAllowedForDocument(this);
|
||||
if (storageAccess == nsContentUtils::StorageAccess::eDeny) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (storageAccess == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
|
||||
!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
|
||||
if (nsContentUtils::StorageDisabledByAntiTracking(this, nullptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,8 +56,7 @@ class nsHTMLDocument : public mozilla::dom::Document, public nsIHTMLDocument {
|
|||
// Document
|
||||
virtual void Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) override;
|
||||
virtual void ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal* aStoragePrincipal) override;
|
||||
nsIPrincipal* aPrincipal) override;
|
||||
|
||||
virtual nsresult StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
|
||||
nsILoadGroup* aLoadGroup,
|
||||
|
|
|
@ -301,19 +301,14 @@ nsresult IDBFactory::AllowedForWindowInternal(nsPIDOMWindowInner* aWindow,
|
|||
// the factory callsite records whether the browser is in private browsing.
|
||||
// and thus we don't have to respect that setting here. IndexedDB has no
|
||||
// concept of session-local storage, and thus ignores it.
|
||||
if (access == nsContentUtils::StorageAccess::eDeny) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
if (access == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
|
||||
!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
|
||||
if (access <= nsContentUtils::StorageAccess::eDeny) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
|
||||
MOZ_ASSERT(sop);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = sop->GetEffectiveStoragePrincipal();
|
||||
nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
|
||||
if (NS_WARN_IF(!principal)) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
|
|
@ -1729,12 +1729,10 @@ nsresult ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
|
|||
}
|
||||
info.mLoadingPrincipal = info.mPrincipal;
|
||||
|
||||
// StoragePrincipal for ServiceWorkers is equal to mPrincipal because, at the
|
||||
// moment, ServiceWorkers are not exposed in partitioned contexts.
|
||||
info.mStoragePrincipal = info.mPrincipal;
|
||||
|
||||
info.mStorageAccess =
|
||||
nsContentUtils::StorageAccess access =
|
||||
nsContentUtils::StorageAllowedForServiceWorker(info.mPrincipal);
|
||||
info.mStorageAllowed =
|
||||
access > nsContentUtils::StorageAccess::ePrivateBrowsing;
|
||||
|
||||
info.mCookieSettings = mozilla::net::CookieSettings::Create();
|
||||
MOZ_ASSERT(info.mCookieSettings);
|
||||
|
@ -1755,8 +1753,7 @@ nsresult ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
|
|||
|
||||
WorkerPrivate::OverrideLoadInfoLoadGroup(info, info.mPrincipal);
|
||||
|
||||
rv = info.SetPrincipalsOnMainThread(info.mPrincipal, info.mStoragePrincipal,
|
||||
info.mLoadGroup);
|
||||
rv = info.SetPrincipalOnMainThread(info.mPrincipal, info.mLoadGroup);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
* https://wicg.github.io/feature-policy/#policy
|
||||
*/
|
||||
|
||||
interface Principal;
|
||||
interface WindowProxy;
|
||||
interface nsISupports;
|
||||
interface URI;
|
||||
|
@ -359,10 +358,6 @@ partial interface Document {
|
|||
[CEReactions, NewObject, Throws, Func="IsChromeOrXBL"]
|
||||
Element createXULElement(DOMString localName, optional (ElementCreationOptions or DOMString) options);
|
||||
|
||||
// The principal to use for the storage area of this document
|
||||
[ChromeOnly]
|
||||
readonly attribute Principal effectiveStoragePrincipal;
|
||||
|
||||
// Touch bits
|
||||
// XXXbz I can't find the sane spec for this stuff, so just cribbing
|
||||
// from our xpidl for now.
|
||||
|
|
|
@ -1188,7 +1188,7 @@ class ScriptLoaderRunnable final : public nsIRunnable, public nsINamed {
|
|||
// URL must exactly match the final worker script URL in order to
|
||||
// properly set the referrer header on fetch/xhr requests. If bug 1340694
|
||||
// is ever fixed this can be removed.
|
||||
rv = mWorkerPrivate->SetPrincipalsFromChannel(channel);
|
||||
rv = mWorkerPrivate->SetPrincipalFromChannel(channel);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp = mWorkerPrivate->GetCSP();
|
||||
|
@ -1296,11 +1296,8 @@ class ScriptLoaderRunnable final : public nsIRunnable, public nsINamed {
|
|||
// referrer logic depends on the WorkerPrivate principal having a URL
|
||||
// that matches the worker script URL. If bug 1340694 is ever fixed
|
||||
// this can be removed.
|
||||
// XXX: force the storagePrincipal to be equal to the response one. This
|
||||
// is OK for now because we don't want to expose storagePrincipal
|
||||
// functionality in ServiceWorkers yet.
|
||||
rv = mWorkerPrivate->SetPrincipalsOnMainThread(
|
||||
responsePrincipal, responsePrincipal, loadGroup);
|
||||
rv = mWorkerPrivate->SetPrincipalOnMainThread(responsePrincipal,
|
||||
loadGroup);
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
rv = mWorkerPrivate->SetCSPFromHeaderValues(aCSPHeaderValue,
|
||||
|
@ -1844,7 +1841,7 @@ class ChannelGetterRunnable final : public WorkerMainThreadRunnable {
|
|||
getter_AddRefs(channel));
|
||||
NS_ENSURE_SUCCESS(mResult, true);
|
||||
|
||||
mResult = mLoadInfo.SetPrincipalsFromChannel(channel);
|
||||
mResult = mLoadInfo.SetPrincipalFromChannel(channel);
|
||||
NS_ENSURE_SUCCESS(mResult, true);
|
||||
|
||||
mLoadInfo.mChannel = channel.forget();
|
||||
|
|
|
@ -87,19 +87,17 @@ WorkerLoadInfoData::WorkerLoadInfoData()
|
|||
mReportCSPViolations(false),
|
||||
mXHRParamsAllowed(false),
|
||||
mPrincipalIsSystem(false),
|
||||
mStorageAccess(nsContentUtils::StorageAccess::eDeny),
|
||||
mStorageAllowed(false),
|
||||
mFirstPartyStorageAccessGranted(false),
|
||||
mServiceWorkersTestingInWindow(false),
|
||||
mSecureContext(eNotSet) {}
|
||||
|
||||
nsresult WorkerLoadInfo::SetPrincipalsOnMainThread(
|
||||
nsIPrincipal* aPrincipal, nsIPrincipal* aStoragePrincipal,
|
||||
nsILoadGroup* aLoadGroup) {
|
||||
nsresult WorkerLoadInfo::SetPrincipalOnMainThread(nsIPrincipal* aPrincipal,
|
||||
nsILoadGroup* aLoadGroup) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(aLoadGroup, aPrincipal));
|
||||
|
||||
mPrincipal = aPrincipal;
|
||||
mStoragePrincipal = aStoragePrincipal;
|
||||
mPrincipalIsSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
|
||||
|
||||
nsresult rv = aPrincipal->GetCsp(getter_AddRefs(mCSP));
|
||||
|
@ -115,33 +113,23 @@ nsresult WorkerLoadInfo::SetPrincipalsOnMainThread(
|
|||
mLoadGroup = aLoadGroup;
|
||||
|
||||
mPrincipalInfo = new PrincipalInfo();
|
||||
mStoragePrincipalInfo = new PrincipalInfo();
|
||||
mOriginAttributes = nsContentUtils::GetOriginAttributes(aLoadGroup);
|
||||
|
||||
rv = PrincipalToPrincipalInfo(aPrincipal, mPrincipalInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aPrincipal->Equals(aStoragePrincipal)) {
|
||||
*mStoragePrincipalInfo = *mPrincipalInfo;
|
||||
} else {
|
||||
mStoragePrincipalInfo = new PrincipalInfo();
|
||||
rv = PrincipalToPrincipalInfo(aStoragePrincipal, mStoragePrincipalInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = nsContentUtils::GetUTFOrigin(aPrincipal, mOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult WorkerLoadInfo::GetPrincipalsAndLoadGroupFromChannel(
|
||||
nsresult WorkerLoadInfo::GetPrincipalAndLoadGroupFromChannel(
|
||||
nsIChannel* aChannel, nsIPrincipal** aPrincipalOut,
|
||||
nsIPrincipal** aStoragePrincipalOut, nsILoadGroup** aLoadGroupOut) {
|
||||
nsILoadGroup** aLoadGroupOut) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_DIAGNOSTIC_ASSERT(aChannel);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aPrincipalOut);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aStoragePrincipalOut);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aLoadGroupOut);
|
||||
|
||||
// Initial triggering principal should be set
|
||||
|
@ -151,10 +139,8 @@ nsresult WorkerLoadInfo::GetPrincipalsAndLoadGroupFromChannel(
|
|||
MOZ_DIAGNOSTIC_ASSERT(ssm);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> channelPrincipal;
|
||||
nsCOMPtr<nsIPrincipal> channelStoragePrincipal;
|
||||
nsresult rv = ssm->GetChannelResultPrincipals(
|
||||
aChannel, getter_AddRefs(channelPrincipal),
|
||||
getter_AddRefs(channelStoragePrincipal));
|
||||
nsresult rv = ssm->GetChannelResultPrincipal(
|
||||
aChannel, getter_AddRefs(channelPrincipal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Every time we call GetChannelResultPrincipal() it will return a different
|
||||
|
@ -168,7 +154,6 @@ nsresult WorkerLoadInfo::GetPrincipalsAndLoadGroupFromChannel(
|
|||
if (mPrincipal && mPrincipal->GetIsNullPrincipal() &&
|
||||
channelPrincipal->GetIsNullPrincipal()) {
|
||||
channelPrincipal = mPrincipal;
|
||||
channelStoragePrincipal = mPrincipal;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadGroup> channelLoadGroup;
|
||||
|
@ -201,7 +186,6 @@ nsresult WorkerLoadInfo::GetPrincipalsAndLoadGroupFromChannel(
|
|||
// Assign the system principal to the resource:// worker only if it
|
||||
// was loaded from code using the system principal.
|
||||
channelPrincipal = mLoadingPrincipal;
|
||||
channelStoragePrincipal = mLoadingPrincipal;
|
||||
} else {
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
|
@ -213,35 +197,30 @@ nsresult WorkerLoadInfo::GetPrincipalsAndLoadGroupFromChannel(
|
|||
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(channelLoadGroup, channelPrincipal));
|
||||
|
||||
channelPrincipal.forget(aPrincipalOut);
|
||||
channelStoragePrincipal.forget(aStoragePrincipalOut);
|
||||
channelLoadGroup.forget(aLoadGroupOut);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult WorkerLoadInfo::SetPrincipalsFromChannel(nsIChannel* aChannel) {
|
||||
nsresult WorkerLoadInfo::SetPrincipalFromChannel(nsIChannel* aChannel) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsIPrincipal> storagePrincipal;
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
nsresult rv = GetPrincipalsAndLoadGroupFromChannel(
|
||||
aChannel, getter_AddRefs(principal), getter_AddRefs(storagePrincipal),
|
||||
getter_AddRefs(loadGroup));
|
||||
nsresult rv = GetPrincipalAndLoadGroupFromChannel(
|
||||
aChannel, getter_AddRefs(principal), getter_AddRefs(loadGroup));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return SetPrincipalsOnMainThread(principal, storagePrincipal, loadGroup);
|
||||
return SetPrincipalOnMainThread(principal, loadGroup);
|
||||
}
|
||||
|
||||
bool WorkerLoadInfo::FinalChannelPrincipalIsValid(nsIChannel* aChannel) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsIPrincipal> storagePrincipal;
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
nsresult rv = GetPrincipalsAndLoadGroupFromChannel(
|
||||
aChannel, getter_AddRefs(principal), getter_AddRefs(storagePrincipal),
|
||||
getter_AddRefs(loadGroup));
|
||||
nsresult rv = GetPrincipalAndLoadGroupFromChannel(
|
||||
aChannel, getter_AddRefs(principal), getter_AddRefs(loadGroup));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
// Verify that the channel is still a null principal. We don't care
|
||||
|
@ -264,10 +243,7 @@ bool WorkerLoadInfo::FinalChannelPrincipalIsValid(nsIChannel* aChannel) {
|
|||
bool WorkerLoadInfo::PrincipalIsValid() const {
|
||||
return mPrincipal && mPrincipalInfo &&
|
||||
mPrincipalInfo->type() != PrincipalInfo::T__None &&
|
||||
mPrincipalInfo->type() <= PrincipalInfo::T__Last &&
|
||||
mStoragePrincipal && mStoragePrincipalInfo &&
|
||||
mStoragePrincipalInfo->type() != PrincipalInfo::T__None &&
|
||||
mStoragePrincipalInfo->type() <= PrincipalInfo::T__Last;
|
||||
mPrincipalInfo->type() <= PrincipalInfo::T__Last;
|
||||
}
|
||||
|
||||
bool WorkerLoadInfo::PrincipalURIMatchesScriptURL() {
|
||||
|
@ -336,7 +312,7 @@ bool WorkerLoadInfo::ProxyReleaseMainThreadObjects(
|
|||
|
||||
bool WorkerLoadInfo::ProxyReleaseMainThreadObjects(
|
||||
WorkerPrivate* aWorkerPrivate, nsCOMPtr<nsILoadGroup>& aLoadGroupToCancel) {
|
||||
static const uint32_t kDoomedCount = 11;
|
||||
static const uint32_t kDoomedCount = 10;
|
||||
nsTArray<nsCOMPtr<nsISupports>> doomed(kDoomedCount);
|
||||
|
||||
SwapToISupportsArray(mWindow, doomed);
|
||||
|
@ -344,7 +320,6 @@ bool WorkerLoadInfo::ProxyReleaseMainThreadObjects(
|
|||
SwapToISupportsArray(mBaseURI, doomed);
|
||||
SwapToISupportsArray(mResolvedScriptURI, doomed);
|
||||
SwapToISupportsArray(mPrincipal, doomed);
|
||||
SwapToISupportsArray(mStoragePrincipal, doomed);
|
||||
SwapToISupportsArray(mLoadingPrincipal, doomed);
|
||||
SwapToISupportsArray(mChannel, doomed);
|
||||
SwapToISupportsArray(mCSP, doomed);
|
||||
|
|
|
@ -50,7 +50,6 @@ struct WorkerLoadInfoData {
|
|||
// If we load a data: URL, mPrincipal will be a null principal.
|
||||
nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsCOMPtr<nsIPrincipal> mStoragePrincipal;
|
||||
|
||||
// Taken from the parent context.
|
||||
nsCOMPtr<nsICookieSettings> mCookieSettings;
|
||||
|
@ -92,7 +91,6 @@ struct WorkerLoadInfoData {
|
|||
RefPtr<InterfaceRequestor> mInterfaceRequestor;
|
||||
|
||||
nsAutoPtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
|
||||
nsAutoPtr<mozilla::ipc::PrincipalInfo> mStoragePrincipalInfo;
|
||||
nsCString mDomain;
|
||||
nsString mOrigin; // Derived from mPrincipal; can be used on worker thread.
|
||||
|
||||
|
@ -114,7 +112,7 @@ struct WorkerLoadInfoData {
|
|||
bool mReportCSPViolations;
|
||||
bool mXHRParamsAllowed;
|
||||
bool mPrincipalIsSystem;
|
||||
nsContentUtils::StorageAccess mStorageAccess;
|
||||
bool mStorageAllowed;
|
||||
bool mFirstPartyStorageAccessGranted;
|
||||
bool mServiceWorkersTestingInWindow;
|
||||
OriginAttributes mOriginAttributes;
|
||||
|
@ -138,15 +136,14 @@ struct WorkerLoadInfo : WorkerLoadInfoData {
|
|||
|
||||
WorkerLoadInfo& operator=(WorkerLoadInfo&& aOther) = default;
|
||||
|
||||
nsresult SetPrincipalsOnMainThread(nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal* aStoragePrincipal,
|
||||
nsILoadGroup* aLoadGroup);
|
||||
nsresult SetPrincipalOnMainThread(nsIPrincipal* aPrincipal,
|
||||
nsILoadGroup* aLoadGroup);
|
||||
|
||||
nsresult GetPrincipalsAndLoadGroupFromChannel(
|
||||
nsIChannel* aChannel, nsIPrincipal** aPrincipalOut,
|
||||
nsIPrincipal** aStoragePrincipalOut, nsILoadGroup** aLoadGroupOut);
|
||||
nsresult GetPrincipalAndLoadGroupFromChannel(nsIChannel* aChannel,
|
||||
nsIPrincipal** aPrincipalOut,
|
||||
nsILoadGroup** aLoadGroupOut);
|
||||
|
||||
nsresult SetPrincipalsFromChannel(nsIChannel* aChannel);
|
||||
nsresult SetPrincipalFromChannel(nsIChannel* aChannel);
|
||||
|
||||
bool FinalChannelPrincipalIsValid(nsIChannel* aChannel);
|
||||
|
||||
|
|
|
@ -1932,15 +1932,13 @@ void WorkerPrivate::SetBaseURI(nsIURI* aBaseURI) {
|
|||
nsContentUtils::GetUTFOrigin(aBaseURI, mLocationInfo.mOrigin);
|
||||
}
|
||||
|
||||
nsresult WorkerPrivate::SetPrincipalsOnMainThread(
|
||||
nsIPrincipal* aPrincipal, nsIPrincipal* aStoragePrincipal,
|
||||
nsILoadGroup* aLoadGroup) {
|
||||
return mLoadInfo.SetPrincipalsOnMainThread(aPrincipal, aStoragePrincipal,
|
||||
aLoadGroup);
|
||||
nsresult WorkerPrivate::SetPrincipalOnMainThread(nsIPrincipal* aPrincipal,
|
||||
nsILoadGroup* aLoadGroup) {
|
||||
return mLoadInfo.SetPrincipalOnMainThread(aPrincipal, aLoadGroup);
|
||||
}
|
||||
|
||||
nsresult WorkerPrivate::SetPrincipalsFromChannel(nsIChannel* aChannel) {
|
||||
return mLoadInfo.SetPrincipalsFromChannel(aChannel);
|
||||
nsresult WorkerPrivate::SetPrincipalFromChannel(nsIChannel* aChannel) {
|
||||
return mLoadInfo.SetPrincipalFromChannel(aChannel);
|
||||
}
|
||||
|
||||
bool WorkerPrivate::FinalChannelPrincipalIsValid(nsIChannel* aChannel) {
|
||||
|
@ -2357,7 +2355,7 @@ nsresult WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindowInner* aWindow,
|
|||
loadInfo.mDomain = aParent->Domain();
|
||||
loadInfo.mFromWindow = aParent->IsFromWindow();
|
||||
loadInfo.mWindowID = aParent->WindowID();
|
||||
loadInfo.mStorageAccess = aParent->StorageAccess();
|
||||
loadInfo.mStorageAllowed = aParent->IsStorageAllowed();
|
||||
loadInfo.mOriginAttributes = aParent->GetOriginAttributes();
|
||||
loadInfo.mServiceWorkersTestingInWindow =
|
||||
aParent->ServiceWorkersTestingInWindow();
|
||||
|
@ -2484,8 +2482,9 @@ nsresult WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindowInner* aWindow,
|
|||
|
||||
loadInfo.mFromWindow = true;
|
||||
loadInfo.mWindowID = globalWindow->WindowID();
|
||||
loadInfo.mStorageAccess =
|
||||
nsContentUtils::StorageAccess access =
|
||||
nsContentUtils::StorageAllowedForWindow(globalWindow);
|
||||
loadInfo.mStorageAllowed = access > nsContentUtils::StorageAccess::eDeny;
|
||||
loadInfo.mCookieSettings = document->CookieSettings();
|
||||
loadInfo.mOriginAttributes =
|
||||
nsContentUtils::GetOriginAttributes(document);
|
||||
|
@ -2531,7 +2530,7 @@ nsresult WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindowInner* aWindow,
|
|||
loadInfo.mXHRParamsAllowed = true;
|
||||
loadInfo.mFromWindow = false;
|
||||
loadInfo.mWindowID = UINT64_MAX;
|
||||
loadInfo.mStorageAccess = nsContentUtils::StorageAccess::eAllow;
|
||||
loadInfo.mStorageAllowed = true;
|
||||
loadInfo.mCookieSettings = mozilla::net::CookieSettings::Create();
|
||||
MOZ_ASSERT(loadInfo.mCookieSettings);
|
||||
|
||||
|
@ -2564,7 +2563,7 @@ nsresult WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindowInner* aWindow,
|
|||
getter_AddRefs(loadInfo.mResolvedScriptURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = loadInfo.SetPrincipalsFromChannel(loadInfo.mChannel);
|
||||
rv = loadInfo.SetPrincipalFromChannel(loadInfo.mChannel);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
@ -3360,11 +3359,6 @@ void WorkerPrivate::PropagateFirstPartyStorageAccessGrantedInternal() {
|
|||
|
||||
mLoadInfo.mFirstPartyStorageAccessGranted = true;
|
||||
|
||||
WorkerGlobalScope* globalScope = GlobalScope();
|
||||
if (globalScope) {
|
||||
globalScope->FirstPartyStorageAccessGranted();
|
||||
}
|
||||
|
||||
for (uint32_t index = 0; index < data->mChildWorkers.Length(); index++) {
|
||||
data->mChildWorkers[index]->PropagateFirstPartyStorageAccessGranted();
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "mozilla/CondVar.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/RelativeTimeline.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsTObserverArray.h"
|
||||
|
@ -662,11 +661,6 @@ class WorkerPrivate : public RelativeTimeline {
|
|||
return mLoadInfo.mPrincipal;
|
||||
}
|
||||
|
||||
nsIPrincipal* GetEffectiveStoragePrincipal() const {
|
||||
AssertIsOnMainThread();
|
||||
return mLoadInfo.mStoragePrincipal;
|
||||
}
|
||||
|
||||
nsIPrincipal* GetLoadingPrincipal() const {
|
||||
AssertIsOnMainThread();
|
||||
return mLoadInfo.mLoadingPrincipal;
|
||||
|
@ -685,10 +679,6 @@ class WorkerPrivate : public RelativeTimeline {
|
|||
return *mLoadInfo.mPrincipalInfo;
|
||||
}
|
||||
|
||||
const mozilla::ipc::PrincipalInfo& GetEffectiveStoragePrincipalInfo() const {
|
||||
return *mLoadInfo.mStoragePrincipalInfo;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIChannel> ForgetWorkerChannel() {
|
||||
AssertIsOnMainThread();
|
||||
return mLoadInfo.mChannel.forget();
|
||||
|
@ -738,13 +728,10 @@ class WorkerPrivate : public RelativeTimeline {
|
|||
mLoadInfo.mXHRParamsAllowed = aAllowed;
|
||||
}
|
||||
|
||||
nsContentUtils::StorageAccess StorageAccess() const {
|
||||
bool IsStorageAllowed() const {
|
||||
AssertIsOnWorkerThread();
|
||||
if (mLoadInfo.mFirstPartyStorageAccessGranted) {
|
||||
return nsContentUtils::StorageAccess::eAllow;
|
||||
}
|
||||
|
||||
return mLoadInfo.mStorageAccess;
|
||||
return mLoadInfo.mStorageAllowed ||
|
||||
mLoadInfo.mFirstPartyStorageAccessGranted;
|
||||
}
|
||||
|
||||
nsICookieSettings* CookieSettings() const {
|
||||
|
@ -797,11 +784,10 @@ class WorkerPrivate : public RelativeTimeline {
|
|||
|
||||
void CycleCollect(bool aDummy);
|
||||
|
||||
nsresult SetPrincipalsOnMainThread(nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal* aStoragePrincipal,
|
||||
nsILoadGroup* aLoadGroup);
|
||||
nsresult SetPrincipalOnMainThread(nsIPrincipal* aPrincipal,
|
||||
nsILoadGroup* aLoadGroup);
|
||||
|
||||
nsresult SetPrincipalsFromChannel(nsIChannel* aChannel);
|
||||
nsresult SetPrincipalFromChannel(nsIChannel* aChannel);
|
||||
|
||||
bool FinalChannelPrincipalIsValid(nsIChannel* aChannel);
|
||||
|
||||
|
|
|
@ -393,23 +393,13 @@ already_AddRefed<IDBFactory> WorkerGlobalScope::GetIndexedDB(
|
|||
RefPtr<IDBFactory> indexedDB = mIndexedDB;
|
||||
|
||||
if (!indexedDB) {
|
||||
nsContentUtils::StorageAccess access = mWorkerPrivate->StorageAccess();
|
||||
|
||||
if (access == nsContentUtils::StorageAccess::eDeny) {
|
||||
if (!mWorkerPrivate->IsStorageAllowed()) {
|
||||
NS_WARNING("IndexedDB is not allowed in this worker!");
|
||||
aErrorResult = NS_ERROR_DOM_SECURITY_ERR;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (access == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
|
||||
!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
|
||||
NS_WARNING("IndexedDB is not allowed in this worker!");
|
||||
aErrorResult = NS_ERROR_DOM_SECURITY_ERR;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const PrincipalInfo& principalInfo =
|
||||
mWorkerPrivate->GetEffectiveStoragePrincipalInfo();
|
||||
const PrincipalInfo& principalInfo = mWorkerPrivate->GetPrincipalInfo();
|
||||
|
||||
nsresult rv = IDBFactory::CreateForWorker(this, principalInfo,
|
||||
mWorkerPrivate->WindowID(),
|
||||
|
@ -497,10 +487,6 @@ WorkerGlobalScope::GetOrCreateServiceWorkerRegistration(
|
|||
return ref.forget();
|
||||
}
|
||||
|
||||
void WorkerGlobalScope::FirstPartyStorageAccessGranted() {
|
||||
mIndexedDB = nullptr;
|
||||
}
|
||||
|
||||
DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(
|
||||
WorkerPrivate* aWorkerPrivate, const nsString& aName)
|
||||
: WorkerGlobalScope(aWorkerPrivate), mName(aName) {}
|
||||
|
|
|
@ -190,8 +190,6 @@ class WorkerGlobalScope : public DOMEventTargetHelper,
|
|||
RefPtr<mozilla::dom::ServiceWorkerRegistration>
|
||||
GetOrCreateServiceWorkerRegistration(
|
||||
const ServiceWorkerRegistrationDescriptor& aDescriptor) override;
|
||||
|
||||
void FirstPartyStorageAccessGranted();
|
||||
};
|
||||
|
||||
class DedicatedWorkerGlobalScope final : public WorkerGlobalScope {
|
||||
|
|
|
@ -262,31 +262,16 @@ nsresult RemoteWorkerChild::ExecWorkerOnMainThread(
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> storagePrincipal =
|
||||
PrincipalInfoToPrincipal(aData.storagePrincipalInfo(), &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = PopulatePrincipalContentSecurityPolicy(
|
||||
storagePrincipal, aData.storagePrincipalCsp(),
|
||||
aData.storagePrincipalPreloadCsp());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
WorkerLoadInfo info;
|
||||
info.mBaseURI = DeserializeURI(aData.baseScriptURL());
|
||||
info.mResolvedScriptURI = DeserializeURI(aData.resolvedScriptURL());
|
||||
|
||||
info.mPrincipalInfo = new PrincipalInfo(aData.principalInfo());
|
||||
info.mStoragePrincipalInfo = new PrincipalInfo(aData.storagePrincipalInfo());
|
||||
|
||||
info.mDomain = aData.domain();
|
||||
info.mPrincipal = principal;
|
||||
info.mStoragePrincipal = storagePrincipal;
|
||||
info.mLoadingPrincipal = loadingPrincipal;
|
||||
info.mStorageAccess = aData.storageAccess();
|
||||
info.mStorageAllowed = aData.isStorageAccessAllowed();
|
||||
info.mOriginAttributes =
|
||||
BasePrincipal::Cast(principal)->OriginAttributesRef();
|
||||
info.mCookieSettings = net::CookieSettings::Create();
|
||||
|
@ -305,8 +290,7 @@ nsresult RemoteWorkerChild::ExecWorkerOnMainThread(
|
|||
new SharedWorkerInterfaceRequestor();
|
||||
info.mInterfaceRequestor->SetOuterRequestor(requestor);
|
||||
|
||||
rv = info.SetPrincipalsOnMainThread(info.mPrincipal, info.mStoragePrincipal,
|
||||
info.mLoadGroup);
|
||||
rv = info.SetPrincipalOnMainThread(info.mPrincipal, info.mLoadGroup);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ include PBackgroundSharedTypes;
|
|||
include URIParams;
|
||||
|
||||
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
|
||||
using nsContentUtils::StorageAccess from "mozilla/dom/ClientIPCUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -38,17 +37,13 @@ struct RemoteWorkerData
|
|||
ContentSecurityPolicy[] principalCsp;
|
||||
ContentSecurityPolicy[] principalPreloadCsp;
|
||||
|
||||
PrincipalInfo storagePrincipalInfo;
|
||||
ContentSecurityPolicy[] storagePrincipalCsp;
|
||||
ContentSecurityPolicy[] storagePrincipalPreloadCsp;
|
||||
|
||||
nsCString domain;
|
||||
|
||||
bool isSecureContext;
|
||||
|
||||
IPCClientInfo? clientInfo;
|
||||
|
||||
StorageAccess storageAccess;
|
||||
bool isStorageAccessAllowed;
|
||||
|
||||
bool isSharedWorker;
|
||||
};
|
||||
|
|
|
@ -102,14 +102,14 @@ already_AddRefed<SharedWorker> SharedWorker::Constructor(
|
|||
do_QueryInterface(aGlobal.GetAsSupports());
|
||||
MOZ_ASSERT(window);
|
||||
|
||||
// If the window is blocked from accessing storage, do not allow it
|
||||
// to connect to a SharedWorker. This would potentially allow it
|
||||
// to communicate with other windows that do have storage access.
|
||||
// Allow private browsing, however, as we handle that isolation
|
||||
// via the principal.
|
||||
auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
|
||||
if (storageAllowed == nsContentUtils::StorageAccess::eDeny) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (storageAllowed == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
|
||||
!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
|
||||
if (storageAllowed != nsContentUtils::StorageAccess::eAllow &&
|
||||
storageAllowed != nsContentUtils::StorageAccess::ePrivateBrowsing) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -176,57 +176,6 @@ already_AddRefed<SharedWorker> SharedWorker::Constructor(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Here, the StoragePrincipal is always equal to the SharedWorker's principal
|
||||
// because the channel is not opened yet, and, because of this, it's not
|
||||
// classified. We need to force the correct originAttributes.
|
||||
if (storageAllowed == nsContentUtils::StorageAccess::ePartitionedOrDeny) {
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(window);
|
||||
if (!sop) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIPrincipal* windowPrincipal = sop->GetPrincipal();
|
||||
if (!windowPrincipal) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIPrincipal* windowStoragePrincipal = sop->GetEffectiveStoragePrincipal();
|
||||
if (!windowStoragePrincipal) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!windowPrincipal->Equals(windowStoragePrincipal)) {
|
||||
loadInfo.mStoragePrincipal =
|
||||
BasePrincipal::Cast(loadInfo.mPrincipal)
|
||||
->CloneForcingOriginAttributes(
|
||||
BasePrincipal::Cast(windowStoragePrincipal)
|
||||
->OriginAttributesRef());
|
||||
}
|
||||
}
|
||||
|
||||
PrincipalInfo storagePrincipalInfo;
|
||||
if (loadInfo.mPrincipal->Equals(loadInfo.mStoragePrincipal)) {
|
||||
storagePrincipalInfo = principalInfo;
|
||||
} else {
|
||||
aRv = PrincipalToPrincipalInfo(loadInfo.mStoragePrincipal,
|
||||
&storagePrincipalInfo);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsTArray<ContentSecurityPolicy> storagePrincipalCSP;
|
||||
nsTArray<ContentSecurityPolicy> storagePrincipalPreloadCSP;
|
||||
aRv = PopulateContentSecurityPolicyArray(loadInfo.mStoragePrincipal,
|
||||
storagePrincipalCSP,
|
||||
storagePrincipalPreloadCSP);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We don't actually care about this MessageChannel, but we use it to 'steal'
|
||||
// its 2 connected ports.
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(window);
|
||||
|
@ -255,12 +204,15 @@ already_AddRefed<SharedWorker> SharedWorker::Constructor(
|
|||
ipcClientInfo.emplace(clientInfo.value().ToIPC());
|
||||
}
|
||||
|
||||
bool storageAccessAllowed =
|
||||
storageAllowed > nsContentUtils::StorageAccess::eDeny;
|
||||
|
||||
RemoteWorkerData remoteWorkerData(
|
||||
nsString(aScriptURL), baseURL, resolvedScriptURL, name,
|
||||
loadingPrincipalInfo, loadingPrincipalCSP, loadingPrincipalPreloadCSP,
|
||||
principalInfo, principalCSP, principalPreloadCSP, storagePrincipalInfo,
|
||||
storagePrincipalCSP, storagePrincipalPreloadCSP, loadInfo.mDomain,
|
||||
isSecureContext, ipcClientInfo, storageAllowed, true /* sharedWorker */);
|
||||
principalInfo, principalCSP, principalPreloadCSP, loadInfo.mDomain,
|
||||
isSecureContext, ipcClientInfo, storageAccessAllowed,
|
||||
true /* sharedWorker */);
|
||||
|
||||
PSharedWorkerChild* pActor = actorChild->SendPSharedWorkerConstructor(
|
||||
remoteWorkerData, loadInfo.mWindowID, portIdentifier);
|
||||
|
|
|
@ -22,13 +22,11 @@ namespace dom {
|
|||
// static
|
||||
already_AddRefed<SharedWorkerManagerHolder> SharedWorkerManager::Create(
|
||||
SharedWorkerService* aService, nsIEventTarget* aPBackgroundEventTarget,
|
||||
const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal,
|
||||
const OriginAttributes& aStoragePrincipalAttrs) {
|
||||
const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<SharedWorkerManager> manager =
|
||||
new SharedWorkerManager(aPBackgroundEventTarget, aData, aLoadingPrincipal,
|
||||
aStoragePrincipalAttrs);
|
||||
RefPtr<SharedWorkerManager> manager = new SharedWorkerManager(
|
||||
aPBackgroundEventTarget, aData, aLoadingPrincipal);
|
||||
|
||||
RefPtr<SharedWorkerManagerHolder> holder =
|
||||
new SharedWorkerManagerHolder(manager, aService);
|
||||
|
@ -37,12 +35,10 @@ already_AddRefed<SharedWorkerManagerHolder> SharedWorkerManager::Create(
|
|||
|
||||
SharedWorkerManager::SharedWorkerManager(
|
||||
nsIEventTarget* aPBackgroundEventTarget, const RemoteWorkerData& aData,
|
||||
nsIPrincipal* aLoadingPrincipal,
|
||||
const OriginAttributes& aStoragePrincipalAttrs)
|
||||
nsIPrincipal* aLoadingPrincipal)
|
||||
: mPBackgroundEventTarget(aPBackgroundEventTarget),
|
||||
mLoadingPrincipal(aLoadingPrincipal),
|
||||
mDomain(aData.domain()),
|
||||
mStoragePrincipalAttrs(aStoragePrincipalAttrs),
|
||||
mResolvedScriptURL(DeserializeURI(aData.resolvedScriptURL())),
|
||||
mName(aData.name()),
|
||||
mIsSecureContext(aData.isSecureContext()),
|
||||
|
@ -84,10 +80,11 @@ bool SharedWorkerManager::MaybeCreateRemoteWorker(
|
|||
}
|
||||
|
||||
already_AddRefed<SharedWorkerManagerHolder>
|
||||
SharedWorkerManager::MatchOnMainThread(
|
||||
SharedWorkerService* aService, const nsACString& aDomain,
|
||||
nsIURI* aScriptURL, const nsAString& aName, nsIPrincipal* aLoadingPrincipal,
|
||||
const OriginAttributes& aStoragePrincipalAttrs) {
|
||||
SharedWorkerManager::MatchOnMainThread(SharedWorkerService* aService,
|
||||
const nsACString& aDomain,
|
||||
nsIURI* aScriptURL,
|
||||
const nsAString& aName,
|
||||
nsIPrincipal* aLoadingPrincipal) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
bool urlEquals;
|
||||
|
@ -99,8 +96,7 @@ SharedWorkerManager::MatchOnMainThread(
|
|||
// We want to be sure that the window's principal subsumes the
|
||||
// SharedWorker's loading principal and vice versa.
|
||||
mLoadingPrincipal->Subsumes(aLoadingPrincipal) &&
|
||||
aLoadingPrincipal->Subsumes(mLoadingPrincipal) &&
|
||||
mStoragePrincipalAttrs == aStoragePrincipalAttrs;
|
||||
aLoadingPrincipal->Subsumes(mLoadingPrincipal);
|
||||
if (!match) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -67,16 +67,14 @@ class SharedWorkerManager final : public RemoteWorkerObserver {
|
|||
|
||||
static already_AddRefed<SharedWorkerManagerHolder> Create(
|
||||
SharedWorkerService* aService, nsIEventTarget* aPBackgroundEventTarget,
|
||||
const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal,
|
||||
const OriginAttributes& aStoragePrincipalAttrs);
|
||||
const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal);
|
||||
|
||||
// Returns a holder if this manager matches. The holder blocks the shutdown of
|
||||
// the manager.
|
||||
already_AddRefed<SharedWorkerManagerHolder> MatchOnMainThread(
|
||||
SharedWorkerService* aService, const nsACString& aDomain,
|
||||
nsIURI* aScriptURL, const nsAString& aName,
|
||||
nsIPrincipal* aLoadingPrincipal,
|
||||
const OriginAttributes& aStoragePrincipalAttrs);
|
||||
nsIPrincipal* aLoadingPrincipal);
|
||||
|
||||
// RemoteWorkerObserver
|
||||
|
||||
|
@ -116,8 +114,7 @@ class SharedWorkerManager final : public RemoteWorkerObserver {
|
|||
private:
|
||||
SharedWorkerManager(nsIEventTarget* aPBackgroundEventTarget,
|
||||
const RemoteWorkerData& aData,
|
||||
nsIPrincipal* aLoadingPrincipal,
|
||||
const OriginAttributes& aStoragePrincipalAttrs);
|
||||
nsIPrincipal* aLoadingPrincipal);
|
||||
|
||||
~SharedWorkerManager();
|
||||
|
||||
|
@ -125,7 +122,6 @@ class SharedWorkerManager final : public RemoteWorkerObserver {
|
|||
|
||||
nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
|
||||
nsCString mDomain;
|
||||
OriginAttributes mStoragePrincipalAttrs;
|
||||
nsCOMPtr<nsIURI> mResolvedScriptURL;
|
||||
nsString mName;
|
||||
bool mIsSecureContext;
|
||||
|
|
|
@ -219,9 +219,16 @@ void SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(
|
|||
MOZ_ASSERT(aActor);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
nsCOMPtr<nsIPrincipal> storagePrincipal =
|
||||
PrincipalInfoToPrincipal(aData.storagePrincipalInfo(), &rv);
|
||||
if (NS_WARN_IF(!storagePrincipal)) {
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
PrincipalInfoToPrincipal(aData.principalInfo(), &rv);
|
||||
if (NS_WARN_IF(!principal)) {
|
||||
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
|
||||
return;
|
||||
}
|
||||
|
||||
rv = PopulatePrincipalContentSecurityPolicy(principal, aData.principalCsp(),
|
||||
aData.principalPreloadCsp());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
|
||||
return;
|
||||
}
|
||||
|
@ -248,8 +255,8 @@ void SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(
|
|||
DeserializeURI(aData.resolvedScriptURL());
|
||||
for (SharedWorkerManager* workerManager : mWorkerManagers) {
|
||||
managerHolder = workerManager->MatchOnMainThread(
|
||||
this, aData.domain(), resolvedScriptURL, aData.name(), loadingPrincipal,
|
||||
BasePrincipal::Cast(storagePrincipal)->OriginAttributesRef());
|
||||
this, aData.domain(), resolvedScriptURL, aData.name(),
|
||||
loadingPrincipal);
|
||||
if (managerHolder) {
|
||||
break;
|
||||
}
|
||||
|
@ -257,9 +264,8 @@ void SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(
|
|||
|
||||
// Let's create a new one.
|
||||
if (!managerHolder) {
|
||||
managerHolder = SharedWorkerManager::Create(
|
||||
this, aBackgroundEventTarget, aData, loadingPrincipal,
|
||||
BasePrincipal::Cast(storagePrincipal)->OriginAttributesRef());
|
||||
managerHolder = SharedWorkerManager::Create(this, aBackgroundEventTarget,
|
||||
aData, loadingPrincipal);
|
||||
|
||||
mWorkerManagers.AppendElement(managerHolder->Manager());
|
||||
} else {
|
||||
|
|
|
@ -129,7 +129,7 @@ nsresult NS_NewDOMDocument(Document** aInstancePtrResult,
|
|||
d->SetLoadedAsData(aLoadedAsData);
|
||||
d->SetDocumentURI(aDocumentURI);
|
||||
// Must set the principal first, since SetBaseURI checks it.
|
||||
d->SetPrincipals(aPrincipal, aPrincipal);
|
||||
d->SetPrincipal(aPrincipal);
|
||||
d->SetBaseURI(aBaseURI);
|
||||
|
||||
// We need to set the script handling object after we set the principal such
|
||||
|
@ -252,15 +252,14 @@ void XMLDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) {
|
|||
}
|
||||
|
||||
void XMLDocument::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal* aStoragePrincipal) {
|
||||
nsIPrincipal* aPrincipal) {
|
||||
if (mChannelIsPending) {
|
||||
StopDocumentLoad();
|
||||
mChannel->Cancel(NS_BINDING_ABORTED);
|
||||
mChannelIsPending = false;
|
||||
}
|
||||
|
||||
Document::ResetToURI(aURI, aLoadGroup, aPrincipal, aStoragePrincipal);
|
||||
Document::ResetToURI(aURI, aLoadGroup, aPrincipal);
|
||||
}
|
||||
|
||||
bool XMLDocument::Load(const nsAString& aUrl, CallerType aCallerType,
|
||||
|
@ -275,7 +274,6 @@ bool XMLDocument::Load(const nsAString& aUrl, CallerType aCallerType,
|
|||
|
||||
nsCOMPtr<Document> callingDoc = GetEntryDocument();
|
||||
nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
|
||||
nsCOMPtr<nsIPrincipal> storagePrincipal = EffectiveStoragePrincipal();
|
||||
|
||||
// The callingDoc's Principal and doc's Principal should be the same
|
||||
if (callingDoc && (callingDoc->NodePrincipal() != principal)) {
|
||||
|
@ -372,7 +370,7 @@ bool XMLDocument::Load(const nsAString& aUrl, CallerType aCallerType,
|
|||
loadGroup = callingDoc->GetDocumentLoadGroup();
|
||||
}
|
||||
|
||||
ResetToURI(uri, loadGroup, principal, storagePrincipal);
|
||||
ResetToURI(uri, loadGroup, principal);
|
||||
|
||||
mListenerManager = elm;
|
||||
|
||||
|
|
|
@ -26,8 +26,7 @@ class XMLDocument : public Document {
|
|||
|
||||
virtual void Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) override;
|
||||
virtual void ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal* aStoragePrincipal) override;
|
||||
nsIPrincipal* aPrincipal) override;
|
||||
|
||||
virtual void SetSuppressParserErrorElement(bool aSuppress) override;
|
||||
virtual bool SuppressParserErrorElement() override;
|
||||
|
|
|
@ -46,7 +46,6 @@ void URIUtils::resolveHref(const nsAString& href, const nsAString& base,
|
|||
void URIUtils::ResetWithSource(Document* aNewDoc, nsINode* aSourceNode) {
|
||||
nsCOMPtr<Document> sourceDoc = aSourceNode->OwnerDoc();
|
||||
nsIPrincipal* sourcePrincipal = sourceDoc->NodePrincipal();
|
||||
nsIPrincipal* sourceStoragePrincipal = sourceDoc->EffectiveStoragePrincipal();
|
||||
|
||||
// Copy the channel and loadgroup from the source document.
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = sourceDoc->GetDocumentLoadGroup();
|
||||
|
@ -67,7 +66,7 @@ void URIUtils::ResetWithSource(Document* aNewDoc, nsINode* aSourceNode) {
|
|||
}
|
||||
|
||||
aNewDoc->Reset(channel, loadGroup);
|
||||
aNewDoc->SetPrincipals(sourcePrincipal, sourceStoragePrincipal);
|
||||
aNewDoc->SetPrincipal(sourcePrincipal);
|
||||
aNewDoc->SetBaseURI(sourceDoc->GetDocBaseURI());
|
||||
|
||||
// Copy charset
|
||||
|
|
|
@ -193,8 +193,7 @@ void XULDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) {
|
|||
}
|
||||
|
||||
void XULDocument::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal* aStoragePrincipal) {
|
||||
nsIPrincipal* aPrincipal) {
|
||||
MOZ_ASSERT_UNREACHABLE("ResetToURI");
|
||||
}
|
||||
|
||||
|
@ -243,21 +242,10 @@ nsresult XULDocument::StartDocumentLoad(const char* aCommand,
|
|||
|
||||
// Get the document's principal
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsIPrincipal> storagePrincipal;
|
||||
rv = nsContentUtils::GetSecurityManager()->GetChannelResultPrincipals(
|
||||
mChannel, getter_AddRefs(principal), getter_AddRefs(storagePrincipal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool equal = principal->Equals(storagePrincipal);
|
||||
|
||||
nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
|
||||
mChannel, getter_AddRefs(principal));
|
||||
principal = MaybeDowngradePrincipal(principal);
|
||||
if (equal) {
|
||||
storagePrincipal = principal;
|
||||
} else {
|
||||
storagePrincipal = MaybeDowngradePrincipal(storagePrincipal);
|
||||
}
|
||||
|
||||
SetPrincipals(principal, storagePrincipal);
|
||||
SetPrincipal(principal);
|
||||
|
||||
ResetStylesheetsToURI(mDocumentURI);
|
||||
|
||||
|
|
|
@ -59,8 +59,7 @@ class XULDocument final : public XMLDocument {
|
|||
// Document interface
|
||||
virtual void Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) override;
|
||||
virtual void ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal* aStoragePrincipal) override;
|
||||
nsIPrincipal* aPrincipal) override;
|
||||
|
||||
virtual nsresult StartDocumentLoad(const char* aCommand, nsIChannel* channel,
|
||||
nsILoadGroup* aLoadGroup,
|
||||
|
|
|
@ -29,10 +29,6 @@ class BackstagePass : public nsIGlobalObject,
|
|||
|
||||
virtual nsIPrincipal* GetPrincipal() override { return mPrincipal; }
|
||||
|
||||
virtual nsIPrincipal* GetEffectiveStoragePrincipal() override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual JSObject* GetGlobalJSObject() override;
|
||||
|
||||
void ForgetGlobalObject() { mWrapper = nullptr; }
|
||||
|
|
|
@ -45,8 +45,6 @@ class SandboxPrivate : public nsIGlobalObject,
|
|||
|
||||
nsIPrincipal* GetPrincipal() override { return mPrincipal; }
|
||||
|
||||
nsIPrincipal* GetEffectiveStoragePrincipal() override { return nullptr; }
|
||||
|
||||
JSObject* GetGlobalJSObject() override { return GetWrapper(); }
|
||||
|
||||
void ForgetGlobalObject(JSObject* obj) { ClearWrapper(obj); }
|
||||
|
|
|
@ -277,7 +277,7 @@ already_AddRefed<Document> nsContentDLF::CreateBlankDocument(
|
|||
if (!uri) {
|
||||
return nullptr;
|
||||
}
|
||||
blankDoc->ResetToURI(uri, aLoadGroup, aPrincipal, aPrincipal);
|
||||
blankDoc->ResetToURI(uri, aLoadGroup, aPrincipal);
|
||||
blankDoc->SetContainer(aContainer);
|
||||
|
||||
// add some simple content structure
|
||||
|
|
|
@ -2233,12 +2233,6 @@ VARCACHE_PREF(
|
|||
RelaxedAtomicBool, false
|
||||
)
|
||||
|
||||
VARCACHE_PREF(
|
||||
"privacy.storagePrincipal.enabledForTrackers",
|
||||
privacy_storagePrincipal_enabledForTrackers,
|
||||
RelaxedAtomicBool, false
|
||||
)
|
||||
|
||||
// Password protection
|
||||
VARCACHE_PREF(
|
||||
"browser.safebrowsing.passwords.enabled",
|
||||
|
|
|
@ -189,12 +189,6 @@ LoadInfo::LoadInfo(
|
|||
!nsContentUtils::IsInPrivateBrowsing(doc))) {
|
||||
mTopLevelStorageAreaPrincipal = innerWindow->GetPrincipal();
|
||||
}
|
||||
|
||||
// If this is the first level iframe, innerWindow is our top-level
|
||||
// principal.
|
||||
if (!mTopLevelPrincipal) {
|
||||
mTopLevelPrincipal = innerWindow->GetPrincipal();
|
||||
}
|
||||
}
|
||||
|
||||
mDocumentHasLoaded = innerWindow->IsDocumentLoaded();
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/StoragePrincipalHelper.h"
|
||||
#include "mozilla/TaskQueue.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsCategoryCache.h"
|
||||
|
@ -1852,14 +1851,13 @@ nsresult NS_LoadPersistentPropertiesFromURISpec(
|
|||
|
||||
bool NS_UsePrivateBrowsing(nsIChannel *channel) {
|
||||
OriginAttributes attrs;
|
||||
bool result = NS_GetOriginAttributes(channel, attrs, false);
|
||||
bool result = NS_GetOriginAttributes(channel, attrs);
|
||||
NS_ENSURE_TRUE(result, result);
|
||||
return attrs.mPrivateBrowsingId > 0;
|
||||
}
|
||||
|
||||
bool NS_GetOriginAttributes(nsIChannel *aChannel,
|
||||
mozilla::OriginAttributes &aAttributes,
|
||||
bool aUsingStoragePrincipal) {
|
||||
mozilla::OriginAttributes &aAttributes) {
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
||||
loadInfo->GetOriginAttributes(&aAttributes);
|
||||
|
||||
|
@ -1875,10 +1873,6 @@ bool NS_GetOriginAttributes(nsIChannel *aChannel,
|
|||
isPrivate = loadContext && loadContext->UsePrivateBrowsing();
|
||||
}
|
||||
aAttributes.SyncAttributesWithPrivateBrowsing(isPrivate);
|
||||
|
||||
if (aUsingStoragePrincipal) {
|
||||
StoragePrincipalHelper::PrepareOriginAttributes(aChannel, aAttributes);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -610,12 +610,9 @@ bool NS_UsePrivateBrowsing(nsIChannel *channel);
|
|||
|
||||
/**
|
||||
* Extract the OriginAttributes from the channel's triggering principal.
|
||||
* If aUsingStoragePrincipal is set to true, the originAttributes could have
|
||||
* first-party isolation domain set to the top-level URI.
|
||||
*/
|
||||
bool NS_GetOriginAttributes(nsIChannel *aChannel,
|
||||
mozilla::OriginAttributes &aAttributes,
|
||||
bool aUsingStoragePrincipal = false);
|
||||
mozilla::OriginAttributes &aAttributes);
|
||||
|
||||
/**
|
||||
* Returns true if the channel has visited any cross-origin URLs on any
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "mozilla/net/NeckoChild.h"
|
||||
#include "mozilla/SystemGroup.h"
|
||||
#include "mozilla/StoragePrincipalHelper.h"
|
||||
#include "nsCookie.h"
|
||||
#include "nsCookieService.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
@ -176,7 +175,6 @@ void CookieServiceChild::TrackCookieLoad(nsIChannel *aChannel) {
|
|||
}
|
||||
}
|
||||
mozilla::OriginAttributes attrs = loadInfo->GetOriginAttributes();
|
||||
StoragePrincipalHelper::PrepareOriginAttributes(aChannel, attrs);
|
||||
URIParams uriParams;
|
||||
SerializeURI(uri, uriParams);
|
||||
bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
|
||||
|
@ -296,7 +294,6 @@ void CookieServiceChild::GetCookieStringFromCookieHashTable(
|
|||
if (aChannel) {
|
||||
loadInfo = aChannel->LoadInfo();
|
||||
attrs = loadInfo->GetOriginAttributes();
|
||||
StoragePrincipalHelper::PrepareOriginAttributes(aChannel, attrs);
|
||||
}
|
||||
|
||||
nsCookieService::GetBaseDomain(TLDService, aHostURI, baseDomain,
|
||||
|
@ -565,7 +562,6 @@ nsresult CookieServiceChild::SetCookieStringInternal(nsIURI *aHostURI,
|
|||
|
||||
MOZ_ASSERT(loadInfo);
|
||||
attrs = loadInfo->GetOriginAttributes();
|
||||
StoragePrincipalHelper::PrepareOriginAttributes(aChannel, attrs);
|
||||
} else {
|
||||
SerializeURI(nullptr, channelURIParams);
|
||||
}
|
||||
|
@ -577,7 +573,7 @@ nsresult CookieServiceChild::SetCookieStringInternal(nsIURI *aHostURI,
|
|||
if (mIPCOpen) {
|
||||
SendSetCookieString(hostURIParams, channelURIParams, optionalLoadInfoArgs,
|
||||
isForeign, isTrackingResource,
|
||||
firstPartyStorageAccessGranted, attrs, cookieString,
|
||||
firstPartyStorageAccessGranted, cookieString,
|
||||
stringServerTime, aFromHttp);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "mozilla/StoragePrincipalHelper.h"
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsCookieService.h"
|
||||
#include "nsIChannel.h"
|
||||
|
@ -127,8 +126,6 @@ void CookieServiceParent::TrackCookieLoad(nsIChannel *aChannel) {
|
|||
bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
|
||||
bool aIsSameSiteForeign = NS_IsSameSiteForeign(aChannel, uri);
|
||||
|
||||
StoragePrincipalHelper::PrepareOriginAttributes(aChannel, attrs);
|
||||
|
||||
// Send matching cookies to Child.
|
||||
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil;
|
||||
thirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
|
||||
|
@ -210,9 +207,8 @@ mozilla::ipc::IPCResult CookieServiceParent::RecvSetCookieString(
|
|||
const URIParams &aHost, const Maybe<URIParams> &aChannelURI,
|
||||
const Maybe<LoadInfoArgs> &aLoadInfoArgs, const bool &aIsForeign,
|
||||
const bool &aIsTrackingResource,
|
||||
const bool &aFirstPartyStorageAccessGranted, const OriginAttributes &aAttrs,
|
||||
const nsCString &aCookieString, const nsCString &aServerTime,
|
||||
const bool &aFromHttp) {
|
||||
const bool &aFirstPartyStorageAccessGranted, const nsCString &aCookieString,
|
||||
const nsCString &aServerTime, const bool &aFromHttp) {
|
||||
if (!mCookieService) return IPC_OK();
|
||||
|
||||
// Deserialize URI. Having a host URI is mandatory and should always be
|
||||
|
@ -244,12 +240,17 @@ mozilla::ipc::IPCResult CookieServiceParent::RecvSetCookieString(
|
|||
// NB: dummyChannel could be null if something failed in CreateDummyChannel.
|
||||
nsDependentCString cookieString(aCookieString, 0);
|
||||
|
||||
OriginAttributes attrs;
|
||||
if (loadInfo) {
|
||||
attrs = loadInfo->GetOriginAttributes();
|
||||
}
|
||||
|
||||
// We set this to true while processing this cookie update, to make sure
|
||||
// we don't send it back to the same content process.
|
||||
mProcessingCookie = true;
|
||||
mCookieService->SetCookieStringInternal(
|
||||
hostURI, aIsForeign, aIsTrackingResource, aFirstPartyStorageAccessGranted,
|
||||
cookieString, aServerTime, aFromHttp, aAttrs, dummyChannel);
|
||||
cookieString, aServerTime, aFromHttp, attrs, dummyChannel);
|
||||
mProcessingCookie = false;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
|
|
@ -49,8 +49,8 @@ class CookieServiceParent : public PCookieServiceParent {
|
|||
const Maybe<LoadInfoArgs> &aLoadInfoArgs, const bool &aIsForeign,
|
||||
const bool &aIsTrackingResource,
|
||||
const bool &aFirstPartyStorageAccessGranted,
|
||||
const OriginAttributes &aAttrs, const nsCString &aCookieString,
|
||||
const nsCString &aServerTime, const bool &aFromHttp);
|
||||
const nsCString &aCookieString, const nsCString &aServerTime,
|
||||
const bool &aFromHttp);
|
||||
|
||||
mozilla::ipc::IPCResult RecvPrepareCookieList(
|
||||
const URIParams &aHost, const bool &aIsForeign,
|
||||
|
|
|
@ -75,7 +75,6 @@ parent:
|
|||
bool isForeign,
|
||||
bool isTrackingResource,
|
||||
bool firstPartyStorageAccessGranted,
|
||||
OriginAttributes aStoragePrincipalAttrs,
|
||||
nsCString cookieString,
|
||||
nsCString serverTime,
|
||||
bool aFromHttp);
|
||||
|
|
|
@ -1990,8 +1990,7 @@ nsresult nsCookieService::GetCookieStringCommon(nsIURI *aHostURI,
|
|||
|
||||
OriginAttributes attrs;
|
||||
if (aChannel) {
|
||||
NS_GetOriginAttributes(aChannel, attrs,
|
||||
true /* considering storage principal */);
|
||||
NS_GetOriginAttributes(aChannel, attrs);
|
||||
}
|
||||
|
||||
bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
|
||||
|
@ -2110,8 +2109,7 @@ nsresult nsCookieService::SetCookieStringCommon(nsIURI *aHostURI,
|
|||
|
||||
OriginAttributes attrs;
|
||||
if (aChannel) {
|
||||
NS_GetOriginAttributes(aChannel, attrs,
|
||||
true /* considering storage principal */);
|
||||
NS_GetOriginAttributes(aChannel, attrs);
|
||||
}
|
||||
|
||||
nsDependentCString cookieString(aCookieHeader);
|
||||
|
@ -4042,12 +4040,6 @@ CookieStatus nsCookieService::CheckPrefs(
|
|||
if (aIsForeign && aIsTrackingResource && !aFirstPartyStorageAccessGranted &&
|
||||
aCookieSettings->GetCookieBehavior() ==
|
||||
nsICookieService::BEHAVIOR_REJECT_TRACKER) {
|
||||
if (StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
|
||||
MOZ_ASSERT(!aOriginAttrs.mFirstPartyDomain.IsEmpty(),
|
||||
"We must have a StoragePrincipal here!");
|
||||
return STATUS_ACCEPTED;
|
||||
}
|
||||
|
||||
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI,
|
||||
aCookieHeader, "cookies are disabled in trackers");
|
||||
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
|
||||
|
|
|
@ -84,8 +84,7 @@ PrototypeDocumentParser::Parse(nsIURI* aURL, nsIRequestObserver* aListener,
|
|||
mCurrentPrototype = proto;
|
||||
|
||||
// Set up the right principal on the document.
|
||||
mDocument->SetPrincipals(proto->DocumentPrincipal(),
|
||||
proto->DocumentPrincipal());
|
||||
mDocument->SetPrincipal(proto->DocumentPrincipal());
|
||||
} else {
|
||||
// It's just a vanilla document load. Create a parser to deal
|
||||
// with the stream n' stuff.
|
||||
|
@ -186,7 +185,7 @@ nsresult PrototypeDocumentParser::PrepareToLoadPrototype(
|
|||
nsXULPrototypeCache::GetInstance()->PutPrototype(mCurrentPrototype);
|
||||
}
|
||||
|
||||
mDocument->SetPrincipals(aDocumentPrincipal, aDocumentPrincipal);
|
||||
mDocument->SetPrincipal(aDocumentPrincipal);
|
||||
|
||||
// Create a XUL content sink, a parser, and kick off a load for
|
||||
// the document.
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "StoragePrincipalHelper.h"
|
||||
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/StaticPrefs.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace {
|
||||
|
||||
already_AddRefed<nsIURI> MaybeGetFirstPartyURI(nsIChannel* aChannel) {
|
||||
MOZ_ASSERT(aChannel);
|
||||
|
||||
if (!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Let's use the storage principal only if we need to partition the cookie
|
||||
// jar.
|
||||
nsContentUtils::StorageAccess access =
|
||||
nsContentUtils::StorageAllowedForChannel(aChannel);
|
||||
if (access != nsContentUtils::StorageAccess::ePartitionedOrDeny) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
|
||||
if (!httpChannel) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(httpChannel->IsThirdPartyTrackingResource());
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
||||
nsCOMPtr<nsIPrincipal> toplevelPrincipal = loadInfo->GetTopLevelPrincipal();
|
||||
if (!toplevelPrincipal) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> principalURI;
|
||||
nsresult rv = toplevelPrincipal->GetURI(getter_AddRefs(principalURI));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return principalURI.forget();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
nsresult StoragePrincipalHelper::Create(nsIChannel* aChannel,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal** aStoragePrincipal) {
|
||||
MOZ_ASSERT(aChannel);
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
MOZ_ASSERT(aStoragePrincipal);
|
||||
|
||||
auto scopeExit = MakeScopeExit([&] {
|
||||
nsCOMPtr<nsIPrincipal> storagePrincipal = aPrincipal;
|
||||
storagePrincipal.forget(aStoragePrincipal);
|
||||
});
|
||||
|
||||
nsCOMPtr<nsIURI> principalURI = MaybeGetFirstPartyURI(aChannel);
|
||||
if (!principalURI) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
scopeExit.release();
|
||||
|
||||
nsCOMPtr<nsIPrincipal> storagePrincipal =
|
||||
BasePrincipal::Cast(aPrincipal)
|
||||
->CloneForcingFirstPartyDomain(principalURI);
|
||||
|
||||
storagePrincipal.forget(aStoragePrincipal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult StoragePrincipalHelper::PrepareOriginAttributes(
|
||||
nsIChannel* aChannel, OriginAttributes& aOriginAttributes) {
|
||||
MOZ_ASSERT(aChannel);
|
||||
|
||||
nsCOMPtr<nsIURI> principalURI = MaybeGetFirstPartyURI(aChannel);
|
||||
if (!principalURI) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aOriginAttributes.SetFirstPartyDomain(false, principalURI,
|
||||
true /* aForced */);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -1,137 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_StoragePrincipalHelper_h
|
||||
#define mozilla_StoragePrincipalHelper_h
|
||||
|
||||
/**
|
||||
* StoragePrincipal
|
||||
* ~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* StoragePrincipal is the nsIPrincipal to be used to open the cookie jar of a
|
||||
* resource's origin. Normally, the StoragePrincipal corresponds to the
|
||||
* resource's origin, but, in some scenarios, it can be different: it can have
|
||||
* some extra origin attributes.
|
||||
*
|
||||
* Each storage component, should always use the StoragePrincipal instead of the
|
||||
* 'real' one in order to implement the partitioning correctly.
|
||||
*
|
||||
* On the web, each resource has its own origin (see
|
||||
* https://html.spec.whatwg.org/multipage/origin.html#concept-origin) and each
|
||||
* origin has its own cookie jar, containing cookies, storage data, cache and so
|
||||
* on.
|
||||
*
|
||||
* In addition, gecko has a set of attributes to differentiate the same origin
|
||||
* in different contexts (OriginAttributes). The main ones are:
|
||||
* - privateBrowsingId, for private browsing navigation.
|
||||
* - userContextId, for containers
|
||||
* - firstPartyIsolation, for TOR.
|
||||
*
|
||||
* In gecko-world, the origin and its attributes are stored and managed by the
|
||||
* nsIPrincipal interface. Both resource's Principal and resource's
|
||||
* StoragePrincipal are nsIPrincipal interfaces and, normally, they are the same
|
||||
* object.
|
||||
*
|
||||
* Here is the way you can obtain the two Principals:
|
||||
* From a Document:
|
||||
* - Document's principal: nsINode::NodePrincipal
|
||||
* - Document's StoragePrincipal: Document::EffectiveStoragePrincipal
|
||||
* From a Global object:
|
||||
* - nsIScriptObjectPrincipal::getPrincipal
|
||||
* - nsIScriptObjectPrincipal::getEffectiveStoragePrincipal
|
||||
* From a Worker:
|
||||
* - WorkerPrivate::GetPrincipal().
|
||||
* - WorkerPrivate::GetEffectiveStoragePrincipal();
|
||||
* For a nsIChannel, the final principals must be calculated and they can be
|
||||
* obtained by calling:
|
||||
* - nsIScriptSecurityManager::getChannelResultPrincipal() or
|
||||
* - nsIScriptSecurityManager::getChannelResultStoragePrincipal().
|
||||
*
|
||||
* Principal VS StoragePrincipal
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* At the moment, we are experimenting the partitioning of cookie jars for 3rd
|
||||
* party trackers: each 3rd party origin, detected as a tracker, will have a
|
||||
* partitioned cookie jar, created by the tracker's origin, plus, the
|
||||
* first-party domain.
|
||||
*
|
||||
* This means that, for those origins, StoragePrincipal will be equal to the
|
||||
* main Principal but it will also have the 'first-party-domain' attribute set
|
||||
* as the first-party URL's domain. Because of this, the tracker's cookie jar
|
||||
* will be partitioned and it will be unique per first-party domain.
|
||||
*
|
||||
* The naminig is important. This is why Document has the StoragePrincipal
|
||||
* stored in a member variable called mIntrinsicStoragePrincipal: this
|
||||
* storagePrincipal is immutable even when Document::EffectiveStoragePrincipal
|
||||
* returns the main principal.
|
||||
*
|
||||
* Storage access permission
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* A resource's origin and its attributes are immutable. StoragePrincipal can
|
||||
* change: when a tracker has the storage permission granted, its
|
||||
* StoragePrincipal becomes equal to its document's principal. In this way, the
|
||||
* tracker will have access to its first-party cookie jar, escaping from the
|
||||
* its partitioning.
|
||||
*
|
||||
* To know more about when the storage access permission is granted, see the
|
||||
* anti-tracking project's documentation.
|
||||
* See: https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API and
|
||||
* https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Privacy/Storage_access_policy#Storage_access_grants
|
||||
*
|
||||
*
|
||||
* When the storage access permission is granted, any of the StoragePrincipal
|
||||
* getter methods will return the main principal instead of the storage one, and
|
||||
* each storage component should consider the new Principal only.
|
||||
*
|
||||
* There are several ways to receive storage-permission notifications:
|
||||
* - Add some code in nsGlobalWindowInner::StorageAccessGranted().
|
||||
* - WorkerScope::FirstPartyStorageAccessGranted for Workers.
|
||||
* - observe the permission changes (not recommended)
|
||||
*
|
||||
* SharedWorkers and BroadcastChannels
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* SharedWorker and BroadcastChannel instances latch the effective storage
|
||||
* principal at the moment of their creation. Existing bindings to the
|
||||
* partitioned storage principal will continue to exist and operate even as it
|
||||
* becomes possible to create bindings associated with the non-partitioned node
|
||||
* principal. This makes it possible for such globals to bi-directionally
|
||||
* bridge information between partitioned and non-partitioned principals.
|
||||
*
|
||||
* {Dedicated,Shared,Service}Workers
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* The storage access permission propagation happens with a ControlRunnable.
|
||||
* This could impact the use of sync event-loops. Take a reference of the
|
||||
* principal you want to use because it can change!
|
||||
*
|
||||
* ServiceWorkers are currently disabled for partitioned contexts.
|
||||
*
|
||||
* Client API uses the main principal always because there is not a direct
|
||||
* connection between this API and the cookie jar. If we want to support
|
||||
* ServiceWorkers in partitioned context, this part must be revisited.
|
||||
*/
|
||||
|
||||
class nsIChannel;
|
||||
class nsIPrincipal;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class OriginAttributes;
|
||||
|
||||
class StoragePrincipalHelper final {
|
||||
public:
|
||||
static nsresult Create(nsIChannel* aChannel, nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal** aStoragePrincipal);
|
||||
|
||||
static nsresult PrepareOriginAttributes(nsIChannel* aChannel,
|
||||
OriginAttributes& aOriginAttributes);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_StoragePrincipalHelper_h
|
|
@ -9,12 +9,10 @@ with Files('**'):
|
|||
|
||||
EXPORTS.mozilla = [
|
||||
'AntiTrackingCommon.h',
|
||||
'StoragePrincipalHelper.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AntiTrackingCommon.cpp',
|
||||
'StoragePrincipalHelper.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>3rd party content!</title>
|
||||
<script type="text/javascript" src="https://example.com/browser/toolkit/components/antitracking/test/browser/storageAccessAPIHelpers.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Here the 3rd party content!</h1>
|
||||
<script>
|
||||
|
||||
function info(msg) {
|
||||
parent.postMessage({ type: "info", msg }, "*");
|
||||
}
|
||||
|
||||
function ok(what, msg) {
|
||||
parent.postMessage({ type: "ok", what: !!what, msg }, "*");
|
||||
}
|
||||
|
||||
function is(a, b, msg) {
|
||||
ok(a === b, msg);
|
||||
}
|
||||
|
||||
onmessage = function(e) {
|
||||
let data = e.data;
|
||||
let runnableStr = `(() => {return (${data});})();`;
|
||||
let runnable = eval(runnableStr); // eslint-disable-line no-eval
|
||||
|
||||
let win = window.open("3rdPartyStorageWO.html");
|
||||
win.onload = async _ => {
|
||||
/* import-globals-from storageAccessAPIHelpers.js */
|
||||
await noStorageAccessInitially();
|
||||
|
||||
await runnable.call(this, this, win, false /* allowed */);
|
||||
/* import-globals-from storageAccessAPIHelpers.js */
|
||||
await callRequestStorageAccess();
|
||||
await runnable.call(this, this, win, true /* allowed */);
|
||||
|
||||
win.close();
|
||||
parent.postMessage({ type: "finish" }, "*");
|
||||
};
|
||||
};
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,8 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>1st party content!</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Here the 1st party content!</h1>
|
||||
</body>
|
||||
</html>
|
|
@ -1,707 +0,0 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* import-globals-from head.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
var gFeatures = undefined;
|
||||
|
||||
this.AntiTracking = {
|
||||
runTest(name, callbackTracking, callbackNonTracking, cleanupFunction, extraPrefs,
|
||||
windowOpenTest = true, userInteractionTest = true,
|
||||
expectedBlockingNotifications = Ci.nsIWebProgressListener.STATE_COOKIES_BLOCKED_TRACKER,
|
||||
runInPrivateWindow = false, iframeSandbox = null, accessRemoval = null,
|
||||
callbackAfterRemoval = null) {
|
||||
// Here we want to test that a 3rd party context is simply blocked.
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_REJECT_TRACKER,
|
||||
blockingByContentBlockingRTUI: true,
|
||||
allowList: false,
|
||||
callback: callbackTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval,
|
||||
callbackAfterRemoval,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_REJECT_TRACKER,
|
||||
blockingByContentBlockingRTUI: false,
|
||||
allowList: true,
|
||||
callback: callbackTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval,
|
||||
callbackAfterRemoval,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
if (callbackNonTracking) {
|
||||
let runExtraTests = true;
|
||||
let options = {};
|
||||
if (typeof callbackNonTracking == "object") {
|
||||
options.callback = callbackNonTracking.callback;
|
||||
runExtraTests = callbackNonTracking.runExtraTests;
|
||||
if ("cookieBehavior" in callbackNonTracking) {
|
||||
options.cookieBehavior = callbackNonTracking.cookieBehavior;
|
||||
} else {
|
||||
options.cookieBehavior = BEHAVIOR_ACCEPT;
|
||||
}
|
||||
if ("blockingByContentBlockingRTUI" in callbackNonTracking) {
|
||||
options.blockingByContentBlockingRTUI =
|
||||
callbackNonTracking.blockingByContentBlockingRTUI;
|
||||
} else {
|
||||
options.blockingByContentBlockingRTUI = false;
|
||||
}
|
||||
if ("blockingByAllowList" in callbackNonTracking) {
|
||||
options.blockingByAllowList =
|
||||
callbackNonTracking.blockingByAllowList;
|
||||
} else {
|
||||
options.blockingByAllowList = false;
|
||||
}
|
||||
callbackNonTracking = options.callback;
|
||||
options.accessRemoval = null;
|
||||
options.callbackAfterRemoval = null;
|
||||
}
|
||||
|
||||
// Phase 1: Here we want to test that a 3rd party context is not blocked if pref is off.
|
||||
if (runExtraTests) {
|
||||
// There are five ways in which the third-party context may not be blocked:
|
||||
// * If the cookieBehavior pref causes it to not be blocked.
|
||||
// * If the contentBlocking pref causes it to not be blocked.
|
||||
// * If both of these prefs cause it to not be blocked.
|
||||
// * If the top-level page is on the content blocking allow list.
|
||||
// * If the contentBlocking third-party cookies UI pref is off, the allow list will be ignored.
|
||||
// All of these cases are tested here.
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_ACCEPT,
|
||||
blockingByContentBlockingRTUI: true,
|
||||
allowList: false,
|
||||
callback: callbackNonTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications: 0,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval: null, // only passed with non-blocking callback
|
||||
callbackAfterRemoval: null,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_ACCEPT,
|
||||
blockingByContentBlockingRTUI: false,
|
||||
allowList: true,
|
||||
callback: callbackNonTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications: 0,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval: null, // only passed with non-blocking callback
|
||||
callbackAfterRemoval: null,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_ACCEPT,
|
||||
blockingByContentBlockingRTUI: false,
|
||||
allowList: false,
|
||||
callback: callbackNonTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications: 0,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval: null, // only passed with non-blocking callback
|
||||
callbackAfterRemoval: null,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_REJECT,
|
||||
blockingByContentBlockingRTUI: true,
|
||||
allowList: false,
|
||||
callback: callbackTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications: 0,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval: null, // only passed with non-blocking callback
|
||||
callbackAfterRemoval: null,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_LIMIT_FOREIGN,
|
||||
blockingByContentBlockingRTUI: true,
|
||||
allowList: true,
|
||||
callback: callbackNonTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications: 0,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval: null, // only passed with non-blocking callback
|
||||
callbackAfterRemoval: null,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_REJECT_FOREIGN,
|
||||
blockingByContentBlockingRTUI: true,
|
||||
allowList: true,
|
||||
callback: callbackNonTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications: 0,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval: null, // only passed with non-blocking callback
|
||||
callbackAfterRemoval: null,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_REJECT_TRACKER,
|
||||
blockingByContentBlockingRTUI: true,
|
||||
allowList: true,
|
||||
callback: callbackNonTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications: 0,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval,
|
||||
callbackAfterRemoval,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_REJECT_TRACKER,
|
||||
blockingByContentBlockingRTUI: false,
|
||||
allowList: false,
|
||||
callback: callbackNonTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications: false,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval: null, // only passed with non-blocking callback
|
||||
callbackAfterRemoval: null,
|
||||
thirdPartyPage: TEST_ANOTHER_3RD_PARTY_PAGE,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
}
|
||||
|
||||
// Phase 2: Here we want to test that a third-party context doesn't
|
||||
// get blocked with when the same origin is opened through window.open().
|
||||
if (windowOpenTest) {
|
||||
this._createWindowOpenTask(name, callbackTracking, callbackNonTracking,
|
||||
runInPrivateWindow, iframeSandbox, extraPrefs);
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
}
|
||||
|
||||
// Phase 3: Here we want to test that a third-party context doesn't
|
||||
// get blocked with user interaction present
|
||||
if (userInteractionTest) {
|
||||
this._createUserInteractionTask(name, callbackTracking, callbackNonTracking,
|
||||
runInPrivateWindow, iframeSandbox, extraPrefs);
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async interactWithTracker() {
|
||||
let windowClosed = new Promise(resolve => {
|
||||
Services.ww.registerNotification(function notification(aSubject, aTopic, aData) {
|
||||
if (aTopic == "domwindowclosed") {
|
||||
Services.ww.unregisterNotification(notification);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
info("Let's interact with the tracker");
|
||||
window.open(TEST_3RD_PARTY_DOMAIN + TEST_PATH + "3rdPartyOpenUI.html");
|
||||
await windowClosed;
|
||||
},
|
||||
|
||||
async _setupTest(win, cookieBehavior, blockingByContentBlockingRTUI,
|
||||
extraPrefs) {
|
||||
await SpecialPowers.flushPrefEnv();
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.storage_access.enabled", true],
|
||||
["browser.contentblocking.allowlist.annotations.enabled", blockingByContentBlockingRTUI],
|
||||
["browser.contentblocking.allowlist.storage.enabled", blockingByContentBlockingRTUI],
|
||||
["network.cookie.cookieBehavior", cookieBehavior],
|
||||
["privacy.trackingprotection.enabled", false],
|
||||
["privacy.trackingprotection.pbmode.enabled", false],
|
||||
["privacy.trackingprotection.annotate_channels", cookieBehavior != BEHAVIOR_ACCEPT],
|
||||
[win.ContentBlocking.prefIntroCount, win.ContentBlocking.MAX_INTROS],
|
||||
["privacy.restrict3rdpartystorage.userInteractionRequiredForHosts", "tracking.example.com,tracking.example.org"],
|
||||
]});
|
||||
|
||||
if (extraPrefs && Array.isArray(extraPrefs) && extraPrefs.length) {
|
||||
await SpecialPowers.pushPrefEnv({"set": extraPrefs });
|
||||
|
||||
for (let item of extraPrefs) {
|
||||
// When setting up skip URLs, we need to wait to ensure our prefs
|
||||
// actually take effect. In order to do this, we set up a skip list
|
||||
// observer and wait until it calls us back.
|
||||
if (item[0] == "urlclassifier.trackingAnnotationSkipURLs") {
|
||||
info("Waiting for the skip list service to initialize...");
|
||||
let classifier = Cc["@mozilla.org/url-classifier/dbservice;1"]
|
||||
.getService(Ci.nsIURIClassifier);
|
||||
let feature = classifier.getFeatureByName("tracking-annotation");
|
||||
await TestUtils.waitForCondition(() => feature.skipHostList == item[1].toLowerCase(),
|
||||
"Skip list service initialized");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await UrlClassifierTestUtils.addTestTrackers();
|
||||
},
|
||||
|
||||
_createTask(options) {
|
||||
add_task(async function() {
|
||||
info("Starting " + (options.cookieBehavior != BEHAVIOR_ACCEPT ? "blocking" : "non-blocking") + " cookieBehavior (" + options.cookieBehavior + ") and " +
|
||||
(options.blockingByContentBlockingRTUI ? "" : "no") + " contentBlocking third-party cookies UI with" +
|
||||
(options.allowList ? "" : "out") + " allow list test " + options.name +
|
||||
" running in a " + (options.runInPrivateWindow ? "private" : "normal") + " window " +
|
||||
" with iframe sandbox set to " + options.iframeSandbox +
|
||||
" and access removal set to " + options.accessRemoval +
|
||||
(typeof options.thirdPartyPage == "string" ? (
|
||||
" and third party page set to " + options.thirdPartyPage) : ""));
|
||||
|
||||
is(!!options.callbackAfterRemoval, !!options.accessRemoval,
|
||||
"callbackAfterRemoval must be passed when accessRemoval is non-null");
|
||||
|
||||
let win = window;
|
||||
if (options.runInPrivateWindow) {
|
||||
win = OpenBrowserWindow({private: true});
|
||||
await TestUtils.topicObserved("browser-delayed-startup-finished");
|
||||
}
|
||||
|
||||
await AntiTracking._setupTest(win, options.cookieBehavior,
|
||||
options.blockingByContentBlockingRTUI,
|
||||
options.extraPrefs);
|
||||
|
||||
let cookieBlocked = 0;
|
||||
let listener = {
|
||||
onContentBlockingEvent(webProgress, request, event) {
|
||||
if ((event & options.expectedBlockingNotifications)) {
|
||||
++cookieBlocked;
|
||||
}
|
||||
},
|
||||
};
|
||||
win.gBrowser.addProgressListener(listener);
|
||||
|
||||
info("Creating a new tab");
|
||||
let tab = BrowserTestUtils.addTab(win.gBrowser, TEST_TOP_PAGE);
|
||||
win.gBrowser.selectedTab = tab;
|
||||
|
||||
let browser = win.gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
if (options.allowList) {
|
||||
info("Disabling content blocking for this page");
|
||||
win.ContentBlocking.disableForCurrentPage();
|
||||
|
||||
// The previous function reloads the browser, so wait for it to load again!
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
}
|
||||
|
||||
info("Creating a 3rd party content");
|
||||
let doAccessRemovalChecks = typeof options.accessRemoval == "string" &&
|
||||
options.cookieBehavior == BEHAVIOR_REJECT_TRACKER &&
|
||||
options.blockingByContentBlockingRTUI &&
|
||||
!options.allowList;
|
||||
let thirdPartyPage;
|
||||
if (typeof options.thirdPartyPage == "string") {
|
||||
thirdPartyPage = options.thirdPartyPage;
|
||||
} else {
|
||||
thirdPartyPage = TEST_3RD_PARTY_PAGE;
|
||||
}
|
||||
await ContentTask.spawn(browser,
|
||||
{ page: thirdPartyPage,
|
||||
nextPage: TEST_4TH_PARTY_PAGE,
|
||||
callback: options.callback.toString(),
|
||||
callbackAfterRemoval: options.callbackAfterRemoval ?
|
||||
options.callbackAfterRemoval.toString() : null,
|
||||
accessRemoval: options.accessRemoval,
|
||||
iframeSandbox: options.iframeSandbox,
|
||||
allowList: options.allowList,
|
||||
doAccessRemovalChecks },
|
||||
async function(obj) {
|
||||
let id = "id" + Math.random();
|
||||
await new content.Promise(resolve => {
|
||||
let ifr = content.document.createElement("iframe");
|
||||
ifr.id = id;
|
||||
ifr.onload = function() {
|
||||
info("Sending code to the 3rd party content");
|
||||
let callback = obj.allowList + "!!!" + obj.callback;
|
||||
ifr.contentWindow.postMessage(callback, "*");
|
||||
};
|
||||
if (typeof obj.iframeSandbox == "string") {
|
||||
ifr.setAttribute("sandbox", obj.iframeSandbox);
|
||||
}
|
||||
|
||||
content.addEventListener("message", function msg(event) {
|
||||
if (event.data.type == "finish") {
|
||||
content.removeEventListener("message", msg);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "ok") {
|
||||
ok(event.data.what, event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "info") {
|
||||
info(event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, "Unknown message");
|
||||
});
|
||||
|
||||
content.document.body.appendChild(ifr);
|
||||
ifr.src = obj.page;
|
||||
});
|
||||
|
||||
if (obj.doAccessRemovalChecks) {
|
||||
info(`Running after removal checks (${obj.accessRemoval})`);
|
||||
switch (obj.accessRemoval) {
|
||||
case "navigate-subframe":
|
||||
await new content.Promise(resolve => {
|
||||
let ifr = content.document.getElementById(id);
|
||||
let oldWindow = ifr.contentWindow;
|
||||
ifr.onload = function() {
|
||||
info("Sending code to the old 3rd party content");
|
||||
oldWindow.postMessage(obj.callbackAfterRemoval, "*");
|
||||
};
|
||||
if (typeof obj.iframeSandbox == "string") {
|
||||
ifr.setAttribute("sandbox", obj.iframeSandbox);
|
||||
}
|
||||
|
||||
content.addEventListener("message", function msg(event) {
|
||||
if (event.data.type == "finish") {
|
||||
content.removeEventListener("message", msg);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "ok") {
|
||||
ok(event.data.what, event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "info") {
|
||||
info(event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, "Unknown message");
|
||||
});
|
||||
|
||||
ifr.src = obj.nextPage;
|
||||
});
|
||||
break;
|
||||
default:
|
||||
ok(false, "Unexpected accessRemoval code passed: " + obj.accessRemoval);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (options.allowList) {
|
||||
info("Enabling content blocking for this page");
|
||||
win.ContentBlocking.enableForCurrentPage();
|
||||
|
||||
// The previous function reloads the browser, so wait for it to load again!
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
}
|
||||
|
||||
win.gBrowser.removeProgressListener(listener);
|
||||
|
||||
is(!!cookieBlocked, !!options.expectedBlockingNotifications, "Checking cookie blocking notifications");
|
||||
|
||||
info("Removing the tab");
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
if (options.runInPrivateWindow) {
|
||||
win.close();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_createCleanupTask(cleanupFunction) {
|
||||
add_task(async function() {
|
||||
info("Cleaning up.");
|
||||
if (cleanupFunction) {
|
||||
await cleanupFunction();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_createWindowOpenTask(name, blockingCallback, nonBlockingCallback, runInPrivateWindow,
|
||||
iframeSandbox, extraPrefs) {
|
||||
add_task(async function() {
|
||||
info("Starting window-open test " + name);
|
||||
|
||||
let win = window;
|
||||
if (runInPrivateWindow) {
|
||||
win = OpenBrowserWindow({private: true});
|
||||
await TestUtils.topicObserved("browser-delayed-startup-finished");
|
||||
}
|
||||
|
||||
await AntiTracking._setupTest(win, BEHAVIOR_REJECT_TRACKER, true, extraPrefs);
|
||||
|
||||
info("Creating a new tab");
|
||||
let tab = BrowserTestUtils.addTab(win.gBrowser, TEST_TOP_PAGE);
|
||||
win.gBrowser.selectedTab = tab;
|
||||
|
||||
let browser = win.gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
let pageURL = TEST_3RD_PARTY_PAGE_WO;
|
||||
if (gFeatures == "noopener") {
|
||||
pageURL += "?noopener";
|
||||
}
|
||||
|
||||
info("Creating a 3rd party content");
|
||||
await ContentTask.spawn(browser,
|
||||
{ page: pageURL,
|
||||
blockingCallback: blockingCallback.toString(),
|
||||
nonBlockingCallback: nonBlockingCallback.toString(),
|
||||
iframeSandbox,
|
||||
},
|
||||
async function(obj) {
|
||||
await new content.Promise(resolve => {
|
||||
let ifr = content.document.createElement("iframe");
|
||||
ifr.onload = function() {
|
||||
info("Sending code to the 3rd party content");
|
||||
ifr.contentWindow.postMessage(obj, "*");
|
||||
};
|
||||
if (typeof obj.iframeSandbox == "string") {
|
||||
ifr.setAttribute("sandbox", obj.iframeSandbox);
|
||||
}
|
||||
|
||||
content.addEventListener("message", function msg(event) {
|
||||
if (event.data.type == "finish") {
|
||||
content.removeEventListener("message", msg);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "ok") {
|
||||
ok(event.data.what, event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "info") {
|
||||
info(event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, "Unknown message");
|
||||
});
|
||||
|
||||
content.document.body.appendChild(ifr);
|
||||
ifr.src = obj.page;
|
||||
});
|
||||
});
|
||||
|
||||
info("Removing the tab");
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
if (runInPrivateWindow) {
|
||||
win.close();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_createUserInteractionTask(name, blockingCallback, nonBlockingCallback,
|
||||
runInPrivateWindow, iframeSandbox, extraPrefs) {
|
||||
add_task(async function() {
|
||||
info("Starting user-interaction test " + name);
|
||||
|
||||
let win = window;
|
||||
if (runInPrivateWindow) {
|
||||
win = OpenBrowserWindow({private: true});
|
||||
await TestUtils.topicObserved("browser-delayed-startup-finished");
|
||||
}
|
||||
|
||||
await AntiTracking._setupTest(win, BEHAVIOR_REJECT_TRACKER, true, extraPrefs);
|
||||
|
||||
info("Creating a new tab");
|
||||
let tab = BrowserTestUtils.addTab(win.gBrowser, TEST_TOP_PAGE);
|
||||
win.gBrowser.selectedTab = tab;
|
||||
|
||||
let browser = win.gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
info("Creating a 3rd party content");
|
||||
await ContentTask.spawn(browser,
|
||||
{ page: TEST_3RD_PARTY_PAGE_UI,
|
||||
popup: TEST_POPUP_PAGE,
|
||||
blockingCallback: blockingCallback.toString(),
|
||||
iframeSandbox,
|
||||
},
|
||||
async function(obj) {
|
||||
let ifr = content.document.createElement("iframe");
|
||||
let loading = new content.Promise(resolve => { ifr.onload = resolve; });
|
||||
if (typeof obj.iframeSandbox == "string") {
|
||||
ifr.setAttribute("sandbox", obj.iframeSandbox);
|
||||
}
|
||||
content.document.body.appendChild(ifr);
|
||||
ifr.src = obj.page;
|
||||
await loading;
|
||||
|
||||
info("The 3rd party content should not have access to first party storage.");
|
||||
await new content.Promise(resolve => {
|
||||
content.addEventListener("message", function msg(event) {
|
||||
if (event.data.type == "finish") {
|
||||
content.removeEventListener("message", msg);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "ok") {
|
||||
ok(event.data.what, event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "info") {
|
||||
info(event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, "Unknown message");
|
||||
});
|
||||
ifr.contentWindow.postMessage({ callback: obj.blockingCallback }, "*");
|
||||
});
|
||||
|
||||
let windowClosed = new content.Promise(resolve => {
|
||||
Services.ww.registerNotification(function notification(aSubject, aTopic, aData) {
|
||||
if (aTopic == "domwindowclosed") {
|
||||
Services.ww.unregisterNotification(notification);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
info("Opening a window from the iframe.");
|
||||
ifr.contentWindow.open(obj.popup);
|
||||
|
||||
info("Let's wait for the window to be closed");
|
||||
await windowClosed;
|
||||
|
||||
info("First time, the 3rd party content should not have access to first party storage " +
|
||||
"because the tracker did not have user interaction");
|
||||
await new content.Promise(resolve => {
|
||||
content.addEventListener("message", function msg(event) {
|
||||
if (event.data.type == "finish") {
|
||||
content.removeEventListener("message", msg);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "ok") {
|
||||
ok(event.data.what, event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "info") {
|
||||
info(event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, "Unknown message");
|
||||
});
|
||||
ifr.contentWindow.postMessage({ callback: obj.blockingCallback }, "*");
|
||||
});
|
||||
});
|
||||
|
||||
await AntiTracking.interactWithTracker();
|
||||
|
||||
await ContentTask.spawn(browser,
|
||||
{ page: TEST_3RD_PARTY_PAGE_UI,
|
||||
popup: TEST_POPUP_PAGE,
|
||||
nonBlockingCallback: nonBlockingCallback.toString(),
|
||||
iframeSandbox,
|
||||
},
|
||||
async function(obj) {
|
||||
let ifr = content.document.createElement("iframe");
|
||||
let loading = new content.Promise(resolve => { ifr.onload = resolve; });
|
||||
if (typeof obj.iframeSandbox == "string") {
|
||||
ifr.setAttribute("sandbox", obj.iframeSandbox);
|
||||
}
|
||||
content.document.body.appendChild(ifr);
|
||||
ifr.src = obj.page;
|
||||
await loading;
|
||||
|
||||
let windowClosed = new content.Promise(resolve => {
|
||||
Services.ww.registerNotification(function notification(aSubject, aTopic, aData) {
|
||||
if (aTopic == "domwindowclosed") {
|
||||
Services.ww.unregisterNotification(notification);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
info("Opening a window from the iframe.");
|
||||
ifr.contentWindow.open(obj.popup);
|
||||
|
||||
info("Let's wait for the window to be closed");
|
||||
await windowClosed;
|
||||
|
||||
info("The 3rd party content should now have access to first party storage.");
|
||||
await new content.Promise(resolve => {
|
||||
content.addEventListener("message", function msg(event) {
|
||||
if (event.data.type == "finish") {
|
||||
content.removeEventListener("message", msg);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "ok") {
|
||||
ok(event.data.what, event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "info") {
|
||||
info(event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, "Unknown message");
|
||||
});
|
||||
ifr.contentWindow.postMessage({ callback: obj.nonBlockingCallback }, "*");
|
||||
});
|
||||
});
|
||||
|
||||
info("Removing the tab");
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
if (runInPrivateWindow) {
|
||||
win.close();
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
@ -9,8 +9,6 @@ support-files =
|
|||
container.html
|
||||
embedder.html
|
||||
head.js
|
||||
antitracking_head.js
|
||||
storageprincipal_head.js
|
||||
image.sjs
|
||||
imageCacheWorker.js
|
||||
page.html
|
||||
|
@ -25,8 +23,6 @@ support-files =
|
|||
popup.html
|
||||
server.sjs
|
||||
storageAccessAPIHelpers.js
|
||||
3rdPartyStorage.html
|
||||
3rdPartyStorageWO.html
|
||||
!/browser/modules/test/browser/head.js
|
||||
|
||||
[browser_allowListNotifications.js]
|
||||
|
@ -92,12 +88,3 @@ support-files = localStorageEvents.html
|
|||
[browser_workerPropagation.js]
|
||||
support-files = workerIframe.html
|
||||
[browser_cookieBetweenTabs.js]
|
||||
[browser_partitionedMessaging.js]
|
||||
[browser_partitionedIndexedDB.js]
|
||||
[browser_partitionedCookies.js]
|
||||
support-files = cookies.sjs
|
||||
[browser_partitionedDOMCache.js]
|
||||
[browser_partitionedServiceWorkers.js]
|
||||
support-files = matchAll.js
|
||||
[browser_partitionedSharedWorkers.js]
|
||||
support-files = sharedWorker.js
|
||||
|
|
|
@ -10,9 +10,6 @@
|
|||
// private windows wouldn't send any blocking notifications as they don't have
|
||||
// storage access in the first place.
|
||||
|
||||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
"use strict";
|
||||
add_task(async _ => {
|
||||
let uri = Services.io.newURI("https://example.net");
|
||||
Services.perms.add(uri, "trackingprotection-pb",
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
// This test works by setting up an exception for the tracker domain, which
|
||||
// disables all the anti-tracking tests.
|
||||
|
||||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
add_task(async _ => {
|
||||
Services.perms.add(Services.io.newURI("https://tracking.example.org"),
|
||||
"cookie", Services.perms.ALLOW_ACTION);
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
AntiTracking.runTest("Set/Get Cookies",
|
||||
// Blocking callback
|
||||
async _ => {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
AntiTracking.runTest("DOM Cache",
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
AntiTracking.runTest("IndexedDB",
|
||||
// blocking callback
|
||||
async _ => {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
AntiTracking.runTest("IndexedDB in workers",
|
||||
async _ => {
|
||||
function blockCode() {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
AntiTracking.runTest("localStorage",
|
||||
async _ => {
|
||||
is(window.localStorage, null, "LocalStorage is null");
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
AntiTracking.runTest("BroadcastChannel",
|
||||
async _ => {
|
||||
try {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
gFeatures = "noopener";
|
||||
|
||||
AntiTracking.runTest("Blocking in the case of noopener windows",
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
AntiTracking.runTest("ServiceWorkers",
|
||||
async _ => {
|
||||
await navigator.serviceWorker.register("empty.js").then(
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
AntiTracking.runTest("ServiceWorkers and Storage Access API",
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
AntiTracking.runTest("sessionStorage",
|
||||
async _ => {
|
||||
let shouldThrow = SpecialPowers.Services.prefs.getIntPref("network.cookie.cookieBehavior") == SpecialPowers.Ci.nsICookieService.BEHAVIOR_REJECT;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
AntiTracking.runTest("SharedWorkers",
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
// This test works by setting up an exception for the tracker domain, which
|
||||
// disables all the anti-tracking tests.
|
||||
|
||||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
add_task(async _ => {
|
||||
Services.perms.add(Services.io.newURI("https://tracking.example.org"),
|
||||
"cookie", Services.perms.DENY_ACTION);
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
/* import-globals-from storageprincipal_head.js */
|
||||
|
||||
StoragePrincipalHelper.runTest("HTTP Cookies",
|
||||
async (win3rdParty, win1stParty, allowed) => {
|
||||
await win3rdParty.fetch("cookies.sjs?3rd").then(r => r.text());
|
||||
await win3rdParty.fetch("cookies.sjs").then(r => r.text()).then(text => {
|
||||
is(text, "cookie:foopy=3rd", "3rd party cookie set");
|
||||
});
|
||||
|
||||
await win1stParty.fetch("cookies.sjs?first").then(r => r.text());
|
||||
await win1stParty.fetch("cookies.sjs").then(r => r.text()).then(text => {
|
||||
is(text, "cookie:foopy=first", "First party cookie set");
|
||||
});
|
||||
|
||||
await win3rdParty.fetch("cookies.sjs").then(r => r.text()).then(text => {
|
||||
if (allowed) {
|
||||
is(text, "cookie:foopy=first", "3rd party has the first party cookie set");
|
||||
} else {
|
||||
is(text, "cookie:foopy=3rd", "3rd party has not the first party cookie set");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
async _ => {
|
||||
await new Promise(resolve => {
|
||||
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
|
||||
});
|
||||
});
|
||||
|
||||
StoragePrincipalHelper.runTest("DOM Cookies",
|
||||
async (win3rdParty, win1stParty, allowed) => {
|
||||
win3rdParty.document.cookie = "foo=3rd";
|
||||
is(win3rdParty.document.cookie, "foo=3rd", "3rd party cookie set");
|
||||
|
||||
win1stParty.document.cookie = "foo=first";
|
||||
is(win1stParty.document.cookie, "foo=first", "First party cookie set");
|
||||
|
||||
if (allowed) {
|
||||
is(win3rdParty.document.cookie, "foo=first", "3rd party has the first party cookie set");
|
||||
} else {
|
||||
is(win3rdParty.document.cookie, "foo=3rd", "3rd party has not the first party cookie set");
|
||||
}
|
||||
},
|
||||
|
||||
async _ => {
|
||||
await new Promise(resolve => {
|
||||
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
|
||||
});
|
||||
});
|
|
@ -1,21 +0,0 @@
|
|||
/* import-globals-from storageprincipal_head.js */
|
||||
|
||||
StoragePrincipalHelper.runTest("DOMCache",
|
||||
async (win3rdParty, win1stParty, allowed) => {
|
||||
// DOM Cache is not supported. Always blocked.
|
||||
await win3rdParty.caches.open("wow").then(
|
||||
_ => { ok(allowed, "DOM Cache cannot be used!"); },
|
||||
_ => { ok(!allowed, "DOM Cache cannot be used!"); }
|
||||
);
|
||||
|
||||
await win1stParty.caches.open("wow").then(
|
||||
_ => { ok(true, "DOM Cache shoulw be available"); },
|
||||
_ => { ok(false, "DOM Cache shoulw be available"); },
|
||||
);
|
||||
},
|
||||
|
||||
async _ => {
|
||||
await new Promise(resolve => {
|
||||
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
|
||||
});
|
||||
});
|
|
@ -1,46 +0,0 @@
|
|||
/* import-globals-from storageprincipal_head.js */
|
||||
|
||||
StoragePrincipalHelper.runTest("IndexedDB",
|
||||
async (win3rdParty, win1stParty, allowed) => {
|
||||
await new Promise(resolve => {
|
||||
let a = win1stParty.indexedDB.open("test", 1);
|
||||
ok(!!a, "IDB should not be blocked in 1st party contexts");
|
||||
|
||||
a.onsuccess = e => {
|
||||
let db = e.target.result;
|
||||
is(db.objectStoreNames.length, 1, "We have 1 objectStore");
|
||||
is(db.objectStoreNames[0], "foobar", "We have 'foobar' objectStore");
|
||||
resolve();
|
||||
};
|
||||
|
||||
a.onupgradeneeded = e => {
|
||||
let db = e.target.result;
|
||||
is(db.objectStoreNames.length, 0, "We have 0 objectStores");
|
||||
db.createObjectStore("foobar", { keyPath: "test" });
|
||||
};
|
||||
});
|
||||
|
||||
await new Promise(resolve => {
|
||||
let a = win3rdParty.indexedDB.open("test", 1);
|
||||
ok(!!a, "IDB should not be blocked in 3rd party contexts");
|
||||
|
||||
a.onsuccess = e => {
|
||||
let db = e.target.result;
|
||||
|
||||
if (allowed) {
|
||||
is(db.objectStoreNames.length, 1, "We have 1 objectStore");
|
||||
is(db.objectStoreNames[0], "foobar", "We have 'foobar' objectStore");
|
||||
} else {
|
||||
is(db.objectStoreNames.length, 0, "We have 0 objectStore");
|
||||
}
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
async _ => {
|
||||
await new Promise(resolve => {
|
||||
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
|
||||
});
|
||||
});
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
AntiTracking.runTest("localStorage and Storage Access API",
|
||||
async _ => {
|
||||
/* import-globals-from storageAccessAPIHelpers.js */
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
/* import-globals-from storageprincipal_head.js */
|
||||
|
||||
StoragePrincipalHelper.runTest("BroadcastChannel",
|
||||
async (win3rdParty, win1stParty, allowed) => {
|
||||
let a = new win3rdParty.BroadcastChannel("hello");
|
||||
ok(!!a, "BroadcastChannel should be created by 3rd party iframe");
|
||||
|
||||
let b = new win1stParty.BroadcastChannel("hello");
|
||||
ok(!!b, "BroadcastChannel should be created by 1st party iframe");
|
||||
|
||||
// BroadcastChannel uses the incument global, this means that its CTOR will
|
||||
// always use the 3rd party iframe's window as global.
|
||||
},
|
||||
async _ => {
|
||||
await new Promise(resolve => {
|
||||
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
|
||||
});
|
||||
});
|
|
@ -1,65 +0,0 @@
|
|||
/* import-globals-from storageprincipal_head.js */
|
||||
|
||||
StoragePrincipalHelper.runTest("ServiceWorkers",
|
||||
async (win3rdParty, win1stParty, allowed) => {
|
||||
// ServiceWorkers are not supported. Always blocked.
|
||||
await win3rdParty.navigator.serviceWorker.register("empty.js").then(
|
||||
_ => { ok(allowed, "Success: ServiceWorker cannot be used!"); },
|
||||
_ => { ok(!allowed, "Failed: ServiceWorker cannot be used!"); });
|
||||
|
||||
await win1stParty.navigator.serviceWorker.register("empty.js").then(
|
||||
_ => { ok(true, "Success: ServiceWorker should be available!"); },
|
||||
_ => { ok(false, "Failed: ServiceWorker should be available!"); });
|
||||
},
|
||||
|
||||
async _ => {
|
||||
await new Promise(resolve => {
|
||||
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
|
||||
});
|
||||
},
|
||||
|
||||
[["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.ipc.processCount", 1],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]]);
|
||||
|
||||
StoragePrincipalHelper.runTest("ServiceWorkers - MatchAll",
|
||||
async (win3rdParty, win1stParty, allowed) => {
|
||||
if (!win1stParty.sw) {
|
||||
let reg = await win1stParty.navigator.serviceWorker.register("matchAll.js");
|
||||
if (reg.installing.state !== "activated") {
|
||||
await new Promise(resolve => {
|
||||
let w = reg.installing;
|
||||
w.addEventListener("statechange", function onStateChange() {
|
||||
if (w.state === "activated") {
|
||||
w.removeEventListener("statechange", onStateChange);
|
||||
win1stParty.sw = reg.active;
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let msgPromise = new Promise(resolve => {
|
||||
win1stParty.navigator.serviceWorker.addEventListener("message", msg => {
|
||||
resolve(msg.data);
|
||||
});
|
||||
});
|
||||
|
||||
win1stParty.sw.postMessage(win3rdParty.location.href);
|
||||
let msg = await msgPromise;
|
||||
|
||||
is(allowed, msg, "We want to have the 3rd party window controlled.");
|
||||
},
|
||||
|
||||
async _ => {
|
||||
await new Promise(resolve => {
|
||||
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
|
||||
});
|
||||
},
|
||||
|
||||
[["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.ipc.processCount", 1],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]]);
|
|
@ -1,36 +0,0 @@
|
|||
/* import-globals-from storageprincipal_head.js */
|
||||
|
||||
StoragePrincipalHelper.runTest("SharedWorkers",
|
||||
async (win3rdParty, win1stParty, allowed) => {
|
||||
let sh1 = new win1stParty.SharedWorker("sharedWorker.js");
|
||||
await new Promise(resolve => {
|
||||
sh1.port.onmessage = e => {
|
||||
is(e.data, 1, "We expected 1 connection");
|
||||
resolve();
|
||||
};
|
||||
sh1.port.postMessage("count");
|
||||
});
|
||||
|
||||
let sh3 = new win3rdParty.SharedWorker("sharedWorker.js");
|
||||
await new Promise(resolve => {
|
||||
sh3.port.onmessage = e => {
|
||||
ok(!allowed, "We should be here only if the SharedWorker is partitioned");
|
||||
is(e.data, 1, "We expected 1 connection for 3rd party SharedWorker");
|
||||
resolve();
|
||||
};
|
||||
sh3.onerror = _ => {
|
||||
ok(allowed, "We should be here only if the SharedWorker is not partitioned");
|
||||
resolve();
|
||||
};
|
||||
sh3.port.postMessage("count");
|
||||
});
|
||||
|
||||
sh1.port.postMessage("close");
|
||||
sh3.port.postMessage("close");
|
||||
},
|
||||
|
||||
async _ => {
|
||||
await new Promise(resolve => {
|
||||
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
|
||||
});
|
||||
});
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
AntiTracking.runTest("Test whether we receive any persistent permissions in normal windows",
|
||||
// Blocking callback
|
||||
async _ => {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
AntiTracking.runTest("Test whether we receive any persistent permissions in private windows",
|
||||
// Blocking callback
|
||||
async _ => {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
add_task(async function() {
|
||||
info("Starting subResources test");
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
AntiTracking.runTest("localStorage with a tracker that is whitelisted via a pref",
|
||||
async _ => {
|
||||
let shouldThrow = SpecialPowers.Services.prefs.getIntPref("network.cookie.cookieBehavior") == SpecialPowers.Ci.nsICookieService.BEHAVIOR_REJECT;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
AntiTracking.runTest("Storage Access API called in a private window",
|
||||
// blocking callback
|
||||
async _ => {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
AntiTracking.runTest("Storage Access API returns promises that maintain user activation for calling its reject handler",
|
||||
// blocking callback
|
||||
async _ => {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
AntiTracking.runTest("Storage Access API returns promises that maintain user activation",
|
||||
// blocking callback
|
||||
async _ => {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
AntiTracking.runTest("Storage Access is removed when subframe navigates",
|
||||
// blocking callback
|
||||
async _ => {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
let counter = 0;
|
||||
|
||||
AntiTracking.runTest("Storage Access API called in a sandboxed iframe",
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* import-globals-from antitracking_head.js */
|
||||
|
||||
add_task(async function() {
|
||||
info("Starting subResources test");
|
||||
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
function handleRequest(aRequest, aResponse) {
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 200);
|
||||
let cookie = "";
|
||||
if (aRequest.hasHeader("Cookie")) {
|
||||
cookie = aRequest.getHeader("Cookie");
|
||||
}
|
||||
aResponse.write("cookie:" + cookie);
|
||||
|
||||
if (aRequest.queryString) {
|
||||
aResponse.setHeader("Set-Cookie", "foopy=" + aRequest.queryString);
|
||||
}
|
||||
}
|
|
@ -1,10 +1,3 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_DOMAIN = "http://example.net/";
|
||||
const TEST_DOMAIN_2 = "http://xn--exmple-cua.test/";
|
||||
const TEST_DOMAIN_3 = "https://xn--hxajbheg2az3al.xn--jxalpdlp/";
|
||||
|
@ -32,7 +25,6 @@ const TEST_3RD_PARTY_PAGE_UI = TEST_3RD_PARTY_DOMAIN + TEST_PATH + "3rdPartyUI.h
|
|||
const TEST_3RD_PARTY_PAGE_WITH_SVG = TEST_3RD_PARTY_DOMAIN + TEST_PATH + "3rdPartySVG.html";
|
||||
const TEST_4TH_PARTY_PAGE = TEST_4TH_PARTY_DOMAIN + TEST_PATH + "3rdParty.html";
|
||||
const TEST_ANOTHER_3RD_PARTY_PAGE = TEST_ANOTHER_3RD_PARTY_DOMAIN + TEST_PATH + "3rdParty.html";
|
||||
const TEST_3RD_PARTY_STORAGE_PAGE = TEST_3RD_PARTY_DOMAIN + TEST_PATH + "3rdPartyStorage.html";
|
||||
|
||||
const BEHAVIOR_ACCEPT = Ci.nsICookieService.BEHAVIOR_ACCEPT;
|
||||
const BEHAVIOR_REJECT = Ci.nsICookieService.BEHAVIOR_REJECT;
|
||||
|
@ -40,14 +32,704 @@ const BEHAVIOR_LIMIT_FOREIGN = Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN;
|
|||
const BEHAVIOR_REJECT_FOREIGN = Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN;
|
||||
const BEHAVIOR_REJECT_TRACKER = Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER;
|
||||
|
||||
var gFeatures = undefined;
|
||||
|
||||
let {UrlClassifierTestUtils} = ChromeUtils.import("resource://testing-common/UrlClassifierTestUtils.jsm");
|
||||
|
||||
requestLongerTimeout(3);
|
||||
|
||||
const {UrlClassifierTestUtils} = ChromeUtils.import("resource://testing-common/UrlClassifierTestUtils.jsm");
|
||||
this.AntiTracking = {
|
||||
runTest(name, callbackTracking, callbackNonTracking, cleanupFunction, extraPrefs,
|
||||
windowOpenTest = true, userInteractionTest = true,
|
||||
expectedBlockingNotifications = Ci.nsIWebProgressListener.STATE_COOKIES_BLOCKED_TRACKER,
|
||||
runInPrivateWindow = false, iframeSandbox = null, accessRemoval = null,
|
||||
callbackAfterRemoval = null) {
|
||||
// Here we want to test that a 3rd party context is simply blocked.
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_REJECT_TRACKER,
|
||||
blockingByContentBlockingRTUI: true,
|
||||
allowList: false,
|
||||
callback: callbackTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval,
|
||||
callbackAfterRemoval,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/toolkit/components/antitracking/test/browser/antitracking_head.js",
|
||||
this);
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_REJECT_TRACKER,
|
||||
blockingByContentBlockingRTUI: false,
|
||||
allowList: true,
|
||||
callback: callbackTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval,
|
||||
callbackAfterRemoval,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/toolkit/components/antitracking/test/browser/storageprincipal_head.js",
|
||||
this);
|
||||
if (callbackNonTracking) {
|
||||
let runExtraTests = true;
|
||||
let options = {};
|
||||
if (typeof callbackNonTracking == "object") {
|
||||
options.callback = callbackNonTracking.callback;
|
||||
runExtraTests = callbackNonTracking.runExtraTests;
|
||||
if ("cookieBehavior" in callbackNonTracking) {
|
||||
options.cookieBehavior = callbackNonTracking.cookieBehavior;
|
||||
} else {
|
||||
options.cookieBehavior = BEHAVIOR_ACCEPT;
|
||||
}
|
||||
if ("blockingByContentBlockingRTUI" in callbackNonTracking) {
|
||||
options.blockingByContentBlockingRTUI =
|
||||
callbackNonTracking.blockingByContentBlockingRTUI;
|
||||
} else {
|
||||
options.blockingByContentBlockingRTUI = false;
|
||||
}
|
||||
if ("blockingByAllowList" in callbackNonTracking) {
|
||||
options.blockingByAllowList =
|
||||
callbackNonTracking.blockingByAllowList;
|
||||
} else {
|
||||
options.blockingByAllowList = false;
|
||||
}
|
||||
callbackNonTracking = options.callback;
|
||||
options.accessRemoval = null;
|
||||
options.callbackAfterRemoval = null;
|
||||
}
|
||||
|
||||
// Phase 1: Here we want to test that a 3rd party context is not blocked if pref is off.
|
||||
if (runExtraTests) {
|
||||
// There are five ways in which the third-party context may not be blocked:
|
||||
// * If the cookieBehavior pref causes it to not be blocked.
|
||||
// * If the contentBlocking pref causes it to not be blocked.
|
||||
// * If both of these prefs cause it to not be blocked.
|
||||
// * If the top-level page is on the content blocking allow list.
|
||||
// * If the contentBlocking third-party cookies UI pref is off, the allow list will be ignored.
|
||||
// All of these cases are tested here.
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_ACCEPT,
|
||||
blockingByContentBlockingRTUI: true,
|
||||
allowList: false,
|
||||
callback: callbackNonTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications: 0,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval: null, // only passed with non-blocking callback
|
||||
callbackAfterRemoval: null,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_ACCEPT,
|
||||
blockingByContentBlockingRTUI: false,
|
||||
allowList: true,
|
||||
callback: callbackNonTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications: 0,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval: null, // only passed with non-blocking callback
|
||||
callbackAfterRemoval: null,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_ACCEPT,
|
||||
blockingByContentBlockingRTUI: false,
|
||||
allowList: false,
|
||||
callback: callbackNonTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications: 0,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval: null, // only passed with non-blocking callback
|
||||
callbackAfterRemoval: null,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_REJECT,
|
||||
blockingByContentBlockingRTUI: true,
|
||||
allowList: false,
|
||||
callback: callbackTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications: 0,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval: null, // only passed with non-blocking callback
|
||||
callbackAfterRemoval: null,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_LIMIT_FOREIGN,
|
||||
blockingByContentBlockingRTUI: true,
|
||||
allowList: true,
|
||||
callback: callbackNonTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications: 0,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval: null, // only passed with non-blocking callback
|
||||
callbackAfterRemoval: null,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_REJECT_FOREIGN,
|
||||
blockingByContentBlockingRTUI: true,
|
||||
allowList: true,
|
||||
callback: callbackNonTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications: 0,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval: null, // only passed with non-blocking callback
|
||||
callbackAfterRemoval: null,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_REJECT_TRACKER,
|
||||
blockingByContentBlockingRTUI: true,
|
||||
allowList: true,
|
||||
callback: callbackNonTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications: 0,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval,
|
||||
callbackAfterRemoval,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
|
||||
this._createTask({
|
||||
name,
|
||||
cookieBehavior: BEHAVIOR_REJECT_TRACKER,
|
||||
blockingByContentBlockingRTUI: false,
|
||||
allowList: false,
|
||||
callback: callbackNonTracking,
|
||||
extraPrefs,
|
||||
expectedBlockingNotifications: false,
|
||||
runInPrivateWindow,
|
||||
iframeSandbox,
|
||||
accessRemoval: null, // only passed with non-blocking callback
|
||||
callbackAfterRemoval: null,
|
||||
thirdPartyPage: TEST_ANOTHER_3RD_PARTY_PAGE,
|
||||
});
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
}
|
||||
|
||||
// Phase 2: Here we want to test that a third-party context doesn't
|
||||
// get blocked with when the same origin is opened through window.open().
|
||||
if (windowOpenTest) {
|
||||
this._createWindowOpenTask(name, callbackTracking, callbackNonTracking,
|
||||
runInPrivateWindow, iframeSandbox, extraPrefs);
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
}
|
||||
|
||||
// Phase 3: Here we want to test that a third-party context doesn't
|
||||
// get blocked with user interaction present
|
||||
if (userInteractionTest) {
|
||||
this._createUserInteractionTask(name, callbackTracking, callbackNonTracking,
|
||||
runInPrivateWindow, iframeSandbox, extraPrefs);
|
||||
this._createCleanupTask(cleanupFunction);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async interactWithTracker() {
|
||||
let windowClosed = new Promise(resolve => {
|
||||
Services.ww.registerNotification(function notification(aSubject, aTopic, aData) {
|
||||
if (aTopic == "domwindowclosed") {
|
||||
Services.ww.unregisterNotification(notification);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
info("Let's interact with the tracker");
|
||||
window.open(TEST_3RD_PARTY_DOMAIN + TEST_PATH + "3rdPartyOpenUI.html");
|
||||
await windowClosed;
|
||||
},
|
||||
|
||||
async _setupTest(win, cookieBehavior, blockingByContentBlockingRTUI,
|
||||
extraPrefs) {
|
||||
await SpecialPowers.flushPrefEnv();
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.storage_access.enabled", true],
|
||||
["browser.contentblocking.allowlist.annotations.enabled", blockingByContentBlockingRTUI],
|
||||
["browser.contentblocking.allowlist.storage.enabled", blockingByContentBlockingRTUI],
|
||||
["network.cookie.cookieBehavior", cookieBehavior],
|
||||
["privacy.trackingprotection.enabled", false],
|
||||
["privacy.trackingprotection.pbmode.enabled", false],
|
||||
["privacy.trackingprotection.annotate_channels", cookieBehavior != BEHAVIOR_ACCEPT],
|
||||
[win.ContentBlocking.prefIntroCount, win.ContentBlocking.MAX_INTROS],
|
||||
["privacy.restrict3rdpartystorage.userInteractionRequiredForHosts", "tracking.example.com,tracking.example.org"],
|
||||
]});
|
||||
|
||||
if (extraPrefs && Array.isArray(extraPrefs) && extraPrefs.length) {
|
||||
await SpecialPowers.pushPrefEnv({"set": extraPrefs });
|
||||
|
||||
for (let item of extraPrefs) {
|
||||
// When setting up skip URLs, we need to wait to ensure our prefs
|
||||
// actually take effect. In order to do this, we set up a skip list
|
||||
// observer and wait until it calls us back.
|
||||
if (item[0] == "urlclassifier.trackingAnnotationSkipURLs") {
|
||||
info("Waiting for the skip list service to initialize...");
|
||||
let classifier = Cc["@mozilla.org/url-classifier/dbservice;1"]
|
||||
.getService(Ci.nsIURIClassifier);
|
||||
let feature = classifier.getFeatureByName("tracking-annotation");
|
||||
await TestUtils.waitForCondition(() => feature.skipHostList == item[1].toLowerCase(),
|
||||
"Skip list service initialized");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await UrlClassifierTestUtils.addTestTrackers();
|
||||
},
|
||||
|
||||
_createTask(options) {
|
||||
add_task(async function() {
|
||||
info("Starting " + (options.cookieBehavior != BEHAVIOR_ACCEPT ? "blocking" : "non-blocking") + " cookieBehavior (" + options.cookieBehavior + ") and " +
|
||||
(options.blockingByContentBlockingRTUI ? "" : "no") + " contentBlocking third-party cookies UI with" +
|
||||
(options.allowList ? "" : "out") + " allow list test " + options.name +
|
||||
" running in a " + (options.runInPrivateWindow ? "private" : "normal") + " window " +
|
||||
" with iframe sandbox set to " + options.iframeSandbox +
|
||||
" and access removal set to " + options.accessRemoval +
|
||||
(typeof options.thirdPartyPage == "string" ? (
|
||||
" and third party page set to " + options.thirdPartyPage) : ""));
|
||||
|
||||
is(!!options.callbackAfterRemoval, !!options.accessRemoval,
|
||||
"callbackAfterRemoval must be passed when accessRemoval is non-null");
|
||||
|
||||
let win = window;
|
||||
if (options.runInPrivateWindow) {
|
||||
win = OpenBrowserWindow({private: true});
|
||||
await TestUtils.topicObserved("browser-delayed-startup-finished");
|
||||
}
|
||||
|
||||
await AntiTracking._setupTest(win, options.cookieBehavior,
|
||||
options.blockingByContentBlockingRTUI,
|
||||
options.extraPrefs);
|
||||
|
||||
let cookieBlocked = 0;
|
||||
let listener = {
|
||||
onContentBlockingEvent(webProgress, request, event) {
|
||||
if ((event & options.expectedBlockingNotifications)) {
|
||||
++cookieBlocked;
|
||||
}
|
||||
},
|
||||
};
|
||||
win.gBrowser.addProgressListener(listener);
|
||||
|
||||
info("Creating a new tab");
|
||||
let tab = BrowserTestUtils.addTab(win.gBrowser, TEST_TOP_PAGE);
|
||||
win.gBrowser.selectedTab = tab;
|
||||
|
||||
let browser = win.gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
if (options.allowList) {
|
||||
info("Disabling content blocking for this page");
|
||||
win.ContentBlocking.disableForCurrentPage();
|
||||
|
||||
// The previous function reloads the browser, so wait for it to load again!
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
}
|
||||
|
||||
info("Creating a 3rd party content");
|
||||
let doAccessRemovalChecks = typeof options.accessRemoval == "string" &&
|
||||
options.cookieBehavior == BEHAVIOR_REJECT_TRACKER &&
|
||||
options.blockingByContentBlockingRTUI &&
|
||||
!options.allowList;
|
||||
let thirdPartyPage;
|
||||
if (typeof options.thirdPartyPage == "string") {
|
||||
thirdPartyPage = options.thirdPartyPage;
|
||||
} else {
|
||||
thirdPartyPage = TEST_3RD_PARTY_PAGE;
|
||||
}
|
||||
await ContentTask.spawn(browser,
|
||||
{ page: thirdPartyPage,
|
||||
nextPage: TEST_4TH_PARTY_PAGE,
|
||||
callback: options.callback.toString(),
|
||||
callbackAfterRemoval: options.callbackAfterRemoval ?
|
||||
options.callbackAfterRemoval.toString() : null,
|
||||
accessRemoval: options.accessRemoval,
|
||||
iframeSandbox: options.iframeSandbox,
|
||||
allowList: options.allowList,
|
||||
doAccessRemovalChecks },
|
||||
async function(obj) {
|
||||
let id = "id" + Math.random();
|
||||
await new content.Promise(resolve => {
|
||||
let ifr = content.document.createElement("iframe");
|
||||
ifr.id = id;
|
||||
ifr.onload = function() {
|
||||
info("Sending code to the 3rd party content");
|
||||
let callback = obj.allowList + "!!!" + obj.callback;
|
||||
ifr.contentWindow.postMessage(callback, "*");
|
||||
};
|
||||
if (typeof obj.iframeSandbox == "string") {
|
||||
ifr.setAttribute("sandbox", obj.iframeSandbox);
|
||||
}
|
||||
|
||||
content.addEventListener("message", function msg(event) {
|
||||
if (event.data.type == "finish") {
|
||||
content.removeEventListener("message", msg);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "ok") {
|
||||
ok(event.data.what, event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "info") {
|
||||
info(event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, "Unknown message");
|
||||
});
|
||||
|
||||
content.document.body.appendChild(ifr);
|
||||
ifr.src = obj.page;
|
||||
});
|
||||
|
||||
if (obj.doAccessRemovalChecks) {
|
||||
info(`Running after removal checks (${obj.accessRemoval})`);
|
||||
switch (obj.accessRemoval) {
|
||||
case "navigate-subframe":
|
||||
await new content.Promise(resolve => {
|
||||
let ifr = content.document.getElementById(id);
|
||||
let oldWindow = ifr.contentWindow;
|
||||
ifr.onload = function() {
|
||||
info("Sending code to the old 3rd party content");
|
||||
oldWindow.postMessage(obj.callbackAfterRemoval, "*");
|
||||
};
|
||||
if (typeof obj.iframeSandbox == "string") {
|
||||
ifr.setAttribute("sandbox", obj.iframeSandbox);
|
||||
}
|
||||
|
||||
content.addEventListener("message", function msg(event) {
|
||||
if (event.data.type == "finish") {
|
||||
content.removeEventListener("message", msg);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "ok") {
|
||||
ok(event.data.what, event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "info") {
|
||||
info(event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, "Unknown message");
|
||||
});
|
||||
|
||||
ifr.src = obj.nextPage;
|
||||
});
|
||||
break;
|
||||
default:
|
||||
ok(false, "Unexpected accessRemoval code passed: " + obj.accessRemoval);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (options.allowList) {
|
||||
info("Enabling content blocking for this page");
|
||||
win.ContentBlocking.enableForCurrentPage();
|
||||
|
||||
// The previous function reloads the browser, so wait for it to load again!
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
}
|
||||
|
||||
win.gBrowser.removeProgressListener(listener);
|
||||
|
||||
is(!!cookieBlocked, !!options.expectedBlockingNotifications, "Checking cookie blocking notifications");
|
||||
|
||||
info("Removing the tab");
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
if (options.runInPrivateWindow) {
|
||||
win.close();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_createCleanupTask(cleanupFunction) {
|
||||
add_task(async function() {
|
||||
info("Cleaning up.");
|
||||
if (cleanupFunction) {
|
||||
await cleanupFunction();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_createWindowOpenTask(name, blockingCallback, nonBlockingCallback, runInPrivateWindow,
|
||||
iframeSandbox, extraPrefs) {
|
||||
add_task(async function() {
|
||||
info("Starting window-open test " + name);
|
||||
|
||||
let win = window;
|
||||
if (runInPrivateWindow) {
|
||||
win = OpenBrowserWindow({private: true});
|
||||
await TestUtils.topicObserved("browser-delayed-startup-finished");
|
||||
}
|
||||
|
||||
await AntiTracking._setupTest(win, BEHAVIOR_REJECT_TRACKER, true, extraPrefs);
|
||||
|
||||
info("Creating a new tab");
|
||||
let tab = BrowserTestUtils.addTab(win.gBrowser, TEST_TOP_PAGE);
|
||||
win.gBrowser.selectedTab = tab;
|
||||
|
||||
let browser = win.gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
let pageURL = TEST_3RD_PARTY_PAGE_WO;
|
||||
if (gFeatures == "noopener") {
|
||||
pageURL += "?noopener";
|
||||
}
|
||||
|
||||
info("Creating a 3rd party content");
|
||||
await ContentTask.spawn(browser,
|
||||
{ page: pageURL,
|
||||
blockingCallback: blockingCallback.toString(),
|
||||
nonBlockingCallback: nonBlockingCallback.toString(),
|
||||
iframeSandbox,
|
||||
},
|
||||
async function(obj) {
|
||||
await new content.Promise(resolve => {
|
||||
let ifr = content.document.createElement("iframe");
|
||||
ifr.onload = function() {
|
||||
info("Sending code to the 3rd party content");
|
||||
ifr.contentWindow.postMessage(obj, "*");
|
||||
};
|
||||
if (typeof obj.iframeSandbox == "string") {
|
||||
ifr.setAttribute("sandbox", obj.iframeSandbox);
|
||||
}
|
||||
|
||||
content.addEventListener("message", function msg(event) {
|
||||
if (event.data.type == "finish") {
|
||||
content.removeEventListener("message", msg);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "ok") {
|
||||
ok(event.data.what, event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "info") {
|
||||
info(event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, "Unknown message");
|
||||
});
|
||||
|
||||
content.document.body.appendChild(ifr);
|
||||
ifr.src = obj.page;
|
||||
});
|
||||
});
|
||||
|
||||
info("Removing the tab");
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
if (runInPrivateWindow) {
|
||||
win.close();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_createUserInteractionTask(name, blockingCallback, nonBlockingCallback,
|
||||
runInPrivateWindow, iframeSandbox, extraPrefs) {
|
||||
add_task(async function() {
|
||||
info("Starting user-interaction test " + name);
|
||||
|
||||
let win = window;
|
||||
if (runInPrivateWindow) {
|
||||
win = OpenBrowserWindow({private: true});
|
||||
await TestUtils.topicObserved("browser-delayed-startup-finished");
|
||||
}
|
||||
|
||||
await AntiTracking._setupTest(win, BEHAVIOR_REJECT_TRACKER, true, extraPrefs);
|
||||
|
||||
info("Creating a new tab");
|
||||
let tab = BrowserTestUtils.addTab(win.gBrowser, TEST_TOP_PAGE);
|
||||
win.gBrowser.selectedTab = tab;
|
||||
|
||||
let browser = win.gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
info("Creating a 3rd party content");
|
||||
await ContentTask.spawn(browser,
|
||||
{ page: TEST_3RD_PARTY_PAGE_UI,
|
||||
popup: TEST_POPUP_PAGE,
|
||||
blockingCallback: blockingCallback.toString(),
|
||||
iframeSandbox,
|
||||
},
|
||||
async function(obj) {
|
||||
let ifr = content.document.createElement("iframe");
|
||||
let loading = new content.Promise(resolve => { ifr.onload = resolve; });
|
||||
if (typeof obj.iframeSandbox == "string") {
|
||||
ifr.setAttribute("sandbox", obj.iframeSandbox);
|
||||
}
|
||||
content.document.body.appendChild(ifr);
|
||||
ifr.src = obj.page;
|
||||
await loading;
|
||||
|
||||
info("The 3rd party content should not have access to first party storage.");
|
||||
await new content.Promise(resolve => {
|
||||
content.addEventListener("message", function msg(event) {
|
||||
if (event.data.type == "finish") {
|
||||
content.removeEventListener("message", msg);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "ok") {
|
||||
ok(event.data.what, event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "info") {
|
||||
info(event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, "Unknown message");
|
||||
});
|
||||
ifr.contentWindow.postMessage({ callback: obj.blockingCallback }, "*");
|
||||
});
|
||||
|
||||
let windowClosed = new content.Promise(resolve => {
|
||||
Services.ww.registerNotification(function notification(aSubject, aTopic, aData) {
|
||||
if (aTopic == "domwindowclosed") {
|
||||
Services.ww.unregisterNotification(notification);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
info("Opening a window from the iframe.");
|
||||
ifr.contentWindow.open(obj.popup);
|
||||
|
||||
info("Let's wait for the window to be closed");
|
||||
await windowClosed;
|
||||
|
||||
info("First time, the 3rd party content should not have access to first party storage " +
|
||||
"because the tracker did not have user interaction");
|
||||
await new content.Promise(resolve => {
|
||||
content.addEventListener("message", function msg(event) {
|
||||
if (event.data.type == "finish") {
|
||||
content.removeEventListener("message", msg);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "ok") {
|
||||
ok(event.data.what, event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "info") {
|
||||
info(event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, "Unknown message");
|
||||
});
|
||||
ifr.contentWindow.postMessage({ callback: obj.blockingCallback }, "*");
|
||||
});
|
||||
});
|
||||
|
||||
await AntiTracking.interactWithTracker();
|
||||
|
||||
await ContentTask.spawn(browser,
|
||||
{ page: TEST_3RD_PARTY_PAGE_UI,
|
||||
popup: TEST_POPUP_PAGE,
|
||||
nonBlockingCallback: nonBlockingCallback.toString(),
|
||||
iframeSandbox,
|
||||
},
|
||||
async function(obj) {
|
||||
let ifr = content.document.createElement("iframe");
|
||||
let loading = new content.Promise(resolve => { ifr.onload = resolve; });
|
||||
if (typeof obj.iframeSandbox == "string") {
|
||||
ifr.setAttribute("sandbox", obj.iframeSandbox);
|
||||
}
|
||||
content.document.body.appendChild(ifr);
|
||||
ifr.src = obj.page;
|
||||
await loading;
|
||||
|
||||
let windowClosed = new content.Promise(resolve => {
|
||||
Services.ww.registerNotification(function notification(aSubject, aTopic, aData) {
|
||||
if (aTopic == "domwindowclosed") {
|
||||
Services.ww.unregisterNotification(notification);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
info("Opening a window from the iframe.");
|
||||
ifr.contentWindow.open(obj.popup);
|
||||
|
||||
info("Let's wait for the window to be closed");
|
||||
await windowClosed;
|
||||
|
||||
info("The 3rd party content should now have access to first party storage.");
|
||||
await new content.Promise(resolve => {
|
||||
content.addEventListener("message", function msg(event) {
|
||||
if (event.data.type == "finish") {
|
||||
content.removeEventListener("message", msg);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "ok") {
|
||||
ok(event.data.what, event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "info") {
|
||||
info(event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, "Unknown message");
|
||||
});
|
||||
ifr.contentWindow.postMessage({ callback: obj.nonBlockingCallback }, "*");
|
||||
});
|
||||
});
|
||||
|
||||
info("Removing the tab");
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
if (runInPrivateWindow) {
|
||||
win.close();
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
/* import-globals-from head.js */
|
||||
/* import-globals-from antitracking_head.js */
|
||||
/* import-globals-from browser_imageCache4.js */
|
||||
|
||||
AntiTracking.runTest("Image cache - should load the image three times.",
|
||||
// blocking callback
|
||||
async _ => {
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
self.addEventListener("message", async e => {
|
||||
let clients = await self.clients.matchAll({type: "window", includeUncontrolled: true});
|
||||
|
||||
let hasWindow = false;
|
||||
for (let client of clients) {
|
||||
if (e.data == client.url) {
|
||||
hasWindow = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
e.source.postMessage(hasWindow);
|
||||
});
|
|
@ -1,18 +0,0 @@
|
|||
let ports = 0;
|
||||
self.onconnect = e => {
|
||||
++ports;
|
||||
e.ports[0].onmessage = event => {
|
||||
if (event.data === "count") {
|
||||
e.ports[0].postMessage(ports);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data === "close") {
|
||||
self.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// Error.
|
||||
e.ports[0].postMessage(-1);
|
||||
};
|
||||
};
|
|
@ -1,89 +0,0 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* import-globals-from head.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.StoragePrincipalHelper = {
|
||||
runTest(name, callback, cleanupFunction, extraPrefs) {
|
||||
add_task(async _ => {
|
||||
info("Starting test `" + name + "'...");
|
||||
|
||||
await SpecialPowers.flushPrefEnv();
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.storage_access.enabled", true],
|
||||
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER],
|
||||
["privacy.trackingprotection.enabled", false],
|
||||
["privacy.trackingprotection.pbmode.enabled", false],
|
||||
["privacy.trackingprotection.annotate_channels", true],
|
||||
["privacy.storagePrincipal.enabledForTrackers", true],
|
||||
]});
|
||||
|
||||
if (extraPrefs && Array.isArray(extraPrefs) && extraPrefs.length) {
|
||||
await SpecialPowers.pushPrefEnv({"set": extraPrefs });
|
||||
}
|
||||
|
||||
await UrlClassifierTestUtils.addTestTrackers();
|
||||
|
||||
info("Creating a new tab");
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, TEST_TOP_PAGE);
|
||||
gBrowser.selectedTab = tab;
|
||||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
info("Creating a 3rd party content");
|
||||
await ContentTask.spawn(browser, {
|
||||
page: TEST_3RD_PARTY_STORAGE_PAGE,
|
||||
callback: callback.toString(),
|
||||
},
|
||||
async obj => {
|
||||
await new content.Promise(resolve => {
|
||||
let ifr = content.document.createElement("iframe");
|
||||
ifr.onload = __ => {
|
||||
is(ifr.contentWindow.document.nodePrincipal.originAttributes.firstPartyDomain, "", "We don't have first-party set on nodePrincipal");
|
||||
is(ifr.contentWindow.document.effectiveStoragePrincipal.originAttributes.firstPartyDomain, "example.net", "We have first-party set on storagePrincipal");
|
||||
info("Sending code to the 3rd party content");
|
||||
ifr.contentWindow.postMessage(obj.callback, "*");
|
||||
};
|
||||
|
||||
content.addEventListener("message", function msg(event) {
|
||||
if (event.data.type == "finish") {
|
||||
content.removeEventListener("message", msg);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "ok") {
|
||||
ok(event.data.what, event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "info") {
|
||||
info(event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, "Unknown message");
|
||||
});
|
||||
|
||||
content.document.body.appendChild(ifr);
|
||||
ifr.src = obj.page;
|
||||
});
|
||||
});
|
||||
|
||||
info("Removing the tab");
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(async _ => {
|
||||
info("Cleaning up.");
|
||||
if (cleanupFunction) {
|
||||
await cleanupFunction();
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
Загрузка…
Ссылка в новой задаче