Backed out 3 changesets (bug 1844558, bug 1894040) for causing build bustages on BounceTrackingProtection.cpp . CLOSED TREE

Backed out changeset 00cce862553d (bug 1844558)
Backed out changeset 3fcb5ea142fd (bug 1894040)
Backed out changeset aa731ff97ebd (bug 1894040)
This commit is contained in:
Narcis Beleuzu 2024-08-09 17:03:12 +03:00
parent ef34fc3422
commit c284a53117
32 changed files with 182 additions and 977 deletions

View File

@ -162,9 +162,6 @@ var allowlist = [
// toolkit/mozapps/extensions/AddonContentPolicy.cpp
{ file: "resource://gre/localization/en-US/toolkit/global/cspErrors.ftl" },
// toolkit/components/antitracking/bouncetrackingprotection/BounceTrackingProtection.cpp
{ file: "resource://gre/localization/en-US/toolkit/global/antiTracking.ftl" },
// The l10n build system can't package string files only for some platforms.
{
file: "resource://gre/chrome/en-US/locale/en-US/global-platform/mac/accessible.properties",

View File

@ -178,10 +178,6 @@ BrowsingContextWebProgress::GetBounceTrackingState() {
return do_AddRef(mBounceTrackingState);
}
void BrowsingContextWebProgress::DropBounceTrackingState() {
mBounceTrackingState = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
// nsIWebProgressListener

View File

@ -64,10 +64,6 @@ class BrowsingContextWebProgress final : public nsIWebProgress,
already_AddRefed<BounceTrackingState> GetBounceTrackingState();
// Drops our reference to BounceTrackingState. This is used when the feature
// gets disabled.
void DropBounceTrackingState();
private:
virtual ~BrowsingContextWebProgress();

View File

@ -14789,17 +14789,11 @@
value: ""
mirror: never
# Controls Bounce Tracking Protection behavior.
# Set to 0 to fully disable. See nsIBounceTrackingProtection.idl for
# documentation.
- name: privacy.bounceTrackingProtection.mode
type: uint32_t
#ifdef NIGHTLY_BUILD
value: 1
#else
value: 3
#endif
mirror: always
# Main pref to enable / disable the feature.
- name: privacy.bounceTrackingProtection.enabled
type: bool
value: true
mirror: once
# How long to wait for a client redirect after a navigation ends.
- name: privacy.bounceTrackingProtection.clientBounceDetectionTimerPeriodMS
@ -14833,6 +14827,14 @@
value: true
mirror: always
# Enables a mode where if bounce tracking protection is enabled it classifies
# but does not purge trackers. This mode is helpful for testing the feature
# without risking data loss. Telemetry is still collected normally.
- name: privacy.bounceTrackingProtection.enableDryRunMode
type: bool
value: @IS_NOT_NIGHTLY_BUILD@
mirror: always
# To be used in automated test environments to enable observer messages.
- name: privacy.bounceTrackingProtection.enableTestMode
type: bool

View File

@ -40,8 +40,6 @@
#include "mozilla/dom/WindowContext.h"
#include "mozilla/dom/WindowGlobalChild.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "nsIConsoleService.h"
#include "mozilla/intl/Localization.h"
#define TEST_OBSERVER_MSG_RECORD_BOUNCES_FINISHED "test-record-bounces-finished"
@ -59,8 +57,6 @@ static bool sInitFailed = false;
// Initialized on first call of GetSingleton.
Maybe<bool> BounceTrackingProtection::sFeatureIsEnabled;
static const char kBTPModePref[] = "privacy.bounceTrackingProtection.mode";
static constexpr uint32_t TRACKER_PURGE_FLAGS =
nsIClearDataService::CLEAR_ALL_CACHES | nsIClearDataService::CLEAR_COOKIES |
nsIClearDataService::CLEAR_DOM_STORAGES |
@ -82,8 +78,13 @@ BounceTrackingProtection::GetSingleton() {
// First call to GetSingleton, check main feature pref and record telemetry.
if (sFeatureIsEnabled.isNothing()) {
if (StaticPrefs::privacy_bounceTrackingProtection_mode() ==
nsIBounceTrackingProtection::MODE_DISABLED) {
if (StaticPrefs::privacy_bounceTrackingProtection_enabled_AtStartup()) {
sFeatureIsEnabled = Some(true);
glean::bounce_tracking_protection::enabled_at_startup.Set(true);
glean::bounce_tracking_protection::enabled_dry_run_mode_at_startup.Set(
StaticPrefs::privacy_bounceTrackingProtection_enableDryRunMode());
} else {
sFeatureIsEnabled = Some(false);
glean::bounce_tracking_protection::enabled_at_startup.Set(false);
@ -93,12 +94,6 @@ BounceTrackingProtection::GetSingleton() {
// Feature is disabled.
return nullptr;
}
sFeatureIsEnabled = Some(true);
glean::bounce_tracking_protection::enabled_at_startup.Set(true);
glean::bounce_tracking_protection::enabled_dry_run_mode_at_startup.Set(
StaticPrefs::privacy_bounceTrackingProtection_mode() ==
nsIBounceTrackingProtection::MODE_ENABLED_DRY_RUN);
}
MOZ_ASSERT(sFeatureIsEnabled.isSome());
@ -129,17 +124,14 @@ BounceTrackingProtection::GetSingleton() {
}
nsresult BounceTrackingProtection::Init() {
MOZ_ASSERT(StaticPrefs::privacy_bounceTrackingProtection_mode() !=
nsIBounceTrackingProtection::MODE_DISABLED,
"Mode pref must have an enabled state for init to be called.");
MOZ_LOG(
gBounceTrackingProtectionLog, LogLevel::Info,
("Init BounceTrackingProtection. Config: mode: %d, "
("Init BounceTrackingProtection. Config: enableDryRunMode: %d, "
"bounceTrackingActivationLifetimeSec: %d, bounceTrackingGracePeriodSec: "
"%d, bounceTrackingPurgeTimerPeriodSec: %d, "
"clientBounceDetectionTimerPeriodMS: %d, requireStatefulBounces: %d, "
"HasMigratedUserActivationData: %d",
StaticPrefs::privacy_bounceTrackingProtection_mode(),
StaticPrefs::privacy_bounceTrackingProtection_enableDryRunMode(),
StaticPrefs::
privacy_bounceTrackingProtection_bounceTrackingActivationLifetimeSec(),
StaticPrefs::
@ -163,31 +155,6 @@ nsresult BounceTrackingProtection::Init() {
("user activation permission migration failed"));
}
// Register feature pref listener which dynamically enables or disables the
// feature depending on feature pref state.
rv = Preferences::RegisterCallback(&BounceTrackingProtection::OnPrefChange,
kBTPModePref);
NS_ENSURE_SUCCESS(rv, rv);
// Run the remaining init logic.
return OnModeChange(true);
}
nsresult BounceTrackingProtection::UpdateBounceTrackingPurgeTimer(
bool aShouldEnable) {
// Cancel the existing timer.
// If disabling: we're done now.
// If enabling: schedule a new timer so interval changes (as controlled by the
// pref) are taken into account.
if (mBounceTrackingPurgeTimer) {
mBounceTrackingPurgeTimer->Cancel();
mBounceTrackingPurgeTimer = nullptr;
}
if (!aShouldEnable) {
return NS_OK;
}
// Schedule timer for tracker purging. The timer interval is determined by
// pref.
uint32_t purgeTimerPeriod = StaticPrefs::
@ -221,82 +188,6 @@ nsresult BounceTrackingProtection::UpdateBounceTrackingPurgeTimer(
"mBounceTrackingPurgeTimer");
}
// static
void BounceTrackingProtection::OnPrefChange(const char* aPref, void* aData) {
MOZ_ASSERT(sBounceTrackingProtection);
MOZ_ASSERT(strcmp(kBTPModePref, aPref) == 0);
sBounceTrackingProtection->OnModeChange(false);
}
nsresult BounceTrackingProtection::OnModeChange(bool aIsStartup) {
// Get feature mode from pref and ensure its within bounds.
uint8_t modeInt = StaticPrefs::privacy_bounceTrackingProtection_mode();
NS_ENSURE_TRUE(
modeInt >= 0 && modeInt <= nsIBounceTrackingProtection::MAX_MODE_VALUE,
NS_ERROR_FAILURE);
nsIBounceTrackingProtection::Modes mode =
static_cast<nsIBounceTrackingProtection::Modes>(modeInt);
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
("%s: mode: %d.", __FUNCTION__, mode));
if (sInitFailed) {
return NS_ERROR_FAILURE;
}
nsresult result = NS_OK;
if (!aIsStartup) {
// Clear bounce tracker candidate map for any mode change so it's not leaked
// into other modes. For example if we switch from dry-run mode into fully
// enabled we want a clean slate to not purge trackers that we've classified
// in dry-run mode. User activation data must be kept to avoid false
// positives.
MOZ_ASSERT(mStorage);
result = mStorage->ClearByType(
BounceTrackingProtectionStorage::EntryType::BounceTracker);
}
// On disable
if (mode == nsIBounceTrackingProtection::MODE_DISABLED ||
mode == nsIBounceTrackingProtection::MODE_ENABLED_STANDBY) {
// No further cleanup needed if we're just starting up.
if (aIsStartup) {
MOZ_ASSERT(!mStorageObserver);
MOZ_ASSERT(!mBounceTrackingPurgeTimer);
return result;
}
// Destroy storage observer to stop receiving storage notifications.
mStorageObserver = nullptr;
// Stop regular purging.
nsresult rv = UpdateBounceTrackingPurgeTimer(false);
if (NS_WARN_IF(NS_FAILED(rv))) {
result = rv;
// Even if this step fails try to do more cleanup.
}
// Clear all per-tab state.
BounceTrackingState::DestroyAll();
return result;
}
// On enable
MOZ_ASSERT(mode == nsIBounceTrackingProtection::MODE_ENABLED ||
mode == nsIBounceTrackingProtection::MODE_ENABLED_DRY_RUN);
// Create and init storage observer.
mStorageObserver = new BounceTrackingStorageObserver();
nsresult rv = mStorageObserver->Init();
NS_ENSURE_SUCCESS(rv, rv);
// Schedule regular purging.
rv = UpdateBounceTrackingPurgeTimer(true);
NS_ENSURE_SUCCESS(rv, rv);
return result;
}
nsresult BounceTrackingProtection::RecordStatefulBounces(
BounceTrackingState* aBounceTrackingState) {
NS_ENSURE_ARG_POINTER(aBounceTrackingState);
@ -315,8 +206,6 @@ nsresult BounceTrackingProtection::RecordStatefulBounces(
mStorage->GetOrCreateStateGlobal(aBounceTrackingState);
MOZ_ASSERT(globalState);
nsTArray<nsCString> classifiedHosts;
// For each host in navigables bounce tracking record's bounce set:
for (const nsACString& host : record->GetBounceHosts()) {
// Skip "null" entries, they are only used for logging purposes.
@ -376,8 +265,6 @@ nsresult BounceTrackingProtection::RecordStatefulBounces(
continue;
}
classifiedHosts.AppendElement(host);
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Info,
("%s: Added bounce tracker candidate. siteHost: %s, "
"aBounceTrackingState: %s",
@ -391,11 +278,6 @@ nsresult BounceTrackingProtection::RecordStatefulBounces(
("%s: Done, reset aBounceTrackingState: %s", __FUNCTION__,
aBounceTrackingState->Describe().get()));
// Log a message to the web console for each classified host.
nsresult rv = LogBounceTrackersClassifiedToWebConsole(aBounceTrackingState,
classifiedHosts);
NS_ENSURE_SUCCESS(rv, rv);
// If running in test automation, dispatch an observer message indicating
// we're finished recording bounces.
if (StaticPrefs::privacy_bounceTrackingProtection_enableTestMode()) {
@ -642,9 +524,7 @@ BounceTrackingProtection::TestRunPurgeBounceTrackers(
purgedSiteHosts) {
promise->MaybeResolve(purgedSiteHosts);
},
[promise](const PurgeBounceTrackersMozPromise::RejectValueType& error) {
promise->MaybeReject(error);
});
[promise] { promise->MaybeRejectWithUndefined(); });
promise.forget(aPromise);
return NS_OK;
@ -705,74 +585,6 @@ BounceTrackingProtection::TestMaybeMigrateUserInteractionPermissions() {
return MaybeMigrateUserInteractionPermissions();
}
// static
nsresult BounceTrackingProtection::LogBounceTrackersClassifiedToWebConsole(
BounceTrackingState* aBounceTrackingState,
const nsTArray<nsCString>& aSiteHosts) {
NS_ENSURE_ARG(aBounceTrackingState);
// Nothing to log.
if (aSiteHosts.IsEmpty()) {
return NS_OK;
}
RefPtr<dom::BrowsingContext> browsingContext =
aBounceTrackingState->CurrentBrowsingContext();
if (!browsingContext) {
return NS_OK;
}
// Get the localized copy from antiTracking.ftl and insert the variables.
nsTArray<nsCString> resourceIDs = {"toolkit/global/antiTracking.ftl"_ns};
RefPtr<intl::Localization> l10n =
intl::Localization::Create(resourceIDs, true);
for (const nsACString& siteHost : aSiteHosts) {
auto l10nArgs = dom::Optional<intl::L10nArgs>();
l10nArgs.Construct();
auto siteHostArg = l10nArgs.Value().Entries().AppendElement();
siteHostArg->mKey = "siteHost";
siteHostArg->mValue.SetValue().SetAsUTF8String().Assign(siteHost);
auto gracePeriodArg = l10nArgs.Value().Entries().AppendElement();
gracePeriodArg->mKey = "gracePeriodSeconds";
gracePeriodArg->mValue.SetValue().SetAsDouble() = StaticPrefs::
privacy_bounceTrackingProtection_bounceTrackingGracePeriodSec();
// Construct the localized string.
nsAutoCString message;
ErrorResult errorResult;
l10n->FormatValueSync("btp-warning-tracker-classified"_ns, l10nArgs,
message, errorResult);
if (NS_WARN_IF(errorResult.Failed())) {
return errorResult.StealNSResult();
}
// Log to the console via nsIScriptError object.
nsresult rv = NS_OK;
nsCOMPtr<nsIScriptError> error =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = error->InitWithWindowID(
NS_ConvertUTF8toUTF16(message), ""_ns, 0, 0,
nsIScriptError::warningFlag, "bounceTrackingProtection",
browsingContext->GetCurrentInnerWindowId(), true);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIConsoleService> consoleService =
do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// The actual log call.
rv = consoleService->LogMessage(error);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
RefPtr<GenericPromise>
BounceTrackingProtection::EnsureRemoteExceptionListService() {
// Check if mRemoteExceptionList is already initialized.
@ -799,17 +611,6 @@ BounceTrackingProtection::EnsureRemoteExceptionListService() {
RefPtr<BounceTrackingProtection::PurgeBounceTrackersMozPromise>
BounceTrackingProtection::PurgeBounceTrackers() {
// Only purge when the feature is actually enabled.
if (StaticPrefs::privacy_bounceTrackingProtection_mode() !=
nsIBounceTrackingProtection::MODE_ENABLED &&
StaticPrefs::privacy_bounceTrackingProtection_mode() !=
nsIBounceTrackingProtection::MODE_ENABLED_DRY_RUN) {
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
("%s: Skip: Purging disabled via mode pref.", __FUNCTION__));
return PurgeBounceTrackersMozPromise::CreateAndReject(
nsresult::NS_ERROR_NOT_AVAILABLE, __func__);
}
// Prevent multiple purge operations from running at the same time.
if (mPurgeInProgress) {
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
@ -943,14 +744,6 @@ nsresult BounceTrackingProtection::PurgeBounceTrackersForStateGlobal(
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
("%s: %s", __FUNCTION__, aStateGlobal->Describe().get()));
// Ensure we only purge when pref configuration allows it.
if (StaticPrefs::privacy_bounceTrackingProtection_mode() !=
nsIBounceTrackingProtection::MODE_ENABLED &&
StaticPrefs::privacy_bounceTrackingProtection_mode() !=
nsIBounceTrackingProtection::MODE_ENABLED_DRY_RUN) {
return NS_ERROR_NOT_AVAILABLE;
}
const PRTime now = PR_Now();
// 1. Remove hosts from the user activation map whose user activation flag has
@ -1048,8 +841,7 @@ nsresult BounceTrackingProtection::PurgeBounceTrackersForStateGlobal(
__FUNCTION__, PromiseFlatCString(host).get(), bounceTime,
aStateGlobal->Describe().get()));
if (StaticPrefs::privacy_bounceTrackingProtection_mode() ==
nsIBounceTrackingProtection::MODE_ENABLED_DRY_RUN) {
if (StaticPrefs::privacy_bounceTrackingProtection_enableDryRunMode()) {
// In dry-run mode, we don't actually clear the data, but we still want to
// resolve the promise to indicate that the data would have been cleared.
cb->OnDataDeleted(0);

View File

@ -4,7 +4,6 @@
#ifndef mozilla_BounceTrackingProtection_h__
#define mozilla_BounceTrackingProtection_h__
#include "BounceTrackingStorageObserver.h"
#include "mozilla/Logging.h"
#include "mozilla/MozPromise.h"
#include "nsIBounceTrackingProtection.h"
@ -80,18 +79,6 @@ class BounceTrackingProtection final : public nsIBounceTrackingProtection,
// Initializes the singleton instance of BounceTrackingProtection.
[[nodiscard]] nsresult Init();
// Listens for feature pref changes and enables / disables BTP.
static void OnPrefChange(const char* aPref, void* aData);
// Called by OnPrefChange when the mode pref changes.
// isStartup indicates whether this is the initial mode change after startup.
nsresult OnModeChange(bool aIsStartup);
// Schedules or cancels the periodic bounce tracker purging. If this method is
// called while purging is already scheduled it will cancel the existing timer
// and then start a new timer.
nsresult UpdateBounceTrackingPurgeTimer(bool aShouldEnable);
// Keeps track of whether the feature is enabled based on pref state.
// Initialized on first call of GetSingleton.
static Maybe<bool> sFeatureIsEnabled;
@ -99,9 +86,6 @@ class BounceTrackingProtection final : public nsIBounceTrackingProtection,
// Timer which periodically runs PurgeBounceTrackers.
nsCOMPtr<nsITimer> mBounceTrackingPurgeTimer;
// Used to notify BounceTrackingState of storage and cookie access.
RefPtr<BounceTrackingStorageObserver> mStorageObserver;
// Storage for user agent globals.
RefPtr<BounceTrackingProtectionStorage> mStorage;
@ -139,13 +123,6 @@ class BounceTrackingProtection final : public nsIBounceTrackingProtection,
// is important so we don't purge data for sites the user has interacted with
// before the feature was enabled.
[[nodiscard]] nsresult MaybeMigrateUserInteractionPermissions();
// Log a warning about the classification of a site as a bounce tracker. The
// message is logged to the devtools console aBounceTrackingState is
// associated with.
[[nodiscard]] static nsresult LogBounceTrackersClassifiedToWebConsole(
BounceTrackingState* aBounceTrackingState,
const nsTArray<nsCString>& aSiteHosts);
};
} // namespace mozilla

View File

@ -19,7 +19,6 @@
#include "mozilla/Services.h"
#include "nsCOMPtr.h"
#include "nsDirectoryServiceUtils.h"
#include "nsIBounceTrackingProtection.h"
#include "nsIObserverService.h"
#include "nsIPrincipal.h"
#include "nsIScriptSecurityManager.h"
@ -59,20 +58,6 @@ BounceTrackingProtectionStorage::GetOrCreateStateGlobal(
aOriginAttributes);
}
nsresult BounceTrackingProtectionStorage::ClearByType(
BounceTrackingProtectionStorage::EntryType aType) {
for (auto iter = mStateGlobal.Iter(); !iter.Done(); iter.Next()) {
BounceTrackingStateGlobal* stateGlobal = iter.Data();
MOZ_ASSERT(stateGlobal);
// Update in memory state. Skip storage so we can batch the writes later.
nsresult rv = stateGlobal->ClearByType(aType, true);
NS_ENSURE_SUCCESS(rv, rv);
}
// Clear on-disk state for all OriginAttributes by type.
return DeleteDBEntriesByType(nullptr, aType);
}
nsresult BounceTrackingProtectionStorage::ClearBySiteHost(
const nsACString& aSiteHost, OriginAttributes* aOriginAttributes) {
NS_ENSURE_TRUE(!aSiteHost.IsEmpty(), NS_ERROR_INVALID_ARG);
@ -277,34 +262,6 @@ nsresult BounceTrackingProtectionStorage::DeleteDBEntriesInTimeRange(
return NS_OK;
}
nsresult BounceTrackingProtectionStorage::DeleteDBEntriesByType(
OriginAttributes* aOriginAttributes,
BounceTrackingProtectionStorage::EntryType aEntryType) {
MOZ_ASSERT(NS_IsMainThread());
nsresult rv = WaitForInitialization();
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<BounceTrackingProtectionStorage> self = this;
Maybe<OriginAttributes> originAttributes;
if (aOriginAttributes) {
originAttributes.emplace(*aOriginAttributes);
}
IncrementPendingWrites();
mBackgroundThread->Dispatch(
NS_NewRunnableFunction(
"BounceTrackingProtectionStorage::DeleteDBEntriesByType",
[self, originAttributes, aEntryType]() {
nsresult rv = self->DeleteDataByType(self->mDatabaseConnection,
originAttributes, aEntryType);
self->DecrementPendingWrites();
NS_ENSURE_SUCCESS_VOID(rv);
}),
NS_DISPATCH_EVENT_MAY_BLOCK);
return NS_OK;
}
nsresult
BounceTrackingProtectionStorage::DeleteDBEntriesByOriginAttributesPattern(
const OriginAttributesPattern& aOriginAttributesPattern) {
@ -457,9 +414,9 @@ nsresult BounceTrackingProtectionStorage::Init() {
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug, ("%s", __FUNCTION__));
// Init shouldn't be called if the feature is disabled.
NS_ENSURE_TRUE(StaticPrefs::privacy_bounceTrackingProtection_mode() !=
nsIBounceTrackingProtection::MODE_DISABLED,
NS_ERROR_FAILURE);
NS_ENSURE_TRUE(
StaticPrefs::privacy_bounceTrackingProtection_enabled_AtStartup(),
NS_ERROR_FAILURE);
// Register a shutdown blocker so we can flush pending changes to disk before
// shutdown.
@ -827,49 +784,6 @@ nsresult BounceTrackingProtectionStorage::DeleteDataInTimeRange(
return deleteStmt->Execute();
}
// static
nsresult BounceTrackingProtectionStorage::DeleteDataByType(
mozIStorageConnection* aDatabaseConnection,
const Maybe<OriginAttributes>& aOriginAttributes,
BounceTrackingProtectionStorage::EntryType aEntryType) {
MOZ_ASSERT(!NS_IsMainThread(),
"Must not write to the table from the main thread.");
MOZ_ASSERT(aDatabaseConnection);
MOZ_ASSERT(aOriginAttributes.isNothing() ||
aOriginAttributes->mPrivateBrowsingId ==
nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID);
nsAutoCString deleteQuery(
"DELETE FROM sites "
"WHERE entryType = :entryType"_ns);
if (aOriginAttributes) {
deleteQuery.AppendLiteral(
" AND originAttributeSuffix = :originAttributeSuffix");
}
deleteQuery.AppendLiteral(";");
nsCOMPtr<mozIStorageStatement> deleteStmt;
nsresult rv = aDatabaseConnection->CreateStatement(
deleteQuery, getter_AddRefs(deleteStmt));
NS_ENSURE_SUCCESS(rv, rv);
rv = deleteStmt->BindInt32ByName("entryType"_ns,
static_cast<int32_t>(aEntryType));
NS_ENSURE_SUCCESS(rv, rv);
if (aOriginAttributes) {
nsAutoCString originAttributeSuffix;
aOriginAttributes->CreateSuffix(originAttributeSuffix);
rv = deleteStmt->BindUTF8StringByName("originAttributeSuffix"_ns,
originAttributeSuffix);
NS_ENSURE_SUCCESS(rv, rv);
}
return deleteStmt->Execute();
}
nsresult BounceTrackingProtectionStorage::DeleteDataByOriginAttributesPattern(
mozIStorageConnection* aDatabaseConnection,
const OriginAttributesPattern& aOriginAttributesPattern) {

View File

@ -64,10 +64,6 @@ class BounceTrackingProtectionStorage final : public nsIObserver,
// migration.
enum class EntryType : uint8_t { BounceTracker = 0, UserActivation = 1 };
// Clear all user activation or bounce tracker entries.
[[nodiscard]] nsresult ClearByType(
BounceTrackingProtectionStorage::EntryType aType);
// Clear all state for a given site host. If aOriginAttributes is passed, only
// entries for that OA will be deleted.
[[nodiscard]] nsresult ClearBySiteHost(const nsACString& aSiteHost,
@ -149,13 +145,6 @@ class BounceTrackingProtectionStorage final : public nsIObserver,
Maybe<PRTime> aTo,
Maybe<BounceTrackingProtectionStorage::EntryType> aEntryType = Nothing{});
// Delete all entries of a specific type.
// aOriginAttributes can be passed
[[nodiscard]] nsresult DeleteDataByType(
mozIStorageConnection* aDatabaseConnection,
const Maybe<OriginAttributes>& aOriginAttributes,
BounceTrackingProtectionStorage::EntryType aEntryType);
// Delete all entries matching the given OriginAttributesPattern. Worker
// thread only.
[[nodiscard]] static nsresult DeleteDataByOriginAttributesPattern(
@ -206,12 +195,6 @@ class BounceTrackingProtectionStorage final : public nsIObserver,
OriginAttributes* aOriginAttributes, PRTime aFrom,
Maybe<PRTime> aTo = Nothing{}, Maybe<EntryType> aEntryType = Nothing{});
// Delete all DB entries matching the given type.
// If aOriginAttributes is passed it acts as an additional filter.
[[nodiscard]] nsresult DeleteDBEntriesByType(
OriginAttributes* aOriginAttributes,
BounceTrackingProtectionStorage::EntryType aEntryType);
// Deletes all DB entries matching the given OriginAttributesPattern.
[[nodiscard]] nsresult DeleteDBEntriesByOriginAttributesPattern(
const OriginAttributesPattern& aOriginAttributesPattern);

View File

@ -39,21 +39,17 @@ namespace mozilla {
static StaticAutoPtr<nsTHashMap<uint64_t, WeakPtr<BounceTrackingState>>>
sBounceTrackingStates;
static StaticRefPtr<BounceTrackingStorageObserver> sStorageObserver;
NS_IMPL_ISUPPORTS(BounceTrackingState, nsIWebProgressListener,
nsISupportsWeakReference);
BounceTrackingState::BounceTrackingState() {
MOZ_ASSERT(StaticPrefs::privacy_bounceTrackingProtection_mode() ==
nsIBounceTrackingProtection::MODE_ENABLED ||
StaticPrefs::privacy_bounceTrackingProtection_mode() ==
nsIBounceTrackingProtection::MODE_ENABLED_DRY_RUN);
MOZ_ASSERT(StaticPrefs::privacy_bounceTrackingProtection_enabled_AtStartup());
mBounceTrackingProtection = BounceTrackingProtection::GetSingleton();
};
BounceTrackingState::~BounceTrackingState() {
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Verbose,
("BounceTrackingState destructor"));
if (sBounceTrackingStates) {
sBounceTrackingStates->Remove(mBrowserId);
}
@ -112,55 +108,21 @@ already_AddRefed<BounceTrackingState> BounceTrackingState::GetOrCreate(
}
sBounceTrackingStates->InsertOrUpdate(browserId, newBTS);
// And the storage observer.
if (!sStorageObserver) {
sStorageObserver = new BounceTrackingStorageObserver();
ClearOnShutdown(&sStorageObserver);
aRv = sStorageObserver->Init();
NS_ENSURE_SUCCESS(aRv, nullptr);
}
return newBTS.forget();
};
// static
void BounceTrackingState::ResetAll() { Reset(nullptr, nullptr); }
// static
void BounceTrackingState::DestroyAll() {
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug, ("%s", __FUNCTION__));
if (!sBounceTrackingStates) {
return;
}
// Fully reset all BounceTrackingStates, so even if some don't get destroyed
// straight away things like running timers are stopped.
BounceTrackingState::Reset(nullptr, nullptr);
// Destroy all BounceTrackingState objects.
for (auto iter = sBounceTrackingStates->Iter(); !iter.Done(); iter.Next()) {
WeakPtr<BounceTrackingState> bts = iter.Data();
// Need to remove the element from the map prior to calling Destroy()
// because the destructor also updates the map and we can't iterate and
// externally modify the map at the same time. This way the Remove() call of
// the destructor is a no-op.
iter.Remove();
if (!bts) {
continue;
}
// Destroy the BounceTrackingState by dropping references to it. This is
// best effort. If something still holds a reference it still stay alive
// longer.
// Tell the web progress to drop the BTS reference.
RefPtr<dom::BrowsingContext> browsingContext =
bts->CurrentBrowsingContext();
if (!browsingContext) {
continue;
}
dom::BrowsingContextWebProgress* webProgress =
browsingContext->Canonical()->GetWebProgress();
if (!webProgress) {
continue;
}
webProgress->DropBounceTrackingState();
}
// Clean up the map.
sBounceTrackingStates = nullptr;
}
// static
void BounceTrackingState::ResetAllForOriginAttributes(
const OriginAttributes& aOriginAttributes) {
@ -175,19 +137,14 @@ void BounceTrackingState::ResetAllForOriginAttributesPattern(
nsresult BounceTrackingState::Init(
dom::BrowsingContextWebProgress* aWebProgress) {
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
("BounceTrackingState::%s", __FUNCTION__));
MOZ_ASSERT(!mIsInitialized,
"BounceTrackingState must not be initialized twice.");
mIsInitialized = true;
NS_ENSURE_ARG_POINTER(aWebProgress);
NS_ENSURE_TRUE(StaticPrefs::privacy_bounceTrackingProtection_mode() ==
nsIBounceTrackingProtection::MODE_ENABLED ||
StaticPrefs::privacy_bounceTrackingProtection_mode() ==
nsIBounceTrackingProtection::MODE_ENABLED_DRY_RUN,
NS_ERROR_NOT_AVAILABLE);
NS_ENSURE_TRUE(
StaticPrefs::privacy_bounceTrackingProtection_enabled_AtStartup(),
NS_ERROR_NOT_AVAILABLE);
NS_ENSURE_TRUE(mBounceTrackingProtection, NS_ERROR_FAILURE);
// Store the browser ID so we can get the associated BC later without having
@ -203,8 +160,11 @@ nsresult BounceTrackingState::Init(
// Add a listener for window load. See BounceTrackingState::OnStateChange for
// the listener code.
return aWebProgress->AddProgressListener(this,
nsIWebProgress::NOTIFY_STATE_WINDOW);
nsresult rv = aWebProgress->AddProgressListener(
this, nsIWebProgress::NOTIFY_STATE_WINDOW);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
void BounceTrackingState::ResetBounceTrackingRecord() {
@ -266,10 +226,8 @@ bool BounceTrackingState::ShouldCreateBounceTrackingStateForWebProgress(
dom::BrowsingContextWebProgress* aWebProgress) {
NS_ENSURE_TRUE(aWebProgress, false);
uint8_t mode = StaticPrefs::privacy_bounceTrackingProtection_mode();
// Classification / purging is disabled.
if (mode != nsIBounceTrackingProtection::MODE_ENABLED &&
mode != nsIBounceTrackingProtection::MODE_ENABLED_DRY_RUN) {
// Feature is globally disabled.
if (!StaticPrefs::privacy_bounceTrackingProtection_enabled_AtStartup()) {
return false;
}

View File

@ -49,15 +49,8 @@ class BounceTrackingState : public nsIWebProgressListener,
// Reset state for all BounceTrackingState instances this includes resetting
// BounceTrackingRecords and cancelling any running timers.
static void ResetAll();
// Resets and destroys all BounceTrackingState objects. This is used when the
// feature gets disabled.
static void DestroyAll();
// Reset BounceTrackingState objects matching OriginAttributes.
static void ResetAllForOriginAttributes(
const OriginAttributes& aOriginAttributes);
// Same as above but for a pattern.
static void ResetAllForOriginAttributesPattern(
const OriginAttributesPattern& aPattern);

View File

@ -206,26 +206,6 @@ nsresult BounceTrackingStateGlobal::RemoveBounceTrackers(
return NS_OK;
}
nsresult BounceTrackingStateGlobal::ClearByType(
BounceTrackingProtectionStorage::EntryType aType, bool aSkipStorage) {
if (aType == BounceTrackingProtectionStorage::EntryType::BounceTracker) {
mBounceTrackers.Clear();
} else {
MOZ_ASSERT(aType ==
BounceTrackingProtectionStorage::EntryType::UserActivation);
mUserActivation.Clear();
}
if (aSkipStorage || !ShouldPersistToDisk()) {
return NS_OK;
}
NS_ENSURE_TRUE(mStorage, NS_ERROR_FAILURE);
return mStorage->DeleteDBEntriesByType(
&mOriginAttributes,
BounceTrackingProtectionStorage::EntryType::BounceTracker);
}
// static
nsCString BounceTrackingStateGlobal::DescribeMap(
const nsTHashMap<nsCStringHashKey, PRTime>& aMap) {

View File

@ -66,10 +66,6 @@ class BounceTrackingStateGlobal final {
[[nodiscard]] nsresult RemoveBounceTrackers(
const nsTArray<nsCString>& aSiteHosts);
// Clear user activation or bounce tracker map.
[[nodiscard]] nsresult ClearByType(
BounceTrackingProtectionStorage::EntryType aType, bool aSkipStorage);
[[nodiscard]] nsresult ClearSiteHost(const nsACString& aSiteHost,
bool aSkipStorage = false);

View File

@ -18,25 +18,21 @@
namespace mozilla {
NS_IMPL_ISUPPORTS(BounceTrackingStorageObserver, nsIObserver,
nsISupportsWeakReference);
NS_IMPL_ISUPPORTS(BounceTrackingStorageObserver, nsIObserver);
nsresult BounceTrackingStorageObserver::Init() {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
("BounceTrackingStorageObserver::%s", __FUNCTION__));
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug, ("%s", __FUNCTION__));
// Add observers to listen for cookie changes.
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
NS_ENSURE_TRUE(observerService, NS_ERROR_FAILURE);
// Passing ownsWeak=true so we don't have to unregister the observer when
// BounceTrackingStorageObserver gets destroyed.
nsresult rv = observerService->AddObserver(this, "cookie-changed", true);
nsresult rv = observerService->AddObserver(this, "cookie-changed", false);
NS_ENSURE_SUCCESS(rv, rv);
return observerService->AddObserver(this, "private-cookie-changed", true);
return observerService->AddObserver(this, "private-cookie-changed", false);
}
// nsIObserver

View File

@ -6,7 +6,6 @@
#include "mozilla/Logging.h"
#include "nsIObserver.h"
#include "nsWeakReference.h"
namespace mozilla {
@ -16,19 +15,19 @@ class WindowContext;
extern LazyLogModule gBounceTrackingProtectionLog;
class BounceTrackingStorageObserver : public nsIObserver,
public nsSupportsWeakReference {
class BounceTrackingStorageObserver final : public nsIObserver {
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
public:
BounceTrackingStorageObserver() = default;
[[nodiscard]] nsresult Init();
[[nodiscard]] static nsresult OnInitialStorageAccess(
dom::WindowContext* aWindowContext);
[[nodiscard]] nsresult Init();
private:
virtual ~BounceTrackingStorageObserver() = default;
~BounceTrackingStorageObserver() = default;
};
} // namespace mozilla

View File

@ -4,7 +4,6 @@
#include "ClearDataCallback.h"
#include "mozilla/glean/GleanMetrics.h"
#include "nsIBounceTrackingProtection.h"
#include "nsIURIClassifier.h"
#include "mozilla/net/UrlClassifierFeatureFactory.h"
#include "nsNetCID.h"
@ -46,8 +45,7 @@ ClearDataCallback::ClearDataCallback(ClearDataMozPromise::Private* aPromise,
mClearDurationTimer(0) {
MOZ_ASSERT(!aHost.IsEmpty(), "Host must not be empty");
if (StaticPrefs::privacy_bounceTrackingProtection_mode() ==
nsIBounceTrackingProtection::MODE_ENABLED) {
if (!StaticPrefs::privacy_bounceTrackingProtection_enableDryRunMode()) {
// Only collect timing information when actually performing the deletion
mClearDurationTimer =
glean::bounce_tracking_protection::purge_duration.Start();
@ -114,8 +112,7 @@ void ClearDataCallback::RecordClearDurationTelemetry() {
}
void ClearDataCallback::RecordPurgeCountTelemetry(bool aFailed) {
if (StaticPrefs::privacy_bounceTrackingProtection_mode() ==
nsIBounceTrackingProtection::MODE_ENABLED_DRY_RUN) {
if (StaticPrefs::privacy_bounceTrackingProtection_enableDryRunMode()) {
MOZ_ASSERT(aFailed == 0, "Dry-run purge can't fail");
glean::bounce_tracking_protection::purge_count.Get("dry"_ns).Add(1);
} else if (aFailed) {
@ -183,8 +180,8 @@ void ClearDataCallback::RecordPurgeEventTelemetry(bool aSuccess) {
// Record a glean event for the clear action.
glean::bounce_tracking_protection::PurgeActionExtra extra = {
.bounceTime = Some(mBounceTime / PR_USEC_PER_SEC),
.isDryRun = Some(StaticPrefs::privacy_bounceTrackingProtection_mode() ==
nsIBounceTrackingProtection::MODE_ENABLED_DRY_RUN),
.isDryRun = Some(
StaticPrefs::privacy_bounceTrackingProtection_enableDryRunMode()),
.siteHost = Some(mHost),
.success = Some(aSuccess),
};

View File

@ -7,37 +7,6 @@
[scriptable, uuid(4866F748-29DA-4C10-8EAA-ED2F7851E6B1)]
interface nsIBounceTrackingProtection : nsISupports {
/**
* Modes for Bounce Tracking Protection
*
* MODE_DISABLED - Feature fully disabled and not initialized at startup. No
* user activation signals are collected. Requires a restart to apply.
* MODE_ENABLED - Feature fully enabled. This includes: collection of user
* activation signals, classification of bounce trackers, periodic purging
* of bounce trackers.
* MODE_ENABLED_STANDBY - Tracker classification and purging is disabled.
* User activation signals are still collected and stored.
* MODE_ENABLED_DRY_RUN - Dry-run mode: The feature is fully enabled, but
* tracker purging is simulated. No site data is purged. Purge telemetry
* still gets collected. This mode is helpful for testing the feature
* without risking data loss.
*
* For toggling the feature in privacy settings UI switch between
* MODE_ENABLED and MODE_NO_PURGE. This is important so that user activation
* signals are still collected even if the feature is "turned off" for the
* user.
* Fully enabling / disabling the feature (MODE_DISABLED -> x or x ->
* MODE_DISABLED) requires a restart to apply.
*/
cenum Modes : 8 {
MODE_DISABLED = 0,
MODE_ENABLED = 1,
MODE_ENABLED_STANDBY = 2,
MODE_ENABLED_DRY_RUN = 3,
// Not a valid mode, only used for pref validation.
MAX_MODE_VALUE = 3,
};
// Reset the global bounce tracking state, including the maps for tracking
// bounce tracker candidates and user activation.
void clearAll();

View File

@ -1,9 +1,10 @@
[DEFAULT]
head = "head.js"
prefs = [
"privacy.bounceTrackingProtection.mode=1",
"privacy.bounceTrackingProtection.enabled=true",
"privacy.bounceTrackingProtection.enableTestMode=true",
"privacy.bounceTrackingProtection.bounceTrackingPurgeTimerPeriodSec=0",
"privacy.bounceTrackingProtection.enableDryRunMode=false",
# Do not upgrade ORIGIN_TRACKER_B, all other origins are already HTTPS
"dom.security.https_first=false",
]
@ -16,11 +17,9 @@ support-files = [
"file_web_worker.js",
]
["browser_bouncetracking_cookie_behavior.js"]
["browser_bouncetracking_dry_run.js"]
["browser_bouncetracking_mode_prefs.js"]
["browser_bouncetracking_initialize.js"]
["browser_bouncetracking_oa_isolation.js"]
@ -52,5 +51,3 @@ support-files = [
["browser_bouncetracking_webAuthUserActivation.js"]
support-files = ["!/dom/webauthn/tests/browser/head.js"]
["browser_bouncetracking_web_console.js"]

View File

@ -1,103 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// The test needs to open new PBM windows which is slow on debug builds.
requestLongerTimeout(2);
/**
* Helper function for testing that BTP gets enabled/disabled for a specific
* cookie behavior.
*
* @param {Number} cookieBehavior - One of Ci.nsICookieService.BEHAVIOR* values.
* @param {Number} privateBrowsingId - Run test in private/non-private mode.
*/
async function runTestCookieBehavior(
cookieBehavior,
privateBrowsingId,
shouldBeEnabled
) {
info(
"runTestCookieBehavior " +
JSON.stringify({ cookieBehavior, privateBrowsingId, shouldBeEnabled })
);
if (privateBrowsingId == 0) {
await SpecialPowers.pushPrefEnv({
set: [["network.cookie.cookieBehavior", cookieBehavior]],
});
} else {
await SpecialPowers.pushPrefEnv({
set: [["network.cookie.cookieBehavior.pbmode", cookieBehavior]],
});
}
await runTestBounce({
bounceType: "server",
setState: "cookie-server",
originAttributes: {
privateBrowsingId,
},
expectRecordBounces: shouldBeEnabled,
expectCandidate: shouldBeEnabled,
expectPurge: shouldBeEnabled,
});
// Cleanup
await SpecialPowers.popPrefEnv();
}
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [
["privacy.bounceTrackingProtection.requireStatefulBounces", true],
["privacy.bounceTrackingProtection.bounceTrackingGracePeriodSec", 0],
],
});
});
/**
* Tests classification + purging with different cookie behavior settings.
*/
add_task(async function test_cookie_behaviors() {
for (let pbId = 0; pbId < 2; pbId++) {
// BTP is disabled
await runTestCookieBehavior(
Ci.nsICookieService.BEHAVIOR_ACCEPT,
pbId,
false
);
await runTestCookieBehavior(
Ci.nsICookieService.BEHAVIOR_REJECT,
pbId,
false
);
// BTP is enabled
await runTestCookieBehavior(
Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN,
pbId,
true
);
await runTestCookieBehavior(
Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN,
pbId,
true
);
await runTestCookieBehavior(
Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER,
pbId,
true
);
await runTestCookieBehavior(
Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
pbId,
true
);
}
Assert.equal(
Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
Ci.nsICookieService.BEHAVIOR_LAST,
"test covers all cookie behaviors"
);
});

View File

@ -86,12 +86,7 @@ add_setup(async function () {
add_task(async function test_purge_in_regular_mode() {
await SpecialPowers.pushPrefEnv({
set: [
[
"privacy.bounceTrackingProtection.mode",
Ci.nsIBounceTrackingProtection.MODE_ENABLED,
],
],
set: [["privacy.bounceTrackingProtection.enableDryRunMode", false]],
});
await runPurgeTest(true);
@ -99,12 +94,7 @@ add_task(async function test_purge_in_regular_mode() {
add_task(async function test_purge_in_dry_run_mode() {
await SpecialPowers.pushPrefEnv({
set: [
[
"privacy.bounceTrackingProtection.mode",
Ci.nsIBounceTrackingProtection.MODE_ENABLED_DRY_RUN,
],
],
set: [["privacy.bounceTrackingProtection.enableDryRunMode", true]],
});
await runPurgeTest(false);

View File

@ -0,0 +1,68 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* helper function for testing that btp was initialized
*
* @param {Number} cookieMode: one of Ci.nsICookieService.BEHAVIOR* values
* @param {Number} privateBrowsingId: run test in private/non-private mode
*/
async function testInit(cookieMode, privateBrowsingId) {
if (privateBrowsingId != 0) {
await SpecialPowers.pushPrefEnv({
set: [["network.cookie.cookieBehavior", cookieMode]],
});
} else {
await SpecialPowers.pushPrefEnv({
set: [["network.cookie.cookieBehavior.pbmode", cookieMode]],
});
}
let originAttributes = {
privateBrowsingId,
};
info("Run server bounce with cookie.");
await runTestBounce({
bounceType: "server",
setState: "cookie-server",
originAttributes,
postBounceCallback: () => {
// Make sure we recorded bounceTracking
let numTrackersPurged =
bounceTrackingProtection.testGetBounceTrackerCandidateHosts(
originAttributes
).length;
Assert.equal(numTrackersPurged, 1, "All tracker candidates found.");
},
});
// Cleanup
await SpecialPowers.popPrefEnv();
Services.fog.testResetFOG();
bounceTrackingProtection.clearAll();
}
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [
["privacy.bounceTrackingProtection.requireStatefulBounces", true],
["privacy.bounceTrackingProtection.bounceTrackingGracePeriodSec", 0],
],
});
});
add_task(async function () {
for (let pbId = 0; pbId < 2; pbId++) {
await testInit(Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN, pbId);
await testInit(Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN, pbId);
await testInit(Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER, pbId);
}
Assert.equal(
Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
Ci.nsICookieService.BEHAVIOR_LAST,
"test covers all cookie behaviours"
);
});

View File

@ -1,139 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {
MODE_DISABLED,
MODE_ENABLED,
MODE_ENABLED_STANDBY,
MODE_ENABLED_DRY_RUN,
} = Ci.nsIBounceTrackingProtection;
const BTP_MODE_PREF = "privacy.bounceTrackingProtection.mode";
/**
* Run a bounce test with a custom bounce tracking protection mode.
* @param {Number} mode - Mode to set for BTP. Any of
* Ci.nsIBounceTrackingProtection.MODE_*
* @param {boolean} shouldBeEnabled - Whether BTP should classify + purge in
* this mode.
*/
async function runTestModePref(mode, shouldBeEnabled) {
info("runTestModePref " + JSON.stringify({ mode, shouldBeEnabled }));
await SpecialPowers.pushPrefEnv({
set: [[BTP_MODE_PREF, mode]],
});
info("Run server bounce with cookie.");
await runTestBounce({
bounceType: "server",
setState: "cookie-server",
expectRecordBounces: shouldBeEnabled,
expectCandidate: shouldBeEnabled,
expectPurge: shouldBeEnabled,
});
await SpecialPowers.popPrefEnv();
}
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [
["privacy.bounceTrackingProtection.requireStatefulBounces", true],
["privacy.bounceTrackingProtection.bounceTrackingGracePeriodSec", 0],
],
});
});
/**
* Tests classification + purging with different BTP modes.
*/
add_task(async function test_mode_pref() {
await runTestModePref(MODE_DISABLED, false);
await runTestModePref(MODE_ENABLED, true);
await runTestModePref(MODE_ENABLED_STANDBY, false);
await runTestModePref(MODE_ENABLED_DRY_RUN, true);
});
/**
* Tests that when the BTP mode is switched the bounce tracker candidate list is
* cleared.
*/
add_task(async function test_mode_switch_clears_bounce_candidates() {
// Start with MODE_ENABLED
let modeOriginal = Services.prefs.getIntPref(BTP_MODE_PREF);
registerCleanupFunction(() => {
Services.prefs.setIntPref(BTP_MODE_PREF, modeOriginal);
bounceTrackingProtection.clearAll();
});
info(
"Populate BTP state: Add bounce tracker candidates and a user activation."
);
bounceTrackingProtection.testAddBounceTrackerCandidate(
{},
"bounce-tracker.com",
1
);
bounceTrackingProtection.testAddBounceTrackerCandidate(
{},
"another-bounce-tracker.net",
2
);
bounceTrackingProtection.testAddUserActivation(
{},
"user-activation.com",
400
);
Assert.equal(
bounceTrackingProtection.testGetBounceTrackerCandidateHosts({}).length,
2,
"Bounce tracker candidate map should have been populated."
);
Assert.equal(
bounceTrackingProtection.testGetUserActivationHosts({}).length,
1,
"User activation map should have been populated."
);
info("Update to MODE_ENABLED_DRY_RUN");
Services.prefs.setIntPref(BTP_MODE_PREF, MODE_ENABLED_DRY_RUN);
Assert.equal(
bounceTrackingProtection.testGetBounceTrackerCandidateHosts({}).length,
0,
"Mode change should have cleared bouncer tracker candidate map."
);
Assert.equal(
bounceTrackingProtection.testGetUserActivationHosts({}).length,
1,
"Mode change should NOT have cleared user activation map."
);
info("Add a new bounce tracker");
bounceTrackingProtection.testAddBounceTrackerCandidate(
{},
"bounce-tracker2.com",
1
);
Assert.equal(
bounceTrackingProtection.testGetBounceTrackerCandidateHosts({}).length,
1,
"Bounce tracker candidate map should have been populated."
);
info("Switch back to MODE_ENABLED");
Services.prefs.setIntPref(BTP_MODE_PREF, MODE_ENABLED);
Assert.equal(
bounceTrackingProtection.testGetBounceTrackerCandidateHosts({}).length,
0,
"Mode change should have cleared bouncer tracker candidate map."
);
Assert.equal(
bounceTrackingProtection.testGetUserActivationHosts({}).length,
1,
"Mode change should NOT have cleared user activation map."
);
});

View File

@ -23,14 +23,7 @@ function assertCounterNull() {
async function testPurgeCount(isDryRunMode) {
await SpecialPowers.pushPrefEnv({
set: [
[
"privacy.bounceTrackingProtection.mode",
isDryRunMode
? Ci.nsIBounceTrackingProtection.MODE_ENABLED_DRY_RUN
: Ci.nsIBounceTrackingProtection.MODE_ENABLED,
],
],
set: [["privacy.bounceTrackingProtection.enableDryRunMode", isDryRunMode]],
});
assertCounterNull();

View File

@ -7,14 +7,7 @@ let bounceTrackingProtection;
async function test_purge_duration(isDryRunMode) {
await SpecialPowers.pushPrefEnv({
set: [
[
"privacy.bounceTrackingProtection.mode",
isDryRunMode
? Ci.nsIBounceTrackingProtection.MODE_ENABLED_DRY_RUN
: Ci.nsIBounceTrackingProtection.MODE_ENABLED,
],
],
set: [["privacy.bounceTrackingProtection.enableDryRunMode", isDryRunMode]],
});
is(

View File

@ -22,14 +22,7 @@ add_setup(async function () {
async function runTest(useDryRunMode) {
await SpecialPowers.pushPrefEnv({
set: [
[
"privacy.bounceTrackingProtection.mode",
useDryRunMode
? Ci.nsIBounceTrackingProtection.MODE_ENABLED_DRY_RUN
: Ci.nsIBounceTrackingProtection.MODE_ENABLED,
],
],
set: [["privacy.bounceTrackingProtection.enableDryRunMode", useDryRunMode]],
});
is(

View File

@ -1,73 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let btpGracePeriodSec = Services.prefs.getIntPref(
"privacy.bounceTrackingProtection.bounceTrackingGracePeriodSec"
);
/**
* Registers a console listener and waits for the bounce tracker classified message
* to be logged.
* @returns {Promise} - Promise which resolves once the message has been logged.
*/
async function waitForBounceTrackerClassifiedMessage(siteHost) {
let lastMessage;
// Checking if the grace period is
// privacy.bounceTrackingProtection.bounceTrackingGracePeriodSec requires
// extra steps because l10n applies further transformations to the number such
// as adding a ",".
let gracePeriodFormatted = new Intl.NumberFormat("en-US", {
useGrouping: true,
}).format(
Services.prefs.getIntPref(
"privacy.bounceTrackingProtection.bounceTrackingGracePeriodSec"
)
);
let isBTPClassifiedMsg = msg =>
msg.includes(
`${siteHost}” has been classified as a bounce tracker. If it does not receive user activation within the next ${gracePeriodFormatted} seconds it will have its state purged.`
);
await new Promise(resolve => {
SpecialPowers.registerConsoleListener(consoleMsg => {
if (!consoleMsg?.message || consoleMsg.message == "SENTINEL") {
return;
}
lastMessage = consoleMsg;
if (isBTPClassifiedMsg(consoleMsg.message)) {
resolve();
}
});
});
SpecialPowers.postConsoleSentinel();
ok(lastMessage.isScriptError, "Message should be script error.");
ok(lastMessage.isWarning, "Message should be a warning.");
ok(
isBTPClassifiedMsg(lastMessage.message),
"Observed bounce tracker classified console message."
);
}
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [
["privacy.bounceTrackingProtection.requireStatefulBounces", true],
["privacy.bounceTrackingProtection.bounceTrackingGracePeriodSec", 0],
],
});
});
add_task(async function test_bounce_tracker_classified_web_console_message() {
let consoleMsgPromise = waitForBounceTrackerClassifiedMessage(SITE_TRACKER);
info("Run server bounce with cookie.");
await runTestBounce({
bounceType: "server",
setState: "cookie-server",
});
await consoleMsgPromise;
});

View File

@ -231,21 +231,15 @@ async function navigateLinkClick(
* run for the given browser.
*/
async function waitForRecordBounces(browser) {
let { browserId } = browser.browsingContext;
info(
`waitForRecordBounces: Waiting for record bounces for browser: ${browserId}.`
);
await TestUtils.topicObserved(
return TestUtils.topicObserved(
OBSERVER_MSG_RECORD_BOUNCES_FINISHED,
subject => {
// Ensure the message was dispatched for the browser we're interested in.
let propBag = subject.QueryInterface(Ci.nsIPropertyBag2);
return browserId == propBag.getProperty("browserId");
let browserId = propBag.getProperty("browserId");
return browser.browsingContext.browserId == browserId;
}
);
info(`waitForRecordBounces: Recorded bounces for browser ${browserId}.`);
}
/**
@ -269,9 +263,6 @@ async function waitForRecordBounces(browser) {
* @param {('same-site'|'cross-site')} [options.setCookieViaImage] - Whether to
* set the state via an image request. Only applies to setState ==
* "cookie-server".
* @param {boolean} [options.expectRecordBounces=true] - Whether the record
* bounces algorithm runs and we should wait for the test message. This
* shouldn't run when the feature is disabled.
* @param {boolean} [options.expectCandidate=true] - Expect the redirecting site
* to be identified as a bounce tracker (candidate).
* @param {boolean} [options.expectPurge=true] - Expect the redirecting site to
@ -295,7 +286,6 @@ async function runTestBounce(options = {}) {
setStateInWebWorker = false,
setStateInNestedWebWorker = false,
setCookieViaImage = null,
expectRecordBounces = true,
expectCandidate = true,
expectPurge = true,
originAttributes = {},
@ -342,10 +332,7 @@ async function runTestBounce(options = {}) {
let browser = tab.linkedBrowser;
await BrowserTestUtils.browserLoaded(browser, true, initialURL);
let promiseRecordBounces;
if (expectRecordBounces) {
promiseRecordBounces = waitForRecordBounces(browser);
}
let promiseRecordBounces = waitForRecordBounces(browser);
// The final destination after the bounce.
let targetURL = new URL(getBaseUrl(ORIGIN_B) + "file_start.html");
@ -376,26 +363,14 @@ async function runTestBounce(options = {}) {
// Navigate again with user gesture which triggers
// BounceTrackingProtection::RecordStatefulBounces. We could rely on the
// timeout (mClientBounceDetectionTimeout) here but that can cause races in
// debug where the load is quite slow.
let finalTargetURL = new URL(getBaseUrl(ORIGIN_C) + "file_start.html");
let finalLoadPromise = BrowserTestUtils.browserLoaded(
// timeout (mClientBounceDetectionTimeout) here but that can cause races
// in debug where the load is quite slow.
await navigateLinkClick(
browser,
true,
initialURL.href
new URL(getBaseUrl(ORIGIN_C) + "file_start.html")
);
await navigateLinkClick(browser, finalTargetURL);
await finalLoadPromise;
if (expectRecordBounces) {
await promiseRecordBounces;
} else {
// If we don't expect classification to happen only wait for navigation from
// the navigateLinkClick to complete. This navigation would trigger
// RecordStatefulBounces if the protection was enabled. Give
// RecordStatefulBounces time to run after navigation.
await new Promise(resolve => setTimeout(resolve, 0));
}
await promiseRecordBounces;
Assert.deepEqual(
bounceTrackingProtection
@ -418,25 +393,11 @@ async function runTestBounce(options = {}) {
// If the caller specified a function to run after the bounce, run it now.
await postBounceCallback();
// Run tracker purging. If the feature is disabled this throws.
let mode = Services.prefs.getIntPref("privacy.bounceTrackingProtection.mode");
let expectPurgingToThrow =
mode != Ci.nsIBounceTrackingProtection.MODE_ENABLED &&
mode != Ci.nsIBounceTrackingProtection.MODE_ENABLED_DRY_RUN;
if (expectPurgingToThrow) {
await Assert.rejects(
bounceTrackingProtection.testRunPurgeBounceTrackers(),
/NS_ERROR_NOT_AVAILABLE/,
"testRunPurgeBounceTrackers should reject when BTP is disabled."
);
} else {
Assert.deepEqual(
await bounceTrackingProtection.testRunPurgeBounceTrackers(),
expectPurge ? [SITE_TRACKER] : [],
`Should ${expectPurge ? "" : "not "}purge state for ${SITE_TRACKER}.`
);
}
Assert.deepEqual(
await bounceTrackingProtection.testRunPurgeBounceTrackers(),
expectPurge ? [SITE_TRACKER] : [],
`Should ${expectPurge ? "" : "not "}purge state for ${SITE_TRACKER}.`
);
// Clean up
BrowserTestUtils.removeTab(tab);

View File

@ -1,6 +1,6 @@
[DEFAULT]
prefs = [
"privacy.bounceTrackingProtection.mode=1",
"privacy.bounceTrackingProtection.enabled=true",
"privacy.bounceTrackingProtection.enableTestMode=true",
]

View File

@ -28,11 +28,9 @@ add_setup(function () {
* @param {bool} num - Number of hosts to purge
*/
async function testNumHostsPerPurgeRun(isDryRunMode, num) {
Services.prefs.setIntPref(
"privacy.bounceTrackingProtection.mode",
Services.prefs.setBoolPref(
"privacy.bounceTrackingProtection.enableDryRunMode",
isDryRunMode
? Ci.nsIBounceTrackingProtection.MODE_ENABLED_DRY_RUN
: Ci.nsIBounceTrackingProtection.MODE_ENABLED
);
Assert.equal(
@ -71,7 +69,9 @@ async function testNumHostsPerPurgeRun(isDryRunMode, num) {
}
// Cleanup
Services.prefs.clearUserPref("privacy.bounceTrackingProtection.mode");
Services.prefs.clearUserPref(
"privacy.bounceTrackingProtection.enableDryRunMode"
);
Services.fog.testResetFOG();
btp.clearAll();
}

View File

@ -1,8 +1,9 @@
[DEFAULT]
prefs = [
"privacy.bounceTrackingProtection.mode=1",
"privacy.bounceTrackingProtection.enabled=true",
"privacy.bounceTrackingProtection.enableTestMode=true",
"privacy.bounceTrackingProtection.bounceTrackingPurgeTimerPeriodSec=0",
"privacy.bounceTrackingProtection.enableDryRunMode=false",
]
["test_bouncetracking_clearExpiredUserActivation.js"]

View File

@ -40,9 +40,9 @@ XPCOMUtils.defineLazyServiceGetter(
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
"bounceTrackingProtectionMode",
"privacy.bounceTrackingProtection.mode",
Ci.nsIBounceTrackingProtection.MODE_DISABLED
"isBounceTrackingProtectionEnabled",
"privacy.bounceTrackingProtection.enabled",
false
);
/**
@ -1798,20 +1798,14 @@ const IdentityCredentialStorageCleaner = {
const BounceTrackingProtectionStateCleaner = {
async deleteAll() {
if (
lazy.bounceTrackingProtectionMode ==
Ci.nsIBounceTrackingProtection.MODE_DISABLED
) {
if (!lazy.isBounceTrackingProtectionEnabled) {
return;
}
await lazy.bounceTrackingProtection.clearAll();
},
async deleteByPrincipal(aPrincipal) {
if (
lazy.bounceTrackingProtectionMode ==
Ci.nsIBounceTrackingProtection.MODE_DISABLED
) {
if (!lazy.isBounceTrackingProtectionEnabled) {
return;
}
let { baseDomain, originAttributes } = aPrincipal;
@ -1822,30 +1816,21 @@ const BounceTrackingProtectionStateCleaner = {
},
async deleteByBaseDomain(aBaseDomain) {
if (
lazy.bounceTrackingProtectionMode ==
Ci.nsIBounceTrackingProtection.MODE_DISABLED
) {
if (!lazy.isBounceTrackingProtectionEnabled) {
return;
}
await lazy.bounceTrackingProtection.clearBySiteHost(aBaseDomain);
},
async deleteByRange(aFrom, aTo) {
if (
lazy.bounceTrackingProtectionMode ==
Ci.nsIBounceTrackingProtection.MODE_DISABLED
) {
if (!lazy.isBounceTrackingProtectionEnabled) {
return;
}
await lazy.bounceTrackingProtection.clearByTimeRange(aFrom, aTo);
},
async deleteByHost(aHost) {
if (
lazy.bounceTrackingProtectionMode ==
Ci.nsIBounceTrackingProtection.MODE_DISABLED
) {
if (!lazy.isBounceTrackingProtectionEnabled) {
return;
}
let baseDomain = getBaseDomainWithFallback(aHost);
@ -1853,10 +1838,7 @@ const BounceTrackingProtectionStateCleaner = {
},
async deleteByOriginAttributes(aOriginAttributesPatternString) {
if (
lazy.bounceTrackingProtectionMode ==
Ci.nsIBounceTrackingProtection.MODE_DISABLED
) {
if (!lazy.isBounceTrackingProtectionEnabled) {
return;
}
await lazy.bounceTrackingProtection.clearByOriginAttributesPattern(

View File

@ -3423,11 +3423,21 @@ bounceTrackingProtection:
hasExposure: false
variables:
enabled:
type: int
type: boolean
setPref:
branch: default
pref: privacy.bounceTrackingProtection.mode
description: Mode to run the feature in. See nsIBounceTrackingProtection.idl for documentation.
pref: privacy.bounceTrackingProtection.enabled
description: Main flag to enable / disable the feature.
enableDryRunMode:
type: boolean
setPref:
branch: default
pref: privacy.bounceTrackingProtection.enableDryRunMode
description: >-
Enables a mode where if bounce tracking protection is enabled it
classifies but does not purge trackers. This mode is helpful for testing
the feature without risking data loss. Telemetry is still collected
normally.
remoteTabManagement:
description: >

View File

@ -1,13 +0,0 @@
# 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/.
# Message which is shown when Bounce Tracking Protection has detected site as a
# bounce tracker. Do not translate "bounce tracker".
# Variables:
# $siteHost (string): The host portion of the site which has been classified as a tracker.
# $gracePeriodSeconds (number): Grace period window in seconds until the site purged (clearing cookies, storages and caches).
btp-warning-tracker-classified =
{ $gracePeriodSeconds ->
*[other] “{ $siteHost }” has been classified as a bounce tracker. If it does not receive user activation within the next { $gracePeriodSeconds } seconds it will have its state purged.
}