From ecd5aada04baf4dc925bd7886b8ef7ceecd7d024 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 15 Oct 2018 10:29:33 +0000 Subject: [PATCH] Bug 1498370 - Update the storage access flag when storage access is granted/denied r=baku Differential Revision: https://phabricator.services.mozilla.com/D8550 --HG-- extra : moz-landing-system : lando --- dom/base/nsDocument.cpp | 25 -------- dom/base/nsGlobalWindowOuter.cpp | 62 +++++++++++++++++++ dom/base/nsGlobalWindowOuter.h | 5 ++ .../antitracking/AntiTrackingCommon.cpp | 36 +++++++++++ .../antitracking/AntiTrackingCommon.h | 6 ++ 5 files changed, 109 insertions(+), 25 deletions(-) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 79d7bd77cf48..7a7f00e5b445 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -13669,31 +13669,6 @@ nsIDocument::HasStorageAccess(mozilla::ErrorResult& aRv) return promise.forget(); } - if (AntiTrackingCommon::ShouldHonorContentBlockingCookieRestrictions() && - StaticPrefs::network_cookie_cookieBehavior() == - nsICookieService::BEHAVIOR_REJECT_TRACKER) { - // If we need to abide by Content Blocking cookie restrictions, ensure to - // first do all of our storage access checks. If storage access isn't - // disabled in our document, given that we're a third-party, we must either - // not be a tracker, or be whitelisted for some reason (e.g. a storage - // access permission being granted). In that case, resolve the promise and - // say we have obtained storage access. - if (!nsContentUtils::StorageDisabledByAntiTracking(this, nullptr)) { - // Note, storage might be allowed because the top-level document is on - // the content blocking allowlist! In that case, don't provide special - // treatment here. - bool isOnAllowList = false; - if (NS_SUCCEEDED(AntiTrackingCommon::IsOnContentBlockingAllowList( - topLevelDoc->GetDocumentURI(), - AntiTrackingCommon::eStorageChecks, - isOnAllowList)) && - !isOnAllowList) { - promise->MaybeResolve(true); - return promise.forget(); - } - } - } - nsPIDOMWindowInner* inner = GetInnerWindow(); nsGlobalWindowOuter* outer = nullptr; if (inner) { diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp index d94d7c7c1391..0f0bd47feca9 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -18,6 +18,8 @@ #include "nsDOMNavigationTiming.h" #include "nsICookieService.h" #include "nsIDOMStorageManager.h" +#include "nsIPermission.h" +#include "nsIPermissionManager.h" #include "nsISecureBrowserUI.h" #include "nsIWebProgressListener.h" #include "mozilla/AntiTrackingCommon.h" @@ -978,6 +980,11 @@ nsGlobalWindowOuter::~nsGlobalWindowOuter() if (ac) ac->RemoveWindowAsListener(this); + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (obs) { + obs->RemoveObserver(this, PERM_CHANGE_NOTIFICATION); + } + nsLayoutStatics::Release(); } @@ -1089,6 +1096,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindowOuter) NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMChromeWindow, IsChromeWindow()) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) + NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_END @@ -6802,6 +6810,56 @@ nsGlobalWindowOuter::GetInterface(const nsIID & aIID, void **aSink) return rv; } +//***************************************************************************** +// nsGlobalWindowOuter::nsIObserver +//***************************************************************************** + +NS_IMETHODIMP +nsGlobalWindowOuter::Observe(nsISupports* aSupports, const char* aTopic, + const char16_t* aData) +{ + if (!nsCRT::strcmp(aTopic, PERM_CHANGE_NOTIFICATION)) { + if (!nsCRT::strcmp(aData, u"cleared") && !aSupports) { + // All permissions have been cleared. + mHasStorageAccess = false; + return NS_OK; + } + nsCOMPtr permission = do_QueryInterface(aSupports); + if (!permission) { + return NS_OK; + } + nsIPrincipal* principal = GetPrincipal(); + if (!principal) { + return NS_OK; + } + if (!AntiTrackingCommon::IsStorageAccessPermission(permission, principal)) { + return NS_OK; + } + if (!nsCRT::strcmp(aData, u"deleted")) { + // The storage access permission was deleted. + mHasStorageAccess = false; + return NS_OK; + } + if (!nsCRT::strcmp(aData, u"added") || + !nsCRT::strcmp(aData, u"changed")) { + // The storage access permission was granted or modified. + uint32_t expireType = 0; + int64_t expireTime = 0; + MOZ_ALWAYS_SUCCEEDS(permission->GetExpireType(&expireType)); + MOZ_ALWAYS_SUCCEEDS(permission->GetExpireTime(&expireTime)); + if ((expireType == nsIPermissionManager::EXPIRE_TIME && + expireTime >= PR_Now() / 1000) || + (expireType == nsIPermissionManager::EXPIRE_SESSION && + expireTime != 0)) { + // Permission hasn't expired yet. + mHasStorageAccess = true; + return NS_OK; + } + } + } + return NS_OK; +} + bool nsGlobalWindowOuter::IsSuspended() const { @@ -7673,6 +7731,10 @@ nsGlobalWindowOuter::Create(nsIDocShell* aDocShell, bool aIsChrome) window->SetDocShell(aDocShell); window->InitWasOffline(); + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (obs) { + obs->AddObserver(window, PERM_CHANGE_NOTIFICATION, true); + } return window.forget(); } diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h index dfa827074440..526a37c6dbc2 100644 --- a/dom/base/nsGlobalWindowOuter.h +++ b/dom/base/nsGlobalWindowOuter.h @@ -27,6 +27,7 @@ #include "nsIBrowserDOMWindow.h" #include "nsIInterfaceRequestor.h" #include "nsIDOMChromeWindow.h" +#include "nsIObserver.h" #include "nsIScriptGlobalObject.h" #include "nsIScriptObjectPrincipal.h" #include "nsITimer.h" @@ -172,6 +173,7 @@ class nsGlobalWindowOuter final , public nsSupportsWeakReference , public nsIInterfaceRequestor , public PRCListStr + , public nsIObserver { public: typedef nsDataHashtable OuterWindowByIdTable; @@ -361,6 +363,9 @@ public: // nsIInterfaceRequestor NS_DECL_NSIINTERFACEREQUESTOR + // nsIObserver + NS_DECL_NSIOBSERVER + already_AddRefed IndexedGetterOuter(uint32_t aIndex); already_AddRefed GetTop() override; diff --git a/toolkit/components/antitracking/AntiTrackingCommon.cpp b/toolkit/components/antitracking/AntiTrackingCommon.cpp index 437110037568..139e2a814257 100644 --- a/toolkit/components/antitracking/AntiTrackingCommon.cpp +++ b/toolkit/components/antitracking/AntiTrackingCommon.cpp @@ -564,6 +564,42 @@ AntiTrackingCommon::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(n LOG(("Result: %s", NS_SUCCEEDED(rv) ? "success" : "failure")); } +// static +bool +AntiTrackingCommon::IsStorageAccessPermission(nsIPermission* aPermission, + nsIPrincipal* aPrincipal) +{ + MOZ_ASSERT(aPermission); + MOZ_ASSERT(aPrincipal); + + nsAutoCString origin; + nsresult rv = aPrincipal->GetOriginNoSuffix(origin); + if (NS_WARN_IF(NS_FAILED(rv))) { + return false; + } + + // The permission key may belong either to a tracking origin on the same + // origin as the granted origin, or on another origin as the granted origin + // (for example when a tracker in a third-party context uses window.open to + // open another origin where that second origin would be the granted origin.) + // But even in the second case, the type of the permission would still be + // formed by concatenating the granted origin to the end of the type name + // (see CreatePermissionKey). Therefore, we pass in the same argument to + // both tracking origin and granted origin here in order to compute the + // shorter permission key and will then do a prefix match on the type of the + // input permission to see if it is a storage access permission or not. + nsAutoCString permissionKey; + CreatePermissionKey(origin, origin, permissionKey); + + nsAutoCString type; + rv = aPermission->GetType(type); + if (NS_WARN_IF(NS_FAILED(rv))) { + return false; + } + + return StringBeginsWith(type, permissionKey); +} + bool AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* aWindow, nsIURI* aURI, diff --git a/toolkit/components/antitracking/AntiTrackingCommon.h b/toolkit/components/antitracking/AntiTrackingCommon.h index df83c50ece3a..ce5aba2d9235 100644 --- a/toolkit/components/antitracking/AntiTrackingCommon.h +++ b/toolkit/components/antitracking/AntiTrackingCommon.h @@ -13,6 +13,7 @@ class nsIChannel; class nsIHttpChannel; +class nsIPermission; class nsIPrincipal; class nsIURI; class nsPIDOMWindowInner; @@ -108,6 +109,11 @@ public: nsPIDOMWindowInner* aParentWindow, StorageAccessGrantedReason aReason); + // Returns true if the permission passed in is a storage access permission + // for the passed in principal argument. + static bool + IsStorageAccessPermission(nsIPermission* aPermission, nsIPrincipal* aPrincipal); + static void StoreUserInteractionFor(nsIPrincipal* aPrincipal);