blob: d199b66687e079915b4111b1d6332db2fe99323f [file] [log] [blame]
// 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 "content/browser/tpcd_heuristics/opener_heuristic_utils.h"
#include "base/functional/bind.h"
#include "base/test/scoped_feature_list.h"
#include "components/content_settings/core/common/features.h"
#include "content/browser/btm/btm_bounce_detector.h"
#include "content/public/browser/btm_redirect_info.h"
#include "content/public/browser/cookie_access_details.h"
#include "net/http/http_status_code.h"
#include "services/network/public/cpp/features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace {
using content::Btm3PcSettingsCallback;
using content::BtmDataAccessType;
using content::BtmRedirectChainInfoPtr;
using content::BtmRedirectInfo;
using content::BtmRedirectInfoPtr;
using ChainPair =
std::pair<BtmRedirectChainInfoPtr, std::vector<BtmRedirectInfoPtr>>;
void AppendChainPair(std::vector<ChainPair>& vec,
std::vector<BtmRedirectInfoPtr> redirects,
BtmRedirectChainInfoPtr chain) {
vec.emplace_back(std::move(chain), std::move(redirects));
}
std::vector<BtmRedirectInfoPtr> MakeServerRedirects(
std::vector<std::string> urls,
BtmDataAccessType access_type = BtmDataAccessType::kReadWrite) {
std::vector<BtmRedirectInfoPtr> redirects;
for (const auto& url : urls) {
redirects.push_back(BtmRedirectInfo::CreateForServer(
/*redirector_url=*/GURL(url),
/*redirector_source_id=*/ukm::AssignNewSourceId(),
/*access_type=*/access_type,
/*time=*/base::Time::Now(),
/*was_response_cached=*/false,
/*response_code=*/net::HTTP_FOUND,
/*server_bounce_delay=*/base::TimeDelta()));
}
return redirects;
}
BtmRedirectInfoPtr MakeClientRedirect(
std::string url,
BtmDataAccessType access_type = BtmDataAccessType::kReadWrite,
bool has_sticky_activation = false,
bool has_web_authn_assertion = false) {
return BtmRedirectInfo::CreateForClient(
/*redirector_url=*/GURL(url),
/*redirector_source_id=*/ukm::AssignNewSourceId(),
/*access_type=*/access_type,
/*time=*/base::Time::Now(),
/*client_bounce_delay=*/base::Seconds(1),
/*has_sticky_activation=*/has_sticky_activation,
/*web_authn_assertion_request_succeeded*/ has_web_authn_assertion);
}
Btm3PcSettingsCallback GetAre3pcsAllowedCallback() {
return base::BindRepeating([] { return false; });
}
} // namespace
namespace content {
TEST(OpenerHeuristicUtilsTest, GetPopupProvider) {
// Any google.com subdomain.
EXPECT_EQ(GetPopupProvider(GURL("https://accounts.google.com/")),
PopupProvider::kGoogle);
EXPECT_EQ(GetPopupProvider(GURL("https://www.google.com/")),
PopupProvider::kGoogle);
// Also match http (just in case).
EXPECT_EQ(GetPopupProvider(GURL("http://www.google.com/")),
PopupProvider::kGoogle);
// If not a known provider, return kUnknown.
EXPECT_EQ(GetPopupProvider(GURL("https://www.example.com/")),
PopupProvider::kUnknown);
}
TEST(IsAdTaggedCookieForHeuristics, ReturnsCorrectlyInExperiment) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeatureWithParameters(
network::features::kSkipTpcdMitigationsForAds,
{{"SkipTpcdMitigationsForAdsHeuristics", "true"}});
CookieAccessDetails details;
EXPECT_EQ(IsAdTaggedCookieForHeuristics(details), OptionalBool::kFalse);
details.cookie_setting_overrides.Put(
net::CookieSettingOverride::kSkipTPCDHeuristicsGrant);
EXPECT_EQ(IsAdTaggedCookieForHeuristics(details), OptionalBool::kTrue);
}
TEST(IsAdTaggedCookieForHeuristics, ReturnsCorrectlyWithoutExperimentFeature) {
base::test::ScopedFeatureList features;
features.InitAndDisableFeature(network::features::kSkipTpcdMitigationsForAds);
CookieAccessDetails details;
EXPECT_EQ(IsAdTaggedCookieForHeuristics(details), OptionalBool::kUnknown);
details.cookie_setting_overrides.Put(
net::CookieSettingOverride::kSkipTPCDHeuristicsGrant);
EXPECT_EQ(IsAdTaggedCookieForHeuristics(details), OptionalBool::kUnknown);
}
TEST(IsAdTaggedCookieForHeuristics, ReturnsCorrectlyWithoutExperimentParam) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeatureWithParameters(
network::features::kSkipTpcdMitigationsForAds,
{{"SkipTpcdMitigationsForAdsHeuristics", "false"}});
CookieAccessDetails details;
EXPECT_EQ(IsAdTaggedCookieForHeuristics(details), OptionalBool::kUnknown);
details.cookie_setting_overrides.Put(
net::CookieSettingOverride::kSkipTPCDHeuristicsGrant);
EXPECT_EQ(IsAdTaggedCookieForHeuristics(details), OptionalBool::kUnknown);
}
TEST(BtmRedirectContextTest, GetRedirectHeuristicURLs_NoRequirements) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeatureWithParameters(
content_settings::features::kTpcdHeuristicsGrants,
{{"TpcdRedirectHeuristicRequireABAFlow", "false"}});
GURL first_party_url = GURL("http://a.test/");
ukm::SourceId first_party_source_id = ukm::AssignNewSourceId();
GURL current_interaction_url = GURL("http://b.test/");
ukm::SourceId current_interaction_source_id = ukm::AssignNewSourceId();
GURL no_current_interaction_url("http://c.test/");
std::vector<ChainPair> chains;
BtmRedirectContext context(
base::BindRepeating(AppendChainPair, std::ref(chains)), base::DoNothing(),
GetAre3pcsAllowedCallback(), GURL(), ukm::kInvalidSourceId,
/*redirect_prefix_count=*/0);
context.AppendCommitted(
std::make_pair(first_party_url, first_party_source_id),
{MakeServerRedirects({"http://c.test"})}, current_interaction_url,
current_interaction_source_id, false);
context.AppendCommitted(
MakeClientRedirect("http://b.test/", BtmDataAccessType::kNone,
/*has_sticky_activation=*/true),
{}, first_party_url, first_party_source_id, false);
ASSERT_EQ(context.size(), 2u);
std::map<std::string, std::pair<GURL, bool>>
sites_to_url_and_current_interaction =
GetRedirectHeuristicURLs(context, first_party_url, std::nullopt,
/*require_current_interaction=*/false);
EXPECT_THAT(
sites_to_url_and_current_interaction,
testing::UnorderedElementsAre(
std::pair<std::string, std::pair<GURL, bool>>(
"b.test", std::make_pair(current_interaction_url, true)),
std::pair<std::string, std::pair<GURL, bool>>(
"c.test", std::make_pair(no_current_interaction_url, false))));
}
TEST(BtmRedirectContextTest, GetRedirectHeuristicURLs_RequireABAFlow) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeatureWithParameters(
content_settings::features::kTpcdHeuristicsGrants,
{{"TpcdRedirectHeuristicRequireABAFlow", "true"}});
GURL first_party_url = GURL("http://a.test/");
ukm::SourceId first_party_source_id = ukm::AssignNewSourceId();
GURL aba_url("http://b.test/");
GURL no_aba_url("http://c.test/");
std::vector<ChainPair> chains;
BtmRedirectContext context(
base::BindRepeating(AppendChainPair, std::ref(chains)), base::DoNothing(),
GetAre3pcsAllowedCallback(), GURL(), ukm::kInvalidSourceId,
/*redirect_prefix_count=*/0);
context.AppendCommitted(
std::make_pair(first_party_url, first_party_source_id),
{MakeServerRedirects({"http://b.test", "http://c.test"})},
first_party_url, first_party_source_id, false);
ASSERT_EQ(context.size(), 2u);
std::set<std::string> allowed_sites = {GetSiteForBtm(aba_url)};
std::map<std::string, std::pair<GURL, bool>>
sites_to_url_and_current_interaction =
GetRedirectHeuristicURLs(context, first_party_url, allowed_sites,
/*require_current_interaction=*/false);
EXPECT_THAT(sites_to_url_and_current_interaction,
testing::UnorderedElementsAre(
std::pair<std::string, std::pair<GURL, bool>>(
"b.test", std::make_pair(aba_url, false))));
}
TEST(BtmRedirectContextTest,
GetRedirectHeuristicURLs_RequireCurrentInteraction) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeatureWithParameters(
content_settings::features::kTpcdHeuristicsGrants,
{{"TpcdRedirectHeuristicRequireABAFlow", "false"}});
GURL first_party_url = GURL("http://a.test/");
ukm::SourceId first_party_source_id = ukm::AssignNewSourceId();
GURL current_interaction_url = GURL("http://b.test/");
ukm::SourceId current_interaction_source_id = ukm::AssignNewSourceId();
GURL no_current_interaction_url("http://c.test/");
std::vector<ChainPair> chains;
BtmRedirectContext context(
base::BindRepeating(AppendChainPair, std::ref(chains)), base::DoNothing(),
GetAre3pcsAllowedCallback(), GURL(), ukm::kInvalidSourceId,
/*redirect_prefix_count=*/0);
context.AppendCommitted(
std::make_pair(first_party_url, first_party_source_id),
{MakeServerRedirects({"http://c.test"})}, current_interaction_url,
current_interaction_source_id, false);
context.AppendCommitted(
MakeClientRedirect("http://b.test/", BtmDataAccessType::kNone,
/*has_sticky_activation=*/false, true),
{}, first_party_url, first_party_source_id, false);
ASSERT_EQ(context.size(), 2u);
std::map<std::string, std::pair<GURL, bool>>
sites_to_url_and_current_interaction =
GetRedirectHeuristicURLs(context, first_party_url, std::nullopt,
/*require_current_interaction=*/true);
EXPECT_THAT(
sites_to_url_and_current_interaction,
testing::UnorderedElementsAre(
std::pair<std::string, std::pair<GURL, bool>>(
"b.test", std::make_pair(current_interaction_url, true))));
}
} // namespace content