Skip to content

Commit

Permalink
Add a devtools issue + protocol for sites allowlisted for third-party…
Browse files Browse the repository at this point in the history
… cookie deprecation.

Bug: b/305738703
Change-Id: If6f6a7c5331506cb805c223bfb5c6644b193ce5e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4916620
Reviewed-by: Andrey Kosyakov <caseq@chromium.org>
Commit-Queue: Anton Maliev <amaliev@chromium.org>
Reviewed-by: Christian Dullweber <dullweber@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1211547}
  • Loading branch information
amaliev authored and Chromium LUCI CQ committed Oct 18, 2023
1 parent 68918e8 commit 5beee05
Show file tree
Hide file tree
Showing 14 changed files with 417 additions and 26 deletions.
2 changes: 2 additions & 0 deletions chrome/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -1834,6 +1834,8 @@ static_library("browser") {
"tpcd/heuristics/opener_heuristic_tab_helper.h",
"tpcd/heuristics/opener_heuristic_utils.cc",
"tpcd/heuristics/opener_heuristic_utils.h",
"tpcd/metadata/devtools_observer.cc",
"tpcd/metadata/devtools_observer.h",
"tpcd/metadata/updater_service.cc",
"tpcd/metadata/updater_service.h",
"tpcd/metadata/updater_service_factory.cc",
Expand Down
67 changes: 67 additions & 0 deletions chrome/browser/tpcd/metadata/devtools_observer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// 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/metadata/devtools_observer.h"

#include "chrome/browser/content_settings/cookie_settings_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/content_settings/core/common/cookie_settings_base.h"
#include "content/public/browser/cookie_access_details.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "third_party/blink/public/mojom/devtools/inspector_issue.mojom.h"

namespace tpcd::metadata {

TpcdMetadataDevtoolsObserver::TpcdMetadataDevtoolsObserver(
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
content::WebContentsUserData<TpcdMetadataDevtoolsObserver>(
*web_contents) {
cookie_settings_ = CookieSettingsFactory::GetForProfile(
Profile::FromBrowserContext(web_contents->GetBrowserContext()));
}

TpcdMetadataDevtoolsObserver::~TpcdMetadataDevtoolsObserver() = default;

void TpcdMetadataDevtoolsObserver::OnCookiesAccessed(
content::RenderFrameHost* render_frame_host,
const content::CookieAccessDetails& details) {
OnCookiesAccessedImpl(details.url, details.first_party_url);
}

void TpcdMetadataDevtoolsObserver::OnCookiesAccessed(
content::NavigationHandle* navigation_handle,
const content::CookieAccessDetails& details) {
OnCookiesAccessedImpl(details.url, details.first_party_url);
}

void TpcdMetadataDevtoolsObserver::OnCookiesAccessedImpl(
const GURL& url,
const GURL& first_party_url) {
if (cookie_settings_->IsAllowedByTpcdMetadataGrant(url, first_party_url)) {
EmitMetadataGrantDevtoolsIssue(url);
}
}

void TpcdMetadataDevtoolsObserver::EmitMetadataGrantDevtoolsIssue(
const GURL& url) {
auto details = blink::mojom::InspectorIssueDetails::New();

auto metadata_issue_details =
blink::mojom::CookieDeprecationMetadataIssueDetails::New();
metadata_issue_details->allowed_sites.push_back(url.host());
details->cookie_deprecation_metadata_issue_details =
std::move(metadata_issue_details);

web_contents()->GetPrimaryMainFrame()->ReportInspectorIssue(
blink::mojom::InspectorIssueInfo::New(
blink::mojom::InspectorIssueCode::kCookieDeprecationMetadataIssue,
std::move(details)));
}

WEB_CONTENTS_USER_DATA_KEY_IMPL(TpcdMetadataDevtoolsObserver);

} // namespace tpcd::metadata
46 changes: 46 additions & 0 deletions chrome/browser/tpcd/metadata/devtools_observer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// 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_METADATA_DEVTOOLS_OBSERVER_H_
#define CHROME_BROWSER_TPCD_METADATA_DEVTOOLS_OBSERVER_H_

#include "chrome/browser/dips/dips_service.h"
#include "chrome/browser/tpcd/heuristics/opener_heuristic_tab_helper.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"

namespace tpcd::metadata {

class TpcdMetadataDevtoolsObserver
: public content::WebContentsObserver,
public content::WebContentsUserData<TpcdMetadataDevtoolsObserver> {
public:
explicit TpcdMetadataDevtoolsObserver(content::WebContents* web_contents);
TpcdMetadataDevtoolsObserver() = delete;
~TpcdMetadataDevtoolsObserver() override;

private:
// To allow use of WebContentsUserData::CreateForWebContents()
friend class content::WebContentsUserData<TpcdMetadataDevtoolsObserver>;

// 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;

void OnCookiesAccessedImpl(const GURL& url, const GURL& first_party_url);

// Emit a devtools issue when `url` is allowed cookie access as a third-party
// site on the current page.
void EmitMetadataGrantDevtoolsIssue(const GURL& url);

scoped_refptr<content_settings::CookieSettings> cookie_settings_;

WEB_CONTENTS_USER_DATA_KEY_DECL();
};

} // namespace tpcd::metadata

#endif // CHROME_BROWSER_TPCD_METADATA_DEVTOOLS_OBSERVER_H_
186 changes: 186 additions & 0 deletions chrome/browser/tpcd/metadata/devtools_observer_browsertest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// 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 "base/files/file_path.h"
#include "chrome/browser/content_settings/cookie_settings_factory.h"
#include "chrome/browser/dips/dips_service.h"
#include "chrome/browser/dips/dips_test_utils.h"
#include "chrome/browser/tpcd/metadata/devtools_observer.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/chrome_test_utils.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/content_settings/core/common/features.h"
#include "components/tpcd/metadata/parser.h"
#include "components/tpcd/metadata/parser_test_helper.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_devtools_protocol_client.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "third_party/blink/public/mojom/devtools/inspector_issue.mojom.h"

namespace tpcd::metadata {
namespace {

using ::chrome_test_utils::GetActiveWebContents;

} // namespace

class TpcdMetadataDevtoolsObserverBrowserTest
: public PlatformBrowserTest,
public content::TestDevToolsProtocolClient {
public:
explicit TpcdMetadataDevtoolsObserverBrowserTest(
bool enable_metadata_feature = true)
: https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
feature_list_.InitWithFeatureStates(
{{content_settings::features::kTrackingProtection3pcd, true},
{net::features::kTpcdMetadataGrants, enable_metadata_feature}});
}

void SetUpOnMainThread() override {
ASSERT_TRUE(embedded_test_server()->Start());
host_resolver()->AddRule("a.test", "127.0.0.1");
host_resolver()->AddRule("b.test", "127.0.0.1");
host_resolver()->AddRule("c.test", "127.0.0.1");

// Set up HTTPS server with image for cookie.
https_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
https_server_.AddDefaultHandlers(
base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
ASSERT_TRUE(https_server_.Start());

// Open and reset DevTools.
AttachToWebContents(GetActiveWebContents(this));
SendCommandSync("Audits.enable");
ClearNotifications();

// Initialize mock 3PCD metadata component.
std::vector<MetadataPair> metadata_pairs;
const std::string first_party_pattern_spec = "[*.]a.test";
const std::string third_party_pattern_spec_1 = "[*.]b.test";
const std::string third_party_pattern_spec_2 = "c.test";
metadata_pairs.emplace_back(third_party_pattern_spec_1,
first_party_pattern_spec);
metadata_pairs.emplace_back(third_party_pattern_spec_2,
first_party_pattern_spec);
Metadata metadata = MakeMetadataProtoFromVectorOfPair(metadata_pairs);
tpcd::metadata::Parser::GetInstance()->ParseMetadata(
metadata.SerializeAsString());

// Initialize devtools WebContentsObserver.
devtools_observer_ = TpcdMetadataDevtoolsObserver::FromWebContents(
GetActiveWebContents(this));
}

void TearDownOnMainThread() override {
DetachProtocolClient();
devtools_observer_ = nullptr;
}

protected:
void AddCookieAccess(const std::string& first_party_site,
const std::string& third_party_site) {
ASSERT_TRUE(NavigateToSetCookie(GetActiveWebContents(this), &https_server_,
third_party_site,
/*is_secure_cookie_set=*/true));
ASSERT_TRUE(content::NavigateToURL(
GetActiveWebContents(this),
embedded_test_server()->GetURL(first_party_site, "/title1.html")));
CreateImageAndWaitForCookieAccess(
GetActiveWebContents(this),
https_server_.GetURL(third_party_site, "/favicon/icon.png"));
}

void WaitForIssueAndCheckAllowedSites(const std::vector<std::string>& sites) {
auto is_metadata_issue = [](const base::Value::Dict& params) {
return *(params.FindStringByDottedPath("issue.code")) ==
"CookieDeprecationMetadataIssue";
};

// Wait for notification of a Metadata Issue.
base::Value::Dict params = WaitForMatchingNotification(
"Audits.issueAdded", base::BindRepeating(is_metadata_issue));
ASSERT_EQ(*params.FindStringByDottedPath("issue.code"),
"CookieDeprecationMetadataIssue");

base::Value::Dict* metadata_issue_details = params.FindDictByDottedPath(
"issue.details.cookieDeprecationMetadataIssueDetails");
ASSERT_TRUE(metadata_issue_details);

std::vector<std::string> allowed_sites;
base::Value::List* allowed_sites_list =
metadata_issue_details->FindList("allowedSites");
if (allowed_sites_list) {
for (const auto& val : *allowed_sites_list) {
allowed_sites.push_back(val.GetString());
}
}

// Verify the reported allowed sites match the expected sites.
EXPECT_THAT(allowed_sites, testing::ElementsAreArray(sites));

// Clear existing notifications so subsequent calls don't fail by checking
// `sites` against old notifications.
ClearNotifications();
}

void CheckNoAddedIssue() {
ReportDummyIssue();

WaitForIssueAndCheckAllowedSites({"dummy.test"});
}

private:
void ReportDummyIssue() {
auto details = blink::mojom::InspectorIssueDetails::New();

auto metadata_issue_details =
blink::mojom::CookieDeprecationMetadataIssueDetails::New();
metadata_issue_details->allowed_sites.push_back("dummy.test");
details->cookie_deprecation_metadata_issue_details =
std::move(metadata_issue_details);

GetActiveWebContents(this)->GetPrimaryMainFrame()->ReportInspectorIssue(
blink::mojom::InspectorIssueInfo::New(
blink::mojom::InspectorIssueCode::kCookieDeprecationMetadataIssue,
std::move(details)));
}

base::test::ScopedFeatureList feature_list_;
net::EmbeddedTestServer https_server_;
raw_ptr<TpcdMetadataDevtoolsObserver> devtools_observer_ = nullptr;
};

IN_PROC_BROWSER_TEST_F(TpcdMetadataDevtoolsObserverBrowserTest,
EmitsDevtoolsIssues) {
AddCookieAccess("a.test", "b.test");
WaitForIssueAndCheckAllowedSites({"b.test"});

AddCookieAccess("a.test", "c.test");
WaitForIssueAndCheckAllowedSites({"c.test"});
}

IN_PROC_BROWSER_TEST_F(TpcdMetadataDevtoolsObserverBrowserTest,
DoesNotEmitDevtoolsIssueForSiteNotInAllowlist) {
AddCookieAccess("b.test", "a.test");

CheckNoAddedIssue();
}

class TpcdMetadataDevtoolsObserverDisabledBrowserTest
: public TpcdMetadataDevtoolsObserverBrowserTest {
public:
TpcdMetadataDevtoolsObserverDisabledBrowserTest()
: TpcdMetadataDevtoolsObserverBrowserTest(
/*enable_metadata_feature=*/false) {}
};

IN_PROC_BROWSER_TEST_F(TpcdMetadataDevtoolsObserverDisabledBrowserTest,
DoesNotEmitDevtoolsIssueWithMissingFeature) {
AddCookieAccess("a.test", "b.test");

CheckNoAddedIssue();
}

} // namespace tpcd::metadata

0 comments on commit 5beee05

Please sign in to comment.