Reland "[DIPS] Move from //chrome to //content."
This reverts commit5783b19dd0
. Reason for revert: Fix failing bot. Original change's description: > Revert "[DIPS] Move from //chrome to //content." > > This reverts commit8915d9509c
. > > Reason for revert: > https://ci.chromium.org/ui/p/chromium/builders/ci/linux-cast-x64-rel/6859/overview > > Original change's description: > > [DIPS] Move from //chrome to //content. > > > > By moving DIPS (Bounce Tracking Mitigations) into //content, it will be > > available for all content embedders, such as Android WebView. > > > > Aside from the obvious file moves, the main changes are: > > - DIPS-related WebContentsObservers are created in > > WebContentsImpl::Init() instead of TabHelpers::AttachTabHelpers() > > - No more DIPSServiceFactory: BrowserContextImpl creates and owns the > > DIPSServiceImpl directly > > - No more DIPSCleanupService (nor its factory): BrowserContextImpl > > deletes the DIPS database file if necessary > > - The logic to trigger DIPS data deletion moved from > > ChromeBrowsingDataRemoverDelegate to BrowsingDataRemoverImpl > > - Tests have to override the ContentBrowserClient instead of setting > > prefs and modifying the HostContentSettingsMap to test 3PC behavior > > - The OpenerHeuristicService was split into two pieces: the part that > > creates cookie grants was moved into //content as the new method > > BrowserContext::BackfillPopupHeuristicGrants(); and the part that > > observes the tracking protection settings stays in //chrome and calls > > that method. > > - Many FeatureParams were moved from tpcd_experiment_features.h in > > //chrome to //components/content_settings/core/common/features.h > > - components/content_settings/core/common was added to content/DEPS > > - Renamed SiteDataAccessType to DIPSDataAccessType > > > > In followup CLs, we will > > (1) Put all of the DIPS classes, functions, etc into the content namespace (crrev.com/c/6039087) > > (2) Rename DIPS prefixes to Dips to comply with the style guide > > (3) Change b/ bug references to crbug.com/ > > (4) Delete DipsDelegate, moving its methods to ContentBrowserClient > > > > Bug: 40883201 > > Change-Id: I3c07e867ae00e6817ff286a71722473c08ead624 > > Fuchsia-Binary-Size: Size increase is unavoidable - moving feature from //chrome to //content > > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6000406 > > Reviewed-by: Avi Drissman <avi@chromium.org> > > Reviewed-by: Joshua Hood <jdh@chromium.org> > > Commit-Queue: Ryan Tarpine <rtarpine@chromium.org> > > Reviewed-by: Adam Langley <agl@chromium.org> > > Cr-Commit-Position: refs/heads/main@{#1399855} > > Bug: 40883201 > Change-Id: I7c74ccf088a40075dd2134d855dc4ad5ea08ae58 > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6117354 > Owners-Override: Owen Min <zmin@chromium.org> > Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> > Auto-Submit: Owen Min <zmin@chromium.org> > Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> > Cr-Commit-Position: refs/heads/main@{#1399859} Bug: 40883201 Change-Id: If191568901b803a8c4d1daebab27a295cbe38a0e Fuchsia-Binary-Size: Size increase is unavoidable - moving feature from //chrome to //content Cq-Include-Trybots: luci.chromium.try:linux-cast-x64-rel Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6121689 Reviewed-by: Avi Drissman <avi@chromium.org> Reviewed-by: Joshua Hood <jdh@chromium.org> Reviewed-by: Adam Langley <agl@chromium.org> Owners-Override: Ryan Tarpine <rtarpine@chromium.org> Reviewed-by: Mike Wasserman <msw@chromium.org> Commit-Queue: Ryan Tarpine <rtarpine@chromium.org> Cr-Commit-Position: refs/heads/main@{#1400362}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
6d610a2fae
commit
35c4db2b9a
chrome
browser
BUILD.gnabout_flags.cc
browsing_data
chrome_browsing_data_remover_delegate.ccchrome_browsing_data_remover_delegate.hchrome_browsing_data_remover_delegate_unittest.cc
chrome_content_browser_client.ccchrome_content_browser_client.hdevtools
dips
BUILD.gnDEPSchrome_dips_delegate.ccdips_browser_signin_detector.ccdips_browser_signin_detector_factory.ccdips_browser_signin_detector_unittest.ccdips_cleanup_service.ccdips_cleanup_service.hdips_cleanup_service_factory.ccdips_cleanup_service_factory.hdips_cleanup_service_unittest.ccdips_devtools_browsertest.ccdips_service.hdips_service_factory.ccdips_service_factory.hstateful_bounce_counter.ccstateful_bounce_counter.h
profiles
storage_access_api
tpcd
experiment
heuristics
opener_heuristic_metrics.hopener_heuristic_service.ccopener_heuristic_service.hopener_heuristic_service_browsertest.ccopener_heuristic_service_factory.ccopener_heuristic_utils.h
metadata
ui
test
components
content
DEPS
browser
BUILD.gnbrowser_context.ccbrowser_context_impl.ccbrowser_context_impl.h
browsing_data
dips
BUILD.gnDEPSDIR_METADATAOWNERSREADME.mdcookie_access_filter.cccookie_access_filter.hcookie_access_filter_unittest.ccdips_bounce_detector.ccdips_bounce_detector.hdips_bounce_detector_browsertest.ccdips_bounce_detector_unittest.ccdips_browsertest_utils.ccdips_browsertest_utils.hdips_database.ccdips_database.hdips_database_migrator.ccdips_database_migrator.hdips_database_migrator_unittest.ccdips_database_unittest.ccdips_helper_browsertest.ccdips_navigation_flow_detector.ccdips_navigation_flow_detector.hdips_navigation_flow_detector_browsertest.ccdips_service_impl.ccdips_service_impl.hdips_service_unittest.ccdips_state.ccdips_state.hdips_storage.ccdips_storage.hdips_storage_unittest.ccdips_test_utils.ccdips_test_utils.hdips_utils.ccdips_utils.hdips_utils_unittest.ccpersistent_repeating_timer.ccpersistent_repeating_timer.hpersistent_repeating_timer_unittest.cc
tpcd_heuristics
BUILD.gnDIR_METADATAOWNERSREADME.mdopener_heuristic_browsertest.ccopener_heuristic_metrics.ccopener_heuristic_metrics.hopener_heuristic_metrics_unittest.ccopener_heuristic_tab_helper.ccopener_heuristic_tab_helper.hopener_heuristic_utils.ccopener_heuristic_utils.hopener_heuristic_utils_unittest.ccredirect_heuristic_tab_helper.ccredirect_heuristic_tab_helper.h
web_contents
public
browser
test
test
BUILD.gncontent_test_bundle_data.filelist
data
ui/views/controls/webview
@ -369,39 +369,10 @@ static_library("browser") {
|
||||
"digital_credentials/digital_identity_low_risk_origins.h",
|
||||
"dips/chrome_dips_delegate.cc",
|
||||
"dips/chrome_dips_delegate.h",
|
||||
"dips/cookie_access_filter.cc",
|
||||
"dips/cookie_access_filter.h",
|
||||
"dips/dips_bounce_detector.cc",
|
||||
"dips/dips_bounce_detector.h",
|
||||
"dips/dips_browser_signin_detector.cc",
|
||||
"dips/dips_browser_signin_detector.h",
|
||||
"dips/dips_browser_signin_detector_factory.cc",
|
||||
"dips/dips_browser_signin_detector_factory.h",
|
||||
"dips/dips_cleanup_service.cc",
|
||||
"dips/dips_cleanup_service.h",
|
||||
"dips/dips_cleanup_service_factory.cc",
|
||||
"dips/dips_cleanup_service_factory.h",
|
||||
"dips/dips_database.cc",
|
||||
"dips/dips_database.h",
|
||||
"dips/dips_database_migrator.cc",
|
||||
"dips/dips_database_migrator.h",
|
||||
"dips/dips_navigation_flow_detector.cc",
|
||||
"dips/dips_navigation_flow_detector.h",
|
||||
"dips/dips_redirect_info.cc",
|
||||
"dips/dips_redirect_info.h",
|
||||
"dips/dips_service.h",
|
||||
"dips/dips_service_factory.cc",
|
||||
"dips/dips_service_factory.h",
|
||||
"dips/dips_service_impl.cc",
|
||||
"dips/dips_service_impl.h",
|
||||
"dips/dips_state.cc",
|
||||
"dips/dips_state.h",
|
||||
"dips/dips_storage.cc",
|
||||
"dips/dips_storage.h",
|
||||
"dips/dips_utils.cc",
|
||||
"dips/dips_utils.h",
|
||||
"dips/persistent_repeating_timer.cc",
|
||||
"dips/persistent_repeating_timer.h",
|
||||
"dips/stateful_bounce_counter.cc",
|
||||
"dips/stateful_bounce_counter.h",
|
||||
"display_capture/captured_surface_control_permission_context.cc",
|
||||
@ -1586,18 +1557,10 @@ static_library("browser") {
|
||||
"tpcd/experiment/experiment_manager_impl.h",
|
||||
"tpcd/experiment/tpcd_experiment_features.cc",
|
||||
"tpcd/experiment/tpcd_experiment_features.h",
|
||||
"tpcd/heuristics/opener_heuristic_metrics.cc",
|
||||
"tpcd/heuristics/opener_heuristic_metrics.h",
|
||||
"tpcd/heuristics/opener_heuristic_service.cc",
|
||||
"tpcd/heuristics/opener_heuristic_service.h",
|
||||
"tpcd/heuristics/opener_heuristic_service_factory.cc",
|
||||
"tpcd/heuristics/opener_heuristic_service_factory.h",
|
||||
"tpcd/heuristics/opener_heuristic_tab_helper.cc",
|
||||
"tpcd/heuristics/opener_heuristic_tab_helper.h",
|
||||
"tpcd/heuristics/opener_heuristic_utils.cc",
|
||||
"tpcd/heuristics/opener_heuristic_utils.h",
|
||||
"tpcd/heuristics/redirect_heuristic_tab_helper.cc",
|
||||
"tpcd/heuristics/redirect_heuristic_tab_helper.h",
|
||||
"tpcd/http_error_observer/http_error_tab_helper.cc",
|
||||
"tpcd/http_error_observer/http_error_tab_helper.h",
|
||||
"tpcd/metadata/devtools_observer.cc",
|
||||
|
@ -3302,56 +3302,75 @@ const FeatureEntry::FeatureParam
|
||||
kTpcdHeuristicsGrants_CurrentInteraction_ShortRedirect_MainFrameInitiator
|
||||
[] = {
|
||||
{content_settings::features::kTpcdReadHeuristicsGrantsName, "true"},
|
||||
{tpcd::experiment::
|
||||
{content_settings::features::
|
||||
kTpcdWritePopupCurrentInteractionHeuristicsGrantsName,
|
||||
"30d"},
|
||||
{tpcd::experiment::kTpcdBackfillPopupHeuristicsGrantsName, "30d"},
|
||||
{tpcd::experiment::kTpcdPopupHeuristicEnableForIframeInitiatorName,
|
||||
{content_settings::features::kTpcdBackfillPopupHeuristicsGrantsName,
|
||||
"30d"},
|
||||
{content_settings::features::
|
||||
kTpcdPopupHeuristicEnableForIframeInitiatorName,
|
||||
"none"},
|
||||
{tpcd::experiment::kTpcdWriteRedirectHeuristicGrantsName, "15m"},
|
||||
{tpcd::experiment::kTpcdRedirectHeuristicRequireABAFlowName,
|
||||
{content_settings::features::kTpcdWriteRedirectHeuristicGrantsName,
|
||||
"15m"},
|
||||
{content_settings::features::
|
||||
kTpcdRedirectHeuristicRequireABAFlowName,
|
||||
"true"},
|
||||
{tpcd::experiment::
|
||||
{content_settings::features::
|
||||
kTpcdRedirectHeuristicRequireCurrentInteractionName,
|
||||
"true"}};
|
||||
const FeatureEntry::FeatureParam
|
||||
kTpcdHeuristicsGrants_CurrentInteraction_LongRedirect_MainFrameInitiator[] =
|
||||
{{content_settings::features::kTpcdReadHeuristicsGrantsName, "true"},
|
||||
{tpcd::experiment::
|
||||
{content_settings::features::
|
||||
kTpcdWritePopupCurrentInteractionHeuristicsGrantsName,
|
||||
"30d"},
|
||||
{tpcd::experiment::kTpcdBackfillPopupHeuristicsGrantsName, "30d"},
|
||||
{tpcd::experiment::kTpcdPopupHeuristicEnableForIframeInitiatorName,
|
||||
{content_settings::features::kTpcdBackfillPopupHeuristicsGrantsName,
|
||||
"30d"},
|
||||
{content_settings::features::
|
||||
kTpcdPopupHeuristicEnableForIframeInitiatorName,
|
||||
"none"},
|
||||
{tpcd::experiment::kTpcdWriteRedirectHeuristicGrantsName, "30d"},
|
||||
{tpcd::experiment::kTpcdRedirectHeuristicRequireABAFlowName, "true"},
|
||||
{tpcd::experiment::kTpcdRedirectHeuristicRequireCurrentInteractionName,
|
||||
{content_settings::features::kTpcdWriteRedirectHeuristicGrantsName,
|
||||
"30d"},
|
||||
{content_settings::features::kTpcdRedirectHeuristicRequireABAFlowName,
|
||||
"true"},
|
||||
{content_settings::features::
|
||||
kTpcdRedirectHeuristicRequireCurrentInteractionName,
|
||||
"true"}};
|
||||
const FeatureEntry::FeatureParam
|
||||
kTpcdHeuristicsGrants_CurrentInteraction_ShortRedirect_AllFrameInitiator[] =
|
||||
{{content_settings::features::kTpcdReadHeuristicsGrantsName, "true"},
|
||||
{tpcd::experiment::
|
||||
{content_settings::features::
|
||||
kTpcdWritePopupCurrentInteractionHeuristicsGrantsName,
|
||||
"30d"},
|
||||
{tpcd::experiment::kTpcdBackfillPopupHeuristicsGrantsName, "30d"},
|
||||
{tpcd::experiment::kTpcdPopupHeuristicEnableForIframeInitiatorName,
|
||||
{content_settings::features::kTpcdBackfillPopupHeuristicsGrantsName,
|
||||
"30d"},
|
||||
{content_settings::features::
|
||||
kTpcdPopupHeuristicEnableForIframeInitiatorName,
|
||||
"all"},
|
||||
{tpcd::experiment::kTpcdWriteRedirectHeuristicGrantsName, "15m"},
|
||||
{tpcd::experiment::kTpcdRedirectHeuristicRequireABAFlowName, "true"},
|
||||
{tpcd::experiment::kTpcdRedirectHeuristicRequireCurrentInteractionName,
|
||||
{content_settings::features::kTpcdWriteRedirectHeuristicGrantsName,
|
||||
"15m"},
|
||||
{content_settings::features::kTpcdRedirectHeuristicRequireABAFlowName,
|
||||
"true"},
|
||||
{content_settings::features::
|
||||
kTpcdRedirectHeuristicRequireCurrentInteractionName,
|
||||
"true"}};
|
||||
const FeatureEntry::FeatureParam
|
||||
kTpcdHeuristicsGrants_CurrentInteraction_LongRedirect_AllFrameInitiator[] =
|
||||
{{content_settings::features::kTpcdReadHeuristicsGrantsName, "true"},
|
||||
{tpcd::experiment::
|
||||
{content_settings::features::
|
||||
kTpcdWritePopupCurrentInteractionHeuristicsGrantsName,
|
||||
"30d"},
|
||||
{tpcd::experiment::kTpcdBackfillPopupHeuristicsGrantsName, "30d"},
|
||||
{tpcd::experiment::kTpcdPopupHeuristicEnableForIframeInitiatorName,
|
||||
{content_settings::features::kTpcdBackfillPopupHeuristicsGrantsName,
|
||||
"30d"},
|
||||
{content_settings::features::
|
||||
kTpcdPopupHeuristicEnableForIframeInitiatorName,
|
||||
"all"},
|
||||
{tpcd::experiment::kTpcdWriteRedirectHeuristicGrantsName, "30d"},
|
||||
{tpcd::experiment::kTpcdRedirectHeuristicRequireABAFlowName, "true"},
|
||||
{tpcd::experiment::kTpcdRedirectHeuristicRequireCurrentInteractionName,
|
||||
{content_settings::features::kTpcdWriteRedirectHeuristicGrantsName,
|
||||
"30d"},
|
||||
{content_settings::features::kTpcdRedirectHeuristicRequireABAFlowName,
|
||||
"true"},
|
||||
{content_settings::features::
|
||||
kTpcdRedirectHeuristicRequireCurrentInteractionName,
|
||||
"true"}};
|
||||
|
||||
const FeatureEntry::FeatureVariation kTpcdHeuristicsGrantsVariations[] = {
|
||||
|
@ -42,9 +42,6 @@
|
||||
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
|
||||
#include "chrome/browser/crash_upload_list/crash_upload_list.h"
|
||||
#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
|
||||
#include "chrome/browser/dips/chrome_dips_delegate.h"
|
||||
#include "chrome/browser/dips/dips_service_impl.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "chrome/browser/domain_reliability/service_factory.h"
|
||||
#include "chrome/browser/downgrade/user_data_downgrade.h"
|
||||
#include "chrome/browser/download/download_prefs.h"
|
||||
@ -152,7 +149,6 @@
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/browsing_data_filter_builder.h"
|
||||
#include "content/public/browser/dips_delegate.h"
|
||||
#include "content/public/browser/host_zoom_map.h"
|
||||
#include "content/public/browser/origin_trials_controller_delegate.h"
|
||||
#include "content/public/browser/prefetch_service_delegate.h"
|
||||
@ -284,8 +280,7 @@ ChromeBrowsingDataRemoverDelegate::ChromeBrowsingDataRemoverDelegate(
|
||||
webapp_registry_(std::make_unique<WebappRegistry>())
|
||||
#endif
|
||||
,
|
||||
credential_store_(MakeCredentialStore()),
|
||||
dips_delegate_(ChromeDipsDelegate::Create()) {
|
||||
credential_store_(MakeCredentialStore()) {
|
||||
domain_reliability_clearer_ = base::BindRepeating(
|
||||
[](BrowserContext* browser_context,
|
||||
content::BrowsingDataFilterBuilder* filter_builder,
|
||||
@ -909,30 +904,6 @@ void ChromeBrowsingDataRemoverDelegate::RemoveEmbedderData(
|
||||
->RemoveEmbargoAndResetCounts(filter);
|
||||
}
|
||||
|
||||
// Different types of DIPS events are cleared for DATA_TYPE_HISTORY and
|
||||
// DATA_TYPE_COOKIES.
|
||||
DIPSEventRemovalType dips_mask = DIPSEventRemovalType::kNone;
|
||||
if ((remove_mask & content::BrowsingDataRemover::DATA_TYPE_COOKIES) &&
|
||||
!filter_builder->PartitionedCookiesOnly()) {
|
||||
// If there's no delegate, delete everything whenever the user is deleting
|
||||
// cookies.
|
||||
dips_mask |= dips_delegate_ ? DIPSEventRemovalType::kStorage
|
||||
: DIPSEventRemovalType::kAll;
|
||||
}
|
||||
// If there's a delegate, ask it whether to delete DIPS history.
|
||||
if (dips_delegate_ &&
|
||||
dips_delegate_->ShouldDeleteInteractionRecords(remove_mask)) {
|
||||
dips_mask |= DIPSEventRemovalType::kHistory;
|
||||
}
|
||||
|
||||
if (dips_mask != DIPSEventRemovalType::kNone) {
|
||||
if (DIPSServiceImpl* dips_service = DIPSServiceImpl::Get(profile_)) {
|
||||
dips_service->RemoveEvents(delete_begin_, delete_end_,
|
||||
filter_builder->BuildNetworkServiceFilter(),
|
||||
dips_mask);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Password manager
|
||||
if (remove_mask & constants::DATA_TYPE_PASSWORDS) {
|
||||
|
@ -39,7 +39,6 @@ class WaitableEvent;
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
class DipsDelegate;
|
||||
class StoragePartition;
|
||||
}
|
||||
|
||||
@ -266,8 +265,6 @@ class ChromeBrowsingDataRemoverDelegate
|
||||
|
||||
std::unique_ptr<device::fido::PlatformCredentialStore> credential_store_;
|
||||
|
||||
std::unique_ptr<content::DipsDelegate> dips_delegate_;
|
||||
|
||||
base::WeakPtrFactory<ChromeBrowsingDataRemoverDelegate> weak_ptr_factory_{
|
||||
this};
|
||||
};
|
||||
|
@ -51,8 +51,6 @@
|
||||
#include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_factory.h"
|
||||
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
|
||||
#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
|
||||
#include "chrome/browser/dips/dips_service_impl.h"
|
||||
#include "chrome/browser/dips/dips_storage.h"
|
||||
#include "chrome/browser/domain_reliability/service_factory.h"
|
||||
#include "chrome/browser/download/chrome_download_manager_delegate.h"
|
||||
#include "chrome/browser/download/download_core_service_factory.h"
|
||||
@ -687,44 +685,6 @@ class ClearDomainReliabilityTester {
|
||||
base::RepeatingCallback<bool(const GURL&)> last_filter_;
|
||||
};
|
||||
|
||||
class RemoveDIPSEventsTester {
|
||||
public:
|
||||
explicit RemoveDIPSEventsTester(Profile* profile) {
|
||||
storage_ = DIPSServiceImpl::Get(profile)->storage();
|
||||
}
|
||||
|
||||
void WriteEventTimes(GURL url,
|
||||
std::optional<base::Time> storage_time,
|
||||
std::optional<base::Time> interaction_time) {
|
||||
if (storage_time.has_value()) {
|
||||
storage_->AsyncCall(&DIPSStorage::RecordStorage)
|
||||
.WithArgs(url, storage_time.value(), DIPSCookieMode::kBlock3PC);
|
||||
}
|
||||
if (interaction_time.has_value()) {
|
||||
storage_->AsyncCall(&DIPSStorage::RecordInteraction)
|
||||
.WithArgs(url, interaction_time.value(), DIPSCookieMode::kBlock3PC);
|
||||
}
|
||||
storage_->FlushPostedTasksForTesting();
|
||||
}
|
||||
|
||||
std::optional<StateValue> ReadStateValue(GURL url) {
|
||||
std::optional<StateValue> value;
|
||||
|
||||
storage_->AsyncCall(&DIPSStorage::Read)
|
||||
.WithArgs(url)
|
||||
.Then(base::BindLambdaForTesting([&](const DIPSState& state) {
|
||||
value = state.was_loaded() ? std::make_optional(state.ToStateValue())
|
||||
: std::nullopt;
|
||||
}));
|
||||
storage_->FlushPostedTasksForTesting();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
raw_ptr<base::SequenceBound<DIPSStorage>> storage_;
|
||||
};
|
||||
|
||||
class RemoveSecurePaymentConfirmationCredentialsTester {
|
||||
public:
|
||||
using MockWrapper = testing::NiceMock<payments::MockWebDataServiceWrapper>;
|
||||
@ -3588,125 +3548,6 @@ TEST_F(ChromeBrowsingDataRemoverDelegateTest, RemoveTopicSettings) {
|
||||
EXPECT_TRUE(privacy_sandbox_settings->IsTopicAllowed(topic_two));
|
||||
}
|
||||
|
||||
TEST_F(ChromeBrowsingDataRemoverDelegateTest, RemoveDIPSEventsForLastHour) {
|
||||
RemoveDIPSEventsTester tester(GetProfile());
|
||||
GURL url1("https://example1.com");
|
||||
GURL url2("https://example2.com");
|
||||
base::Time two_hours_ago = base::Time::Now() - base::Hours(2);
|
||||
|
||||
tester.WriteEventTimes(url1, /*storage_time=*/base::Time::Now(),
|
||||
/*interaction_time=*/std::nullopt);
|
||||
tester.WriteEventTimes(url2, /*storage_time=*/std::nullopt,
|
||||
/*interaction_time=*/two_hours_ago);
|
||||
|
||||
{
|
||||
std::optional<StateValue> state_val1 = tester.ReadStateValue(url1);
|
||||
std::optional<StateValue> state_val2 = tester.ReadStateValue(url2);
|
||||
|
||||
ASSERT_TRUE(state_val1.has_value());
|
||||
EXPECT_TRUE(state_val1->site_storage_times.has_value());
|
||||
ASSERT_TRUE(state_val2.has_value());
|
||||
EXPECT_TRUE(state_val2->user_interaction_times.has_value());
|
||||
}
|
||||
|
||||
uint64_t remove_mask = constants::DATA_TYPE_HISTORY |
|
||||
content::BrowsingDataRemover::DATA_TYPE_COOKIES;
|
||||
|
||||
BlockUntilBrowsingDataRemoved(AnHourAgo(), base::Time::Max(), remove_mask,
|
||||
false);
|
||||
|
||||
{
|
||||
std::optional<StateValue> state_val1 = tester.ReadStateValue(url1);
|
||||
std::optional<StateValue> state_val2 = tester.ReadStateValue(url2);
|
||||
|
||||
EXPECT_FALSE(state_val1.has_value());
|
||||
ASSERT_TRUE(state_val2.has_value());
|
||||
EXPECT_TRUE(state_val2->user_interaction_times.has_value());
|
||||
}
|
||||
|
||||
BlockUntilBrowsingDataRemoved(base::Time(), base::Time::Max(), remove_mask,
|
||||
false);
|
||||
|
||||
{
|
||||
std::optional<StateValue> state_val1 = tester.ReadStateValue(url1);
|
||||
std::optional<StateValue> state_val2 = tester.ReadStateValue(url2);
|
||||
|
||||
EXPECT_FALSE(state_val1.has_value());
|
||||
EXPECT_FALSE(state_val2.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ChromeBrowsingDataRemoverDelegateTest, RemoveDIPSEventsByType) {
|
||||
RemoveDIPSEventsTester tester(GetProfile());
|
||||
GURL url1("https://example1.com");
|
||||
GURL url2("https://example2.com");
|
||||
GURL url3("https://example3.com");
|
||||
base::Time two_hours_ago = base::Time::Now() - base::Hours(2);
|
||||
|
||||
tester.WriteEventTimes(url1, /*storage_time=*/base::Time::Now(),
|
||||
/*interaction_time=*/std::nullopt);
|
||||
tester.WriteEventTimes(url2, /*storage_time=*/std::nullopt,
|
||||
/*interaction_time=*/base::Time::Now());
|
||||
tester.WriteEventTimes(url3, /*storage_time=*/base::Time::Now(),
|
||||
/*interaction_time=*/two_hours_ago);
|
||||
|
||||
{
|
||||
std::optional<StateValue> state_val1 = tester.ReadStateValue(url1);
|
||||
std::optional<StateValue> state_val2 = tester.ReadStateValue(url2);
|
||||
std::optional<StateValue> state_val3 = tester.ReadStateValue(url3);
|
||||
|
||||
ASSERT_TRUE(state_val1.has_value());
|
||||
EXPECT_TRUE(state_val1->site_storage_times.has_value());
|
||||
|
||||
ASSERT_TRUE(state_val2.has_value());
|
||||
EXPECT_TRUE(state_val2->user_interaction_times.has_value());
|
||||
|
||||
ASSERT_TRUE(state_val3.has_value());
|
||||
EXPECT_TRUE(state_val3->site_storage_times.has_value());
|
||||
EXPECT_TRUE(state_val3->user_interaction_times.has_value());
|
||||
}
|
||||
|
||||
// Remove interaction events from DIPS Storage.
|
||||
BlockUntilBrowsingDataRemoved(AnHourAgo(), base::Time::Max(),
|
||||
constants::DATA_TYPE_HISTORY, false);
|
||||
|
||||
// Verify the interaction event for url2 has been removed.
|
||||
{
|
||||
std::optional<StateValue> state_val1 = tester.ReadStateValue(url1);
|
||||
std::optional<StateValue> state_val2 = tester.ReadStateValue(url2);
|
||||
std::optional<StateValue> state_val3 = tester.ReadStateValue(url3);
|
||||
|
||||
ASSERT_TRUE(state_val1.has_value());
|
||||
EXPECT_TRUE(state_val1->site_storage_times.has_value());
|
||||
|
||||
EXPECT_FALSE(state_val2.has_value());
|
||||
|
||||
ASSERT_TRUE(state_val3.has_value());
|
||||
EXPECT_TRUE(state_val3->site_storage_times.has_value());
|
||||
EXPECT_TRUE(state_val3->user_interaction_times.has_value());
|
||||
}
|
||||
|
||||
// Remove storage events from DIPS Storage.
|
||||
BlockUntilBrowsingDataRemoved(AnHourAgo(), base::Time::Max(),
|
||||
content::BrowsingDataRemover::DATA_TYPE_COOKIES,
|
||||
false);
|
||||
|
||||
// Verify the storage events for url1 and url3 have been removed.
|
||||
{
|
||||
std::optional<StateValue> state_val1 = tester.ReadStateValue(url1);
|
||||
std::optional<StateValue> state_val2 = tester.ReadStateValue(url2);
|
||||
std::optional<StateValue> state_val3 = tester.ReadStateValue(url3);
|
||||
|
||||
EXPECT_FALSE(state_val1.has_value());
|
||||
|
||||
EXPECT_FALSE(state_val2.has_value());
|
||||
|
||||
ASSERT_TRUE(state_val3.has_value());
|
||||
EXPECT_FALSE(state_val3->site_storage_times.has_value());
|
||||
EXPECT_TRUE(state_val3->user_interaction_times.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ChromeBrowsingDataRemoverDelegateTest,
|
||||
ClearPermissionPromptCounts) {
|
||||
RemovePermissionPromptCountsTest tester(GetProfile());
|
||||
|
@ -3665,18 +3665,6 @@ bool ChromeContentBrowserClient::IsFullCookieAccessAllowed(
|
||||
content::WebContents* web_contents,
|
||||
const GURL& url,
|
||||
const blink::StorageKey& storage_key) {
|
||||
return dips_move::IsFullCookieAccessAllowed(browser_context, web_contents,
|
||||
url, storage_key);
|
||||
}
|
||||
|
||||
// TODO: crbug.com/369813097 - Move this implementation into
|
||||
// ChromeContentBrowserClient::IsFullCookieAccessAllowed() after DIPS migrates
|
||||
// to //content.
|
||||
namespace dips_move {
|
||||
bool IsFullCookieAccessAllowed(content::BrowserContext* browser_context,
|
||||
content::WebContents* web_contents,
|
||||
const GURL& url,
|
||||
const blink::StorageKey& storage_key) {
|
||||
Profile* profile = Profile::FromBrowserContext(browser_context);
|
||||
scoped_refptr<content_settings::CookieSettings> cookie_settings =
|
||||
CookieSettingsFactory::GetForProfile(profile);
|
||||
@ -3688,7 +3676,6 @@ bool IsFullCookieAccessAllowed(content::BrowserContext* browser_context,
|
||||
url::Origin::Create(storage_key.top_level_site().GetURL()),
|
||||
cookie_settings->SettingOverridesForStorage());
|
||||
}
|
||||
} // namespace dips_move
|
||||
|
||||
void ChromeContentBrowserClient::GrantCookieAccessDueToHeuristic(
|
||||
content::BrowserContext* browser_context,
|
||||
@ -3696,19 +3683,6 @@ void ChromeContentBrowserClient::GrantCookieAccessDueToHeuristic(
|
||||
const net::SchemefulSite& accessing_site,
|
||||
base::TimeDelta ttl,
|
||||
bool ignore_schemes) {
|
||||
dips_move::GrantCookieAccessDueToHeuristic(
|
||||
browser_context, top_frame_site, accessing_site, ttl, ignore_schemes);
|
||||
}
|
||||
|
||||
// TODO: crbug.com/369813097 - Move this implementation into
|
||||
// ChromeContentBrowserClient::GrantCookieAccessDueToHeuristic() after DIPS
|
||||
// migrates to //content.
|
||||
namespace dips_move {
|
||||
void GrantCookieAccessDueToHeuristic(content::BrowserContext* browser_context,
|
||||
const net::SchemefulSite& top_frame_site,
|
||||
const net::SchemefulSite& accessing_site,
|
||||
base::TimeDelta ttl,
|
||||
bool ignore_schemes) {
|
||||
scoped_refptr<content_settings::CookieSettings> cookie_settings =
|
||||
CookieSettingsFactory::GetForProfile(
|
||||
Profile::FromBrowserContext(browser_context));
|
||||
@ -3720,7 +3694,6 @@ void GrantCookieAccessDueToHeuristic(content::BrowserContext* browser_context,
|
||||
accessing_site.GetURL(), top_frame_site.GetURL(), ttl,
|
||||
/*use_schemeless_patterns=*/ignore_schemes);
|
||||
}
|
||||
} // namespace dips_move
|
||||
|
||||
#if BUILDFLAG(IS_CHROMEOS)
|
||||
void ChromeContentBrowserClient::OnTrustAnchorUsed(
|
||||
|
@ -1363,20 +1363,4 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
|
||||
base::WeakPtrFactory<ChromeContentBrowserClient> weak_factory_{this};
|
||||
};
|
||||
|
||||
// DO NOT USE. Functions in this namespace are only for the migration of DIPS to
|
||||
// the content/ folder. They will be deleted soon.
|
||||
//
|
||||
// TODO: crbug.com/369813097 - Remove this after DIPS migrates to //content.
|
||||
namespace dips_move {
|
||||
void GrantCookieAccessDueToHeuristic(content::BrowserContext* browser_context,
|
||||
const net::SchemefulSite& top_frame_site,
|
||||
const net::SchemefulSite& accessing_site,
|
||||
base::TimeDelta ttl,
|
||||
bool ignore_schemes);
|
||||
bool IsFullCookieAccessAllowed(content::BrowserContext* browser_context,
|
||||
content::WebContents* web_contents,
|
||||
const GURL& url,
|
||||
const blink::StorageKey& storage_key);
|
||||
} // namespace dips_move
|
||||
|
||||
#endif // CHROME_BROWSER_CHROME_CONTENT_BROWSER_CLIENT_H_
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include "chrome/browser/data_saver/data_saver.h"
|
||||
#include "chrome/browser/devtools/devtools_window.h"
|
||||
#include "chrome/browser/devtools/protocol/devtools_protocol_test_support.h"
|
||||
#include "chrome/browser/dips/dips_test_utils.h"
|
||||
#include "chrome/browser/extensions/extension_service.h"
|
||||
#include "chrome/browser/extensions/extension_util.h"
|
||||
#include "chrome/browser/extensions/unpacked_installer.h"
|
||||
@ -38,6 +37,7 @@
|
||||
#include "chrome/browser/privacy_sandbox/privacy_sandbox_attestations/privacy_sandbox_attestations_mixin.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/ssl/https_upgrades_util.h"
|
||||
#include "chrome/browser/tpcd/support/trial_test_utils.h"
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
#include "chrome/common/chrome_paths.h"
|
||||
#include "chrome/common/webui_url_constants.h"
|
||||
@ -53,12 +53,17 @@
|
||||
#include "components/infobars/core/infobar_delegate.h"
|
||||
#include "components/privacy_sandbox/privacy_sandbox_attestations/privacy_sandbox_attestations.h"
|
||||
#include "content/public/browser/devtools_agent_host.h"
|
||||
#include "content/public/browser/dips_redirect_info.h"
|
||||
#include "content/public/browser/dips_service.h"
|
||||
#include "content/public/browser/navigation_entry.h"
|
||||
#include "content/public/browser/page_navigator.h"
|
||||
#include "content/public/browser/ssl_status.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
#include "content/public/common/referrer.h"
|
||||
#include "content/public/test/browser_test.h"
|
||||
#include "content/public/test/browser_test_utils.h"
|
||||
#include "content/public/test/dips_service_test_utils.h"
|
||||
#include "content/public/test/preloading_test_util.h"
|
||||
#include "content/public/test/prerender_test_util.h"
|
||||
#include "extensions/browser/api/extensions_api_client.h"
|
||||
@ -81,6 +86,8 @@
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "third_party/blink/public/common/features.h"
|
||||
#include "third_party/boringssl/src/include/openssl/ssl.h"
|
||||
#include "ui/base/page_transition_types.h"
|
||||
#include "ui/base/window_open_disposition.h"
|
||||
#include "ui/gfx/codec/png_codec.h"
|
||||
#include "url/origin.h"
|
||||
|
||||
@ -563,6 +570,76 @@ class DevToolsProtocolTest_BounceTrackingMitigations
|
||||
base::test::ScopedFeatureList scoped_feature_list_;
|
||||
};
|
||||
|
||||
testing::AssertionResult SimulateDipsBounce(content::WebContents* web_contents,
|
||||
const GURL& initial_url,
|
||||
const GURL& bounce_url,
|
||||
const GURL& final_url) {
|
||||
web_contents = web_contents->OpenURL(
|
||||
content::OpenURLParams(initial_url, content::Referrer(),
|
||||
WindowOpenDisposition::NEW_FOREGROUND_TAB,
|
||||
ui::PageTransition::PAGE_TRANSITION_TYPED,
|
||||
/*is_renderer_initiated=*/false),
|
||||
{});
|
||||
if (!web_contents) {
|
||||
return testing::AssertionFailure() << "OpenURL() returned nullptr";
|
||||
}
|
||||
|
||||
if (!content::WaitForLoadStop(web_contents)) {
|
||||
return testing::AssertionFailure() << "Failed to wait for loading to stop";
|
||||
}
|
||||
|
||||
DIPSService* dips_service =
|
||||
DIPSService::Get(web_contents->GetBrowserContext());
|
||||
if (!content::NavigateToURLFromRenderer(web_contents, bounce_url)) {
|
||||
return testing::AssertionFailure()
|
||||
<< "Failed to navigate to " << bounce_url;
|
||||
}
|
||||
|
||||
tpcd::trial::URLCookieAccessObserver cookie_observer(
|
||||
web_contents, bounce_url, tpcd::trial::CookieOperation::kChange);
|
||||
testing::AssertionResult js_result =
|
||||
content::ExecJs(web_contents, "document.cookie = 'bounce=stateful';",
|
||||
content::EXECUTE_SCRIPT_NO_USER_GESTURE);
|
||||
if (!js_result) {
|
||||
return js_result;
|
||||
}
|
||||
cookie_observer.Wait();
|
||||
|
||||
content::DipsRedirectChainObserver final_observer(dips_service, final_url);
|
||||
if (!content::NavigateToURLFromRendererWithoutUserGesture(web_contents,
|
||||
final_url)) {
|
||||
return testing::AssertionFailure() << "Failed to navigate to " << final_url;
|
||||
}
|
||||
|
||||
// End redirect chain by closing the tab.
|
||||
web_contents->Close();
|
||||
final_observer.Wait();
|
||||
|
||||
if (testing::Test::HasFailure()) {
|
||||
return testing::AssertionFailure() << "Failure generated while waiting for "
|
||||
"the redirect chain to be reported";
|
||||
}
|
||||
|
||||
if (final_observer.redirects()->size() != 1) {
|
||||
return testing::AssertionFailure() << "Expected 1 redirect; found "
|
||||
<< final_observer.redirects()->size();
|
||||
}
|
||||
|
||||
const DIPSRedirectInfo& redirect = *final_observer.redirects()->at(0);
|
||||
if (redirect.url.url != bounce_url) {
|
||||
return testing::AssertionFailure() << "Expected redirect at " << bounce_url
|
||||
<< "; found " << redirect.url.url;
|
||||
}
|
||||
|
||||
if (redirect.access_type != DIPSDataAccessType::kWrite &&
|
||||
redirect.access_type != DIPSDataAccessType::kReadWrite) {
|
||||
return testing::AssertionFailure()
|
||||
<< "No write access recorded for redirect";
|
||||
}
|
||||
|
||||
return testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest_BounceTrackingMitigations,
|
||||
RunBounceTrackingMitigations) {
|
||||
SetBlockThirdPartyCookies(true);
|
||||
@ -577,8 +654,7 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest_BounceTrackingMitigations,
|
||||
// Record a stateful bounce for `bouncer`.
|
||||
ASSERT_TRUE(SimulateDipsBounce(
|
||||
web_contents(), embedded_test_server()->GetURL("a.test", "/empty.html"),
|
||||
bouncer, embedded_test_server()->GetURL("b.test", "/empty.html"),
|
||||
embedded_test_server()->GetURL("c.test", "/empty.html")));
|
||||
bouncer, embedded_test_server()->GetURL("b.test", "/empty.html")));
|
||||
|
||||
SendCommandSync("Storage.runBounceTrackingMitigations");
|
||||
|
||||
|
@ -3,13 +3,14 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/devtools/protocol/storage_handler.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "chrome/browser/devtools/protocol/storage.h"
|
||||
#include "chrome/browser/dips/dips_service.h"
|
||||
#include "chrome/browser/first_party_sets/first_party_sets_policy_service.h"
|
||||
#include "chrome/browser/first_party_sets/first_party_sets_policy_service_factory.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/dips_service.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "net/first_party_sets/first_party_set_entry.h"
|
||||
|
||||
@ -21,6 +22,7 @@ StorageHandler::StorageHandler(content::WebContents* web_contents,
|
||||
|
||||
StorageHandler::~StorageHandler() = default;
|
||||
|
||||
// TODO: crbug.com/380896828 - move CDP support for DIPS to //content.
|
||||
void StorageHandler::RunBounceTrackingMitigations(
|
||||
std::unique_ptr<RunBounceTrackingMitigationsCallback> callback) {
|
||||
DIPSService* dips_service =
|
||||
|
@ -4,87 +4,15 @@
|
||||
|
||||
source_set("unit_tests") {
|
||||
testonly = true
|
||||
sources = [
|
||||
"cookie_access_filter_unittest.cc",
|
||||
"dips_bounce_detector_unittest.cc",
|
||||
"dips_browser_signin_detector_unittest.cc",
|
||||
"dips_cleanup_service_unittest.cc",
|
||||
"dips_database_migrator_unittest.cc",
|
||||
"dips_database_unittest.cc",
|
||||
"dips_service_unittest.cc",
|
||||
"dips_storage_unittest.cc",
|
||||
"dips_utils_unittest.cc",
|
||||
"persistent_repeating_timer_unittest.cc",
|
||||
]
|
||||
sources = [ "dips_browser_signin_detector_unittest.cc" ]
|
||||
|
||||
deps = [
|
||||
":golden_dbs_bundle_data",
|
||||
"//base",
|
||||
"//base/test:test_support",
|
||||
"//chrome/browser",
|
||||
"//chrome/browser/browsing_data:constants",
|
||||
"//chrome/browser/content_settings",
|
||||
"//chrome/browser/content_settings:content_settings_factory",
|
||||
"//chrome/test:test_support",
|
||||
"//components/site_engagement/content",
|
||||
"//components/ukm:test_support",
|
||||
"//content/test:test_support",
|
||||
"//sql:test_support",
|
||||
"//testing/gtest",
|
||||
"//url",
|
||||
]
|
||||
|
||||
data = [ "//chrome/test/data/dips/v1.sql" ]
|
||||
}
|
||||
|
||||
bundle_data("golden_dbs_bundle_data") {
|
||||
visibility = [ ":unit_tests" ]
|
||||
testonly = true
|
||||
sources = [
|
||||
"//chrome/test/data/dips/v1.sql",
|
||||
"//chrome/test/data/dips/v2.sql",
|
||||
"//chrome/test/data/dips/v3.sql",
|
||||
"//chrome/test/data/dips/v4.sql",
|
||||
"//chrome/test/data/dips/v5.sql",
|
||||
]
|
||||
outputs = [ "{{bundle_resources_dir}}/" +
|
||||
"{{source_root_relative_dir}}/{{source_file_part}}" ]
|
||||
}
|
||||
|
||||
source_set("browser_tests") {
|
||||
testonly = true
|
||||
sources = [
|
||||
"dips_bounce_detector_browsertest.cc",
|
||||
"dips_helper_browsertest.cc",
|
||||
"dips_navigation_flow_detector_browsertest.cc",
|
||||
]
|
||||
|
||||
defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
|
||||
|
||||
deps = [
|
||||
"//base",
|
||||
"//base/test:test_support",
|
||||
"//chrome/browser",
|
||||
"//chrome/browser/browsing_data:constants",
|
||||
"//chrome/browser/content_settings",
|
||||
"//chrome/browser/content_settings:content_settings_factory",
|
||||
"//chrome/browser/ui",
|
||||
"//chrome/browser/ui/tabs:tabs_public",
|
||||
"//chrome/test:test_support",
|
||||
"//components/privacy_sandbox:tracking_protection_prefs",
|
||||
"//components/privacy_sandbox/privacy_sandbox_attestations",
|
||||
"//components/site_engagement/content:content",
|
||||
"//components/subresource_filter/core/common:test_support",
|
||||
"//components/ukm:test_support",
|
||||
"//content/test:test_support",
|
||||
"//device/fido:test_support",
|
||||
"//net:test_support",
|
||||
"//third_party/blink/public/common",
|
||||
]
|
||||
|
||||
if (is_android) {
|
||||
deps += [ "//chrome/test:test_support_ui_android" ]
|
||||
} else {
|
||||
deps += [ "//chrome/test:test_support_ui" ]
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
include_rules = [
|
||||
"+components/keyed_service",
|
||||
"+content/public/browser",
|
||||
"+content/public/test",
|
||||
"+net",
|
||||
]
|
||||
|
||||
specific_include_rules = {
|
||||
"dips_bounce_detector_browsertest\.cc": [
|
||||
"+device/fido/virtual_fido_device_factory.h",
|
||||
],
|
||||
"dips_navigation_flow_detector_browsertest\.cc": [
|
||||
"+device/fido/virtual_fido_device_factory.h",
|
||||
],
|
||||
}
|
@ -28,7 +28,7 @@ ProfileSelections GetHumanProfileSelections() {
|
||||
|
||||
} // namespace
|
||||
|
||||
static_assert(content::DipsDelegate::kDefaultRemoveMask ==
|
||||
static_assert(DIPSService::kDefaultRemoveMask ==
|
||||
(chrome_browsing_data_remover::FILTERABLE_DATA_TYPES &
|
||||
((content::BrowsingDataRemover::DATA_TYPE_CONTENT_END << 1) -
|
||||
1)),
|
||||
|
@ -10,12 +10,12 @@
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/strings/strcat.h"
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/dips/dips_service.h"
|
||||
#include "components/signin/public/identity_manager/account_info.h"
|
||||
#include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
|
||||
#include "components/signin/public/identity_manager/identity_manager.h"
|
||||
#include "components/signin/public/identity_manager/signin_constants.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/dips_service.h"
|
||||
|
||||
using signin::constants::kNoHostedDomainFound;
|
||||
|
||||
|
@ -6,11 +6,10 @@
|
||||
|
||||
#include "chrome/browser/dips/chrome_dips_delegate.h"
|
||||
#include "chrome/browser/dips/dips_browser_signin_detector.h"
|
||||
#include "chrome/browser/dips/dips_service.h"
|
||||
#include "chrome/browser/dips/dips_service_factory.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/signin/identity_manager_factory.h"
|
||||
#include "components/keyed_service/content/browser_context_dependency_manager.h"
|
||||
#include "content/public/browser/dips_service.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
|
||||
/*static*/
|
||||
@ -40,7 +39,6 @@ DIPSBrowserSigninDetectorFactory::DIPSBrowserSigninDetectorFactory(PassKey)
|
||||
: BrowserContextKeyedServiceFactory(
|
||||
"DIPSBrowserSigninDetector",
|
||||
BrowserContextDependencyManager::GetInstance()) {
|
||||
DependsOn(DIPSServiceFactory::GetInstance());
|
||||
DependsOn(IdentityManagerFactory::GetInstance());
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,6 @@
|
||||
#include "base/test/test_file_util.h"
|
||||
#include "base/test/test_future.h"
|
||||
#include "chrome/browser/dips/dips_browser_signin_detector_factory.h"
|
||||
#include "chrome/browser/dips/dips_service.h"
|
||||
#include "chrome/browser/dips/dips_test_utils.h"
|
||||
#include "chrome/browser/signin/chrome_signin_client_factory.h"
|
||||
#include "chrome/browser/signin/chrome_signin_client_test_util.h"
|
||||
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
|
||||
@ -29,6 +27,7 @@
|
||||
#include "components/signin/public/identity_manager/account_info.h"
|
||||
#include "components/signin/public/identity_manager/account_managed_status_finder.h"
|
||||
#include "components/signin/public/identity_manager/identity_test_environment.h"
|
||||
#include "content/public/browser/dips_service.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
#include "content/public/test/browser_task_environment.h"
|
||||
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
|
||||
@ -132,9 +131,6 @@ class BrowserSigninDetectorServiceTest : public testing::Test {
|
||||
base::StrCat({"foo@", kIdentityProviderDomain}), kIdentityProviderDomain};
|
||||
|
||||
private:
|
||||
ScopedInitFeature feature_{features::kDIPS,
|
||||
/*enable:*/ true,
|
||||
/*params:*/ {{"persist_database", "true"}}};
|
||||
network::TestURLLoaderFactory test_url_loader_factory_;
|
||||
std::unique_ptr<TestingProfile> profile_;
|
||||
std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
|
||||
|
@ -1,32 +0,0 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_cleanup_service.h"
|
||||
|
||||
#include "chrome/browser/dips/dips_cleanup_service_factory.h"
|
||||
#include "chrome/browser/dips/dips_storage.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
|
||||
DIPSCleanupService::DIPSCleanupService(content::BrowserContext* context) {
|
||||
DCHECK(!base::FeatureList::IsEnabled(features::kDIPS));
|
||||
DIPSStorage::DeleteDatabaseFiles(
|
||||
GetDIPSFilePath(context),
|
||||
base::BindOnce(&DIPSCleanupService::OnCleanupFinished,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
DIPSCleanupService::~DIPSCleanupService() = default;
|
||||
|
||||
/* static */
|
||||
DIPSCleanupService* DIPSCleanupService::Get(content::BrowserContext* context) {
|
||||
return DIPSCleanupServiceFactory::GetForBrowserContext(context);
|
||||
}
|
||||
|
||||
void DIPSCleanupService::WaitOnCleanupForTesting() {
|
||||
wait_for_cleanup_.Run();
|
||||
}
|
||||
|
||||
void DIPSCleanupService::OnCleanupFinished() {
|
||||
wait_for_cleanup_.Quit();
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_DIPS_DIPS_CLEANUP_SERVICE_H_
|
||||
#define CHROME_BROWSER_DIPS_DIPS_CLEANUP_SERVICE_H_
|
||||
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "components/keyed_service/core/keyed_service.h"
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
}
|
||||
|
||||
class DIPSCleanupService : public KeyedService {
|
||||
public:
|
||||
// Use DIPSCleanupServiceFactory::BuildServiceInstanceForBrowserContext
|
||||
// instead.
|
||||
explicit DIPSCleanupService(content::BrowserContext* context);
|
||||
~DIPSCleanupService() override;
|
||||
|
||||
static DIPSCleanupService* Get(content::BrowserContext* context);
|
||||
|
||||
void WaitOnCleanupForTesting();
|
||||
|
||||
private:
|
||||
void OnCleanupFinished();
|
||||
|
||||
base::RunLoop wait_for_cleanup_;
|
||||
base::WeakPtrFactory<DIPSCleanupService> weak_factory_{this};
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_DIPS_DIPS_CLEANUP_SERVICE_H_
|
@ -1,61 +0,0 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_cleanup_service_factory.h"
|
||||
|
||||
#include "base/no_destructor.h"
|
||||
#include "chrome/browser/dips/chrome_dips_delegate.h"
|
||||
#include "chrome/browser/dips/dips_cleanup_service.h"
|
||||
#include "components/keyed_service/content/browser_context_dependency_manager.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
|
||||
// static
|
||||
DIPSCleanupService* DIPSCleanupServiceFactory::GetForBrowserContext(
|
||||
content::BrowserContext* context) {
|
||||
return static_cast<DIPSCleanupService*>(
|
||||
GetInstance()->GetServiceForBrowserContext(context, /*create=*/true));
|
||||
}
|
||||
|
||||
DIPSCleanupServiceFactory* DIPSCleanupServiceFactory::GetInstance() {
|
||||
static base::NoDestructor<DIPSCleanupServiceFactory> instance;
|
||||
return instance.get();
|
||||
}
|
||||
|
||||
DIPSCleanupServiceFactory::DIPSCleanupServiceFactory()
|
||||
: BrowserContextKeyedServiceFactory(
|
||||
"DIPSCleanupService",
|
||||
BrowserContextDependencyManager::GetInstance()) {}
|
||||
|
||||
DIPSCleanupServiceFactory::~DIPSCleanupServiceFactory() = default;
|
||||
|
||||
content::BrowserContext* DIPSCleanupServiceFactory::GetBrowserContextToUse(
|
||||
content::BrowserContext* context) const {
|
||||
// Only enable when DIPS is turned off.
|
||||
if (base::FeatureList::IsEnabled(features::kDIPS)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Only enable for profiles where DIPS is normally enabled.
|
||||
if (!ChromeDipsDelegate::Create()->ShouldEnableDips(context)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Only enable for profiles where the DIPS DB is written to disk.
|
||||
if (context->IsOffTheRecord()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
std::unique_ptr<KeyedService>
|
||||
DIPSCleanupServiceFactory::BuildServiceInstanceForBrowserContext(
|
||||
content::BrowserContext* context) const {
|
||||
return std::make_unique<DIPSCleanupService>(context);
|
||||
}
|
||||
|
||||
bool DIPSCleanupServiceFactory::ServiceIsCreatedWithBrowserContext() const {
|
||||
return true;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_DIPS_DIPS_CLEANUP_SERVICE_FACTORY_H_
|
||||
#define CHROME_BROWSER_DIPS_DIPS_CLEANUP_SERVICE_FACTORY_H_
|
||||
|
||||
#include "base/no_destructor.h"
|
||||
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
}
|
||||
|
||||
class DIPSCleanupService;
|
||||
|
||||
class DIPSCleanupServiceFactory : public BrowserContextKeyedServiceFactory {
|
||||
public:
|
||||
static DIPSCleanupServiceFactory* GetInstance();
|
||||
static DIPSCleanupService* GetForBrowserContext(
|
||||
content::BrowserContext* context);
|
||||
|
||||
private:
|
||||
friend base::NoDestructor<DIPSCleanupServiceFactory>;
|
||||
|
||||
DIPSCleanupServiceFactory();
|
||||
~DIPSCleanupServiceFactory() override;
|
||||
|
||||
// BrowserContextKeyedServiceFactory:
|
||||
content::BrowserContext* GetBrowserContextToUse(
|
||||
content::BrowserContext* context) const override;
|
||||
std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
|
||||
content::BrowserContext* context) const override;
|
||||
bool ServiceIsCreatedWithBrowserContext() const override;
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_DIPS_DIPS_CLEANUP_SERVICE_FACTORY_H_
|
@ -1,81 +0,0 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_cleanup_service.h"
|
||||
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/test/test_file_util.h"
|
||||
#include "chrome/browser/dips/dips_service_impl.h"
|
||||
#include "chrome/browser/dips/dips_test_utils.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "chrome/test/base/testing_profile.h"
|
||||
#include "content/public/test/browser_task_environment.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
class DIPSCleanupServiceTest : public testing::Test {
|
||||
protected:
|
||||
void WaitOnStorage(DIPSServiceImpl* service) {
|
||||
service->storage()->FlushPostedTasksForTesting();
|
||||
}
|
||||
|
||||
private:
|
||||
content::BrowserTaskEnvironment task_environment_;
|
||||
};
|
||||
|
||||
TEST_F(DIPSCleanupServiceTest, DontCreateServiceIfFeatureEnabled) {
|
||||
ScopedInitDIPSFeature init_dips(true);
|
||||
|
||||
TestingProfile profile;
|
||||
EXPECT_EQ(DIPSCleanupService::Get(&profile), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(DIPSCleanupServiceTest, CreateServiceIfFeatureDisabled) {
|
||||
ScopedInitDIPSFeature init_dips(false);
|
||||
|
||||
TestingProfile profile;
|
||||
EXPECT_NE(DIPSCleanupService::Get(&profile), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(DIPSCleanupServiceTest, DeleteDbFilesIfFeatureDisabled) {
|
||||
base::FilePath data_path = base::CreateUniqueTempDirectoryScopedToTest();
|
||||
|
||||
{
|
||||
// Ensure the DIPS feature is enabled and the database is set to be
|
||||
// persisted.
|
||||
ScopedInitDIPSFeature enable_dips(true, {{"persist_database", "true"}});
|
||||
|
||||
std::unique_ptr<TestingProfile> profile =
|
||||
TestingProfile::Builder().SetPath(data_path).Build();
|
||||
|
||||
DIPSServiceImpl* dips_service = DIPSServiceImpl::Get(profile.get());
|
||||
ASSERT_NE(dips_service, nullptr);
|
||||
ASSERT_EQ(DIPSCleanupService::Get(profile.get()), nullptr);
|
||||
|
||||
WaitOnStorage(dips_service);
|
||||
dips_service->WaitForFileDeletionCompleteForTesting();
|
||||
|
||||
ASSERT_TRUE(base::PathExists(GetDIPSFilePath(profile.get())));
|
||||
}
|
||||
|
||||
// This should be equivalent to the DIPS db filepath in |data_path|.
|
||||
ASSERT_TRUE(base::PathExists(data_path.Append(kDIPSFilename)));
|
||||
|
||||
{
|
||||
// Disable the DIPS feature.
|
||||
ScopedInitDIPSFeature disable_dips(false);
|
||||
|
||||
std::unique_ptr<TestingProfile> profile =
|
||||
TestingProfile::Builder().SetPath(data_path).Build();
|
||||
|
||||
DIPSCleanupService* cleanup_service =
|
||||
DIPSCleanupService::Get(profile.get());
|
||||
ASSERT_NE(cleanup_service, nullptr);
|
||||
ASSERT_EQ(DIPSServiceImpl::Get(profile.get()), nullptr);
|
||||
|
||||
cleanup_service->WaitOnCleanupForTesting();
|
||||
EXPECT_FALSE(base::PathExists(GetDIPSFilePath(profile.get())));
|
||||
}
|
||||
}
|
156
chrome/browser/dips/dips_devtools_browsertest.cc
Normal file
156
chrome/browser/dips/dips_devtools_browsertest.cc
Normal file
@ -0,0 +1,156 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/values.h"
|
||||
#include "chrome/test/base/chrome_test_utils.h"
|
||||
#include "chrome/test/base/platform_browser_test.h"
|
||||
#include "content/public/browser/cookie_access_details.h"
|
||||
#include "content/public/browser/global_routing_id.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "content/public/test/browser_test.h"
|
||||
#include "content/public/test/browser_test_utils.h"
|
||||
#include "content/public/test/test_devtools_protocol_client.h"
|
||||
#include "net/dns/mock_host_resolver.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using CookieOperation = content::CookieAccessDetails::Type;
|
||||
|
||||
class FrameCookieAccessObserver : public content::WebContentsObserver {
|
||||
public:
|
||||
explicit FrameCookieAccessObserver(
|
||||
content::WebContents* web_contents,
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
CookieOperation access_type)
|
||||
: WebContentsObserver(web_contents),
|
||||
rfh_token_(render_frame_host->GetGlobalFrameToken()),
|
||||
access_type_(access_type) {}
|
||||
|
||||
// Wait until the frame accesses cookies.
|
||||
void Wait() { run_loop_.Run(); }
|
||||
|
||||
// WebContentsObserver override
|
||||
void OnCookiesAccessed(content::RenderFrameHost* render_frame_host,
|
||||
const content::CookieAccessDetails& details) override {
|
||||
if (details.type == access_type_ &&
|
||||
render_frame_host->GetGlobalFrameToken() == rfh_token_) {
|
||||
run_loop_.Quit();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const content::GlobalRenderFrameHostToken rfh_token_;
|
||||
const CookieOperation access_type_;
|
||||
base::RunLoop run_loop_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class DIPSBounceTrackingDevToolsIssueTest
|
||||
: public content::TestDevToolsProtocolClient,
|
||||
public PlatformBrowserTest {
|
||||
protected:
|
||||
void SetUpOnMainThread() override {
|
||||
PlatformBrowserTest::SetUpOnMainThread();
|
||||
host_resolver()->AddRule("*", "127.0.0.1");
|
||||
embedded_test_server()->AddDefaultHandlers(GetChromeTestDataDir());
|
||||
ASSERT_TRUE(embedded_test_server()->Start());
|
||||
}
|
||||
|
||||
void WaitForIssueAndCheckTrackingSites(
|
||||
const std::vector<std::string>& sites) {
|
||||
auto is_dips_issue = [](const base::Value::Dict& params) {
|
||||
return *(params.FindStringByDottedPath("issue.code")) ==
|
||||
"BounceTrackingIssue";
|
||||
};
|
||||
|
||||
// Wait for notification of a Bounce Tracking Issue.
|
||||
base::Value::Dict params = WaitForMatchingNotification(
|
||||
"Audits.issueAdded", base::BindRepeating(is_dips_issue));
|
||||
ASSERT_EQ(*params.FindStringByDottedPath("issue.code"),
|
||||
"BounceTrackingIssue");
|
||||
|
||||
base::Value::Dict* bounce_tracking_issue_details =
|
||||
params.FindDictByDottedPath("issue.details.bounceTrackingIssueDetails");
|
||||
ASSERT_TRUE(bounce_tracking_issue_details);
|
||||
|
||||
std::vector<std::string> tracking_sites;
|
||||
base::Value::List* tracking_sites_list =
|
||||
bounce_tracking_issue_details->FindList("trackingSites");
|
||||
if (tracking_sites_list) {
|
||||
for (const auto& val : *tracking_sites_list) {
|
||||
tracking_sites.push_back(val.GetString());
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the reported tracking sites match the expected sites.
|
||||
EXPECT_THAT(tracking_sites, testing::ElementsAreArray(sites));
|
||||
|
||||
// Clear existing notifications so subsequent calls don't fail by checking
|
||||
// `sites` against old notifications.
|
||||
ClearNotifications();
|
||||
}
|
||||
|
||||
void TearDownOnMainThread() override {
|
||||
DetachProtocolClient();
|
||||
PlatformBrowserTest::TearDownOnMainThread();
|
||||
}
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(DIPSBounceTrackingDevToolsIssueTest,
|
||||
BounceTrackingDevToolsIssue) {
|
||||
content::WebContents* web_contents =
|
||||
chrome_test_utils::GetActiveWebContents(this);
|
||||
|
||||
// Visit initial page on a.test.
|
||||
ASSERT_TRUE(content::NavigateToURL(
|
||||
web_contents, embedded_test_server()->GetURL("a.test", "/title1.html")));
|
||||
|
||||
// Open DevTools and enable Audit domain.
|
||||
AttachToWebContents(web_contents);
|
||||
SendCommandSync("Audits.enable");
|
||||
ClearNotifications();
|
||||
|
||||
// Navigate with a click (not a redirect) to b.test, which S-redirects to
|
||||
// c.test.
|
||||
ASSERT_TRUE(content::NavigateToURLFromRenderer(
|
||||
web_contents,
|
||||
embedded_test_server()->GetURL(
|
||||
"b.test", "/cross-site-with-cookie/c.test/title1.html"),
|
||||
embedded_test_server()->GetURL("c.test", "/title1.html")));
|
||||
WaitForIssueAndCheckTrackingSites({"b.test"});
|
||||
|
||||
// Write a cookie via JS on c.test.
|
||||
content::RenderFrameHost* frame = web_contents->GetPrimaryMainFrame();
|
||||
FrameCookieAccessObserver cookie_observer(web_contents, frame,
|
||||
CookieOperation::kChange);
|
||||
ASSERT_TRUE(content::ExecJs(frame, "document.cookie = 'foo=bar';",
|
||||
content::EXECUTE_SCRIPT_NO_USER_GESTURE));
|
||||
cookie_observer.Wait();
|
||||
|
||||
// Navigate without a click (i.e. by C-redirecting) to d.test.
|
||||
ASSERT_TRUE(content::NavigateToURLFromRendererWithoutUserGesture(
|
||||
web_contents, embedded_test_server()->GetURL("d.test", "/title1.html")));
|
||||
WaitForIssueAndCheckTrackingSites({"c.test"});
|
||||
|
||||
// Navigate without a click (i.e. by C-redirecting) to e.test, which
|
||||
// S-redirects to f.test, which S-redirects to g.test.
|
||||
ASSERT_TRUE(content::NavigateToURLFromRendererWithoutUserGesture(
|
||||
web_contents,
|
||||
embedded_test_server()->GetURL(
|
||||
"e.test",
|
||||
"/cross-site-with-cookie/f.test/cross-site-with-cookie/g.test/"
|
||||
"title1.html"),
|
||||
embedded_test_server()->GetURL("g.test", "/title1.html")));
|
||||
// Note d.test is not listed as a potentially tracking site since it did not
|
||||
// write cookies before bouncing the user.
|
||||
WaitForIssueAndCheckTrackingSites({"e.test", "f.test"});
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_DIPS_DIPS_SERVICE_H_
|
||||
#define CHROME_BROWSER_DIPS_DIPS_SERVICE_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/functional/callback_forward.h"
|
||||
#include "base/observer_list_types.h"
|
||||
#include "base/supports_user_data.h"
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/dips/dips_redirect_info.h"
|
||||
|
||||
class GURL;
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
class WebContents;
|
||||
} // namespace content
|
||||
|
||||
// When DIPS moves to //content, DIPSService will be exposed in the Content API,
|
||||
// available to embedders such as Chrome.
|
||||
class DIPSService : public base::SupportsUserData {
|
||||
public:
|
||||
using DeletedSitesCallback =
|
||||
base::OnceCallback<void(const std::vector<std::string>& sites)>;
|
||||
using CheckInteractionCallback = base::OnceCallback<void(bool)>;
|
||||
|
||||
class Observer : public base::CheckedObserver {
|
||||
public:
|
||||
virtual void OnStatefulBounce(content::WebContents* web_contents) {}
|
||||
virtual void OnChainHandled(const DIPSRedirectChainInfoPtr& chain) {}
|
||||
};
|
||||
|
||||
static DIPSService* Get(content::BrowserContext* context);
|
||||
|
||||
virtual void RecordBrowserSignIn(std::string_view domain) = 0;
|
||||
|
||||
virtual void DeleteEligibleSitesImmediately(
|
||||
DeletedSitesCallback callback) = 0;
|
||||
|
||||
virtual void RecordInteractionForTesting(const GURL& url) = 0;
|
||||
|
||||
virtual void DidSiteHaveInteractionSince(
|
||||
const GURL& url,
|
||||
base::Time bound,
|
||||
CheckInteractionCallback callback) const = 0;
|
||||
|
||||
virtual void AddObserver(Observer* observer) = 0;
|
||||
virtual void RemoveObserver(const Observer* observer) = 0;
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_DIPS_DIPS_SERVICE_H_
|
@ -1,54 +0,0 @@
|
||||
// Copyright 2022 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_service_factory.h"
|
||||
|
||||
#include "base/no_destructor.h"
|
||||
#include "chrome/browser/dips/chrome_dips_delegate.h"
|
||||
#include "chrome/browser/dips/dips_service_impl.h"
|
||||
#include "components/keyed_service/content/browser_context_dependency_manager.h"
|
||||
|
||||
using PassKey = base::PassKey<DIPSServiceFactory>;
|
||||
|
||||
/* static */
|
||||
DIPSServiceImpl* DIPSServiceFactory::GetForBrowserContext(
|
||||
content::BrowserContext* context) {
|
||||
auto* dips_service = static_cast<DIPSServiceImpl*>(
|
||||
GetInstance()->GetServiceForBrowserContext(context, /*create=*/true));
|
||||
if (dips_service) {
|
||||
dips_service->MaybeNotifyCreated(PassKey());
|
||||
}
|
||||
return dips_service;
|
||||
}
|
||||
|
||||
DIPSServiceFactory* DIPSServiceFactory::GetInstance() {
|
||||
static base::NoDestructor<DIPSServiceFactory> instance;
|
||||
return instance.get();
|
||||
}
|
||||
|
||||
DIPSServiceFactory::DIPSServiceFactory()
|
||||
: BrowserContextKeyedServiceFactory(
|
||||
"DIPSServiceImpl",
|
||||
BrowserContextDependencyManager::GetInstance()) {}
|
||||
|
||||
DIPSServiceFactory::~DIPSServiceFactory() = default;
|
||||
|
||||
content::BrowserContext* DIPSServiceFactory::GetBrowserContextToUse(
|
||||
content::BrowserContext* context) const {
|
||||
if (!base::FeatureList::IsEnabled(features::kDIPS)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!ChromeDipsDelegate::Create()->ShouldEnableDips(context)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
std::unique_ptr<KeyedService>
|
||||
DIPSServiceFactory::BuildServiceInstanceForBrowserContext(
|
||||
content::BrowserContext* context) const {
|
||||
return std::make_unique<DIPSServiceImpl>(PassKey(), context);
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
// Copyright 2022 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_DIPS_DIPS_SERVICE_FACTORY_H_
|
||||
#define CHROME_BROWSER_DIPS_DIPS_SERVICE_FACTORY_H_
|
||||
|
||||
#include "base/no_destructor.h"
|
||||
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
}
|
||||
|
||||
class DIPSServiceImpl;
|
||||
|
||||
class DIPSServiceFactory : public BrowserContextKeyedServiceFactory {
|
||||
public:
|
||||
static DIPSServiceFactory* GetInstance();
|
||||
static DIPSServiceImpl* GetForBrowserContext(
|
||||
content::BrowserContext* context);
|
||||
|
||||
private:
|
||||
friend base::NoDestructor<DIPSServiceFactory>;
|
||||
|
||||
DIPSServiceFactory();
|
||||
~DIPSServiceFactory() override;
|
||||
|
||||
// BrowserContextKeyedServiceFactory:
|
||||
content::BrowserContext* GetBrowserContextToUse(
|
||||
content::BrowserContext* context) const override;
|
||||
std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
|
||||
content::BrowserContext* context) const override;
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_DIPS_DIPS_SERVICE_FACTORY_H_
|
@ -6,8 +6,8 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "chrome/browser/dips/dips_bounce_detector.h"
|
||||
#include "components/content_settings/browser/page_specific_content_settings.h"
|
||||
#include "content/public/browser/dips_service.h"
|
||||
#include "content/public/browser/web_contents_user_data.h"
|
||||
|
||||
namespace dips {
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/supports_user_data.h"
|
||||
#include "base/types/pass_key.h"
|
||||
#include "chrome/browser/dips/dips_service.h"
|
||||
#include "content/public/browser/dips_service.h"
|
||||
|
||||
namespace dips {
|
||||
|
||||
|
@ -52,8 +52,6 @@
|
||||
#include "chrome/browser/device_api/managed_configuration_api_factory.h"
|
||||
#include "chrome/browser/device_reauth/chrome_device_authenticator_factory.h"
|
||||
#include "chrome/browser/dips/dips_browser_signin_detector_factory.h"
|
||||
#include "chrome/browser/dips/dips_cleanup_service_factory.h"
|
||||
#include "chrome/browser/dips/dips_service_factory.h"
|
||||
#include "chrome/browser/dom_distiller/dom_distiller_service_factory.h"
|
||||
#include "chrome/browser/domain_reliability/service_factory.h"
|
||||
#include "chrome/browser/download/background_download_service_factory.h"
|
||||
@ -814,8 +812,6 @@ void ChromeBrowserMainExtraPartsProfiles::
|
||||
DiceWebSigninInterceptorFactory::GetInstance();
|
||||
#endif
|
||||
DIPSBrowserSigninDetectorFactory::GetInstance();
|
||||
DIPSCleanupServiceFactory::GetInstance();
|
||||
DIPSServiceFactory::GetInstance();
|
||||
DocumentSuggestionsServiceFactory::GetInstance();
|
||||
dom_distiller::DomDistillerServiceFactory::GetInstance();
|
||||
DomainDiversityReporterFactory::GetInstance();
|
||||
|
@ -447,7 +447,6 @@ IN_PROC_BROWSER_TEST_F(ProfileKeyedServiceGuestBrowserTest,
|
||||
"ConnectorsService",
|
||||
"CupsPrintersManagerFactory",
|
||||
"DIPSBrowserSigninDetector",
|
||||
"DIPSServiceImpl",
|
||||
"DataControlsRulesService",
|
||||
"DownloadCoreService",
|
||||
"EnterpriseManagementService",
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/content_settings/cookie_settings_factory.h"
|
||||
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
|
||||
#include "chrome/browser/dips/dips_service.h"
|
||||
#include "chrome/browser/first_party_sets/first_party_sets_policy_service.h"
|
||||
#include "chrome/browser/first_party_sets/first_party_sets_policy_service_factory.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
@ -35,6 +34,7 @@
|
||||
#include "components/permissions/permission_request_id.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/dips_service.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/runtime_feature_state/runtime_feature_state_document_data.h"
|
||||
#include "content/public/browser/storage_partition.h"
|
||||
|
@ -16,8 +16,6 @@
|
||||
#include "base/version.h"
|
||||
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
|
||||
#include "chrome/browser/content_settings/page_specific_content_settings_delegate.h"
|
||||
#include "chrome/browser/dips/dips_bounce_detector.h"
|
||||
#include "chrome/browser/dips/dips_service.h"
|
||||
#include "chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.h"
|
||||
#include "chrome/browser/webid/federated_identity_permission_context.h"
|
||||
#include "chrome/browser/webid/federated_identity_permission_context_factory.h"
|
||||
@ -37,6 +35,7 @@
|
||||
#include "components/permissions/permission_util.h"
|
||||
#include "components/permissions/test/mock_permission_prompt_factory.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "content/public/browser/dips_service.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
#include "content/public/test/browser_test_utils.h"
|
||||
|
@ -110,57 +110,4 @@ const base::FeatureParam<bool> kExcludePwaOrTwaInstalled{
|
||||
/*default_value=*/true};
|
||||
#endif
|
||||
|
||||
const char kTpcdWritePopupCurrentInteractionHeuristicsGrantsName[] =
|
||||
"TpcdWritePopupCurrentInteractionHeuristicsGrants";
|
||||
const char kTpcdWritePopupPastInteractionHeuristicsGrantsName[] =
|
||||
"TpcdWritePopupPastInteractionHeuristicsGrants";
|
||||
const char kTpcdBackfillPopupHeuristicsGrantsName[] =
|
||||
"TpcdBackfillPopupHeuristicsGrants";
|
||||
const char kTpcdPopupHeuristicDisableForAdTaggedPopupsName[] =
|
||||
"TpcdPopupHeuristicDisableForAdTaggedPopups";
|
||||
const char kTpcdPopupHeuristicEnableForIframeInitiatorName[] =
|
||||
"TpcdPopupHeuristicEnableForIframeInitiator";
|
||||
const char kTpcdWriteRedirectHeuristicGrantsName[] =
|
||||
"TpcdWriteRedirectHeuristicGrants";
|
||||
const char kTpcdRedirectHeuristicRequireABAFlowName[] =
|
||||
"TpcdRedirectHeuristicRequireABAFlow";
|
||||
const char kTpcdRedirectHeuristicRequireCurrentInteractionName[] =
|
||||
"TpcdRedirectHeuristicRequireCurrentInteraction";
|
||||
|
||||
const base::FeatureParam<base::TimeDelta>
|
||||
kTpcdWritePopupCurrentInteractionHeuristicsGrants{
|
||||
&content_settings::features::kTpcdHeuristicsGrants,
|
||||
kTpcdWritePopupCurrentInteractionHeuristicsGrantsName, base::Days(30)};
|
||||
|
||||
const base::FeatureParam<base::TimeDelta>
|
||||
kTpcdWritePopupPastInteractionHeuristicsGrants{
|
||||
&content_settings::features::kTpcdHeuristicsGrants,
|
||||
kTpcdWritePopupPastInteractionHeuristicsGrantsName, base::TimeDelta()};
|
||||
|
||||
const base::FeatureParam<base::TimeDelta> kTpcdBackfillPopupHeuristicsGrants{
|
||||
&content_settings::features::kTpcdHeuristicsGrants,
|
||||
kTpcdBackfillPopupHeuristicsGrantsName, base::Days(30)};
|
||||
|
||||
const base::FeatureParam<bool> kTpcdPopupHeuristicDisableForAdTaggedPopups{
|
||||
&content_settings::features::kTpcdHeuristicsGrants,
|
||||
kTpcdPopupHeuristicDisableForAdTaggedPopupsName, false};
|
||||
|
||||
const base::FeatureParam<EnableForIframeTypes>
|
||||
kTpcdPopupHeuristicEnableForIframeInitiator{
|
||||
&content_settings::features::kTpcdHeuristicsGrants,
|
||||
kTpcdPopupHeuristicEnableForIframeInitiatorName,
|
||||
EnableForIframeTypes::kAll, &kEnableForIframeTypesOptions};
|
||||
|
||||
const base::FeatureParam<base::TimeDelta> kTpcdWriteRedirectHeuristicGrants{
|
||||
&content_settings::features::kTpcdHeuristicsGrants,
|
||||
kTpcdWriteRedirectHeuristicGrantsName, base::Minutes(15)};
|
||||
|
||||
const base::FeatureParam<bool> kTpcdRedirectHeuristicRequireABAFlow{
|
||||
&content_settings::features::kTpcdHeuristicsGrants,
|
||||
kTpcdRedirectHeuristicRequireABAFlowName, true};
|
||||
|
||||
const base::FeatureParam<bool> kTpcdRedirectHeuristicRequireCurrentInteraction{
|
||||
&content_settings::features::kTpcdHeuristicsGrants,
|
||||
kTpcdRedirectHeuristicRequireCurrentInteractionName, true};
|
||||
|
||||
} // namespace tpcd::experiment
|
||||
|
@ -57,72 +57,6 @@ extern const base::FeatureParam<base::TimeDelta> kInstallTimeForNewUser;
|
||||
extern const base::FeatureParam<bool> kExcludePwaOrTwaInstalled;
|
||||
#endif
|
||||
|
||||
extern const char kTpcdWritePopupCurrentInteractionHeuristicsGrantsName[];
|
||||
extern const char kTpcdWritePopupPastInteractionHeuristicsGrantsName[];
|
||||
extern const char kTpcdBackfillPopupHeuristicsGrantsName[];
|
||||
extern const char kTpcdPopupHeuristicDisableForAdTaggedPopupsName[];
|
||||
extern const char kTpcdPopupHeuristicEnableForIframeInitiatorName[];
|
||||
extern const char kTpcdWriteRedirectHeuristicGrantsName[];
|
||||
extern const char kTpcdRedirectHeuristicRequireABAFlowName[];
|
||||
extern const char kTpcdRedirectHeuristicRequireCurrentInteractionName[];
|
||||
|
||||
// The duration of the storage access grant created when observing the Popup
|
||||
// With Current Interaction scenario. If set to zero duration, do not create a
|
||||
// grant.
|
||||
extern const base::FeatureParam<base::TimeDelta>
|
||||
kTpcdWritePopupCurrentInteractionHeuristicsGrants;
|
||||
|
||||
// The duration of the storage access grant created when observing the Popup
|
||||
// With Past Interaction scenario. If set to zero duration, do not create a
|
||||
// grant.
|
||||
extern const base::FeatureParam<base::TimeDelta>
|
||||
kTpcdWritePopupPastInteractionHeuristicsGrants;
|
||||
|
||||
// The lookback and duration of the storage access grants created when
|
||||
// backfilling the Popup With Current Interaction scenario on onboarding to
|
||||
// 3PCD. If set to zero duration, to not create backfill grants.
|
||||
extern const base::FeatureParam<base::TimeDelta>
|
||||
kTpcdBackfillPopupHeuristicsGrants;
|
||||
|
||||
// Whether to disable writing Popup heuristic grants when the popup is opened
|
||||
// via an ad-tagged frame.
|
||||
extern const base::FeatureParam<bool>
|
||||
kTpcdPopupHeuristicDisableForAdTaggedPopups;
|
||||
|
||||
enum class EnableForIframeTypes { kNone = 0, kFirstParty = 1, kAll = 2 };
|
||||
|
||||
// Whether to enable writing Popup heuristic grants when the popup is opened via
|
||||
// an iframe initiator.
|
||||
|
||||
// * kNone: Ignore popups initiated from iframes.
|
||||
// * kFirstPartyIframes: Only write grants for popups initiated from 1P iframes,
|
||||
// or nested tree of all 1P iframes.
|
||||
// * kAllIframes: Write grants for popups initiated from any frame.
|
||||
constexpr base::FeatureParam<EnableForIframeTypes>::Option
|
||||
kEnableForIframeTypesOptions[] = {
|
||||
{EnableForIframeTypes::kNone, "none"},
|
||||
{EnableForIframeTypes::kFirstParty, "first-party"},
|
||||
{EnableForIframeTypes::kAll, "all"},
|
||||
};
|
||||
extern const base::FeatureParam<EnableForIframeTypes>
|
||||
kTpcdPopupHeuristicEnableForIframeInitiator;
|
||||
|
||||
// The duration of the storage access grant created when observing the Redirect
|
||||
// With Current Interaction scenario. If set to zero duration, do not create a
|
||||
// grant.
|
||||
extern const base::FeatureParam<base::TimeDelta>
|
||||
kTpcdWriteRedirectHeuristicGrants;
|
||||
|
||||
// Whether to require an A-B-A flow (where the first party preceded the
|
||||
// third-party redirect in the tab history) when applying the Redirect
|
||||
// heuristic.
|
||||
extern const base::FeatureParam<bool> kTpcdRedirectHeuristicRequireABAFlow;
|
||||
|
||||
// Whether to require the third-party interaction to be in the current
|
||||
// navigation when applying the Redirect heuristic.
|
||||
extern const base::FeatureParam<bool>
|
||||
kTpcdRedirectHeuristicRequireCurrentInteraction;
|
||||
|
||||
} // namespace tpcd::experiment
|
||||
|
||||
#endif // CHROME_BROWSER_TPCD_EXPERIMENT_TPCD_EXPERIMENT_FEATURES_H_
|
||||
|
@ -1,14 +0,0 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_TPCD_HEURISTICS_OPENER_HEURISTIC_METRICS_H_
|
||||
#define CHROME_BROWSER_TPCD_HEURISTICS_OPENER_HEURISTIC_METRICS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Bucketize `sample` into 50 buckets, capped at maximum and distributed
|
||||
// non-linearly similarly to base::Histogram::InitializeBucketRanges.
|
||||
int32_t Bucketize3PCDHeuristicSample(int64_t sample, int64_t maximum);
|
||||
|
||||
#endif // CHROME_BROWSER_TPCD_HEURISTICS_OPENER_HEURISTIC_METRICS_H_
|
@ -4,13 +4,11 @@
|
||||
|
||||
#include "chrome/browser/tpcd/heuristics/opener_heuristic_service.h"
|
||||
|
||||
#include "chrome/browser/chrome_content_browser_client.h"
|
||||
#include "chrome/browser/dips/dips_service_impl.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "chrome/browser/privacy_sandbox/tracking_protection_settings_factory.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/tpcd/experiment/tpcd_experiment_features.h"
|
||||
#include "chrome/browser/tpcd/heuristics/opener_heuristic_service_factory.h"
|
||||
#include "components/content_settings/core/common/features.h"
|
||||
#include "components/privacy_sandbox/tracking_protection_settings.h"
|
||||
#include "url/origin.h"
|
||||
|
||||
@ -18,7 +16,6 @@ OpenerHeuristicService::OpenerHeuristicService(
|
||||
base::PassKey<OpenerHeuristicServiceFactory>,
|
||||
content::BrowserContext* context)
|
||||
: browser_context_(context),
|
||||
dips_(DIPSServiceImpl::Get(context)),
|
||||
tracking_protection_settings_(
|
||||
TrackingProtectionSettingsFactory::GetForProfile(
|
||||
Profile::FromBrowserContext(context))) {
|
||||
@ -37,65 +34,32 @@ OpenerHeuristicService* OpenerHeuristicService::Get(
|
||||
}
|
||||
|
||||
void OpenerHeuristicService::Shutdown() {
|
||||
dips_ = nullptr;
|
||||
tracking_protection_settings_ = nullptr;
|
||||
tracking_protection_settings_observation_.Reset();
|
||||
}
|
||||
|
||||
void OpenerHeuristicService::OnTrackingProtection3pcdChanged() {
|
||||
if (IsShuttingDown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!base::FeatureList::IsEnabled(
|
||||
content_settings::features::kTpcdHeuristicsGrants) ||
|
||||
!tpcd::experiment::kTpcdBackfillPopupHeuristicsGrants.Get()
|
||||
.is_positive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tracking_protection_settings_ ||
|
||||
!tracking_protection_settings_->IsTrackingProtection3pcdEnabled()) {
|
||||
NotifyBackfillPopupHeuristicGrants(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: crbug.com/1502264 - ensure backfill is completed if interrupted
|
||||
dips_->storage()
|
||||
->AsyncCall(&DIPSStorage::ReadRecentPopupsWithInteraction)
|
||||
.WithArgs(tpcd::experiment::kTpcdBackfillPopupHeuristicsGrants.Get())
|
||||
.Then(
|
||||
base::BindOnce(&OpenerHeuristicService::BackfillPopupHeuristicGrants,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
browser_context_->BackfillPopupHeuristicGrants(base::BindOnce(
|
||||
&OpenerHeuristicService::NotifyBackfillPopupHeuristicGrants,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void OpenerHeuristicService::BackfillPopupHeuristicGrants(
|
||||
std::vector<PopupWithTime> recent_popups) {
|
||||
if (IsShuttingDown()) {
|
||||
return;
|
||||
}
|
||||
void OpenerHeuristicService::AddObserver(Observer* observer) {
|
||||
observers_.AddObserver(observer);
|
||||
}
|
||||
|
||||
for (const auto& popup : recent_popups) {
|
||||
base::TimeDelta grant_duration =
|
||||
tpcd::experiment::kTpcdBackfillPopupHeuristicsGrants.Get() -
|
||||
(base::Time::Now() - popup.last_popup_time);
|
||||
if (!grant_duration.is_positive()) {
|
||||
continue;
|
||||
}
|
||||
void OpenerHeuristicService::RemoveObserver(Observer* observer) {
|
||||
observers_.RemoveObserver(observer);
|
||||
}
|
||||
|
||||
// `popup_site` and `opener_site` were read from the DIPS database,
|
||||
// and were originally computed by calling GetSiteForDIPS().
|
||||
// GrantCookieAccessDueToHeuristic() takes SchemefulSites, so we create some
|
||||
// here, but since we pass ignore_schemes=true the scheme doesn't matter
|
||||
// (and port never matters for SchemefulSites), so we hardcode http and 80.
|
||||
net::SchemefulSite popup_site(
|
||||
url::Origin::CreateFromNormalizedTuple("http", popup.popup_site, 80));
|
||||
net::SchemefulSite opener_site(
|
||||
url::Origin::CreateFromNormalizedTuple("http", popup.opener_site, 80));
|
||||
|
||||
// TODO: crbug.com/40883201 - When we move to //content, we will call
|
||||
// this via ContentBrowserClient instead of as a standalone function.
|
||||
dips_move::GrantCookieAccessDueToHeuristic(browser_context_, opener_site,
|
||||
popup_site, grant_duration,
|
||||
/*ignore_schemes=*/true);
|
||||
void OpenerHeuristicService::NotifyBackfillPopupHeuristicGrants(bool success) {
|
||||
for (auto& observer : observers_) {
|
||||
observer.OnBackfillPopupHeuristicGrants(browser_context_.get(), success);
|
||||
}
|
||||
}
|
||||
|
@ -5,12 +5,11 @@
|
||||
#ifndef CHROME_BROWSER_TPCD_HEURISTICS_OPENER_HEURISTIC_SERVICE_H_
|
||||
#define CHROME_BROWSER_TPCD_HEURISTICS_OPENER_HEURISTIC_SERVICE_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "base/observer_list_types.h"
|
||||
#include "base/scoped_observation.h"
|
||||
#include "base/types/pass_key.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "components/keyed_service/core/keyed_service.h"
|
||||
#include "components/privacy_sandbox/tracking_protection_settings_observer.h"
|
||||
|
||||
@ -22,37 +21,44 @@ namespace privacy_sandbox {
|
||||
class TrackingProtectionSettings;
|
||||
}
|
||||
|
||||
class DIPSServiceImpl;
|
||||
class OpenerHeuristicServiceFactory;
|
||||
|
||||
class OpenerHeuristicService
|
||||
: public KeyedService,
|
||||
privacy_sandbox::TrackingProtectionSettingsObserver {
|
||||
public:
|
||||
class Observer : public base::CheckedObserver {
|
||||
public:
|
||||
virtual void OnBackfillPopupHeuristicGrants(
|
||||
content::BrowserContext* browser_context,
|
||||
bool success) = 0;
|
||||
};
|
||||
|
||||
OpenerHeuristicService(base::PassKey<OpenerHeuristicServiceFactory>,
|
||||
content::BrowserContext* context);
|
||||
~OpenerHeuristicService() override;
|
||||
|
||||
static OpenerHeuristicService* Get(content::BrowserContext* context);
|
||||
|
||||
void AddObserver(Observer* observer);
|
||||
void RemoveObserver(Observer* observer);
|
||||
|
||||
private:
|
||||
// KeyedService overrides:
|
||||
void Shutdown() override;
|
||||
|
||||
bool IsShuttingDown() const { return !dips_; }
|
||||
// Create backfill storage access grants for the provided recent popups.
|
||||
void BackfillPopupHeuristicGrants(std::vector<PopupWithTime> recent_popups);
|
||||
|
||||
// TrackingProtectionSettingsObserver overrides:
|
||||
void OnTrackingProtection3pcdChanged() override;
|
||||
|
||||
void NotifyBackfillPopupHeuristicGrants(bool success);
|
||||
|
||||
raw_ptr<content::BrowserContext> browser_context_;
|
||||
raw_ptr<DIPSServiceImpl> dips_;
|
||||
raw_ptr<privacy_sandbox::TrackingProtectionSettings>
|
||||
tracking_protection_settings_;
|
||||
base::ScopedObservation<privacy_sandbox::TrackingProtectionSettings,
|
||||
privacy_sandbox::TrackingProtectionSettingsObserver>
|
||||
tracking_protection_settings_observation_{this};
|
||||
base::ObserverList<Observer, /*check_empty=*/true> observers_;
|
||||
|
||||
base::WeakPtrFactory<OpenerHeuristicService> weak_factory_{this};
|
||||
};
|
||||
|
@ -0,0 +1,84 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/tpcd/heuristics/opener_heuristic_service.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "base/run_loop.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/test/base/chrome_test_utils.h"
|
||||
#include "chrome/test/base/in_process_browser_test.h"
|
||||
#include "chrome/test/base/platform_browser_test.h"
|
||||
#include "components/content_settings/core/common/features.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "components/privacy_sandbox/tracking_protection_prefs.h"
|
||||
#include "content/public/test/browser_test.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
class OpenerHeuristicServiceTest : public PlatformBrowserTest,
|
||||
public testing::WithParamInterface<bool> {
|
||||
public:
|
||||
void SetUp() override {
|
||||
feature_list_.InitWithFeaturesAndParameters(
|
||||
{{content_settings::features::kTpcdHeuristicsGrants,
|
||||
base::FieldTrialParams{{"TpcdBackfillPopupHeuristicsGrants",
|
||||
backfill_enabled() ? "1us" : "0"}}}},
|
||||
// Disable the tracking protection feature so that its pref takes
|
||||
// precedence.
|
||||
{content_settings::features::kTrackingProtection3pcd});
|
||||
PlatformBrowserTest::SetUp();
|
||||
}
|
||||
|
||||
bool backfill_enabled() const { return GetParam(); }
|
||||
|
||||
private:
|
||||
base::test::ScopedFeatureList feature_list_;
|
||||
};
|
||||
|
||||
class BackfillObserver : public OpenerHeuristicService::Observer {
|
||||
public:
|
||||
explicit BackfillObserver(OpenerHeuristicService* service) {
|
||||
observation_.Observe(service);
|
||||
}
|
||||
|
||||
std::optional<bool> status() const { return status_; }
|
||||
|
||||
void Wait() { run_loop_.Run(); }
|
||||
|
||||
private:
|
||||
void OnBackfillPopupHeuristicGrants(content::BrowserContext* browser_context,
|
||||
bool success) override {
|
||||
status_ = success;
|
||||
run_loop_.Quit();
|
||||
}
|
||||
|
||||
base::RunLoop run_loop_;
|
||||
std::optional<bool> status_;
|
||||
base::ScopedObservation<OpenerHeuristicService,
|
||||
OpenerHeuristicService::Observer>
|
||||
observation_{this};
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_P(OpenerHeuristicServiceTest,
|
||||
BackfillWhenTrackingProtection3pcdEnabled) {
|
||||
Profile* profile = chrome_test_utils::GetProfile(this);
|
||||
BackfillObserver observer(OpenerHeuristicService::Get(profile));
|
||||
profile->GetPrefs()->SetBoolean(prefs::kTrackingProtection3pcdEnabled, true);
|
||||
observer.Wait();
|
||||
ASSERT_EQ(observer.status(), backfill_enabled());
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_P(OpenerHeuristicServiceTest,
|
||||
DontRequestBackfillWhenTrackingProtection3pcdDisabled) {
|
||||
Profile* profile = chrome_test_utils::GetProfile(this);
|
||||
BackfillObserver observer(OpenerHeuristicService::Get(profile));
|
||||
profile->GetPrefs()->SetBoolean(prefs::kTrackingProtection3pcdEnabled, false);
|
||||
observer.Wait();
|
||||
ASSERT_THAT(observer.status(), testing::Optional(false));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(All, OpenerHeuristicServiceTest, testing::Bool());
|
@ -7,8 +7,6 @@
|
||||
#include "base/no_destructor.h"
|
||||
#include "base/types/pass_key.h"
|
||||
#include "chrome/browser/dips/chrome_dips_delegate.h"
|
||||
#include "chrome/browser/dips/dips_service_factory.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "chrome/browser/privacy_sandbox/tracking_protection_settings_factory.h"
|
||||
#include "chrome/browser/tpcd/heuristics/opener_heuristic_service.h"
|
||||
#include "components/content_settings/core/common/features.h"
|
||||
@ -30,7 +28,6 @@ OpenerHeuristicServiceFactory::OpenerHeuristicServiceFactory()
|
||||
: BrowserContextKeyedServiceFactory(
|
||||
"OpenerHeuristicService",
|
||||
BrowserContextDependencyManager::GetInstance()) {
|
||||
DependsOn(DIPSServiceFactory::GetInstance());
|
||||
DependsOn(TrackingProtectionSettingsFactory::GetInstance());
|
||||
}
|
||||
|
||||
|
@ -1,17 +0,0 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_TPCD_HEURISTICS_OPENER_HEURISTIC_UTILS_H_
|
||||
#define CHROME_BROWSER_TPCD_HEURISTICS_OPENER_HEURISTIC_UTILS_H_
|
||||
|
||||
class GURL;
|
||||
|
||||
enum class PopupProvider {
|
||||
kUnknown = 0,
|
||||
kGoogle = 1,
|
||||
};
|
||||
|
||||
PopupProvider GetPopupProvider(const GURL& popup_url);
|
||||
|
||||
#endif // CHROME_BROWSER_TPCD_HEURISTICS_OPENER_HEURISTIC_UTILS_H_
|
@ -8,7 +8,6 @@
|
||||
#include "base/values.h"
|
||||
#include "chrome/browser/content_settings/cookie_settings_factory.h"
|
||||
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
|
||||
#include "chrome/browser/dips/dips_test_utils.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/subresource_filter/subresource_filter_browser_test_harness.h"
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
@ -34,6 +33,93 @@ namespace {
|
||||
|
||||
using ::chrome_test_utils::GetActiveWebContents;
|
||||
|
||||
class URLCookieAccessObserver : public content::WebContentsObserver {
|
||||
public:
|
||||
URLCookieAccessObserver(content::WebContents* web_contents,
|
||||
GURL url,
|
||||
content::CookieAccessDetails::Type access_type);
|
||||
|
||||
void Wait();
|
||||
|
||||
private:
|
||||
// WebContentsObserver overrides
|
||||
void OnCookiesAccessed(content::RenderFrameHost* render_frame_host,
|
||||
const content::CookieAccessDetails& details) override;
|
||||
void OnCookiesAccessed(content::NavigationHandle* navigation_handle,
|
||||
const content::CookieAccessDetails& details) override;
|
||||
|
||||
GURL url_;
|
||||
content::CookieAccessDetails::Type access_type_;
|
||||
base::RunLoop run_loop_;
|
||||
};
|
||||
|
||||
URLCookieAccessObserver::URLCookieAccessObserver(
|
||||
content::WebContents* web_contents,
|
||||
GURL url,
|
||||
content::CookieAccessDetails::Type access_type)
|
||||
: WebContentsObserver(web_contents),
|
||||
url_(std::move(url)),
|
||||
access_type_(access_type) {}
|
||||
|
||||
void URLCookieAccessObserver::Wait() {
|
||||
run_loop_.Run();
|
||||
}
|
||||
|
||||
void URLCookieAccessObserver::OnCookiesAccessed(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
const content::CookieAccessDetails& details) {
|
||||
if (details.type == access_type_ && details.url == url_) {
|
||||
run_loop_.Quit();
|
||||
}
|
||||
}
|
||||
|
||||
void URLCookieAccessObserver::OnCookiesAccessed(
|
||||
content::NavigationHandle* navigation_handle,
|
||||
const content::CookieAccessDetails& details) {
|
||||
if (details.type == access_type_ && details.url == url_) {
|
||||
run_loop_.Quit();
|
||||
}
|
||||
}
|
||||
|
||||
bool NavigateToSetCookie(content::WebContents* web_contents,
|
||||
const net::EmbeddedTestServer* server,
|
||||
std::string_view host,
|
||||
bool is_secure_cookie_set,
|
||||
bool is_ad_tagged) {
|
||||
std::string relative_url = "/set-cookie?name=value";
|
||||
if (is_secure_cookie_set) {
|
||||
relative_url += ";Secure;SameSite=None";
|
||||
}
|
||||
if (is_ad_tagged) {
|
||||
relative_url += "&isad=1";
|
||||
}
|
||||
const auto url = server->GetURL(host, relative_url);
|
||||
|
||||
URLCookieAccessObserver observer(web_contents, url,
|
||||
content::CookieAccessDetails::Type::kChange);
|
||||
bool success = content::NavigateToURL(web_contents, url);
|
||||
if (success) {
|
||||
observer.Wait();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void CreateImageAndWaitForCookieAccess(content::WebContents* web_contents,
|
||||
const GURL& image_url) {
|
||||
URLCookieAccessObserver observer(web_contents, image_url,
|
||||
content::CookieAccessDetails::Type::kRead);
|
||||
ASSERT_TRUE(content::ExecJs(web_contents,
|
||||
content::JsReplace(
|
||||
R"(
|
||||
let img = document.createElement('img');
|
||||
img.src = $1;
|
||||
document.body.appendChild(img);)",
|
||||
image_url),
|
||||
content::EXECUTE_SCRIPT_NO_USER_GESTURE));
|
||||
// The image must cause a cookie access, or else this will hang.
|
||||
observer.Wait();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class TpcdMetadataDevtoolsObserverBrowserTest
|
||||
|
@ -27,8 +27,6 @@
|
||||
#include "chrome/browser/content_settings/mixed_content_settings_tab_helper.h"
|
||||
#include "chrome/browser/content_settings/page_specific_content_settings_delegate.h"
|
||||
#include "chrome/browser/content_settings/sound_content_setting_observer.h"
|
||||
#include "chrome/browser/dips/dips_bounce_detector.h"
|
||||
#include "chrome/browser/dips/dips_navigation_flow_detector.h"
|
||||
#include "chrome/browser/external_protocol/external_protocol_observer.h"
|
||||
#include "chrome/browser/favicon/favicon_utils.h"
|
||||
#include "chrome/browser/file_system_access/file_system_access_features.h"
|
||||
@ -84,8 +82,7 @@
|
||||
#include "chrome/browser/sync/sessions/sync_sessions_web_contents_router_factory.h"
|
||||
#include "chrome/browser/tab_contents/navigation_metrics_recorder.h"
|
||||
#include "chrome/browser/task_manager/web_contents_tags.h"
|
||||
#include "chrome/browser/tpcd/heuristics/opener_heuristic_tab_helper.h"
|
||||
#include "chrome/browser/tpcd/heuristics/redirect_heuristic_tab_helper.h"
|
||||
#include "chrome/browser/tpcd/heuristics/opener_heuristic_service.h"
|
||||
#include "chrome/browser/tpcd/http_error_observer/http_error_tab_helper.h"
|
||||
#include "chrome/browser/tpcd/metadata/devtools_observer.h"
|
||||
#include "chrome/browser/tpcd/support/validity_service.h"
|
||||
@ -332,17 +329,6 @@ void TabHelpers::AttachTabHelpers(WebContents* web_contents) {
|
||||
// ChromeSubresourceFilterClient has it as a dependency.
|
||||
infobars::ContentInfoBarManager::CreateForWebContents(web_contents);
|
||||
|
||||
// `PageSpecificContentSettings` (PSCS) needs to come before
|
||||
// `DIPSWebContentsObserver` for this latter to be correctly added to the PSCS
|
||||
// observer list.
|
||||
content_settings::PageSpecificContentSettings::CreateForWebContents(
|
||||
web_contents,
|
||||
std::make_unique<PageSpecificContentSettingsDelegate>(web_contents));
|
||||
|
||||
// RedirectChainDetector comes before common tab helpers since
|
||||
// DIPSWebContentsObserver has it as a dependency.
|
||||
RedirectChainDetector::CreateForWebContents(web_contents);
|
||||
|
||||
Profile* profile =
|
||||
Profile::FromBrowserContext(web_contents->GetBrowserContext());
|
||||
|
||||
@ -402,9 +388,10 @@ void TabHelpers::AttachTabHelpers(WebContents* web_contents) {
|
||||
commerce::ShoppingServiceFactory::GetForBrowserContext(profile),
|
||||
ISOLATED_WORLD_ID_CHROME_INTERNAL);
|
||||
ConnectionHelpTabHelper::CreateForWebContents(web_contents);
|
||||
content_settings::PageSpecificContentSettings::CreateForWebContents(
|
||||
web_contents,
|
||||
std::make_unique<PageSpecificContentSettingsDelegate>(web_contents));
|
||||
CoreTabHelper::CreateForWebContents(web_contents);
|
||||
DipsNavigationFlowDetector::CreateForWebContents(web_contents);
|
||||
DIPSWebContentsObserver::MaybeCreateForWebContents(web_contents);
|
||||
#if BUILDFLAG(ENABLE_REPORTING)
|
||||
if (base::FeatureList::IsEnabled(
|
||||
net::features::kReportingApiEnableEnterpriseCookieIssues)) {
|
||||
@ -442,7 +429,7 @@ void TabHelpers::AttachTabHelpers(WebContents* web_contents) {
|
||||
MixedContentSettingsTabHelper::CreateForWebContents(web_contents);
|
||||
NavigationMetricsRecorder::CreateForWebContents(web_contents);
|
||||
NavigationPredictorPreconnectClient::CreateForWebContents(web_contents);
|
||||
OpenerHeuristicTabHelper::CreateForWebContents(web_contents);
|
||||
OpenerHeuristicService::Get(web_contents->GetBrowserContext());
|
||||
if (optimization_guide::features::IsOptimizationHintsEnabled()) {
|
||||
OptimizationGuideWebContentsObserver::CreateForWebContents(web_contents);
|
||||
}
|
||||
@ -498,7 +485,6 @@ void TabHelpers::AttachTabHelpers(WebContents* web_contents) {
|
||||
PrefsTabHelper::CreateForWebContents(web_contents);
|
||||
prerender::NoStatePrefetchTabHelper::CreateForWebContents(web_contents);
|
||||
RecentlyAudibleHelper::CreateForWebContents(web_contents);
|
||||
RedirectHeuristicTabHelper::CreateForWebContents(web_contents);
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
RequestDesktopSiteWebContentsObserverAndroid::CreateForWebContents(
|
||||
web_contents);
|
||||
|
@ -158,8 +158,6 @@ static_library("test_support") {
|
||||
"../browser/autofill/automated_tests/cache_replayer.h",
|
||||
"../browser/component_updater/privacy_sandbox_attestations_component_installer_test_util.cc",
|
||||
"../browser/component_updater/privacy_sandbox_attestations_component_installer_test_util.h",
|
||||
"../browser/dips/dips_test_utils.cc",
|
||||
"../browser/dips/dips_test_utils.h",
|
||||
"../browser/fingerprinting_protection/fingerprinting_protection_filter_browser_test_harness.cc",
|
||||
"../browser/fingerprinting_protection/fingerprinting_protection_filter_browser_test_harness.h",
|
||||
"../browser/notifications/notification_display_service_tester.cc",
|
||||
@ -1540,7 +1538,6 @@ if (is_android) {
|
||||
"//chrome/browser/autofill",
|
||||
"//chrome/browser/browsing_data:constants",
|
||||
"//chrome/browser/content_settings:content_settings_factory",
|
||||
"//chrome/browser/dips:browser_tests",
|
||||
"//chrome/browser/enterprise/data_controls:data_controls",
|
||||
"//chrome/browser/fast_checkout:test_support",
|
||||
"//chrome/browser/flags:flags_android",
|
||||
@ -1963,7 +1960,6 @@ if (!is_android) {
|
||||
"//chrome/browser/data_saver",
|
||||
"//chrome/browser/devtools",
|
||||
"//chrome/browser/devtools:test_support",
|
||||
"//chrome/browser/dips:browser_tests",
|
||||
"//chrome/browser/enterprise/watermark:watermark_view_lib",
|
||||
"//chrome/browser/error_reporting:test_support",
|
||||
"//chrome/browser/favicon",
|
||||
@ -2780,6 +2776,7 @@ if (!is_android) {
|
||||
"../browser/devtools/protocol/devtools_protocol_test_support.h",
|
||||
"../browser/devtools/protocol/devtools_pwa_browsertest.cc",
|
||||
"../browser/devtools/protocol/form_devtools_issues_browsertest.cc",
|
||||
"../browser/dips/dips_devtools_browsertest.cc",
|
||||
"../browser/direct_sockets/direct_sockets_apitest.cc",
|
||||
"../browser/dom_distiller/distillable_page_utils_browsertest.cc",
|
||||
"../browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc",
|
||||
@ -3126,7 +3123,7 @@ if (!is_android) {
|
||||
"../browser/tpcd/experiment/eligibility_service_browsertest.cc",
|
||||
"../browser/tpcd/experiment/experiment_manager_impl_browsertest.cc",
|
||||
"../browser/tpcd/experiment/tpcd_mitigations_browsertest.cc",
|
||||
"../browser/tpcd/heuristics/opener_heuristic_browsertest.cc",
|
||||
"../browser/tpcd/heuristics/opener_heuristic_service_browsertest.cc",
|
||||
"../browser/tpcd/metadata/devtools_observer_browsertest.cc",
|
||||
"../browser/tpcd/metadata/manager_browsertest.cc",
|
||||
"../browser/tpcd/support/top_level_trial_service_browsertest.cc",
|
||||
@ -6372,7 +6369,6 @@ test("unit_tests") {
|
||||
"//chrome/browser/sync_file_system/drive_backend:sync_file_system_drive_proto",
|
||||
"//chrome/browser/top_level_storage_access_api:permissions",
|
||||
"//chrome/browser/tpcd/experiment:unit_tests",
|
||||
"//chrome/browser/tpcd/heuristics:unit_tests",
|
||||
"//chrome/browser/ui:browser_element_identifiers",
|
||||
"//chrome/browser/ui:test_support",
|
||||
"//chrome/browser/ui:ui_features",
|
||||
|
@ -102,6 +102,24 @@ BASE_FEATURE(kNativeUnpartitionedStoragePermittedWhen3PCOff,
|
||||
|
||||
const char kTpcdReadHeuristicsGrantsName[] = "TpcdReadHeuristicsGrants";
|
||||
|
||||
const char kTpcdWriteRedirectHeuristicGrantsName[] =
|
||||
"TpcdWriteRedirectHeuristicGrants";
|
||||
const char kTpcdRedirectHeuristicRequireABAFlowName[] =
|
||||
"TpcdRedirectHeuristicRequireABAFlow";
|
||||
const char kTpcdRedirectHeuristicRequireCurrentInteractionName[] =
|
||||
"TpcdRedirectHeuristicRequireCurrentInteraction";
|
||||
|
||||
const char kTpcdWritePopupCurrentInteractionHeuristicsGrantsName[] =
|
||||
"TpcdWritePopupCurrentInteractionHeuristicsGrants";
|
||||
const char kTpcdWritePopupPastInteractionHeuristicsGrantsName[] =
|
||||
"TpcdWritePopupPastInteractionHeuristicsGrants";
|
||||
const char kTpcdBackfillPopupHeuristicsGrantsName[] =
|
||||
"TpcdBackfillPopupHeuristicsGrants";
|
||||
const char kTpcdPopupHeuristicDisableForAdTaggedPopupsName[] =
|
||||
"TpcdPopupHeuristicDisableForAdTaggedPopups";
|
||||
const char kTpcdPopupHeuristicEnableForIframeInitiatorName[] =
|
||||
"TpcdPopupHeuristicEnableForIframeInitiator";
|
||||
|
||||
BASE_FEATURE(kTpcdHeuristicsGrants,
|
||||
"TpcdHeuristicsGrants",
|
||||
base::FEATURE_ENABLED_BY_DEFAULT);
|
||||
@ -109,6 +127,42 @@ BASE_FEATURE(kTpcdHeuristicsGrants,
|
||||
const base::FeatureParam<bool> kTpcdReadHeuristicsGrants{
|
||||
&kTpcdHeuristicsGrants, kTpcdReadHeuristicsGrantsName, true};
|
||||
|
||||
const base::FeatureParam<base::TimeDelta> kTpcdWriteRedirectHeuristicGrants{
|
||||
&content_settings::features::kTpcdHeuristicsGrants,
|
||||
kTpcdWriteRedirectHeuristicGrantsName, base::Minutes(15)};
|
||||
|
||||
const base::FeatureParam<bool> kTpcdRedirectHeuristicRequireABAFlow{
|
||||
&content_settings::features::kTpcdHeuristicsGrants,
|
||||
kTpcdRedirectHeuristicRequireABAFlowName, true};
|
||||
|
||||
const base::FeatureParam<bool> kTpcdRedirectHeuristicRequireCurrentInteraction{
|
||||
&content_settings::features::kTpcdHeuristicsGrants,
|
||||
kTpcdRedirectHeuristicRequireCurrentInteractionName, true};
|
||||
|
||||
const base::FeatureParam<base::TimeDelta>
|
||||
kTpcdWritePopupCurrentInteractionHeuristicsGrants{
|
||||
&content_settings::features::kTpcdHeuristicsGrants,
|
||||
kTpcdWritePopupCurrentInteractionHeuristicsGrantsName, base::Days(30)};
|
||||
|
||||
const base::FeatureParam<base::TimeDelta>
|
||||
kTpcdWritePopupPastInteractionHeuristicsGrants{
|
||||
&content_settings::features::kTpcdHeuristicsGrants,
|
||||
kTpcdWritePopupPastInteractionHeuristicsGrantsName, base::TimeDelta()};
|
||||
|
||||
const base::FeatureParam<base::TimeDelta> kTpcdBackfillPopupHeuristicsGrants{
|
||||
&content_settings::features::kTpcdHeuristicsGrants,
|
||||
kTpcdBackfillPopupHeuristicsGrantsName, base::Days(30)};
|
||||
|
||||
const base::FeatureParam<bool> kTpcdPopupHeuristicDisableForAdTaggedPopups{
|
||||
&content_settings::features::kTpcdHeuristicsGrants,
|
||||
kTpcdPopupHeuristicDisableForAdTaggedPopupsName, false};
|
||||
|
||||
const base::FeatureParam<EnableForIframeTypes>
|
||||
kTpcdPopupHeuristicEnableForIframeInitiator{
|
||||
&content_settings::features::kTpcdHeuristicsGrants,
|
||||
kTpcdPopupHeuristicEnableForIframeInitiatorName,
|
||||
EnableForIframeTypes::kAll, &kEnableForIframeTypesOptions};
|
||||
|
||||
BASE_FEATURE(kContentSettingsPartitioning,
|
||||
"ContentSettingsPartitioning",
|
||||
base::FEATURE_DISABLED_BY_DEFAULT);
|
||||
|
@ -121,6 +121,27 @@ BASE_DECLARE_FEATURE(kTrackingProtection3pcd);
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
BASE_DECLARE_FEATURE(kNativeUnpartitionedStoragePermittedWhen3PCOff);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Start of third-party cookie access heuristics features //
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// The content module implements the third-party cookie (3PC or TPC) access
|
||||
// heuristics described here:
|
||||
// https://github.com/amaliev/3pcd-exemption-heuristics/blob/main/explainer.md
|
||||
//
|
||||
// At a high level, the heuristics are enabled/disabled by the
|
||||
// kTpcdHeuristicsGrants Feature.
|
||||
//
|
||||
// The heuristics can be tweaked through the FeatureParams declared below. They
|
||||
// affect when the heuristics apply and how long the temporary cookie access
|
||||
// lasts.
|
||||
//
|
||||
// The heuristics grant third-party cookie access via calls to
|
||||
// ContentBrowserClient::GrantCookieAccessDueToHeuristic(). Embedders should
|
||||
// take these calls, kTpcdHeuristicsGrants, and kTpcdReadHeuristicsGrants into
|
||||
// account in their implementation of
|
||||
// ContentBrowserClient::IsFullCookieAccessAllowed().
|
||||
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const char kTpcdReadHeuristicsGrantsName[];
|
||||
|
||||
@ -134,6 +155,93 @@ BASE_DECLARE_FEATURE(kTpcdHeuristicsGrants);
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const base::FeatureParam<bool> kTpcdReadHeuristicsGrants;
|
||||
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const char kTpcdWriteRedirectHeuristicGrantsName[];
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const char kTpcdRedirectHeuristicRequireABAFlowName[];
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const char kTpcdRedirectHeuristicRequireCurrentInteractionName[];
|
||||
|
||||
// The duration of the storage access grant created when observing the Redirect
|
||||
// With Current Interaction scenario. If set to zero duration, do not create a
|
||||
// grant.
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const base::FeatureParam<base::TimeDelta>
|
||||
kTpcdWriteRedirectHeuristicGrants;
|
||||
|
||||
// Whether to require an A-B-A flow (where the first party preceded the
|
||||
// third-party redirect in the tab history) when applying the Redirect
|
||||
// heuristic.
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const base::FeatureParam<bool> kTpcdRedirectHeuristicRequireABAFlow;
|
||||
|
||||
// Whether to require the third-party interaction to be in the current
|
||||
// navigation when applying the Redirect heuristic.
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const base::FeatureParam<bool>
|
||||
kTpcdRedirectHeuristicRequireCurrentInteraction;
|
||||
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const char kTpcdPopupHeuristicEnableForIframeInitiatorName[];
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const char kTpcdWritePopupCurrentInteractionHeuristicsGrantsName[];
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const char kTpcdWritePopupPastInteractionHeuristicsGrantsName[];
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const char kTpcdBackfillPopupHeuristicsGrantsName[];
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const char kTpcdPopupHeuristicDisableForAdTaggedPopupsName[];
|
||||
|
||||
enum class EnableForIframeTypes { kNone = 0, kFirstParty = 1, kAll = 2 };
|
||||
|
||||
// Whether to enable writing Popup heuristic grants when the popup is opened via
|
||||
// an iframe initiator.
|
||||
|
||||
// * kNone: Ignore popups initiated from iframes.
|
||||
// * kFirstPartyIframes: Only write grants for popups initiated from 1P iframes,
|
||||
// or nested tree of all 1P iframes.
|
||||
// * kAllIframes: Write grants for popups initiated from any frame.
|
||||
constexpr base::FeatureParam<EnableForIframeTypes>::Option
|
||||
kEnableForIframeTypesOptions[] = {
|
||||
{EnableForIframeTypes::kNone, "none"},
|
||||
{EnableForIframeTypes::kFirstParty, "first-party"},
|
||||
{EnableForIframeTypes::kAll, "all"},
|
||||
};
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const base::FeatureParam<EnableForIframeTypes>
|
||||
kTpcdPopupHeuristicEnableForIframeInitiator;
|
||||
|
||||
// The duration of the storage access grant created when observing the Popup
|
||||
// With Current Interaction scenario. If set to zero duration, do not create a
|
||||
// grant.
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const base::FeatureParam<base::TimeDelta>
|
||||
kTpcdWritePopupCurrentInteractionHeuristicsGrants;
|
||||
|
||||
// The duration of the storage access grant created when observing the Popup
|
||||
// With Past Interaction scenario. If set to zero duration, do not create a
|
||||
// grant.
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const base::FeatureParam<base::TimeDelta>
|
||||
kTpcdWritePopupPastInteractionHeuristicsGrants;
|
||||
|
||||
// The lookback and duration of the storage access grants created when
|
||||
// backfilling the Popup With Current Interaction scenario on onboarding to
|
||||
// 3PCD. If set to zero duration, to not create backfill grants.
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const base::FeatureParam<base::TimeDelta>
|
||||
kTpcdBackfillPopupHeuristicsGrants;
|
||||
|
||||
// Whether to disable writing Popup heuristic grants when the popup is opened
|
||||
// via an ad-tagged frame.
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
extern const base::FeatureParam<bool>
|
||||
kTpcdPopupHeuristicDisableForAdTaggedPopups;
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// End of third-party cookie access heuristics features //
|
||||
//////////////////////////////////////////////////////////
|
||||
|
||||
// Whether we should partition content settings (by StoragePartitions for
|
||||
// non-ios platforms).
|
||||
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/ukm/content/source_url_recorder.h"
|
||||
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "components/ukm/test_ukm_recorder.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
@ -11,6 +12,7 @@
|
||||
#include "services/metrics/public/cpp/ukm_recorder.h"
|
||||
#include "services/metrics/public/cpp/ukm_source.h"
|
||||
#include "services/metrics/public/cpp/ukm_source_id.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/metrics_proto/ukm/source.pb.h"
|
||||
#include "url/gurl.h"
|
||||
@ -61,26 +63,33 @@ TEST_F(SourceUrlRecorderWebContentsObserverTest, InitialUrl) {
|
||||
|
||||
const auto& sources = test_ukm_recorder_.GetSources();
|
||||
|
||||
// Expect two sources, one for navigation, one for document.
|
||||
EXPECT_EQ(2ul, sources.size());
|
||||
// Expect three sources, one each for navigation, redirect, and document.
|
||||
EXPECT_EQ(3ul, sources.size());
|
||||
size_t navigation_type_source_count = 0;
|
||||
size_t redirect_type_source_count = 0;
|
||||
size_t document_type_source_count = 0;
|
||||
for (const auto& kv : sources) {
|
||||
if (ukm::GetSourceIdType(kv.first) ==
|
||||
ukm::SourceIdObj::Type::NAVIGATION_ID) {
|
||||
// The navigation source has both URLs.
|
||||
EXPECT_EQ(initial_url, kv.second->urls().front());
|
||||
EXPECT_EQ(final_url, kv.second->urls().back());
|
||||
EXPECT_THAT(kv.second->urls(),
|
||||
testing::ElementsAre(initial_url, final_url));
|
||||
navigation_type_source_count++;
|
||||
}
|
||||
if (ukm::GetSourceIdType(kv.first) == ukm::SourceIdObj::Type::REDIRECT_ID) {
|
||||
// The redirect source has the initial URL which the navigation requested.
|
||||
EXPECT_THAT(kv.second->urls(), testing::ElementsAre(initial_url));
|
||||
redirect_type_source_count++;
|
||||
}
|
||||
if (ukm::GetSourceIdType(kv.first) == ukm::SourceIdObj::Type::DEFAULT) {
|
||||
// The document source has the final URL which is one set on the
|
||||
// committed document.
|
||||
EXPECT_EQ(final_url, kv.second->urls().front());
|
||||
EXPECT_THAT(kv.second->urls(), testing::ElementsAre(final_url));
|
||||
document_type_source_count++;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(1u, navigation_type_source_count);
|
||||
EXPECT_EQ(1u, redirect_type_source_count);
|
||||
EXPECT_EQ(1u, document_type_source_count);
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ include_rules = [
|
||||
"+components/app_launch_prefetch",
|
||||
"+components/attribution_reporting",
|
||||
"+components/browsing_topics/common",
|
||||
"+components/content_settings/core/common",
|
||||
"+components/input",
|
||||
"+components/memory_pressure",
|
||||
# components/performance_manager sits between chrome/ and content/, except for
|
||||
|
@ -955,6 +955,26 @@ source_set("browser") {
|
||||
"devtools/worker_or_worklet_devtools_agent_host.h",
|
||||
"devtools/worklet_devtools_agent_host.cc",
|
||||
"devtools/worklet_devtools_agent_host.h",
|
||||
"dips/cookie_access_filter.cc",
|
||||
"dips/cookie_access_filter.h",
|
||||
"dips/dips_bounce_detector.cc",
|
||||
"dips/dips_bounce_detector.h",
|
||||
"dips/dips_database.cc",
|
||||
"dips/dips_database.h",
|
||||
"dips/dips_database_migrator.cc",
|
||||
"dips/dips_database_migrator.h",
|
||||
"dips/dips_navigation_flow_detector.cc",
|
||||
"dips/dips_navigation_flow_detector.h",
|
||||
"dips/dips_service_impl.cc",
|
||||
"dips/dips_service_impl.h",
|
||||
"dips/dips_state.cc",
|
||||
"dips/dips_state.h",
|
||||
"dips/dips_storage.cc",
|
||||
"dips/dips_storage.h",
|
||||
"dips/dips_utils.cc",
|
||||
"dips/dips_utils.h",
|
||||
"dips/persistent_repeating_timer.cc",
|
||||
"dips/persistent_repeating_timer.h",
|
||||
"display_cutout/display_cutout_constants.h",
|
||||
"display_cutout/display_cutout_host_impl.cc",
|
||||
"display_cutout/display_cutout_host_impl.h",
|
||||
@ -2195,6 +2215,14 @@ source_set("browser") {
|
||||
"synthetic_trial_syncer.cc",
|
||||
"theme_helper.cc",
|
||||
"theme_helper.h",
|
||||
"tpcd_heuristics/opener_heuristic_metrics.cc",
|
||||
"tpcd_heuristics/opener_heuristic_metrics.h",
|
||||
"tpcd_heuristics/opener_heuristic_tab_helper.cc",
|
||||
"tpcd_heuristics/opener_heuristic_tab_helper.h",
|
||||
"tpcd_heuristics/opener_heuristic_utils.cc",
|
||||
"tpcd_heuristics/opener_heuristic_utils.h",
|
||||
"tpcd_heuristics/redirect_heuristic_tab_helper.cc",
|
||||
"tpcd_heuristics/redirect_heuristic_tab_helper.h",
|
||||
"tracing/background_tracing_agent_client_impl.cc",
|
||||
"tracing/background_tracing_agent_client_impl.h",
|
||||
"tracing/background_tracing_manager_impl.cc",
|
||||
@ -3594,7 +3622,9 @@ if (is_android) {
|
||||
# See comment at the top of //content/BUILD.gn for how this works.
|
||||
group("for_content_tests") {
|
||||
visibility = [
|
||||
"//content/browser/dips:unit_tests",
|
||||
"//content/browser/indexed_db:unit_tests",
|
||||
"//content/browser/tpcd_heuristics:unit_tests",
|
||||
"//content/public/test/android/*",
|
||||
"//content/test/*",
|
||||
"//content/web_test:web_test_browser",
|
||||
|
@ -353,6 +353,11 @@ ResourceContext* BrowserContext::GetResourceContext() const {
|
||||
return impl()->GetResourceContext();
|
||||
}
|
||||
|
||||
void BrowserContext::BackfillPopupHeuristicGrants(
|
||||
base::OnceCallback<void(bool)> callback) {
|
||||
return impl_->BackfillPopupHeuristicGrants(std::move(callback));
|
||||
}
|
||||
|
||||
base::WeakPtr<BrowserContext> BrowserContext::GetWeakPtr() {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
@ -6,12 +6,18 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/check_is_test.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/functional/callback_helpers.h"
|
||||
#include "base/location.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "base/trace_event/trace_event.h"
|
||||
#include "build/build_config.h"
|
||||
#include "components/content_settings/core/common/features.h"
|
||||
#include "content/browser/background_sync/background_sync_scheduler.h"
|
||||
#include "content/browser/browsing_data/browsing_data_remover_impl.h"
|
||||
#include "content/browser/dips/dips_service_impl.h"
|
||||
#include "content/browser/download/download_manager_impl.h"
|
||||
#include "content/browser/in_memory_federated_permission_context.h"
|
||||
#include "content/browser/permissions/permission_controller_impl.h"
|
||||
@ -25,8 +31,11 @@
|
||||
#include "content/browser/storage_partition_impl_map.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/content_browser_client.h"
|
||||
#include "content/public/browser/dips_delegate.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/shared_worker_service.h"
|
||||
#include "content/public/common/content_client.h"
|
||||
#include "media/capabilities/webrtc_video_stats_db_impl.h"
|
||||
#include "media/learning/common/media_learning_tasks.h"
|
||||
#include "media/learning/impl/learning_session_impl.h"
|
||||
@ -68,10 +77,61 @@ BrowserContextImpl* BrowserContextImpl::From(BrowserContext* self) {
|
||||
return self->impl();
|
||||
}
|
||||
|
||||
void BrowserContextImpl::MaybeCleanupDips() {
|
||||
base::ScopedClosureRunner quit_runner(dips_cleanup_loop_.QuitClosure());
|
||||
// Don't attempt to delete the database if the DIPS feature is enabled; we
|
||||
// need it.
|
||||
if (base::FeatureList::IsEnabled(features::kDIPS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't attempt to delete the database if this browser context should never
|
||||
// have DIPS enabled. (This is important for embedders like ChromeOS, which
|
||||
// have internal non-user-facing browser contexts. We don't want to touch
|
||||
// them.)
|
||||
if (dips_delegate_ && !dips_delegate_->ShouldEnableDips(self_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't attempt to delete the database if this browser context doesn't write
|
||||
// to disk. (This is important for embedders like Chrome, which can make OTR
|
||||
// browser contexts share the same data directory as a non-OTR context.)
|
||||
if (self_->IsOffTheRecord()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DIPSStorage::DeleteDatabaseFiles(GetDIPSFilePath(self_),
|
||||
quit_runner.Release());
|
||||
}
|
||||
|
||||
void BrowserContextImpl::WaitForDipsCleanupForTesting() {
|
||||
dips_cleanup_loop_.Run();
|
||||
}
|
||||
|
||||
BrowserContextImpl::BrowserContextImpl(BrowserContext* self) : self_(self) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
|
||||
background_sync_scheduler_ = base::MakeRefCounted<BackgroundSyncScheduler>();
|
||||
|
||||
// TODO: crbug.com/382509288 - don't allow null clients here, even in tests.
|
||||
if (GetContentClient()) {
|
||||
if (GetContentClient()->browser()) {
|
||||
dips_delegate_ = GetContentClient()->browser()->CreateDipsDelegate();
|
||||
} else {
|
||||
CHECK_IS_TEST() << "Attempted to create BrowserContext without a "
|
||||
"ContentBrowserClient";
|
||||
}
|
||||
} else {
|
||||
CHECK_IS_TEST()
|
||||
<< "Attempted to create BrowserContext without a ContentClient";
|
||||
}
|
||||
// Run MaybeCleanupDips() very soon. We can't call it right now because it
|
||||
// calls a virtual function (BrowserContext::IsOffTheRecord()), which causes
|
||||
// undefined behavior since we're called by the BrowserContext constructor
|
||||
// and the method is not implemented by that class.
|
||||
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
|
||||
FROM_HERE, base::BindOnce(&BrowserContextImpl::MaybeCleanupDips,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
BrowserContextImpl::~BrowserContextImpl() {
|
||||
@ -245,6 +305,11 @@ void BrowserContextImpl::ShutdownStoragePartitions() {
|
||||
background_sync_scheduler_.reset();
|
||||
|
||||
storage_partition_map_.reset();
|
||||
|
||||
// Delete the DIPSService, causing its SQLite database file to be closed. This
|
||||
// is necessary for TestBrowserContext to be able to delete its temporary
|
||||
// directory.
|
||||
dips_service_.reset();
|
||||
}
|
||||
|
||||
DownloadManager* BrowserContextImpl::GetDownloadManager() {
|
||||
@ -346,4 +411,89 @@ void BrowserContextImpl::WriteIntoTrace(
|
||||
proto->set_id(UniqueId());
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool ShouldEnableDips(BrowserContext* browser_context,
|
||||
DipsDelegate* dips_delegate) {
|
||||
if (!base::FeatureList::IsEnabled(features::kDIPS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dips_delegate && !dips_delegate->ShouldEnableDips(browser_context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
DIPSServiceImpl* BrowserContextImpl::GetDipsService() {
|
||||
if (!dips_service_) {
|
||||
if (!ShouldEnableDips(self_, dips_delegate_.get())) {
|
||||
return nullptr;
|
||||
}
|
||||
dips_service_ = std::make_unique<DIPSServiceImpl>(
|
||||
base::PassKey<BrowserContextImpl>(), self_);
|
||||
if (dips_delegate_) {
|
||||
dips_delegate_->OnDipsServiceCreated(self_, dips_service_.get());
|
||||
}
|
||||
}
|
||||
|
||||
return dips_service_.get();
|
||||
}
|
||||
|
||||
namespace {
|
||||
void CreatePopupHeuristicGrants(base::WeakPtr<BrowserContext> browser_context,
|
||||
base::OnceCallback<void(bool)> callback,
|
||||
std::vector<PopupWithTime> recent_popups) {
|
||||
if (!browser_context) {
|
||||
std::move(callback).Run(false);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const PopupWithTime& popup : recent_popups) {
|
||||
base::TimeDelta grant_duration =
|
||||
content_settings::features::kTpcdBackfillPopupHeuristicsGrants.Get() -
|
||||
(base::Time::Now() - popup.last_popup_time);
|
||||
if (!grant_duration.is_positive()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// `popup_site` and `opener_site` were read from the DIPS database,
|
||||
// and were originally computed by calling GetSiteForDIPS().
|
||||
// GrantCookieAccessDueToHeuristic() takes SchemefulSites, so we create some
|
||||
// here, but since we pass ignore_schemes=true the scheme doesn't matter
|
||||
// (and port never matters for SchemefulSites), so we hardcode http and 80.
|
||||
net::SchemefulSite popup_site(
|
||||
url::Origin::CreateFromNormalizedTuple("http", popup.popup_site, 80));
|
||||
net::SchemefulSite opener_site(
|
||||
url::Origin::CreateFromNormalizedTuple("http", popup.opener_site, 80));
|
||||
|
||||
GetContentClient()->browser()->GrantCookieAccessDueToHeuristic(
|
||||
browser_context.get(), opener_site, popup_site, grant_duration,
|
||||
/*ignore_schemes=*/true);
|
||||
}
|
||||
std::move(callback).Run(true);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void BrowserContextImpl::BackfillPopupHeuristicGrants(
|
||||
base::OnceCallback<void(bool)> callback) {
|
||||
if (!base::FeatureList::IsEnabled(
|
||||
content_settings::features::kTpcdHeuristicsGrants) ||
|
||||
!content_settings::features::kTpcdBackfillPopupHeuristicsGrants.Get()
|
||||
.is_positive()) {
|
||||
std::move(callback).Run(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: crbug.com/1502264 - ensure backfill is completed if Chrome is
|
||||
// shutdown or crashes.
|
||||
GetDipsService()
|
||||
->storage()
|
||||
->AsyncCall(&DIPSStorage::ReadRecentPopupsWithInteraction)
|
||||
.WithArgs(
|
||||
content_settings::features::kTpcdBackfillPopupHeuristicsGrants.Get())
|
||||
.Then(base::BindOnce(&CreatePopupHeuristicGrants, self_->GetWeakPtr(),
|
||||
std::move(callback)));
|
||||
}
|
||||
} // namespace content
|
||||
|
@ -10,8 +10,12 @@
|
||||
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "build/build_config.h"
|
||||
#include "content/browser/dips/dips_service_impl.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/dips_delegate.h"
|
||||
#include "content/public/browser/resource_context.h"
|
||||
#include "content/public/browser/shared_cors_origin_access_list.h"
|
||||
|
||||
@ -114,6 +118,17 @@ class CONTENT_EXPORT BrowserContextImpl {
|
||||
return resource_context_.get();
|
||||
}
|
||||
|
||||
DIPSServiceImpl* GetDipsService();
|
||||
// If the DIPS database file should be deleted, wait for it. Otherwise, return
|
||||
// immediately.
|
||||
//
|
||||
// TODO: crbug.com/356624038 - delete this method when the DIPS feature flag
|
||||
// is removed.
|
||||
void WaitForDipsCleanupForTesting();
|
||||
|
||||
// (See BrowserContext::BackfillPopupHeuristicGrants().)
|
||||
void BackfillPopupHeuristicGrants(base::OnceCallback<void(bool)> callback);
|
||||
|
||||
private:
|
||||
// Creates the media service for storing/retrieving WebRTC encoding and
|
||||
// decoding performance stats. Exposed here rather than StoragePartition
|
||||
@ -121,6 +136,13 @@ class CONTENT_EXPORT BrowserContextImpl {
|
||||
// exposed to the web directly, so privacy is not compromised.
|
||||
std::unique_ptr<media::WebrtcVideoPerfHistory> CreateWebrtcVideoPerfHistory();
|
||||
|
||||
// Delete any existing DIPS database file if DIPS is disabled (because it's
|
||||
// not possible for the user to clear it through the browser UI).
|
||||
//
|
||||
// TODO: crbug.com/356624038 - delete this method when the DIPS feature flag
|
||||
// is removed.
|
||||
void MaybeCleanupDips();
|
||||
|
||||
// BrowserContextImpl is owned and build from BrowserContext constructor.
|
||||
// TODO(crbug.com/40169693): Invert the dependency. Make BrowserContext
|
||||
// a pure interface and BrowserContextImpl implements it. Remove the `self_`
|
||||
@ -149,6 +171,18 @@ class CONTENT_EXPORT BrowserContextImpl {
|
||||
std::unique_ptr<media::VideoDecodePerfHistory> video_decode_perf_history_;
|
||||
std::unique_ptr<media::WebrtcVideoPerfHistory> webrtc_video_perf_history_;
|
||||
|
||||
// A cached instance of the DIPS delegate created by the browser client.
|
||||
std::unique_ptr<DipsDelegate> dips_delegate_;
|
||||
// Manages DIPS for all WebContentses using this browser context.
|
||||
std::unique_ptr<DIPSServiceImpl> dips_service_;
|
||||
// If DIPS is disabled, any existing database file is asynchronously deleted
|
||||
// when the BrowserContextImpl is created. This RunLoop allows tests to wait
|
||||
// for the deletion to complete.
|
||||
//
|
||||
// TODO: crbug.com/356624038 - delete this when the DIPS feature flag is
|
||||
// removed.
|
||||
base::RunLoop dips_cleanup_loop_;
|
||||
|
||||
// TODO(crbug.com/40604019): Get rid of ResourceContext.
|
||||
// Created on the UI thread, otherwise lives on and is destroyed on the IO
|
||||
// thread.
|
||||
@ -158,6 +192,10 @@ class CONTENT_EXPORT BrowserContextImpl {
|
||||
#if BUILDFLAG(IS_CHROMEOS)
|
||||
scoped_refptr<storage::ExternalMountPoints> external_mount_points_;
|
||||
#endif
|
||||
|
||||
// TODO: crbug.com/40169693 - BrowserContext and BrowserContextImpl both have
|
||||
// WeakPtrFactories. Remove one once the inheritance is sorted out.
|
||||
base::WeakPtrFactory<BrowserContextImpl> weak_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace content
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include "base/trace_event/trace_event.h"
|
||||
#include "components/browsing_data/core/cookie_or_cache_deletion_choice.h"
|
||||
#include "content/browser/browsing_data/browsing_data_filter_builder_impl.h"
|
||||
#include "content/browser/dips/dips_service_impl.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/browser/renderer_host/render_frame_host_impl.h"
|
||||
#include "content/browser/renderer_host/render_process_host_impl.h"
|
||||
#include "content/browser/web_contents/web_contents_impl.h"
|
||||
@ -40,9 +42,11 @@
|
||||
#include "content/public/browser/browsing_data_remover_delegate.h"
|
||||
#include "content/public/browser/client_hints_controller_delegate.h"
|
||||
#include "content/public/browser/content_browser_client.h"
|
||||
#include "content/public/browser/dips_delegate.h"
|
||||
#include "content/public/browser/download_manager.h"
|
||||
#include "content/public/browser/storage_partition.h"
|
||||
#include "content/public/browser/storage_partition_config.h"
|
||||
#include "content/public/common/content_client.h"
|
||||
#include "mojo/public/cpp/bindings/callback_helpers.h"
|
||||
#include "services/network/public/cpp/features.h"
|
||||
#include "services/network/public/mojom/clear_data_filter.mojom.h"
|
||||
@ -124,6 +128,7 @@ BrowsingDataRemoverImpl::BrowsingDataRemoverImpl(
|
||||
storage_partition_config_(std::nullopt),
|
||||
is_removing_(false) {
|
||||
DCHECK(browser_context_);
|
||||
dips_delegate_ = GetContentClient()->browser()->CreateDipsDelegate();
|
||||
}
|
||||
|
||||
BrowsingDataRemoverImpl::~BrowsingDataRemoverImpl() {
|
||||
@ -678,6 +683,31 @@ void BrowsingDataRemoverImpl::RemoveImpl(
|
||||
}
|
||||
}
|
||||
|
||||
// Different types of DIPS events are cleared for DATA_TYPE_HISTORY and
|
||||
// DATA_TYPE_COOKIES.
|
||||
DIPSEventRemovalType dips_mask = DIPSEventRemovalType::kNone;
|
||||
if ((remove_mask & DATA_TYPE_COOKIES) &&
|
||||
!filter_builder->PartitionedCookiesOnly()) {
|
||||
// If there's no delegate, delete everything whenever the user is deleting
|
||||
// cookies.
|
||||
dips_mask |= dips_delegate_ ? DIPSEventRemovalType::kStorage
|
||||
: DIPSEventRemovalType::kAll;
|
||||
}
|
||||
// If there's a delegate, ask it whether to delete DIPS history.
|
||||
if (dips_delegate_ &&
|
||||
dips_delegate_->ShouldDeleteInteractionRecords(remove_mask)) {
|
||||
dips_mask |= DIPSEventRemovalType::kHistory;
|
||||
}
|
||||
|
||||
if (dips_mask != DIPSEventRemovalType::kNone) {
|
||||
if (DIPSServiceImpl* dips_service =
|
||||
DIPSServiceImpl::Get(browser_context_)) {
|
||||
dips_service->RemoveEvents(delete_begin_, delete_end_,
|
||||
filter_builder->BuildNetworkServiceFilter(),
|
||||
dips_mask);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Embedder data.
|
||||
if (embedder_delegate_) {
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
|
||||
@ -31,6 +32,7 @@ namespace content {
|
||||
|
||||
class BrowserContext;
|
||||
class BrowsingDataFilterBuilder;
|
||||
class DipsDelegate;
|
||||
class StoragePartition;
|
||||
|
||||
class CONTENT_EXPORT BrowsingDataRemoverImpl
|
||||
@ -245,6 +247,8 @@ class CONTENT_EXPORT BrowsingDataRemoverImpl
|
||||
// A delegate to delete the embedder-specific data. Owned by the embedder.
|
||||
raw_ptr<BrowsingDataRemoverDelegate, DanglingUntriaged> embedder_delegate_;
|
||||
|
||||
std::unique_ptr<DipsDelegate> dips_delegate_;
|
||||
|
||||
// Start time to delete from.
|
||||
base::Time delete_begin_;
|
||||
|
||||
|
@ -29,9 +29,16 @@
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/task/cancelable_task_tracker.h"
|
||||
#include "base/task/single_thread_task_runner.h"
|
||||
#include "base/test/bind.h"
|
||||
#include "base/test/gmock_callback_support.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/test/test_future.h"
|
||||
#include "base/threading/sequence_bound.h"
|
||||
#include "base/time/time.h"
|
||||
#include "content/browser/dips/dips_service_impl.h"
|
||||
#include "content/browser/dips/dips_storage.h"
|
||||
#include "content/browser/dips/dips_test_utils.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
@ -43,6 +50,7 @@
|
||||
#include "content/public/browser/storage_partition.h"
|
||||
#include "content/public/browser/storage_partition_config.h"
|
||||
#include "content/public/browser/storage_usage_info.h"
|
||||
#include "content/public/common/content_client.h"
|
||||
#include "content/public/test/browser_task_environment.h"
|
||||
#include "content/public/test/browsing_data_remover_test_util.h"
|
||||
#include "content/public/test/mock_download_manager.h"
|
||||
@ -366,7 +374,15 @@ class RemoveDownloadsTester {
|
||||
|
||||
class BrowsingDataRemoverImplTest : public testing::Test {
|
||||
public:
|
||||
BrowsingDataRemoverImplTest() : browser_context_(new TestBrowserContext()) {
|
||||
BrowsingDataRemoverImplTest() : BrowsingDataRemoverImplTest(nullptr) {}
|
||||
|
||||
explicit BrowsingDataRemoverImplTest(
|
||||
std::unique_ptr<ContentBrowserClient> browser_client)
|
||||
: browser_client_(std::move(browser_client)) {
|
||||
if (browser_client_) {
|
||||
browser_client_setting_.emplace(browser_client_.get());
|
||||
}
|
||||
browser_context_ = std::make_unique<TestBrowserContext>();
|
||||
remover_ = static_cast<BrowsingDataRemoverImpl*>(
|
||||
browser_context_->GetBrowsingDataRemover());
|
||||
|
||||
@ -495,6 +511,8 @@ class BrowsingDataRemoverImplTest : public testing::Test {
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<ContentBrowserClient> browser_client_;
|
||||
std::optional<ScopedContentBrowserClientSetting> browser_client_setting_;
|
||||
std::unique_ptr<StoragePartitionRemovalTestStoragePartition>
|
||||
storage_partition_;
|
||||
|
||||
@ -2114,4 +2132,168 @@ TEST_F(BrowsingDataRemoverImplSharedStorageTest,
|
||||
mock_policy()));
|
||||
}
|
||||
|
||||
class RemoveDIPSEventsTester {
|
||||
public:
|
||||
explicit RemoveDIPSEventsTester(BrowserContext* browser_context) {
|
||||
storage_ = DIPSServiceImpl::Get(browser_context)->storage();
|
||||
}
|
||||
|
||||
void WriteEventTimes(GURL url,
|
||||
std::optional<base::Time> storage_time,
|
||||
std::optional<base::Time> interaction_time) {
|
||||
if (storage_time.has_value()) {
|
||||
storage_->AsyncCall(&DIPSStorage::RecordStorage)
|
||||
.WithArgs(url, storage_time.value(), DIPSCookieMode::kBlock3PC);
|
||||
}
|
||||
if (interaction_time.has_value()) {
|
||||
storage_->AsyncCall(&DIPSStorage::RecordInteraction)
|
||||
.WithArgs(url, interaction_time.value(), DIPSCookieMode::kBlock3PC);
|
||||
}
|
||||
storage_->FlushPostedTasksForTesting();
|
||||
}
|
||||
|
||||
std::optional<StateValue> ReadStateValue(GURL url) {
|
||||
base::test::TestFuture<DIPSState> dips_state;
|
||||
storage_->AsyncCall(&DIPSStorage::Read)
|
||||
.WithArgs(url)
|
||||
.Then(dips_state.GetCallback());
|
||||
|
||||
const DIPSState& state = dips_state.Get();
|
||||
if (!state.was_loaded()) {
|
||||
return {};
|
||||
}
|
||||
return state.ToStateValue();
|
||||
}
|
||||
|
||||
private:
|
||||
raw_ptr<base::SequenceBound<DIPSStorage>> storage_;
|
||||
};
|
||||
|
||||
class BrowsingDataRemoverImplDipsTest : public BrowsingDataRemoverImplTest {
|
||||
public:
|
||||
BrowsingDataRemoverImplDipsTest()
|
||||
: BrowsingDataRemoverImplTest(
|
||||
std::make_unique<TpcBlockingBrowserClient>()) {}
|
||||
};
|
||||
|
||||
TEST_F(BrowsingDataRemoverImplDipsTest, RemoveDIPSEventsForLastHour) {
|
||||
RemoveDIPSEventsTester tester(GetBrowserContext());
|
||||
GURL url1("https://example1.com");
|
||||
GURL url2("https://example2.com");
|
||||
base::Time two_hours_ago = base::Time::Now() - base::Hours(2);
|
||||
|
||||
tester.WriteEventTimes(url1, /*storage_time=*/base::Time::Now(),
|
||||
/*interaction_time=*/std::nullopt);
|
||||
tester.WriteEventTimes(url2, /*storage_time=*/std::nullopt,
|
||||
/*interaction_time=*/two_hours_ago);
|
||||
|
||||
{
|
||||
std::optional<StateValue> state_val1 = tester.ReadStateValue(url1);
|
||||
std::optional<StateValue> state_val2 = tester.ReadStateValue(url2);
|
||||
|
||||
ASSERT_TRUE(state_val1.has_value());
|
||||
EXPECT_TRUE(state_val1->site_storage_times.has_value());
|
||||
ASSERT_TRUE(state_val2.has_value());
|
||||
EXPECT_TRUE(state_val2->user_interaction_times.has_value());
|
||||
}
|
||||
|
||||
uint64_t remove_mask = TpcBlockingBrowserClient::DATA_TYPE_HISTORY |
|
||||
content::BrowsingDataRemover::DATA_TYPE_COOKIES;
|
||||
|
||||
BlockUntilBrowsingDataRemoved(AnHourAgo(), base::Time::Max(), remove_mask,
|
||||
false);
|
||||
|
||||
{
|
||||
std::optional<StateValue> state_val1 = tester.ReadStateValue(url1);
|
||||
std::optional<StateValue> state_val2 = tester.ReadStateValue(url2);
|
||||
|
||||
EXPECT_FALSE(state_val1.has_value());
|
||||
ASSERT_TRUE(state_val2.has_value());
|
||||
EXPECT_TRUE(state_val2->user_interaction_times.has_value());
|
||||
}
|
||||
|
||||
BlockUntilBrowsingDataRemoved(base::Time(), base::Time::Max(), remove_mask,
|
||||
false);
|
||||
|
||||
{
|
||||
std::optional<StateValue> state_val1 = tester.ReadStateValue(url1);
|
||||
std::optional<StateValue> state_val2 = tester.ReadStateValue(url2);
|
||||
|
||||
EXPECT_FALSE(state_val1.has_value());
|
||||
EXPECT_FALSE(state_val2.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BrowsingDataRemoverImplDipsTest, RemoveDIPSEventsByType) {
|
||||
RemoveDIPSEventsTester tester(GetBrowserContext());
|
||||
GURL url1("https://example1.com");
|
||||
GURL url2("https://example2.com");
|
||||
GURL url3("https://example3.com");
|
||||
base::Time two_hours_ago = base::Time::Now() - base::Hours(2);
|
||||
|
||||
tester.WriteEventTimes(url1, /*storage_time=*/base::Time::Now(),
|
||||
/*interaction_time=*/std::nullopt);
|
||||
tester.WriteEventTimes(url2, /*storage_time=*/std::nullopt,
|
||||
/*interaction_time=*/base::Time::Now());
|
||||
tester.WriteEventTimes(url3, /*storage_time=*/base::Time::Now(),
|
||||
/*interaction_time=*/two_hours_ago);
|
||||
|
||||
{
|
||||
std::optional<StateValue> state_val1 = tester.ReadStateValue(url1);
|
||||
std::optional<StateValue> state_val2 = tester.ReadStateValue(url2);
|
||||
std::optional<StateValue> state_val3 = tester.ReadStateValue(url3);
|
||||
|
||||
ASSERT_TRUE(state_val1.has_value());
|
||||
EXPECT_TRUE(state_val1->site_storage_times.has_value());
|
||||
|
||||
ASSERT_TRUE(state_val2.has_value());
|
||||
EXPECT_TRUE(state_val2->user_interaction_times.has_value());
|
||||
|
||||
ASSERT_TRUE(state_val3.has_value());
|
||||
EXPECT_TRUE(state_val3->site_storage_times.has_value());
|
||||
EXPECT_TRUE(state_val3->user_interaction_times.has_value());
|
||||
}
|
||||
|
||||
// Remove interaction events from DIPS Storage.
|
||||
BlockUntilBrowsingDataRemoved(AnHourAgo(), base::Time::Max(),
|
||||
TpcBlockingBrowserClient::DATA_TYPE_HISTORY,
|
||||
false);
|
||||
|
||||
// Verify the interaction event for url2 has been removed.
|
||||
{
|
||||
std::optional<StateValue> state_val1 = tester.ReadStateValue(url1);
|
||||
std::optional<StateValue> state_val2 = tester.ReadStateValue(url2);
|
||||
std::optional<StateValue> state_val3 = tester.ReadStateValue(url3);
|
||||
|
||||
ASSERT_TRUE(state_val1.has_value());
|
||||
EXPECT_TRUE(state_val1->site_storage_times.has_value());
|
||||
|
||||
EXPECT_FALSE(state_val2.has_value());
|
||||
|
||||
ASSERT_TRUE(state_val3.has_value());
|
||||
EXPECT_TRUE(state_val3->site_storage_times.has_value());
|
||||
EXPECT_TRUE(state_val3->user_interaction_times.has_value());
|
||||
}
|
||||
|
||||
// Remove storage events from DIPS Storage.
|
||||
BlockUntilBrowsingDataRemoved(AnHourAgo(), base::Time::Max(),
|
||||
content::BrowsingDataRemover::DATA_TYPE_COOKIES,
|
||||
false);
|
||||
|
||||
// Verify the storage events for url1 and url3 have been removed.
|
||||
{
|
||||
std::optional<StateValue> state_val1 = tester.ReadStateValue(url1);
|
||||
std::optional<StateValue> state_val2 = tester.ReadStateValue(url2);
|
||||
std::optional<StateValue> state_val3 = tester.ReadStateValue(url3);
|
||||
|
||||
EXPECT_FALSE(state_val1.has_value());
|
||||
|
||||
EXPECT_FALSE(state_val2.has_value());
|
||||
|
||||
ASSERT_TRUE(state_val3.has_value());
|
||||
EXPECT_FALSE(state_val3->site_storage_times.has_value());
|
||||
EXPECT_TRUE(state_val3->user_interaction_times.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace content
|
||||
|
53
content/browser/dips/BUILD.gn
Normal file
53
content/browser/dips/BUILD.gn
Normal file
@ -0,0 +1,53 @@
|
||||
# Copyright 2024 The Chromium Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
source_set("unit_tests") {
|
||||
testonly = true
|
||||
|
||||
# See content_unittests for justification.
|
||||
if (is_component_build) {
|
||||
check_includes = false
|
||||
}
|
||||
|
||||
sources = [
|
||||
"cookie_access_filter_unittest.cc",
|
||||
"dips_bounce_detector_unittest.cc",
|
||||
"dips_database_migrator_unittest.cc",
|
||||
"dips_database_unittest.cc",
|
||||
"dips_service_unittest.cc",
|
||||
"dips_storage_unittest.cc",
|
||||
"dips_utils_unittest.cc",
|
||||
"persistent_repeating_timer_unittest.cc",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":golden_dbs_bundle_data",
|
||||
"//base",
|
||||
"//base/test:test_support",
|
||||
"//components/site_engagement/content",
|
||||
"//components/ukm:test_support",
|
||||
"//content/browser:for_content_tests",
|
||||
"//content/test:browsertest_support",
|
||||
"//content/test:test_support",
|
||||
"//sql:test_support",
|
||||
"//testing/gtest",
|
||||
"//url",
|
||||
]
|
||||
|
||||
data = [ "//content/test/data/dips/v1.sql" ]
|
||||
}
|
||||
|
||||
bundle_data("golden_dbs_bundle_data") {
|
||||
visibility = [ ":unit_tests" ]
|
||||
testonly = true
|
||||
sources = [
|
||||
"//content/test/data/dips/v1.sql",
|
||||
"//content/test/data/dips/v2.sql",
|
||||
"//content/test/data/dips/v3.sql",
|
||||
"//content/test/data/dips/v4.sql",
|
||||
"//content/test/data/dips/v5.sql",
|
||||
]
|
||||
outputs = [ "{{bundle_resources_dir}}/" +
|
||||
"{{source_root_relative_dir}}/{{source_file_part}}" ]
|
||||
}
|
5
content/browser/dips/DEPS
Normal file
5
content/browser/dips/DEPS
Normal file
@ -0,0 +1,5 @@
|
||||
specific_include_rules = {
|
||||
"dips_bounce_detector_browsertest\.cc": [
|
||||
"+device/fido",
|
||||
],
|
||||
}
|
7
content/browser/dips/DIR_METADATA
Normal file
7
content/browser/dips/DIR_METADATA
Normal file
@ -0,0 +1,7 @@
|
||||
monorail: {
|
||||
component: "Privacy>NavTracking"
|
||||
}
|
||||
team_email: "dc-komics@google.com"
|
||||
buganizer_public: {
|
||||
component_id: 1456144
|
||||
}
|
7
content/browser/dips/OWNERS
Normal file
7
content/browser/dips/OWNERS
Normal file
@ -0,0 +1,7 @@
|
||||
amaliev@chromium.org
|
||||
bcl@chromium.org
|
||||
jdh@chromium.org
|
||||
njeunje@chromium.org
|
||||
rtarpine@chromium.org
|
||||
svend@chromium.org
|
||||
wanderview@chromium.org
|
33
content/browser/dips/README.md
Normal file
33
content/browser/dips/README.md
Normal file
@ -0,0 +1,33 @@
|
||||
## **DIPS (Detect/Delete Incidental Party State)**
|
||||
|
||||
This directory contains the code for Chromium's DIPS (Detect/Delete Incidental Party State) feature, known externally as Bounce Tracking Mitigations (BTM). DIPS aims to mitigate the privacy impact of "bounce tracking", a technique used to track users across websites without relying on third-party cookies.
|
||||
|
||||
**What is bounce tracking?**
|
||||
|
||||
Bounce tracking involves redirecting users through a tracker website, often without their knowledge or interaction. This allows the tracker to set or access first-party cookies, effectively circumventing third-party cookie restrictions and user privacy preferences.
|
||||
|
||||
**How does DIPS work?**
|
||||
|
||||
DIPS detects potential bounce tracking by analyzing website behavior, such as:
|
||||
|
||||
- Short dwell times on a website before redirecting.
|
||||
- Programmatic redirects (as opposed to user-initiated ones).
|
||||
- Writing to storage (cookies, etc.) before redirecting.
|
||||
|
||||
If DIPS determines that a website is likely involved in bounce tracking, and there's no indication of legitimate user interaction with the site, it automatically deletes the site's storage (eTLD+1).
|
||||
|
||||
**Goals of DIPS:**
|
||||
|
||||
- **Reduce cross-site tracking:*- Limit the ability of bounce trackers to identify and track users across different contexts.
|
||||
- **Protect user privacy:*- Prevent bounce tracking from circumventing third-party cookie restrictions.
|
||||
- **Maintain compatibility:*- Avoid disrupting legitimate use cases like federated logins and payment flows that rely on redirects.
|
||||
- **Adaptability:*- Mitigate tracking by short-lived domains that may evade traditional blocklist-based approaches.
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- **Replacing third-party cookie blocking:*- DIPS is primarily designed for environments where third-party cookies are already restricted.
|
||||
- **Mitigating tracking by sites with significant first-party activity:*- DIPS focuses on incidental parties (sites without meaningful user interaction) and may not be effective against sites with substantial first-party engagement.
|
||||
|
||||
**Further Reading:**
|
||||
|
||||
- Explainer: https://github.com/privacycg/nav-tracking-mitigations/blob/main/bounce-tracking-explainer.md
|
@ -2,15 +2,15 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/cookie_access_filter.h"
|
||||
#include "content/browser/dips/cookie_access_filter.h"
|
||||
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
|
||||
CookieAccessFilter::CookieAccessFilter() = default;
|
||||
CookieAccessFilter::~CookieAccessFilter() = default;
|
||||
|
||||
void CookieAccessFilter::AddAccess(const GURL& url, CookieOperation op) {
|
||||
SiteDataAccessType t = ToSiteDataAccessType(op);
|
||||
DIPSDataAccessType t = ToDIPSDataAccessType(op);
|
||||
if (!accesses_.empty() && accesses_.back().url == url) {
|
||||
// Coalesce accesses for the same URL. They may have come from separate
|
||||
// visits, but we can't distinguish them from redundant calls, which are
|
||||
@ -34,11 +34,11 @@ void CookieAccessFilter::AddAccess(const GURL& url, CookieOperation op) {
|
||||
// multiple times, even consecutively, in a single redirect chain.
|
||||
//
|
||||
// To handle that corner case (imperfectly), if the same URL appears multiple
|
||||
// times in a row, it will get the same SiteDataAccessType for all of them.
|
||||
// times in a row, it will get the same DIPSDataAccessType for all of them.
|
||||
bool CookieAccessFilter::Filter(const std::vector<GURL>& urls,
|
||||
std::vector<SiteDataAccessType>* result) const {
|
||||
std::vector<DIPSDataAccessType>* result) const {
|
||||
result->clear();
|
||||
result->resize(urls.size(), SiteDataAccessType::kNone);
|
||||
result->resize(urls.size(), DIPSDataAccessType::kNone);
|
||||
|
||||
size_t url_idx = 0;
|
||||
size_t access_idx = 0;
|
||||
@ -82,6 +82,6 @@ bool CookieAccessFilter::Filter(const std::vector<GURL>& urls,
|
||||
}
|
||||
|
||||
// Otherwise, fill the entire result vector with kUnknown and return false.
|
||||
std::fill(result->begin(), result->end(), SiteDataAccessType::kUnknown);
|
||||
std::fill(result->begin(), result->end(), DIPSDataAccessType::kUnknown);
|
||||
return false;
|
||||
}
|
@ -2,19 +2,20 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_DIPS_COOKIE_ACCESS_FILTER_H_
|
||||
#define CHROME_BROWSER_DIPS_COOKIE_ACCESS_FILTER_H_
|
||||
#ifndef CONTENT_BROWSER_DIPS_COOKIE_ACCESS_FILTER_H_
|
||||
#define CONTENT_BROWSER_DIPS_COOKIE_ACCESS_FILTER_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/common/content_export.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
// Filters a chain of URLs to the ones which accessed cookies.
|
||||
//
|
||||
// Intended for use by a WebContentsObserver which overrides OnCookiesAccessed
|
||||
// and DidFinishNavigation.
|
||||
class CookieAccessFilter {
|
||||
class CONTENT_EXPORT CookieAccessFilter {
|
||||
public:
|
||||
CookieAccessFilter();
|
||||
~CookieAccessFilter();
|
||||
@ -29,7 +30,7 @@ class CookieAccessFilter {
|
||||
// kUnknown. (Note: this depends on the order of previous calls to
|
||||
// AddAccess()).
|
||||
bool Filter(const std::vector<GURL>& urls,
|
||||
std::vector<SiteDataAccessType>* result) const;
|
||||
std::vector<DIPSDataAccessType>* result) const;
|
||||
|
||||
// Returns true iff AddAccess() has never been called.
|
||||
bool is_empty() const { return accesses_.empty(); }
|
||||
@ -37,7 +38,7 @@ class CookieAccessFilter {
|
||||
private:
|
||||
struct CookieAccess {
|
||||
GURL url;
|
||||
SiteDataAccessType type = SiteDataAccessType::kUnknown;
|
||||
DIPSDataAccessType type = DIPSDataAccessType::kUnknown;
|
||||
};
|
||||
|
||||
// We use a vector rather than a set of URLs because order can matter. If the
|
||||
@ -46,4 +47,4 @@ class CookieAccessFilter {
|
||||
std::vector<CookieAccess> accesses_;
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_DIPS_COOKIE_ACCESS_FILTER_H_
|
||||
#endif // CONTENT_BROWSER_DIPS_COOKIE_ACCESS_FILTER_H_
|
@ -2,29 +2,29 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/cookie_access_filter.h"
|
||||
#include "content/browser/dips/cookie_access_filter.h"
|
||||
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
TEST(CookieAccessType, BitwiseOrOperator) {
|
||||
ASSERT_EQ(SiteDataAccessType::kRead,
|
||||
SiteDataAccessType::kNone | SiteDataAccessType::kRead);
|
||||
ASSERT_EQ(DIPSDataAccessType::kRead,
|
||||
DIPSDataAccessType::kNone | DIPSDataAccessType::kRead);
|
||||
|
||||
ASSERT_EQ(SiteDataAccessType::kWrite,
|
||||
SiteDataAccessType::kNone | SiteDataAccessType::kWrite);
|
||||
ASSERT_EQ(DIPSDataAccessType::kWrite,
|
||||
DIPSDataAccessType::kNone | DIPSDataAccessType::kWrite);
|
||||
|
||||
ASSERT_EQ(SiteDataAccessType::kReadWrite,
|
||||
SiteDataAccessType::kRead | SiteDataAccessType::kWrite);
|
||||
ASSERT_EQ(DIPSDataAccessType::kReadWrite,
|
||||
DIPSDataAccessType::kRead | DIPSDataAccessType::kWrite);
|
||||
|
||||
ASSERT_EQ(SiteDataAccessType::kUnknown,
|
||||
SiteDataAccessType::kUnknown | SiteDataAccessType::kNone);
|
||||
ASSERT_EQ(DIPSDataAccessType::kUnknown,
|
||||
DIPSDataAccessType::kUnknown | DIPSDataAccessType::kNone);
|
||||
|
||||
ASSERT_EQ(SiteDataAccessType::kUnknown,
|
||||
SiteDataAccessType::kUnknown | SiteDataAccessType::kRead);
|
||||
ASSERT_EQ(DIPSDataAccessType::kUnknown,
|
||||
DIPSDataAccessType::kUnknown | DIPSDataAccessType::kRead);
|
||||
|
||||
ASSERT_EQ(SiteDataAccessType::kUnknown,
|
||||
SiteDataAccessType::kUnknown | SiteDataAccessType::kWrite);
|
||||
ASSERT_EQ(DIPSDataAccessType::kUnknown,
|
||||
DIPSDataAccessType::kUnknown | DIPSDataAccessType::kWrite);
|
||||
}
|
||||
|
||||
TEST(CookieAccessFilter, NoAccesses) {
|
||||
@ -32,10 +32,10 @@ TEST(CookieAccessFilter, NoAccesses) {
|
||||
GURL url2("http://google.com");
|
||||
CookieAccessFilter filter;
|
||||
|
||||
std::vector<SiteDataAccessType> result;
|
||||
std::vector<DIPSDataAccessType> result;
|
||||
ASSERT_TRUE(filter.Filter({url1, url2}, &result));
|
||||
EXPECT_THAT(result, testing::ElementsAre(SiteDataAccessType::kNone,
|
||||
SiteDataAccessType::kNone));
|
||||
EXPECT_THAT(result, testing::ElementsAre(DIPSDataAccessType::kNone,
|
||||
DIPSDataAccessType::kNone));
|
||||
}
|
||||
|
||||
TEST(CookieAccessFilter, OneRead_Former) {
|
||||
@ -44,10 +44,10 @@ TEST(CookieAccessFilter, OneRead_Former) {
|
||||
CookieAccessFilter filter;
|
||||
filter.AddAccess(url1, CookieOperation::kRead);
|
||||
|
||||
std::vector<SiteDataAccessType> result;
|
||||
std::vector<DIPSDataAccessType> result;
|
||||
ASSERT_TRUE(filter.Filter({url1, url2}, &result));
|
||||
EXPECT_THAT(result, testing::ElementsAre(SiteDataAccessType::kRead,
|
||||
SiteDataAccessType::kNone));
|
||||
EXPECT_THAT(result, testing::ElementsAre(DIPSDataAccessType::kRead,
|
||||
DIPSDataAccessType::kNone));
|
||||
}
|
||||
|
||||
TEST(CookieAccessFilter, OneRead_Latter) {
|
||||
@ -56,10 +56,10 @@ TEST(CookieAccessFilter, OneRead_Latter) {
|
||||
CookieAccessFilter filter;
|
||||
filter.AddAccess(url2, CookieOperation::kRead);
|
||||
|
||||
std::vector<SiteDataAccessType> result;
|
||||
std::vector<DIPSDataAccessType> result;
|
||||
ASSERT_TRUE(filter.Filter({url1, url2}, &result));
|
||||
EXPECT_THAT(result, testing::ElementsAre(SiteDataAccessType::kNone,
|
||||
SiteDataAccessType::kRead));
|
||||
EXPECT_THAT(result, testing::ElementsAre(DIPSDataAccessType::kNone,
|
||||
DIPSDataAccessType::kRead));
|
||||
}
|
||||
|
||||
TEST(CookieAccessFilter, OneWrite) {
|
||||
@ -68,10 +68,10 @@ TEST(CookieAccessFilter, OneWrite) {
|
||||
CookieAccessFilter filter;
|
||||
filter.AddAccess(url2, CookieOperation::kChange);
|
||||
|
||||
std::vector<SiteDataAccessType> result;
|
||||
std::vector<DIPSDataAccessType> result;
|
||||
ASSERT_TRUE(filter.Filter({url1, url2}, &result));
|
||||
EXPECT_THAT(result, testing::ElementsAre(SiteDataAccessType::kNone,
|
||||
SiteDataAccessType::kWrite));
|
||||
EXPECT_THAT(result, testing::ElementsAre(DIPSDataAccessType::kNone,
|
||||
DIPSDataAccessType::kWrite));
|
||||
}
|
||||
|
||||
TEST(CookieAccessFilter, UnexpectedURL) {
|
||||
@ -80,10 +80,10 @@ TEST(CookieAccessFilter, UnexpectedURL) {
|
||||
CookieAccessFilter filter;
|
||||
filter.AddAccess(GURL("http://other.com"), CookieOperation::kRead);
|
||||
|
||||
std::vector<SiteDataAccessType> result;
|
||||
std::vector<DIPSDataAccessType> result;
|
||||
ASSERT_FALSE(filter.Filter({url1, url2}, &result));
|
||||
EXPECT_THAT(result, testing::ElementsAre(SiteDataAccessType::kUnknown,
|
||||
SiteDataAccessType::kUnknown));
|
||||
EXPECT_THAT(result, testing::ElementsAre(DIPSDataAccessType::kUnknown,
|
||||
DIPSDataAccessType::kUnknown));
|
||||
}
|
||||
|
||||
TEST(CookieAccessFilter, TwoReads) {
|
||||
@ -93,10 +93,10 @@ TEST(CookieAccessFilter, TwoReads) {
|
||||
filter.AddAccess(url1, CookieOperation::kRead);
|
||||
filter.AddAccess(url2, CookieOperation::kRead);
|
||||
|
||||
std::vector<SiteDataAccessType> result;
|
||||
std::vector<DIPSDataAccessType> result;
|
||||
ASSERT_TRUE(filter.Filter({url1, url2}, &result));
|
||||
EXPECT_THAT(result, testing::ElementsAre(SiteDataAccessType::kRead,
|
||||
SiteDataAccessType::kRead));
|
||||
EXPECT_THAT(result, testing::ElementsAre(DIPSDataAccessType::kRead,
|
||||
DIPSDataAccessType::kRead));
|
||||
}
|
||||
|
||||
TEST(CookieAccessFilter, CoalesceReadBeforeWrite) {
|
||||
@ -107,10 +107,10 @@ TEST(CookieAccessFilter, CoalesceReadBeforeWrite) {
|
||||
filter.AddAccess(url1, CookieOperation::kChange);
|
||||
filter.AddAccess(url2, CookieOperation::kRead);
|
||||
|
||||
std::vector<SiteDataAccessType> result;
|
||||
std::vector<DIPSDataAccessType> result;
|
||||
ASSERT_TRUE(filter.Filter({url1, url2}, &result));
|
||||
EXPECT_THAT(result, testing::ElementsAre(SiteDataAccessType::kReadWrite,
|
||||
SiteDataAccessType::kRead));
|
||||
EXPECT_THAT(result, testing::ElementsAre(DIPSDataAccessType::kReadWrite,
|
||||
DIPSDataAccessType::kRead));
|
||||
}
|
||||
|
||||
TEST(CookieAccessFilter, CoalesceReadBeforeWrite_Repeated) {
|
||||
@ -121,11 +121,11 @@ TEST(CookieAccessFilter, CoalesceReadBeforeWrite_Repeated) {
|
||||
filter.AddAccess(url1, CookieOperation::kChange);
|
||||
filter.AddAccess(url2, CookieOperation::kRead);
|
||||
|
||||
std::vector<SiteDataAccessType> result;
|
||||
std::vector<DIPSDataAccessType> result;
|
||||
ASSERT_TRUE(filter.Filter({url1, url1, url2}, &result));
|
||||
EXPECT_THAT(result, testing::ElementsAre(SiteDataAccessType::kReadWrite,
|
||||
SiteDataAccessType::kReadWrite,
|
||||
SiteDataAccessType::kRead));
|
||||
EXPECT_THAT(result, testing::ElementsAre(DIPSDataAccessType::kReadWrite,
|
||||
DIPSDataAccessType::kReadWrite,
|
||||
DIPSDataAccessType::kRead));
|
||||
}
|
||||
|
||||
TEST(CookieAccessFilter, CoalesceWrites) {
|
||||
@ -136,10 +136,10 @@ TEST(CookieAccessFilter, CoalesceWrites) {
|
||||
filter.AddAccess(url1, CookieOperation::kChange);
|
||||
filter.AddAccess(url2, CookieOperation::kRead);
|
||||
|
||||
std::vector<SiteDataAccessType> result;
|
||||
std::vector<DIPSDataAccessType> result;
|
||||
ASSERT_TRUE(filter.Filter({url1, url2}, &result));
|
||||
EXPECT_THAT(result, testing::ElementsAre(SiteDataAccessType::kWrite,
|
||||
SiteDataAccessType::kRead));
|
||||
EXPECT_THAT(result, testing::ElementsAre(DIPSDataAccessType::kWrite,
|
||||
DIPSDataAccessType::kRead));
|
||||
}
|
||||
|
||||
TEST(CookieAccessFilter, CoalesceWrites_Repeated) {
|
||||
@ -150,11 +150,11 @@ TEST(CookieAccessFilter, CoalesceWrites_Repeated) {
|
||||
filter.AddAccess(url1, CookieOperation::kChange);
|
||||
filter.AddAccess(url2, CookieOperation::kRead);
|
||||
|
||||
std::vector<SiteDataAccessType> result;
|
||||
std::vector<DIPSDataAccessType> result;
|
||||
ASSERT_TRUE(filter.Filter({url1, url1, url2}, &result));
|
||||
EXPECT_THAT(result, testing::ElementsAre(SiteDataAccessType::kWrite,
|
||||
SiteDataAccessType::kWrite,
|
||||
SiteDataAccessType::kRead));
|
||||
EXPECT_THAT(result, testing::ElementsAre(DIPSDataAccessType::kWrite,
|
||||
DIPSDataAccessType::kWrite,
|
||||
DIPSDataAccessType::kRead));
|
||||
}
|
||||
|
||||
TEST(CookieAccessFilter, CoalesceReads) {
|
||||
@ -165,10 +165,10 @@ TEST(CookieAccessFilter, CoalesceReads) {
|
||||
filter.AddAccess(url1, CookieOperation::kRead);
|
||||
filter.AddAccess(url2, CookieOperation::kRead);
|
||||
|
||||
std::vector<SiteDataAccessType> result;
|
||||
std::vector<DIPSDataAccessType> result;
|
||||
ASSERT_TRUE(filter.Filter({url1, url2}, &result));
|
||||
EXPECT_THAT(result, testing::ElementsAre(SiteDataAccessType::kRead,
|
||||
SiteDataAccessType::kRead));
|
||||
EXPECT_THAT(result, testing::ElementsAre(DIPSDataAccessType::kRead,
|
||||
DIPSDataAccessType::kRead));
|
||||
}
|
||||
|
||||
TEST(CookieAccessFilter, CoalesceReads_Repeated) {
|
||||
@ -179,11 +179,11 @@ TEST(CookieAccessFilter, CoalesceReads_Repeated) {
|
||||
filter.AddAccess(url1, CookieOperation::kRead);
|
||||
filter.AddAccess(url2, CookieOperation::kRead);
|
||||
|
||||
std::vector<SiteDataAccessType> result;
|
||||
std::vector<DIPSDataAccessType> result;
|
||||
ASSERT_TRUE(filter.Filter({url1, url1, url2}, &result));
|
||||
EXPECT_THAT(result, testing::ElementsAre(SiteDataAccessType::kRead,
|
||||
SiteDataAccessType::kRead,
|
||||
SiteDataAccessType::kRead));
|
||||
EXPECT_THAT(result, testing::ElementsAre(DIPSDataAccessType::kRead,
|
||||
DIPSDataAccessType::kRead,
|
||||
DIPSDataAccessType::kRead));
|
||||
}
|
||||
|
||||
TEST(CookieAccessFilter, CoalesceWriteBeforeRead) {
|
||||
@ -194,10 +194,10 @@ TEST(CookieAccessFilter, CoalesceWriteBeforeRead) {
|
||||
filter.AddAccess(url1, CookieOperation::kRead);
|
||||
filter.AddAccess(url2, CookieOperation::kRead);
|
||||
|
||||
std::vector<SiteDataAccessType> result;
|
||||
std::vector<DIPSDataAccessType> result;
|
||||
ASSERT_TRUE(filter.Filter({url1, url2}, &result));
|
||||
EXPECT_THAT(result, testing::ElementsAre(SiteDataAccessType::kReadWrite,
|
||||
SiteDataAccessType::kRead));
|
||||
EXPECT_THAT(result, testing::ElementsAre(DIPSDataAccessType::kReadWrite,
|
||||
DIPSDataAccessType::kRead));
|
||||
}
|
||||
|
||||
TEST(CookieAccessFilter, CoalesceWriteBeforeRead_Repeated) {
|
||||
@ -208,11 +208,11 @@ TEST(CookieAccessFilter, CoalesceWriteBeforeRead_Repeated) {
|
||||
filter.AddAccess(url1, CookieOperation::kRead);
|
||||
filter.AddAccess(url2, CookieOperation::kRead);
|
||||
|
||||
std::vector<SiteDataAccessType> result;
|
||||
std::vector<DIPSDataAccessType> result;
|
||||
ASSERT_TRUE(filter.Filter({url1, url1, url2}, &result));
|
||||
EXPECT_THAT(result, testing::ElementsAre(SiteDataAccessType::kReadWrite,
|
||||
SiteDataAccessType::kReadWrite,
|
||||
SiteDataAccessType::kRead));
|
||||
EXPECT_THAT(result, testing::ElementsAre(DIPSDataAccessType::kReadWrite,
|
||||
DIPSDataAccessType::kReadWrite,
|
||||
DIPSDataAccessType::kRead));
|
||||
}
|
||||
|
||||
TEST(CookieAccessFilter, SameURLTwiceWithDifferentAccessTypes) {
|
||||
@ -224,9 +224,9 @@ TEST(CookieAccessFilter, SameURLTwiceWithDifferentAccessTypes) {
|
||||
filter.AddAccess(url2, CookieOperation::kChange);
|
||||
filter.AddAccess(url1, CookieOperation::kRead);
|
||||
|
||||
std::vector<SiteDataAccessType> result;
|
||||
std::vector<DIPSDataAccessType> result;
|
||||
ASSERT_TRUE(filter.Filter({url1, url2, url1}, &result));
|
||||
EXPECT_THAT(result, testing::ElementsAre(SiteDataAccessType::kWrite,
|
||||
SiteDataAccessType::kReadWrite,
|
||||
SiteDataAccessType::kRead));
|
||||
EXPECT_THAT(result, testing::ElementsAre(DIPSDataAccessType::kWrite,
|
||||
DIPSDataAccessType::kReadWrite,
|
||||
DIPSDataAccessType::kRead));
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_bounce_detector.h"
|
||||
#include "content/browser/dips/dips_bounce_detector.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
@ -25,14 +25,14 @@
|
||||
#include "base/time/time.h"
|
||||
#include "base/timer/timer.h"
|
||||
#include "base/types/optional_ref.h"
|
||||
#include "chrome/browser/chrome_content_browser_client.h"
|
||||
#include "chrome/browser/dips/cookie_access_filter.h"
|
||||
#include "chrome/browser/dips/dips_redirect_info.h"
|
||||
#include "chrome/browser/dips/dips_service_impl.h"
|
||||
#include "chrome/browser/dips/dips_storage.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "content/browser/dips/cookie_access_filter.h"
|
||||
#include "content/browser/dips/dips_service_impl.h"
|
||||
#include "content/browser/dips/dips_storage.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/content_browser_client.h"
|
||||
#include "content/public/browser/cookie_access_details.h"
|
||||
#include "content/public/browser/dips_redirect_info.h"
|
||||
#include "content/public/browser/navigation_handle.h"
|
||||
#include "content/public/browser/page.h"
|
||||
#include "content/public/browser/page_user_data.h"
|
||||
@ -193,7 +193,7 @@ DIPSRedirectContext::~DIPSRedirectContext() = default;
|
||||
void DIPSRedirectContext::AppendClientRedirect(
|
||||
DIPSRedirectInfoPtr client_redirect) {
|
||||
DCHECK_EQ(client_redirect->redirect_type, DIPSRedirectType::kClient);
|
||||
if (client_redirect->access_type > SiteDataAccessType::kRead) {
|
||||
if (client_redirect->access_type > DIPSDataAccessType::kRead) {
|
||||
redirectors_.insert(client_redirect->site);
|
||||
}
|
||||
redirects_.push_back(std::move(client_redirect));
|
||||
@ -204,7 +204,7 @@ void DIPSRedirectContext::AppendServerRedirects(
|
||||
std::vector<DIPSRedirectInfoPtr> server_redirects) {
|
||||
for (auto& redirect : server_redirects) {
|
||||
DCHECK_EQ(redirect->redirect_type, DIPSRedirectType::kServer);
|
||||
if (redirect->access_type > SiteDataAccessType::kRead) {
|
||||
if (redirect->access_type > DIPSDataAccessType::kRead) {
|
||||
redirectors_.insert(redirect->site);
|
||||
}
|
||||
redirects_.push_back(std::move(redirect));
|
||||
@ -462,8 +462,7 @@ bool AddLateCookieAccess(const GURL& url,
|
||||
for (size_t i = 1; i <= lookback; i++) {
|
||||
const size_t offset = redirects.size() - i;
|
||||
if (redirects[offset]->url.url == url) {
|
||||
redirects[offset]->access_type =
|
||||
redirects[offset]->access_type | ToSiteDataAccessType(op);
|
||||
redirects[offset]->access_type |= ToDIPSDataAccessType(op);
|
||||
|
||||
// This cookie access might indicate a stateful bounce and ideally we'd
|
||||
// report an issue to notify the user, but the navigation already
|
||||
@ -570,16 +569,15 @@ void Populate3PcExceptions(content::BrowserContext* browser_context,
|
||||
blink::StorageKey::CreateFirstParty(url::Origin::Create(initial_url));
|
||||
const blink::StorageKey final_url_key =
|
||||
blink::StorageKey::CreateFirstParty(url::Origin::Create(final_url));
|
||||
// TODO: crbug.com/40883201 - When we move to //content, we will call
|
||||
// IsFullCookieAccessAllowed() via ContentBrowserClient instead of as a
|
||||
// standalone function.
|
||||
content::ContentBrowserClient* browser_client =
|
||||
content::GetContentClient()->browser();
|
||||
for (DIPSRedirectInfoPtr& redirect : redirects) {
|
||||
redirect->has_3pc_exception =
|
||||
dips_move::IsFullCookieAccessAllowed(browser_context, web_contents,
|
||||
redirect->url.url,
|
||||
initial_url_key) ||
|
||||
dips_move::IsFullCookieAccessAllowed(browser_context, web_contents,
|
||||
redirect->url.url, final_url_key);
|
||||
browser_client->IsFullCookieAccessAllowed(browser_context, web_contents,
|
||||
redirect->url.url,
|
||||
initial_url_key) ||
|
||||
browser_client->IsFullCookieAccessAllowed(
|
||||
browser_context, web_contents, redirect->url.url, final_url_key);
|
||||
}
|
||||
}
|
||||
} // namespace dips
|
||||
@ -715,7 +713,7 @@ void DIPSBounceDetector::DidStartNavigation(
|
||||
// The delay between the previous navigation commit and the current
|
||||
// client-redirect is only tracked for stateful bounces.
|
||||
if (client_detection_state_->site_data_access_type >
|
||||
SiteDataAccessType::kNone) {
|
||||
DIPSDataAccessType::kNone) {
|
||||
UmaHistogramTimeToBounce(client_bounce_delay);
|
||||
}
|
||||
|
||||
@ -885,7 +883,7 @@ void DIPSBounceDetector::OnClientSiteDataAccessed(const GURL& url,
|
||||
GetSiteForDIPS(url) == client_detection_state_->current_site) {
|
||||
client_detection_state_->site_data_access_type =
|
||||
client_detection_state_->site_data_access_type |
|
||||
ToSiteDataAccessType(op);
|
||||
ToDIPSDataAccessType(op);
|
||||
|
||||
if (op == CookieOperation::kChange) {
|
||||
client_detection_state_->last_storage_time = now;
|
||||
@ -1040,7 +1038,7 @@ void DIPSBounceDetector::DidFinishNavigation(
|
||||
|
||||
// Before we replace the ClientBounceDetectionState, keep a copy of whether
|
||||
// the previous page accessed storage or not.
|
||||
std::optional<SiteDataAccessType> prev_page_access_type;
|
||||
std::optional<DIPSDataAccessType> prev_page_access_type;
|
||||
if (client_detection_state_) {
|
||||
prev_page_access_type = client_detection_state_->site_data_access_type;
|
||||
}
|
||||
@ -1072,7 +1070,7 @@ void DIPSBounceDetector::DidFinishNavigation(
|
||||
}
|
||||
|
||||
std::vector<DIPSRedirectInfoPtr> redirects;
|
||||
std::vector<SiteDataAccessType> access_types;
|
||||
std::vector<DIPSDataAccessType> access_types;
|
||||
server_state->filter.Filter(navigation_handle->GetRedirectChain(),
|
||||
&access_types);
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_DIPS_DIPS_BOUNCE_DETECTOR_H_
|
||||
#define CHROME_BROWSER_DIPS_DIPS_BOUNCE_DETECTOR_H_
|
||||
#ifndef CONTENT_BROWSER_DIPS_DIPS_BOUNCE_DETECTOR_H_
|
||||
#define CONTENT_BROWSER_DIPS_DIPS_BOUNCE_DETECTOR_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@ -19,13 +19,14 @@
|
||||
#include "base/time/time.h"
|
||||
#include "base/timer/timer.h"
|
||||
#include "base/types/optional_ref.h"
|
||||
#include "chrome/browser/dips/cookie_access_filter.h"
|
||||
#include "chrome/browser/dips/dips_redirect_info.h"
|
||||
#include "chrome/browser/dips/dips_service_impl.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "content/browser/dips/cookie_access_filter.h"
|
||||
#include "content/browser/dips/dips_service_impl.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/common/content_export.h"
|
||||
#include "content/public/browser/allow_service_worker_result.h"
|
||||
#include "content/public/browser/cookie_access_details.h"
|
||||
#include "content/public/browser/dedicated_worker_service.h"
|
||||
#include "content/public/browser/dips_redirect_info.h"
|
||||
#include "content/public/browser/navigation_handle.h"
|
||||
#include "content/public/browser/navigation_handle_timing.h"
|
||||
#include "content/public/browser/navigation_handle_user_data.h"
|
||||
@ -49,6 +50,9 @@ namespace url {
|
||||
class Origin;
|
||||
}
|
||||
|
||||
using DIPSRedirectChainHandler =
|
||||
base::RepeatingCallback<void(std::vector<DIPSRedirectInfoPtr>,
|
||||
DIPSRedirectChainInfoPtr)>;
|
||||
using DIPSIssueHandler =
|
||||
base::RepeatingCallback<void(std::set<std::string> sites)>;
|
||||
using DIPSIssueReportingCallback =
|
||||
@ -72,7 +76,7 @@ class ClientBounceDetectionState {
|
||||
std::optional<base::Time> last_activation_time;
|
||||
std::optional<base::Time> last_storage_time;
|
||||
std::optional<base::Time> last_successful_web_authn_assertion_time;
|
||||
SiteDataAccessType site_data_access_type = SiteDataAccessType::kUnknown;
|
||||
DIPSDataAccessType site_data_access_type = DIPSDataAccessType::kUnknown;
|
||||
};
|
||||
|
||||
// Either the URL navigated away from (starting a new chain), or the client-side
|
||||
@ -92,7 +96,7 @@ inline constexpr int kAllSitesFollowingFirstPartyLookbackLength = 10;
|
||||
// A redirect-chain-in-progress. It grows by calls to Append() and restarts by
|
||||
// calls to EndChain().
|
||||
// TODO: crbug.com/324573484 - rename to remove association with DIPS.
|
||||
class DIPSRedirectContext {
|
||||
class CONTENT_EXPORT DIPSRedirectContext {
|
||||
public:
|
||||
DIPSRedirectContext(DIPSRedirectChainHandler handler,
|
||||
DIPSIssueHandler issue_handler,
|
||||
@ -199,7 +203,7 @@ class DIPSRedirectContext {
|
||||
// A simplified interface to WebContents and DIPSServiceImpl that can be faked
|
||||
// in tests. Needed to allow unit testing DIPSBounceDetector.
|
||||
// TODO: crbug.com/324573484 - rename to remove association with DIPS.
|
||||
class DIPSBounceDetectorDelegate {
|
||||
class CONTENT_EXPORT DIPSBounceDetectorDelegate {
|
||||
public:
|
||||
virtual ~DIPSBounceDetectorDelegate();
|
||||
virtual UrlAndSourceId GetLastCommittedURL() const = 0;
|
||||
@ -214,7 +218,7 @@ class DIPSBounceDetectorDelegate {
|
||||
// ServerBounceDetectionState gets attached to NavigationHandle (which is a
|
||||
// SupportsUserData subclass) to store data needed to detect stateful
|
||||
// server-side redirects.
|
||||
class ServerBounceDetectionState
|
||||
class CONTENT_EXPORT ServerBounceDetectionState
|
||||
: public content::NavigationHandleUserData<ServerBounceDetectionState> {
|
||||
public:
|
||||
ServerBounceDetectionState();
|
||||
@ -243,7 +247,7 @@ class ServerBounceDetectionState
|
||||
// A simplified interface to content::NavigationHandle that can be faked in
|
||||
// tests. Needed to allow unit testing DIPSBounceDetector.
|
||||
// TODO: crbug.com/324573484 - rename to remove association with DIPS.
|
||||
class DIPSNavigationHandle {
|
||||
class CONTENT_EXPORT DIPSNavigationHandle {
|
||||
public:
|
||||
virtual ~DIPSNavigationHandle();
|
||||
|
||||
@ -281,7 +285,7 @@ class DIPSNavigationHandle {
|
||||
// metrics and storing them in the DIPSDatabase).
|
||||
// TODO: crbug.com/324573484 - rename this to avoid confusion with
|
||||
// RedirectChainDetector and remove its association with DIPS.
|
||||
class DIPSBounceDetector {
|
||||
class CONTENT_EXPORT DIPSBounceDetector {
|
||||
public:
|
||||
explicit DIPSBounceDetector(DIPSBounceDetectorDelegate* delegate,
|
||||
const base::TickClock* tick_clock,
|
||||
@ -371,7 +375,7 @@ class DelayedChainHandler {
|
||||
|
||||
// Detects chains of server- and client redirects, and notifies observers.
|
||||
// TODO: crbug.com/324573485 - move to separate file.
|
||||
class RedirectChainDetector
|
||||
class CONTENT_EXPORT RedirectChainDetector
|
||||
: public content::WebContentsObserver,
|
||||
public content::WebContentsUserData<RedirectChainDetector>,
|
||||
public DIPSBounceDetectorDelegate {
|
||||
@ -466,7 +470,7 @@ class RedirectChainDetector
|
||||
|
||||
// Populates the DIPS Database with site metadata, for the DIPS Service to
|
||||
// recognize and delete the storage of sites that perform bounce tracking.
|
||||
class DIPSWebContentsObserver
|
||||
class CONTENT_EXPORT DIPSWebContentsObserver
|
||||
: public content::WebContentsObserver,
|
||||
public content::WebContentsUserData<DIPSWebContentsObserver>,
|
||||
public content::SharedWorkerService::Observer,
|
||||
@ -585,15 +589,17 @@ namespace dips {
|
||||
ukm::SourceId GetInitialRedirectSourceId(
|
||||
content::NavigationHandle* navigation_handle);
|
||||
|
||||
bool IsOrWasInPrimaryPage(content::RenderFrameHost* render_frame_host);
|
||||
CONTENT_EXPORT bool IsOrWasInPrimaryPage(
|
||||
content::RenderFrameHost* render_frame_host);
|
||||
|
||||
// Sets the `has_3pc_exception` field of each element of `redirects`.
|
||||
void Populate3PcExceptions(content::BrowserContext* browser_context,
|
||||
content::WebContents* web_contents,
|
||||
const GURL& initial_url,
|
||||
const GURL& final_url,
|
||||
base::span<DIPSRedirectInfoPtr> redirects);
|
||||
CONTENT_EXPORT void Populate3PcExceptions(
|
||||
content::BrowserContext* browser_context,
|
||||
content::WebContents* web_contents,
|
||||
const GURL& initial_url,
|
||||
const GURL& final_url,
|
||||
base::span<DIPSRedirectInfoPtr> redirects);
|
||||
|
||||
} // namespace dips
|
||||
|
||||
#endif // CHROME_BROWSER_DIPS_DIPS_BOUNCE_DETECTOR_H_
|
||||
#endif // CONTENT_BROWSER_DIPS_DIPS_BOUNCE_DETECTOR_H_
|
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_bounce_detector.h"
|
||||
#include "content/browser/dips/dips_bounce_detector.h"
|
||||
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
@ -19,11 +19,11 @@
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/types/pass_key.h"
|
||||
#include "chrome/browser/dips/dips_service_impl.h"
|
||||
#include "chrome/browser/dips/dips_test_utils.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "components/content_settings/core/common/features.h"
|
||||
#include "components/ukm/test_ukm_recorder.h"
|
||||
#include "content/browser/dips/dips_service_impl.h"
|
||||
#include "content/browser/dips/dips_test_utils.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/public/browser/navigation_handle.h"
|
||||
#include "content/public/browser/navigation_handle_timing.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
@ -68,7 +68,7 @@ void AppendRedirect(std::vector<std::string>* redirects,
|
||||
"[%zu/%zu] %s -> %s (%s) -> %s", redirect.chain_index.value() + 1,
|
||||
chain.length, FormatURL(chain.initial_url.url).c_str(),
|
||||
FormatURL(redirect.url.url).c_str(),
|
||||
SiteDataAccessTypeToString(redirect.access_type).data(),
|
||||
DIPSDataAccessTypeToString(redirect.access_type).data(),
|
||||
FormatURL(chain.final_url.url).c_str()));
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ class TestBounceDetectorDelegate : public DIPSBounceDetectorDelegate {
|
||||
redirect->chain_id = chain->chain_id;
|
||||
redirect->chain_index = redirect_index;
|
||||
redirect->has_3pc_exception = false;
|
||||
DCHECK(redirect->access_type != SiteDataAccessType::kUnknown);
|
||||
DCHECK(redirect->access_type != DIPSDataAccessType::kUnknown);
|
||||
AppendRedirect(&redirects_, *redirect, *chain);
|
||||
|
||||
DIPSServiceImpl::HandleRedirectForTesting(
|
||||
@ -933,12 +933,12 @@ TEST_F(DIPSBounceDetectorTest, Histograms_UMA) {
|
||||
histograms.GetAllSamples("Privacy.DIPS.BounceCategoryClient.Block3PC"),
|
||||
testing::ElementsAre(
|
||||
// b.test
|
||||
Bucket((int)RedirectCategory::kReadCookies_HasEngagement, 1)));
|
||||
Bucket((int)DIPSRedirectCategory::kReadCookies_HasEngagement, 1)));
|
||||
EXPECT_THAT(
|
||||
histograms.GetAllSamples("Privacy.DIPS.BounceCategoryServer.Block3PC"),
|
||||
testing::ElementsAre(
|
||||
// c.test
|
||||
Bucket((int)RedirectCategory::kWriteCookies_NoEngagement, 1)));
|
||||
Bucket((int)DIPSRedirectCategory::kWriteCookies_NoEngagement, 1)));
|
||||
|
||||
// Verify the time-to-bounce metric was recorded for the client bounce.
|
||||
histograms.ExpectBucketCount(
|
||||
@ -974,7 +974,7 @@ TEST_F(DIPSBounceDetectorTest, Histograms_UKM) {
|
||||
EXPECT_THAT(
|
||||
ukm_entries[0].metrics,
|
||||
ElementsAre(Pair("ClientBounceDelay", 2),
|
||||
Pair("CookieAccessType", (int)SiteDataAccessType::kRead),
|
||||
Pair("CookieAccessType", (int)DIPSDataAccessType::kRead),
|
||||
Pair("HasStickyActivation", false),
|
||||
Pair("InitialAndFinalSitesSame", false),
|
||||
Pair("RedirectAndFinalSiteSame", false),
|
||||
@ -989,7 +989,7 @@ TEST_F(DIPSBounceDetectorTest, Histograms_UKM) {
|
||||
EXPECT_THAT(
|
||||
ukm_entries[1].metrics,
|
||||
ElementsAre(Pair("ClientBounceDelay", 0),
|
||||
Pair("CookieAccessType", (int)SiteDataAccessType::kWrite),
|
||||
Pair("CookieAccessType", (int)DIPSDataAccessType::kWrite),
|
||||
Pair("HasStickyActivation", false),
|
||||
Pair("InitialAndFinalSitesSame", false),
|
||||
Pair("RedirectAndFinalSiteSame", false),
|
||||
@ -1086,7 +1086,7 @@ void AppendChainPair(std::vector<ChainPair>& vec,
|
||||
|
||||
std::vector<DIPSRedirectInfoPtr> MakeServerRedirects(
|
||||
std::vector<std::string> urls,
|
||||
SiteDataAccessType access_type = SiteDataAccessType::kReadWrite) {
|
||||
DIPSDataAccessType access_type = DIPSDataAccessType::kReadWrite) {
|
||||
std::vector<DIPSRedirectInfoPtr> redirects;
|
||||
for (const auto& url : urls) {
|
||||
redirects.push_back(std::make_unique<DIPSRedirectInfo>(
|
||||
@ -1103,7 +1103,7 @@ std::vector<DIPSRedirectInfoPtr> MakeServerRedirects(
|
||||
|
||||
DIPSRedirectInfoPtr MakeClientRedirect(
|
||||
std::string url,
|
||||
SiteDataAccessType access_type = SiteDataAccessType::kReadWrite,
|
||||
DIPSDataAccessType access_type = DIPSDataAccessType::kReadWrite,
|
||||
bool has_sticky_activation = false,
|
||||
bool has_web_authn_assertion = false) {
|
||||
return std::make_unique<DIPSRedirectInfo>(
|
||||
@ -1128,9 +1128,9 @@ MATCHER_P(HasRedirectType, redirect_type, "") {
|
||||
result_listener);
|
||||
}
|
||||
|
||||
MATCHER_P(HasSiteDataAccessType, access_type, "") {
|
||||
MATCHER_P(HasDIPSDataAccessType, access_type, "") {
|
||||
*result_listener << "whose access_type is "
|
||||
<< SiteDataAccessTypeToString(arg->access_type);
|
||||
<< DIPSDataAccessTypeToString(arg->access_type);
|
||||
return ExplainMatchResult(Eq(access_type), arg->access_type, result_listener);
|
||||
}
|
||||
|
||||
@ -1443,7 +1443,7 @@ TEST(DIPSRedirectContextTest, AddLateCookieAccess) {
|
||||
MakeUrlAndId("http://a.test/"),
|
||||
MakeServerRedirects(
|
||||
{"http://b.test/", "http://c.test/", "http://d.test/"},
|
||||
SiteDataAccessType::kNone),
|
||||
DIPSDataAccessType::kNone),
|
||||
MakeUrlAndId("http://e.test/"), false);
|
||||
|
||||
EXPECT_TRUE(context.AddLateCookieAccess(GURL("http://d.test/"),
|
||||
@ -1453,14 +1453,14 @@ TEST(DIPSRedirectContextTest, AddLateCookieAccess) {
|
||||
CookieOperation::kRead));
|
||||
|
||||
context.AppendCommitted(
|
||||
MakeClientRedirect("http://e.test/", SiteDataAccessType::kNone),
|
||||
MakeClientRedirect("http://e.test/", DIPSDataAccessType::kNone),
|
||||
MakeServerRedirects({"http://f.test/", "http://g.test/"},
|
||||
SiteDataAccessType::kRead),
|
||||
DIPSDataAccessType::kRead),
|
||||
MakeUrlAndId("http://h.test/"), false);
|
||||
|
||||
context.AppendCommitted(
|
||||
MakeClientRedirect("http://h.test/", SiteDataAccessType::kNone),
|
||||
MakeServerRedirects({"http://i.test/"}, SiteDataAccessType::kRead),
|
||||
MakeClientRedirect("http://h.test/", DIPSDataAccessType::kNone),
|
||||
MakeServerRedirects({"http://i.test/"}, DIPSDataAccessType::kRead),
|
||||
MakeUrlAndId("http://j.test/"), false);
|
||||
|
||||
// Since kMaxLookback=5, AddLateCookieAccess() can attribute late accesses to
|
||||
@ -1488,21 +1488,21 @@ TEST(DIPSRedirectContextTest, AddLateCookieAccess) {
|
||||
EXPECT_THAT(
|
||||
chains[0].second,
|
||||
ElementsAre(AllOf(HasUrl("http://b.test/"),
|
||||
HasSiteDataAccessType(SiteDataAccessType::kNone)),
|
||||
HasDIPSDataAccessType(DIPSDataAccessType::kNone)),
|
||||
AllOf(HasUrl("http://c.test/"),
|
||||
HasSiteDataAccessType(SiteDataAccessType::kRead)),
|
||||
HasDIPSDataAccessType(DIPSDataAccessType::kRead)),
|
||||
AllOf(HasUrl("http://d.test/"),
|
||||
HasSiteDataAccessType(SiteDataAccessType::kWrite)),
|
||||
HasDIPSDataAccessType(DIPSDataAccessType::kWrite)),
|
||||
AllOf(HasUrl("http://e.test/"),
|
||||
HasSiteDataAccessType(SiteDataAccessType::kRead)),
|
||||
HasDIPSDataAccessType(DIPSDataAccessType::kRead)),
|
||||
AllOf(HasUrl("http://f.test/"),
|
||||
HasSiteDataAccessType(SiteDataAccessType::kRead)),
|
||||
HasDIPSDataAccessType(DIPSDataAccessType::kRead)),
|
||||
AllOf(HasUrl("http://g.test/"),
|
||||
HasSiteDataAccessType(SiteDataAccessType::kReadWrite)),
|
||||
HasDIPSDataAccessType(DIPSDataAccessType::kReadWrite)),
|
||||
AllOf(HasUrl("http://h.test/"),
|
||||
HasSiteDataAccessType(SiteDataAccessType::kRead)),
|
||||
HasDIPSDataAccessType(DIPSDataAccessType::kRead)),
|
||||
AllOf(HasUrl("http://i.test/"),
|
||||
HasSiteDataAccessType(SiteDataAccessType::kRead))));
|
||||
HasDIPSDataAccessType(DIPSDataAccessType::kRead))));
|
||||
}
|
||||
|
||||
TEST(DIPSRedirectContextTest, GetRedirectHeuristicURLs_NoRequirements) {
|
||||
@ -1525,7 +1525,7 @@ TEST(DIPSRedirectContextTest, GetRedirectHeuristicURLs_NoRequirements) {
|
||||
{MakeServerRedirects({"http://c.test"})},
|
||||
current_interaction_url, false);
|
||||
context.AppendCommitted(
|
||||
MakeClientRedirect("http://b.test/", SiteDataAccessType::kNone,
|
||||
MakeClientRedirect("http://b.test/", DIPSDataAccessType::kNone,
|
||||
/*has_sticky_activation=*/true),
|
||||
{}, first_party_url, false);
|
||||
|
||||
@ -1600,7 +1600,7 @@ TEST(DIPSRedirectContextTest,
|
||||
{MakeServerRedirects({"http://c.test"})},
|
||||
current_interaction_url, false);
|
||||
context.AppendCommitted(
|
||||
MakeClientRedirect("http://b.test/", SiteDataAccessType::kNone,
|
||||
MakeClientRedirect("http://b.test/", DIPSDataAccessType::kNone,
|
||||
/*has_sticky_activation=*/false, true),
|
||||
{}, first_party_url, false);
|
||||
|
||||
@ -1640,7 +1640,7 @@ TEST(DIPSRedirectContextTest,
|
||||
UrlAndSourceId(),
|
||||
/*redirect_prefix_count=*/0);
|
||||
context.AppendCommitted(
|
||||
MakeClientRedirect("http://a.test/", SiteDataAccessType::kNone, false,
|
||||
MakeClientRedirect("http://a.test/", DIPSDataAccessType::kNone, false,
|
||||
true),
|
||||
{}, MakeUrlAndId("http://b.test/"), false);
|
||||
ASSERT_EQ(context.size(), 1u);
|
||||
@ -1686,7 +1686,7 @@ TEST(
|
||||
{MakeServerRedirects({"http://b.test"})},
|
||||
MakeUrlAndId("http://c.test/"), false);
|
||||
context.AppendCommitted(
|
||||
MakeClientRedirect("http://b.test/", SiteDataAccessType::kNone, false,
|
||||
MakeClientRedirect("http://b.test/", DIPSDataAccessType::kNone, false,
|
||||
true),
|
||||
{}, MakeUrlAndId("http://d.test/"), false);
|
||||
ASSERT_EQ(context.size(), 2u);
|
||||
@ -1709,7 +1709,7 @@ TEST(
|
||||
{MakeServerRedirects({"http://b.test/"})},
|
||||
MakeUrlAndId("http://c.test/"), false);
|
||||
context.AppendCommitted(
|
||||
MakeClientRedirect("http://b.test/", SiteDataAccessType::kNone, false,
|
||||
MakeClientRedirect("http://b.test/", DIPSDataAccessType::kNone, false,
|
||||
true),
|
||||
MakeServerRedirects({"http://a.test/server-redirect/"}),
|
||||
MakeUrlAndId("http://d.test/"), false);
|
52
content/browser/dips/dips_browsertest_utils.cc
Normal file
52
content/browser/dips/dips_browsertest_utils.cc
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "content/browser/dips/dips_browsertest_utils.h"
|
||||
|
||||
#include "content/public/browser/dips_delegate.h"
|
||||
|
||||
namespace content {
|
||||
|
||||
bool ContentBrowserTestTpcBlockingBrowserClient::IsFullCookieAccessAllowed(
|
||||
content::BrowserContext* browser_context,
|
||||
content::WebContents* web_contents,
|
||||
const GURL& url,
|
||||
const blink::StorageKey& storage_key) {
|
||||
return impl_.IsFullCookieAccessAllowed(browser_context, web_contents, url,
|
||||
storage_key);
|
||||
}
|
||||
|
||||
void ContentBrowserTestTpcBlockingBrowserClient::
|
||||
GrantCookieAccessDueToHeuristic(content::BrowserContext* browser_context,
|
||||
const net::SchemefulSite& top_frame_site,
|
||||
const net::SchemefulSite& accessing_site,
|
||||
base::TimeDelta ttl,
|
||||
bool ignore_schemes) {
|
||||
impl_.GrantCookieAccessDueToHeuristic(browser_context, top_frame_site,
|
||||
accessing_site, ttl, ignore_schemes);
|
||||
}
|
||||
|
||||
std::unique_ptr<content::DipsDelegate>
|
||||
ContentBrowserTestTpcBlockingBrowserClient::CreateDipsDelegate() {
|
||||
return impl_.CreateDipsDelegate();
|
||||
}
|
||||
|
||||
bool ContentBrowserTestTpcBlockingBrowserClient::
|
||||
IsPrivacySandboxReportingDestinationAttested(
|
||||
content::BrowserContext* browser_context,
|
||||
const url::Origin& destination_origin,
|
||||
content::PrivacySandboxInvokingAPI invoking_api) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContentBrowserTestTpcBlockingBrowserClient::IsInterestGroupAPIAllowed(
|
||||
content::BrowserContext* browser_context,
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
InterestGroupApiOperation operation,
|
||||
const url::Origin& top_frame_origin,
|
||||
const url::Origin& api_origin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace content
|
70
content/browser/dips/dips_browsertest_utils.h
Normal file
70
content/browser/dips/dips_browsertest_utils.h
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CONTENT_BROWSER_DIPS_DIPS_BROWSERTEST_UTILS_H_
|
||||
#define CONTENT_BROWSER_DIPS_DIPS_BROWSERTEST_UTILS_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/time/time.h"
|
||||
#include "content/browser/dips/dips_test_utils.h"
|
||||
#include "content/public/test/content_browser_test_content_browser_client.h"
|
||||
|
||||
class GURL;
|
||||
|
||||
namespace blink {
|
||||
class StorageKey;
|
||||
}
|
||||
|
||||
namespace net {
|
||||
class SchemefulSite;
|
||||
}
|
||||
|
||||
namespace url {
|
||||
class Origin;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
class DipsDelegate;
|
||||
class BrowserContext;
|
||||
class RenderFrameHost;
|
||||
class WebContents;
|
||||
|
||||
// Wraps TpcBlockingBrowserClient for use in content browser tests (which
|
||||
// require subclasses of ContentBrowserTestContentBrowserClient).
|
||||
class ContentBrowserTestTpcBlockingBrowserClient
|
||||
: public ContentBrowserTestContentBrowserClient {
|
||||
public:
|
||||
bool IsFullCookieAccessAllowed(BrowserContext* browser_context,
|
||||
WebContents* web_contents,
|
||||
const GURL& url,
|
||||
const blink::StorageKey& storage_key) override;
|
||||
|
||||
void GrantCookieAccessDueToHeuristic(BrowserContext* browser_context,
|
||||
const net::SchemefulSite& top_frame_site,
|
||||
const net::SchemefulSite& accessing_site,
|
||||
base::TimeDelta ttl,
|
||||
bool ignore_schemes) override;
|
||||
|
||||
std::unique_ptr<DipsDelegate> CreateDipsDelegate() override;
|
||||
|
||||
bool IsPrivacySandboxReportingDestinationAttested(
|
||||
BrowserContext* browser_context,
|
||||
const url::Origin& destination_origin,
|
||||
PrivacySandboxInvokingAPI invoking_api) override;
|
||||
|
||||
bool IsInterestGroupAPIAllowed(BrowserContext* browser_context,
|
||||
RenderFrameHost* render_frame_host,
|
||||
InterestGroupApiOperation operation,
|
||||
const url::Origin& top_frame_origin,
|
||||
const url::Origin& api_origin) override;
|
||||
|
||||
TpcBlockingBrowserClient& impl() { return impl_; }
|
||||
|
||||
private:
|
||||
TpcBlockingBrowserClient impl_;
|
||||
};
|
||||
} // namespace content
|
||||
|
||||
#endif // CONTENT_BROWSER_DIPS_DIPS_BROWSERTEST_UTILS_H_
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_database.h"
|
||||
#include "content/browser/dips/dips_database.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
@ -19,8 +19,8 @@
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/dips/dips_database_migrator.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "content/browser/dips/dips_database_migrator.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
#include "sql/database.h"
|
||||
#include "sql/error_delegate_util.h"
|
||||
@ -36,9 +36,10 @@ BASE_FEATURE(kSqlWALModeOnDipsDatabase,
|
||||
base::FEATURE_ENABLED_BY_DEFAULT);
|
||||
|
||||
// NOTE: This is flag is intended for local testing and debugging only.
|
||||
// TODO: crbug.com/380903149 - re-enable exclusive locking.
|
||||
BASE_FEATURE(kDisableExclusiveLockingOnDipsDatabase,
|
||||
"DisableExclusiveLockingOnDipsDatabase",
|
||||
base::FEATURE_DISABLED_BY_DEFAULT);
|
||||
base::FEATURE_ENABLED_BY_DEFAULT);
|
||||
|
||||
constexpr char kTimerLastFiredKey[] = "timer_last_fired";
|
||||
|
||||
@ -93,11 +94,6 @@ void BindTimesOrNull(sql::Statement& statement,
|
||||
|
||||
} // namespace
|
||||
|
||||
// See comments at declaration of these variables in dips_database.h
|
||||
// for details.
|
||||
const base::TimeDelta DIPSDatabase::kMetricsInterval = base::Hours(24);
|
||||
const base::TimeDelta DIPSDatabase::kPopupTtl = base::Days(60);
|
||||
|
||||
DIPSDatabase::DIPSDatabase(const std::optional<base::FilePath>& db_path)
|
||||
: db_path_(db_path.value_or(base::FilePath())) {
|
||||
DCHECK(base::FeatureList::IsEnabled(features::kDIPS));
|
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_DIPS_DIPS_DATABASE_H_
|
||||
#define CHROME_BROWSER_DIPS_DIPS_DATABASE_H_
|
||||
#ifndef CONTENT_BROWSER_DIPS_DIPS_DATABASE_H_
|
||||
#define CONTENT_BROWSER_DIPS_DIPS_DATABASE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@ -13,7 +13,8 @@
|
||||
#include "base/strings/cstring_view.h"
|
||||
#include "base/time/clock.h"
|
||||
#include "base/time/default_clock.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/common/content_export.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
#include "sql/database.h"
|
||||
#include "sql/init_status.h"
|
||||
@ -21,7 +22,7 @@
|
||||
#include "sql/statement.h"
|
||||
|
||||
// Encapsulates an SQL database that holds DIPS info.
|
||||
class DIPSDatabase {
|
||||
class CONTENT_EXPORT DIPSDatabase {
|
||||
public:
|
||||
// Version number of the database schema.
|
||||
// NOTE: When changing the version, add a new golden file for the new version
|
||||
@ -34,11 +35,11 @@ class DIPSDatabase {
|
||||
static constexpr char kPrepopulatedKey[] = "prepopulated";
|
||||
|
||||
// The length of time that will be waited between emitting db health metrics.
|
||||
static const base::TimeDelta kMetricsInterval;
|
||||
static constexpr base::TimeDelta kMetricsInterval = base::Hours(24);
|
||||
|
||||
// How long DIPS maintains popups in storage (for recording Popup Heuristic
|
||||
// storage accesses).
|
||||
static const base::TimeDelta kPopupTtl;
|
||||
static constexpr base::TimeDelta kPopupTtl = base::Days(60);
|
||||
|
||||
// Passing in an std::nullopt `db_path` causes the db to be created in
|
||||
// memory. Init() must be called before using the DIPSDatabase to make sure it
|
||||
@ -287,4 +288,4 @@ class DIPSDatabase {
|
||||
SEQUENCE_CHECKER(sequence_checker_);
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_DIPS_DIPS_DATABASE_H_
|
||||
#endif // CONTENT_BROWSER_DIPS_DIPS_DATABASE_H_
|
@ -2,11 +2,11 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_database_migrator.h"
|
||||
#include "content/browser/dips/dips_database_migrator.h"
|
||||
|
||||
#include "base/check_deref.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "chrome/browser/dips/dips_database.h"
|
||||
#include "content/browser/dips/dips_database.h"
|
||||
#include "sql/meta_table.h"
|
||||
#include "sql/statement.h"
|
||||
|
@ -2,19 +2,21 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_DIPS_DIPS_DATABASE_MIGRATOR_H_
|
||||
#define CHROME_BROWSER_DIPS_DIPS_DATABASE_MIGRATOR_H_
|
||||
#ifndef CONTENT_BROWSER_DIPS_DIPS_DATABASE_MIGRATOR_H_
|
||||
#define CONTENT_BROWSER_DIPS_DIPS_DATABASE_MIGRATOR_H_
|
||||
|
||||
#include "content/common/content_export.h"
|
||||
#include "sql/database.h"
|
||||
#include "sql/meta_table.h"
|
||||
|
||||
// Returns whether the migration was successful.
|
||||
bool MigrateDIPSSchemaToLatestVersion(sql::Database& db,
|
||||
sql::MetaTable& meta_table);
|
||||
CONTENT_EXPORT bool MigrateDIPSSchemaToLatestVersion(
|
||||
sql::Database& db,
|
||||
sql::MetaTable& meta_table);
|
||||
|
||||
namespace internal {
|
||||
|
||||
class DIPSDatabaseMigrator {
|
||||
class CONTENT_EXPORT DIPSDatabaseMigrator {
|
||||
public:
|
||||
// `db` and `meta_table` must be non-null and must outlive this
|
||||
// `DIPSDatabaseMigrator` instance.
|
||||
@ -66,4 +68,4 @@ class DIPSDatabaseMigrator {
|
||||
|
||||
} // namespace internal
|
||||
|
||||
#endif // CHROME_BROWSER_DIPS_DIPS_DATABASE_MIGRATOR_H_
|
||||
#endif // CONTENT_BROWSER_DIPS_DIPS_DATABASE_MIGRATOR_H_
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_database_migrator.h"
|
||||
#include "content/browser/dips/dips_database_migrator.h"
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
@ -10,7 +10,7 @@
|
||||
#include "base/path_service.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "chrome/browser/dips/dips_test_utils.h"
|
||||
#include "content/browser/dips/dips_test_utils.h"
|
||||
#include "sql/database.h"
|
||||
#include "sql/test/test_helpers.h"
|
||||
#include "sql/transaction.h"
|
||||
@ -31,7 +31,7 @@ class DIPSDatabaseMigrationTest : public testing::Test {
|
||||
if (!base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &root)) {
|
||||
return AssertionFailure() << "Could not get test data directory root";
|
||||
}
|
||||
base::FilePath file_path = root.AppendASCII("chrome")
|
||||
base::FilePath file_path = root.AppendASCII("content")
|
||||
.AppendASCII("test")
|
||||
.AppendASCII("data")
|
||||
.AppendASCII("dips")
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_database.h"
|
||||
#include "content/browser/dips/dips_database.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <optional>
|
||||
@ -21,8 +21,8 @@
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/test/simple_test_clock.h"
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/dips/dips_test_utils.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "content/browser/dips/dips_test_utils.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
#include "content/public/common/dips_utils.h"
|
||||
#include "sql/database.h"
|
||||
@ -1619,7 +1619,7 @@ class DIPSDatabaseInitializationTest : public testing::Test {
|
||||
void LoadDatabase(const char* file_name) {
|
||||
base::FilePath root;
|
||||
ASSERT_TRUE(base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &root));
|
||||
base::FilePath file_path = root.AppendASCII("chrome")
|
||||
base::FilePath file_path = root.AppendASCII("content")
|
||||
.AppendASCII("test")
|
||||
.AppendASCII("data")
|
||||
.AppendASCII("dips")
|
190
chrome/browser/dips/dips_helper_browsertest.cc → content/browser/dips/dips_helper_browsertest.cc
190
chrome/browser/dips/dips_helper_browsertest.cc → content/browser/dips/dips_helper_browsertest.cc
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/rand_util.h"
|
||||
#include "base/run_loop.h"
|
||||
@ -14,39 +16,35 @@
|
||||
#include "base/test/test_file_util.h"
|
||||
#include "base/time/time.h"
|
||||
#include "build/build_config.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "chrome/browser/browsing_data/browsing_data_important_sites_util.h"
|
||||
#include "chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h"
|
||||
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
|
||||
#include "chrome/browser/dips/dips_bounce_detector.h"
|
||||
#include "chrome/browser/dips/dips_service_impl.h"
|
||||
#include "chrome/browser/dips/dips_storage.h"
|
||||
#include "chrome/browser/dips/dips_test_utils.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "chrome/browser/profiles/profile_manager.h"
|
||||
#include "chrome/test/base/chrome_test_utils.h"
|
||||
#include "chrome/test/base/platform_browser_test.h"
|
||||
#include "chrome/test/base/testing_profile.h"
|
||||
#include "components/content_settings/core/browser/host_content_settings_map.h"
|
||||
#include "components/content_settings/core/common/content_settings_pattern.h"
|
||||
#include "components/ukm/test_ukm_recorder.h"
|
||||
#include "content/browser/dips/dips_bounce_detector.h"
|
||||
#include "content/browser/dips/dips_browsertest_utils.h"
|
||||
#include "content/browser/dips/dips_service_impl.h"
|
||||
#include "content/browser/dips/dips_storage.h"
|
||||
#include "content/browser/dips/dips_test_utils.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/browsing_data_remover.h"
|
||||
#include "content/public/browser/dips_delegate.h"
|
||||
#include "content/public/browser/dips_service.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
#include "content/public/test/browser_task_environment.h"
|
||||
#include "content/public/test/browser_test.h"
|
||||
#include "content/public/test/browser_test_utils.h"
|
||||
#include "content/public/test/content_browser_test.h"
|
||||
#include "content/public/test/content_browser_test_content_browser_client.h"
|
||||
#include "content/public/test/dips_service_test_utils.h"
|
||||
#include "content/public/test/hit_test_region_observer.h"
|
||||
#include "content/public/test/test_browser_context.h"
|
||||
#include "content/public/test/test_launcher.h"
|
||||
#include "content/shell/browser/shell.h"
|
||||
#include "net/dns/mock_host_resolver.h"
|
||||
#include "third_party/blink/public/common/switches.h"
|
||||
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
#include "chrome/browser/ui/browser_commands.h"
|
||||
#include "chrome/test/base/ui_test_utils.h"
|
||||
#endif // !BUILDFLAG(IS_ANDROID)
|
||||
#include "ui/gfx/geometry/size.h"
|
||||
#include "url/url_constants.h"
|
||||
|
||||
using content::CookieAccessDetails;
|
||||
using content::NavigationHandle;
|
||||
@ -58,7 +56,7 @@ using testing::Pair;
|
||||
using testing::Optional;
|
||||
using testing::Pair;
|
||||
|
||||
class DIPSTabHelperBrowserTest : public PlatformBrowserTest,
|
||||
class DIPSTabHelperBrowserTest : public content::ContentBrowserTest,
|
||||
public testing::WithParamInterface<bool> {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
@ -74,7 +72,7 @@ class DIPSTabHelperBrowserTest : public PlatformBrowserTest,
|
||||
}
|
||||
scoped_feature_list_.InitWithFeaturesAndParameters(enabled_features,
|
||||
disabled_features);
|
||||
PlatformBrowserTest::SetUp();
|
||||
content::ContentBrowserTest::SetUp();
|
||||
}
|
||||
|
||||
void SetUpCommandLine(base::CommandLine* command_line) override {
|
||||
@ -90,26 +88,29 @@ class DIPSTabHelperBrowserTest : public PlatformBrowserTest,
|
||||
host_resolver()->AddRule("d.test", "127.0.0.1");
|
||||
DIPSWebContentsObserver::FromWebContents(GetActiveWebContents())
|
||||
->SetClockForTesting(&test_clock_);
|
||||
browser_client_.emplace();
|
||||
|
||||
// Initialize exceptions for 1P sites with embedded 3P cookies. Block 3PC by
|
||||
// default on a.test and d.test, since those are used as the initial and
|
||||
// final URL in the redirect chains. This avoids trimming bounces due to 1P
|
||||
// exceptions (e.g. Chrome Guard).
|
||||
map_ = HostContentSettingsMapFactory::GetForProfile(
|
||||
chrome_test_utils::GetActiveWebContents(this)->GetBrowserContext());
|
||||
map_->SetContentSettingCustomScope(
|
||||
ContentSettingsPattern::Wildcard(),
|
||||
ContentSettingsPattern::FromString("[*.]a.test"),
|
||||
ContentSettingsType::COOKIES, ContentSetting::CONTENT_SETTING_BLOCK);
|
||||
map_->SetContentSettingCustomScope(
|
||||
ContentSettingsPattern::Wildcard(),
|
||||
ContentSettingsPattern::FromString("[*.]d.test"),
|
||||
ContentSettingsType::COOKIES, ContentSetting::CONTENT_SETTING_BLOCK);
|
||||
browser_client_->impl().SetBlockThirdPartyCookiesByDefault(false);
|
||||
browser_client_->impl().BlockThirdPartyCookiesOnSite(GURL("http://a.test"));
|
||||
browser_client_->impl().BlockThirdPartyCookiesOnSite(GURL("http://d.test"));
|
||||
|
||||
// We can only create extra browser contexts while single-threaded.
|
||||
extra_browser_context_ = CreateTestBrowserContext();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
content::GetUIThreadTaskRunner({})->DeleteSoon(
|
||||
FROM_HERE, std::move(extra_browser_context_));
|
||||
content::ContentBrowserTest::TearDown();
|
||||
}
|
||||
|
||||
WebContents* GetActiveWebContents() {
|
||||
if (!web_contents_) {
|
||||
web_contents_ = chrome_test_utils::GetActiveWebContents(this);
|
||||
web_contents_ = shell()->web_contents();
|
||||
}
|
||||
return web_contents_;
|
||||
}
|
||||
@ -142,7 +143,8 @@ class DIPSTabHelperBrowserTest : public PlatformBrowserTest,
|
||||
DIPSServiceImpl::Get(web_contents->GetBrowserContext());
|
||||
GURL expected_url = web_contents->GetLastCommittedURL();
|
||||
|
||||
RedirectChainObserver chain_observer(dips_service, expected_url);
|
||||
content::DipsRedirectChainObserver chain_observer(dips_service,
|
||||
expected_url);
|
||||
// Performing a browser-based navigation terminates the current redirect
|
||||
// chain.
|
||||
ASSERT_TRUE(content::NavigateToURL(
|
||||
@ -151,18 +153,28 @@ class DIPSTabHelperBrowserTest : public PlatformBrowserTest,
|
||||
chain_observer.Wait();
|
||||
}
|
||||
|
||||
content::BrowserContext* extra_browser_context() {
|
||||
return extra_browser_context_.get();
|
||||
}
|
||||
|
||||
private:
|
||||
raw_ptr<WebContents, AcrossTasksDanglingUntriaged> web_contents_ = nullptr;
|
||||
// browser_client_ is wrapped in optional<> to delay construction -- it won't
|
||||
// be registered properly if it's created too early.
|
||||
std::optional<content::ContentBrowserTestTpcBlockingBrowserClient>
|
||||
browser_client_;
|
||||
base::SimpleTestClock test_clock_;
|
||||
base::test::ScopedFeatureList scoped_feature_list_;
|
||||
raw_ptr<HostContentSettingsMap> map_;
|
||||
std::unique_ptr<content::TestBrowserContext> extra_browser_context_;
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_P(DIPSTabHelperBrowserTest,
|
||||
InteractionsRecordedInAncestorFrames) {
|
||||
GURL url_a = embedded_test_server()->GetURL("a.test", "/iframe_blank.html");
|
||||
GURL url_a =
|
||||
embedded_test_server()->GetURL("a.test", "/page_with_blank_iframe.html");
|
||||
GURL url_b = embedded_test_server()->GetURL("b.test", "/title1.html");
|
||||
const std::string kIframeId = "test"; // defined in iframe_blank.html
|
||||
const std::string kIframeId =
|
||||
"test_iframe"; // defined in page_with_blank_iframe.html
|
||||
base::Time time = base::Time::FromSecondsSinceUnixEpoch(1);
|
||||
content::WebContents* web_contents = GetActiveWebContents();
|
||||
|
||||
@ -273,13 +285,14 @@ IN_PROC_BROWSER_TEST_P(DIPSTabHelperBrowserTest, StorageRecordedInSingleFrame) {
|
||||
// cookie, the cookie needs to be SameSite=None and Secure.
|
||||
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
|
||||
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
|
||||
https_server.AddDefaultHandlers(
|
||||
base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
|
||||
https_server.AddDefaultHandlers(GetTestDataFilePath());
|
||||
ASSERT_TRUE(https_server.Start());
|
||||
|
||||
GURL url_a = embedded_test_server()->GetURL("a.test", "/iframe_blank.html");
|
||||
GURL url_a =
|
||||
embedded_test_server()->GetURL("a.test", "/page_with_blank_iframe.html");
|
||||
GURL url_b = https_server.GetURL("b.test", "/title1.html");
|
||||
const std::string kIframeId = "test"; // defined in iframe_blank.html
|
||||
const std::string kIframeId =
|
||||
"test_iframe"; // defined in page_with_blank_iframe.html
|
||||
base::Time time = base::Time::FromSecondsSinceUnixEpoch(1);
|
||||
content::WebContents* web_contents = GetActiveWebContents();
|
||||
|
||||
@ -321,8 +334,7 @@ IN_PROC_BROWSER_TEST_P(DIPSTabHelperBrowserTest,
|
||||
// cookie, the cookie needs to be SameSite=None and Secure.
|
||||
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
|
||||
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
|
||||
https_server.AddDefaultHandlers(
|
||||
base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
|
||||
https_server.AddDefaultHandlers(GetTestDataFilePath());
|
||||
ASSERT_TRUE(https_server.Start());
|
||||
|
||||
GURL page_url = embedded_test_server()->GetURL("a.test", "/title1.html");
|
||||
@ -409,6 +421,38 @@ IN_PROC_BROWSER_TEST_P(DIPSTabHelperBrowserTest, MultipleSiteStoragesRecorded) {
|
||||
state_2->site_storage_times->second);
|
||||
}
|
||||
|
||||
namespace {
|
||||
class BrowsingDataRemovalObserver
|
||||
: public content::BrowsingDataRemover::Observer {
|
||||
public:
|
||||
explicit BrowsingDataRemovalObserver(base::OnceClosure callback)
|
||||
: callback_(std::move(callback)) {}
|
||||
|
||||
void OnBrowsingDataRemoverDone(uint64_t failed_data_types) override {
|
||||
std::move(callback_).Run();
|
||||
}
|
||||
|
||||
private:
|
||||
base::OnceClosure callback_;
|
||||
};
|
||||
|
||||
bool ClearBrowsingData(content::BrowsingDataRemover* remover,
|
||||
base::TimeDelta time_period) {
|
||||
base::RunLoop run_loop;
|
||||
BrowsingDataRemovalObserver observer(run_loop.QuitClosure());
|
||||
remover->AddObserver(&observer);
|
||||
const base::Time now = base::Time::Now();
|
||||
remover->RemoveAndReply(
|
||||
now - time_period, now,
|
||||
DIPSService::kDefaultRemoveMask |
|
||||
TpcBlockingBrowserClient::DATA_TYPE_HISTORY,
|
||||
content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB, &observer);
|
||||
run_loop.Run();
|
||||
remover->RemoveObserver(&observer);
|
||||
return !testing::Test::HasFailure();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
IN_PROC_BROWSER_TEST_P(DIPSTabHelperBrowserTest,
|
||||
ChromeBrowsingDataRemover_Basic) {
|
||||
content::WebContents* web_contents = GetActiveWebContents();
|
||||
@ -431,20 +475,9 @@ IN_PROC_BROWSER_TEST_P(DIPSTabHelperBrowserTest,
|
||||
EXPECT_EQ(state_initial->user_interaction_times->first, interaction_time);
|
||||
|
||||
// Remove browsing data for the past day.
|
||||
uint64_t remove_mask = chrome_browsing_data_remover::DATA_TYPE_HISTORY |
|
||||
chrome_browsing_data_remover::DATA_TYPE_SITE_DATA;
|
||||
std::unique_ptr<content::BrowsingDataFilterBuilder> filter_builder(
|
||||
content::BrowsingDataFilterBuilder::Create(
|
||||
content::BrowsingDataFilterBuilder::Mode::kPreserve));
|
||||
content::BrowsingDataRemover* remover =
|
||||
GetActiveWebContents()->GetBrowserContext()->GetBrowsingDataRemover();
|
||||
|
||||
base::RunLoop run_loop;
|
||||
browsing_data_important_sites_util::Remove(
|
||||
remove_mask, content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB,
|
||||
browsing_data::TimePeriod::LAST_DAY, std::move(filter_builder), remover,
|
||||
base::IgnoreArgs<uint64_t>(run_loop.QuitClosure()));
|
||||
run_loop.Run();
|
||||
ASSERT_TRUE(ClearBrowsingData(
|
||||
GetActiveWebContents()->GetBrowserContext()->GetBrowsingDataRemover(),
|
||||
base::Days(1)));
|
||||
|
||||
// Verify that the user interaction has been cleared from the DIPS DB.
|
||||
std::optional<StateValue> state_final =
|
||||
@ -547,11 +580,14 @@ IN_PROC_BROWSER_TEST_P(DIPSTabHelperBrowserTest,
|
||||
// Make b.test statefully bounce to d.test.
|
||||
ASSERT_TRUE(content::NavigateToURL(
|
||||
web_contents, embedded_test_server()->GetURL("a.test", "/title1.html")));
|
||||
const GURL bounce_url1 = embedded_test_server()->GetURL(
|
||||
"b.test", "/cross-site-with-cookie/d.test/title1.html");
|
||||
URLCookieAccessObserver observer1(web_contents, bounce_url1,
|
||||
CookieOperation::kChange);
|
||||
ASSERT_TRUE(content::NavigateToURLFromRenderer(
|
||||
web_contents,
|
||||
embedded_test_server()->GetURL(
|
||||
"b.test", "/cross-site-with-cookie/d.test/title1.html"),
|
||||
web_contents, bounce_url1,
|
||||
embedded_test_server()->GetURL("d.test", "/title1.html")));
|
||||
observer1.Wait();
|
||||
// End the chain so the bounce is recorded.
|
||||
ASSERT_TRUE(content::NavigateToURL(
|
||||
web_contents, embedded_test_server()->GetURL("a.test", "/title1.html")));
|
||||
@ -560,11 +596,14 @@ IN_PROC_BROWSER_TEST_P(DIPSTabHelperBrowserTest,
|
||||
// Make c.test statefully bounce to d.test.
|
||||
ASSERT_TRUE(content::NavigateToURL(
|
||||
web_contents, embedded_test_server()->GetURL("a.test", "/title1.html")));
|
||||
const GURL bounce_url2 = embedded_test_server()->GetURL(
|
||||
"c.test", "/cross-site-with-cookie/d.test/title1.html");
|
||||
URLCookieAccessObserver observer2(web_contents, bounce_url2,
|
||||
CookieOperation::kChange);
|
||||
ASSERT_TRUE(content::NavigateToURLFromRenderer(
|
||||
web_contents,
|
||||
embedded_test_server()->GetURL(
|
||||
"c.test", "/cross-site-with-cookie/d.test/title1.html"),
|
||||
web_contents, bounce_url2,
|
||||
embedded_test_server()->GetURL("d.test", "/title1.html")));
|
||||
observer2.Wait();
|
||||
EndRedirectChain();
|
||||
|
||||
// Verify the bounces were recorded. b.test:
|
||||
@ -583,17 +622,9 @@ IN_PROC_BROWSER_TEST_P(DIPSTabHelperBrowserTest,
|
||||
|
||||
// Remove browsing data for the past hour. This should include c.test but not
|
||||
// b.test.
|
||||
base::RunLoop run_loop;
|
||||
browsing_data_important_sites_util::Remove(
|
||||
chrome_browsing_data_remover::DATA_TYPE_HISTORY |
|
||||
chrome_browsing_data_remover::DATA_TYPE_SITE_DATA,
|
||||
content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB,
|
||||
browsing_data::TimePeriod::LAST_HOUR,
|
||||
content::BrowsingDataFilterBuilder::Create(
|
||||
content::BrowsingDataFilterBuilder::Mode::kPreserve),
|
||||
ASSERT_TRUE(ClearBrowsingData(
|
||||
web_contents->GetBrowserContext()->GetBrowsingDataRemover(),
|
||||
base::IgnoreArgs<uint64_t>(run_loop.QuitClosure()));
|
||||
run_loop.Run();
|
||||
base::Hours(1)));
|
||||
|
||||
// Verify only the DIPS record for c.test was deleted.
|
||||
ASSERT_TRUE(GetDIPSState(GetDipsService(web_contents), GURL("http://b.test"))
|
||||
@ -769,12 +800,11 @@ IN_PROC_BROWSER_TEST_P(DIPSTabHelperBrowserTest,
|
||||
ASSERT_EQ(c_state->user_interaction_times, std::nullopt);
|
||||
|
||||
// Open c.test on a new tab in a new window/profile.
|
||||
ProfileManager* profile_manager = g_browser_process->profile_manager();
|
||||
base::FilePath profile_path = profile_manager->user_data_dir().Append(
|
||||
FILE_PATH_LITERAL("OtherProfile"));
|
||||
Browser* new_browser = chrome::OpenEmptyWindow(
|
||||
&profiles::testing::CreateProfileSync(profile_manager, profile_path));
|
||||
ASSERT_TRUE(ui_test_utils::NavigateToURL(new_browser, GURL("http://c.test")));
|
||||
content::Shell* another_window = content::Shell::CreateNewWindow(
|
||||
extra_browser_context(), GURL(url::kAboutBlankURL), nullptr, gfx::Size());
|
||||
ASSERT_TRUE(content::NavigateToURL(
|
||||
another_window->web_contents(),
|
||||
embedded_test_server()->GetURL("c.test", "/title1.html")));
|
||||
|
||||
// Trigger the DIPS timer which would delete tracker data.
|
||||
SetDIPSTime(bounce_time + features::kDIPSGracePeriod.Get() +
|
@ -2,10 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_navigation_flow_detector.h"
|
||||
#include "content/browser/dips/dips_navigation_flow_detector.h"
|
||||
|
||||
#include "base/rand_util.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/public/browser/cookie_access_details.h"
|
||||
#include "content/public/browser/navigation_handle.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
@ -161,8 +161,8 @@ EntrypointInfo::EntrypointInfo(const DIPSRedirectInfo& server_redirect_info,
|
||||
: site(server_redirect_info.site),
|
||||
source_id(server_redirect_info.url.source_id),
|
||||
had_triggering_storage_access(
|
||||
server_redirect_info.access_type == SiteDataAccessType::kWrite ||
|
||||
server_redirect_info.access_type == SiteDataAccessType::kReadWrite),
|
||||
server_redirect_info.access_type == DIPSDataAccessType::kWrite ||
|
||||
server_redirect_info.access_type == DIPSDataAccessType::kReadWrite),
|
||||
was_referral_client_redirect(
|
||||
exit_page_info.WasNavigationToPageClientRedirect()) {}
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_DIPS_DIPS_NAVIGATION_FLOW_DETECTOR_H_
|
||||
#define CHROME_BROWSER_DIPS_DIPS_NAVIGATION_FLOW_DETECTOR_H_
|
||||
#ifndef CONTENT_BROWSER_DIPS_DIPS_NAVIGATION_FLOW_DETECTOR_H_
|
||||
#define CONTENT_BROWSER_DIPS_DIPS_NAVIGATION_FLOW_DETECTOR_H_
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@ -15,7 +15,7 @@
|
||||
#include "base/time/clock.h"
|
||||
#include "base/time/default_clock.h"
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/dips/dips_bounce_detector.h"
|
||||
#include "content/browser/dips/dips_bounce_detector.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "content/public/browser/web_contents_user_data.h"
|
||||
#include "services/metrics/public/cpp/ukm_source_id.h"
|
||||
@ -205,4 +205,4 @@ class DipsNavigationFlowDetector
|
||||
WEB_CONTENTS_USER_DATA_KEY_DECL();
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_DIPS_DIPS_NAVIGATION_FLOW_DETECTOR_H_
|
||||
#endif // CONTENT_BROWSER_DIPS_DIPS_NAVIGATION_FLOW_DETECTOR_H_
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_navigation_flow_detector.h"
|
||||
#include "content/browser/dips/dips_navigation_flow_detector.h"
|
||||
|
||||
#include "base/base64.h"
|
||||
#include "base/test/bind.h"
|
||||
@ -12,16 +12,8 @@
|
||||
#include "base/test/test_future.h"
|
||||
#include "base/test/test_timeouts.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "chrome/browser/content_settings/cookie_settings_factory.h"
|
||||
#include "chrome/browser/dips/dips_test_utils.h"
|
||||
#include "chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/test/base/chrome_test_utils.h"
|
||||
#include "chrome/test/base/platform_browser_test.h"
|
||||
#include "components/content_settings/core/browser/cookie_settings.h"
|
||||
#include "components/content_settings/core/common/pref_names.h"
|
||||
#include "components/privacy_sandbox/privacy_sandbox_attestations/privacy_sandbox_attestations.h"
|
||||
#include "components/ukm/test_ukm_recorder.h"
|
||||
#include "content/browser/dips/dips_test_utils.h"
|
||||
#include "content/public/browser/attribution_data_model.h"
|
||||
#include "content/public/browser/network_service_instance.h"
|
||||
#include "content/public/test/browser_test.h"
|
||||
@ -38,16 +30,6 @@
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/blink/public/common/switches.h"
|
||||
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
#include "chrome/browser/ssl/cert_verifier_browser_test.h"
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
#include "chrome/browser/ui/tabs/public/tab_features.h"
|
||||
#include "components/network_session_configurator/common/network_switches.h"
|
||||
#include "content/public/browser/scoped_authenticator_environment_for_testing.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "device/fido/virtual_fido_device_factory.h"
|
||||
#endif // !BUILDFLAG(IS_ANDROID)
|
||||
|
||||
namespace {
|
||||
|
||||
using AttributionData = std::set<content::AttributionDataModel::DataKey>;
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_service_impl.h"
|
||||
#include "content/browser/dips/dips_service_impl.h"
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
@ -25,19 +25,20 @@
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/types/pass_key.h"
|
||||
#include "chrome/browser/chrome_content_browser_client.h"
|
||||
#include "chrome/browser/dips/chrome_dips_delegate.h"
|
||||
#include "chrome/browser/dips/dips_redirect_info.h"
|
||||
#include "chrome/browser/dips/dips_service_factory.h"
|
||||
#include "chrome/browser/dips/dips_storage.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "chrome/browser/dips/persistent_repeating_timer.h"
|
||||
#include "content/browser/browser_context_impl.h"
|
||||
#include "content/browser/dips/dips_storage.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/browser/dips/persistent_repeating_timer.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/browsing_data_filter_builder.h"
|
||||
#include "content/public/browser/browsing_data_remover.h"
|
||||
#include "content/public/browser/content_browser_client.h"
|
||||
#include "content/public/browser/dips_delegate.h"
|
||||
#include "content/public/browser/dips_redirect_info.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/common/content_client.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
#include "content/public/common/dips_utils.h"
|
||||
#include "net/base/schemeful_site.h"
|
||||
@ -57,28 +58,30 @@ BASE_FEATURE(kDipsOnForegroundSequence,
|
||||
"DipsOnForegroundSequence",
|
||||
base::FEATURE_DISABLED_BY_DEFAULT);
|
||||
|
||||
RedirectCategory ClassifyRedirect(SiteDataAccessType access,
|
||||
bool has_interaction) {
|
||||
DIPSRedirectCategory ClassifyRedirect(DIPSDataAccessType access,
|
||||
bool has_interaction) {
|
||||
using enum DIPSRedirectCategory;
|
||||
|
||||
switch (access) {
|
||||
case SiteDataAccessType::kUnknown:
|
||||
return has_interaction ? RedirectCategory::kUnknownCookies_HasEngagement
|
||||
: RedirectCategory::kUnknownCookies_NoEngagement;
|
||||
case SiteDataAccessType::kNone:
|
||||
return has_interaction ? RedirectCategory::kNoCookies_HasEngagement
|
||||
: RedirectCategory::kNoCookies_NoEngagement;
|
||||
case SiteDataAccessType::kRead:
|
||||
return has_interaction ? RedirectCategory::kReadCookies_HasEngagement
|
||||
: RedirectCategory::kReadCookies_NoEngagement;
|
||||
case SiteDataAccessType::kWrite:
|
||||
return has_interaction ? RedirectCategory::kWriteCookies_HasEngagement
|
||||
: RedirectCategory::kWriteCookies_NoEngagement;
|
||||
case SiteDataAccessType::kReadWrite:
|
||||
return has_interaction ? RedirectCategory::kReadWriteCookies_HasEngagement
|
||||
: RedirectCategory::kReadWriteCookies_NoEngagement;
|
||||
case DIPSDataAccessType::kUnknown:
|
||||
return has_interaction ? kUnknownCookies_HasEngagement
|
||||
: kUnknownCookies_NoEngagement;
|
||||
case DIPSDataAccessType::kNone:
|
||||
return has_interaction ? kNoCookies_HasEngagement
|
||||
: kNoCookies_NoEngagement;
|
||||
case DIPSDataAccessType::kRead:
|
||||
return has_interaction ? kReadCookies_HasEngagement
|
||||
: kReadCookies_NoEngagement;
|
||||
case DIPSDataAccessType::kWrite:
|
||||
return has_interaction ? kWriteCookies_HasEngagement
|
||||
: kWriteCookies_NoEngagement;
|
||||
case DIPSDataAccessType::kReadWrite:
|
||||
return has_interaction ? kReadWriteCookies_HasEngagement
|
||||
: kReadWriteCookies_NoEngagement;
|
||||
}
|
||||
}
|
||||
|
||||
inline void UmaHistogramBounceCategory(RedirectCategory category,
|
||||
inline void UmaHistogramBounceCategory(DIPSRedirectCategory category,
|
||||
DIPSCookieMode mode,
|
||||
DIPSRedirectType type) {
|
||||
const std::string histogram_name =
|
||||
@ -272,9 +275,11 @@ DIPSService* DIPSService::Get(content::BrowserContext* context) {
|
||||
return DIPSServiceImpl::Get(context);
|
||||
}
|
||||
|
||||
DIPSServiceImpl::DIPSServiceImpl(base::PassKey<DIPSServiceFactory>,
|
||||
DIPSServiceImpl::DIPSServiceImpl(base::PassKey<content::BrowserContextImpl>,
|
||||
content::BrowserContext* context)
|
||||
: browser_context_(context), dips_delegate_(ChromeDipsDelegate::Create()) {
|
||||
: browser_context_(context),
|
||||
dips_delegate_(
|
||||
content::GetContentClient()->browser()->CreateDipsDelegate()) {
|
||||
DCHECK(base::FeatureList::IsEnabled(features::kDIPS));
|
||||
std::optional<base::FilePath> path_to_use;
|
||||
base::FilePath dips_path = GetDIPSFilePath(browser_context_);
|
||||
@ -329,7 +334,7 @@ DIPSServiceImpl::~DIPSServiceImpl() {
|
||||
|
||||
/* static */
|
||||
DIPSServiceImpl* DIPSServiceImpl::Get(content::BrowserContext* context) {
|
||||
return DIPSServiceFactory::GetForBrowserContext(context);
|
||||
return content::BrowserContextImpl::From(context)->GetDipsService();
|
||||
}
|
||||
|
||||
scoped_refptr<base::SequencedTaskRunner> DIPSServiceImpl::CreateTaskRunner() {
|
||||
@ -363,7 +368,7 @@ void DIPSServiceImpl::HandleRedirectChain(
|
||||
if (redirects.empty()) {
|
||||
DCHECK(!chain->is_partial_chain);
|
||||
for (auto& observer : observers_) {
|
||||
observer.OnChainHandled(chain);
|
||||
observer.OnChainHandled(redirects, chain);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -444,7 +449,7 @@ void DIPSServiceImpl::GotState(
|
||||
// All redirects handled.
|
||||
if (!chain->is_partial_chain) {
|
||||
for (auto& observer : observers_) {
|
||||
observer.OnChainHandled(chain);
|
||||
observer.OnChainHandled(redirects, chain);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@ -543,7 +548,8 @@ void DIPSServiceImpl::HandleRedirect(
|
||||
.SetRedirectChainIndex(redirect.chain_index.value())
|
||||
.SetRedirectChainLength(chain.length)
|
||||
.SetIsPartialRedirectChain(chain.is_partial_chain)
|
||||
.SetClientBounceDelay(BucketizeBounceDelay(redirect.client_bounce_delay))
|
||||
.SetClientBounceDelay(
|
||||
BucketizeDIPSBounceDelay(redirect.client_bounce_delay))
|
||||
.SetHasStickyActivation(redirect.has_sticky_activation)
|
||||
.SetWebAuthnAssertionRequestSucceeded(
|
||||
redirect.web_authn_assertion_request_succeeded)
|
||||
@ -556,15 +562,15 @@ void DIPSServiceImpl::HandleRedirect(
|
||||
}
|
||||
|
||||
// Record this bounce in the DIPS database.
|
||||
if (redirect.access_type != SiteDataAccessType::kUnknown) {
|
||||
if (redirect.access_type != DIPSDataAccessType::kUnknown) {
|
||||
record_bounce.Run(
|
||||
redirect.url.url, redirect.has_3pc_exception.value(),
|
||||
chain.final_url.url, redirect.time,
|
||||
/*stateful=*/redirect.access_type > SiteDataAccessType::kRead,
|
||||
/*stateful=*/redirect.access_type > DIPSDataAccessType::kRead,
|
||||
stateful_bounce_callback);
|
||||
}
|
||||
|
||||
RedirectCategory category =
|
||||
DIPSRedirectCategory category =
|
||||
ClassifyRedirect(redirect.access_type, redirect.has_interaction.value());
|
||||
UmaHistogramBounceCategory(category, chain.cookie_mode.value(),
|
||||
redirect.redirect_type);
|
||||
@ -682,9 +688,8 @@ void DIPSServiceImpl::RunDeletionTaskOnUIThread(std::vector<std::string> sites,
|
||||
base::OnceClosure callback) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
||||
uint64_t remove_mask = dips_delegate_
|
||||
? dips_delegate_->GetRemoveMask()
|
||||
: content::DipsDelegate::kDefaultRemoveMask;
|
||||
uint64_t remove_mask =
|
||||
dips_delegate_ ? dips_delegate_->GetRemoveMask() : kDefaultRemoveMask;
|
||||
|
||||
StateClearer::DeleteState(browser_context_->GetBrowsingDataRemover(),
|
||||
std::move(sites), remove_mask, std::move(callback));
|
||||
@ -705,15 +710,6 @@ void DIPSServiceImpl::RecordBrowserSignIn(std::string_view domain) {
|
||||
base::Time::Now(), GetCookieMode());
|
||||
}
|
||||
|
||||
void DIPSServiceImpl::MaybeNotifyCreated(base::PassKey<DIPSServiceFactory>) {
|
||||
if (delegate_notified_) {
|
||||
return;
|
||||
}
|
||||
|
||||
delegate_notified_ = true; // Set this first to prevent infinite recursion.
|
||||
ChromeDipsDelegate::Create()->OnDipsServiceCreated(browser_context_, this);
|
||||
}
|
||||
|
||||
void DIPSServiceImpl::NotifyStatefulBounce(content::WebContents* web_contents) {
|
||||
for (auto& observer : observers_) {
|
||||
observer.OnStatefulBounce(web_contents);
|
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_DIPS_DIPS_SERVICE_IMPL_H_
|
||||
#define CHROME_BROWSER_DIPS_DIPS_SERVICE_IMPL_H_
|
||||
#ifndef CONTENT_BROWSER_DIPS_DIPS_SERVICE_IMPL_H_
|
||||
#define CONTENT_BROWSER_DIPS_DIPS_SERVICE_IMPL_H_
|
||||
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/functional/callback_forward.h"
|
||||
@ -15,17 +15,16 @@
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "base/threading/sequence_bound.h"
|
||||
#include "base/types/pass_key.h"
|
||||
#include "chrome/browser/dips/dips_redirect_info.h"
|
||||
#include "chrome/browser/dips/dips_service.h"
|
||||
#include "chrome/browser/dips/dips_storage.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "components/keyed_service/core/keyed_service.h"
|
||||
#include "content/browser/dips/dips_storage.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/common/content_export.h"
|
||||
#include "content/public/browser/browsing_data_filter_builder.h"
|
||||
|
||||
class DIPSServiceFactory;
|
||||
#include "content/public/browser/dips_redirect_info.h"
|
||||
#include "content/public/browser/dips_service.h"
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
class BrowserContextImpl;
|
||||
class DipsDelegate;
|
||||
} // namespace content
|
||||
|
||||
@ -36,7 +35,7 @@ class PersistentRepeatingTimer;
|
||||
// When DIPS moves to //content, DIPSServiceImpl will *not* be exposed in the
|
||||
// Content API. Only other code in //content (such as the DIPS implementation)
|
||||
// will be allowed to access it.
|
||||
class DIPSServiceImpl : public DIPSService, public KeyedService {
|
||||
class CONTENT_EXPORT DIPSServiceImpl : public DIPSService {
|
||||
public:
|
||||
using RecordBounceCallback = base::RepeatingCallback<void(
|
||||
const GURL& url,
|
||||
@ -46,13 +45,14 @@ class DIPSServiceImpl : public DIPSService, public KeyedService {
|
||||
bool stateful,
|
||||
base::RepeatingCallback<void(const GURL&)> stateful_bounce_callback)>;
|
||||
|
||||
DIPSServiceImpl(base::PassKey<DIPSServiceFactory>,
|
||||
DIPSServiceImpl(base::PassKey<content::BrowserContextImpl>,
|
||||
content::BrowserContext* context);
|
||||
~DIPSServiceImpl() override;
|
||||
|
||||
static DIPSServiceImpl* Get(content::BrowserContext* context);
|
||||
|
||||
base::SequenceBound<DIPSStorage>* storage() { return &storage_; }
|
||||
|
||||
void RecordBounceForTesting(
|
||||
const GURL& url,
|
||||
bool has_3pc_exception,
|
||||
@ -127,10 +127,6 @@ class DIPSServiceImpl : public DIPSService, public KeyedService {
|
||||
}
|
||||
}
|
||||
|
||||
// The first time this method is called, it calls
|
||||
// DipsDelegate::OnDipsServiceCreated(). On subsequent calls, it does nothing.
|
||||
void MaybeNotifyCreated(base::PassKey<DIPSServiceFactory>);
|
||||
|
||||
// Notify Observers that a stateful bounce took place in `web_contents`.
|
||||
void NotifyStatefulBounce(content::WebContents* web_contents);
|
||||
|
||||
@ -177,11 +173,10 @@ class DIPSServiceImpl : public DIPSService, public KeyedService {
|
||||
base::SequenceBound<DIPSStorage> storage_;
|
||||
base::ObserverList<Observer> observers_;
|
||||
std::unique_ptr<content::DipsDelegate> dips_delegate_;
|
||||
bool delegate_notified_ = false;
|
||||
|
||||
std::map<std::string, int> open_sites_;
|
||||
|
||||
base::WeakPtrFactory<DIPSServiceImpl> weak_factory_{this};
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_DIPS_DIPS_SERVICE_IMPL_H_
|
||||
#endif // CONTENT_BROWSER_DIPS_DIPS_SERVICE_IMPL_H_
|
@ -2,9 +2,13 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "content/public/browser/dips_service.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/files/scoped_temp_dir.h"
|
||||
#include "base/functional/callback_forward.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/run_loop.h"
|
||||
@ -16,28 +20,22 @@
|
||||
#include "base/time/default_clock.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/types/pass_key.h"
|
||||
#include "chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h"
|
||||
#include "chrome/browser/content_settings/cookie_settings_factory.h"
|
||||
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
|
||||
#include "chrome/browser/dips/dips_bounce_detector.h"
|
||||
#include "chrome/browser/dips/dips_redirect_info.h"
|
||||
#include "chrome/browser/dips/dips_service_factory.h"
|
||||
#include "chrome/browser/dips/dips_service_impl.h"
|
||||
#include "chrome/browser/dips/dips_state.h"
|
||||
#include "chrome/browser/dips/dips_test_utils.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "chrome/test/base/testing_profile.h"
|
||||
#include "components/content_settings/core/browser/cookie_settings.h"
|
||||
#include "components/content_settings/core/browser/host_content_settings_map.h"
|
||||
#include "components/content_settings/core/common/content_settings.h"
|
||||
#include "components/content_settings/core/common/content_settings_pattern.h"
|
||||
#include "components/content_settings/core/common/pref_names.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "components/ukm/test_ukm_recorder.h"
|
||||
#include "content/browser/browser_context_impl.h"
|
||||
#include "content/browser/dips/dips_bounce_detector.h"
|
||||
#include "content/browser/dips/dips_service_impl.h"
|
||||
#include "content/browser/dips/dips_state.h"
|
||||
#include "content/browser/dips/dips_test_utils.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/dips_delegate.h"
|
||||
#include "content/public/browser/dips_redirect_info.h"
|
||||
#include "content/public/common/content_client.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
#include "content/public/test/browser_task_environment.h"
|
||||
#include "content/public/test/dips_service_test_utils.h"
|
||||
#include "content/public/test/mock_browsing_data_remover_delegate.h"
|
||||
#include "content/public/test/test_browser_context.h"
|
||||
#include "net/base/schemeful_site.h"
|
||||
#include "net/cookies/cookie_partition_key.h"
|
||||
#include "net/http/http_status_code.h"
|
||||
@ -45,8 +43,10 @@
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/blink/public/common/features_generated.h"
|
||||
#include "third_party/blink/public/common/storage_key/storage_key.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
using content::DipsRedirectChainObserver;
|
||||
using testing::AllOf;
|
||||
using testing::ElementsAre;
|
||||
using testing::IsEmpty;
|
||||
@ -59,7 +59,7 @@ bool Has3pcException(content::BrowserContext* browser_context,
|
||||
const GURL& final_url) {
|
||||
auto redirect = std::make_unique<DIPSRedirectInfo>(
|
||||
UrlAndSourceId(url, ukm::kInvalidSourceId), DIPSRedirectType::kServer,
|
||||
SiteDataAccessType::kWrite, base::Time::Now(), false, net::HTTP_FOUND,
|
||||
DIPSDataAccessType::kWrite, base::Time::Now(), false, net::HTTP_FOUND,
|
||||
base::TimeDelta());
|
||||
dips::Populate3PcExceptions(browser_context, web_contents, initial_url,
|
||||
final_url, base::span_from_ref(redirect));
|
||||
@ -93,14 +93,14 @@ class DIPSServiceTest : public testing::Test {
|
||||
TEST_F(DIPSServiceTest, CreateServiceIfFeatureEnabled) {
|
||||
ScopedInitDIPSFeature init_dips(true);
|
||||
|
||||
TestingProfile profile;
|
||||
content::TestBrowserContext profile;
|
||||
EXPECT_NE(DIPSServiceImpl::Get(&profile), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(DIPSServiceTest, DontCreateServiceIfFeatureDisabled) {
|
||||
ScopedInitDIPSFeature init_dips(false);
|
||||
|
||||
TestingProfile profile;
|
||||
content::TestBrowserContext profile;
|
||||
EXPECT_EQ(DIPSServiceImpl::Get(&profile), nullptr);
|
||||
}
|
||||
|
||||
@ -110,14 +110,14 @@ TEST_F(DIPSServiceTest, DontCreateServiceIfFeatureDisabled) {
|
||||
TEST_F(DIPSServiceTest, DeleteDbFilesIfPersistenceDisabled) {
|
||||
base::FilePath data_path = base::CreateUniqueTempDirectoryScopedToTest();
|
||||
DIPSServiceImpl* service;
|
||||
std::unique_ptr<TestingProfile> profile;
|
||||
std::unique_ptr<content::TestBrowserContext> profile;
|
||||
|
||||
// Ensure the DIPS feature is enabled and the database is set to be persisted.
|
||||
base::test::ScopedFeatureList feature_list;
|
||||
feature_list.InitAndEnableFeatureWithParameters(
|
||||
features::kDIPS, {{"persist_database", "true"}});
|
||||
|
||||
profile = TestingProfile::Builder().SetPath(data_path).Build();
|
||||
profile = std::make_unique<content::TestBrowserContext>(data_path);
|
||||
service = DIPSServiceImpl::Get(profile.get());
|
||||
ASSERT_NE(service, nullptr);
|
||||
|
||||
@ -132,10 +132,10 @@ TEST_F(DIPSServiceTest, DeleteDbFilesIfPersistenceDisabled) {
|
||||
feature_list.InitAndEnableFeatureWithParameters(
|
||||
features::kDIPS, {{"persist_database", "false"}});
|
||||
|
||||
// Reset the TestingProfile, then create a new instance with the same user
|
||||
// Reset the TestBrowserContext, then create a new instance with the same user
|
||||
// data path.
|
||||
profile.reset();
|
||||
profile = TestingProfile::Builder().SetPath(data_path).Build();
|
||||
profile = std::make_unique<content::TestBrowserContext>(data_path);
|
||||
|
||||
service = DIPSServiceImpl::Get(profile.get());
|
||||
ASSERT_NE(service, nullptr);
|
||||
@ -157,8 +157,8 @@ TEST_F(DIPSServiceTest, PreserveRegularProfileDbFiles) {
|
||||
features::kDIPS, {{"persist_database", "true"}});
|
||||
|
||||
// Build a regular profile.
|
||||
std::unique_ptr<TestingProfile> profile =
|
||||
TestingProfile::Builder().SetPath(data_path).Build();
|
||||
std::unique_ptr<content::TestBrowserContext> profile =
|
||||
std::make_unique<content::TestBrowserContext>(data_path);
|
||||
DIPSServiceImpl* service = DIPSServiceImpl::Get(profile.get());
|
||||
ASSERT_NE(service, nullptr);
|
||||
|
||||
@ -169,10 +169,10 @@ TEST_F(DIPSServiceTest, PreserveRegularProfileDbFiles) {
|
||||
ASSERT_TRUE(base::PathExists(GetDIPSFilePath(profile.get())));
|
||||
|
||||
// Build an off-the-record profile based on `profile`.
|
||||
TestingProfile* otr_profile =
|
||||
TestingProfile::Builder().SetPath(data_path).BuildIncognito(
|
||||
profile.get());
|
||||
DIPSServiceImpl* otr_service = DIPSServiceImpl::Get(otr_profile);
|
||||
std::unique_ptr<content::TestBrowserContext> otr_profile =
|
||||
std::make_unique<content::TestBrowserContext>(profile->GetPath());
|
||||
otr_profile->set_is_off_the_record(true);
|
||||
DIPSServiceImpl* otr_service = DIPSServiceImpl::Get(otr_profile.get());
|
||||
ASSERT_NE(otr_service, nullptr);
|
||||
|
||||
// Ensure the OTR profile's database has been initialized and any file
|
||||
@ -182,12 +182,18 @@ TEST_F(DIPSServiceTest, PreserveRegularProfileDbFiles) {
|
||||
|
||||
// Ensure the regular profile's database files were NOT deleted.
|
||||
EXPECT_TRUE(base::PathExists(GetDIPSFilePath(profile.get())));
|
||||
|
||||
// Every TestBrowserContext normally deletes its folder when it's destroyed.
|
||||
// But since `otr_profile` is sharing `profile`'s directory, we don't want it
|
||||
// to delete that folder (`profile` will).
|
||||
otr_profile->TakePath();
|
||||
}
|
||||
|
||||
TEST_F(DIPSServiceTest, EmptySiteEventsIgnored) {
|
||||
base::test::ScopedFeatureList feature_list;
|
||||
feature_list.InitAndEnableFeature(features::kDIPS);
|
||||
std::unique_ptr<TestingProfile> profile = std::make_unique<TestingProfile>();
|
||||
std::unique_ptr<content::TestBrowserContext> profile =
|
||||
std::make_unique<content::TestBrowserContext>();
|
||||
DIPSServiceImpl* service = DIPSServiceImpl::Get(profile.get());
|
||||
|
||||
// Record a bounce for an empty URL.
|
||||
@ -211,30 +217,20 @@ TEST_F(DIPSServiceTest, EmptySiteEventsIgnored) {
|
||||
class DIPSServiceStateRemovalTest : public testing::Test {
|
||||
public:
|
||||
DIPSServiceStateRemovalTest()
|
||||
: profile_(std::make_unique<TestingProfile>()),
|
||||
service_(DIPSServiceImpl::Get(GetProfile())),
|
||||
cookie_settings_(
|
||||
CookieSettingsFactory::GetForProfile(GetProfile()).get()) {}
|
||||
: profile_(std::make_unique<content::TestBrowserContext>()),
|
||||
service_(DIPSServiceImpl::Get(GetProfile())) {
|
||||
content::SetBrowserClientForTesting(&browser_client_);
|
||||
}
|
||||
|
||||
base::TimeDelta grace_period;
|
||||
base::TimeDelta interaction_ttl;
|
||||
base::TimeDelta tiny_delta = base::Milliseconds(1);
|
||||
|
||||
void SetBlockThirdPartyCookies(bool value) {
|
||||
GetProfile()->GetPrefs()->SetInteger(
|
||||
prefs::kCookieControlsMode,
|
||||
static_cast<int>(
|
||||
value ? content_settings::CookieControlsMode::kBlockThirdParty
|
||||
: content_settings::CookieControlsMode::kOff));
|
||||
}
|
||||
|
||||
Profile* GetProfile() { return profile_.get(); }
|
||||
content::BrowserContext* GetProfile() { return profile_.get(); }
|
||||
DIPSServiceImpl* GetService() { return service_; }
|
||||
content_settings::CookieSettings* GetCookieSettings() {
|
||||
return cookie_settings_;
|
||||
}
|
||||
|
||||
protected:
|
||||
TpcBlockingBrowserClient browser_client_;
|
||||
content::BrowserTaskEnvironment task_environment_;
|
||||
content::MockBrowsingDataRemoverDelegate delegate_;
|
||||
|
||||
@ -245,8 +241,7 @@ class DIPSServiceStateRemovalTest : public testing::Test {
|
||||
ASSERT_LT(tiny_delta, grace_period);
|
||||
|
||||
GetProfile()->GetBrowsingDataRemover()->SetEmbedderDelegate(&delegate_);
|
||||
SetBlockThirdPartyCookies(true);
|
||||
ASSERT_TRUE(GetCookieSettings()->ShouldBlockThirdPartyCookies());
|
||||
browser_client_.SetBlockThirdPartyCookiesByDefault(true);
|
||||
|
||||
DCHECK(service_);
|
||||
service_->SetStorageClockForTesting(&clock_);
|
||||
@ -274,39 +269,23 @@ class DIPSServiceStateRemovalTest : public testing::Test {
|
||||
}
|
||||
|
||||
// Add an exception to the third-party cookie blocking rule for
|
||||
// |third_party_url| embedded by |first_party_url|. If |first_party_url| is
|
||||
// not provided, |third_party_url| is allowed when embedded by any site. If
|
||||
// |third_party_url| is not provided, any sites embedded under
|
||||
// |first_party_url| are excepted.
|
||||
void Add3PCException(const std::optional<GURL>& first_party_url,
|
||||
const std::optional<GURL>& third_party_url) {
|
||||
HostContentSettingsMap* map =
|
||||
HostContentSettingsMapFactory::GetForProfile(GetProfile());
|
||||
// |third_party_url| embedded by |first_party_url|.
|
||||
void Add3PCException(const GURL& first_party_url,
|
||||
const GURL& third_party_url) {
|
||||
browser_client_.GrantCookieAccessDueToHeuristic(
|
||||
profile_.get(), net::SchemefulSite(first_party_url),
|
||||
net::SchemefulSite(third_party_url), base::Days(1),
|
||||
/*ignore_schemas=*/false);
|
||||
|
||||
ContentSettingsPattern first_party_pattern =
|
||||
first_party_url.has_value() ? ContentSettingsPattern::FromString(
|
||||
"[*.]" + first_party_url->host())
|
||||
: ContentSettingsPattern::Wildcard();
|
||||
|
||||
ContentSettingsPattern third_party_pattern =
|
||||
third_party_url.has_value() ? ContentSettingsPattern::FromString(
|
||||
"[*.]" + third_party_url->host())
|
||||
: ContentSettingsPattern::Wildcard();
|
||||
|
||||
map->SetContentSettingCustomScope(third_party_pattern, first_party_pattern,
|
||||
ContentSettingsType::COOKIES,
|
||||
ContentSetting::CONTENT_SETTING_ALLOW);
|
||||
|
||||
EXPECT_EQ(CONTENT_SETTING_BLOCK,
|
||||
GetCookieSettings()->GetCookieSetting(
|
||||
first_party_url.value_or(GURL()), net::SiteForCookies(),
|
||||
third_party_url.value_or(GURL()),
|
||||
net::CookieSettingOverrides(), nullptr));
|
||||
EXPECT_EQ(CONTENT_SETTING_ALLOW,
|
||||
GetCookieSettings()->GetCookieSetting(
|
||||
third_party_url.value_or(GURL()), net::SiteForCookies(),
|
||||
first_party_url.value_or(GURL()),
|
||||
net::CookieSettingOverrides(), nullptr));
|
||||
auto* client = content::GetContentClientForTesting()->browser();
|
||||
EXPECT_TRUE(client->IsFullCookieAccessAllowed(
|
||||
profile_.get(), nullptr, third_party_url,
|
||||
blink::StorageKey::CreateFirstParty(
|
||||
url::Origin::Create(first_party_url))));
|
||||
EXPECT_FALSE(client->IsFullCookieAccessAllowed(
|
||||
profile_.get(), nullptr, first_party_url,
|
||||
blink::StorageKey::CreateFirstParty(
|
||||
url::Origin::Create(third_party_url))));
|
||||
}
|
||||
|
||||
void RecordBounce(
|
||||
@ -325,23 +304,38 @@ class DIPSServiceStateRemovalTest : public testing::Test {
|
||||
private:
|
||||
base::SimpleTestClock clock_;
|
||||
|
||||
std::unique_ptr<TestingProfile> profile_;
|
||||
std::unique_ptr<content::TestBrowserContext> profile_;
|
||||
raw_ptr<DIPSServiceImpl, DanglingUntriaged> service_ = nullptr;
|
||||
raw_ptr<content_settings::CookieSettings, DanglingUntriaged>
|
||||
cookie_settings_ = nullptr;
|
||||
};
|
||||
|
||||
namespace {
|
||||
class RedirectChainCounter : public DIPSService::Observer {
|
||||
public:
|
||||
explicit RedirectChainCounter(DIPSService* service) { obs_.Observe(service); }
|
||||
|
||||
size_t count() const { return count_; }
|
||||
|
||||
private:
|
||||
void OnChainHandled(const std::vector<DIPSRedirectInfoPtr>& redirects,
|
||||
const DIPSRedirectChainInfoPtr& chain) override {
|
||||
count_++;
|
||||
}
|
||||
|
||||
size_t count_ = 0;
|
||||
base::ScopedObservation<DIPSService, Observer> obs_{this};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_F(DIPSServiceStateRemovalTest,
|
||||
CompleteChain_NotifiesRedirectChainObservers) {
|
||||
CompleteChain_NotifiesDipsRedirectChainObservers) {
|
||||
GetService()->SetStorageClockForTesting(base::DefaultClock::GetInstance());
|
||||
auto observer = std::make_unique<RedirectChainObserver>(
|
||||
GetService(), /*final_url=*/GURL("http://c.test/"));
|
||||
RedirectChainCounter chain_counter(GetService());
|
||||
|
||||
std::vector<DIPSRedirectInfoPtr> complete_redirects;
|
||||
complete_redirects.push_back(std::make_unique<DIPSRedirectInfo>(
|
||||
/*url=*/MakeUrlAndId("http://b.test/"),
|
||||
/*redirect_type=*/DIPSRedirectType::kServer,
|
||||
/*access_type=*/SiteDataAccessType::kNone,
|
||||
/*access_type=*/DIPSDataAccessType::kNone,
|
||||
/*time=*/Now(),
|
||||
/*was_response_cached=*/false,
|
||||
/*response_code=*/net::HTTP_FOUND,
|
||||
@ -359,20 +353,19 @@ TEST_F(DIPSServiceStateRemovalTest,
|
||||
base::BindRepeating([](const GURL& final_url) {}));
|
||||
WaitOnStorage(GetService());
|
||||
// Expect one call to Observer.OnChainHandled when handling a complete chain.
|
||||
EXPECT_EQ(observer->handle_call_count, 1u);
|
||||
EXPECT_EQ(chain_counter.count(), 1u);
|
||||
}
|
||||
|
||||
TEST_F(DIPSServiceStateRemovalTest,
|
||||
PartialChain_DoesNotNotifyRedirectChainObservers) {
|
||||
PartialChain_DoesNotNotifyDipsRedirectChainObservers) {
|
||||
GetService()->SetStorageClockForTesting(base::DefaultClock::GetInstance());
|
||||
auto observer = std::make_unique<RedirectChainObserver>(
|
||||
GetService(), /*final_url=*/GURL("http://c.test/"));
|
||||
RedirectChainCounter chain_counter(GetService());
|
||||
|
||||
std::vector<DIPSRedirectInfoPtr> partial_redirects;
|
||||
partial_redirects.push_back(std::make_unique<DIPSRedirectInfo>(
|
||||
/*url=*/MakeUrlAndId("http://b.test/"),
|
||||
/*redirect_type=*/DIPSRedirectType::kServer,
|
||||
/*access_type=*/SiteDataAccessType::kNone,
|
||||
/*access_type=*/DIPSDataAccessType::kNone,
|
||||
/*time=*/Now(),
|
||||
/*was_response_cached=*/false,
|
||||
/*response_code=*/net::HTTP_FOUND,
|
||||
@ -390,14 +383,14 @@ TEST_F(DIPSServiceStateRemovalTest,
|
||||
base::BindRepeating([](const GURL& final_url) {}));
|
||||
WaitOnStorage(GetService());
|
||||
// Expect no calls to Observer.OnChainHandled when handling a partial chain.
|
||||
EXPECT_EQ(observer->handle_call_count, 0u);
|
||||
EXPECT_EQ(chain_counter.count(), 0u);
|
||||
}
|
||||
|
||||
// NOTE: The use of a MockBrowsingDataRemoverDelegate in this test fixture
|
||||
// means that when DIPS deletion is enabled, the row for 'url' is not actually
|
||||
// removed from the DIPS db since 'delegate_' doesn't actually carryout the
|
||||
// removal task.
|
||||
TEST_F(DIPSServiceStateRemovalTest, BrowsingDataDeletion_Enabled) {
|
||||
TEST_F(DIPSServiceStateRemovalTest, DISABLED_BrowsingDataDeletion_Enabled) {
|
||||
ukm::TestAutoSetUkmRecorder ukm_recorder;
|
||||
base::test::ScopedFeatureList feature_list;
|
||||
feature_list.InitAndEnableFeatureWithParameters(
|
||||
@ -427,7 +420,7 @@ TEST_F(DIPSServiceStateRemovalTest, BrowsingDataDeletion_Enabled) {
|
||||
net::CookiePartitionKeyCollection());
|
||||
delegate_.ExpectCall(
|
||||
base::Time::Min(), base::Time::Max(),
|
||||
(chrome_browsing_data_remover::FILTERABLE_DATA_TYPES &
|
||||
(DIPSService::kDefaultRemoveMask &
|
||||
~content::BrowsingDataRemover::DATA_TYPE_PRIVACY_SANDBOX) |
|
||||
content::BrowsingDataRemover::DATA_TYPE_AVOID_CLOSING_CONNECTIONS,
|
||||
content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB |
|
||||
@ -507,7 +500,7 @@ TEST_F(DIPSServiceStateRemovalTest,
|
||||
GURL excepted_3p_url("https://excepted-as-3p.com");
|
||||
GURL non_excepted_url("https://not-excepted.com");
|
||||
|
||||
Add3PCException(std::nullopt, excepted_3p_url);
|
||||
browser_client_.GrantCookieAccessTo3pSite(excepted_3p_url);
|
||||
|
||||
int stateful_bounce_count = 0;
|
||||
base::RepeatingCallback<void(const GURL&)> increment_bounce =
|
||||
@ -554,7 +547,7 @@ TEST_F(DIPSServiceStateRemovalTest,
|
||||
GURL redirect_url_2("https://redirect-2.com");
|
||||
GURL redirect_url_3("https://redirect-3.com");
|
||||
|
||||
Add3PCException(excepted_1p_url, std::nullopt);
|
||||
browser_client_.AllowThirdPartyCookiesOnSite(excepted_1p_url);
|
||||
Add3PCException(scoped_excepted_1p_url, redirect_url_1);
|
||||
|
||||
int stateful_bounce_count = 0;
|
||||
@ -613,8 +606,11 @@ TEST_F(DIPSServiceStateRemovalTest,
|
||||
EXPECT_EQ(stateful_bounce_count, 2);
|
||||
}
|
||||
|
||||
// TODO: crbug.com/376625002 - temporarily disabled for the move to //content,
|
||||
// where there's no HostContentSettingsMap. Find an appropriate way to implement
|
||||
// this test in //content or move it back to //chrome.
|
||||
TEST_F(DIPSServiceStateRemovalTest,
|
||||
BrowsingDataDeletion_RespectsStorageAccessGrantExceptions) {
|
||||
DISABLED_BrowsingDataDeletion_RespectsStorageAccessGrantExceptions) {
|
||||
ukm::TestAutoSetUkmRecorder ukm_recorder;
|
||||
std::vector<base::test::FeatureRefAndParams> enabled_features;
|
||||
enabled_features.push_back(
|
||||
@ -631,6 +627,7 @@ TEST_F(DIPSServiceStateRemovalTest,
|
||||
GURL redirect_url_3("https://redirect-3.com");
|
||||
|
||||
// Create Storage Access grants for the required sites.
|
||||
/*
|
||||
HostContentSettingsMap* map =
|
||||
HostContentSettingsMapFactory::GetForProfile(GetProfile());
|
||||
map->SetContentSettingCustomScope(
|
||||
@ -643,7 +640,7 @@ TEST_F(DIPSServiceStateRemovalTest,
|
||||
ContentSettingsPattern::FromString(
|
||||
"[*.]" + top_level_storage_access_grant_url.host()),
|
||||
ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS, CONTENT_SETTING_ALLOW);
|
||||
|
||||
*/
|
||||
int stateful_bounce_count = 0;
|
||||
base::RepeatingCallback<void(const GURL&)> increment_bounce =
|
||||
base::BindLambdaForTesting(
|
||||
@ -701,7 +698,7 @@ TEST_F(DIPSServiceStateRemovalTest,
|
||||
TEST_F(
|
||||
DIPSServiceStateRemovalTest,
|
||||
BrowsingDataDeletion_Respects1PExceptionsForBlocking3PCWhenDefaultAllowed) {
|
||||
SetBlockThirdPartyCookies(false);
|
||||
browser_client_.SetBlockThirdPartyCookiesByDefault(false);
|
||||
|
||||
ukm::TestAutoSetUkmRecorder ukm_recorder;
|
||||
base::test::ScopedFeatureList feature_list;
|
||||
@ -716,17 +713,9 @@ TEST_F(
|
||||
GURL redirect_url_3("https://redirect-3.com");
|
||||
GURL redirect_url_4("https://redirect-4.com");
|
||||
|
||||
// Exceptions to block third-party cookies.
|
||||
HostContentSettingsMap* map =
|
||||
HostContentSettingsMapFactory::GetForProfile(GetProfile());
|
||||
map->SetContentSettingCustomScope(
|
||||
ContentSettingsPattern::Wildcard(),
|
||||
ContentSettingsPattern::FromString("[*.]" + blocked_1p_url.host()),
|
||||
ContentSettingsType::COOKIES, ContentSetting::CONTENT_SETTING_BLOCK);
|
||||
map->SetContentSettingCustomScope(
|
||||
ContentSettingsPattern::FromString("[*.]" + redirect_url_1.host()),
|
||||
ContentSettingsPattern::FromString("[*.]" + scoped_blocked_1p_url.host()),
|
||||
ContentSettingsType::COOKIES, ContentSetting::CONTENT_SETTING_BLOCK);
|
||||
// // Exceptions to block third-party cookies.
|
||||
browser_client_.BlockThirdPartyCookiesOnSite(blocked_1p_url);
|
||||
browser_client_.BlockThirdPartyCookies(redirect_url_1, scoped_blocked_1p_url);
|
||||
|
||||
int stateful_bounce_count = 0;
|
||||
base::RepeatingCallback<void(const GURL&)> increment_bounce =
|
||||
@ -812,7 +801,7 @@ TEST_F(DIPSServiceStateRemovalTest, ImmediateEnforcement) {
|
||||
net::CookiePartitionKeyCollection());
|
||||
delegate_.ExpectCall(
|
||||
base::Time::Min(), base::Time::Max(),
|
||||
(chrome_browsing_data_remover::FILTERABLE_DATA_TYPES &
|
||||
(DIPSService::kDefaultRemoveMask &
|
||||
~content::BrowsingDataRemover::DATA_TYPE_PRIVACY_SANDBOX) |
|
||||
content::BrowsingDataRemover::DATA_TYPE_AVOID_CLOSING_CONNECTIONS,
|
||||
content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB |
|
||||
@ -953,7 +942,7 @@ TEST_F(DIPSServiceHistogramTest, Deletion_ExceptedAs1P) {
|
||||
// Record a bounce.
|
||||
GURL url("https://example.com");
|
||||
GURL excepted_1p_url("https://initial.com");
|
||||
Add3PCException(excepted_1p_url, std::nullopt);
|
||||
browser_client_.AllowThirdPartyCookiesOnSite(excepted_1p_url);
|
||||
base::Time bounce_time = base::Time::FromSecondsSinceUnixEpoch(2);
|
||||
RecordBounce(url, excepted_1p_url, GURL("https://final.com"), bounce_time,
|
||||
true, base::BindRepeating([](const GURL& final_url) {}));
|
||||
@ -987,7 +976,7 @@ TEST_F(DIPSServiceHistogramTest, Deletion_ExceptedAs3P) {
|
||||
|
||||
// Record a bounce.
|
||||
GURL excepted_3p_url("https://example.com");
|
||||
Add3PCException(std::nullopt, excepted_3p_url);
|
||||
browser_client_.GrantCookieAccessTo3pSite(excepted_3p_url);
|
||||
base::Time bounce_time = base::Time::FromSecondsSinceUnixEpoch(2);
|
||||
RecordBounce(excepted_3p_url, GURL("https://initial.com"),
|
||||
GURL("https://final.com"), bounce_time, true,
|
||||
@ -1009,7 +998,7 @@ TEST_F(DIPSServiceHistogramTest, Deletion_ExceptedAs3P) {
|
||||
EXPECT_FALSE(GetDIPSState(GetService(), excepted_3p_url).has_value());
|
||||
}
|
||||
|
||||
TEST_F(DIPSServiceHistogramTest, Deletion_Enforced) {
|
||||
TEST_F(DIPSServiceHistogramTest, DISABLED_Deletion_Enforced) {
|
||||
base::test::ScopedFeatureList feature_list;
|
||||
feature_list.InitAndEnableFeatureWithParameters(
|
||||
features::kDIPS,
|
||||
@ -1055,19 +1044,19 @@ TEST_F(DIPSServiceHistogramTest, ServerBounceDelay) {
|
||||
.GetTotalCountsForPrefix(kServerRedirectsStatusCodePrefix)
|
||||
.empty());
|
||||
|
||||
TestingProfile profile;
|
||||
content::TestBrowserContext profile;
|
||||
DIPSServiceImpl* service = DIPSServiceImpl::Get(&profile);
|
||||
|
||||
UrlAndSourceId initial_url = MakeUrlAndId("http://a.test/");
|
||||
UrlAndSourceId first_redirect_url = MakeUrlAndId("http://b.test/");
|
||||
UrlAndSourceId second_redirect_url = MakeUrlAndId("http://c.test/");
|
||||
|
||||
RedirectChainObserver observer(service, GURL());
|
||||
content::DipsRedirectChainObserver observer(service, GURL());
|
||||
std::vector<DIPSRedirectInfoPtr> redirects;
|
||||
redirects.push_back(std::make_unique<DIPSRedirectInfo>(
|
||||
first_redirect_url,
|
||||
/*redirect_type=*/DIPSRedirectType::kServer,
|
||||
/*access_type=*/SiteDataAccessType::kNone,
|
||||
/*access_type=*/DIPSDataAccessType::kNone,
|
||||
/*time=*/base::Time::Now(),
|
||||
/*was_response_cached=*/true,
|
||||
/*response_code=*/net::HTTP_MOVED_PERMANENTLY,
|
||||
@ -1075,7 +1064,7 @@ TEST_F(DIPSServiceHistogramTest, ServerBounceDelay) {
|
||||
redirects.push_back(std::make_unique<DIPSRedirectInfo>(
|
||||
second_redirect_url,
|
||||
/*redirect_type=*/DIPSRedirectType::kServer,
|
||||
/*access_type=*/SiteDataAccessType::kNone,
|
||||
/*access_type=*/DIPSDataAccessType::kNone,
|
||||
/*time=*/base::Time::Now(),
|
||||
/*was_response_cached=*/false,
|
||||
/*response_code=*/net::HTTP_FOUND,
|
||||
@ -1121,7 +1110,7 @@ using DIPSServiceUkmTest = DIPSServiceTest;
|
||||
|
||||
TEST_F(DIPSServiceUkmTest, BothChainBeginAndChainEnd) {
|
||||
ukm::TestAutoSetUkmRecorder ukm_recorder;
|
||||
TestingProfile profile;
|
||||
content::TestBrowserContext profile;
|
||||
DIPSServiceImpl* service = DIPSServiceImpl::Get(&profile);
|
||||
|
||||
UrlAndSourceId initial_url = MakeUrlAndId("http://a.test/");
|
||||
@ -1129,12 +1118,12 @@ TEST_F(DIPSServiceUkmTest, BothChainBeginAndChainEnd) {
|
||||
UrlAndSourceId redirect_url2 = MakeUrlAndId("http://c.test/first");
|
||||
UrlAndSourceId final_url = MakeUrlAndId("http://c.test/second");
|
||||
|
||||
RedirectChainObserver observer(service, final_url.url);
|
||||
DipsRedirectChainObserver observer(service, final_url.url);
|
||||
std::vector<DIPSRedirectInfoPtr> redirects;
|
||||
redirects.push_back(std::make_unique<DIPSRedirectInfo>(
|
||||
redirect_url1,
|
||||
/*redirect_type=*/DIPSRedirectType::kServer,
|
||||
/*access_type=*/SiteDataAccessType::kNone,
|
||||
/*access_type=*/DIPSDataAccessType::kNone,
|
||||
/*time=*/base::Time::Now(),
|
||||
/*was_response_cached=*/false,
|
||||
/*response_code=*/net::HTTP_FOUND,
|
||||
@ -1142,7 +1131,7 @@ TEST_F(DIPSServiceUkmTest, BothChainBeginAndChainEnd) {
|
||||
redirects.push_back(std::make_unique<DIPSRedirectInfo>(
|
||||
redirect_url2,
|
||||
/*redirect_type=*/DIPSRedirectType::kServer,
|
||||
/*access_type=*/SiteDataAccessType::kNone,
|
||||
/*access_type=*/DIPSDataAccessType::kNone,
|
||||
/*time=*/base::Time::Now(),
|
||||
/*was_response_cached=*/false,
|
||||
/*response_code=*/net::HTTP_FOUND,
|
||||
@ -1185,19 +1174,19 @@ TEST_F(DIPSServiceUkmTest, BothChainBeginAndChainEnd) {
|
||||
|
||||
TEST_F(DIPSServiceUkmTest, InitialAndFinalSitesSame_True) {
|
||||
ukm::TestAutoSetUkmRecorder ukm_recorder;
|
||||
TestingProfile profile;
|
||||
content::TestBrowserContext profile;
|
||||
DIPSServiceImpl* service = DIPSServiceImpl::Get(&profile);
|
||||
|
||||
UrlAndSourceId initial_url = MakeUrlAndId("http://a.test/");
|
||||
UrlAndSourceId redirect_url = MakeUrlAndId("http://b.test/");
|
||||
UrlAndSourceId final_url = MakeUrlAndId("http://a.test/different-path");
|
||||
|
||||
RedirectChainObserver observer(service, final_url.url);
|
||||
DipsRedirectChainObserver observer(service, final_url.url);
|
||||
std::vector<DIPSRedirectInfoPtr> redirects;
|
||||
redirects.push_back(std::make_unique<DIPSRedirectInfo>(
|
||||
redirect_url,
|
||||
/*redirect_type=*/DIPSRedirectType::kServer,
|
||||
/*access_type=*/SiteDataAccessType::kNone,
|
||||
/*access_type=*/DIPSDataAccessType::kNone,
|
||||
/*time=*/base::Time::Now(),
|
||||
/*was_response_cached=*/false,
|
||||
/*response_code=*/net::HTTP_FOUND,
|
||||
@ -1233,13 +1222,13 @@ TEST_F(DIPSServiceUkmTest, InitialAndFinalSitesSame_True) {
|
||||
|
||||
TEST_F(DIPSServiceUkmTest, DontReportEmptyChainsAtAll) {
|
||||
ukm::TestAutoSetUkmRecorder ukm_recorder;
|
||||
TestingProfile profile;
|
||||
content::TestBrowserContext profile;
|
||||
DIPSServiceImpl* service = DIPSServiceImpl::Get(&profile);
|
||||
|
||||
UrlAndSourceId initial_url = MakeUrlAndId("http://a.test/");
|
||||
UrlAndSourceId final_url = MakeUrlAndId("http://b.test/");
|
||||
|
||||
RedirectChainObserver observer(service, final_url.url);
|
||||
DipsRedirectChainObserver observer(service, final_url.url);
|
||||
DIPSRedirectChainInfoPtr chain = std::make_unique<DIPSRedirectChainInfo>(
|
||||
initial_url, final_url,
|
||||
/*length=*/0, /*is_partial_chain=*/false);
|
||||
@ -1254,18 +1243,18 @@ TEST_F(DIPSServiceUkmTest, DontReportEmptyChainsAtAll) {
|
||||
|
||||
TEST_F(DIPSServiceUkmTest, DontReportChainBeginIfInvalidSourceId) {
|
||||
ukm::TestAutoSetUkmRecorder ukm_recorder;
|
||||
TestingProfile profile;
|
||||
content::TestBrowserContext profile;
|
||||
DIPSServiceImpl* service = DIPSServiceImpl::Get(&profile);
|
||||
|
||||
UrlAndSourceId redirect_url = MakeUrlAndId("http://b.test/");
|
||||
UrlAndSourceId final_url = MakeUrlAndId("http://c.test/");
|
||||
|
||||
RedirectChainObserver observer(service, final_url.url);
|
||||
DipsRedirectChainObserver observer(service, final_url.url);
|
||||
std::vector<DIPSRedirectInfoPtr> redirects;
|
||||
redirects.push_back(std::make_unique<DIPSRedirectInfo>(
|
||||
redirect_url,
|
||||
/*redirect_type=*/DIPSRedirectType::kServer,
|
||||
/*access_type=*/SiteDataAccessType::kNone,
|
||||
/*access_type=*/DIPSDataAccessType::kNone,
|
||||
/*time=*/base::Time::Now(),
|
||||
/*was_response_cached=*/false,
|
||||
/*response_code=*/net::HTTP_FOUND,
|
||||
@ -1291,18 +1280,18 @@ TEST_F(DIPSServiceUkmTest, DontReportChainBeginIfInvalidSourceId) {
|
||||
|
||||
TEST_F(DIPSServiceUkmTest, DontReportChainEndIfInvalidSourceId) {
|
||||
ukm::TestAutoSetUkmRecorder ukm_recorder;
|
||||
TestingProfile profile;
|
||||
content::TestBrowserContext profile;
|
||||
DIPSServiceImpl* service = DIPSServiceImpl::Get(&profile);
|
||||
|
||||
UrlAndSourceId initial_url = MakeUrlAndId("http://a.test/");
|
||||
UrlAndSourceId redirect_url = MakeUrlAndId("http://b.test/");
|
||||
|
||||
RedirectChainObserver observer(service, GURL());
|
||||
DipsRedirectChainObserver observer(service, GURL());
|
||||
std::vector<DIPSRedirectInfoPtr> redirects;
|
||||
redirects.push_back(std::make_unique<DIPSRedirectInfo>(
|
||||
redirect_url,
|
||||
/*redirect_type=*/DIPSRedirectType::kServer,
|
||||
/*access_type=*/SiteDataAccessType::kNone,
|
||||
/*access_type=*/DIPSDataAccessType::kNone,
|
||||
/*time=*/base::Time::Now(),
|
||||
/*was_response_cached=*/false,
|
||||
/*response_code=*/net::HTTP_FOUND,
|
||||
@ -1325,3 +1314,47 @@ TEST_F(DIPSServiceUkmTest, DontReportChainEndIfInvalidSourceId) {
|
||||
|
||||
EXPECT_THAT(ukm_recorder.GetEntries("DIPS.ChainEnd", {}), IsEmpty());
|
||||
}
|
||||
|
||||
TEST(DIPSCleanupTest, DatabaseFileIsDeletedIfFeatureIsDisabled) {
|
||||
content::BrowserTaskEnvironment task_environment;
|
||||
|
||||
base::FilePath user_data_dir;
|
||||
base::FilePath db_path;
|
||||
|
||||
// First, create a browser context while DIPS is enabled, and confirm a
|
||||
// database file is created.
|
||||
{
|
||||
content::TestBrowserContext browser_context;
|
||||
db_path = GetDIPSFilePath(&browser_context);
|
||||
// Wait for the database to be created.
|
||||
content::BrowserContextImpl::From(&browser_context)
|
||||
->GetDipsService()
|
||||
->storage()
|
||||
->FlushPostedTasksForTesting();
|
||||
ASSERT_TRUE(base::PathExists(db_path));
|
||||
|
||||
// Take ownership of the browser context's directory so we can reuse it.
|
||||
user_data_dir = browser_context.TakePath();
|
||||
|
||||
// Confirm that WaitForDipsCleanupForTesting() returns even if the file is
|
||||
// not deleted.
|
||||
content::BrowserContextImpl::From(&browser_context)
|
||||
->WaitForDipsCleanupForTesting();
|
||||
ASSERT_TRUE(base::PathExists(db_path));
|
||||
}
|
||||
|
||||
// Confirm the file still exists after the browser context is destroyed.
|
||||
ASSERT_TRUE(base::PathExists(db_path));
|
||||
|
||||
// Create another browser context for the same directory, while DIPS is
|
||||
// disabled. Confirm the database file is deleted.
|
||||
{
|
||||
ScopedInitDIPSFeature disable_dips(false);
|
||||
content::TestBrowserContext browser_context(user_data_dir);
|
||||
ASSERT_FALSE(
|
||||
content::BrowserContextImpl::From(&browser_context)->GetDipsService());
|
||||
content::BrowserContextImpl::From(&browser_context)
|
||||
->WaitForDipsCleanupForTesting();
|
||||
ASSERT_FALSE(base::PathExists(db_path));
|
||||
}
|
||||
}
|
@ -2,10 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_state.h"
|
||||
#include "content/browser/dips/dips_state.h"
|
||||
|
||||
#include "chrome/browser/dips/dips_storage.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "content/browser/dips/dips_storage.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
|
||||
DIPSState::DIPSState(DIPSStorage* storage, std::string site)
|
||||
: storage_(storage), site_(std::move(site)), was_loaded_(false) {}
|
||||
@ -19,6 +19,7 @@ DIPSState::DIPSState(DIPSStorage* storage,
|
||||
state_(state) {}
|
||||
|
||||
DIPSState::DIPSState(DIPSState&&) = default;
|
||||
DIPSState& DIPSState::operator=(DIPSState&&) = default;
|
||||
|
||||
DIPSState::~DIPSState() {
|
||||
if (dirty_) {
|
@ -2,14 +2,15 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_DIPS_DIPS_STATE_H_
|
||||
#define CHROME_BROWSER_DIPS_DIPS_STATE_H_
|
||||
#ifndef CONTENT_BROWSER_DIPS_DIPS_STATE_H_
|
||||
#define CONTENT_BROWSER_DIPS_DIPS_STATE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/common/content_export.h"
|
||||
|
||||
class DIPSStorage;
|
||||
|
||||
@ -17,7 +18,11 @@ class DIPSStorage;
|
||||
class DirtyBit {
|
||||
public:
|
||||
explicit DirtyBit(bool value = false) : value_(value) {}
|
||||
DirtyBit(DirtyBit&& old) : value_(std::exchange(old.value_, false)) {}
|
||||
DirtyBit(DirtyBit&& old) { *this = std::move(old); }
|
||||
DirtyBit& operator=(DirtyBit&& old) {
|
||||
value_ = std::exchange(old.value_, false);
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool() const { return value_; }
|
||||
|
||||
@ -37,13 +42,14 @@ class DirtyBit {
|
||||
|
||||
// Not to be confused with state stored by sites (e.g. cookies, local storage),
|
||||
// DIPSState represents the state recorded by DIPSService itself.
|
||||
class DIPSState {
|
||||
class CONTENT_EXPORT DIPSState {
|
||||
public:
|
||||
DIPSState(DIPSStorage* storage, std::string site);
|
||||
// For loaded DIPSState.
|
||||
DIPSState(DIPSStorage* storage, std::string site, const StateValue& state);
|
||||
|
||||
DIPSState(DIPSState&&);
|
||||
DIPSState& operator=(DIPSState&&);
|
||||
// Flushes changes to storage_.
|
||||
~DIPSState();
|
||||
|
||||
@ -81,4 +87,4 @@ class DIPSState {
|
||||
StateValue state_;
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_DIPS_DIPS_STATE_H_
|
||||
#endif // CONTENT_BROWSER_DIPS_DIPS_STATE_H_
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_storage.h"
|
||||
#include "content/browser/dips/dips_storage.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
#include "content/public/common/dips_utils.h"
|
||||
#include "services/network/public/mojom/clear_data_filter.mojom.h"
|
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_DIPS_DIPS_STORAGE_H_
|
||||
#define CHROME_BROWSER_DIPS_DIPS_STORAGE_H_
|
||||
#ifndef CONTENT_BROWSER_DIPS_DIPS_STORAGE_H_
|
||||
#define CONTENT_BROWSER_DIPS_DIPS_STORAGE_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
@ -14,9 +14,10 @@
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/sequence_checker.h"
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/dips/dips_database.h"
|
||||
#include "chrome/browser/dips/dips_state.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "content/browser/dips/dips_database.h"
|
||||
#include "content/browser/dips/dips_state.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/common/content_export.h"
|
||||
#include "services/network/public/mojom/network_context.mojom.h"
|
||||
|
||||
class GURL;
|
||||
@ -24,7 +25,7 @@ class GURL;
|
||||
using UrlPredicate = base::RepeatingCallback<bool(const GURL&)>;
|
||||
|
||||
// Manages the storage of DIPSState values.
|
||||
class DIPSStorage {
|
||||
class CONTENT_EXPORT DIPSStorage {
|
||||
public:
|
||||
explicit DIPSStorage(const std::optional<base::FilePath>& path);
|
||||
~DIPSStorage();
|
||||
@ -147,4 +148,4 @@ class DIPSStorage {
|
||||
base::WeakPtrFactory<DIPSStorage> weak_factory_{this};
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_DIPS_DIPS_STORAGE_H_
|
||||
#endif // CONTENT_BROWSER_DIPS_DIPS_STORAGE_H_
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_storage.h"
|
||||
#include "content/browser/dips/dips_storage.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
@ -16,8 +16,8 @@
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/threading/sequence_bound.h"
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/dips/dips_state.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "content/browser/dips/dips_state.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/public/browser/browsing_data_filter_builder.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
#include "services/network/public/mojom/clear_data_filter.mojom.h"
|
||||
@ -799,9 +799,9 @@ TEST_F(DIPSStorageTest, RemoveBySite) {
|
||||
EXPECT_FALSE(state1.site_storage_times().has_value()); // removed
|
||||
EXPECT_EQ(state1.user_interaction_times()->first,
|
||||
std::make_optional(
|
||||
base::Time::FromSecondsSinceUnixEpoch(2))); // no change
|
||||
EXPECT_FALSE(state1.stateful_bounce_times().has_value()); // removed
|
||||
EXPECT_FALSE(state1.bounce_times().has_value()); // removed
|
||||
base::Time::FromSecondsSinceUnixEpoch(2))); // no change
|
||||
EXPECT_FALSE(state1.stateful_bounce_times().has_value()); // removed
|
||||
EXPECT_FALSE(state1.bounce_times().has_value()); // removed
|
||||
|
||||
DIPSState state2 = storage_.Read(url2);
|
||||
EXPECT_EQ(state2.site_storage_times()->first,
|
@ -2,21 +2,22 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_test_utils.h"
|
||||
#include "content/browser/dips/dips_test_utils.h"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "base/test/bind.h"
|
||||
#include "chrome/browser/dips/dips_cleanup_service_factory.h"
|
||||
#include "chrome/browser/dips/dips_service.h"
|
||||
#include "chrome/browser/dips/dips_service_factory.h"
|
||||
#include "chrome/browser/dips/dips_service_impl.h"
|
||||
#include "content/browser/dips/dips_service_impl.h"
|
||||
#include "content/public/browser/browsing_data_remover.h"
|
||||
#include "content/public/browser/dips_delegate.h"
|
||||
#include "content/public/browser/dips_service.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
#include "content/public/test/browser_test_utils.h"
|
||||
#include "content/public/test/hit_test_region_observer.h"
|
||||
#include "content/public/test/test_frame_navigation_observer.h"
|
||||
#include "content/public/test/test_utils.h"
|
||||
#include "net/base/schemeful_site.h"
|
||||
#include "net/test/embedded_test_server/embedded_test_server.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
|
||||
@ -226,29 +227,6 @@ void FrameCookieAccessObserver::OnCookiesAccessed(
|
||||
}
|
||||
}
|
||||
|
||||
RedirectChainObserver::RedirectChainObserver(DIPSService* service,
|
||||
GURL final_url,
|
||||
size_t expected_match_count)
|
||||
: final_url_(std::move(final_url)),
|
||||
expected_match_count_(expected_match_count) {
|
||||
obs_.Observe(service);
|
||||
}
|
||||
|
||||
RedirectChainObserver::~RedirectChainObserver() = default;
|
||||
|
||||
void RedirectChainObserver::OnChainHandled(
|
||||
const DIPSRedirectChainInfoPtr& chain) {
|
||||
handle_call_count++;
|
||||
if (chain->final_url.url == final_url_ &&
|
||||
++match_count_ == expected_match_count_) {
|
||||
run_loop_.Quit();
|
||||
}
|
||||
}
|
||||
|
||||
void RedirectChainObserver::Wait() {
|
||||
run_loop_.Run();
|
||||
}
|
||||
|
||||
UserActivationObserver::UserActivationObserver(
|
||||
WebContents* web_contents,
|
||||
RenderFrameHost* render_frame_host)
|
||||
@ -360,59 +338,112 @@ UrlAndSourceId MakeUrlAndId(std::string_view url) {
|
||||
return UrlAndSourceId(GURL(url), ukm::AssignNewSourceId());
|
||||
}
|
||||
|
||||
testing::AssertionResult SimulateDipsBounce(content::WebContents* web_contents,
|
||||
const GURL& initial_url,
|
||||
const GURL& bounce_url,
|
||||
const GURL& final_url,
|
||||
const GURL& next_initial_url) {
|
||||
if (web_contents->GetLastCommittedURL() == initial_url) {
|
||||
return testing::AssertionFailure() << "Already on " << initial_url;
|
||||
TpcBlockingBrowserClient::TpcBlockingBrowserClient() = default;
|
||||
TpcBlockingBrowserClient::~TpcBlockingBrowserClient() = default;
|
||||
|
||||
bool TpcBlockingBrowserClient::IsFullCookieAccessAllowed(
|
||||
content::BrowserContext* browser_context,
|
||||
content::WebContents* web_contents,
|
||||
const GURL& url,
|
||||
const blink::StorageKey& storage_key) {
|
||||
// TODO: crbug.com/384531044 - implement this method by subclassing
|
||||
// `content_settings::CookieSettingsBase` and calling its
|
||||
// `IsFullCookieAccessAllowed()`.
|
||||
const net::SchemefulSite top_level_site = storage_key.top_level_site();
|
||||
const net::SchemefulSite url_site(url);
|
||||
|
||||
if (base::Contains(tpc_1p_blocks_, top_level_site)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DIPSService* dips_service =
|
||||
DIPSService::Get(web_contents->GetBrowserContext());
|
||||
RedirectChainObserver initial_observer(dips_service, initial_url);
|
||||
if (!content::NavigateToURL(web_contents, initial_url)) {
|
||||
return testing::AssertionFailure()
|
||||
<< "Failed to navigate to " << initial_url;
|
||||
}
|
||||
initial_observer.Wait();
|
||||
|
||||
if (testing::Test::HasFailure()) {
|
||||
return testing::AssertionFailure()
|
||||
<< "Failure generated while waiting for the previous redirect chain "
|
||||
"to be reported";
|
||||
if (base::Contains(tpc_blocks_, std::make_pair(top_level_site, url_site))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!content::NavigateToURLFromRenderer(web_contents, bounce_url)) {
|
||||
return testing::AssertionFailure()
|
||||
<< "Failed to navigate to " << bounce_url;
|
||||
if (!block_3pcs_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
testing::AssertionResult js_result =
|
||||
content::ExecJs(web_contents, "document.cookie = 'bounce=stateful';",
|
||||
content::EXECUTE_SCRIPT_NO_USER_GESTURE);
|
||||
if (!js_result) {
|
||||
return js_result;
|
||||
if (storage_key.ToNetSiteForCookies().IsFirstParty(url)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
RedirectChainObserver final_observer(dips_service, final_url);
|
||||
if (!content::NavigateToURLFromRendererWithoutUserGesture(web_contents,
|
||||
final_url)) {
|
||||
return testing::AssertionFailure() << "Failed to navigate to " << final_url;
|
||||
// XXX how should we use storage_key.origin() ?
|
||||
if (base::Contains(tpc_1p_site_exceptions_, top_level_site)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// End redirect chain by navigating with a user gesture.
|
||||
if (!content::NavigateToURLFromRenderer(web_contents, next_initial_url)) {
|
||||
return testing::AssertionFailure()
|
||||
<< "Failed to navigate to " << next_initial_url;
|
||||
}
|
||||
final_observer.Wait();
|
||||
|
||||
if (testing::Test::HasFailure()) {
|
||||
return testing::AssertionFailure() << "Failure generated while waiting for "
|
||||
"the redirect chain to be reported";
|
||||
if (base::Contains(tpc_3p_site_exceptions_, url_site)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return testing::AssertionSuccess();
|
||||
if (base::Contains(
|
||||
schemeless_tpc_exceptions_,
|
||||
std::make_pair(
|
||||
top_level_site.registrable_domain_or_host_for_testing(),
|
||||
url_site.registrable_domain_or_host_for_testing()))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool b =
|
||||
base::Contains(tpc_exceptions_, std::make_pair(top_level_site, url_site));
|
||||
return b;
|
||||
}
|
||||
|
||||
void TpcBlockingBrowserClient::GrantCookieAccessDueToHeuristic(
|
||||
content::BrowserContext* browser_context,
|
||||
const net::SchemefulSite& top_frame_site,
|
||||
const net::SchemefulSite& accessing_site,
|
||||
base::TimeDelta ttl,
|
||||
bool ignore_schemes) {
|
||||
if (ignore_schemes) {
|
||||
schemeless_tpc_exceptions_.emplace(
|
||||
top_frame_site.registrable_domain_or_host_for_testing(),
|
||||
accessing_site.registrable_domain_or_host_for_testing());
|
||||
} else {
|
||||
tpc_exceptions_.emplace(top_frame_site, accessing_site);
|
||||
}
|
||||
}
|
||||
|
||||
// A DipsDelegate that only differs from the default (i.e., no delegate)
|
||||
// behavior in one way: ShouldDeleteInteractionRecords() checks for the
|
||||
// DATA_TYPE_HISTORY bit.
|
||||
class SimpleDipsDelegate : public content::DipsDelegate {
|
||||
public:
|
||||
bool ShouldEnableDips(content::BrowserContext* browser_context) override {
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnDipsServiceCreated(content::BrowserContext* browser_context,
|
||||
DIPSService* dips_service) override {}
|
||||
|
||||
uint64_t GetRemoveMask() override { return DIPSService::kDefaultRemoveMask; }
|
||||
|
||||
bool ShouldDeleteInteractionRecords(uint64_t remove_mask) override {
|
||||
return remove_mask & TpcBlockingBrowserClient::DATA_TYPE_HISTORY;
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<content::DipsDelegate>
|
||||
TpcBlockingBrowserClient::CreateDipsDelegate() {
|
||||
return std::make_unique<SimpleDipsDelegate>();
|
||||
}
|
||||
|
||||
void TpcBlockingBrowserClient::AllowThirdPartyCookiesOnSite(const GURL& url) {
|
||||
tpc_1p_site_exceptions_.emplace(url);
|
||||
}
|
||||
|
||||
void TpcBlockingBrowserClient::GrantCookieAccessTo3pSite(const GURL& url) {
|
||||
tpc_3p_site_exceptions_.emplace(url);
|
||||
}
|
||||
|
||||
void TpcBlockingBrowserClient::BlockThirdPartyCookiesOnSite(const GURL& url) {
|
||||
tpc_1p_blocks_.emplace(url);
|
||||
}
|
||||
|
||||
void TpcBlockingBrowserClient::BlockThirdPartyCookies(
|
||||
const GURL& url,
|
||||
const GURL& first_party_url) {
|
||||
tpc_blocks_.emplace(net::SchemefulSite(first_party_url),
|
||||
net::SchemefulSite(url));
|
||||
}
|
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_DIPS_DIPS_TEST_UTILS_H_
|
||||
#define CHROME_BROWSER_DIPS_DIPS_TEST_UTILS_H_
|
||||
#ifndef CONTENT_BROWSER_DIPS_DIPS_TEST_UTILS_H_
|
||||
#define CONTENT_BROWSER_DIPS_DIPS_TEST_UTILS_H_
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
@ -14,13 +14,12 @@
|
||||
#include "base/scoped_observation.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "chrome/browser/dips/dips_redirect_info.h"
|
||||
#include "chrome/browser/dips/dips_service.h"
|
||||
#include "chrome/browser/dips/dips_service_impl.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "chrome/browser/profiles/profile_test_util.h"
|
||||
#include "components/ukm/test_ukm_recorder.h"
|
||||
#include "content/browser/dips/dips_service_impl.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/public/browser/cookie_access_details.h"
|
||||
#include "content/public/browser/dips_redirect_info.h"
|
||||
#include "content/public/browser/dips_service.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "content/public/test/browser_test_utils.h"
|
||||
@ -187,27 +186,6 @@ class FrameCookieAccessObserver : public content::WebContentsObserver {
|
||||
base::RunLoop run_loop_;
|
||||
};
|
||||
|
||||
class RedirectChainObserver : public DIPSService::Observer {
|
||||
public:
|
||||
explicit RedirectChainObserver(DIPSService* service,
|
||||
GURL final_url,
|
||||
size_t expected_match_count = 1);
|
||||
~RedirectChainObserver() override;
|
||||
|
||||
void OnChainHandled(const DIPSRedirectChainInfoPtr& chain) override;
|
||||
|
||||
void Wait();
|
||||
|
||||
size_t handle_call_count = 0;
|
||||
|
||||
private:
|
||||
GURL final_url_;
|
||||
size_t match_count_ = 0;
|
||||
size_t expected_match_count_;
|
||||
base::RunLoop run_loop_;
|
||||
base::ScopedObservation<DIPSService, Observer> obs_{this};
|
||||
};
|
||||
|
||||
class UserActivationObserver : public content::WebContentsObserver {
|
||||
public:
|
||||
explicit UserActivationObserver(content::WebContents* web_contents,
|
||||
@ -305,14 +283,46 @@ void SimulateMouseClickAndWait(content::WebContents*);
|
||||
// Make a UrlAndSourceId with a randomly-generated UKM source id.
|
||||
UrlAndSourceId MakeUrlAndId(std::string_view url);
|
||||
|
||||
// Cause DIPS to record a stateful client bounce on `bounce_url` to `final_url`.
|
||||
// The redirect chain will be started by performing a browser-initiated
|
||||
// navigation to `initial_url`, and terminated by another such navigation to
|
||||
// `next_url`.
|
||||
testing::AssertionResult SimulateDipsBounce(content::WebContents*,
|
||||
const GURL& initial_url,
|
||||
const GURL& bounce_url,
|
||||
const GURL& final_url,
|
||||
const GURL& next_url);
|
||||
// A ContentBrowserClient that supports third-party cookie blocking. Note that
|
||||
// this can only be used directly by unit tests; browser tests must use
|
||||
// ContentBrowserTestTpcBlockingBrowserClient instead.
|
||||
class TpcBlockingBrowserClient : public content::ContentBrowserClient {
|
||||
public:
|
||||
static constexpr uint64_t DATA_TYPE_HISTORY =
|
||||
content::BrowsingDataRemover::DATA_TYPE_CONTENT_END << 1;
|
||||
|
||||
#endif // CHROME_BROWSER_DIPS_DIPS_TEST_UTILS_H_
|
||||
TpcBlockingBrowserClient();
|
||||
~TpcBlockingBrowserClient() override;
|
||||
|
||||
void SetBlockThirdPartyCookiesByDefault(bool block) { block_3pcs_ = block; }
|
||||
|
||||
bool IsFullCookieAccessAllowed(content::BrowserContext* browser_context,
|
||||
content::WebContents* web_contents,
|
||||
const GURL& url,
|
||||
const blink::StorageKey& storage_key) override;
|
||||
|
||||
void GrantCookieAccessDueToHeuristic(content::BrowserContext* browser_context,
|
||||
const net::SchemefulSite& top_frame_site,
|
||||
const net::SchemefulSite& accessing_site,
|
||||
base::TimeDelta ttl,
|
||||
bool ignore_schemes) override;
|
||||
|
||||
std::unique_ptr<content::DipsDelegate> CreateDipsDelegate() override;
|
||||
|
||||
void AllowThirdPartyCookiesOnSite(const GURL& url);
|
||||
void GrantCookieAccessTo3pSite(const GURL& url);
|
||||
|
||||
void BlockThirdPartyCookiesOnSite(const GURL& url);
|
||||
void BlockThirdPartyCookies(const GURL& url, const GURL& first_party_url);
|
||||
|
||||
private:
|
||||
bool block_3pcs_ = false;
|
||||
std::set<net::SchemefulSite> tpc_1p_site_exceptions_;
|
||||
std::set<net::SchemefulSite> tpc_3p_site_exceptions_;
|
||||
std::set<std::pair<std::string, std::string>> schemeless_tpc_exceptions_;
|
||||
std::set<std::pair<net::SchemefulSite, net::SchemefulSite>> tpc_exceptions_;
|
||||
std::set<net::SchemefulSite> tpc_1p_blocks_;
|
||||
std::set<std::pair<net::SchemefulSite, net::SchemefulSite>> tpc_blocks_;
|
||||
};
|
||||
|
||||
#endif // CONTENT_BROWSER_DIPS_DIPS_TEST_UTILS_H_
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string_view>
|
||||
@ -17,6 +17,39 @@
|
||||
#include "url/gurl.h"
|
||||
#include "url/origin.h"
|
||||
|
||||
base::cstring_view DIPSCookieModeToString(DIPSCookieMode mode) {
|
||||
switch (mode) {
|
||||
case DIPSCookieMode::kBlock3PC:
|
||||
return "Block3PC";
|
||||
case DIPSCookieMode::kOffTheRecord_Block3PC:
|
||||
return "OffTheRecord_Block3PC";
|
||||
}
|
||||
}
|
||||
|
||||
base::cstring_view DIPSRedirectTypeToString(DIPSRedirectType type) {
|
||||
switch (type) {
|
||||
case DIPSRedirectType::kClient:
|
||||
return "Client";
|
||||
case DIPSRedirectType::kServer:
|
||||
return "Server";
|
||||
}
|
||||
}
|
||||
|
||||
base::cstring_view DIPSDataAccessTypeToString(DIPSDataAccessType type) {
|
||||
switch (type) {
|
||||
case DIPSDataAccessType::kUnknown:
|
||||
return "Unknown";
|
||||
case DIPSDataAccessType::kNone:
|
||||
return "None";
|
||||
case DIPSDataAccessType::kRead:
|
||||
return "Read";
|
||||
case DIPSDataAccessType::kWrite:
|
||||
return "Write";
|
||||
case DIPSDataAccessType::kReadWrite:
|
||||
return "ReadWrite";
|
||||
}
|
||||
}
|
||||
|
||||
base::FilePath GetDIPSFilePath(content::BrowserContext* context) {
|
||||
return context->GetPath().Append(kDIPSFilename);
|
||||
}
|
||||
@ -59,9 +92,9 @@ std::ostream& operator<<(std::ostream& os, TimestampRange range) {
|
||||
return os << "[" << range->first << ", " << range->second << "]";
|
||||
}
|
||||
|
||||
// SiteDataAccessType:
|
||||
std::ostream& operator<<(std::ostream& os, SiteDataAccessType access_type) {
|
||||
return os << SiteDataAccessTypeToString(access_type);
|
||||
// DIPSDataAccessType:
|
||||
std::ostream& operator<<(std::ostream& os, DIPSDataAccessType access_type) {
|
||||
return os << DIPSDataAccessTypeToString(access_type);
|
||||
}
|
||||
|
||||
// DIPSCookieMode:
|
||||
@ -105,7 +138,7 @@ std::ostream& operator<<(std::ostream& os, DIPSRedirectType type) {
|
||||
return os << DIPSRedirectTypeToString(type);
|
||||
}
|
||||
|
||||
int64_t BucketizeBounceDelay(base::TimeDelta delta) {
|
||||
int64_t BucketizeDIPSBounceDelay(base::TimeDelta delta) {
|
||||
return std::clamp(delta.InSeconds(), INT64_C(0), INT64_C(10));
|
||||
}
|
||||
|
||||
@ -149,8 +182,6 @@ bool HasSameSiteIframe(content::WebContents* web_contents, const GURL& url) {
|
||||
return found;
|
||||
}
|
||||
|
||||
const base::TimeDelta kDIPSTimestampUpdateInterval = base::Minutes(1);
|
||||
|
||||
bool UpdateTimestamp(std::optional<base::Time>& last_time, base::Time now) {
|
||||
if (!last_time.has_value() ||
|
||||
(now - last_time.value()) >= kDIPSTimestampUpdateInterval) {
|
@ -2,17 +2,19 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_DIPS_DIPS_UTILS_H_
|
||||
#define CHROME_BROWSER_DIPS_DIPS_UTILS_H_
|
||||
#ifndef CONTENT_BROWSER_DIPS_DIPS_UTILS_H_
|
||||
#define CONTENT_BROWSER_DIPS_DIPS_UTILS_H_
|
||||
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <string_view>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/strings/cstring_view.h"
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/dips/dips_redirect_info.h"
|
||||
#include "content/common/content_export.h"
|
||||
#include "content/public/browser/cookie_access_details.h"
|
||||
#include "content/public/browser/dips_redirect_info.h"
|
||||
#include "content/public/browser/navigation_handle.h"
|
||||
#include "content/public/browser/page.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
@ -31,8 +33,15 @@ namespace url {
|
||||
class Origin;
|
||||
}
|
||||
|
||||
// For use in tests/debugging.
|
||||
CONTENT_EXPORT base::cstring_view DIPSCookieModeToString(DIPSCookieMode mode);
|
||||
CONTENT_EXPORT base::cstring_view DIPSRedirectTypeToString(
|
||||
DIPSRedirectType type);
|
||||
CONTENT_EXPORT base::cstring_view DIPSDataAccessTypeToString(
|
||||
DIPSDataAccessType type);
|
||||
|
||||
// A single cookie-accessing operation (either read or write). Not to be
|
||||
// confused with SiteDataAccessType, which can also represent no access or both
|
||||
// confused with DIPSDataAccessType, which can also represent no access or both
|
||||
// read+write.
|
||||
using CookieOperation = network::mojom::CookieAccessDetails::Type;
|
||||
|
||||
@ -43,19 +52,24 @@ const base::FilePath::CharType kDIPSFilename[] = FILE_PATH_LITERAL("DIPS");
|
||||
// if one exists.
|
||||
// NOTE: This returns the same value regardless of if there is actually a
|
||||
// persisted DIPSDatabase for the BrowserContext or not.
|
||||
base::FilePath GetDIPSFilePath(content::BrowserContext* context);
|
||||
CONTENT_EXPORT base::FilePath GetDIPSFilePath(content::BrowserContext* context);
|
||||
|
||||
inline SiteDataAccessType ToSiteDataAccessType(CookieOperation op) {
|
||||
return (op == CookieOperation::kChange ? SiteDataAccessType::kWrite
|
||||
: SiteDataAccessType::kRead);
|
||||
inline DIPSDataAccessType ToDIPSDataAccessType(CookieOperation op) {
|
||||
return (op == CookieOperation::kChange ? DIPSDataAccessType::kWrite
|
||||
: DIPSDataAccessType::kRead);
|
||||
}
|
||||
std::ostream& operator<<(std::ostream& os, SiteDataAccessType access_type);
|
||||
CONTENT_EXPORT std::ostream& operator<<(std::ostream& os,
|
||||
DIPSDataAccessType access_type);
|
||||
|
||||
constexpr SiteDataAccessType operator|(SiteDataAccessType lhs,
|
||||
SiteDataAccessType rhs) {
|
||||
return static_cast<SiteDataAccessType>(static_cast<int>(lhs) |
|
||||
constexpr DIPSDataAccessType operator|(DIPSDataAccessType lhs,
|
||||
DIPSDataAccessType rhs) {
|
||||
return static_cast<DIPSDataAccessType>(static_cast<int>(lhs) |
|
||||
static_cast<int>(rhs));
|
||||
}
|
||||
inline DIPSDataAccessType& operator|=(DIPSDataAccessType& lhs,
|
||||
DIPSDataAccessType rhs) {
|
||||
return (lhs = lhs | rhs);
|
||||
}
|
||||
|
||||
DIPSCookieMode GetDIPSCookieMode(bool is_otr);
|
||||
std::string_view GetHistogramSuffix(DIPSCookieMode mode);
|
||||
@ -95,14 +109,17 @@ constexpr DIPSEventRemovalType& operator&=(DIPSEventRemovalType& lhs,
|
||||
}
|
||||
|
||||
std::string_view GetHistogramPiece(DIPSRedirectType type);
|
||||
std::ostream& operator<<(std::ostream& os, DIPSRedirectType type);
|
||||
CONTENT_EXPORT std::ostream& operator<<(std::ostream& os,
|
||||
DIPSRedirectType type);
|
||||
|
||||
using TimestampRange = std::optional<std::pair<base::Time, base::Time>>;
|
||||
// Expand the range to include `time` if necessary. Returns true iff the range
|
||||
// was modified.
|
||||
bool UpdateTimestampRange(TimestampRange& range, base::Time time);
|
||||
CONTENT_EXPORT bool UpdateTimestampRange(TimestampRange& range,
|
||||
base::Time time);
|
||||
// Checks that `this` range is either null or falls within `other`.
|
||||
bool IsNullOrWithin(const TimestampRange& inner, const TimestampRange& outer);
|
||||
CONTENT_EXPORT bool IsNullOrWithin(const TimestampRange& inner,
|
||||
const TimestampRange& outer);
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, TimestampRange type);
|
||||
|
||||
@ -129,6 +146,8 @@ struct PopupWithTime {
|
||||
base::Time last_popup_time;
|
||||
};
|
||||
|
||||
// These values are emitted in metrics and should not be renumbered. This one
|
||||
// type is used for both of the IsAdTagged and HasSameSiteIframe UKM enums.
|
||||
enum class OptionalBool {
|
||||
kUnknown = 0,
|
||||
kFalse = 1,
|
||||
@ -148,15 +167,15 @@ inline bool operator==(const StateValue& lhs, const StateValue& rhs) {
|
||||
rhs.web_authn_assertion_times);
|
||||
}
|
||||
|
||||
// Return the number of seconds in `td`, clamped to [0, 10].
|
||||
// Return the number of seconds in `delta`, clamped to [0, 10].
|
||||
// i.e. 11 linearly-sized buckets.
|
||||
int64_t BucketizeBounceDelay(base::TimeDelta delta);
|
||||
CONTENT_EXPORT int64_t BucketizeDIPSBounceDelay(base::TimeDelta delta);
|
||||
|
||||
// Returns an opaque value representing the "privacy boundary" that the URL
|
||||
// belongs to. Currently returns eTLD+1, but this is an implementation detail
|
||||
// and may change.
|
||||
std::string GetSiteForDIPS(const GURL& url);
|
||||
std::string GetSiteForDIPS(const url::Origin& origin);
|
||||
CONTENT_EXPORT std::string GetSiteForDIPS(const GURL& url);
|
||||
CONTENT_EXPORT std::string GetSiteForDIPS(const url::Origin& origin);
|
||||
|
||||
// Returns true iff `web_contents` contains an iframe whose committed URL
|
||||
// belongs to the same site as `url`.
|
||||
@ -165,10 +184,11 @@ bool HasSameSiteIframe(content::WebContents* web_contents, const GURL& url);
|
||||
// Returns whether the provided cookie access was ad-tagged, based on the cookie
|
||||
// settings overrides. Returns Unknown if kSkipTpcdMitigationsForAdsHeuristics
|
||||
// is false and the override is not set regardless.
|
||||
OptionalBool IsAdTaggedCookieForHeuristics(
|
||||
const content::CookieAccessDetails& details);
|
||||
CONTENT_EXPORT OptionalBool
|
||||
IsAdTaggedCookieForHeuristics(const content::CookieAccessDetails& details);
|
||||
|
||||
bool HasCHIPS(const net::CookieAccessResultList& cookie_access_result_list);
|
||||
CONTENT_EXPORT bool HasCHIPS(
|
||||
const net::CookieAccessResultList& cookie_access_result_list);
|
||||
|
||||
// Returns `True` iff the `navigation_handle` represents a navigation
|
||||
// happening in an iframe of the primary frame tree.
|
||||
@ -224,10 +244,12 @@ inline std::optional<GURL> GetFirstPartyURL(content::RenderFrameHost* rfh) {
|
||||
// The amount of time since a page last received user interaction before a
|
||||
// subsequent user interaction event may be recorded to DIPS Storage for the
|
||||
// same page.
|
||||
extern const base::TimeDelta kDIPSTimestampUpdateInterval;
|
||||
inline constexpr base::TimeDelta kDIPSTimestampUpdateInterval =
|
||||
base::Minutes(1);
|
||||
|
||||
[[nodiscard]] bool UpdateTimestamp(std::optional<base::Time>& last_time,
|
||||
base::Time now);
|
||||
[[nodiscard]] CONTENT_EXPORT bool UpdateTimestamp(
|
||||
std::optional<base::Time>& last_time,
|
||||
base::Time now);
|
||||
|
||||
// DIPSInteractionType is used in UKM to record the way the user interacted with
|
||||
// the site. It should match CookieHeuristicInteractionType in
|
||||
@ -244,12 +266,12 @@ enum class DIPSRecordedEvent {
|
||||
kWebAuthnAssertion,
|
||||
};
|
||||
|
||||
// RedirectCategory is basically the cross-product of SiteDataAccessType and a
|
||||
// boolean value indicating site engagement. It's used in UMA enum histograms.
|
||||
// DIPSRedirectCategory is basically the cross-product of DIPSDataAccessType and
|
||||
// a boolean value indicating site engagement. It's used in UMA enum histograms.
|
||||
//
|
||||
// These values are persisted to logs. Entries should not be renumbered and
|
||||
// numeric values should never be reused.
|
||||
enum class RedirectCategory {
|
||||
enum class DIPSRedirectCategory {
|
||||
kNoCookies_NoEngagement = 0,
|
||||
kReadCookies_NoEngagement = 1,
|
||||
kWriteCookies_NoEngagement = 2,
|
||||
@ -307,4 +329,4 @@ enum class DIPSDatabaseTable {
|
||||
kMaxValue = kPopups,
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_DIPS_DIPS_UTILS_H_
|
||||
#endif // CONTENT_BROWSER_DIPS_DIPS_UTILS_H_
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/time/time.h"
|
||||
@ -101,23 +101,23 @@ TEST(TimestampRangeTest, IsNullOrWithin_AllowsEquals) {
|
||||
EXPECT_TRUE(IsNullOrWithin(range, range));
|
||||
}
|
||||
|
||||
TEST(BucketizeBounceDelayTest, BucketizeBounceDelay) {
|
||||
TEST(BucketizeDIPSBounceDelayTest, BucketizeDIPSBounceDelay) {
|
||||
// any TimeDelta in (-inf, 1s) should return 0
|
||||
EXPECT_EQ(0, BucketizeBounceDelay(base::Days(-1)));
|
||||
EXPECT_EQ(0, BucketizeBounceDelay(base::Milliseconds(0)));
|
||||
EXPECT_EQ(0, BucketizeBounceDelay(base::Milliseconds(999)));
|
||||
EXPECT_EQ(0, BucketizeDIPSBounceDelay(base::Days(-1)));
|
||||
EXPECT_EQ(0, BucketizeDIPSBounceDelay(base::Milliseconds(0)));
|
||||
EXPECT_EQ(0, BucketizeDIPSBounceDelay(base::Milliseconds(999)));
|
||||
// anything in [1s, 2s) should return 1
|
||||
EXPECT_EQ(1, BucketizeBounceDelay(base::Milliseconds(1000)));
|
||||
EXPECT_EQ(1, BucketizeBounceDelay(base::Milliseconds(1999)));
|
||||
EXPECT_EQ(1, BucketizeDIPSBounceDelay(base::Milliseconds(1000)));
|
||||
EXPECT_EQ(1, BucketizeDIPSBounceDelay(base::Milliseconds(1999)));
|
||||
// similarly for [2s, 3s)
|
||||
EXPECT_EQ(2, BucketizeBounceDelay(base::Milliseconds(2000)));
|
||||
EXPECT_EQ(2, BucketizeBounceDelay(base::Milliseconds(2999)));
|
||||
EXPECT_EQ(2, BucketizeDIPSBounceDelay(base::Milliseconds(2000)));
|
||||
EXPECT_EQ(2, BucketizeDIPSBounceDelay(base::Milliseconds(2999)));
|
||||
// ...
|
||||
EXPECT_EQ(9, BucketizeBounceDelay(base::Milliseconds(9999)));
|
||||
EXPECT_EQ(9, BucketizeDIPSBounceDelay(base::Milliseconds(9999)));
|
||||
// anything in [10s, inf) should return 10
|
||||
EXPECT_EQ(10, BucketizeBounceDelay(base::Milliseconds(10000)));
|
||||
EXPECT_EQ(10, BucketizeBounceDelay(base::Milliseconds(10001)));
|
||||
EXPECT_EQ(10, BucketizeBounceDelay(base::Days(1)));
|
||||
EXPECT_EQ(10, BucketizeDIPSBounceDelay(base::Milliseconds(10000)));
|
||||
EXPECT_EQ(10, BucketizeDIPSBounceDelay(base::Milliseconds(10001)));
|
||||
EXPECT_EQ(10, BucketizeDIPSBounceDelay(base::Days(1)));
|
||||
}
|
||||
|
||||
TEST(UpdateTimestampTest, AlwaysReplaceNullOpt) {
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/persistent_repeating_timer.h"
|
||||
#include "content/browser/dips/persistent_repeating_timer.h"
|
||||
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/functional/callback.h"
|
11
chrome/browser/dips/persistent_repeating_timer.h → content/browser/dips/persistent_repeating_timer.h
11
chrome/browser/dips/persistent_repeating_timer.h → content/browser/dips/persistent_repeating_timer.h
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_DIPS_PERSISTENT_REPEATING_TIMER_H_
|
||||
#define CHROME_BROWSER_DIPS_PERSISTENT_REPEATING_TIMER_H_
|
||||
#ifndef CONTENT_BROWSER_DIPS_PERSISTENT_REPEATING_TIMER_H_
|
||||
#define CONTENT_BROWSER_DIPS_PERSISTENT_REPEATING_TIMER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
@ -13,6 +13,7 @@
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/timer/timer.h"
|
||||
#include "content/common/content_export.h"
|
||||
|
||||
// We copied this class from
|
||||
// //components/signin/public/base/persistent_repeating_timer.h in order to
|
||||
@ -24,9 +25,9 @@ namespace dips {
|
||||
// This class fires a task repeatedly, across application restarts. The timer
|
||||
// stores the date of the last invocation in a preference, which is persisted
|
||||
// to disk.
|
||||
class PersistentRepeatingTimer {
|
||||
class CONTENT_EXPORT PersistentRepeatingTimer {
|
||||
public:
|
||||
class Storage {
|
||||
class CONTENT_EXPORT Storage {
|
||||
public:
|
||||
using TimeCallback = base::OnceCallback<void(std::optional<base::Time>)>;
|
||||
virtual ~Storage();
|
||||
@ -60,4 +61,4 @@ class PersistentRepeatingTimer {
|
||||
|
||||
} // namespace dips
|
||||
|
||||
#endif // CHROME_BROWSER_DIPS_PERSISTENT_REPEATING_TIMER_H_
|
||||
#endif // CONTENT_BROWSER_DIPS_PERSISTENT_REPEATING_TIMER_H_
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/dips/persistent_repeating_timer.h"
|
||||
#include "content/browser/dips/persistent_repeating_timer.h"
|
||||
|
||||
#include <memory>
|
||||
|
@ -4,6 +4,12 @@
|
||||
|
||||
source_set("unit_tests") {
|
||||
testonly = true
|
||||
|
||||
# See content_unittests for justification.
|
||||
if (is_component_build) {
|
||||
check_includes = false
|
||||
}
|
||||
|
||||
sources = [
|
||||
"opener_heuristic_metrics_unittest.cc",
|
||||
"opener_heuristic_utils_unittest.cc",
|
||||
@ -11,7 +17,8 @@ source_set("unit_tests") {
|
||||
|
||||
deps = [
|
||||
"//base",
|
||||
"//chrome/browser",
|
||||
"//content/browser:for_content_tests",
|
||||
"//testing/gtest",
|
||||
"//url",
|
||||
]
|
||||
}
|
5
content/browser/tpcd_heuristics/OWNERS
Normal file
5
content/browser/tpcd_heuristics/OWNERS
Normal file
@ -0,0 +1,5 @@
|
||||
amaliev@chromium.org
|
||||
jdh@chromium.org
|
||||
njeunje@chromium.org
|
||||
rtarpine@chromium.org
|
||||
wanderview@chromium.org
|
5
content/browser/tpcd_heuristics/README.md
Normal file
5
content/browser/tpcd_heuristics/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Third-Party Cookie Blocking Breakage Mitigation Heuristics
|
||||
|
||||
This directory contains code specific to efforts intended to mitigate
|
||||
site breakage caused by the blocking of third-party cookies, while
|
||||
prioritizing user privacy.
|
@ -7,66 +7,67 @@
|
||||
#include "base/functional/callback_forward.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/metrics/field_trial_params.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/test/bind.h"
|
||||
#include "base/test/gmock_expected_support.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/test/simple_test_clock.h"
|
||||
#include "base/test/test_future.h"
|
||||
#include "base/test/values_test_util.h"
|
||||
#include "base/time/time.h"
|
||||
#include "build/build_config.h"
|
||||
#include "chrome/browser/content_settings/cookie_settings_factory.h"
|
||||
#include "chrome/browser/dips/dips_service_impl.h"
|
||||
#include "chrome/browser/dips/dips_storage.h"
|
||||
#include "chrome/browser/dips/dips_test_utils.h"
|
||||
#include "chrome/browser/dips/dips_utils.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/subresource_filter/subresource_filter_browser_test_harness.h"
|
||||
#include "chrome/browser/tpcd/experiment/tpcd_experiment_features.h"
|
||||
#include "chrome/browser/tpcd/heuristics/opener_heuristic_metrics.h"
|
||||
#include "chrome/browser/tpcd/heuristics/opener_heuristic_tab_helper.h"
|
||||
#include "chrome/browser/tpcd/heuristics/opener_heuristic_utils.h"
|
||||
#include "chrome/test/base/chrome_test_utils.h"
|
||||
#include "components/content_settings/core/browser/cookie_settings.h"
|
||||
#include "components/content_settings/core/common/content_settings.h"
|
||||
#include "components/content_settings/core/common/features.h"
|
||||
#include "components/content_settings/core/common/pref_names.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "components/subresource_filter/content/browser/ad_tagging_browser_test_utils.h"
|
||||
#include "components/subresource_filter/core/common/test_ruleset_utils.h"
|
||||
#include "components/ukm/content/source_url_recorder.h"
|
||||
#include "components/ukm/test_ukm_recorder.h"
|
||||
#include "content/browser/dips/dips_browsertest_utils.h"
|
||||
#include "content/browser/dips/dips_service_impl.h"
|
||||
#include "content/browser/dips/dips_storage.h"
|
||||
#include "content/browser/dips/dips_test_utils.h"
|
||||
#include "content/browser/dips/dips_utils.h"
|
||||
#include "content/browser/tpcd_heuristics/opener_heuristic_metrics.h"
|
||||
#include "content/browser/tpcd_heuristics/opener_heuristic_tab_helper.h"
|
||||
#include "content/browser/tpcd_heuristics/opener_heuristic_utils.h"
|
||||
#include "content/common/features.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/content_browser_client.h"
|
||||
#include "content/public/browser/dips_delegate.h"
|
||||
#include "content/public/browser/navigation_handle.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "content/public/common/content_client.h"
|
||||
#include "content/public/test/browser_test.h"
|
||||
#include "content/public/test/browser_test_utils.h"
|
||||
#include "content/public/test/content_browser_test.h"
|
||||
#include "content/public/test/content_browser_test_content_browser_client.h"
|
||||
#include "content/public/test/hit_test_region_observer.h"
|
||||
#include "content/public/test/render_frame_host_test_support.h"
|
||||
#include "content/public/test/test_devtools_protocol_client.h"
|
||||
#include "content/public/test/test_navigation_observer.h"
|
||||
#include "content/shell/browser/shell.h"
|
||||
#include "net/cookies/site_for_cookies.h"
|
||||
#include "net/dns/mock_host_resolver.h"
|
||||
#include "services/metrics/public/cpp/ukm_source.h"
|
||||
#include "services/metrics/public/cpp/ukm_source_id.h"
|
||||
#include "services/network/public/cpp/features.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/blink/public/common/storage_key/storage_key.h"
|
||||
#include "third_party/blink/public/common/switches.h"
|
||||
#include "ui/base/window_open_disposition.h"
|
||||
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
#endif // !BUILDFLAG(IS_ANDROID)
|
||||
|
||||
using base::test::HasValue;
|
||||
using base::test::ValueIs;
|
||||
using content::NavigationHandle;
|
||||
using content::RenderFrameHost;
|
||||
using content::WebContents;
|
||||
using content::WebContentsObserver;
|
||||
using content_settings::features::EnableForIframeTypes;
|
||||
using testing::ElementsAre;
|
||||
using testing::Field;
|
||||
using testing::Optional;
|
||||
using testing::Pair;
|
||||
using tpcd::experiment::EnableForIframeTypes;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -75,7 +76,7 @@ struct AccessGrantTestCase {
|
||||
bool disable_for_ad_tagged_popups = false;
|
||||
};
|
||||
|
||||
const AccessGrantTestCase kAccessGrantTestCases[] = {
|
||||
[[maybe_unused]] const AccessGrantTestCase kAccessGrantTestCases[] = {
|
||||
{.write_grant_enabled = false, .disable_for_ad_tagged_popups = false},
|
||||
{.write_grant_enabled = true, .disable_for_ad_tagged_popups = false},
|
||||
{.write_grant_enabled = true, .disable_for_ad_tagged_popups = true}};
|
||||
@ -160,32 +161,29 @@ class NavigationFinishObserver : public WebContentsObserver {
|
||||
|
||||
// SubresourceFilterBrowserTest is necessary to test ad-tagging related
|
||||
// behaviors.
|
||||
class OpenerHeuristicBrowserTest
|
||||
: public subresource_filter::SubresourceFilterBrowserTest,
|
||||
public content::TestDevToolsProtocolClient {
|
||||
class OpenerHeuristicBrowserTest : public content::ContentBrowserTest,
|
||||
public content::TestDevToolsProtocolClient {
|
||||
public:
|
||||
OpenerHeuristicBrowserTest()
|
||||
: https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
|
||||
// We host the "images" on an HTTPS server, because for it to write a
|
||||
// cookie, the cookie needs to be SameSite=None and Secure.
|
||||
https_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
|
||||
https_server_.AddDefaultHandlers(
|
||||
base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
|
||||
https_server_.AddDefaultHandlers(GetTestDataFilePath());
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
tpcd_heuristics_grants_params_["TpcdReadHeuristicsGrants"] = "true";
|
||||
|
||||
feature_list_.InitWithFeaturesAndParameters(
|
||||
{{content_settings::features::kTpcdHeuristicsGrants,
|
||||
tpcd_heuristics_grants_params_},
|
||||
{network::features::kSkipTpcdMitigationsForAds,
|
||||
{{"SkipTpcdMitigationsForAdsHeuristics", "true"}}},
|
||||
{content_settings::features::kTrackingProtection3pcd, {}}},
|
||||
{
|
||||
{content_settings::features::kTpcdHeuristicsGrants,
|
||||
tpcd_heuristics_grants_params_},
|
||||
{network::features::kSkipTpcdMitigationsForAds,
|
||||
{{"SkipTpcdMitigationsForAdsHeuristics", "true"}}},
|
||||
},
|
||||
{});
|
||||
|
||||
OpenerHeuristicTabHelper::SetClockForTesting(&clock_);
|
||||
PlatformBrowserTest::SetUp();
|
||||
content::ContentBrowserTest::SetUp();
|
||||
}
|
||||
|
||||
void SetUpCommandLine(base::CommandLine* command_line) override {
|
||||
@ -194,21 +192,31 @@ class OpenerHeuristicBrowserTest
|
||||
}
|
||||
|
||||
void SetUpOnMainThread() override {
|
||||
SubresourceFilterBrowserTest::SetUpOnMainThread();
|
||||
content::ContentBrowserTest::SetUpOnMainThread();
|
||||
|
||||
ASSERT_TRUE(https_server_.Start());
|
||||
ASSERT_TRUE(embedded_test_server()->Start());
|
||||
host_resolver()->AddRule("*", "127.0.0.1");
|
||||
|
||||
// These rules apply an ad-tagging param to scripts in ad_script.js,
|
||||
// and to cookies marked with the `isad=1` param value.
|
||||
SetRulesetWithRules(
|
||||
{subresource_filter::testing::CreateSuffixRule("ad_script.js"),
|
||||
subresource_filter::testing::CreateSuffixRule("isad=1")});
|
||||
// TODO: crbug.com/376625002 - disabled for the move to //content since
|
||||
// SubresourceFilterBrowserTest is unavailable. Either find a way to
|
||||
// implement this test in //content or move it back to //chrome.
|
||||
//
|
||||
// // These rules apply an ad-tagging param to scripts in ad_script.js,
|
||||
// // and to cookies marked with the `isad=1` param value.
|
||||
// SetRulesetWithRules(
|
||||
// {subresource_filter::testing::CreateSuffixRule("ad_script.js"),
|
||||
// subresource_filter::testing::CreateSuffixRule("isad=1")});
|
||||
|
||||
DIPSServiceImpl::Get(GetActiveWebContents()->GetBrowserContext())
|
||||
->SetStorageClockForTesting(&clock_);
|
||||
|
||||
ukm::InitializeSourceUrlRecorderForWebContents(GetActiveWebContents());
|
||||
|
||||
ASSERT_TRUE(
|
||||
content::NavigateToURL(GetActiveWebContents(), GURL("about:blank")));
|
||||
// Open and reset DevTools.
|
||||
AttachToWebContents(chrome_test_utils::GetActiveWebContents(this));
|
||||
AttachToWebContents(GetActiveWebContents());
|
||||
SendCommandSync("Audits.enable");
|
||||
ClearNotifications();
|
||||
}
|
||||
@ -220,7 +228,7 @@ class OpenerHeuristicBrowserTest
|
||||
}
|
||||
|
||||
content::WebContents* GetActiveWebContents() {
|
||||
return chrome_test_utils::GetActiveWebContents(this);
|
||||
return shell()->web_contents();
|
||||
}
|
||||
|
||||
OpenerHeuristicTabHelper* GetTabHelper() {
|
||||
@ -250,6 +258,12 @@ class OpenerHeuristicBrowserTest
|
||||
// Open a popup window with the given URL and return its WebContents.
|
||||
base::expected<WebContents*, std::string> OpenPopup(const GURL& url) {
|
||||
auto* web_contents = GetActiveWebContents();
|
||||
if (web_contents->GetLastCommittedURL().is_empty()) {
|
||||
// We can't call window.open() if we're not on a page. Go to about:blank.
|
||||
if (!content::NavigateToURL(web_contents, GURL("about:blank"))) {
|
||||
return base::unexpected("failed to navigate to about:blank");
|
||||
}
|
||||
}
|
||||
PopupObserver observer(web_contents);
|
||||
if (!content::ExecJs(
|
||||
web_contents,
|
||||
@ -293,7 +307,7 @@ class OpenerHeuristicBrowserTest
|
||||
const GURL& url) {
|
||||
content::TestNavigationObserver load_observer(GetActiveWebContents());
|
||||
std::string script = base::StringPrintf(
|
||||
"var iframe = document.getElementById('test');iframe.src='%s';",
|
||||
"var iframe = document.getElementById('test_iframe');iframe.src='%s';",
|
||||
url.spec().c_str());
|
||||
if (!content::ExecJs(parent_frame, script,
|
||||
content::EXECUTE_SCRIPT_NO_USER_GESTURE)) {
|
||||
@ -479,7 +493,7 @@ class OpenerHeuristicIframeInitiatorBrowserTest
|
||||
: iframe_types_flag_(std::get<0>(GetParam())),
|
||||
is_nested_iframe_(std::get<1>(GetParam())) {
|
||||
for (const auto [val, str] :
|
||||
tpcd::experiment::kEnableForIframeTypesOptions) {
|
||||
content_settings::features::kEnableForIframeTypesOptions) {
|
||||
if (val == iframe_types_flag_) {
|
||||
tpcd_heuristics_grants_params_
|
||||
["TpcdPopupHeuristicEnableForIframeInitiator"] = str;
|
||||
@ -496,7 +510,7 @@ IN_PROC_BROWSER_TEST_P(
|
||||
URLsInitiatedByFirstPartyIframes_HavePopupStateWithFlag) {
|
||||
WebContents* web_contents = GetActiveWebContents();
|
||||
const GURL opener_primary_frame_url =
|
||||
embedded_test_server()->GetURL("a.test", "/iframe_blank.html");
|
||||
embedded_test_server()->GetURL("a.test", "/page_with_blank_iframe.html");
|
||||
const GURL opener_iframe_url =
|
||||
embedded_test_server()->GetURL("a.test", "/title1.html");
|
||||
GURL popup_url = embedded_test_server()->GetURL("b.test", "/title1.html");
|
||||
@ -532,9 +546,9 @@ IN_PROC_BROWSER_TEST_P(
|
||||
URLsInitiatedByThirdPartyIframes_HavePopupStateWithFlag) {
|
||||
WebContents* web_contents = GetActiveWebContents();
|
||||
const GURL opener_1p_frame_url =
|
||||
embedded_test_server()->GetURL("a.test", "/iframe_blank.html");
|
||||
embedded_test_server()->GetURL("a.test", "/page_with_blank_iframe.html");
|
||||
const GURL opener_3p_frame_url =
|
||||
embedded_test_server()->GetURL("b.test", "/iframe_blank.html");
|
||||
embedded_test_server()->GetURL("b.test", "/page_with_blank_iframe.html");
|
||||
GURL popup_url = embedded_test_server()->GetURL("b.test", "/title1.html");
|
||||
|
||||
ASSERT_TRUE(content::NavigateToURL(web_contents, opener_1p_frame_url));
|
||||
@ -654,13 +668,19 @@ class OpenerHeuristicMultiplePastInteractionTypesBrowserTest
|
||||
void SetUpOnMainThread() override {
|
||||
OpenerHeuristicBrowserTest::SetUpOnMainThread();
|
||||
|
||||
browser()->profile()->GetPrefs()->SetInteger(
|
||||
prefs::kCookieControlsMode,
|
||||
static_cast<int>(
|
||||
content_settings::CookieControlsMode::kBlockThirdParty));
|
||||
browser()->profile()->GetPrefs()->SetBoolean(
|
||||
prefs::kTrackingProtection3pcdEnabled, true);
|
||||
browser_client_.emplace();
|
||||
browser_client()->SetBlockThirdPartyCookiesByDefault(true);
|
||||
}
|
||||
|
||||
TpcBlockingBrowserClient* browser_client() {
|
||||
return &browser_client_->impl();
|
||||
}
|
||||
|
||||
private:
|
||||
// browser_client_ is wrapped in optional<> to delay construction -- it won't
|
||||
// be registered properly if it's created too early.
|
||||
std::optional<content::ContentBrowserTestTpcBlockingBrowserClient>
|
||||
browser_client_;
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_P(OpenerHeuristicMultiplePastInteractionTypesBrowserTest,
|
||||
@ -712,15 +732,32 @@ class OpenerHeuristicPastInteractionGrantBrowserTest
|
||||
void SetUpOnMainThread() override {
|
||||
OpenerHeuristicBrowserTest::SetUpOnMainThread();
|
||||
|
||||
browser()->profile()->GetPrefs()->SetInteger(
|
||||
prefs::kCookieControlsMode,
|
||||
static_cast<int>(
|
||||
content_settings::CookieControlsMode::kBlockThirdParty));
|
||||
browser()->profile()->GetPrefs()->SetBoolean(
|
||||
prefs::kTrackingProtection3pcdEnabled, true);
|
||||
browser_client_.emplace();
|
||||
browser_client()->SetBlockThirdPartyCookiesByDefault(true);
|
||||
}
|
||||
|
||||
TpcBlockingBrowserClient* browser_client() {
|
||||
return &browser_client_->impl();
|
||||
}
|
||||
|
||||
private:
|
||||
std::optional<content::ContentBrowserTestTpcBlockingBrowserClient>
|
||||
browser_client_;
|
||||
};
|
||||
|
||||
namespace {
|
||||
bool IsFullCookieAccessAllowed(WebContents* web_contents,
|
||||
const GURL& url,
|
||||
const GURL& first_party_url) {
|
||||
return content::GetContentClientForTesting()
|
||||
->browser()
|
||||
->IsFullCookieAccessAllowed(web_contents->GetBrowserContext(),
|
||||
web_contents, url,
|
||||
blink::StorageKey::CreateFirstParty(
|
||||
url::Origin::Create(first_party_url)));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
IN_PROC_BROWSER_TEST_P(OpenerHeuristicPastInteractionGrantBrowserTest,
|
||||
PopupPastInteractionIsReported_WithStorageAccessGrant) {
|
||||
GURL opener_url = embedded_test_server()->GetURL("a.test", "/title1.html");
|
||||
@ -734,29 +771,18 @@ IN_PROC_BROWSER_TEST_P(OpenerHeuristicPastInteractionGrantBrowserTest,
|
||||
|
||||
// Expect that cookie access was granted for the Popup With Past Interaction
|
||||
// heuristic, if the feature is enabled.
|
||||
auto cookie_settings = CookieSettingsFactory::GetForProfile(
|
||||
Profile::FromBrowserContext(GetActiveWebContents()->GetBrowserContext()));
|
||||
EXPECT_EQ(cookie_settings->GetCookieSetting(
|
||||
initial_url, net::SiteForCookies(), opener_url,
|
||||
net::CookieSettingOverrides(), nullptr),
|
||||
GetParam().write_grant_enabled ? CONTENT_SETTING_ALLOW
|
||||
: CONTENT_SETTING_BLOCK);
|
||||
EXPECT_EQ(cookie_settings->GetThirdPartyCookieAllowMechanism(
|
||||
initial_url, net::SiteForCookies::FromUrl(opener_url),
|
||||
opener_url, net::CookieSettingOverrides(), nullptr),
|
||||
GetParam().write_grant_enabled
|
||||
? content_settings::CookieSettingsBase::
|
||||
ThirdPartyCookieAllowMechanism::kAllowBy3PCDHeuristics
|
||||
: content_settings::CookieSettingsBase::
|
||||
ThirdPartyCookieAllowMechanism::kNone);
|
||||
|
||||
EXPECT_EQ(IsFullCookieAccessAllowed(GetActiveWebContents(), initial_url,
|
||||
opener_url),
|
||||
GetParam().write_grant_enabled);
|
||||
// Cookie access was NOT granted for the site that the popup redirected to.
|
||||
EXPECT_EQ(cookie_settings->GetCookieSetting(
|
||||
final_url, net::SiteForCookies(), opener_url,
|
||||
net::CookieSettingOverrides(), nullptr),
|
||||
CONTENT_SETTING_BLOCK);
|
||||
EXPECT_FALSE(
|
||||
IsFullCookieAccessAllowed(GetActiveWebContents(), final_url, opener_url));
|
||||
}
|
||||
|
||||
// TODO: crbug.com/376625002 - disabled for the move to //content since
|
||||
// SubresourceFilterBrowserTest is unavailable. Either find a way to implement
|
||||
// this test in //content or move it back to //chrome.
|
||||
//
|
||||
// TODO(crbug.com/40947612) Flaky on mac.
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
#define MAYBE_AdTaggedPopupPastInteractionIsReported_WithStorageAccessGrant \
|
||||
@ -767,7 +793,7 @@ IN_PROC_BROWSER_TEST_P(OpenerHeuristicPastInteractionGrantBrowserTest,
|
||||
#endif
|
||||
IN_PROC_BROWSER_TEST_P(
|
||||
OpenerHeuristicPastInteractionGrantBrowserTest,
|
||||
MAYBE_AdTaggedPopupPastInteractionIsReported_WithStorageAccessGrant) {
|
||||
DISABLED_AdTaggedPopupPastInteractionIsReported_WithStorageAccessGrant) {
|
||||
GURL opener_url =
|
||||
embedded_test_server()->GetURL("a.com", "/ad_tagging/frame_factory.html");
|
||||
GURL popup_url = embedded_test_server()->GetURL("c.com", "/title1.html");
|
||||
@ -779,13 +805,9 @@ IN_PROC_BROWSER_TEST_P(
|
||||
// Interaction heuristic, only if the flag is *off*.
|
||||
bool should_cookies_be_blocked = !GetParam().write_grant_enabled ||
|
||||
GetParam().disable_for_ad_tagged_popups;
|
||||
auto cookie_settings = CookieSettingsFactory::GetForProfile(
|
||||
Profile::FromBrowserContext(GetActiveWebContents()->GetBrowserContext()));
|
||||
EXPECT_EQ(cookie_settings->GetCookieSetting(
|
||||
popup_url, net::SiteForCookies(), opener_url,
|
||||
net::CookieSettingOverrides(), nullptr),
|
||||
should_cookies_be_blocked ? CONTENT_SETTING_BLOCK
|
||||
: CONTENT_SETTING_ALLOW);
|
||||
EXPECT_EQ(
|
||||
IsFullCookieAccessAllowed(GetActiveWebContents(), popup_url, opener_url),
|
||||
!should_cookies_be_blocked);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(All,
|
||||
@ -913,15 +935,20 @@ class OpenerHeuristicInteractionTypesBrowserTest
|
||||
void SetUpOnMainThread() override {
|
||||
OpenerHeuristicBrowserTest::SetUpOnMainThread();
|
||||
|
||||
browser()->profile()->GetPrefs()->SetInteger(
|
||||
prefs::kCookieControlsMode,
|
||||
static_cast<int>(
|
||||
content_settings::CookieControlsMode::kBlockThirdParty));
|
||||
browser()->profile()->GetPrefs()->SetBoolean(
|
||||
prefs::kTrackingProtection3pcdEnabled, true);
|
||||
browser_client_.emplace();
|
||||
browser_client()->SetBlockThirdPartyCookiesByDefault(true);
|
||||
}
|
||||
|
||||
TpcBlockingBrowserClient* browser_client() {
|
||||
return &browser_client_->impl();
|
||||
}
|
||||
|
||||
base::Time Hours;
|
||||
base::Time UserAuthenticationTime;
|
||||
|
||||
private:
|
||||
std::optional<content::ContentBrowserTestTpcBlockingBrowserClient>
|
||||
browser_client_;
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(All,
|
||||
@ -933,8 +960,7 @@ IN_PROC_BROWSER_TEST_P(OpenerHeuristicInteractionTypesBrowserTest,
|
||||
ukm::TestAutoSetUkmRecorder ukm_recorder;
|
||||
GURL opener_url = embedded_test_server()->GetURL("a.test", "/title1.html");
|
||||
GURL popup_url = embedded_test_server()->GetURL("b.test", "/title1.html");
|
||||
CookieSettingsFactory::GetForProfile(browser()->profile())
|
||||
->SetThirdPartyCookieSetting(opener_url, CONTENT_SETTING_ALLOW);
|
||||
browser_client()->AllowThirdPartyCookiesOnSite(opener_url);
|
||||
|
||||
// Initialize interaction and popup.
|
||||
RecordPastInteraction(popup_url, clock_.Now() - base::Hours(3));
|
||||
@ -989,8 +1015,11 @@ IN_PROC_BROWSER_TEST_P(OpenerHeuristicInteractionTypesBrowserTest,
|
||||
opener_url);
|
||||
EXPECT_EQ(access_entries[0].metrics["AccessId"], access_id);
|
||||
EXPECT_EQ(access_entries[0].metrics["AccessSucceeded"], true);
|
||||
EXPECT_EQ(access_entries[0].metrics["IsAdTagged"],
|
||||
static_cast<int32_t>(OptionalBool::kTrue));
|
||||
// TODO: crbug.com/376625002 - disabled for the move to //content since
|
||||
// SubresourceFilterBrowserTest is unavailable. Either find a way to implement
|
||||
// this test in //content or move it back to //chrome.
|
||||
// EXPECT_EQ(access_entries[0].metrics["IsAdTagged"],
|
||||
// static_cast<int32_t>(OptionalBool::kTrue));
|
||||
EXPECT_EQ(access_entries[0].metrics["HoursSincePopupOpened"], 0);
|
||||
}
|
||||
|
||||
@ -1054,13 +1083,17 @@ class OpenerHeuristicCurrentInteractionGrantBrowserTest
|
||||
void SetUpOnMainThread() override {
|
||||
OpenerHeuristicBrowserTest::SetUpOnMainThread();
|
||||
|
||||
browser()->profile()->GetPrefs()->SetInteger(
|
||||
prefs::kCookieControlsMode,
|
||||
static_cast<int>(
|
||||
content_settings::CookieControlsMode::kBlockThirdParty));
|
||||
browser()->profile()->GetPrefs()->SetBoolean(
|
||||
prefs::kTrackingProtection3pcdEnabled, true);
|
||||
browser_client_.emplace();
|
||||
browser_client()->SetBlockThirdPartyCookiesByDefault(true);
|
||||
}
|
||||
|
||||
TpcBlockingBrowserClient* browser_client() {
|
||||
return &browser_client_->impl();
|
||||
}
|
||||
|
||||
private:
|
||||
std::optional<content::ContentBrowserTestTpcBlockingBrowserClient>
|
||||
browser_client_;
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_P(OpenerHeuristicCurrentInteractionGrantBrowserTest,
|
||||
@ -1075,25 +1108,23 @@ IN_PROC_BROWSER_TEST_P(OpenerHeuristicCurrentInteractionGrantBrowserTest,
|
||||
clock_.Advance(base::Minutes(1));
|
||||
SimulateMouseClick(popup);
|
||||
|
||||
auto cookie_settings = CookieSettingsFactory::GetForProfile(
|
||||
Profile::FromBrowserContext(GetActiveWebContents()->GetBrowserContext()));
|
||||
// Cookie access was NOT granted for the initial URL (that the user didn't
|
||||
// interact with).
|
||||
EXPECT_EQ(cookie_settings->GetCookieSetting(
|
||||
initial_url, net::SiteForCookies(), opener_url,
|
||||
net::CookieSettingOverrides(), nullptr),
|
||||
CONTENT_SETTING_BLOCK);
|
||||
EXPECT_FALSE(IsFullCookieAccessAllowed(GetActiveWebContents(), initial_url,
|
||||
opener_url));
|
||||
// Cookie access WAS granted for the interacted-with URL (if the feature was
|
||||
// enabled).
|
||||
EXPECT_EQ(cookie_settings->GetCookieSetting(
|
||||
final_url, net::SiteForCookies(), opener_url,
|
||||
net::CookieSettingOverrides(), nullptr),
|
||||
GetParam().write_grant_enabled ? CONTENT_SETTING_ALLOW
|
||||
: CONTENT_SETTING_BLOCK);
|
||||
EXPECT_EQ(
|
||||
IsFullCookieAccessAllowed(GetActiveWebContents(), final_url, opener_url),
|
||||
GetParam().write_grant_enabled);
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_P(OpenerHeuristicCurrentInteractionGrantBrowserTest,
|
||||
AdTaggedPopupInteractionWithStorageAccessGrant) {
|
||||
// TODO: crbug.com/376625002 - disabled for the move to //content since
|
||||
// SubresourceFilterBrowserTest is unavailable. Either find a way to implement
|
||||
// this test in //content or move it back to //chrome.
|
||||
IN_PROC_BROWSER_TEST_P(
|
||||
OpenerHeuristicCurrentInteractionGrantBrowserTest,
|
||||
DISABLED_AdTaggedPopupInteractionWithStorageAccessGrant) {
|
||||
GURL opener_url =
|
||||
embedded_test_server()->GetURL("a.com", "/ad_tagging/frame_factory.html");
|
||||
GURL popup_url = embedded_test_server()->GetURL("c.com", "/title1.html");
|
||||
@ -1107,13 +1138,9 @@ IN_PROC_BROWSER_TEST_P(OpenerHeuristicCurrentInteractionGrantBrowserTest,
|
||||
// Interaction heuristic, only if the flag is *off*.
|
||||
bool should_cookies_be_blocked = !GetParam().write_grant_enabled ||
|
||||
GetParam().disable_for_ad_tagged_popups;
|
||||
auto cookie_settings = CookieSettingsFactory::GetForProfile(
|
||||
Profile::FromBrowserContext(GetActiveWebContents()->GetBrowserContext()));
|
||||
EXPECT_EQ(cookie_settings->GetCookieSetting(
|
||||
popup_url, net::SiteForCookies(), opener_url,
|
||||
net::CookieSettingOverrides(), nullptr),
|
||||
should_cookies_be_blocked ? CONTENT_SETTING_BLOCK
|
||||
: CONTENT_SETTING_ALLOW);
|
||||
EXPECT_EQ(
|
||||
IsFullCookieAccessAllowed(GetActiveWebContents(), popup_url, opener_url),
|
||||
!should_cookies_be_blocked);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(All,
|
||||
@ -1203,8 +1230,7 @@ IN_PROC_BROWSER_TEST_P(
|
||||
GURL popup_url_2 =
|
||||
embedded_test_server()->GetURL("b.test", "/server-redirect?title1.html");
|
||||
GURL popup_url_3 = embedded_test_server()->GetURL("b.test", "/title1.html");
|
||||
CookieSettingsFactory::GetForProfile(browser()->profile())
|
||||
->SetThirdPartyCookieSetting(opener_url, CONTENT_SETTING_ALLOW);
|
||||
browser_client()->AllowThirdPartyCookiesOnSite(opener_url);
|
||||
|
||||
// Initialize popup and interaction.
|
||||
ASSERT_TRUE(content::NavigateToURL(GetActiveWebContents(), opener_url));
|
||||
@ -1268,6 +1294,10 @@ IN_PROC_BROWSER_TEST_P(
|
||||
}
|
||||
|
||||
// TODO(https://crbug.com/40933721): flaky on Mac.
|
||||
//
|
||||
// TODO: crbug.com/376625002 - disabled for the move to //content since the
|
||||
// DevTools integration is still only in //chrome. Either find a way to
|
||||
// implement this test in //content or move it back to //chrome.
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
#define MAYBE_PopupInteraction_CookieAccessEmitsDevtoolsWarning \
|
||||
DISABLED_PopupInteraction_CookieAccessEmitsDevtoolsWarning
|
||||
@ -1277,7 +1307,7 @@ IN_PROC_BROWSER_TEST_P(
|
||||
#endif
|
||||
IN_PROC_BROWSER_TEST_F(
|
||||
OpenerHeuristicBrowserTest,
|
||||
MAYBE_PopupInteraction_CookieAccessEmitsDevtoolsWarning) {
|
||||
DISABLED_PopupInteraction_CookieAccessEmitsDevtoolsWarning) {
|
||||
GURL opener_url = https_server_.GetURL("a.test", "/title1.html");
|
||||
GURL popup_url_1 = https_server_.GetURL("c.test", "/title1.html");
|
||||
GURL popup_url_2 =
|
||||
@ -1343,11 +1373,11 @@ IN_PROC_BROWSER_TEST_F(OpenerHeuristicBrowserTest,
|
||||
TopLevelIsReported_HasSameSiteIframe) {
|
||||
ukm::TestAutoSetUkmRecorder ukm_recorder;
|
||||
GURL toplevel_url =
|
||||
embedded_test_server()->GetURL("a.test", "/iframe_blank.html");
|
||||
embedded_test_server()->GetURL("a.test", "/page_with_blank_iframe.html");
|
||||
GURL iframe_url =
|
||||
embedded_test_server()->GetURL("sub.b.test", "/title1.html");
|
||||
GURL popup_url = embedded_test_server()->GetURL("b.test", "/title1.html");
|
||||
const std::string iframe_id = "test";
|
||||
const std::string iframe_id = "test_iframe";
|
||||
WebContents* web_contents = GetActiveWebContents();
|
||||
|
||||
RecordUserActivationInteraction(GURL("https://b.test"),
|
||||
@ -1441,6 +1471,10 @@ IN_PROC_BROWSER_TEST_F(OpenerHeuristicBrowserTest, TopLevel_PopupId) {
|
||||
EXPECT_NE(popup_id, popup_id2);
|
||||
}
|
||||
|
||||
// TODO: crbug.com/376625002 - disabled for the move to //content since
|
||||
// SubresourceFilterBrowserTest is unavailable. Either find a way to implement
|
||||
// this test in //content or move it back to //chrome.
|
||||
//
|
||||
// TODO(crbug.com/41484288): Flaky on mac.
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
#define MAYBE_TopLevel_PastInteraction_AdTagged \
|
||||
@ -1450,7 +1484,7 @@ IN_PROC_BROWSER_TEST_F(OpenerHeuristicBrowserTest, TopLevel_PopupId) {
|
||||
TopLevel_PastInteraction_AdTagged
|
||||
#endif
|
||||
IN_PROC_BROWSER_TEST_F(OpenerHeuristicBrowserTest,
|
||||
MAYBE_TopLevel_PastInteraction_AdTagged) {
|
||||
DISABLED_TopLevel_PastInteraction_AdTagged) {
|
||||
ukm::TestAutoSetUkmRecorder ukm_recorder;
|
||||
GURL toplevel_url =
|
||||
embedded_test_server()->GetURL("a.com", "/ad_tagging/frame_factory.html");
|
||||
@ -1473,8 +1507,11 @@ IN_PROC_BROWSER_TEST_F(OpenerHeuristicBrowserTest,
|
||||
EXPECT_EQ(entries[0].metrics["IsAdTaggedPopupClick"], true);
|
||||
}
|
||||
|
||||
// TODO: crbug.com/376625002 - disabled for the move to //content since
|
||||
// SubresourceFilterBrowserTest is unavailable. Either find a way to implement
|
||||
// this test in //content or move it back to //chrome.
|
||||
IN_PROC_BROWSER_TEST_F(OpenerHeuristicBrowserTest,
|
||||
TopLevel_CurrentInteraction_AdTagged) {
|
||||
DISABLED_TopLevel_CurrentInteraction_AdTagged) {
|
||||
ukm::TestAutoSetUkmRecorder ukm_recorder;
|
||||
GURL toplevel_url =
|
||||
embedded_test_server()->GetURL("a.com", "/ad_tagging/frame_factory.html");
|
||||
@ -1558,7 +1595,7 @@ class OpenerHeuristicBackfillGrantBrowserTest
|
||||
public:
|
||||
OpenerHeuristicBackfillGrantBrowserTest() {
|
||||
tpcd_heuristics_grants_params_["TpcdBackfillPopupHeuristicsGrants"] =
|
||||
GetParam() ? "10m" : "0s";
|
||||
GetParam() ? "1us" : "0s";
|
||||
tpcd_heuristics_grants_params_
|
||||
["TpcdWritePopupCurrentInteractionHeuristicsGrants"] = "0s";
|
||||
}
|
||||
@ -1568,11 +1605,17 @@ class OpenerHeuristicBackfillGrantBrowserTest
|
||||
|
||||
clock_.SetNow(base::Time::Now());
|
||||
|
||||
browser()->profile()->GetPrefs()->SetInteger(
|
||||
prefs::kCookieControlsMode,
|
||||
static_cast<int>(
|
||||
content_settings::CookieControlsMode::kBlockThirdParty));
|
||||
browser_client_.emplace();
|
||||
browser_client()->SetBlockThirdPartyCookiesByDefault(true);
|
||||
}
|
||||
|
||||
TpcBlockingBrowserClient* browser_client() {
|
||||
return &browser_client_->impl();
|
||||
}
|
||||
|
||||
private:
|
||||
std::optional<content::ContentBrowserTestTpcBlockingBrowserClient>
|
||||
browser_client_;
|
||||
};
|
||||
|
||||
// Test the backfill grants created by OpenerHeuristicService when tracking
|
||||
@ -1604,46 +1647,36 @@ IN_PROC_BROWSER_TEST_P(OpenerHeuristicBackfillGrantBrowserTest,
|
||||
clock_.Advance(base::Minutes(1));
|
||||
SimulateMouseClick(popup);
|
||||
|
||||
// The pref is updated when the user in onboarded to 3PCD tracking protection,
|
||||
// and a PrefChangeRegistrar updates the TrackingProtectionSettingsObservers.
|
||||
browser()->profile()->GetPrefs()->SetBoolean(
|
||||
prefs::kTrackingProtection3pcdEnabled, true);
|
||||
GetDipsService()->storage()->FlushPostedTasksForTesting();
|
||||
base::test::TestFuture<bool> backfill_done;
|
||||
GetActiveWebContents()->GetBrowserContext()->BackfillPopupHeuristicGrants(
|
||||
backfill_done.GetCallback());
|
||||
ASSERT_EQ(backfill_done.Get(), GetParam());
|
||||
|
||||
// Expect that a cookie access grant is not backfilled for popup_url_1 or
|
||||
// popup_url_2.
|
||||
auto cookie_settings = CookieSettingsFactory::GetForProfile(
|
||||
Profile::FromBrowserContext(GetActiveWebContents()->GetBrowserContext()));
|
||||
EXPECT_EQ(cookie_settings->GetCookieSetting(
|
||||
popup_url_1, net::SiteForCookies(), opener_url,
|
||||
net::CookieSettingOverrides(), nullptr),
|
||||
CONTENT_SETTING_BLOCK);
|
||||
EXPECT_EQ(cookie_settings->GetCookieSetting(
|
||||
popup_url_2, net::SiteForCookies(), opener_url,
|
||||
net::CookieSettingOverrides(), nullptr),
|
||||
CONTENT_SETTING_BLOCK);
|
||||
EXPECT_FALSE(IsFullCookieAccessAllowed(GetActiveWebContents(), popup_url_1,
|
||||
opener_url));
|
||||
EXPECT_FALSE(IsFullCookieAccessAllowed(GetActiveWebContents(), popup_url_2,
|
||||
opener_url));
|
||||
|
||||
// Expect that a cookie access grant is backfilled for popup_url_3 when the
|
||||
// experiment is enabled.
|
||||
EXPECT_EQ(cookie_settings->GetCookieSetting(
|
||||
popup_url_3, net::SiteForCookies(), opener_url,
|
||||
net::CookieSettingOverrides(), nullptr),
|
||||
GetParam() ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK);
|
||||
EXPECT_EQ(IsFullCookieAccessAllowed(GetActiveWebContents(), popup_url_3,
|
||||
opener_url),
|
||||
GetParam());
|
||||
|
||||
// Expect that the cookie access grant applies to other URLs with the same
|
||||
// eTLD+1.
|
||||
GURL popup_url_3a =
|
||||
embedded_test_server()->GetURL("www.d.test", "/favicon.png");
|
||||
EXPECT_EQ(cookie_settings->GetCookieSetting(
|
||||
popup_url_3a, net::SiteForCookies(), opener_url,
|
||||
net::CookieSettingOverrides(), nullptr),
|
||||
GetParam() ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK);
|
||||
EXPECT_EQ(IsFullCookieAccessAllowed(GetActiveWebContents(), popup_url_3a,
|
||||
opener_url),
|
||||
GetParam());
|
||||
GURL popup_url_3b =
|
||||
embedded_test_server()->GetURL("corp.d.test", "/title1.html");
|
||||
EXPECT_EQ(cookie_settings->GetCookieSetting(
|
||||
popup_url_3b, net::SiteForCookies(), opener_url,
|
||||
net::CookieSettingOverrides(), nullptr),
|
||||
GetParam() ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK);
|
||||
EXPECT_EQ(IsFullCookieAccessAllowed(GetActiveWebContents(), popup_url_3b,
|
||||
opener_url),
|
||||
GetParam());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(All,
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/tpcd/heuristics/opener_heuristic_metrics.h"
|
||||
#include "content/browser/tpcd_heuristics/opener_heuristic_metrics.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
17
content/browser/tpcd_heuristics/opener_heuristic_metrics.h
Normal file
17
content/browser/tpcd_heuristics/opener_heuristic_metrics.h
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CONTENT_BROWSER_TPCD_HEURISTICS_OPENER_HEURISTIC_METRICS_H_
|
||||
#define CONTENT_BROWSER_TPCD_HEURISTICS_OPENER_HEURISTIC_METRICS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "content/common/content_export.h"
|
||||
|
||||
// Bucketize `sample` into 50 buckets, capped at maximum and distributed
|
||||
// non-linearly similarly to base::Histogram::InitializeBucketRanges.
|
||||
CONTENT_EXPORT int32_t Bucketize3PCDHeuristicSample(int64_t sample,
|
||||
int64_t maximum);
|
||||
|
||||
#endif // CONTENT_BROWSER_TPCD_HEURISTICS_OPENER_HEURISTIC_METRICS_H_
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/tpcd/heuristics/opener_heuristic_metrics.h"
|
||||
#include "content/browser/tpcd_heuristics/opener_heuristic_metrics.h"
|
||||
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/functional/callback_forward.h"
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user