зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1803601 - Part 1: Adding a Services.cookieBanners.setDomainPrefAndPersistInPrivateBrowsing() to allow persist cookie banner domain pref for the private browsing. r=pbz
This patch adds a new function setDomainPrefAndPersistInPrivateBrowsing() to nsICookieBannerService. This function allows persisting domain pref in the private browsing mode. Differential Revision: https://phabricator.services.mozilla.com/D164797
This commit is contained in:
Родитель
0be0de0347
Коммит
3bd7091229
|
@ -19,12 +19,15 @@
|
|||
#include "nsVariant.h"
|
||||
|
||||
#define COOKIE_BANNER_CONTENT_PREF_NAME u"cookiebanner"_ns
|
||||
#define COOKIE_BANNER_CONTENT_PREF_NAME_PRIVATE u"cookiebannerprivate"_ns
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
NS_IMPL_ISUPPORTS(CookieBannerDomainPrefService, nsIAsyncShutdownBlocker,
|
||||
nsIObserver)
|
||||
|
||||
NS_IMPL_ISUPPORTS(CookieBannerDomainPrefService::DomainPrefData, nsISupports)
|
||||
|
||||
LazyLogModule gCookieBannerPerSitePrefLog("CookieBannerDomainPref");
|
||||
|
||||
static StaticRefPtr<CookieBannerDomainPrefService>
|
||||
|
@ -90,7 +93,7 @@ void CookieBannerDomainPrefService::Init() {
|
|||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Fail to add observer for 'last-pb-context-exited'.");
|
||||
|
||||
auto initCallback = MakeRefPtr<InitialLoadContentPrefCallback>(this);
|
||||
auto initCallback = MakeRefPtr<InitialLoadContentPrefCallback>(this, false);
|
||||
|
||||
// Populate the content pref for cookie banner domain preferences.
|
||||
rv = contentPrefService->GetByName(COOKIE_BANNER_CONTENT_PREF_NAME, nullptr,
|
||||
|
@ -98,6 +101,15 @@ void CookieBannerDomainPrefService::Init() {
|
|||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Fail to get all content prefs during init.");
|
||||
|
||||
auto initPrivateCallback =
|
||||
MakeRefPtr<InitialLoadContentPrefCallback>(this, true);
|
||||
|
||||
// Populate the content pref for the private browsing.
|
||||
rv = contentPrefService->GetByName(COOKIE_BANNER_CONTENT_PREF_NAME_PRIVATE,
|
||||
nullptr, initPrivateCallback);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Fail to get all content prefs during init.");
|
||||
|
||||
rv = AddShutdownBlocker();
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
|
@ -123,10 +135,8 @@ void CookieBannerDomainPrefService::Shutdown() {
|
|||
|
||||
Maybe<nsICookieBannerService::Modes> CookieBannerDomainPrefService::GetPref(
|
||||
const nsACString& aDomain, bool aIsPrivate) {
|
||||
// For private windows, the domain prefs will only be stored in memory.
|
||||
if (aIsPrivate) {
|
||||
return mPrefsPrivate.MaybeGet(aDomain);
|
||||
}
|
||||
bool isContentPrefLoaded =
|
||||
aIsPrivate ? mIsPrivateContentPrefLoaded : mIsContentPrefLoaded;
|
||||
|
||||
// We return nothing if the first reading of the content pref is not completed
|
||||
// yet. Note that, we won't be able to get the domain pref for early loads.
|
||||
|
@ -135,16 +145,23 @@ Maybe<nsICookieBannerService::Modes> CookieBannerDomainPrefService::GetPref(
|
|||
// handling. So, there should be consent cookies in place to prevent banner
|
||||
// showing. In this case, our cookie injection and banner clicking won't do
|
||||
// anything.
|
||||
if (!mIsContentPrefLoaded) {
|
||||
if (!isContentPrefLoaded) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return mPrefs.MaybeGet(aDomain);
|
||||
Maybe<RefPtr<DomainPrefData>> data =
|
||||
aIsPrivate ? mPrefsPrivate.MaybeGet(aDomain) : mPrefs.MaybeGet(aDomain);
|
||||
|
||||
if (!data) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return Some(data.ref()->mMode);
|
||||
}
|
||||
|
||||
nsresult CookieBannerDomainPrefService::SetPref(
|
||||
const nsACString& aDomain, nsICookieBannerService::Modes aMode,
|
||||
bool aIsPrivate) {
|
||||
bool aIsPrivate, bool aPersistInPrivateBrowsing) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// Don't do anything if we are shutting down.
|
||||
if (NS_WARN_IF(mIsShuttingDown)) {
|
||||
|
@ -153,16 +170,36 @@ nsresult CookieBannerDomainPrefService::SetPref(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// For private windows, the domain prefs will only be stored in memory.
|
||||
if (aIsPrivate) {
|
||||
Unused << mPrefsPrivate.InsertOrUpdate(aDomain, aMode);
|
||||
return NS_OK;
|
||||
}
|
||||
EnsureInitCompleted(aIsPrivate);
|
||||
|
||||
EnsureInitCompleted();
|
||||
// Create the domain pref data. The data is always persistent for normal
|
||||
// windows. For private windows, the data is only persistent if requested.
|
||||
auto domainPrefData = MakeRefPtr<DomainPrefData>(
|
||||
aMode, aIsPrivate ? aPersistInPrivateBrowsing : true);
|
||||
bool wasPersistentInPrivate = false;
|
||||
|
||||
// Update the in-memory domain preference map.
|
||||
Unused << mPrefs.InsertOrUpdate(aDomain, aMode);
|
||||
if (aIsPrivate) {
|
||||
Maybe<RefPtr<DomainPrefData>> data = mPrefsPrivate.MaybeGet(aDomain);
|
||||
|
||||
wasPersistentInPrivate = data ? data.ref()->mIsPersistent : false;
|
||||
Unused << mPrefsPrivate.InsertOrUpdate(aDomain, domainPrefData);
|
||||
} else {
|
||||
Unused << mPrefs.InsertOrUpdate(aDomain, domainPrefData);
|
||||
}
|
||||
|
||||
// For private windows, the domain prefs will only be stored in memory.
|
||||
// Unless, this function is instructed to persist setting for private
|
||||
// browsing. To make the disk state consistent with the memory state, we need
|
||||
// to clear the domain pref in the disk when we no longer need to persist the
|
||||
// domain pref for the domain in PBM.
|
||||
if (!aPersistInPrivateBrowsing && aIsPrivate) {
|
||||
// Clear the domain pref in disk if it was persistent.
|
||||
if (wasPersistentInPrivate) {
|
||||
return RemoveContentPrefForDomain(aDomain, true);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Set the preference to the content pref service.
|
||||
nsCOMPtr<nsIContentPrefService2> contentPrefService =
|
||||
|
@ -178,8 +215,10 @@ nsresult CookieBannerDomainPrefService::SetPref(
|
|||
|
||||
// Store the domain preference to the content pref service.
|
||||
rv = contentPrefService->Set(NS_ConvertUTF8toUTF16(aDomain),
|
||||
COOKIE_BANNER_CONTENT_PREF_NAME, variant,
|
||||
nullptr, callback);
|
||||
aIsPrivate
|
||||
? COOKIE_BANNER_CONTENT_PREF_NAME_PRIVATE
|
||||
: COOKIE_BANNER_CONTENT_PREF_NAME,
|
||||
variant, nullptr, callback);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Fail to set cookie banner domain pref.");
|
||||
|
||||
|
@ -196,30 +235,16 @@ nsresult CookieBannerDomainPrefService::RemovePref(const nsACString& aDomain,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// For private windows, we only need to remove in-memory settings.
|
||||
EnsureInitCompleted(aIsPrivate);
|
||||
|
||||
// Clear in-memory domain pref.
|
||||
if (aIsPrivate) {
|
||||
mPrefsPrivate.Remove(aDomain);
|
||||
return NS_OK;
|
||||
} else {
|
||||
mPrefs.Remove(aDomain);
|
||||
}
|
||||
|
||||
EnsureInitCompleted();
|
||||
|
||||
mPrefs.Remove(aDomain);
|
||||
|
||||
nsCOMPtr<nsIContentPrefService2> contentPrefService =
|
||||
do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(contentPrefService, NS_ERROR_FAILURE);
|
||||
|
||||
auto callback = MakeRefPtr<WriteContentPrefCallback>(this);
|
||||
mWritingCount++;
|
||||
|
||||
// Remove the domain preference from the content pref service.
|
||||
nsresult rv = contentPrefService->RemoveByDomainAndName(
|
||||
NS_ConvertUTF8toUTF16(aDomain), COOKIE_BANNER_CONTENT_PREF_NAME, nullptr,
|
||||
callback);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Fail to remove cookie banner domain pref.");
|
||||
return rv;
|
||||
return RemoveContentPrefForDomain(aDomain, aIsPrivate);
|
||||
}
|
||||
|
||||
nsresult CookieBannerDomainPrefService::RemoveAll(bool aIsPrivate) {
|
||||
|
@ -231,16 +256,15 @@ nsresult CookieBannerDomainPrefService::RemoveAll(bool aIsPrivate) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// For private windows, we only need to remove in-memory settings.
|
||||
EnsureInitCompleted(aIsPrivate);
|
||||
|
||||
// Clear in-memory domain pref.
|
||||
if (aIsPrivate) {
|
||||
mPrefsPrivate.Clear();
|
||||
return NS_OK;
|
||||
} else {
|
||||
mPrefs.Clear();
|
||||
}
|
||||
|
||||
EnsureInitCompleted();
|
||||
|
||||
mPrefs.Clear();
|
||||
|
||||
nsCOMPtr<nsIContentPrefService2> contentPrefService =
|
||||
do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(contentPrefService, NS_ERROR_FAILURE);
|
||||
|
@ -250,21 +274,25 @@ nsresult CookieBannerDomainPrefService::RemoveAll(bool aIsPrivate) {
|
|||
|
||||
// Remove all the domain preferences.
|
||||
nsresult rv = contentPrefService->RemoveByName(
|
||||
COOKIE_BANNER_CONTENT_PREF_NAME, nullptr, callback);
|
||||
aIsPrivate ? COOKIE_BANNER_CONTENT_PREF_NAME_PRIVATE
|
||||
: COOKIE_BANNER_CONTENT_PREF_NAME,
|
||||
nullptr, callback);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Fail to remove all cookie banner domain prefs.");
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void CookieBannerDomainPrefService::EnsureInitCompleted() {
|
||||
if (mIsContentPrefLoaded) {
|
||||
void CookieBannerDomainPrefService::EnsureInitCompleted(bool aIsPrivate) {
|
||||
bool& isContentPrefLoaded =
|
||||
aIsPrivate ? mIsPrivateContentPrefLoaded : mIsContentPrefLoaded;
|
||||
if (isContentPrefLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait until the service is fully initialized.
|
||||
SpinEventLoopUntil("CookieBannerDomainPrefService::EnsureUpdateComplete"_ns,
|
||||
[&] { return mIsContentPrefLoaded; });
|
||||
[&] { return isContentPrefLoaded; });
|
||||
}
|
||||
|
||||
nsresult CookieBannerDomainPrefService::AddShutdownBlocker() {
|
||||
|
@ -287,6 +315,26 @@ nsresult CookieBannerDomainPrefService::RemoveShutdownBlocker() {
|
|||
return GetShutdownBarrier()->RemoveBlocker(this);
|
||||
}
|
||||
|
||||
nsresult CookieBannerDomainPrefService::RemoveContentPrefForDomain(
|
||||
const nsACString& aDomain, bool aIsPrivate) {
|
||||
nsCOMPtr<nsIContentPrefService2> contentPrefService =
|
||||
do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(contentPrefService, NS_ERROR_FAILURE);
|
||||
|
||||
auto callback = MakeRefPtr<WriteContentPrefCallback>(this);
|
||||
mWritingCount++;
|
||||
|
||||
// Remove the domain preference from the content pref service.
|
||||
nsresult rv = contentPrefService->RemoveByDomainAndName(
|
||||
NS_ConvertUTF8toUTF16(aDomain),
|
||||
aIsPrivate ? COOKIE_BANNER_CONTENT_PREF_NAME_PRIVATE
|
||||
: COOKIE_BANNER_CONTENT_PREF_NAME,
|
||||
nullptr, callback);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Fail to remove cookie banner domain pref.");
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(CookieBannerDomainPrefService::BaseContentPrefCallback,
|
||||
nsIContentPrefCallback2)
|
||||
|
||||
|
@ -312,8 +360,17 @@ CookieBannerDomainPrefService::InitialLoadContentPrefCallback::HandleResult(
|
|||
rv = value->GetAsUint8(&data);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
Unused << mService->mPrefs.InsertOrUpdate(
|
||||
NS_ConvertUTF16toUTF8(domain), nsICookieBannerService::Modes(data));
|
||||
// Create the domain pref data and indicate it's persistent.
|
||||
auto domainPrefData =
|
||||
MakeRefPtr<DomainPrefData>(nsICookieBannerService::Modes(data), true);
|
||||
|
||||
if (mIsPrivate) {
|
||||
Unused << mService->mPrefsPrivate.InsertOrUpdate(
|
||||
NS_ConvertUTF16toUTF8(domain), domainPrefData);
|
||||
} else {
|
||||
Unused << mService->mPrefs.InsertOrUpdate(NS_ConvertUTF16toUTF8(domain),
|
||||
domainPrefData);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -323,7 +380,11 @@ CookieBannerDomainPrefService::InitialLoadContentPrefCallback::HandleCompletion(
|
|||
uint16_t aReason) {
|
||||
MOZ_ASSERT(mService);
|
||||
|
||||
mService->mIsContentPrefLoaded = true;
|
||||
if (mIsPrivate) {
|
||||
mService->mIsPrivateContentPrefLoaded = true;
|
||||
} else {
|
||||
mService->mIsContentPrefLoaded = true;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -385,9 +446,12 @@ CookieBannerDomainPrefService::Observe(nsISupports* /*aSubject*/,
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Clear the private browsing domain prefs if we observe the private browsing
|
||||
// session has ended.
|
||||
mPrefsPrivate.Clear();
|
||||
// Clear the private browsing domain prefs that are not persistent when we
|
||||
// observe the private browsing session has ended.
|
||||
mPrefsPrivate.RemoveIf([](const auto& iter) {
|
||||
const RefPtr<DomainPrefData>& data = iter.Data();
|
||||
return !data->mIsPersistent;
|
||||
});
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,8 @@ class CookieBannerDomainPrefService final : public nsIAsyncShutdownBlocker,
|
|||
// Set the preference for the given domain.
|
||||
[[nodiscard]] nsresult SetPref(const nsACString& aDomain,
|
||||
nsICookieBannerService::Modes aMode,
|
||||
bool aIsPrivate);
|
||||
bool aIsPrivate,
|
||||
bool aPersistInPrivateBrowsing);
|
||||
|
||||
// Remove the preference for the given domain.
|
||||
[[nodiscard]] nsresult RemovePref(const nsACString& aDomain, bool aIsPrivate);
|
||||
|
@ -54,6 +55,7 @@ class CookieBannerDomainPrefService final : public nsIAsyncShutdownBlocker,
|
|||
CookieBannerDomainPrefService()
|
||||
: mIsInitialized(false),
|
||||
mIsContentPrefLoaded(false),
|
||||
mIsPrivateContentPrefLoaded(false),
|
||||
mIsShuttingDown(false) {}
|
||||
|
||||
// Indicates whether the service is initialized.
|
||||
|
@ -62,22 +64,48 @@ class CookieBannerDomainPrefService final : public nsIAsyncShutdownBlocker,
|
|||
// Indicates whether the first reading of content pref completed.
|
||||
bool mIsContentPrefLoaded;
|
||||
|
||||
// Indicates whether the first reading of content pref for the private
|
||||
// browsing completed.
|
||||
bool mIsPrivateContentPrefLoaded;
|
||||
|
||||
// Indicates whether we are shutting down.
|
||||
bool mIsShuttingDown;
|
||||
|
||||
// A class to represent the domain pref. It's consist of the service mode and
|
||||
// a boolean to indicated if the domain pref persists in the disk.
|
||||
class DomainPrefData final : public nsISupports {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit DomainPrefData(nsICookieBannerService::Modes aMode,
|
||||
bool aIsPersistent)
|
||||
: mMode(aMode), mIsPersistent(aIsPersistent) {}
|
||||
|
||||
private:
|
||||
~DomainPrefData() = default;
|
||||
|
||||
friend class CookieBannerDomainPrefService;
|
||||
|
||||
nsICookieBannerService::Modes mMode;
|
||||
bool mIsPersistent;
|
||||
};
|
||||
|
||||
// Map of the per site preference keyed by domain.
|
||||
nsTHashMap<nsCStringHashKey, nsICookieBannerService::Modes> mPrefs;
|
||||
nsTHashMap<nsCStringHashKey, RefPtr<DomainPrefData>> mPrefs;
|
||||
|
||||
// Map of the per site preference for private windows keyed by domain.
|
||||
nsTHashMap<nsCStringHashKey, nsICookieBannerService::Modes> mPrefsPrivate;
|
||||
nsTHashMap<nsCStringHashKey, RefPtr<DomainPrefData>> mPrefsPrivate;
|
||||
|
||||
// A helper function that will wait until the initialization of the content
|
||||
// pref completed.
|
||||
void EnsureInitCompleted();
|
||||
void EnsureInitCompleted(bool aIsPrivate);
|
||||
|
||||
nsresult AddShutdownBlocker();
|
||||
nsresult RemoveShutdownBlocker();
|
||||
|
||||
nsresult RemoveContentPrefForDomain(const nsACString& aDomain,
|
||||
bool aIsPrivate);
|
||||
|
||||
class BaseContentPrefCallback : public nsIContentPrefCallback2 {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -99,8 +127,11 @@ class CookieBannerDomainPrefService final : public nsIAsyncShutdownBlocker,
|
|||
NS_DECL_NSICONTENTPREFCALLBACK2
|
||||
|
||||
explicit InitialLoadContentPrefCallback(
|
||||
CookieBannerDomainPrefService* aService)
|
||||
: BaseContentPrefCallback(aService) {}
|
||||
CookieBannerDomainPrefService* aService, bool aIsPrivate)
|
||||
: BaseContentPrefCallback(aService), mIsPrivate(aIsPrivate) {}
|
||||
|
||||
private:
|
||||
bool mIsPrivate;
|
||||
};
|
||||
|
||||
class WriteContentPrefCallback final : public BaseContentPrefCallback {
|
||||
|
|
|
@ -625,6 +625,23 @@ nsCookieBannerService::SetDomainPref(nsIURI* aTopLevelURI,
|
|||
const bool aIsPrivate) {
|
||||
NS_ENSURE_ARG_POINTER(aTopLevelURI);
|
||||
|
||||
return SetDomainPrefInternal(aTopLevelURI, aModes, aIsPrivate, false);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCookieBannerService::SetDomainPrefAndPersistInPrivateBrowsing(
|
||||
nsIURI* aTopLevelURI, nsICookieBannerService::Modes aModes) {
|
||||
NS_ENSURE_ARG_POINTER(aTopLevelURI);
|
||||
|
||||
return SetDomainPrefInternal(aTopLevelURI, aModes, true, true);
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCookieBannerService::SetDomainPrefInternal(
|
||||
nsIURI* aTopLevelURI, nsICookieBannerService::Modes aModes,
|
||||
const bool aIsPrivate, const bool aPersistInPrivateBrowsing) {
|
||||
NS_ENSURE_ARG_POINTER(aTopLevelURI);
|
||||
|
||||
if (!mIsInitialized) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
@ -638,7 +655,8 @@ nsCookieBannerService::SetDomainPref(nsIURI* aTopLevelURI,
|
|||
rv = eTLDService->GetBaseDomain(aTopLevelURI, 0, baseDomain);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mDomainPrefService->SetPref(baseDomain, aModes, aIsPrivate);
|
||||
rv = mDomainPrefService->SetPref(baseDomain, aModes, aIsPrivate,
|
||||
aPersistInPrivateBrowsing);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -81,6 +81,11 @@ class nsCookieBannerService final : public nsIObserver,
|
|||
nsICookieBannerRule** aRule,
|
||||
bool aReportTelemetry = false);
|
||||
|
||||
nsresult SetDomainPrefInternal(nsIURI* aTopLevelURI,
|
||||
nsICookieBannerService::Modes aModes,
|
||||
const bool aIsPrivate,
|
||||
const bool aPersistInPrivateBrowsing);
|
||||
|
||||
/**
|
||||
* Get the rule matching the provided URI.
|
||||
* @param aURI - The URI to match the rule for.
|
||||
|
|
|
@ -96,6 +96,18 @@ interface nsICookieBannerService : nsISupports {
|
|||
in nsICookieBannerService_Modes aMode,
|
||||
in boolean aIsPrivate);
|
||||
|
||||
/**
|
||||
* Set the domain preference of the given top-level URI. It will persist the
|
||||
* domain preference for private browsing.
|
||||
*
|
||||
* WARNING: setting permanent domain preference _will_ leak data in private
|
||||
* browsing. Only use if you understand the consequences and trade-offs. If
|
||||
* you are unsure, |setDomainPref| is very likely what you want to use
|
||||
* instead.
|
||||
*/
|
||||
void setDomainPrefAndPersistInPrivateBrowsing(in nsIURI aTopLevelURI,
|
||||
in nsICookieBannerService_Modes aMode);
|
||||
|
||||
/**
|
||||
* Remove the domain preference of the given top-level URI.
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче