mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-14 04:03:47 +00:00
Backed out 8 changesets (bug 1839919, bug 1876579, bug 1878915) for causing non-unified build bustages on nsCOMPtr.h.
Backed out changeset 99ce75dc42c5 (bug 1878915) Backed out changeset 1ba7f2b78980 (bug 1878915) Backed out changeset c4675cbf4e84 (bug 1878915) Backed out changeset df1f8aa6637f (bug 1839919) Backed out changeset 325f849a24df (bug 1839919) Backed out changeset e1f7b77f841b (bug 1839919) Backed out changeset 33e6ffa9f8cc (bug 1876579) Backed out changeset bae7618dff51 (bug 1876579)
This commit is contained in:
parent
639a3118d1
commit
7b230cb210
@ -477,8 +477,7 @@ export var Sanitizer = {
|
||||
principalsForShutdownClearing,
|
||||
Ci.nsIClearDataService.CLEAR_COOKIES |
|
||||
Ci.nsIClearDataService.CLEAR_COOKIE_BANNER_EXECUTED_RECORD |
|
||||
Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE |
|
||||
Ci.nsIClearDataService.CLEAR_BOUNCE_TRACKING_PROTECTION_STATE
|
||||
Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE
|
||||
);
|
||||
} else {
|
||||
// Not on shutdown
|
||||
@ -486,8 +485,7 @@ export var Sanitizer = {
|
||||
range,
|
||||
Ci.nsIClearDataService.CLEAR_COOKIES |
|
||||
Ci.nsIClearDataService.CLEAR_COOKIE_BANNER_EXECUTED_RECORD |
|
||||
Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE |
|
||||
Ci.nsIClearDataService.CLEAR_BOUNCE_TRACKING_PROTECTION_STATE
|
||||
Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE
|
||||
);
|
||||
}
|
||||
await clearData(range, Ci.nsIClearDataService.CLEAR_MEDIA_DEVICES);
|
||||
@ -922,8 +920,7 @@ export var Sanitizer = {
|
||||
Ci.nsIClearDataService.CLEAR_DOM_STORAGES |
|
||||
Ci.nsIClearDataService.CLEAR_AUTH_TOKENS |
|
||||
Ci.nsIClearDataService.CLEAR_AUTH_CACHE |
|
||||
Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE |
|
||||
Ci.nsIClearDataService.CLEAR_BOUNCE_TRACKING_PROTECTION_STATE
|
||||
Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE
|
||||
);
|
||||
} else {
|
||||
// Not on shutdown
|
||||
@ -934,8 +931,7 @@ export var Sanitizer = {
|
||||
Ci.nsIClearDataService.CLEAR_DOM_STORAGES |
|
||||
Ci.nsIClearDataService.CLEAR_AUTH_TOKENS |
|
||||
Ci.nsIClearDataService.CLEAR_AUTH_CACHE |
|
||||
Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE |
|
||||
Ci.nsIClearDataService.CLEAR_BOUNCE_TRACKING_PROTECTION_STATE
|
||||
Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE
|
||||
);
|
||||
}
|
||||
await clearData(range, Ci.nsIClearDataService.CLEAR_MEDIA_DEVICES);
|
||||
@ -1182,8 +1178,7 @@ async function sanitizeOnShutdown(progress) {
|
||||
Ci.nsIClearDataService.CLEAR_ALL_CACHES |
|
||||
Ci.nsIClearDataService.CLEAR_COOKIES |
|
||||
Ci.nsIClearDataService.CLEAR_DOM_STORAGES |
|
||||
Ci.nsIClearDataService.CLEAR_EME |
|
||||
Ci.nsIClearDataService.CLEAR_BOUNCE_TRACKING_PROTECTION_STATE
|
||||
Ci.nsIClearDataService.CLEAR_EME
|
||||
);
|
||||
progress.sanitizationPrefs.session_permission_exceptions = exceptions;
|
||||
}
|
||||
|
@ -551,8 +551,7 @@ export var SiteDataManager = {
|
||||
Ci.nsIClearDataService.CLEAR_EME |
|
||||
Ci.nsIClearDataService.CLEAR_ALL_CACHES |
|
||||
Ci.nsIClearDataService.CLEAR_COOKIE_BANNER_EXECUTED_RECORD |
|
||||
Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE |
|
||||
Ci.nsIClearDataService.CLEAR_BOUNCE_TRACKING_PROTECTION_STATE;
|
||||
Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE;
|
||||
promises.push(
|
||||
new Promise(function (resolve) {
|
||||
const { clearData } = Services;
|
||||
@ -690,8 +689,7 @@ export var SiteDataManager = {
|
||||
Ci.nsIClearDataService.CLEAR_COOKIES |
|
||||
Ci.nsIClearDataService.CLEAR_DOM_STORAGES |
|
||||
Ci.nsIClearDataService.CLEAR_HSTS |
|
||||
Ci.nsIClearDataService.CLEAR_EME |
|
||||
Ci.nsIClearDataService.CLEAR_BOUNCE_TRACKING_PROTECTION_STATE,
|
||||
Ci.nsIClearDataService.CLEAR_EME,
|
||||
resolve
|
||||
);
|
||||
});
|
||||
|
@ -1,55 +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_OriginAttributesHashKey_h
|
||||
#define mozilla_OriginAttributesHashKey_h
|
||||
|
||||
#include "OriginAttributes.h"
|
||||
#include "PLDHashTable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class OriginAttributesHashKey : public PLDHashEntryHdr {
|
||||
public:
|
||||
using KeyType = OriginAttributes;
|
||||
using KeyTypeRef = const KeyType&;
|
||||
using KeyTypePointer = const KeyType*;
|
||||
|
||||
explicit OriginAttributesHashKey(KeyTypePointer aKey) {
|
||||
mOriginAttributes = *aKey;
|
||||
MOZ_COUNT_CTOR(OriginAttributesHashKey);
|
||||
}
|
||||
OriginAttributesHashKey(OriginAttributesHashKey&& aKey) noexcept {
|
||||
mOriginAttributes = std::move(aKey.mOriginAttributes);
|
||||
MOZ_COUNT_CTOR(OriginAttributesHashKey);
|
||||
}
|
||||
|
||||
MOZ_COUNTED_DTOR(OriginAttributesHashKey)
|
||||
|
||||
KeyTypeRef GetKey() const { return mOriginAttributes; }
|
||||
|
||||
bool KeyEquals(KeyTypePointer aKey) const {
|
||||
return mOriginAttributes == *aKey;
|
||||
}
|
||||
|
||||
static KeyTypePointer KeyToPointer(KeyTypeRef aKey) { return &aKey; }
|
||||
|
||||
static PLDHashNumber HashKey(KeyTypePointer aKey) {
|
||||
nsAutoCString suffix;
|
||||
aKey->CreateSuffix(suffix);
|
||||
return mozilla::HashString(suffix);
|
||||
}
|
||||
|
||||
enum { ALLOW_MEMMOVE = true };
|
||||
|
||||
protected:
|
||||
OriginAttributes mOriginAttributes;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -34,7 +34,6 @@ EXPORTS.mozilla = [
|
||||
"ExpandedPrincipal.h",
|
||||
"NullPrincipal.h",
|
||||
"OriginAttributes.h",
|
||||
"OriginAttributesHashKey.h",
|
||||
"PrincipalHashKey.h",
|
||||
"SystemPrincipal.h",
|
||||
]
|
||||
|
@ -38,8 +38,7 @@ const ClearFlags = [
|
||||
Ci.nsIClearDataService.CLEAR_COOKIES |
|
||||
Ci.nsIClearDataService.CLEAR_MEDIA_DEVICES |
|
||||
Ci.nsIClearDataService.CLEAR_COOKIE_BANNER_EXECUTED_RECORD |
|
||||
Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE |
|
||||
Ci.nsIClearDataService.CLEAR_BOUNCE_TRACKING_PROTECTION_STATE,
|
||||
Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE,
|
||||
],
|
||||
[
|
||||
// NETWORK_CACHE
|
||||
@ -64,8 +63,7 @@ const ClearFlags = [
|
||||
Ci.nsIClearDataService.CLEAR_DOM_PUSH_NOTIFICATIONS |
|
||||
Ci.nsIClearDataService.CLEAR_REPORTS |
|
||||
Ci.nsIClearDataService.CLEAR_COOKIE_BANNER_EXECUTED_RECORD |
|
||||
Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE |
|
||||
Ci.nsIClearDataService.CLEAR_BOUNCE_TRACKING_PROTECTION_STATE,
|
||||
Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE,
|
||||
],
|
||||
[
|
||||
// AUTH_SESSIONS
|
||||
|
@ -4,19 +4,16 @@
|
||||
|
||||
#include "BounceTrackingProtection.h"
|
||||
|
||||
#include "BounceTrackingProtectionStorage.h"
|
||||
#include "BounceTrackingState.h"
|
||||
#include "BounceTrackingRecord.h"
|
||||
|
||||
#include "BounceTrackingStateGlobal.h"
|
||||
#include "ErrorList.h"
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/StaticPrefs_privacy.h"
|
||||
#include "mozilla/dom/BrowsingContextBinding.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsHashPropertyBag.h"
|
||||
#include "nsIClearDataService.h"
|
||||
#include "nsIObserverService.h"
|
||||
@ -68,15 +65,6 @@ BounceTrackingProtection::GetSingleton() {
|
||||
BounceTrackingProtection::BounceTrackingProtection() {
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug, ("constructor"));
|
||||
|
||||
mStorage = new BounceTrackingProtectionStorage();
|
||||
|
||||
nsresult rv = mStorage->Init();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Error,
|
||||
("storage init failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Schedule timer for tracker purging. The timer interval is determined by
|
||||
// pref.
|
||||
uint32_t purgeTimerPeriod = StaticPrefs::
|
||||
@ -91,7 +79,7 @@ BounceTrackingProtection::BounceTrackingProtection() {
|
||||
("Scheduling mBounceTrackingPurgeTimer. Interval: %d seconds.",
|
||||
purgeTimerPeriod));
|
||||
|
||||
rv = NS_NewTimerWithCallback(
|
||||
DebugOnly<nsresult> rv = NS_NewTimerWithCallback(
|
||||
getter_AddRefs(mBounceTrackingPurgeTimer),
|
||||
[](auto) {
|
||||
if (!sBounceTrackingProtection) {
|
||||
@ -126,11 +114,6 @@ nsresult BounceTrackingProtection::RecordStatefulBounces(
|
||||
aBounceTrackingState->GetBounceTrackingRecord();
|
||||
NS_ENSURE_TRUE(record, NS_ERROR_FAILURE);
|
||||
|
||||
// Get the bounce tracker map and the user activation map.
|
||||
RefPtr<BounceTrackingStateGlobal> globalState =
|
||||
mStorage->GetOrCreateStateGlobal(aBounceTrackingState);
|
||||
MOZ_ASSERT(globalState);
|
||||
|
||||
// For each host in navigable’s bounce tracking record's bounce set:
|
||||
for (const nsACString& host : record->GetBounceHosts()) {
|
||||
// If host equals navigable’s bounce tracking record's initial host,
|
||||
@ -150,7 +133,7 @@ nsresult BounceTrackingProtection::RecordStatefulBounces(
|
||||
}
|
||||
|
||||
// If user activation map contains host, continue.
|
||||
if (globalState->HasUserActivation(host)) {
|
||||
if (mUserActivation.Contains(host)) {
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: Skip host with recent user activation: %s", __FUNCTION__,
|
||||
PromiseFlatCString(host).get()));
|
||||
@ -158,7 +141,7 @@ nsresult BounceTrackingProtection::RecordStatefulBounces(
|
||||
}
|
||||
|
||||
// If stateful bounce tracking map contains host, continue.
|
||||
if (globalState->HasBounceTracker(host)) {
|
||||
if (mBounceTrackers.Contains(host)) {
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: Skip already existing host: %s", __FUNCTION__,
|
||||
PromiseFlatCString(host).get()));
|
||||
@ -179,11 +162,8 @@ nsresult BounceTrackingProtection::RecordStatefulBounces(
|
||||
// Set stateful bounce tracking map[host] to topDocument’s relevant settings
|
||||
// object's current wall time.
|
||||
PRTime now = PR_Now();
|
||||
MOZ_ASSERT(!globalState->HasBounceTracker(host));
|
||||
nsresult rv = globalState->RecordBounceTracker(host, now);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
MOZ_ASSERT(!mBounceTrackers.Contains(host));
|
||||
mBounceTrackers.InsertOrUpdate(host, now);
|
||||
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Info,
|
||||
("%s: Added candidate to mBounceTrackers: %s, Time: %" PRIu64,
|
||||
@ -232,28 +212,23 @@ nsresult BounceTrackingProtection::RecordUserActivation(
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Info,
|
||||
("%s: siteHost: %s", __FUNCTION__, siteHost.get()));
|
||||
|
||||
RefPtr<BounceTrackingStateGlobal> globalState =
|
||||
mStorage->GetOrCreateStateGlobal(aPrincipal);
|
||||
MOZ_ASSERT(globalState);
|
||||
bool hasRemoved = mBounceTrackers.Remove(siteHost);
|
||||
if (hasRemoved) {
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: Removed bounce tracking candidate due to user activation: %s",
|
||||
__FUNCTION__, siteHost.get()));
|
||||
}
|
||||
MOZ_ASSERT(!mBounceTrackers.Contains(siteHost));
|
||||
|
||||
return globalState->RecordUserActivation(siteHost, PR_Now());
|
||||
mUserActivation.InsertOrUpdate(siteHost, PR_Now());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BounceTrackingProtection::TestGetBounceTrackerCandidateHosts(
|
||||
JS::Handle<JS::Value> aOriginAttributes, JSContext* aCx,
|
||||
BounceTrackingProtection::GetBounceTrackerCandidateHosts(
|
||||
nsTArray<nsCString>& aCandidates) {
|
||||
MOZ_ASSERT(aCx);
|
||||
|
||||
OriginAttributes oa;
|
||||
if (!aOriginAttributes.isObject() || !oa.Init(aCx, aOriginAttributes)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
BounceTrackingStateGlobal* globalState = mStorage->GetOrCreateStateGlobal(oa);
|
||||
MOZ_ASSERT(globalState);
|
||||
|
||||
for (const nsACString& host : globalState->BounceTrackersMapRef().Keys()) {
|
||||
for (const nsACString& host : mBounceTrackers.Keys()) {
|
||||
aCandidates.AppendElement(host);
|
||||
}
|
||||
|
||||
@ -261,20 +236,8 @@ BounceTrackingProtection::TestGetBounceTrackerCandidateHosts(
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BounceTrackingProtection::TestGetUserActivationHosts(
|
||||
JS::Handle<JS::Value> aOriginAttributes, JSContext* aCx,
|
||||
nsTArray<nsCString>& aHosts) {
|
||||
MOZ_ASSERT(aCx);
|
||||
|
||||
OriginAttributes oa;
|
||||
if (!aOriginAttributes.isObject() || !oa.Init(aCx, aOriginAttributes)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
BounceTrackingStateGlobal* globalState = mStorage->GetOrCreateStateGlobal(oa);
|
||||
MOZ_ASSERT(globalState);
|
||||
|
||||
for (const nsACString& host : globalState->UserActivationMapRef().Keys()) {
|
||||
BounceTrackingProtection::GetUserActivationHosts(nsTArray<nsCString>& aHosts) {
|
||||
for (const nsACString& host : mUserActivation.Keys()) {
|
||||
aHosts.AppendElement(host);
|
||||
}
|
||||
|
||||
@ -282,59 +245,13 @@ BounceTrackingProtection::TestGetUserActivationHosts(
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BounceTrackingProtection::ClearAll() {
|
||||
BounceTrackingState::ResetAll();
|
||||
return mStorage->Clear();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BounceTrackingProtection::ClearBySiteHostAndOA(
|
||||
const nsACString& aSiteHost, JS::Handle<JS::Value> aOriginAttributes,
|
||||
JSContext* aCx) {
|
||||
NS_ENSURE_ARG_POINTER(aCx);
|
||||
|
||||
OriginAttributes originAttributes;
|
||||
if (!aOriginAttributes.isObject() ||
|
||||
!originAttributes.Init(aCx, aOriginAttributes)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Reset per tab state for tabs matching the given OriginAttributes.
|
||||
BounceTrackingState::ResetAllForOriginAttributes(originAttributes);
|
||||
|
||||
return mStorage->ClearBySiteHost(aSiteHost, &originAttributes);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BounceTrackingProtection::ClearBySiteHost(const nsACString& aSiteHost) {
|
||||
BounceTrackingProtection::Reset() {
|
||||
BounceTrackingState::ResetAll();
|
||||
|
||||
return mStorage->ClearBySiteHost(aSiteHost, nullptr);
|
||||
}
|
||||
mBounceTrackers.Clear();
|
||||
mUserActivation.Clear();
|
||||
|
||||
NS_IMETHODIMP
|
||||
BounceTrackingProtection::ClearByTimeRange(PRTime aFrom, PRTime aTo) {
|
||||
NS_ENSURE_TRUE(aFrom >= 0, NS_ERROR_INVALID_ARG);
|
||||
NS_ENSURE_TRUE(aFrom < aTo, NS_ERROR_INVALID_ARG);
|
||||
|
||||
// Clear all BounceTrackingState, we don't keep track of time ranges.
|
||||
BounceTrackingState::ResetAll();
|
||||
|
||||
return mStorage->ClearByTimeRange(aFrom, aTo);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BounceTrackingProtection::ClearByOriginAttributesPattern(
|
||||
const nsAString& aPattern) {
|
||||
OriginAttributesPattern pattern;
|
||||
if (!pattern.Init(aPattern)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Reset all per-tab state matching the given OriginAttributesPattern.
|
||||
BounceTrackingState::ResetAllForOriginAttributesPattern(pattern);
|
||||
|
||||
return mStorage->ClearByOriginAttributesPattern(pattern);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -370,114 +287,34 @@ BounceTrackingProtection::TestRunPurgeBounceTrackers(
|
||||
|
||||
NS_IMETHODIMP
|
||||
BounceTrackingProtection::TestAddBounceTrackerCandidate(
|
||||
JS::Handle<JS::Value> aOriginAttributes, const nsACString& aHost,
|
||||
const PRTime aBounceTime, JSContext* aCx) {
|
||||
MOZ_ASSERT(aCx);
|
||||
|
||||
OriginAttributes oa;
|
||||
if (!aOriginAttributes.isObject() || !oa.Init(aCx, aOriginAttributes)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
BounceTrackingStateGlobal* stateGlobal = mStorage->GetOrCreateStateGlobal(oa);
|
||||
MOZ_ASSERT(stateGlobal);
|
||||
|
||||
// Ensure aHost is lowercase to match nsIURI and nsIPrincipal.
|
||||
nsAutoCString host(aHost);
|
||||
ToLowerCase(host);
|
||||
|
||||
const nsACString& aHost, const PRTime aBounceTime) {
|
||||
// Can not have a host in both maps.
|
||||
nsresult rv = stateGlobal->TestRemoveUserActivation(host);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return stateGlobal->RecordBounceTracker(host, aBounceTime);
|
||||
mUserActivation.Remove(aHost);
|
||||
mBounceTrackers.InsertOrUpdate(aHost, aBounceTime);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BounceTrackingProtection::TestAddUserActivation(
|
||||
JS::Handle<JS::Value> aOriginAttributes, const nsACString& aHost,
|
||||
const PRTime aActivationTime, JSContext* aCx) {
|
||||
MOZ_ASSERT(aCx);
|
||||
|
||||
OriginAttributes oa;
|
||||
if (!aOriginAttributes.isObject() || !oa.Init(aCx, aOriginAttributes)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
BounceTrackingStateGlobal* stateGlobal = mStorage->GetOrCreateStateGlobal(oa);
|
||||
MOZ_ASSERT(stateGlobal);
|
||||
|
||||
// Ensure aHost is lowercase to match nsIURI and nsIPrincipal.
|
||||
nsAutoCString host(aHost);
|
||||
ToLowerCase(host);
|
||||
|
||||
return stateGlobal->RecordUserActivation(host, aActivationTime);
|
||||
BounceTrackingProtection::TestAddUserActivation(const nsACString& aHost,
|
||||
const PRTime aActivationTime) {
|
||||
// Can not have a host in both maps.
|
||||
mBounceTrackers.Remove(aHost);
|
||||
mUserActivation.InsertOrUpdate(aHost, aActivationTime);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<BounceTrackingProtection::PurgeBounceTrackersMozPromise>
|
||||
BounceTrackingProtection::PurgeBounceTrackers() {
|
||||
// Run the purging algorithm for all global state objects.
|
||||
for (const auto& entry : mStorage->StateGlobalMapRef()) {
|
||||
const OriginAttributes& originAttributes = entry.GetKey();
|
||||
BounceTrackingStateGlobal* stateGlobal = entry.GetData();
|
||||
MOZ_ASSERT(stateGlobal);
|
||||
|
||||
if (MOZ_LOG_TEST(gBounceTrackingProtectionLog, LogLevel::Debug)) {
|
||||
nsAutoCString oaSuffix;
|
||||
originAttributes.CreateSuffix(oaSuffix);
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: Running purge algorithm for OA: '%s'", __FUNCTION__,
|
||||
oaSuffix.get()));
|
||||
}
|
||||
|
||||
PurgeBounceTrackersForStateGlobal(stateGlobal, originAttributes);
|
||||
}
|
||||
|
||||
// Wait for all data clearing operations to complete. mClearPromises contains
|
||||
// one promise per host / clear task.
|
||||
return ClearDataMozPromise::AllSettled(GetCurrentSerialEventTarget(),
|
||||
mClearPromises)
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[&](ClearDataMozPromise::AllSettledPromiseType::ResolveOrRejectValue&&
|
||||
aResults) {
|
||||
MOZ_ASSERT(aResults.IsResolve(), "AllSettled never rejects");
|
||||
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Info,
|
||||
("%s: Done. Cleared %zu hosts.", __FUNCTION__,
|
||||
aResults.ResolveValue().Length()));
|
||||
|
||||
nsTArray<nsCString> purgedSiteHosts;
|
||||
// If any clear call failed reject.
|
||||
for (auto& result : aResults.ResolveValue()) {
|
||||
if (result.IsReject()) {
|
||||
mClearPromises.Clear();
|
||||
return PurgeBounceTrackersMozPromise::CreateAndReject(
|
||||
NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
purgedSiteHosts.AppendElement(result.ResolveValue());
|
||||
}
|
||||
|
||||
// No clearing errors, resolve.
|
||||
mClearPromises.Clear();
|
||||
return PurgeBounceTrackersMozPromise::CreateAndResolve(
|
||||
std::move(purgedSiteHosts), __func__);
|
||||
});
|
||||
}
|
||||
|
||||
nsresult BounceTrackingProtection::PurgeBounceTrackersForStateGlobal(
|
||||
BounceTrackingStateGlobal* aStateGlobal,
|
||||
const OriginAttributes& aOriginAttributes) {
|
||||
MOZ_ASSERT(aStateGlobal);
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: #mUserActivation: %d, #mBounceTrackers: %d", __FUNCTION__,
|
||||
aStateGlobal->UserActivationMapRef().Count(),
|
||||
aStateGlobal->BounceTrackersMapRef().Count()));
|
||||
mUserActivation.Count(), mBounceTrackers.Count()));
|
||||
|
||||
// Purge already in progress.
|
||||
if (!mClearPromises.IsEmpty()) {
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: Skip: Purge already in progress.", __FUNCTION__));
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
return PurgeBounceTrackersMozPromise::CreateAndReject(
|
||||
NS_ERROR_NOT_AVAILABLE, __func__);
|
||||
}
|
||||
|
||||
const PRTime now = PR_Now();
|
||||
@ -492,25 +329,38 @@ nsresult BounceTrackingProtection::PurgeBounceTrackersForStateGlobal(
|
||||
|
||||
// 1. Remove hosts from the user activation map whose user activation flag has
|
||||
// expired.
|
||||
nsresult rv =
|
||||
aStateGlobal->ClearUserActivationBefore(now - activationLifetimeUsec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
for (auto hostIter = mUserActivation.Iter(); !hostIter.Done();
|
||||
hostIter.Next()) {
|
||||
const nsACString& host = hostIter.Key();
|
||||
|
||||
// Ensure that mBounceTrackers and mUserActivation maps are disjoint. A host
|
||||
// can never be in both maps.
|
||||
MOZ_ASSERT(!mBounceTrackers.Contains(host));
|
||||
|
||||
// If activationTime + bounce tracking activation lifetime is before now,
|
||||
// then remove host from user activation map.
|
||||
const PRTime& activationTime = hostIter.Data();
|
||||
if ((activationTime + activationLifetimeUsec) < now) {
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: Remove expired user activation for %s", __FUNCTION__,
|
||||
PromiseFlatCString(host).get()));
|
||||
hostIter.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Go over bounce tracker candidate map and purge state.
|
||||
rv = NS_OK;
|
||||
nsresult rv = NS_OK;
|
||||
nsCOMPtr<nsIClearDataService> clearDataService =
|
||||
do_GetService("@mozilla.org/clear-data-service;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return PurgeBounceTrackersMozPromise::CreateAndReject(rv, __func__);
|
||||
}
|
||||
|
||||
mClearPromises.Clear();
|
||||
nsTArray<nsCString> purgedSiteHosts;
|
||||
|
||||
// Collect hosts to remove from the bounce trackers map. We can not remove
|
||||
// them while iterating over the map.
|
||||
nsTArray<nsCString> bounceTrackerCandidatesToRemove;
|
||||
|
||||
for (auto hostIter = aStateGlobal->BounceTrackersMapRef().ConstIter();
|
||||
!hostIter.Done(); hostIter.Next()) {
|
||||
for (auto hostIter = mBounceTrackers.Iter(); !hostIter.Done();
|
||||
hostIter.Next()) {
|
||||
const nsACString& host = hostIter.Key();
|
||||
const PRTime& bounceTime = hostIter.Data();
|
||||
|
||||
@ -555,7 +405,9 @@ nsresult BounceTrackingProtection::PurgeBounceTrackersForStateGlobal(
|
||||
("%s: Purge state for host: %s", __FUNCTION__,
|
||||
PromiseFlatCString(host).get()));
|
||||
|
||||
// TODO: Bug 1842067: Clear by site + OA.
|
||||
// TODO: Bug 1842067: DeleteDataFromBaseDomain clears the whole cookie jar,
|
||||
// including state partitioned under `host` as the top level. Consider only
|
||||
// clearing unpartitioned state.
|
||||
rv = clearDataService->DeleteDataFromBaseDomain(host, false,
|
||||
TRACKER_PURGE_FLAGS, cb);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
@ -567,12 +419,39 @@ nsresult BounceTrackingProtection::PurgeBounceTrackersForStateGlobal(
|
||||
// Remove it from the bounce trackers map, it's about to be purged. If the
|
||||
// clear call fails still remove it. We want to avoid an ever growing list
|
||||
// of hosts in case of repeated failures.
|
||||
bounceTrackerCandidatesToRemove.AppendElement(host);
|
||||
hostIter.Remove();
|
||||
}
|
||||
|
||||
// Remove hosts from the bounce trackers map which we executed purge calls
|
||||
// for.
|
||||
return aStateGlobal->RemoveBounceTrackers(bounceTrackerCandidatesToRemove);
|
||||
// Wait for all data clearing operations to complete. mClearPromises contains
|
||||
// one promise per host / clear task.
|
||||
return ClearDataMozPromise::AllSettled(GetCurrentSerialEventTarget(),
|
||||
mClearPromises)
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[&](ClearDataMozPromise::AllSettledPromiseType::ResolveOrRejectValue&&
|
||||
aResults) {
|
||||
MOZ_ASSERT(aResults.IsResolve(), "AllSettled never rejects");
|
||||
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Info,
|
||||
("%s: Done. Cleared %zu hosts.", __FUNCTION__,
|
||||
aResults.ResolveValue().Length()));
|
||||
|
||||
nsTArray<nsCString> purgedSiteHosts;
|
||||
// If any clear call failed reject.
|
||||
for (auto& result : aResults.ResolveValue()) {
|
||||
if (result.IsReject()) {
|
||||
mClearPromises.Clear();
|
||||
return PurgeBounceTrackersMozPromise::CreateAndReject(
|
||||
NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
purgedSiteHosts.AppendElement(result.ResolveValue());
|
||||
}
|
||||
|
||||
// No clearing errors, resolve.
|
||||
mClearPromises.Clear();
|
||||
return PurgeBounceTrackersMozPromise::CreateAndResolve(
|
||||
std::move(purgedSiteHosts), __func__);
|
||||
});
|
||||
}
|
||||
|
||||
// ClearDataCallback
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "nsIBounceTrackingProtection.h"
|
||||
#include "nsIClearDataService.h"
|
||||
#include "nsTHashMap.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
class nsITimer;
|
||||
@ -15,9 +16,6 @@ class nsITimer;
|
||||
namespace mozilla {
|
||||
|
||||
class BounceTrackingState;
|
||||
class BounceTrackingStateGlobal;
|
||||
class BounceTrackingProtectionStorage;
|
||||
class OriginAttributes;
|
||||
|
||||
extern LazyLogModule gBounceTrackingProtectionLog;
|
||||
|
||||
@ -42,21 +40,25 @@ class BounceTrackingProtection final : public nsIBounceTrackingProtection {
|
||||
BounceTrackingProtection();
|
||||
~BounceTrackingProtection() = default;
|
||||
|
||||
// Map of site hosts to moments. The moments represent the most recent wall
|
||||
// clock time at which the user activated a top-level document on the
|
||||
// associated site host.
|
||||
nsTHashMap<nsCStringHashKey, PRTime> mUserActivation{};
|
||||
|
||||
// Map of site hosts to moments. The moments represent the first wall clock
|
||||
// time since the last execution of the bounce tracking timer at which a page
|
||||
// on the given site host performed an action that could indicate stateful
|
||||
// bounce tracking took place.
|
||||
nsTHashMap<nsCStringHashKey, PRTime> mBounceTrackers{};
|
||||
|
||||
// Timer which periodically runs PurgeBounceTrackers.
|
||||
nsCOMPtr<nsITimer> mBounceTrackingPurgeTimer;
|
||||
|
||||
// Storage for user agent globals.
|
||||
RefPtr<BounceTrackingProtectionStorage> mStorage;
|
||||
|
||||
// Clear state for classified bounce trackers. To be called on an interval.
|
||||
using PurgeBounceTrackersMozPromise =
|
||||
MozPromise<nsTArray<nsCString>, nsresult, true>;
|
||||
RefPtr<PurgeBounceTrackersMozPromise> PurgeBounceTrackers();
|
||||
|
||||
nsresult PurgeBounceTrackersForStateGlobal(
|
||||
BounceTrackingStateGlobal* aStateGlobal,
|
||||
const OriginAttributes& aOriginAttributes);
|
||||
|
||||
// Pending clear operations are stored as ClearDataMozPromise, one per host.
|
||||
using ClearDataMozPromise = MozPromise<nsCString, uint32_t, true>;
|
||||
nsTArray<RefPtr<ClearDataMozPromise>> mClearPromises;
|
||||
|
@ -1,841 +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/. */
|
||||
|
||||
#include "BounceTrackingProtectionStorage.h"
|
||||
#include <cstdint>
|
||||
|
||||
#include "BounceTrackingState.h"
|
||||
#include "BounceTrackingStateGlobal.h"
|
||||
#include "ErrorList.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozIStorageConnection.h"
|
||||
#include "mozIStorageService.h"
|
||||
#include "mozIStorageStatement.h"
|
||||
#include "mozStorageCID.h"
|
||||
#include "mozilla/Components.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/AppShutdown.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/ShutdownPhase.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsStringFwd.h"
|
||||
#include "nsVariant.h"
|
||||
#include "nscore.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
#define BOUNCE_TRACKING_PROTECTION_DB_FILENAME \
|
||||
"bounce-tracking-protection.sqlite"_ns
|
||||
#define SCHEMA_VERSION 1
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
NS_IMPL_ISUPPORTS(BounceTrackingProtectionStorage, nsIAsyncShutdownBlocker,
|
||||
nsIObserver);
|
||||
|
||||
BounceTrackingStateGlobal*
|
||||
BounceTrackingProtectionStorage::GetOrCreateStateGlobal(
|
||||
nsIPrincipal* aPrincipal) {
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
return GetOrCreateStateGlobal(aPrincipal->OriginAttributesRef());
|
||||
}
|
||||
|
||||
BounceTrackingStateGlobal*
|
||||
BounceTrackingProtectionStorage::GetOrCreateStateGlobal(
|
||||
BounceTrackingState* aBounceTrackingState) {
|
||||
MOZ_ASSERT(aBounceTrackingState);
|
||||
return GetOrCreateStateGlobal(aBounceTrackingState->OriginAttributesRef());
|
||||
}
|
||||
|
||||
BounceTrackingStateGlobal*
|
||||
BounceTrackingProtectionStorage::GetOrCreateStateGlobal(
|
||||
const OriginAttributes& aOriginAttributes) {
|
||||
return mStateGlobal.GetOrInsertNew(aOriginAttributes, this,
|
||||
aOriginAttributes);
|
||||
}
|
||||
|
||||
nsresult BounceTrackingProtectionStorage::ClearBySiteHost(
|
||||
const nsACString& aSiteHost, OriginAttributes* aOriginAttributes) {
|
||||
NS_ENSURE_TRUE(!aSiteHost.IsEmpty(), NS_ERROR_INVALID_ARG);
|
||||
|
||||
// If OriginAttributes are passed only clear the matching state global.
|
||||
if (aOriginAttributes) {
|
||||
RefPtr<BounceTrackingStateGlobal> stateGlobal =
|
||||
mStateGlobal.Get(*aOriginAttributes);
|
||||
if (stateGlobal) {
|
||||
nsresult rv = stateGlobal->ClearSiteHost(aSiteHost, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
} else {
|
||||
// Otherwise we need to clear the host across all state globals.
|
||||
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->ClearSiteHost(aSiteHost, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the database.
|
||||
// Private browsing data is not written to disk.
|
||||
if (aOriginAttributes &&
|
||||
aOriginAttributes->mPrivateBrowsingId !=
|
||||
nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID) {
|
||||
return NS_OK;
|
||||
}
|
||||
return DeleteDBEntries(aOriginAttributes, aSiteHost);
|
||||
}
|
||||
|
||||
nsresult BounceTrackingProtectionStorage::ClearByTimeRange(PRTime aFrom,
|
||||
PRTime aTo) {
|
||||
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->ClearByTimeRange(aFrom, Some(aTo), Nothing(), true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Update the database.
|
||||
return DeleteDBEntriesInTimeRange(nullptr, aFrom, Some(aTo));
|
||||
}
|
||||
|
||||
nsresult BounceTrackingProtectionStorage::ClearByOriginAttributesPattern(
|
||||
const OriginAttributesPattern& aOriginAttributesPattern) {
|
||||
// Clear in memory state.
|
||||
for (auto iter = mStateGlobal.Iter(); !iter.Done(); iter.Next()) {
|
||||
if (aOriginAttributesPattern.Matches(iter.Key())) {
|
||||
iter.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Update the database.
|
||||
// Private browsing data is not written to disk.
|
||||
if (aOriginAttributesPattern.mPrivateBrowsingId.WasPassed() &&
|
||||
aOriginAttributesPattern.mPrivateBrowsingId.Value() !=
|
||||
nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID) {
|
||||
return NS_OK;
|
||||
}
|
||||
return DeleteDBEntriesByOriginAttributesPattern(aOriginAttributesPattern);
|
||||
}
|
||||
|
||||
nsresult BounceTrackingProtectionStorage::UpdateDBEntry(
|
||||
const OriginAttributes& aOriginAttributes, const nsACString& aSiteHost,
|
||||
EntryType aEntryType, PRTime aTimeStamp) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aSiteHost.IsEmpty());
|
||||
MOZ_ASSERT(aTimeStamp);
|
||||
|
||||
nsresult rv = WaitForInitialization();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (MOZ_LOG_TEST(gBounceTrackingProtectionLog, LogLevel::Debug)) {
|
||||
nsAutoCString originAttributeSuffix;
|
||||
aOriginAttributes.CreateSuffix(originAttributeSuffix);
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: originAttributes: %s, siteHost=%s, entryType=%d, "
|
||||
"timeStamp=%" PRId64,
|
||||
__FUNCTION__, originAttributeSuffix.get(),
|
||||
PromiseFlatCString(aSiteHost).get(),
|
||||
static_cast<uint8_t>(aEntryType), aTimeStamp));
|
||||
}
|
||||
|
||||
IncrementPendingWrites();
|
||||
|
||||
RefPtr<BounceTrackingProtectionStorage> self = this;
|
||||
nsCString siteHost(aSiteHost);
|
||||
|
||||
mBackgroundThread->Dispatch(
|
||||
NS_NewRunnableFunction(
|
||||
"BounceTrackingProtectionStorage::UpdateEntry",
|
||||
[self, aOriginAttributes, siteHost, aEntryType, aTimeStamp]() {
|
||||
nsresult rv =
|
||||
UpsertData(self->mDatabaseConnection, aOriginAttributes,
|
||||
siteHost, aEntryType, aTimeStamp);
|
||||
self->DecrementPendingWrites();
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
}),
|
||||
NS_DISPATCH_EVENT_MAY_BLOCK);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult BounceTrackingProtectionStorage::DeleteDBEntries(
|
||||
OriginAttributes* aOriginAttributes, const nsACString& aSiteHost) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aSiteHost.IsEmpty());
|
||||
MOZ_ASSERT(!aOriginAttributes ||
|
||||
aOriginAttributes->mPrivateBrowsingId ==
|
||||
nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID,
|
||||
"Must not write private browsing data to the table.");
|
||||
|
||||
nsresult rv = WaitForInitialization();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (MOZ_LOG_TEST(gBounceTrackingProtectionLog, LogLevel::Debug)) {
|
||||
nsAutoCString originAttributeSuffix("*");
|
||||
if (aOriginAttributes) {
|
||||
aOriginAttributes->CreateSuffix(originAttributeSuffix);
|
||||
}
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: originAttributes: %s, siteHost=%s", __FUNCTION__,
|
||||
originAttributeSuffix.get(), PromiseFlatCString(aSiteHost).get()));
|
||||
}
|
||||
|
||||
RefPtr<BounceTrackingProtectionStorage> self = this;
|
||||
nsCString siteHost(aSiteHost);
|
||||
Maybe<OriginAttributes> originAttributes;
|
||||
if (aOriginAttributes) {
|
||||
originAttributes.emplace(*aOriginAttributes);
|
||||
}
|
||||
|
||||
IncrementPendingWrites();
|
||||
mBackgroundThread->Dispatch(
|
||||
NS_NewRunnableFunction("BounceTrackingProtectionStorage::DeleteEntry",
|
||||
[self, originAttributes, siteHost]() {
|
||||
nsresult rv =
|
||||
DeleteData(self->mDatabaseConnection,
|
||||
originAttributes, siteHost);
|
||||
self->DecrementPendingWrites();
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
}),
|
||||
NS_DISPATCH_EVENT_MAY_BLOCK);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult BounceTrackingProtectionStorage::Clear() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// Clear in memory data.
|
||||
mStateGlobal.Clear();
|
||||
|
||||
// Clear on disk data.
|
||||
nsresult rv = WaitForInitialization();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
IncrementPendingWrites();
|
||||
RefPtr<BounceTrackingProtectionStorage> self = this;
|
||||
mBackgroundThread->Dispatch(
|
||||
NS_NewRunnableFunction("BounceTrackingProtectionStorage::Clear",
|
||||
[self]() {
|
||||
nsresult rv =
|
||||
ClearData(self->mDatabaseConnection);
|
||||
self->DecrementPendingWrites();
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
}),
|
||||
NS_DISPATCH_EVENT_MAY_BLOCK);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult BounceTrackingProtectionStorage::DeleteDBEntriesInTimeRange(
|
||||
OriginAttributes* aOriginAttributes, PRTime aFrom, Maybe<PRTime> aTo,
|
||||
Maybe<BounceTrackingProtectionStorage::EntryType> aEntryType) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_ARG_MIN(aFrom, 0);
|
||||
NS_ENSURE_TRUE(aTo.isNothing() || aTo.value() > aFrom, NS_ERROR_INVALID_ARG);
|
||||
|
||||
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::DeleteDBEntriesInTimeRange",
|
||||
[self, originAttributes, aFrom, aTo, aEntryType]() {
|
||||
nsresult rv =
|
||||
DeleteDataInTimeRange(self->mDatabaseConnection,
|
||||
originAttributes, aFrom, aTo, aEntryType);
|
||||
self->DecrementPendingWrites();
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
}),
|
||||
NS_DISPATCH_EVENT_MAY_BLOCK);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
BounceTrackingProtectionStorage::DeleteDBEntriesByOriginAttributesPattern(
|
||||
const OriginAttributesPattern& aOriginAttributesPattern) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aOriginAttributesPattern.mPrivateBrowsingId.WasPassed() ||
|
||||
aOriginAttributesPattern.mPrivateBrowsingId.Value() ==
|
||||
nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID,
|
||||
"Must not clear private browsing data from the table.");
|
||||
|
||||
nsresult rv = WaitForInitialization();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
IncrementPendingWrites();
|
||||
RefPtr<BounceTrackingProtectionStorage> self = this;
|
||||
mBackgroundThread->Dispatch(
|
||||
NS_NewRunnableFunction(
|
||||
"BounceTrackingProtectionStorage::"
|
||||
"DeleteEntriesByOriginAttributesPattern",
|
||||
[self, aOriginAttributesPattern]() {
|
||||
nsresult rv = DeleteDataByOriginAttributesPattern(
|
||||
self->mDatabaseConnection, aOriginAttributesPattern);
|
||||
self->DecrementPendingWrites();
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
}),
|
||||
NS_DISPATCH_EVENT_MAY_BLOCK);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIAsyncShutdownBlocker
|
||||
|
||||
NS_IMETHODIMP BounceTrackingProtectionStorage::BlockShutdown(
|
||||
nsIAsyncShutdownClient* aClient) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsresult rv = WaitForInitialization();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
mShuttingDown.Flip();
|
||||
|
||||
RefPtr<BounceTrackingProtectionStorage> self = this;
|
||||
mBackgroundThread->Dispatch(
|
||||
NS_NewRunnableFunction(
|
||||
"BounceTrackingProtectionStorage::BlockShutdown",
|
||||
[self]() {
|
||||
MonitorAutoLock lock(self->mMonitor);
|
||||
|
||||
MOZ_ASSERT(self->mPendingWrites == 0);
|
||||
|
||||
if (self->mDatabaseConnection) {
|
||||
Unused << self->mDatabaseConnection->Close();
|
||||
self->mDatabaseConnection = nullptr;
|
||||
}
|
||||
|
||||
self->mFinalized.Flip();
|
||||
self->mMonitor.NotifyAll();
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"BounceTrackingProtectionStorage::BlockShutdown "
|
||||
"- mainthread callback",
|
||||
[self]() { self->Finalize(); }));
|
||||
}),
|
||||
NS_DISPATCH_EVENT_MAY_BLOCK);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult BounceTrackingProtectionStorage::WaitForInitialization() {
|
||||
MOZ_ASSERT(NS_IsMainThread(),
|
||||
"Must only wait for initialization in the main thread.");
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
while (!mInitialized && !mErrored && !mShuttingDown) {
|
||||
mMonitor.Wait();
|
||||
}
|
||||
if (mErrored) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (mShuttingDown) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void BounceTrackingProtectionStorage::Finalize() {
|
||||
nsCOMPtr<nsIAsyncShutdownClient> asc = GetAsyncShutdownBarrier();
|
||||
MOZ_ASSERT(asc);
|
||||
DebugOnly<nsresult> rv = asc->RemoveBlocker(this);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
// nsIObserver
|
||||
|
||||
NS_IMETHODIMP
|
||||
BounceTrackingProtectionStorage::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData) {
|
||||
AssertIsOnMainThread();
|
||||
if (nsCRT::strcmp(aTopic, "last-pb-context-exited") != 0) {
|
||||
return nsresult::NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
uint32_t removedCount = 0;
|
||||
// Clear in-memory private browsing entries.
|
||||
for (auto iter = mStateGlobal.Iter(); !iter.Done(); iter.Next()) {
|
||||
BounceTrackingStateGlobal* stateGlobal = iter.Data();
|
||||
MOZ_ASSERT(stateGlobal);
|
||||
if (stateGlobal->IsPrivateBrowsing()) {
|
||||
iter.Remove();
|
||||
removedCount++;
|
||||
}
|
||||
}
|
||||
MOZ_LOG(
|
||||
gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: last-pb-context-exited: Removed %d private browsing state globals",
|
||||
__FUNCTION__, removedCount));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIAsyncShutdownBlocker
|
||||
|
||||
already_AddRefed<nsIAsyncShutdownClient>
|
||||
BounceTrackingProtectionStorage::GetAsyncShutdownBarrier() const {
|
||||
nsCOMPtr<nsIAsyncShutdownService> svc = components::AsyncShutdown::Service();
|
||||
MOZ_RELEASE_ASSERT(svc);
|
||||
|
||||
nsCOMPtr<nsIAsyncShutdownClient> client;
|
||||
nsresult rv = svc->GetProfileBeforeChange(getter_AddRefs(client));
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
MOZ_RELEASE_ASSERT(client);
|
||||
|
||||
return client.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP BounceTrackingProtectionStorage::GetState(nsIPropertyBag**) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP BounceTrackingProtectionStorage::GetName(nsAString& aName) {
|
||||
aName.AssignLiteral("BounceTrackingProtectionStorage: Flushing to disk");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
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_enabled_AtStartup(),
|
||||
NS_ERROR_FAILURE);
|
||||
|
||||
// Register a shutdown blocker so we can flush pending changes to disk before
|
||||
// shutdown.
|
||||
// Init may also be called during shutdown, e.g. because of clearing data
|
||||
// during shutdown.
|
||||
nsCOMPtr<nsIAsyncShutdownClient> shutdownBarrier = GetAsyncShutdownBarrier();
|
||||
NS_ENSURE_TRUE(shutdownBarrier, NS_ERROR_FAILURE);
|
||||
|
||||
bool closed;
|
||||
nsresult rv = shutdownBarrier->GetIsClosed(&closed);
|
||||
if (closed || NS_WARN_IF(NS_FAILED(rv))) {
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
mShuttingDown.Flip();
|
||||
return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
|
||||
}
|
||||
|
||||
rv = shutdownBarrier->AddBlocker(
|
||||
this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Listen for last private browsing context exited message so we can clean up
|
||||
// in memory state when the PBM session ends.
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
NS_ENSURE_TRUE(observerService, NS_ERROR_FAILURE);
|
||||
rv = observerService->AddObserver(this, "last-pb-context-exited", false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Create the database file.
|
||||
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||
getter_AddRefs(mDatabaseFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mDatabaseFile->AppendNative(BOUNCE_TRACKING_PROTECTION_DB_FILENAME);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Init the database and import data.
|
||||
NS_ENSURE_SUCCESS(
|
||||
NS_CreateBackgroundTaskQueue("BounceTrackingProtectionStorage",
|
||||
getter_AddRefs(mBackgroundThread)),
|
||||
NS_ERROR_FAILURE);
|
||||
|
||||
RefPtr<BounceTrackingProtectionStorage> self = this;
|
||||
|
||||
mBackgroundThread->Dispatch(
|
||||
NS_NewRunnableFunction("BounceTrackingProtectionStorage::Init",
|
||||
[self]() {
|
||||
MonitorAutoLock lock(self->mMonitor);
|
||||
nsresult rv = self->CreateDatabaseConnection();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
self->mErrored.Flip();
|
||||
self->mMonitor.Notify();
|
||||
return;
|
||||
}
|
||||
|
||||
rv = self->LoadMemoryStateFromDisk();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
self->mErrored.Flip();
|
||||
self->mMonitor.Notify();
|
||||
return;
|
||||
}
|
||||
|
||||
self->mInitialized.Flip();
|
||||
self->mMonitor.Notify();
|
||||
}),
|
||||
NS_DISPATCH_EVENT_MAY_BLOCK);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult BounceTrackingProtectionStorage::CreateDatabaseConnection() {
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
NS_ENSURE_TRUE(mDatabaseFile, NS_ERROR_NULL_POINTER);
|
||||
|
||||
nsCOMPtr<mozIStorageService> storage =
|
||||
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsresult rv = storage->OpenDatabase(mDatabaseFile,
|
||||
mozIStorageService::CONNECTION_DEFAULT,
|
||||
getter_AddRefs(mDatabaseConnection));
|
||||
if (rv == NS_ERROR_FILE_CORRUPTED) {
|
||||
rv = mDatabaseFile->Remove(false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = storage->OpenDatabase(mDatabaseFile,
|
||||
mozIStorageService::CONNECTION_DEFAULT,
|
||||
getter_AddRefs(mDatabaseConnection));
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ENSURE_TRUE(mDatabaseConnection, NS_ERROR_UNEXPECTED);
|
||||
bool ready = false;
|
||||
mDatabaseConnection->GetConnectionReady(&ready);
|
||||
NS_ENSURE_TRUE(ready, NS_ERROR_UNEXPECTED);
|
||||
|
||||
return EnsureTable();
|
||||
}
|
||||
|
||||
nsresult BounceTrackingProtectionStorage::EnsureTable() {
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
NS_ENSURE_TRUE(mDatabaseConnection, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsresult rv = mDatabaseConnection->SetSchemaVersion(SCHEMA_VERSION);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
const constexpr auto createTableQuery =
|
||||
"CREATE TABLE IF NOT EXISTS sites ("
|
||||
"originAttributeSuffix TEXT NOT NULL,"
|
||||
"siteHost TEXT NOT NULL, "
|
||||
"entryType INTEGER NOT NULL, "
|
||||
"timeStamp INTEGER NOT NULL, "
|
||||
"PRIMARY KEY (originAttributeSuffix, siteHost)"
|
||||
");"_ns;
|
||||
|
||||
return mDatabaseConnection->ExecuteSimpleSQL(createTableQuery);
|
||||
}
|
||||
|
||||
nsresult BounceTrackingProtectionStorage::LoadMemoryStateFromDisk() {
|
||||
MOZ_ASSERT(!NS_IsMainThread(),
|
||||
"Must not load the table from disk in the main thread.");
|
||||
|
||||
const constexpr auto selectAllQuery(
|
||||
"SELECT originAttributeSuffix, siteHost, entryType, timeStamp FROM sites;"_ns);
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> readStmt;
|
||||
nsresult rv = mDatabaseConnection->CreateStatement(selectAllQuery,
|
||||
getter_AddRefs(readStmt));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool hasResult;
|
||||
// Collect DB entries into an array to hand to the main thread later.
|
||||
nsTArray<ImportEntry> importEntries;
|
||||
while (NS_SUCCEEDED(readStmt->ExecuteStep(&hasResult)) && hasResult) {
|
||||
nsAutoCString originAttributeSuffix, siteHost;
|
||||
int64_t timeStamp;
|
||||
int32_t typeInt;
|
||||
|
||||
rv = readStmt->GetUTF8String(0, originAttributeSuffix);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = readStmt->GetUTF8String(1, siteHost);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = readStmt->GetInt32(2, &typeInt);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = readStmt->GetInt64(3, &timeStamp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Convert entryType field to enum.
|
||||
BounceTrackingProtectionStorage::EntryType entryType =
|
||||
static_cast<BounceTrackingProtectionStorage::EntryType>(typeInt);
|
||||
// Check that the enum value is valid.
|
||||
if (NS_WARN_IF(
|
||||
entryType !=
|
||||
BounceTrackingProtectionStorage::EntryType::BounceTracker &&
|
||||
entryType !=
|
||||
BounceTrackingProtectionStorage::EntryType::UserActivation)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
OriginAttributes oa;
|
||||
bool success = oa.PopulateFromSuffix(originAttributeSuffix);
|
||||
if (NS_WARN_IF(!success)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Collect entries to dispatch to main thread later.
|
||||
importEntries.AppendElement(
|
||||
ImportEntry{oa, siteHost, entryType, timeStamp});
|
||||
}
|
||||
|
||||
// We can only access the state map on the main thread.
|
||||
RefPtr<BounceTrackingProtectionStorage> self = this;
|
||||
return NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"BounceTrackingProtectionStorage::LoadMemoryStateFromDisk",
|
||||
[self, importEntries = std::move(importEntries)]() {
|
||||
// For each entry get or create BounceTrackingStateGlobal and insert it
|
||||
// into global state map.
|
||||
for (const ImportEntry& entry : importEntries) {
|
||||
RefPtr<BounceTrackingStateGlobal> stateGlobal =
|
||||
self->GetOrCreateStateGlobal(entry.mOriginAttributes);
|
||||
MOZ_ASSERT(stateGlobal);
|
||||
|
||||
nsresult rv;
|
||||
if (entry.mEntryType ==
|
||||
BounceTrackingProtectionStorage::EntryType::BounceTracker) {
|
||||
rv = stateGlobal->RecordBounceTracker(entry.mSiteHost,
|
||||
entry.mTimeStamp, true);
|
||||
} else {
|
||||
rv = stateGlobal->RecordUserActivation(entry.mSiteHost,
|
||||
entry.mTimeStamp, true);
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv)) &&
|
||||
MOZ_LOG_TEST(gBounceTrackingProtectionLog, LogLevel::Debug)) {
|
||||
nsAutoCString originAttributeSuffix;
|
||||
entry.mOriginAttributes.CreateSuffix(originAttributeSuffix);
|
||||
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: Failed to load entry from disk: "
|
||||
"originAttributeSuffix=%s, siteHost=%s, entryType=%d, "
|
||||
"timeStamp=%" PRId64,
|
||||
__FUNCTION__, originAttributeSuffix.get(),
|
||||
PromiseFlatCString(entry.mSiteHost).get(),
|
||||
static_cast<uint8_t>(entry.mEntryType), entry.mTimeStamp));
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void BounceTrackingProtectionStorage::IncrementPendingWrites() {
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
MOZ_ASSERT(mPendingWrites < std::numeric_limits<uint32_t>::max());
|
||||
mPendingWrites++;
|
||||
}
|
||||
|
||||
void BounceTrackingProtectionStorage::DecrementPendingWrites() {
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
MOZ_ASSERT(mPendingWrites > 0);
|
||||
mPendingWrites--;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult BounceTrackingProtectionStorage::UpsertData(
|
||||
mozIStorageConnection* aDatabaseConnection,
|
||||
const OriginAttributes& aOriginAttributes, const nsACString& aSiteHost,
|
||||
BounceTrackingProtectionStorage::EntryType aEntryType, PRTime aTimeStamp) {
|
||||
MOZ_ASSERT(!NS_IsMainThread(),
|
||||
"Must not write to the table from the main thread.");
|
||||
MOZ_ASSERT(aDatabaseConnection);
|
||||
MOZ_ASSERT(!aSiteHost.IsEmpty());
|
||||
MOZ_ASSERT(aTimeStamp > 0);
|
||||
MOZ_ASSERT(aOriginAttributes.mPrivateBrowsingId ==
|
||||
nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID,
|
||||
"Must not write private browsing data to the table.");
|
||||
|
||||
auto constexpr upsertQuery =
|
||||
"INSERT INTO sites (originAttributeSuffix, siteHost, entryType, "
|
||||
"timeStamp)"
|
||||
"VALUES (:originAttributeSuffix, :siteHost, :entryType, :timeStamp)"
|
||||
"ON CONFLICT (originAttributeSuffix, siteHost)"
|
||||
"DO UPDATE SET entryType = :entryType, timeStamp = :timeStamp;"_ns;
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> upsertStmt;
|
||||
nsresult rv = aDatabaseConnection->CreateStatement(
|
||||
upsertQuery, getter_AddRefs(upsertStmt));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Serialize OriginAttributes.
|
||||
nsAutoCString originAttributeSuffix;
|
||||
aOriginAttributes.CreateSuffix(originAttributeSuffix);
|
||||
|
||||
rv = upsertStmt->BindUTF8StringByName("originAttributeSuffix"_ns,
|
||||
originAttributeSuffix);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = upsertStmt->BindUTF8StringByName("siteHost"_ns, aSiteHost);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = upsertStmt->BindInt32ByName("entryType"_ns,
|
||||
static_cast<int32_t>(aEntryType));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = upsertStmt->BindInt64ByName("timeStamp"_ns, aTimeStamp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return upsertStmt->Execute();
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult BounceTrackingProtectionStorage::DeleteData(
|
||||
mozIStorageConnection* aDatabaseConnection,
|
||||
Maybe<OriginAttributes> aOriginAttributes, const nsACString& aSiteHost) {
|
||||
MOZ_ASSERT(!NS_IsMainThread(),
|
||||
"Must not write to the table from the main thread.");
|
||||
MOZ_ASSERT(aDatabaseConnection);
|
||||
MOZ_ASSERT(!aSiteHost.IsEmpty());
|
||||
MOZ_ASSERT(aOriginAttributes.isNothing() ||
|
||||
aOriginAttributes->mPrivateBrowsingId ==
|
||||
nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID);
|
||||
|
||||
nsAutoCString deleteQuery("DELETE FROM sites WHERE siteHost = :siteHost");
|
||||
|
||||
if (aOriginAttributes) {
|
||||
deleteQuery.AppendLiteral(
|
||||
" AND originAttributeSuffix = :originAttributeSuffix");
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> upsertStmt;
|
||||
nsresult rv = aDatabaseConnection->CreateStatement(
|
||||
deleteQuery, getter_AddRefs(upsertStmt));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = upsertStmt->BindUTF8StringByName("siteHost"_ns, aSiteHost);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aOriginAttributes) {
|
||||
nsAutoCString originAttributeSuffix;
|
||||
aOriginAttributes->CreateSuffix(originAttributeSuffix);
|
||||
rv = upsertStmt->BindUTF8StringByName("originAttributeSuffix"_ns,
|
||||
originAttributeSuffix);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return upsertStmt->Execute();
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult BounceTrackingProtectionStorage::DeleteDataInTimeRange(
|
||||
mozIStorageConnection* aDatabaseConnection,
|
||||
Maybe<OriginAttributes> aOriginAttributes, PRTime aFrom, Maybe<PRTime> aTo,
|
||||
Maybe<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);
|
||||
MOZ_ASSERT(aFrom >= 0);
|
||||
MOZ_ASSERT(aTo.isNothing() || aTo.value() > aFrom);
|
||||
|
||||
nsAutoCString deleteQuery(
|
||||
"DELETE FROM sites "
|
||||
"WHERE timeStamp >= :aFrom"_ns);
|
||||
|
||||
if (aTo.isSome()) {
|
||||
deleteQuery.AppendLiteral(" AND timeStamp <= :aTo");
|
||||
}
|
||||
|
||||
if (aOriginAttributes) {
|
||||
deleteQuery.AppendLiteral(
|
||||
" AND originAttributeSuffix = :originAttributeSuffix");
|
||||
}
|
||||
|
||||
if (aEntryType.isSome()) {
|
||||
deleteQuery.AppendLiteral(" AND entryType = :entryType");
|
||||
}
|
||||
deleteQuery.AppendLiteral(";");
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> deleteStmt;
|
||||
nsresult rv = aDatabaseConnection->CreateStatement(
|
||||
deleteQuery, getter_AddRefs(deleteStmt));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = deleteStmt->BindInt64ByName("aFrom"_ns, aFrom);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aTo.isSome()) {
|
||||
rv = deleteStmt->BindInt64ByName("aTo"_ns, aTo.value());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (aOriginAttributes) {
|
||||
nsAutoCString originAttributeSuffix;
|
||||
aOriginAttributes->CreateSuffix(originAttributeSuffix);
|
||||
rv = deleteStmt->BindUTF8StringByName("originAttributeSuffix"_ns,
|
||||
originAttributeSuffix);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (aEntryType.isSome()) {
|
||||
rv = deleteStmt->BindInt32ByName("entryType"_ns,
|
||||
static_cast<int32_t>(*aEntryType));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return deleteStmt->Execute();
|
||||
}
|
||||
|
||||
nsresult BounceTrackingProtectionStorage::DeleteDataByOriginAttributesPattern(
|
||||
mozIStorageConnection* aDatabaseConnection,
|
||||
const OriginAttributesPattern& aOriginAttributesPattern) {
|
||||
MOZ_ASSERT(!NS_IsMainThread(),
|
||||
"Must not write to the table from the main thread.");
|
||||
MOZ_ASSERT(aDatabaseConnection);
|
||||
|
||||
nsCOMPtr<mozIStorageFunction> patternMatchFunction(
|
||||
new OriginAttrsPatternMatchOASuffixSQLFunction(aOriginAttributesPattern));
|
||||
|
||||
nsresult rv = aDatabaseConnection->CreateFunction(
|
||||
"ORIGIN_ATTRS_PATTERN_MATCH_OA_SUFFIX"_ns, 1, patternMatchFunction);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aDatabaseConnection->ExecuteSimpleSQL(
|
||||
"DELETE FROM sites WHERE "
|
||||
"ORIGIN_ATTRS_PATTERN_MATCH_OA_SUFFIX(originAttributeSuffix);"_ns);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return aDatabaseConnection->RemoveFunction(
|
||||
"ORIGIN_ATTRS_PATTERN_MATCH_OA_SUFFIX"_ns);
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult BounceTrackingProtectionStorage::ClearData(
|
||||
mozIStorageConnection* aDatabaseConnection) {
|
||||
MOZ_ASSERT(!NS_IsMainThread(),
|
||||
"Must not write to the table from the main thread.");
|
||||
NS_ENSURE_ARG_POINTER(aDatabaseConnection);
|
||||
return aDatabaseConnection->ExecuteSimpleSQL("DELETE FROM sites;"_ns);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(OriginAttrsPatternMatchOASuffixSQLFunction,
|
||||
mozIStorageFunction)
|
||||
|
||||
NS_IMETHODIMP
|
||||
OriginAttrsPatternMatchOASuffixSQLFunction::OnFunctionCall(
|
||||
mozIStorageValueArray* aFunctionArguments, nsIVariant** aResult) {
|
||||
nsresult rv;
|
||||
|
||||
nsAutoCString originAttributeSuffix;
|
||||
rv = aFunctionArguments->GetUTF8String(0, originAttributeSuffix);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
OriginAttributes originAttributes;
|
||||
bool parsedSuccessfully =
|
||||
originAttributes.PopulateFromSuffix(originAttributeSuffix);
|
||||
NS_ENSURE_TRUE(parsedSuccessfully, NS_ERROR_FAILURE);
|
||||
|
||||
bool result = mPattern.Matches(originAttributes);
|
||||
|
||||
RefPtr<nsVariant> outVar(new nsVariant());
|
||||
rv = outVar->SetAsBool(result);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
outVar.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
@ -1,220 +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/. */
|
||||
#ifndef mozilla_BounceTrackingProtectionStorage_h__
|
||||
#define mozilla_BounceTrackingProtectionStorage_h__
|
||||
|
||||
#include "mozIStorageFunction.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/ThreadSafety.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "mozilla/dom/FlippedOnce.h"
|
||||
#include "nsIAsyncShutdown.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsTHashMap.h"
|
||||
#include "mozilla/OriginAttributesHashKey.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
class mozIStorageConnection;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class BounceTrackingStateGlobal;
|
||||
class BounceTrackingState;
|
||||
class OriginAttributes;
|
||||
|
||||
extern LazyLogModule gBounceTrackingProtectionLog;
|
||||
|
||||
class BounceTrackingProtectionStorage final : public nsIObserver,
|
||||
public nsIAsyncShutdownBlocker,
|
||||
public SupportsWeakPtr {
|
||||
friend class BounceTrackingStateGlobal;
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIASYNCSHUTDOWNBLOCKER
|
||||
|
||||
public:
|
||||
BounceTrackingProtectionStorage()
|
||||
: mMonitor("mozilla::BounceTrackingProtectionStorage::mMonitor"),
|
||||
mPendingWrites(0){};
|
||||
|
||||
// Initialises the storage including the on-disk database.
|
||||
[[nodiscard]] nsresult Init();
|
||||
|
||||
// Getters for mStateGlobal.
|
||||
BounceTrackingStateGlobal* GetOrCreateStateGlobal(
|
||||
const OriginAttributes& aOriginAttributes);
|
||||
|
||||
BounceTrackingStateGlobal* GetOrCreateStateGlobal(nsIPrincipal* aPrincipal);
|
||||
|
||||
BounceTrackingStateGlobal* GetOrCreateStateGlobal(
|
||||
BounceTrackingState* aBounceTrackingState);
|
||||
|
||||
using StateGlobalMap =
|
||||
nsTHashMap<OriginAttributesHashKey, RefPtr<BounceTrackingStateGlobal>>;
|
||||
// Provides a read-only reference to the state global map.
|
||||
const StateGlobalMap& StateGlobalMapRef() { return mStateGlobal; }
|
||||
|
||||
// The enum values match the database type field. Updating them requires a DB
|
||||
// migration.
|
||||
enum class EntryType : uint8_t { BounceTracker = 0, UserActivation = 1 };
|
||||
|
||||
// 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,
|
||||
OriginAttributes* aOriginAttributes);
|
||||
|
||||
// Clear all state within a given time range.
|
||||
[[nodiscard]] nsresult ClearByTimeRange(PRTime aFrom, PRTime aTo);
|
||||
|
||||
// Clear all state for a given OriginAttributesPattern.
|
||||
[[nodiscard]] nsresult ClearByOriginAttributesPattern(
|
||||
const OriginAttributesPattern& aOriginAttributesPattern);
|
||||
|
||||
// Clear all state.
|
||||
[[nodiscard]] nsresult Clear();
|
||||
|
||||
private:
|
||||
~BounceTrackingProtectionStorage() = default;
|
||||
|
||||
// Worker thread. This should be a valid thread after Init() returns and be
|
||||
// destroyed when we finalize
|
||||
nsCOMPtr<nsISerialEventTarget> mBackgroundThread; // main thread only
|
||||
|
||||
// Database connections. Guaranteed to be non-null and working once
|
||||
// initialized and not-yet finalized
|
||||
RefPtr<mozIStorageConnection> mDatabaseConnection; // Worker thread only
|
||||
|
||||
// Wait (non-blocking) until the service is fully initialized. We may be
|
||||
// waiting for that async work started by Init().
|
||||
[[nodiscard]] nsresult WaitForInitialization();
|
||||
|
||||
// Called to indicate to the async shutdown service that we are all wrapped
|
||||
// up. This also spins down the worker thread, since it is called after all
|
||||
// disk database connections are closed.
|
||||
void Finalize();
|
||||
|
||||
// Utility function to grab the correct barrier this service needs to shut
|
||||
// down by
|
||||
already_AddRefed<nsIAsyncShutdownClient> GetAsyncShutdownBarrier() const;
|
||||
|
||||
// Initialises the DB connection on the worker thread.
|
||||
[[nodiscard]] nsresult CreateDatabaseConnection();
|
||||
|
||||
// Creates amd initialises the database table if needed. Worker thread only.
|
||||
[[nodiscard]] nsresult EnsureTable();
|
||||
|
||||
// Temporary data structure used to import db data into memory.
|
||||
struct ImportEntry {
|
||||
OriginAttributes mOriginAttributes;
|
||||
nsCString mSiteHost;
|
||||
EntryType mEntryType;
|
||||
PRTime mTimeStamp;
|
||||
};
|
||||
|
||||
// Imports state from the database on disk into memory.
|
||||
[[nodiscard]] nsresult LoadMemoryStateFromDisk();
|
||||
|
||||
// Used to (thread-safely) track how many operations have been launched to the
|
||||
// worker thread so that we can wait for it to hit zero before close the disk
|
||||
// database connection
|
||||
void IncrementPendingWrites();
|
||||
void DecrementPendingWrites();
|
||||
|
||||
// Update or create database entry. Worker thread only.
|
||||
[[nodiscard]] static nsresult UpsertData(
|
||||
mozIStorageConnection* aDatabaseConnection,
|
||||
const OriginAttributes& aOriginAttributes, const nsACString& aSiteHost,
|
||||
EntryType aEntryType, PRTime aTimeStamp);
|
||||
|
||||
// Delete database entries. Worker thread only.
|
||||
[[nodiscard]] static nsresult DeleteData(
|
||||
mozIStorageConnection* aDatabaseConnection,
|
||||
Maybe<OriginAttributes> aOriginAttributes, const nsACString& aSiteHost);
|
||||
|
||||
// Delete all entries before a given time. Worker thread only.
|
||||
// If aEntryType is passed only entries of that type will be deleted.
|
||||
[[nodiscard]] static nsresult DeleteDataInTimeRange(
|
||||
mozIStorageConnection* aDatabaseConnection,
|
||||
Maybe<OriginAttributes> aOriginAttributes, PRTime aFrom,
|
||||
Maybe<PRTime> aTo,
|
||||
Maybe<BounceTrackingProtectionStorage::EntryType> aEntryType = Nothing{});
|
||||
|
||||
// Delete all entries matching the given OriginAttributesPattern. Worker
|
||||
// thread only.
|
||||
[[nodiscard]] static nsresult DeleteDataByOriginAttributesPattern(
|
||||
mozIStorageConnection* aDatabaseConnection,
|
||||
const OriginAttributesPattern& aOriginAttributesPattern);
|
||||
|
||||
// Clear all entries from the database.
|
||||
[[nodiscard]] static nsresult ClearData(
|
||||
mozIStorageConnection* aDatabaseConnection);
|
||||
|
||||
// Service state management. We protect these variables with a monitor. This
|
||||
// monitor is also used to signal the completion of initialization and
|
||||
// finalization performed in the worker thread.
|
||||
Monitor mMonitor;
|
||||
|
||||
FlippedOnce<false> mInitialized MOZ_GUARDED_BY(mMonitor);
|
||||
FlippedOnce<false> mErrored MOZ_GUARDED_BY(mMonitor);
|
||||
FlippedOnce<false> mShuttingDown MOZ_GUARDED_BY(mMonitor);
|
||||
FlippedOnce<false> mFinalized MOZ_GUARDED_BY(mMonitor);
|
||||
uint32_t mPendingWrites MOZ_GUARDED_BY(mMonitor);
|
||||
|
||||
// The database file handle. We can only create this in the main thread and
|
||||
// need it in the worker to perform blocking disk IO. So we put it on this,
|
||||
// since we pass this to the worker anyway
|
||||
nsCOMPtr<nsIFile> mDatabaseFile;
|
||||
|
||||
// Map of origin attributes to global state object. This enables us to track
|
||||
// bounce tracking state per OA, e.g. to separate private browsing from normal
|
||||
// browsing.
|
||||
StateGlobalMap mStateGlobal{};
|
||||
|
||||
// Helpers used to sync updates to BounceTrackingStateGlobal with the
|
||||
// database.
|
||||
|
||||
// Updates or inserts a DB entry keyed by OA + site host.
|
||||
[[nodiscard]] nsresult UpdateDBEntry(
|
||||
const OriginAttributes& aOriginAttributes, const nsACString& aSiteHost,
|
||||
EntryType aEntryType, PRTime aTimeStamp);
|
||||
|
||||
// Deletes a DB entry keyed by OA + site host. If only aSiteHost is passed,
|
||||
// all entries for that host will be deleted across OriginAttributes.
|
||||
[[nodiscard]] nsresult DeleteDBEntries(OriginAttributes* aOriginAttributes,
|
||||
const nsACString& aSiteHost);
|
||||
|
||||
// Delete all DB entries before a given time.
|
||||
// If aEntryType is passed only entries of that type will be deleted.
|
||||
[[nodiscard]] nsresult DeleteDBEntriesInTimeRange(
|
||||
OriginAttributes* aOriginAttributes, PRTime aFrom,
|
||||
Maybe<PRTime> aTo = Nothing{}, Maybe<EntryType> aEntryType = Nothing{});
|
||||
|
||||
// Deletes all DB entries matching the given OriginAttributesPattern.
|
||||
[[nodiscard]] nsresult DeleteDBEntriesByOriginAttributesPattern(
|
||||
const OriginAttributesPattern& aOriginAttributesPattern);
|
||||
};
|
||||
|
||||
// A SQL function to match DB entries by OriginAttributesPattern.
|
||||
class OriginAttrsPatternMatchOASuffixSQLFunction final
|
||||
: public mozIStorageFunction {
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGEFUNCTION
|
||||
|
||||
explicit OriginAttrsPatternMatchOASuffixSQLFunction(
|
||||
OriginAttributesPattern const& aPattern)
|
||||
: mPattern(aPattern) {}
|
||||
OriginAttrsPatternMatchOASuffixSQLFunction() = delete;
|
||||
|
||||
private:
|
||||
~OriginAttrsPatternMatchOASuffixSQLFunction() = default;
|
||||
|
||||
OriginAttributesPattern mPattern;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_BounceTrackingProtectionStorage_h__
|
@ -10,7 +10,6 @@
|
||||
|
||||
#include "BounceTrackingStorageObserver.h"
|
||||
#include "ErrorList.h"
|
||||
#include "mozilla/OriginAttributes.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/BrowsingContextWebProgress.h"
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
@ -99,19 +98,20 @@ already_AddRefed<BounceTrackingState> BounceTrackingState::GetOrCreate(
|
||||
return bounceTrackingState.forget();
|
||||
};
|
||||
|
||||
// static
|
||||
void BounceTrackingState::ResetAll() { Reset(nullptr, nullptr); }
|
||||
|
||||
// static
|
||||
void BounceTrackingState::ResetAllForOriginAttributes(
|
||||
const OriginAttributes& aOriginAttributes) {
|
||||
Reset(&aOriginAttributes, nullptr);
|
||||
}
|
||||
|
||||
// static
|
||||
void BounceTrackingState::ResetAllForOriginAttributesPattern(
|
||||
const OriginAttributesPattern& aPattern) {
|
||||
Reset(nullptr, &aPattern);
|
||||
void BounceTrackingState::ResetAll() {
|
||||
if (!sBounceTrackingStates) {
|
||||
return;
|
||||
}
|
||||
for (const RefPtr<BounceTrackingState>& bounceTrackingState :
|
||||
sBounceTrackingStates->Values()) {
|
||||
if (bounceTrackingState->mClientBounceDetectionTimeout) {
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: mClientBounceDetectionTimeout->Cancel()", __FUNCTION__));
|
||||
bounceTrackingState->mClientBounceDetectionTimeout->Cancel();
|
||||
bounceTrackingState->mClientBounceDetectionTimeout = nullptr;
|
||||
}
|
||||
bounceTrackingState->ResetBounceTrackingRecord();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult BounceTrackingState::Init(
|
||||
@ -127,11 +127,6 @@ nsresult BounceTrackingState::Init(
|
||||
dom::BrowsingContext* browsingContext = aWebProgress->GetBrowsingContext();
|
||||
NS_ENSURE_TRUE(browsingContext, NS_ERROR_FAILURE);
|
||||
mBrowserId = browsingContext->BrowserId();
|
||||
// Create a copy of the BC's OriginAttributes so we can use it later without
|
||||
// having to hold a reference to the BC.
|
||||
mOriginAttributes = browsingContext->OriginAttributesRef();
|
||||
MOZ_ASSERT(mOriginAttributes.mPartitionKey.IsEmpty(),
|
||||
"Top level BCs mus not have a partition key.");
|
||||
|
||||
// Add a listener for window load. See BounceTrackingState::OnStateChange for
|
||||
// the listener code.
|
||||
@ -151,42 +146,9 @@ BounceTrackingRecord* BounceTrackingState::GetBounceTrackingRecord() {
|
||||
}
|
||||
|
||||
nsCString BounceTrackingState::Describe() {
|
||||
nsAutoCString oaSuffix;
|
||||
OriginAttributesRef().CreateSuffix(oaSuffix);
|
||||
|
||||
return nsPrintfCString(
|
||||
"{ mBounceTrackingRecord: %s, mOriginAttributes: %s }",
|
||||
mBounceTrackingRecord ? mBounceTrackingRecord->Describe().get() : "null",
|
||||
oaSuffix.get());
|
||||
}
|
||||
|
||||
// static
|
||||
void BounceTrackingState::Reset(const OriginAttributes* aOriginAttributes,
|
||||
const OriginAttributesPattern* aPattern) {
|
||||
if (aOriginAttributes || aPattern) {
|
||||
MOZ_ASSERT((aOriginAttributes != nullptr) != (aPattern != nullptr),
|
||||
"Must not pass both aOriginAttributes and aPattern.");
|
||||
}
|
||||
|
||||
if (!sBounceTrackingStates) {
|
||||
return;
|
||||
}
|
||||
for (const RefPtr<BounceTrackingState>& bounceTrackingState :
|
||||
sBounceTrackingStates->Values()) {
|
||||
if ((aOriginAttributes &&
|
||||
*aOriginAttributes != bounceTrackingState->OriginAttributesRef()) ||
|
||||
(aPattern &&
|
||||
!aPattern->Matches(bounceTrackingState->OriginAttributesRef()))) {
|
||||
continue;
|
||||
}
|
||||
if (bounceTrackingState->mClientBounceDetectionTimeout) {
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: mClientBounceDetectionTimeout->Cancel()", __FUNCTION__));
|
||||
bounceTrackingState->mClientBounceDetectionTimeout->Cancel();
|
||||
bounceTrackingState->mClientBounceDetectionTimeout = nullptr;
|
||||
}
|
||||
bounceTrackingState->ResetBounceTrackingRecord();
|
||||
}
|
||||
"{ mBounceTrackingRecord: %s }",
|
||||
mBounceTrackingRecord ? mBounceTrackingRecord->Describe().get() : "null");
|
||||
}
|
||||
|
||||
// static
|
||||
@ -272,10 +234,6 @@ BounceTrackingState::CurrentBrowsingContext() {
|
||||
return dom::BrowsingContext::GetCurrentTopByBrowserId(mBrowserId);
|
||||
}
|
||||
|
||||
const OriginAttributes& BounceTrackingState::OriginAttributesRef() {
|
||||
return mOriginAttributes;
|
||||
}
|
||||
|
||||
nsresult BounceTrackingState::OnDocumentStartRequest(nsIChannel* aChannel) {
|
||||
NS_ENSURE_ARG_POINTER(aChannel);
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug, ("%s", __FUNCTION__));
|
||||
|
@ -8,8 +8,6 @@
|
||||
#define mozilla_BounceTrackingState_h
|
||||
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "mozilla/OriginAttributes.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIWeakReferenceUtils.h"
|
||||
#include "nsStringFwd.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
@ -50,10 +48,6 @@ class BounceTrackingState : public nsIWebProgressListener,
|
||||
// Reset state for all BounceTrackingState instances this includes resetting
|
||||
// BounceTrackingRecords and cancelling any running timers.
|
||||
static void ResetAll();
|
||||
static void ResetAllForOriginAttributes(
|
||||
const OriginAttributes& aOriginAttributes);
|
||||
static void ResetAllForOriginAttributesPattern(
|
||||
const OriginAttributesPattern& aPattern);
|
||||
|
||||
BounceTrackingRecord* GetBounceTrackingRecord();
|
||||
|
||||
@ -94,8 +88,6 @@ class BounceTrackingState : public nsIWebProgressListener,
|
||||
|
||||
uint64_t GetBrowserId() { return mBrowserId; }
|
||||
|
||||
const OriginAttributes& OriginAttributesRef();
|
||||
|
||||
// Create a string that describes this object. Used for logging.
|
||||
nsCString Describe();
|
||||
|
||||
@ -105,9 +97,6 @@ class BounceTrackingState : public nsIWebProgressListener,
|
||||
|
||||
uint64_t mBrowserId{};
|
||||
|
||||
// OriginAttributes associated with the browser this state is attached to.
|
||||
OriginAttributes mOriginAttributes;
|
||||
|
||||
// Reference to the BounceTrackingProtection singleton.
|
||||
RefPtr<BounceTrackingProtection> mBounceTrackingProtection;
|
||||
|
||||
@ -118,12 +107,6 @@ class BounceTrackingState : public nsIWebProgressListener,
|
||||
// Timer to wait to wait for a client redirect after a navigation ends.
|
||||
RefPtr<nsITimer> mClientBounceDetectionTimeout;
|
||||
|
||||
// Reset state for all BounceTrackingState instances this includes resetting
|
||||
// BounceTrackingRecords and cancelling any running timers.
|
||||
// Optionally filter by OriginAttributes or OriginAttributesPattern.
|
||||
static void Reset(const OriginAttributes* aOriginAttributes,
|
||||
const OriginAttributesPattern* aPattern);
|
||||
|
||||
// Whether the given web progress should hold a BounceTrackingState
|
||||
// instance to monitor bounce tracking navigations.
|
||||
static bool ShouldCreateBounceTrackingStateForWebProgress(
|
||||
|
@ -1,190 +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 "BounceTrackingStateGlobal.h"
|
||||
#include "BounceTrackingProtectionStorage.h"
|
||||
#include "ErrorList.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsIPrincipal.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(BounceTrackingStateGlobal);
|
||||
|
||||
extern LazyLogModule gBounceTrackingProtectionLog;
|
||||
|
||||
BounceTrackingStateGlobal::BounceTrackingStateGlobal(
|
||||
BounceTrackingProtectionStorage* aStorage, const OriginAttributes& aAttrs)
|
||||
: mStorage(aStorage), mOriginAttributes(aAttrs) {
|
||||
MOZ_ASSERT(aStorage);
|
||||
}
|
||||
|
||||
bool BounceTrackingStateGlobal::HasUserActivation(
|
||||
const nsACString& aSiteHost) const {
|
||||
return mUserActivation.Contains(aSiteHost);
|
||||
}
|
||||
|
||||
nsresult BounceTrackingStateGlobal::RecordUserActivation(
|
||||
const nsACString& aSiteHost, PRTime aTime, bool aSkipStorage) {
|
||||
NS_ENSURE_TRUE(aSiteHost.Length(), NS_ERROR_INVALID_ARG);
|
||||
NS_ENSURE_TRUE(aTime > 0, NS_ERROR_INVALID_ARG);
|
||||
|
||||
// A site must only be in one of the maps at a time.
|
||||
bool hasRemoved = mBounceTrackers.Remove(aSiteHost);
|
||||
|
||||
if (hasRemoved) {
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: Removed bounce tracking candidate due to user activation: %s",
|
||||
__FUNCTION__, PromiseFlatCString(aSiteHost).get()));
|
||||
}
|
||||
|
||||
mUserActivation.InsertOrUpdate(aSiteHost, aTime);
|
||||
|
||||
if (aSkipStorage || !ShouldPersistToDisk()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Write the change to storage.
|
||||
NS_ENSURE_TRUE(mStorage, NS_ERROR_FAILURE);
|
||||
return mStorage->UpdateDBEntry(
|
||||
mOriginAttributes, aSiteHost,
|
||||
BounceTrackingProtectionStorage::EntryType::UserActivation, aTime);
|
||||
}
|
||||
|
||||
nsresult BounceTrackingStateGlobal::TestRemoveUserActivation(
|
||||
const nsACString& aSiteHost) {
|
||||
bool hasRemoved = mUserActivation.Remove(aSiteHost);
|
||||
|
||||
// Avoid potentially removing a bounce tracking entry if there is no user
|
||||
// activation entry.
|
||||
if (!hasRemoved) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!ShouldPersistToDisk()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Write the change to storage.
|
||||
NS_ENSURE_TRUE(mStorage, NS_ERROR_FAILURE);
|
||||
return mStorage->DeleteDBEntries(&mOriginAttributes, aSiteHost);
|
||||
}
|
||||
|
||||
nsresult BounceTrackingStateGlobal::ClearUserActivationBefore(PRTime aTime) {
|
||||
return ClearByTimeRange(
|
||||
0, Some(aTime),
|
||||
Some(BounceTrackingProtectionStorage::EntryType::UserActivation));
|
||||
}
|
||||
|
||||
nsresult BounceTrackingStateGlobal::ClearSiteHost(const nsACString& aSiteHost,
|
||||
bool aSkipStorage) {
|
||||
NS_ENSURE_TRUE(aSiteHost.Length(), NS_ERROR_INVALID_ARG);
|
||||
|
||||
bool removedUserActivation = mUserActivation.Remove(aSiteHost);
|
||||
bool removedBounceTracker = mBounceTrackers.Remove(aSiteHost);
|
||||
if (removedUserActivation || removedBounceTracker) {
|
||||
MOZ_ASSERT(removedUserActivation != removedBounceTracker,
|
||||
"A site must only be in one of the maps at a time.");
|
||||
}
|
||||
|
||||
if (aSkipStorage || !ShouldPersistToDisk()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(mStorage, NS_ERROR_FAILURE);
|
||||
return mStorage->DeleteDBEntries(&mOriginAttributes, aSiteHost);
|
||||
}
|
||||
|
||||
nsresult BounceTrackingStateGlobal::ClearByTimeRange(
|
||||
PRTime aFrom, Maybe<PRTime> aTo,
|
||||
Maybe<BounceTrackingProtectionStorage::EntryType> aEntryType,
|
||||
bool aSkipStorage) {
|
||||
NS_ENSURE_ARG_MIN(aFrom, 0);
|
||||
NS_ENSURE_TRUE(!aTo || aTo.value() > aFrom, NS_ERROR_INVALID_ARG);
|
||||
|
||||
// Clear in memory user activation data.
|
||||
if (aEntryType.isNothing() ||
|
||||
aEntryType.value() ==
|
||||
BounceTrackingProtectionStorage::EntryType::UserActivation) {
|
||||
for (auto iter = mUserActivation.Iter(); !iter.Done(); iter.Next()) {
|
||||
if (iter.Data() >= aFrom &&
|
||||
(aTo.isNothing() || iter.Data() <= aTo.value())) {
|
||||
iter.Remove();
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: Remove user activation for %s", __FUNCTION__,
|
||||
PromiseFlatCString(iter.Key()).get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear in memory bounce tracker data.
|
||||
if (aEntryType.isNothing() ||
|
||||
aEntryType.value() ==
|
||||
BounceTrackingProtectionStorage::EntryType::BounceTracker) {
|
||||
for (auto iter = mBounceTrackers.Iter(); !iter.Done(); iter.Next()) {
|
||||
if (iter.Data() >= aFrom &&
|
||||
(aTo.isNothing() || iter.Data() <= aTo.value())) {
|
||||
iter.Remove();
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: Remove bouncer tracker for %s", __FUNCTION__,
|
||||
PromiseFlatCString(iter.Key()).get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aSkipStorage || !ShouldPersistToDisk()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Write the change to storage.
|
||||
NS_ENSURE_TRUE(mStorage, NS_ERROR_FAILURE);
|
||||
return mStorage->DeleteDBEntriesInTimeRange(&mOriginAttributes, aFrom, aTo,
|
||||
aEntryType);
|
||||
}
|
||||
|
||||
bool BounceTrackingStateGlobal::HasBounceTracker(
|
||||
const nsACString& aSiteHost) const {
|
||||
return mBounceTrackers.Contains(aSiteHost);
|
||||
}
|
||||
|
||||
nsresult BounceTrackingStateGlobal::RecordBounceTracker(
|
||||
const nsACString& aSiteHost, PRTime aTime, bool aSkipStorage) {
|
||||
NS_ENSURE_TRUE(aSiteHost.Length(), NS_ERROR_INVALID_ARG);
|
||||
NS_ENSURE_TRUE(aTime > 0, NS_ERROR_INVALID_ARG);
|
||||
|
||||
// Can not record a bounce tracker if the site has a user activation.
|
||||
NS_ENSURE_TRUE(!mUserActivation.Contains(aSiteHost), NS_ERROR_FAILURE);
|
||||
mBounceTrackers.InsertOrUpdate(aSiteHost, aTime);
|
||||
|
||||
if (aSkipStorage || !ShouldPersistToDisk()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Write the change to storage.
|
||||
NS_ENSURE_TRUE(mStorage, NS_ERROR_FAILURE);
|
||||
return mStorage->UpdateDBEntry(
|
||||
mOriginAttributes, aSiteHost,
|
||||
BounceTrackingProtectionStorage::EntryType::BounceTracker, aTime);
|
||||
}
|
||||
|
||||
nsresult BounceTrackingStateGlobal::RemoveBounceTrackers(
|
||||
const nsTArray<nsCString>& aSiteHosts) {
|
||||
for (const nsCString& siteHost : aSiteHosts) {
|
||||
mBounceTrackers.Remove(siteHost);
|
||||
|
||||
// TODO: Create a bulk delete query.
|
||||
if (ShouldPersistToDisk()) {
|
||||
NS_ENSURE_TRUE(mStorage, NS_ERROR_FAILURE);
|
||||
nsresult rv = mStorage->DeleteDBEntries(&mOriginAttributes, siteHost);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
@ -1,110 +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_BounceTrackingStateGlobal_h
|
||||
#define mozilla_BounceTrackingStateGlobal_h
|
||||
|
||||
#include "BounceTrackingProtectionStorage.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsTHashMap.h"
|
||||
#include "nsISupports.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* This class holds the global state maps which are used to keep track of
|
||||
* potential bounce trackers and user activations.
|
||||
* @see BounceTrackingState for the per browser / tab state.
|
||||
*
|
||||
* Updates to the state maps are persisted to storage.
|
||||
*/
|
||||
class BounceTrackingStateGlobal final {
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(BounceTrackingStateGlobal);
|
||||
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(BounceTrackingStateGlobal);
|
||||
|
||||
BounceTrackingStateGlobal(BounceTrackingProtectionStorage* aStorage,
|
||||
const OriginAttributes& aAttrs);
|
||||
|
||||
bool IsPrivateBrowsing() const {
|
||||
return mOriginAttributes.mPrivateBrowsingId !=
|
||||
nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID;
|
||||
}
|
||||
|
||||
bool ShouldPersistToDisk() const { return !IsPrivateBrowsing(); }
|
||||
|
||||
bool HasUserActivation(const nsACString& aSiteHost) const;
|
||||
|
||||
// Store a user interaction flag for the given host. This will remove the
|
||||
// host from the bounce tracker map if it exists.
|
||||
[[nodiscard]] nsresult RecordUserActivation(const nsACString& aSiteHost,
|
||||
PRTime aTime,
|
||||
bool aSkipStorage = false);
|
||||
|
||||
// Test-only method to clear a user activation flag.
|
||||
[[nodiscard]] nsresult TestRemoveUserActivation(const nsACString& aSiteHost);
|
||||
|
||||
// Clear any user interactions that happened before aTime.
|
||||
[[nodiscard]] nsresult ClearUserActivationBefore(PRTime aTime);
|
||||
|
||||
bool HasBounceTracker(const nsACString& aSiteHost) const;
|
||||
|
||||
// Store a bounce tracker flag for the given host. A host which received user
|
||||
// interaction recently can not be recorded as a bounce tracker.
|
||||
[[nodiscard]] nsresult RecordBounceTracker(const nsACString& aSiteHost,
|
||||
PRTime aTime,
|
||||
bool aSkipStorage = false);
|
||||
|
||||
// Remove one or many bounce trackers identified by site host.
|
||||
[[nodiscard]] nsresult RemoveBounceTrackers(
|
||||
const nsTArray<nsCString>& aSiteHosts);
|
||||
|
||||
[[nodiscard]] nsresult ClearSiteHost(const nsACString& aSiteHost,
|
||||
bool aSkipStorage = false);
|
||||
|
||||
[[nodiscard]] nsresult ClearByTimeRange(
|
||||
PRTime aFrom, Maybe<PRTime> aTo = Nothing(),
|
||||
Maybe<BounceTrackingProtectionStorage::EntryType> aEntryType = Nothing(),
|
||||
bool aSkipStorage = false);
|
||||
|
||||
const nsTHashMap<nsCStringHashKey, PRTime>& UserActivationMapRef() {
|
||||
return mUserActivation;
|
||||
}
|
||||
|
||||
const nsTHashMap<nsCStringHashKey, PRTime>& BounceTrackersMapRef() {
|
||||
return mBounceTrackers;
|
||||
}
|
||||
|
||||
private:
|
||||
~BounceTrackingStateGlobal() = default;
|
||||
|
||||
// The storage which manages this state global. Used to persist changes to
|
||||
// this state global in storage.
|
||||
// This needs to be a weak pointer to avoid BounceTrackingProtectionStorage
|
||||
// and BounceTrackingStateGlobal holding strong references to each other
|
||||
// leading to memory leaks.
|
||||
WeakPtr<BounceTrackingProtectionStorage> mStorage;
|
||||
|
||||
// Origin attributes this state global is associated with. e.g. if the state
|
||||
// was associated with a PBM window this would set privateBrowsingId: 1.
|
||||
OriginAttributes mOriginAttributes;
|
||||
|
||||
// Map of site hosts to moments. The moments represent the most recent wall
|
||||
// clock time at which the user activated a top-level document on the
|
||||
// associated site host.
|
||||
nsTHashMap<nsCStringHashKey, PRTime> mUserActivation{};
|
||||
|
||||
// Map of site hosts to moments. The moments represent the first wall clock
|
||||
// time since the last execution of the bounce tracking timer at which a page
|
||||
// on the given site host performed an action that could indicate stateful
|
||||
// bounce tracking took place.
|
||||
nsTHashMap<nsCStringHashKey, PRTime> mBounceTrackers{};
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -20,19 +20,15 @@ XPCOM_MANIFESTS += [
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
"BounceTrackingProtection.h",
|
||||
"BounceTrackingProtectionStorage.h",
|
||||
"BounceTrackingRecord.h",
|
||||
"BounceTrackingState.h",
|
||||
"BounceTrackingStateGlobal.h",
|
||||
"BounceTrackingStorageObserver.h",
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
"BounceTrackingProtection.cpp",
|
||||
"BounceTrackingProtectionStorage.cpp",
|
||||
"BounceTrackingRecord.cpp",
|
||||
"BounceTrackingState.cpp",
|
||||
"BounceTrackingStateGlobal.cpp",
|
||||
"BounceTrackingStorageObserver.cpp",
|
||||
]
|
||||
|
||||
|
@ -6,41 +6,20 @@
|
||||
|
||||
[scriptable, uuid(4866F748-29DA-4C10-8EAA-ED2F7851E6B1)]
|
||||
interface nsIBounceTrackingProtection : nsISupports {
|
||||
|
||||
readonly attribute Array<ACString> bounceTrackerCandidateHosts;
|
||||
readonly attribute Array<ACString> userActivationHosts;
|
||||
|
||||
// Reset the global bounce tracking state, including the maps for tracking
|
||||
// bounce tracker candidates and user activation.
|
||||
void clearAll();
|
||||
|
||||
// Clear bounce tracking state for a specific site host and OriginAttributes pair.
|
||||
[implicit_jscontext]
|
||||
void clearBySiteHostAndOA(in ACString aSiteHost, in jsval originAttributes);
|
||||
|
||||
// Clear bounce tracking state for a specific site host for all OriginAttributes.
|
||||
void clearBySiteHost(in ACString aSiteHost);
|
||||
|
||||
// Clear bounce tracking state for a specific time range.
|
||||
void clearByTimeRange(in PRTime aFrom, in PRTime aTo);
|
||||
|
||||
// Clear bounce tracking state for the given origin attributes.
|
||||
void clearByOriginAttributesPattern(in AString aPattern);
|
||||
void reset();
|
||||
|
||||
// Trigger the bounce tracking timer algorithm that clears state for
|
||||
// classified bounce trackers.
|
||||
[implicit_jscontext]
|
||||
Promise testRunPurgeBounceTrackers();
|
||||
|
||||
// Getters and setters for user activation and bounce tracker state.
|
||||
// These are used for testing purposes only.
|
||||
// State is keyed by OriginAttributes.
|
||||
void testAddBounceTrackerCandidate(in ACString aHost, in PRTime aBounceTime);
|
||||
|
||||
[implicit_jscontext]
|
||||
Array<ACString> testGetBounceTrackerCandidateHosts(in jsval originAttributes);
|
||||
|
||||
[implicit_jscontext]
|
||||
Array<ACString> testGetUserActivationHosts(in jsval originAttributes);
|
||||
|
||||
[implicit_jscontext]
|
||||
void testAddBounceTrackerCandidate(in jsval originAttributes, in ACString aSiteHost, in PRTime aBounceTime);
|
||||
|
||||
[implicit_jscontext]
|
||||
void testAddUserActivation(in jsval originAttributes, in ACString aSiteHost, in PRTime aActivationTime);
|
||||
void testAddUserActivation(in ACString aHost, in PRTime aActivationTime);
|
||||
};
|
||||
|
@ -11,8 +11,6 @@ support-files = [
|
||||
"file_bounce.html",
|
||||
]
|
||||
|
||||
["browser_bouncetracking_oa_isolation.js"]
|
||||
|
||||
["browser_bouncetracking_purge.js"]
|
||||
|
||||
["browser_bouncetracking_simple.js"]
|
||||
|
@ -1,73 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
add_setup(async function () {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["privacy.bounceTrackingProtection.requireStatefulBounces", true],
|
||||
["privacy.bounceTrackingProtection.bounceTrackingGracePeriodSec", 0],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
// Tests that bounces in PBM don't affect state in normal browsing.
|
||||
add_task(async function test_pbm_data_isolated() {
|
||||
await runTestBounce({
|
||||
bounceType: "client",
|
||||
setState: "cookie-client",
|
||||
originAttributes: { privateBrowsingId: 1 },
|
||||
postBounceCallback: () => {
|
||||
// After the PBM bounce assert that we haven't recorded any data for normal browsing.
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetBounceTrackerCandidateHosts({}).length,
|
||||
0,
|
||||
"No bounce tracker candidates for normal browsing."
|
||||
);
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetUserActivationHosts({}).length,
|
||||
0,
|
||||
"No user activations for normal browsing."
|
||||
);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Tests that bounces in PBM don't affect state in normal browsing.
|
||||
add_task(async function test_containers_isolated() {
|
||||
await runTestBounce({
|
||||
bounceType: "server",
|
||||
setState: "cookie-server",
|
||||
originAttributes: { userContextId: 2 },
|
||||
postBounceCallback: () => {
|
||||
// After the bounce in the container tab assert that we haven't recorded any data for normal browsing.
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetBounceTrackerCandidateHosts({}).length,
|
||||
0,
|
||||
"No bounce tracker candidates for normal browsing."
|
||||
);
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetUserActivationHosts({}).length,
|
||||
0,
|
||||
"No user activations for normal browsing."
|
||||
);
|
||||
|
||||
// Or in another container tab.
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetBounceTrackerCandidateHosts({
|
||||
userContextId: 1,
|
||||
}).length,
|
||||
0,
|
||||
"No bounce tracker candidates for container tab 1."
|
||||
);
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetUserActivationHosts({
|
||||
userContextId: 1,
|
||||
}).length,
|
||||
0,
|
||||
"No user activations for container tab 1."
|
||||
);
|
||||
},
|
||||
});
|
||||
});
|
@ -22,17 +22,16 @@ add_setup(async function () {
|
||||
*/
|
||||
|
||||
function initBounceTrackerState() {
|
||||
bounceTrackingProtection.clearAll();
|
||||
bounceTrackingProtection.reset();
|
||||
|
||||
// Bounce time of 1 is out of the grace period which means we should purge.
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate({}, "example.com", 1);
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate({}, "example.net", 1);
|
||||
// Bounce time of 0 is out of the grace period which means we should purge.
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate("example.com", 0);
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate("example.net", 0);
|
||||
|
||||
// Should not purge because within grace period.
|
||||
let timestampWithinGracePeriod =
|
||||
Date.now() - (BOUNCE_TRACKING_GRACE_PERIOD_SEC * 1000) / 2;
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate(
|
||||
{},
|
||||
"example.org",
|
||||
timestampWithinGracePeriod * 1000
|
||||
);
|
||||
@ -62,7 +61,7 @@ add_task(async function test_purging_skip_open_foreground_tab() {
|
||||
"example.com should have been purged now that it no longer has an open tab."
|
||||
);
|
||||
|
||||
bounceTrackingProtection.clearAll();
|
||||
bounceTrackingProtection.reset();
|
||||
});
|
||||
|
||||
add_task(async function test_purging_skip_open_background_tab() {
|
||||
@ -87,7 +86,7 @@ add_task(async function test_purging_skip_open_background_tab() {
|
||||
"example.com should have been purged now that it no longer has an open tab."
|
||||
);
|
||||
|
||||
bounceTrackingProtection.clearAll();
|
||||
bounceTrackingProtection.reset();
|
||||
});
|
||||
|
||||
add_task(async function test_purging_skip_open_tab_extra_window() {
|
||||
@ -117,5 +116,5 @@ add_task(async function test_purging_skip_open_tab_extra_window() {
|
||||
"example.com should have been purged now that it no longer has an open tab."
|
||||
);
|
||||
|
||||
bounceTrackingProtection.clearAll();
|
||||
bounceTrackingProtection.reset();
|
||||
});
|
||||
|
@ -25,12 +25,12 @@ add_task(async function test_server_bounce_simple() {
|
||||
// Tests a chained redirect consisting of a server and a client redirect.
|
||||
add_task(async function test_bounce_chain() {
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetBounceTrackerCandidateHosts({}).length,
|
||||
bounceTrackingProtection.bounceTrackerCandidateHosts.length,
|
||||
0,
|
||||
"No bounce tracker hosts initially."
|
||||
);
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetUserActivationHosts({}).length,
|
||||
bounceTrackingProtection.userActivationHosts.length,
|
||||
0,
|
||||
"No user activation hosts initially."
|
||||
);
|
||||
@ -73,17 +73,17 @@ add_task(async function test_bounce_chain() {
|
||||
await promiseRecordBounces;
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection.testGetBounceTrackerCandidateHosts({}).sort(),
|
||||
bounceTrackingProtection.bounceTrackerCandidateHosts.sort(),
|
||||
[SITE_TRACKER_B, SITE_TRACKER].sort(),
|
||||
`Identified all bounce trackers in the redirect chain.`
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection.testGetUserActivationHosts({}).sort(),
|
||||
bounceTrackingProtection.userActivationHosts.sort(),
|
||||
[SITE_A, SITE_B].sort(),
|
||||
"Should only have user activation for sites where we clicked links."
|
||||
);
|
||||
|
||||
bounceTrackingProtection.clearAll();
|
||||
bounceTrackingProtection.reset();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -145,12 +145,6 @@ async function waitForRecordBounces(browser) {
|
||||
* identified as a bounce tracker (candidate).
|
||||
* @param {boolean} [options.expectPurge=true] - Expect the redirecting site to have
|
||||
* its storage purged.
|
||||
* @param {OriginAttributes} [options.originAttributes={}] - Origin attributes
|
||||
* to use for the test. This determines whether the test is run in normal
|
||||
* browsing, a private window or a container tab. By default the test is run
|
||||
* in normal browsing.
|
||||
* @param {function} [options.postBounceCallback] - Optional function to run after the
|
||||
* bounce has completed.
|
||||
*/
|
||||
async function runTestBounce(options = {}) {
|
||||
let {
|
||||
@ -158,118 +152,68 @@ async function runTestBounce(options = {}) {
|
||||
setState = null,
|
||||
expectCandidate = true,
|
||||
expectPurge = true,
|
||||
originAttributes = {},
|
||||
postBounceCallback = () => {},
|
||||
} = options;
|
||||
info(`runTestBounce ${JSON.stringify(options)}`);
|
||||
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetBounceTrackerCandidateHosts(
|
||||
originAttributes
|
||||
).length,
|
||||
bounceTrackingProtection.bounceTrackerCandidateHosts.length,
|
||||
0,
|
||||
"No bounce tracker hosts initially."
|
||||
);
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(originAttributes)
|
||||
.length,
|
||||
bounceTrackingProtection.userActivationHosts.length,
|
||||
0,
|
||||
"No user activation hosts initially."
|
||||
);
|
||||
|
||||
let win = window;
|
||||
let { privateBrowsingId, userContextId } = originAttributes;
|
||||
let usePrivateWindow =
|
||||
privateBrowsingId != null &&
|
||||
privateBrowsingId !=
|
||||
Services.scriptSecurityManager.DEFAULT_PRIVATE_BROWSING_ID;
|
||||
if (userContextId != null && userContextId > 0 && usePrivateWindow) {
|
||||
throw new Error("userContextId is not supported in private windows");
|
||||
}
|
||||
await BrowserTestUtils.withNewTab(
|
||||
getBaseUrl(ORIGIN_A) + "file_start.html",
|
||||
async browser => {
|
||||
let promiseRecordBounces = waitForRecordBounces(browser);
|
||||
|
||||
if (usePrivateWindow) {
|
||||
win = await BrowserTestUtils.openNewBrowserWindow({ private: true });
|
||||
}
|
||||
// The final destination after the bounce.
|
||||
let targetURL = new URL(getBaseUrl(ORIGIN_B) + "file_start.html");
|
||||
|
||||
let tab = win.gBrowser.addTab(getBaseUrl(ORIGIN_A) + "file_start.html", {
|
||||
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
userContextId,
|
||||
});
|
||||
win.gBrowser.selectedTab = tab;
|
||||
// Navigate through the bounce chain.
|
||||
await navigateLinkClick(
|
||||
browser,
|
||||
getBounceURL({ bounceType, targetURL, setState })
|
||||
);
|
||||
|
||||
let browser = tab.linkedBrowser;
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
// Wait for the final site to be loaded which complete the BounceTrackingRecord.
|
||||
await BrowserTestUtils.browserLoaded(browser, false, targetURL);
|
||||
|
||||
let promiseRecordBounces = waitForRecordBounces(browser);
|
||||
// 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.
|
||||
await navigateLinkClick(
|
||||
browser,
|
||||
new URL(getBaseUrl(ORIGIN_C) + "file_start.html")
|
||||
);
|
||||
|
||||
// The final destination after the bounce.
|
||||
let targetURL = new URL(getBaseUrl(ORIGIN_B) + "file_start.html");
|
||||
await promiseRecordBounces;
|
||||
|
||||
// Navigate through the bounce chain.
|
||||
await navigateLinkClick(
|
||||
browser,
|
||||
getBounceURL({ bounceType, targetURL, setState })
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection.bounceTrackerCandidateHosts,
|
||||
expectCandidate ? [SITE_TRACKER] : [],
|
||||
`Should ${
|
||||
expectCandidate ? "" : "not "
|
||||
}have identified ${SITE_TRACKER} as a bounce tracker.`
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection.userActivationHosts.sort(),
|
||||
[SITE_A, SITE_B].sort(),
|
||||
"Should only have user activation for sites where we clicked links."
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
await bounceTrackingProtection.testRunPurgeBounceTrackers(),
|
||||
expectPurge ? [SITE_TRACKER] : [],
|
||||
`Should ${expectPurge ? "" : "not "}purge state for ${SITE_TRACKER}.`
|
||||
);
|
||||
|
||||
bounceTrackingProtection.reset();
|
||||
}
|
||||
);
|
||||
|
||||
// Wait for the final site to be loaded which complete the BounceTrackingRecord.
|
||||
await BrowserTestUtils.browserLoaded(browser, false, targetURL);
|
||||
|
||||
// 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.
|
||||
await navigateLinkClick(
|
||||
browser,
|
||||
new URL(getBaseUrl(ORIGIN_C) + "file_start.html")
|
||||
);
|
||||
|
||||
await promiseRecordBounces;
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection.testGetBounceTrackerCandidateHosts(
|
||||
originAttributes
|
||||
),
|
||||
expectCandidate ? [SITE_TRACKER] : [],
|
||||
`Should ${
|
||||
expectCandidate ? "" : "not "
|
||||
}have identified ${SITE_TRACKER} as a bounce tracker.`
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetUserActivationHosts(originAttributes)
|
||||
.sort(),
|
||||
[SITE_A, SITE_B].sort(),
|
||||
"Should only have user activation for sites where we clicked links."
|
||||
);
|
||||
|
||||
// If the caller specified a function to run after the bounce, run it now.
|
||||
await postBounceCallback();
|
||||
|
||||
Assert.deepEqual(
|
||||
await bounceTrackingProtection.testRunPurgeBounceTrackers(),
|
||||
expectPurge ? [SITE_TRACKER] : [],
|
||||
`Should ${expectPurge ? "" : "not "}purge state for ${SITE_TRACKER}.`
|
||||
);
|
||||
|
||||
// Clean up
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
if (usePrivateWindow) {
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
|
||||
info(
|
||||
"Closing the last PBM window should trigger a purge of all PBM state."
|
||||
);
|
||||
Assert.ok(
|
||||
!bounceTrackingProtection.testGetBounceTrackerCandidateHosts(
|
||||
originAttributes
|
||||
).length,
|
||||
"No bounce tracker hosts after closing private window."
|
||||
);
|
||||
Assert.ok(
|
||||
!bounceTrackingProtection.testGetUserActivationHosts(originAttributes)
|
||||
.length,
|
||||
"No user activation hosts after closing private window."
|
||||
);
|
||||
}
|
||||
bounceTrackingProtection.clearAll();
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
[DEFAULT]
|
||||
prefs = [
|
||||
"privacy.bounceTrackingProtection.enabled=true",
|
||||
"privacy.bounceTrackingProtection.enableTestMode=true",
|
||||
]
|
||||
|
||||
["test_bouncetracking_storage_persistence.py"]
|
@ -1,133 +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/.
|
||||
|
||||
from marionette_harness import MarionetteTestCase
|
||||
|
||||
# Tests the persistence of the bounce tracking protection storage across
|
||||
# restarts.
|
||||
|
||||
|
||||
class BounceTrackingStoragePersistenceTestCase(MarionetteTestCase):
|
||||
def setUp(self):
|
||||
super(BounceTrackingStoragePersistenceTestCase, self).setUp()
|
||||
self.marionette.enforce_gecko_prefs(
|
||||
{
|
||||
"privacy.bounceTrackingProtection.enabled": True,
|
||||
"privacy.bounceTrackingProtection.enableTestMode": True,
|
||||
}
|
||||
)
|
||||
|
||||
self.marionette.set_context("chrome")
|
||||
self.populate_state()
|
||||
|
||||
def populate_state(self):
|
||||
# Add some data to test persistence.
|
||||
self.marionette.execute_script(
|
||||
"""
|
||||
let bounceTrackingProtection = Cc["@mozilla.org/bounce-tracking-protection;1"].getService(
|
||||
Ci.nsIBounceTrackingProtection
|
||||
);
|
||||
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate({}, "bouncetracker.net", Date.now() * 10000);
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate({}, "bouncetracker.org", Date.now() * 10000);
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate({ userContextId: 3 }, "tracker.com", Date.now() * 10000);
|
||||
// A private browsing entry which must not be persisted across restarts.
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate({ privateBrowsingId: 1 }, "tracker.net", Date.now() * 10000);
|
||||
|
||||
bounceTrackingProtection.testAddUserActivation({}, "example.com", (Date.now() + 5000) * 10000);
|
||||
// A private browsing entry which must not be persisted across restarts.
|
||||
bounceTrackingProtection.testAddUserActivation({ privateBrowsingId: 1 }, "example.org", (Date.now() + 2000) * 10000);
|
||||
"""
|
||||
)
|
||||
|
||||
def test_state_after_restart(self):
|
||||
self.marionette.restart(clean=False, in_app=True)
|
||||
bounceTrackerCandidates = self.marionette.execute_script(
|
||||
"""
|
||||
let bounceTrackingProtection = Cc["@mozilla.org/bounce-tracking-protection;1"].getService(
|
||||
Ci.nsIBounceTrackingProtection
|
||||
);
|
||||
return bounceTrackingProtection.testGetBounceTrackerCandidateHosts({}).sort();
|
||||
""",
|
||||
)
|
||||
self.assertEqual(
|
||||
len(bounceTrackerCandidates),
|
||||
2,
|
||||
msg="There should be two entries for default OA",
|
||||
)
|
||||
self.assertEqual(bounceTrackerCandidates[0], "bouncetracker.net")
|
||||
self.assertEqual(bounceTrackerCandidates[1], "bouncetracker.org")
|
||||
|
||||
bounceTrackerCandidates = self.marionette.execute_script(
|
||||
"""
|
||||
let bounceTrackingProtection = Cc["@mozilla.org/bounce-tracking-protection;1"].getService(
|
||||
Ci.nsIBounceTrackingProtection
|
||||
);
|
||||
return bounceTrackingProtection.testGetBounceTrackerCandidateHosts({ userContextId: 3 }).sort();
|
||||
""",
|
||||
)
|
||||
self.assertEqual(
|
||||
len(bounceTrackerCandidates),
|
||||
1,
|
||||
msg="There should be only one entry for user context 3",
|
||||
)
|
||||
self.assertEqual(bounceTrackerCandidates[0], "tracker.com")
|
||||
|
||||
# Unrelated user context should not have any entries.
|
||||
bounceTrackerCandidates = self.marionette.execute_script(
|
||||
"""
|
||||
let bounceTrackingProtection = Cc["@mozilla.org/bounce-tracking-protection;1"].getService(
|
||||
Ci.nsIBounceTrackingProtection
|
||||
);
|
||||
return bounceTrackingProtection.testGetBounceTrackerCandidateHosts({ userContextId: 4 }).length;
|
||||
""",
|
||||
)
|
||||
self.assertEqual(
|
||||
bounceTrackerCandidates,
|
||||
0,
|
||||
msg="There should be no entries for user context 4",
|
||||
)
|
||||
|
||||
# Private browsing entries should not be persisted across restarts.
|
||||
bounceTrackerCandidates = self.marionette.execute_script(
|
||||
"""
|
||||
let bounceTrackingProtection = Cc["@mozilla.org/bounce-tracking-protection;1"].getService(
|
||||
Ci.nsIBounceTrackingProtection
|
||||
);
|
||||
return bounceTrackingProtection.testGetBounceTrackerCandidateHosts({ privateBrowsingId: 1 }).length;
|
||||
""",
|
||||
)
|
||||
self.assertEqual(
|
||||
bounceTrackerCandidates,
|
||||
0,
|
||||
msg="There should be no entries for private browsing",
|
||||
)
|
||||
|
||||
userActivations = self.marionette.execute_script(
|
||||
"""
|
||||
let bounceTrackingProtection = Cc["@mozilla.org/bounce-tracking-protection;1"].getService(
|
||||
Ci.nsIBounceTrackingProtection
|
||||
);
|
||||
return bounceTrackingProtection.testGetUserActivationHosts({}).sort();
|
||||
""",
|
||||
)
|
||||
self.assertEqual(
|
||||
len(userActivations),
|
||||
1,
|
||||
msg="There should be only one entry for user activation",
|
||||
)
|
||||
self.assertEqual(userActivations[0], "example.com")
|
||||
|
||||
# Private browsing entries should not be persisted across restarts.
|
||||
userActivations = self.marionette.execute_script(
|
||||
"""
|
||||
let bounceTrackingProtection = Cc["@mozilla.org/bounce-tracking-protection;1"].getService(
|
||||
Ci.nsIBounceTrackingProtection
|
||||
);
|
||||
return bounceTrackingProtection.testGetUserActivationHosts({ privateBrowsingId: 1 }).length;
|
||||
""",
|
||||
)
|
||||
self.assertEqual(
|
||||
userActivations, 0, msg="There should be no entries for private browsing"
|
||||
)
|
@ -52,15 +52,11 @@ async function hasStateForHost(host) {
|
||||
*/
|
||||
function assertEmpty() {
|
||||
Assert.equal(
|
||||
btp.testGetBounceTrackerCandidateHosts({}).length,
|
||||
btp.bounceTrackerCandidateHosts.length,
|
||||
0,
|
||||
"No tracker candidates."
|
||||
);
|
||||
Assert.equal(
|
||||
btp.testGetUserActivationHosts({}).length,
|
||||
0,
|
||||
"No user activation hosts."
|
||||
);
|
||||
Assert.equal(btp.userActivationHosts.length, 0, "No user activation hosts.");
|
||||
}
|
||||
|
||||
add_setup(function () {
|
||||
@ -72,7 +68,7 @@ add_setup(function () {
|
||||
);
|
||||
|
||||
// Reset global bounce tracking state.
|
||||
btp.clearAll();
|
||||
btp.reset();
|
||||
|
||||
bounceTrackingGracePeriodSec = Services.prefs.getIntPref(
|
||||
"privacy.bounceTrackingProtection.bounceTrackingGracePeriodSec"
|
||||
@ -204,7 +200,7 @@ add_task(async function test_purge() {
|
||||
if (bounceTime != null) {
|
||||
if (userActivationTime != null) {
|
||||
throw new Error(
|
||||
"Attempting to construct invalid map state. testGetBounceTrackerCandidateHosts({}) and testGetUserActivationHosts({}) must be disjoint."
|
||||
"Attempting to construct invalid map state. bounceTrackerCandidateHosts and userActivationHosts must be disjoint."
|
||||
);
|
||||
}
|
||||
|
||||
@ -214,13 +210,13 @@ add_task(async function test_purge() {
|
||||
info(
|
||||
`Adding bounce. siteHost: ${siteHost}, bounceTime: ${bounceTime} ms`
|
||||
);
|
||||
btp.testAddBounceTrackerCandidate({}, siteHost, bounceTime * 1000);
|
||||
btp.testAddBounceTrackerCandidate(siteHost, bounceTime * 1000);
|
||||
}
|
||||
|
||||
if (userActivationTime != null) {
|
||||
if (bounceTime != null) {
|
||||
throw new Error(
|
||||
"Attempting to construct invalid map state. testGetBounceTrackerCandidateHosts({}) and testGetUserActivationHosts({}) must be disjoint."
|
||||
"Attempting to construct invalid map state. bounceTrackerCandidateHosts and userActivationHosts must be disjoint."
|
||||
);
|
||||
}
|
||||
|
||||
@ -236,7 +232,7 @@ add_task(async function test_purge() {
|
||||
info(
|
||||
`Adding user interaction. siteHost: ${siteHost}, userActivationTime: ${userActivationTime} ms`
|
||||
);
|
||||
btp.testAddUserActivation({}, siteHost, userActivationTime * 1000);
|
||||
btp.testAddUserActivation(siteHost, userActivationTime * 1000);
|
||||
}
|
||||
|
||||
if (shouldPurge) {
|
||||
@ -250,12 +246,12 @@ add_task(async function test_purge() {
|
||||
"Check that bounce and user activation data has been correctly recorded."
|
||||
);
|
||||
Assert.deepEqual(
|
||||
btp.testGetBounceTrackerCandidateHosts({}).sort(),
|
||||
btp.bounceTrackerCandidateHosts.sort(),
|
||||
expectedBounceTrackerHosts.sort(),
|
||||
"Has added bounce tracker hosts."
|
||||
);
|
||||
Assert.deepEqual(
|
||||
btp.testGetUserActivationHosts({}).sort(),
|
||||
btp.userActivationHosts.sort(),
|
||||
expectedUserActivationHosts.sort(),
|
||||
"Has added user activation hosts."
|
||||
);
|
||||
@ -273,13 +269,13 @@ add_task(async function test_purge() {
|
||||
.filter(host => !expectedPurgedHosts.includes(host))
|
||||
.sort();
|
||||
Assert.deepEqual(
|
||||
btp.testGetBounceTrackerCandidateHosts({}).sort(),
|
||||
btp.bounceTrackerCandidateHosts.sort(),
|
||||
expectedBounceTrackerHostsAfterPurge.sort(),
|
||||
"After purge the bounce tracker candidate host set should be updated correctly."
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
btp.testGetUserActivationHosts({}).sort(),
|
||||
btp.userActivationHosts.sort(),
|
||||
expiredUserActivationHosts.sort(),
|
||||
"After purge any expired user activation records should have been removed"
|
||||
);
|
||||
@ -299,7 +295,7 @@ add_task(async function test_purge() {
|
||||
}
|
||||
|
||||
info("Reset bounce tracking state.");
|
||||
btp.clearAll();
|
||||
btp.reset();
|
||||
assertEmpty();
|
||||
|
||||
info("Clean up site data.");
|
||||
|
@ -31,19 +31,6 @@ XPCOMUtils.defineLazyServiceGetter(
|
||||
"@mozilla.org/browser/identity-credential-storage-service;1",
|
||||
"nsIIdentityCredentialStorageService"
|
||||
);
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
lazy,
|
||||
"bounceTrackingProtection",
|
||||
"@mozilla.org/bounce-tracking-protection;1",
|
||||
"nsIBounceTrackingProtection"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
lazy,
|
||||
"isBounceTrackingProtectionEnabled",
|
||||
"privacy.bounceTrackingProtection.enabled",
|
||||
false
|
||||
);
|
||||
|
||||
/**
|
||||
* Test if host, OriginAttributes or principal belong to a baseDomain. Also
|
||||
@ -95,36 +82,6 @@ function hasBaseDomain(
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the base domain from a given host. This is a wrapper around
|
||||
* Services.eTLD.getBaseDomainFromHost which also supports IP addresses and
|
||||
* hosts such as "localhost" which are considered valid base domains for
|
||||
* principals and data storage.
|
||||
* @param {string} aDomainOrHost - Domain or host to be converted. May already
|
||||
* be a valid base domain.
|
||||
* @returns {string} Base domain of the given host. Returns aDomainOrHost if
|
||||
* already a base domain.
|
||||
*/
|
||||
function getBaseDomainWithFallback(aDomainOrHost) {
|
||||
let result = aDomainOrHost;
|
||||
try {
|
||||
result = Services.eTLD.getBaseDomainFromHost(aDomainOrHost);
|
||||
} catch (e) {
|
||||
if (
|
||||
e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS ||
|
||||
e.result == Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS
|
||||
) {
|
||||
// For these 2 expected errors, just take the host as the result.
|
||||
// - NS_ERROR_HOST_IS_IP_ADDRESS: the host is in ipv4/ipv6.
|
||||
// - NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS: not enough domain parts to extract.
|
||||
result = aDomainOrHost;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Here is a list of methods cleaners may implement. These methods must return a
|
||||
// Promise object.
|
||||
// * deleteAll() - this method _must_ exist. When called, it deletes all the
|
||||
@ -1690,57 +1647,6 @@ const IdentityCredentialStorageCleaner = {
|
||||
},
|
||||
};
|
||||
|
||||
const BounceTrackingProtectionStateCleaner = {
|
||||
async deleteAll() {
|
||||
if (!lazy.isBounceTrackingProtectionEnabled) {
|
||||
return;
|
||||
}
|
||||
await lazy.bounceTrackingProtection.clearAll();
|
||||
},
|
||||
|
||||
async deleteByPrincipal(aPrincipal, aIsUserRequest) {
|
||||
if (!lazy.isBounceTrackingProtectionEnabled) {
|
||||
return;
|
||||
}
|
||||
let { baseDomain, originAttributes } = aPrincipal;
|
||||
await lazy.bounceTrackingProtection.clearBySiteHostAndOA(
|
||||
baseDomain,
|
||||
originAttributes
|
||||
);
|
||||
},
|
||||
|
||||
async deleteByBaseDomain(aBaseDomain, aIsUserRequest) {
|
||||
if (!lazy.isBounceTrackingProtectionEnabled) {
|
||||
return;
|
||||
}
|
||||
await lazy.bounceTrackingProtection.clearBySiteHost(aBaseDomain);
|
||||
},
|
||||
|
||||
async deleteByRange(aFrom, aTo) {
|
||||
if (!lazy.isBounceTrackingProtectionEnabled) {
|
||||
return;
|
||||
}
|
||||
await lazy.bounceTrackingProtection.clearByTimeRange(aFrom, aTo);
|
||||
},
|
||||
|
||||
async deleteByHost(aHost, aOriginAttributes) {
|
||||
if (!lazy.isBounceTrackingProtectionEnabled) {
|
||||
return;
|
||||
}
|
||||
let baseDomain = getBaseDomainWithFallback(aHost);
|
||||
await lazy.bounceTrackingProtection.clearBySiteHost(baseDomain);
|
||||
},
|
||||
|
||||
async deleteByOriginAttributes(aOriginAttributesPatternString) {
|
||||
if (!lazy.isBounceTrackingProtectionEnabled) {
|
||||
return;
|
||||
}
|
||||
await lazy.bounceTrackingProtection.clearByOriginAttributesPattern(
|
||||
aOriginAttributesPatternString
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
// Here the map of Flags-Cleaners.
|
||||
const FLAGS_MAP = [
|
||||
{
|
||||
@ -1870,11 +1776,6 @@ const FLAGS_MAP = [
|
||||
flag: Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE,
|
||||
cleaners: [FingerprintingProtectionStateCleaner],
|
||||
},
|
||||
|
||||
{
|
||||
flag: Ci.nsIClearDataService.CLEAR_BOUNCE_TRACKING_PROTECTION_STATE,
|
||||
cleaners: [BounceTrackingProtectionStateCleaner],
|
||||
},
|
||||
];
|
||||
|
||||
export function ClearDataService() {
|
||||
@ -1932,6 +1833,36 @@ ClearDataService.prototype = Object.freeze({
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Compute the base domain from a given host. This is a wrapper around
|
||||
* Services.eTLD.getBaseDomainFromHost which also supports IP addresses and
|
||||
* hosts such as "localhost" which are considered valid base domains for
|
||||
* principals and data storage.
|
||||
* @param {string} aDomainOrHost - Domain or host to be converted. May already
|
||||
* be a valid base domain.
|
||||
* @returns {string} Base domain of the given host. Returns aDomainOrHost if
|
||||
* already a base domain.
|
||||
*/
|
||||
_getBaseDomainWithFallback(aDomainOrHost) {
|
||||
let result = aDomainOrHost;
|
||||
try {
|
||||
result = Services.eTLD.getBaseDomainFromHost(aDomainOrHost);
|
||||
} catch (e) {
|
||||
if (
|
||||
e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS ||
|
||||
e.result == Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS
|
||||
) {
|
||||
// For these 2 expected errors, just take the host as the result.
|
||||
// - NS_ERROR_HOST_IS_IP_ADDRESS: the host is in ipv4/ipv6.
|
||||
// - NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS: not enough domain parts to extract.
|
||||
result = aDomainOrHost;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
deleteDataFromBaseDomain(aDomainOrHost, aIsUserRequest, aFlags, aCallback) {
|
||||
if (!aDomainOrHost || !aCallback) {
|
||||
return Cr.NS_ERROR_INVALID_ARG;
|
||||
@ -1940,7 +1871,7 @@ ClearDataService.prototype = Object.freeze({
|
||||
let baseDomain;
|
||||
|
||||
try {
|
||||
baseDomain = getBaseDomainWithFallback(aDomainOrHost);
|
||||
baseDomain = this._getBaseDomainWithFallback(aDomainOrHost);
|
||||
} catch (e) {
|
||||
return Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -402,8 +402,7 @@ export var SiteDataTestUtils = {
|
||||
Ci.nsIClearDataService.CLEAR_STORAGE_ACCESS |
|
||||
Ci.nsIClearDataService.CLEAR_COOKIE_BANNER_EXCEPTION |
|
||||
Ci.nsIClearDataService.CLEAR_COOKIE_BANNER_EXECUTED_RECORD |
|
||||
Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE |
|
||||
Ci.nsIClearDataService.CLEAR_BOUNCE_TRACKING_PROTECTION_STATE,
|
||||
Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE,
|
||||
resolve
|
||||
);
|
||||
});
|
||||
|
@ -302,11 +302,6 @@ interface nsIClearDataService : nsISupports
|
||||
*/
|
||||
const uint32_t CLEAR_FINGERPRINTING_PROTECTION_STATE = 1 << 27;
|
||||
|
||||
/**
|
||||
* Clear the bounce tracking protection state.
|
||||
*/
|
||||
const uint32_t CLEAR_BOUNCE_TRACKING_PROTECTION_STATE = 1 << 28;
|
||||
|
||||
/**
|
||||
* Use this value to delete all the data.
|
||||
*/
|
||||
@ -338,8 +333,7 @@ interface nsIClearDataService : nsISupports
|
||||
CLEAR_PREDICTOR_NETWORK_DATA | CLEAR_DOM_PUSH_NOTIFICATIONS |
|
||||
CLEAR_CLIENT_AUTH_REMEMBER_SERVICE | CLEAR_REPORTS | CLEAR_CERT_EXCEPTIONS |
|
||||
CLEAR_CREDENTIAL_MANAGER_STATE | CLEAR_COOKIE_BANNER_EXCEPTION |
|
||||
CLEAR_COOKIE_BANNER_EXECUTED_RECORD | CLEAR_FINGERPRINTING_PROTECTION_STATE |
|
||||
CLEAR_BOUNCE_TRACKING_PROTECTION_STATE;
|
||||
CLEAR_COOKIE_BANNER_EXECUTED_RECORD | CLEAR_FINGERPRINTING_PROTECTION_STATE;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1,625 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { XPCOMUtils } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/XPCOMUtils.sys.mjs"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"bounceTrackingProtection",
|
||||
"@mozilla.org/bounce-tracking-protection;1",
|
||||
"nsIBounceTrackingProtection"
|
||||
);
|
||||
|
||||
const { CLEAR_BOUNCE_TRACKING_PROTECTION_STATE } = Ci.nsIClearDataService;
|
||||
|
||||
const OA_DEFAULT = {};
|
||||
const OA_PRIVATE_BROWSING = { privateBrowsingId: 1 };
|
||||
const OA_CONTAINER = { userContextId: 1 };
|
||||
|
||||
function addTestData() {
|
||||
info("Adding test data.");
|
||||
// Add test data for OriginAttributes {} => normal browsing with no container.
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate(
|
||||
OA_DEFAULT,
|
||||
"common-bounce-tracker.com",
|
||||
100
|
||||
);
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate(
|
||||
OA_DEFAULT,
|
||||
"bounce-tracker-normal-browsing.com",
|
||||
200
|
||||
);
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate(
|
||||
OA_DEFAULT,
|
||||
"bounce-tracker-normal-browsing2.com",
|
||||
300
|
||||
);
|
||||
bounceTrackingProtection.testAddUserActivation(
|
||||
OA_DEFAULT,
|
||||
"common-user-activation.com",
|
||||
400
|
||||
);
|
||||
bounceTrackingProtection.testAddUserActivation(
|
||||
OA_DEFAULT,
|
||||
"user-activation-normal-browsing.com",
|
||||
500
|
||||
);
|
||||
bounceTrackingProtection.testAddUserActivation(
|
||||
OA_DEFAULT,
|
||||
"user-activation-normal-browsing2.com",
|
||||
600
|
||||
);
|
||||
|
||||
// Add test data for private browsing.
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate(
|
||||
OA_PRIVATE_BROWSING,
|
||||
"common-bounce-tracker.com",
|
||||
700
|
||||
);
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate(
|
||||
OA_PRIVATE_BROWSING,
|
||||
"bounce-tracker-private-browsing.com",
|
||||
800
|
||||
);
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate(
|
||||
OA_PRIVATE_BROWSING,
|
||||
"bounce-tracker-private-browsing2.com",
|
||||
900
|
||||
);
|
||||
bounceTrackingProtection.testAddUserActivation(
|
||||
OA_PRIVATE_BROWSING,
|
||||
"common-user-activation.com",
|
||||
1000
|
||||
);
|
||||
bounceTrackingProtection.testAddUserActivation(
|
||||
OA_PRIVATE_BROWSING,
|
||||
"user-activation-private-browsing.com",
|
||||
1100
|
||||
);
|
||||
bounceTrackingProtection.testAddUserActivation(
|
||||
OA_PRIVATE_BROWSING,
|
||||
"user-activation-private-browsing2.com",
|
||||
1200
|
||||
);
|
||||
|
||||
// Add test data for a container.
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate(
|
||||
OA_CONTAINER,
|
||||
"common-bounce-tracker.com",
|
||||
1300
|
||||
);
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate(
|
||||
OA_CONTAINER,
|
||||
"bounce-tracker-container.com",
|
||||
1400
|
||||
);
|
||||
bounceTrackingProtection.testAddBounceTrackerCandidate(
|
||||
OA_CONTAINER,
|
||||
"bounce-tracker-container2.com",
|
||||
1500
|
||||
);
|
||||
bounceTrackingProtection.testAddUserActivation(
|
||||
OA_CONTAINER,
|
||||
"common-user-activation.com",
|
||||
1600
|
||||
);
|
||||
bounceTrackingProtection.testAddUserActivation(
|
||||
OA_CONTAINER,
|
||||
"user-activation-container.com",
|
||||
1700
|
||||
);
|
||||
bounceTrackingProtection.testAddUserActivation(
|
||||
OA_CONTAINER,
|
||||
"user-activation-container2.com",
|
||||
1800
|
||||
);
|
||||
}
|
||||
|
||||
async function runDeleteBySiteHostTest(clearDataServiceFn) {
|
||||
addTestData();
|
||||
|
||||
let baseDomain = "common-bounce-tracker.com";
|
||||
info("Deleting by base domain " + baseDomain);
|
||||
await new Promise(function (resolve) {
|
||||
clearDataServiceFn(
|
||||
baseDomain,
|
||||
true,
|
||||
CLEAR_BOUNCE_TRACKING_PROTECTION_STATE,
|
||||
failedFlags => {
|
||||
Assert.equal(failedFlags, 0, "Clearing should have succeeded");
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetBounceTrackerCandidateHosts(OA_DEFAULT)
|
||||
.sort(),
|
||||
[
|
||||
"bounce-tracker-normal-browsing.com",
|
||||
"bounce-tracker-normal-browsing2.com",
|
||||
],
|
||||
"Should have deleted only 'common-bounce-tracker.com' for default OA."
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(OA_DEFAULT).sort(),
|
||||
[
|
||||
"common-user-activation.com",
|
||||
"user-activation-normal-browsing.com",
|
||||
"user-activation-normal-browsing2.com",
|
||||
],
|
||||
"Should not have deleted any user activations for default OA."
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetBounceTrackerCandidateHosts(OA_PRIVATE_BROWSING)
|
||||
.sort(),
|
||||
[
|
||||
"bounce-tracker-private-browsing.com",
|
||||
"bounce-tracker-private-browsing2.com",
|
||||
],
|
||||
"Should have deleted only 'common-bounce-tracker.com' for private browsing."
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetUserActivationHosts(OA_PRIVATE_BROWSING)
|
||||
.sort(),
|
||||
[
|
||||
"common-user-activation.com",
|
||||
"user-activation-private-browsing.com",
|
||||
"user-activation-private-browsing2.com",
|
||||
],
|
||||
"Should not have deleted any user activations for private browsing."
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetBounceTrackerCandidateHosts(OA_CONTAINER)
|
||||
.sort(),
|
||||
["bounce-tracker-container.com", "bounce-tracker-container2.com"],
|
||||
"Should have deleted only 'common-bounce-tracker.com' for container."
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(OA_CONTAINER).sort(),
|
||||
[
|
||||
"common-user-activation.com",
|
||||
"user-activation-container.com",
|
||||
"user-activation-container2.com",
|
||||
],
|
||||
"Should not have deleted any user activations for container."
|
||||
);
|
||||
|
||||
// Cleanup.
|
||||
bounceTrackingProtection.clearAll();
|
||||
}
|
||||
|
||||
do_get_profile();
|
||||
|
||||
add_task(async function test_deleteAll() {
|
||||
addTestData();
|
||||
|
||||
info("Deleting all data.");
|
||||
await new Promise(function (resolve) {
|
||||
Services.clearData.deleteData(
|
||||
CLEAR_BOUNCE_TRACKING_PROTECTION_STATE,
|
||||
failedFlags => {
|
||||
Assert.equal(failedFlags, 0, "Clearing should have succeeded");
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetBounceTrackerCandidateHosts(OA_DEFAULT)
|
||||
.length,
|
||||
0,
|
||||
"All bounce tracker candidates for default OA should be deleted."
|
||||
);
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(OA_DEFAULT).length,
|
||||
0,
|
||||
"All user activations for default OA should be deleted."
|
||||
);
|
||||
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetBounceTrackerCandidateHosts(
|
||||
OA_PRIVATE_BROWSING
|
||||
).length,
|
||||
0,
|
||||
"All bounce tracker candidates for private browsing should be deleted."
|
||||
);
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(OA_PRIVATE_BROWSING)
|
||||
.length,
|
||||
0,
|
||||
"All user activations for private browsing should be deleted."
|
||||
);
|
||||
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetBounceTrackerCandidateHosts(OA_CONTAINER)
|
||||
.length,
|
||||
0,
|
||||
"All bounce tracker candidates for container 1 should be deleted."
|
||||
);
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(OA_CONTAINER).length,
|
||||
0,
|
||||
"All user activations for container 1 should be deleted."
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_deleteByPrincipal() {
|
||||
addTestData();
|
||||
|
||||
let principal = Services.scriptSecurityManager.createContentPrincipal(
|
||||
Services.io.newURI("https://common-bounce-tracker.com"),
|
||||
{}
|
||||
);
|
||||
console.debug("principal", principal.origin);
|
||||
|
||||
info("Deleting by principal " + principal.origin);
|
||||
await new Promise(function (resolve) {
|
||||
Services.clearData.deleteDataFromPrincipal(
|
||||
principal,
|
||||
false,
|
||||
CLEAR_BOUNCE_TRACKING_PROTECTION_STATE,
|
||||
failedFlags => {
|
||||
Assert.equal(failedFlags, 0, "Clearing should have succeeded");
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetBounceTrackerCandidateHosts(OA_DEFAULT)
|
||||
.sort(),
|
||||
[
|
||||
"bounce-tracker-normal-browsing.com",
|
||||
"bounce-tracker-normal-browsing2.com",
|
||||
],
|
||||
"Should have deleted only 'common-bounce-tracker.com' for default OA."
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(OA_DEFAULT).sort(),
|
||||
[
|
||||
"common-user-activation.com",
|
||||
"user-activation-normal-browsing.com",
|
||||
"user-activation-normal-browsing2.com",
|
||||
],
|
||||
"Should not have deleted any user activations for default OA."
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetBounceTrackerCandidateHosts(OA_PRIVATE_BROWSING)
|
||||
.sort(),
|
||||
[
|
||||
"bounce-tracker-private-browsing.com",
|
||||
"bounce-tracker-private-browsing2.com",
|
||||
"common-bounce-tracker.com",
|
||||
],
|
||||
"Should not have deleted 'common-bounce-tracker.com' for private browsing."
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetUserActivationHosts(OA_PRIVATE_BROWSING)
|
||||
.sort(),
|
||||
[
|
||||
"common-user-activation.com",
|
||||
"user-activation-private-browsing.com",
|
||||
"user-activation-private-browsing2.com",
|
||||
],
|
||||
"Should not have deleted any user activations for private browsing."
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetBounceTrackerCandidateHosts(OA_CONTAINER)
|
||||
.sort(),
|
||||
[
|
||||
"bounce-tracker-container.com",
|
||||
"bounce-tracker-container2.com",
|
||||
"common-bounce-tracker.com",
|
||||
],
|
||||
"Should not have deleted 'common-bounce-tracker.com' for container."
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(OA_CONTAINER).sort(),
|
||||
[
|
||||
"common-user-activation.com",
|
||||
"user-activation-container.com",
|
||||
"user-activation-container2.com",
|
||||
],
|
||||
"Should not have deleted any user activations for container."
|
||||
);
|
||||
|
||||
let principal2 = Services.scriptSecurityManager.createContentPrincipal(
|
||||
Services.io.newURI("https://common-user-activation.com"),
|
||||
OA_CONTAINER
|
||||
);
|
||||
|
||||
info("Deleting by principal " + principal2.origin);
|
||||
await new Promise(function (resolve) {
|
||||
Services.clearData.deleteDataFromPrincipal(
|
||||
principal2,
|
||||
false,
|
||||
CLEAR_BOUNCE_TRACKING_PROTECTION_STATE,
|
||||
failedFlags => {
|
||||
Assert.equal(failedFlags, 0, "Clearing should have succeeded");
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetBounceTrackerCandidateHosts(OA_DEFAULT)
|
||||
.sort(),
|
||||
[
|
||||
"bounce-tracker-normal-browsing.com",
|
||||
"bounce-tracker-normal-browsing2.com",
|
||||
],
|
||||
"Should not have deleted any bounce tracker candidates for default OA."
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(OA_DEFAULT).sort(),
|
||||
[
|
||||
"common-user-activation.com",
|
||||
"user-activation-normal-browsing.com",
|
||||
"user-activation-normal-browsing2.com",
|
||||
],
|
||||
"Should not have deleted 'common-user-activation.com' for default OA."
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetBounceTrackerCandidateHosts(OA_PRIVATE_BROWSING)
|
||||
.sort(),
|
||||
[
|
||||
"bounce-tracker-private-browsing.com",
|
||||
"bounce-tracker-private-browsing2.com",
|
||||
"common-bounce-tracker.com",
|
||||
],
|
||||
"Should not have deleted any bounce tracker candidates for private browsing."
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetUserActivationHosts(OA_PRIVATE_BROWSING)
|
||||
.sort(),
|
||||
[
|
||||
"common-user-activation.com",
|
||||
"user-activation-private-browsing.com",
|
||||
"user-activation-private-browsing2.com",
|
||||
],
|
||||
"Should not have deleted 'common-user-activation.com' for private browsing."
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetBounceTrackerCandidateHosts(OA_CONTAINER)
|
||||
.sort(),
|
||||
[
|
||||
"bounce-tracker-container.com",
|
||||
"bounce-tracker-container2.com",
|
||||
"common-bounce-tracker.com",
|
||||
],
|
||||
"Should not have deleted any bounce tracker candidates for container."
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(OA_CONTAINER).sort(),
|
||||
["user-activation-container.com", "user-activation-container2.com"],
|
||||
"Should have deleted 'common-user-activation.com' for private browsing.."
|
||||
);
|
||||
|
||||
// Cleanup.
|
||||
bounceTrackingProtection.clearAll();
|
||||
});
|
||||
|
||||
add_task(async function test_deleteByBaseDomain() {
|
||||
await runDeleteBySiteHostTest(Services.clearData.deleteDataFromBaseDomain);
|
||||
});
|
||||
|
||||
add_task(async function test_deleteByRange() {
|
||||
addTestData();
|
||||
|
||||
let startTime = 200;
|
||||
let endTime = 1300;
|
||||
|
||||
info(`Deleting by range ${startTime} - ${endTime}`);
|
||||
await new Promise(function (resolve) {
|
||||
Services.clearData.deleteDataInTimeRange(
|
||||
startTime,
|
||||
endTime,
|
||||
true,
|
||||
CLEAR_BOUNCE_TRACKING_PROTECTION_STATE,
|
||||
failedFlags => {
|
||||
Assert.equal(failedFlags, 0, "Clearing should have succeeded");
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetBounceTrackerCandidateHosts(OA_DEFAULT)
|
||||
.sort(),
|
||||
["common-bounce-tracker.com"],
|
||||
"Should have only kept 'common-bounce-tracker.com' for default OA."
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(OA_DEFAULT).sort(),
|
||||
[],
|
||||
"Should not have kept any user activations for default OA."
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetBounceTrackerCandidateHosts(OA_PRIVATE_BROWSING)
|
||||
.sort(),
|
||||
[],
|
||||
"Should not have kept any bounces for private browsing."
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetUserActivationHosts(OA_PRIVATE_BROWSING)
|
||||
.sort(),
|
||||
[],
|
||||
"Should not have kept any user activations for private browsing."
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetBounceTrackerCandidateHosts(OA_CONTAINER)
|
||||
.sort(),
|
||||
["bounce-tracker-container.com", "bounce-tracker-container2.com"],
|
||||
"Should have only kept some bouncer trackers for container."
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(OA_CONTAINER).sort(),
|
||||
[
|
||||
"common-user-activation.com",
|
||||
"user-activation-container.com",
|
||||
"user-activation-container2.com",
|
||||
],
|
||||
"Should have kept all user activations for container."
|
||||
);
|
||||
|
||||
// Cleanup.
|
||||
bounceTrackingProtection.clearAll();
|
||||
});
|
||||
|
||||
add_task(async function test_deleteByHost() {
|
||||
await runDeleteBySiteHostTest(Services.clearData.deleteDataFromHost);
|
||||
});
|
||||
|
||||
add_task(async function test_deleteByOriginAttributes() {
|
||||
addTestData();
|
||||
|
||||
info("Deleting by origin attributes. " + JSON.stringify(OA_CONTAINER));
|
||||
await new Promise(function (resolve) {
|
||||
Services.clearData.deleteDataFromOriginAttributesPattern(
|
||||
OA_CONTAINER,
|
||||
failedFlags => {
|
||||
Assert.equal(failedFlags, 0, "Clearing should have succeeded");
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetBounceTrackerCandidateHosts(OA_DEFAULT)
|
||||
.sort(),
|
||||
[
|
||||
"bounce-tracker-normal-browsing.com",
|
||||
"bounce-tracker-normal-browsing2.com",
|
||||
"common-bounce-tracker.com",
|
||||
],
|
||||
"Should not have deleted any bounce tracker candidates for default OA."
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(OA_DEFAULT).sort(),
|
||||
[
|
||||
"common-user-activation.com",
|
||||
"user-activation-normal-browsing.com",
|
||||
"user-activation-normal-browsing2.com",
|
||||
],
|
||||
"Should not have deleted any user activations for default OA."
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetBounceTrackerCandidateHosts(OA_PRIVATE_BROWSING)
|
||||
.sort(),
|
||||
[
|
||||
"bounce-tracker-private-browsing.com",
|
||||
"bounce-tracker-private-browsing2.com",
|
||||
"common-bounce-tracker.com",
|
||||
],
|
||||
"Should not have deleted any bounce tracker candidates for private browsing."
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetUserActivationHosts(OA_PRIVATE_BROWSING)
|
||||
.sort(),
|
||||
[
|
||||
"common-user-activation.com",
|
||||
"user-activation-private-browsing.com",
|
||||
"user-activation-private-browsing2.com",
|
||||
],
|
||||
"Should not have deleted any user activations for private browsing."
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection
|
||||
.testGetBounceTrackerCandidateHosts(OA_CONTAINER)
|
||||
.sort(),
|
||||
[],
|
||||
"Should have deleted all bounce tracker candidates for container."
|
||||
);
|
||||
Assert.deepEqual(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(OA_CONTAINER).sort(),
|
||||
[],
|
||||
"Should have deleted all user activations for container."
|
||||
);
|
||||
|
||||
info("Deleting by origin attributes {} (all).");
|
||||
await new Promise(function (resolve) {
|
||||
Services.clearData.deleteDataFromOriginAttributesPattern(
|
||||
OA_DEFAULT,
|
||||
failedFlags => {
|
||||
Assert.equal(failedFlags, 0, "Clearing should have succeeded");
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetBounceTrackerCandidateHosts(OA_DEFAULT)
|
||||
.length,
|
||||
0,
|
||||
"Should have deleted all bounce tracker candidates for default OA."
|
||||
);
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(OA_DEFAULT).length,
|
||||
0,
|
||||
"Should have deleted all user activations for default OA."
|
||||
);
|
||||
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetBounceTrackerCandidateHosts(
|
||||
OA_PRIVATE_BROWSING
|
||||
).length,
|
||||
0,
|
||||
"Should have deleted all bounce tracker candidates for private browsing."
|
||||
);
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(OA_PRIVATE_BROWSING)
|
||||
.length,
|
||||
0,
|
||||
"Should have deleted all user activations for private browsing."
|
||||
);
|
||||
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetBounceTrackerCandidateHosts(OA_CONTAINER)
|
||||
.length,
|
||||
0,
|
||||
"Should have deleted all bounce tracker candidates for container."
|
||||
);
|
||||
Assert.equal(
|
||||
bounceTrackingProtection.testGetUserActivationHosts(OA_CONTAINER).length,
|
||||
0,
|
||||
"Should have deleted all user activations for container."
|
||||
);
|
||||
|
||||
// Cleanup.
|
||||
bounceTrackingProtection.clearAll();
|
||||
});
|
@ -4,16 +4,9 @@ firefox-appdir = "browser"
|
||||
head = "head.js"
|
||||
skip-if = ["os == 'android'"]
|
||||
support-files = ""
|
||||
prefs = [
|
||||
"privacy.bounceTrackingProtection.enabled=true",
|
||||
"privacy.bounceTrackingProtection.enableTestMode=true",
|
||||
"privacy.bounceTrackingProtection.bounceTrackingPurgeTimerPeriodSec=0",
|
||||
]
|
||||
|
||||
["test_basic.js"]
|
||||
|
||||
["test_bounce_tracking_protection.js"]
|
||||
|
||||
["test_certs.js"]
|
||||
|
||||
["test_cookie_banner_handling.js"]
|
||||
|
Loading…
x
Reference in New Issue
Block a user