| // 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 "components/browsing_data/content/browsing_data_model.h" |
| |
| #include <array> |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| |
| #include "base/check.h" |
| #include "base/run_loop.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "base/test/bind.h" |
| #include "base/test/gmock_expected_support.h" |
| #include "base/test/run_until.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/test_future.h" |
| #include "base/test/test_timeouts.h" |
| #include "base/threading/platform_thread.h" |
| #include "chrome/browser/browsing_data/chrome_browsing_data_model_delegate.h" |
| #include "chrome/browser/media/clear_key_cdm_test_helper.h" |
| #include "chrome/browser/privacy_sandbox/privacy_sandbox_attestations/privacy_sandbox_attestations_mixin.h" |
| #include "chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.h" |
| #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h" |
| #include "chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.h" |
| #include "chrome/browser/web_applications/os_integration/os_integration_manager.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/test/base/chrome_test_utils.h" |
| #include "chrome/test/base/mixin_based_in_process_browser_test.h" |
| #include "chrome/test/base/ui_test_utils.h" |
| #include "components/browsing_data/content/browsing_data_model_test_util.h" |
| #include "components/browsing_data/content/browsing_data_test_util.h" |
| #include "components/browsing_data/content/shared_worker_info.h" |
| #include "components/content_settings/browser/page_specific_content_settings.h" |
| #include "components/content_settings/core/browser/cookie_settings.h" |
| #include "components/network_session_configurator/common/network_switches.h" |
| #include "components/performance_manager/public/features.h" |
| #include "components/privacy_sandbox/privacy_sandbox_attestations/privacy_sandbox_attestations.h" |
| #include "components/privacy_sandbox/privacy_sandbox_settings.h" |
| #include "components/services/storage/public/mojom/local_storage_control.mojom.h" |
| #include "components/services/storage/public/mojom/storage_usage_info.mojom.h" |
| #include "components/services/storage/shared_storage/shared_storage_manager.h" |
| #include "components/unexportable_keys/features.h" |
| #include "content/public/browser/attribution_data_model.h" |
| #include "content/public/browser/dom_storage_context.h" |
| #include "content/public/browser/network_service_instance.h" |
| #include "content/public/browser/private_aggregation_data_model.h" |
| #include "content/public/browser/storage_partition.h" |
| #include "content/public/browser/storage_usage_info.h" |
| #include "content/public/common/content_features.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/content_browser_test_content_browser_client.h" |
| #include "media/base/media_switches.h" |
| #include "net/base/features.h" |
| #include "net/base/schemeful_site.h" |
| #include "net/device_bound_sessions/test_support.h" |
| #include "net/dns/mock_host_resolver.h" |
| #include "net/shared_dictionary/shared_dictionary_isolation_key.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "net/test/embedded_test_server/request_handler_util.h" |
| #include "services/network/public/cpp/cors/cors.h" |
| #include "services/network/public/cpp/features.h" |
| #include "services/network/public/mojom/network_service.mojom.h" |
| #include "services/network/test/trust_token_request_handler.h" |
| #include "services/network/test/trust_token_test_server_handler_registration.h" |
| #include "services/network/test/trust_token_test_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/common/features.h" |
| #include "url/gurl.h" |
| #include "url/origin.h" |
| |
| using base::test::FeatureRef; |
| using base::test::FeatureRefAndParams; |
| using net::test_server::BasicHttpResponse; |
| using net::test_server::HttpMethod; |
| using net::test_server::HttpRequest; |
| using net::test_server::HttpResponse; |
| |
| namespace { |
| |
| constexpr char kTestHost[] = "a.test"; |
| constexpr char kTestHost2[] = "b.test"; |
| constexpr char kTestHost3[] = "c.test"; |
| |
| // FedCM constants |
| constexpr char kAccountId[] = "carl21334213"; |
| constexpr char kIdpOrigin[] = "https://127.0.0.1"; |
| constexpr char kExpectedConfigPath[] = "/fedcm.json"; |
| constexpr char kExpectedWellKnownPath[] = "/.well-known/web-identity"; |
| constexpr char kTestContentType[] = "application/json"; |
| constexpr char kIdpForbiddenHeader[] = "Sec-FedCM-CSRF"; |
| static constexpr char kSetLoginHeader[] = "Set-Login"; |
| static constexpr char kLoggedInHeaderValue[] = "logged-in"; |
| static constexpr char kLoggedOutHeaderValue[] = "logged-out"; |
| constexpr char kToken[] = "[not a real token]"; |
| |
| class TestDeviceBoundSessionAccessObserver |
| : public content::WebContentsObserver { |
| public: |
| TestDeviceBoundSessionAccessObserver(content::WebContents* web_contents, |
| base::OnceClosure on_access_closure) |
| : WebContentsObserver(web_contents), |
| on_access_closure_(std::move(on_access_closure)) {} |
| |
| // WebContentsObserver |
| void OnDeviceBoundSessionAccessed( |
| content::RenderFrameHost* render_frame_host, |
| const net::device_bound_sessions::SessionAccess& access) override { |
| if (on_access_closure_) { |
| std::move(on_access_closure_).Run(); |
| } |
| } |
| void OnDeviceBoundSessionAccessed( |
| content::NavigationHandle* navigation_handle, |
| const net::device_bound_sessions::SessionAccess& access) override { |
| if (on_access_closure_) { |
| std::move(on_access_closure_).Run(); |
| } |
| } |
| |
| private: |
| base::OnceClosure on_access_closure_; |
| }; |
| |
| void ProvideRequestHandlerKeyCommitmentsToNetworkService( |
| std::string_view host, |
| net::EmbeddedTestServer* https_server, |
| const network::test::TrustTokenRequestHandler& request_handler) { |
| base::flat_map<url::Origin, std::string_view> origins_and_commitments; |
| std::string key_commitments = request_handler.GetKeyCommitmentRecord(); |
| |
| GURL::Replacements replacements; |
| replacements.SetHostStr(host); |
| origins_and_commitments.insert_or_assign( |
| url::Origin::Create( |
| https_server->base_url().ReplaceComponents(replacements)), |
| key_commitments); |
| |
| base::RunLoop run_loop; |
| content::GetNetworkService()->SetTrustTokenKeyCommitments( |
| network::WrapKeyCommitmentsForIssuers(std::move(origins_and_commitments)), |
| run_loop.QuitClosure()); |
| run_loop.Run(); |
| } |
| |
| void JoinInterestGroup(const content::ToRenderFrameHost& adapter, |
| net::EmbeddedTestServer* https_server, |
| const std::string& owner_host) { |
| // join interest group |
| auto command = content::JsReplace( |
| R"( |
| (async () => { |
| try { |
| navigator.joinAdInterestGroup( |
| { |
| name: 'cars', |
| owner: $1, |
| biddingLogicURL: $2, |
| trustedBiddingSignalsURL: $3, |
| trustedBiddingSignalsKeys: ['key1'], |
| userBiddingSignals: {some: 'json', data: {here: [1, 2, 3]}}, |
| ads: [{ |
| renderURL: $4, |
| metadata: {ad: 'metadata', here: [1, 2, 3]}, |
| }], |
| }, |
| /*joinDurationSec=*/ 1000); |
| } catch (e) { |
| return e.toString(); |
| } |
| return "Success"; |
| })())", |
| https_server->GetURL(owner_host, "/"), |
| https_server->GetURL(owner_host, "/interest_group/bidding_logic.js"), |
| https_server->GetURL(owner_host, |
| "/interest_group/trusted_bidding_signals.json"), |
| GURL("https://example.com/render")); |
| EXPECT_EQ("Success", EvalJs(adapter, command)); |
| } |
| |
| void RunAdAuction(const content::ToRenderFrameHost& adapter, |
| net::EmbeddedTestServer* https_server, |
| const std::string& seller_host, |
| const std::string& buyer_host) { |
| std::string command = content::JsReplace( |
| R"( |
| (async function() { |
| try { |
| await navigator.runAdAuction({ |
| seller: $1, |
| decisionLogicURL: $2, |
| interestGroupBuyers: [$3], |
| }); |
| } catch (e) { |
| return e.toString(); |
| } |
| return "Success"; |
| })())", |
| https_server->GetURL(seller_host, "/"), |
| https_server->GetURL(seller_host, "/interest_group/decision_logic.js"), |
| https_server->GetURL(buyer_host, "/")); |
| EXPECT_EQ("Success", EvalJs(adapter, command)); |
| } |
| |
| void ExecuteScriptInSharedStorageWorklet( |
| const content::ToRenderFrameHost& execution_target, |
| const std::string& script, |
| GURL* out_module_script_url, |
| net::EmbeddedTestServer* https_server) { |
| CHECK(out_module_script_url); |
| |
| base::StringPairs run_function_body_replacement; |
| run_function_body_replacement.emplace_back("{{RUN_FUNCTION_BODY}}", script); |
| |
| std::string host = |
| execution_target.render_frame_host()->GetLastCommittedOrigin().host(); |
| |
| *out_module_script_url = |
| https_server->GetURL(host, net::test_server::GetFilePathWithReplacements( |
| "/shared_storage/customizable_module.js", |
| run_function_body_replacement)); |
| |
| EXPECT_TRUE(ExecJs(execution_target, |
| content::JsReplace("sharedStorage.worklet.addModule($1)", |
| *out_module_script_url))); |
| |
| testing::AssertionResult result = |
| ExecJs(execution_target, |
| "sharedStorage.run('test-operation', {keepAlive: true});"); |
| } |
| |
| void AccessTopics(const content::ToRenderFrameHost& adapter) { |
| std::string command = |
| R"( |
| (async () => { |
| try { |
| document.browsingTopics(); |
| } catch (e) { |
| return e.toString(); |
| } |
| return "Success"; |
| })())"; |
| EXPECT_EQ("Success", EvalJs(adapter, command)); |
| } |
| |
| class IdpTestServer { |
| public: |
| struct ConfigDetails { |
| net::HttpStatusCode status_code; |
| std::string content_type; |
| std::string accounts_endpoint_url; |
| std::string client_metadata_endpoint_url; |
| std::string id_assertion_endpoint_url; |
| std::string login_url; |
| std::map<std::string, |
| base::RepeatingCallback<std::unique_ptr<HttpResponse>( |
| const HttpRequest&)>> |
| servlets; |
| }; |
| |
| IdpTestServer() = default; |
| ~IdpTestServer() = default; |
| |
| IdpTestServer(const IdpTestServer&) = delete; |
| IdpTestServer& operator=(const IdpTestServer&) = delete; |
| |
| std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request) { |
| // RP files are fetched from the /test base directory. Assume anything |
| // to other paths is directed to the IdP. |
| if (request.relative_url.rfind("/test", 0) == 0) { |
| return nullptr; |
| } |
| |
| if (request.relative_url.rfind("/header/", 0) == 0) { |
| return BuildIdpHeaderResponse(request); |
| } |
| |
| if (request.all_headers.find(kIdpForbiddenHeader) != std::string::npos) { |
| EXPECT_EQ(request.headers.at(kIdpForbiddenHeader), "?1"); |
| } |
| |
| auto response = std::make_unique<BasicHttpResponse>(); |
| if (IsGetRequestWithPath(request, kExpectedConfigPath)) { |
| BuildConfigResponseFromDetails(*response.get(), config_details_); |
| return response; |
| } |
| |
| if (IsGetRequestWithPath(request, kExpectedWellKnownPath)) { |
| BuildWellKnownResponse(*response.get()); |
| return response; |
| } |
| |
| if (config_details_.servlets[request.relative_url]) { |
| return config_details_.servlets[request.relative_url].Run(request); |
| } |
| |
| return nullptr; |
| } |
| |
| std::unique_ptr<HttpResponse> BuildIdpHeaderResponse( |
| const HttpRequest& request) { |
| auto response = std::make_unique<BasicHttpResponse>(); |
| if (request.relative_url.find("/header/signin") != std::string::npos) { |
| response->AddCustomHeader(kSetLoginHeader, kLoggedInHeaderValue); |
| } else if (request.relative_url.find("/header/signout") != |
| std::string::npos) { |
| response->AddCustomHeader(kSetLoginHeader, kLoggedOutHeaderValue); |
| } else { |
| return nullptr; |
| } |
| response->set_code(net::HTTP_OK); |
| response->set_content_type("text/plain"); |
| response->set_content("Header sent."); |
| return response; |
| } |
| |
| void SetConfigResponseDetails(ConfigDetails details) { |
| config_details_ = details; |
| } |
| |
| private: |
| void BuildConfigResponseFromDetails(BasicHttpResponse& response, |
| const ConfigDetails& details) { |
| std::string content = ConvertToJsonDictionary( |
| {{"accounts_endpoint", details.accounts_endpoint_url}, |
| {"client_metadata_endpoint", details.client_metadata_endpoint_url}, |
| {"id_assertion_endpoint", details.id_assertion_endpoint_url}, |
| {"login_url", details.login_url}}); |
| response.set_code(details.status_code); |
| response.set_content(content); |
| response.set_content_type(details.content_type); |
| } |
| |
| void BuildWellKnownResponse(BasicHttpResponse& response) { |
| std::string content = base::StringPrintf("{\"provider_urls\": [\"%s\"]}", |
| kExpectedConfigPath); |
| response.set_code(net::HTTP_OK); |
| response.set_content(content); |
| response.set_content_type("application/json"); |
| } |
| |
| std::string ConvertToJsonDictionary( |
| const std::map<std::string, std::string>& data) { |
| std::string out = "{"; |
| for (auto it : data) { |
| out += "\"" + it.first + "\":\"" + it.second + "\","; |
| } |
| if (!out.empty()) { |
| out[out.length() - 1] = '}'; |
| } |
| return out; |
| } |
| |
| bool IsGetRequestWithPath(const HttpRequest& request, |
| const std::string& expected_path) { |
| return request.method == net::test_server::HttpMethod::METHOD_GET && |
| request.relative_url == expected_path; |
| } |
| |
| ConfigDetails config_details_; |
| }; |
| |
| std::string GetIdpConfigUrl(net::EmbeddedTestServer* https_server) { |
| return std::string(kIdpOrigin) + ":" + |
| base::NumberToString(https_server->port()) + "/fedcm.json"; |
| } |
| |
| IdpTestServer::ConfigDetails BuildValidConfigDetails() { |
| std::string accounts_endpoint_url = "/fedcm/accounts_endpoint.json"; |
| std::string client_metadata_endpoint_url = |
| "/fedcm/client_metadata_endpoint.json"; |
| std::string id_assertion_endpoint_url = "/fedcm/id_assertion_endpoint.json"; |
| std::string login_url = "/fedcm/login.html"; |
| std::map<std::string, base::RepeatingCallback<std::unique_ptr<HttpResponse>( |
| const HttpRequest&)>> |
| servlets; |
| servlets[id_assertion_endpoint_url] = base::BindRepeating( |
| [](const HttpRequest& request) -> std::unique_ptr<HttpResponse> { |
| EXPECT_EQ(request.method, HttpMethod::METHOD_POST); |
| EXPECT_EQ(request.has_content, true); |
| auto response = std::make_unique<BasicHttpResponse>(); |
| response->set_code(net::HTTP_OK); |
| response->set_content_type("text/json"); |
| DCHECK(request.headers.contains("Origin")); |
| response->AddCustomHeader( |
| network::cors::header_names::kAccessControlAllowOrigin, |
| request.headers.at("Origin")); |
| response->AddCustomHeader( |
| network::cors::header_names::kAccessControlAllowCredentials, |
| "true"); |
| // Standard scopes were used, so no extra permission needed. |
| // Return a token immediately. |
| response->set_content(R"({"token": ")" + std::string(kToken) + R"("})"); |
| return response; |
| }); |
| return {net::HTTP_OK, |
| kTestContentType, |
| accounts_endpoint_url, |
| client_metadata_endpoint_url, |
| id_assertion_endpoint_url, |
| login_url, |
| servlets}; |
| } |
| |
| void RunFedCm(const content::ToRenderFrameHost& adapter, |
| net::EmbeddedTestServer* https_server) { |
| std::string command = content::JsReplace( |
| R"( |
| (async () => { |
| try { |
| let cred = await navigator.credentials.get({ |
| identity: { |
| providers: [{ |
| configURL: $1, |
| clientId: '123', |
| nonce: '2', |
| }] |
| }, |
| mediation: 'required' |
| }); |
| return cred.token; |
| } catch (e) { |
| return e.toString(); |
| } |
| })())", |
| GetIdpConfigUrl(https_server)); |
| EXPECT_EQ(kToken, EvalJs(adapter, command)); |
| } |
| |
| void AddLocalStorageUsage(content::RenderFrameHost* render_frame_host, |
| int size) { |
| auto command = |
| content::JsReplace("localStorage.setItem('key', '!'.repeat($1))", size); |
| EXPECT_TRUE(ExecJs(render_frame_host, command)); |
| } |
| |
| void WaitForModelUpdate(BrowsingDataModel* model, size_t expected_size) { |
| ASSERT_TRUE( |
| base::test::RunUntil([&]() { return model->size() == expected_size; })); |
| } |
| |
| void RemoveBrowsingDataForDataOwner(BrowsingDataModel* model, |
| BrowsingDataModel::DataOwner data_owner) { |
| base::RunLoop run_loop; |
| model->RemoveBrowsingData(data_owner, run_loop.QuitClosure()); |
| run_loop.Run(); |
| } |
| |
| // Calls the accessStorage javascript function and awaits its completion for |
| // each frame in the active web contents for |browser|. |
| void EnsurePageAccessedStorage(content::WebContents* web_contents) { |
| web_contents->GetPrimaryMainFrame()->ForEachRenderFrameHost( |
| [](content::RenderFrameHost* frame) { |
| EXPECT_TRUE( |
| content::EvalJs(frame, |
| "(async () => { return await accessStorage();})()") |
| .ExtractBool()); |
| }); |
| } |
| } // namespace |
| |
| using browsing_data_model_test_util::ValidateBrowsingDataEntries; |
| using browsing_data_model_test_util::ValidateBrowsingDataEntriesNonZeroUsage; |
| using OperationResult = storage::SharedStorageDatabase::OperationResult; |
| using browsing_data_test_util::HasDataForType; |
| using browsing_data_test_util::SetDataForType; |
| |
| class BrowsingDataModelBrowserTest |
| : public MixinBasedInProcessBrowserTest, |
| public ::testing::WithParamInterface<bool> { |
| public: |
| BrowsingDataModelBrowserTest() { |
| std::vector<FeatureRefAndParams> enabled_features = { |
| {features::kPrivacySandboxAdsAPIsOverride, {}}, |
| {features::kIsolatedWebApps, {}}, |
| {features::kIsolatedWebAppDevMode, {}}, |
| {network::features::kSharedStorageAPI, {}}, |
| {network::features::kInterestGroupStorage, {}}, |
| {blink::features::kPrivateAggregationApi, {}}, |
| {blink::features::kAdInterestGroupAPI, {}}, |
| {blink::features::kFledge, {}}, |
| {blink::features::kFencedFrames, {}}, |
| {network::features::kBrowsingTopics, {}}, |
| {net::features::kThirdPartyStoragePartitioning, {}}, |
| {network::features::kCompressionDictionaryTransport, {}}, |
| }; |
| |
| std::vector<FeatureRef> disabled_features = { |
| // Need to disable kCompressionDictionaryTransportRequireKnownRootCert |
| // because EmbeddedTestServer's certificate is not rooted at a standard |
| // CA root. |
| net::features::kCompressionDictionaryTransportRequireKnownRootCert, |
| |
| // Model update success is sensitive to how quickly some best effort |
| // tasks are run so the test is not compatible with delaying |
| // them through EnableBestEffortTaskInhibitingPolicy. |
| performance_manager::features::kEnableBestEffortTaskInhibitingPolicy}; |
| |
| #if BUILDFLAG(ENABLE_LIBRARY_CDMS) |
| enabled_features.push_back({media::kExternalClearKeyForTesting, {}}); |
| #endif |
| |
| #if BUILDFLAG(ENABLE_DEVICE_BOUND_SESSIONS) |
| enabled_features.push_back({net::features::kDeviceBoundSessions, |
| {{"RequireOriginTrialTokens", "false"}}}); |
| enabled_features.push_back( |
| {unexportable_keys:: |
| kEnableBoundSessionCredentialsSoftwareKeysForManualTesting, |
| {}}); |
| #endif |
| |
| feature_list_.InitWithFeaturesAndParameters(enabled_features, |
| disabled_features); |
| } |
| |
| ~BrowsingDataModelBrowserTest() override = default; |
| |
| void SetUpOnMainThread() override { |
| PrivacySandboxSettingsFactory::GetForProfile(browser()->profile()) |
| ->SetAllPrivacySandboxAllowedForTesting(); |
| // Mark all Privacy Sandbox APIs as attested since the test cases are |
| // testing behaviors not related to attestations. |
| privacy_sandbox::PrivacySandboxAttestations::GetInstance() |
| ->SetAllPrivacySandboxAttestedForTesting(true); |
| host_resolver()->AddRule("*", "127.0.0.1"); |
| https_server_ = std::make_unique<net::EmbeddedTestServer>( |
| net::test_server::EmbeddedTestServer::TYPE_HTTPS); |
| https_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES); |
| https_server_->AddDefaultHandlers( |
| base::FilePath(FILE_PATH_LITERAL("content/test/data"))); |
| network::test::RegisterTrustTokenTestHandlers(https_test_server(), |
| &request_handler_); |
| idp_server_ = std::make_unique<IdpTestServer>(); |
| https_server_->RegisterRequestHandler(base::BindRepeating( |
| &IdpTestServer::HandleRequest, base::Unretained(idp_server_.get()))); |
| |
| ASSERT_TRUE(https_server_->InitializeAndListen()); |
| |
| // Must come after `InitializeAndListen` so we know the `base_url()`. |
| // We are testing DBSC against kTestHost, so register a handler for it. |
| https_server_->RegisterRequestHandler( |
| net::device_bound_sessions::GetTestRequestHandler( |
| https_server_->GetURL(kTestHost, "/"))); |
| |
| https_server_->StartAcceptingConnections(); |
| } |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| #if BUILDFLAG(ENABLE_LIBRARY_CDMS) |
| // Testing MediaLicenses requires additional command line parameters as |
| // it uses the External Clear Key CDM. |
| RegisterClearKeyCdm(command_line); |
| #endif |
| // These switches are needed to run FedCM and auto-select the first account. |
| command_line->AppendSwitch(switches::kIgnoreCertificateErrors); |
| command_line->AppendSwitchASCII(switches::kUseFakeUIForFedCM, kAccountId); |
| } |
| |
| protected: |
| std::unique_ptr<BrowsingDataModel> BuildBrowsingDataModel() { |
| base::test::TestFuture<std::unique_ptr<BrowsingDataModel>> |
| browsing_data_model; |
| BrowsingDataModel::BuildFromDisk( |
| browser()->profile(), |
| ChromeBrowsingDataModelDelegate::CreateForProfile(browser()->profile()), |
| browsing_data_model.GetCallback()); |
| return browsing_data_model.Take(); |
| } |
| |
| content::StoragePartition* default_storage_partition() { |
| return browser()->profile()->GetDefaultStoragePartition(); |
| } |
| |
| content::WebContents* web_contents() { |
| return browser()->tab_strip_model()->GetActiveWebContents(); |
| } |
| |
| net::EmbeddedTestServer* https_test_server() { return https_server_.get(); } |
| |
| GURL test_url() { return https_server_->GetURL(kTestHost, "/echo"); } |
| |
| void AccessStorage() { |
| ASSERT_TRUE(content::NavigateToURL( |
| chrome_test_utils::GetActiveWebContents(this), storage_accessor_url())); |
| base::RunLoop().RunUntilIdle(); |
| EnsurePageAccessedStorage(chrome_test_utils::GetActiveWebContents(this)); |
| } |
| |
| GURL storage_accessor_url() { |
| auto host_port_pair = |
| net::HostPortPair::FromURL(https_test_server()->GetURL(kTestHost, "/")); |
| base::StringPairs replacement_text = { |
| {"REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString()}}; |
| auto replaced_path = net::test_server::GetFilePathWithReplacements( |
| "/browsing_data/storage_accessor.html", replacement_text); |
| return https_test_server()->GetURL(kTestHost, replaced_path); |
| } |
| |
| IdpTestServer* idp_server() { return idp_server_.get(); } |
| |
| network::test::TrustTokenRequestHandler request_handler_; |
| |
| private: |
| std::unique_ptr<net::EmbeddedTestServer> https_server_; |
| privacy_sandbox::PrivacySandboxAttestationsMixin |
| privacy_sandbox_attestations_mixin_{&mixin_host_}; |
| |
| web_app::OsIntegrationTestOverrideBlockingRegistration faked_os_integration_; |
| base::test::ScopedFeatureList feature_list_; |
| std::unique_ptr<IdpTestServer> idp_server_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| SharedStorageHandledCorrectly) { |
| // Add origin shared storage. |
| auto* shared_storage_manager = |
| default_storage_partition()->GetSharedStorageManager(); |
| ASSERT_NE(nullptr, shared_storage_manager); |
| |
| base::test::TestFuture<OperationResult> future; |
| url::Origin testOrigin = url::Origin::Create(GURL("https://a.test")); |
| shared_storage_manager->Set( |
| testOrigin, u"key", u"value", future.GetCallback(), |
| storage::SharedStorageDatabase::SetBehavior::kDefault); |
| EXPECT_EQ(OperationResult::kSet, future.Get()); |
| |
| std::unique_ptr<BrowsingDataModel> browsing_data_model = |
| BuildBrowsingDataModel(); |
| // Validate shared storage entry saved correctly. |
| base::test::TestFuture<uint64_t> test_entry_storage_size; |
| shared_storage_manager->FetchOrigins(base::BindLambdaForTesting( |
| [&](std::vector<::storage::mojom::StorageUsageInfoPtr> |
| storage_usage_info) { |
| ASSERT_EQ(1U, storage_usage_info.size()); |
| test_entry_storage_size.SetValue( |
| storage_usage_info[0]->total_size_bytes); |
| })); |
| |
| ValidateBrowsingDataEntries( |
| browsing_data_model.get(), |
| {{kTestHost, |
| blink::StorageKey::CreateFirstParty(testOrigin), |
| {{BrowsingDataModel::StorageType::kSharedStorage}, |
| test_entry_storage_size.Get(), |
| /*cookie_count=*/0}}}); |
| |
| // Remove origin. |
| RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost); |
| |
| // Rebuild Browsing Data Model and verify entries are empty. |
| browsing_data_model = BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| SharedStorageAccessReportedCorrectly) { |
| // Navigate to test page. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url())); |
| auto* content_settings = |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()); |
| |
| // Validate that the allowed browsing data model is empty. |
| ValidateBrowsingDataEntries(content_settings->allowed_browsing_data_model(), |
| {}); |
| |
| // Create a SharedStorage entry. |
| std::string command = R"( |
| (async () => { |
| try { |
| await window.sharedStorage.set('age-group', 1); |
| return true; |
| } catch { |
| return false; |
| } |
| })();)"; |
| EXPECT_EQ(true, EvalJs(web_contents(), command)); |
| |
| // Validate that the allowed browsing data model is populated with |
| // SharedStorage entry for `kTestHost`. |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| ValidateBrowsingDataEntries( |
| content_settings->allowed_browsing_data_model(), |
| {{kTestHost, |
| blink::StorageKey::CreateFirstParty(testOrigin), |
| {{BrowsingDataModel::StorageType::kSharedStorage}, |
| /*storage_size=*/0, |
| /*cookie_count=*/0}}}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, TrustTokenIssuance) { |
| // Setup the test server to be able to issue trust tokens, and have it issue |
| // some to the profile. |
| ProvideRequestHandlerKeyCommitmentsToNetworkService( |
| kTestHost, https_test_server(), request_handler_); |
| |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), https_test_server()->GetURL(kTestHost, "/title1.html"))); |
| |
| std::string issuance_origin = |
| url::Origin::Create(https_test_server()->GetURL(kTestHost, "/")) |
| .Serialize(); |
| |
| std::string command = content::JsReplace(R"( |
| (async () => { |
| try { |
| await fetch("/issue", {privateToken: {version: 1, |
| operation: 'token-request'}}); |
| return await document.hasPrivateToken($1); |
| } catch { |
| return false; |
| } |
| })();)", |
| issuance_origin); |
| |
| EXPECT_EQ(true, EvalJs(web_contents(), command)); |
| |
| browser() |
| ->profile() |
| ->GetDefaultStoragePartition() |
| ->FlushNetworkInterfaceForTesting(); |
| |
| // Confirm that a BrowsingDataModel built from disk contains the issued token |
| // information. |
| std::unique_ptr<BrowsingDataModel> browsing_data_model = |
| BuildBrowsingDataModel(); |
| |
| ValidateBrowsingDataEntries( |
| browsing_data_model.get(), |
| {{kTestHost, |
| https_test_server()->GetOrigin(kTestHost), |
| {{BrowsingDataModel::StorageType::kTrustTokens}, 100, 0}}}); |
| |
| // Remove data for the host, and confirm the model updates appropriately. |
| RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| |
| // Build another model from disk, ensuring the data is no longer present. |
| browsing_data_model = BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| InterestGroupsHandledCorrectly) { |
| // Check that no interest groups are joined at the beginning of the test. |
| std::unique_ptr<BrowsingDataModel> browsing_data_model = |
| BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| ASSERT_EQ(browsing_data_model->size(), 0u); |
| |
| // Join an interest group. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url())); |
| JoinInterestGroup(web_contents(), https_test_server(), kTestHost); |
| |
| // Waiting for the browsing data model to be populated, otherwise the test is |
| // flaky. |
| do { |
| browsing_data_model = BuildBrowsingDataModel(); |
| base::PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
| } while (browsing_data_model->size() != 1); |
| |
| // Validate that an interest group is added. |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| content::InterestGroupManager::InterestGroupDataKey data_key{testOrigin, |
| testOrigin}; |
| ValidateBrowsingDataEntries( |
| browsing_data_model.get(), |
| {{kTestHost, |
| data_key, |
| {{BrowsingDataModel::StorageType::kInterestGroup}, |
| /*storage_size=*/1024, |
| /*cookie_count=*/0}}}); |
| |
| // Remove Interest Group. |
| RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost); |
| |
| // Rebuild Browsing Data Model and verify entries are empty. |
| browsing_data_model = BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| InterestGroupsAccessReportedCorrectly) { |
| // Navigate to test page. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url())); |
| auto* content_settings = |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()); |
| |
| // Validate that the allowed browsing data model is empty. |
| auto* allowed_browsing_data_model = |
| content_settings->allowed_browsing_data_model(); |
| ValidateBrowsingDataEntries(allowed_browsing_data_model, {}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 0u); |
| |
| // Join an interest group. |
| JoinInterestGroup(web_contents(), https_test_server(), kTestHost); |
| WaitForModelUpdate(allowed_browsing_data_model, 1); |
| |
| // Validate that an interest group is reported to the browsing data model. |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| content::InterestGroupManager::InterestGroupDataKey data_key{testOrigin, |
| testOrigin}; |
| ValidateBrowsingDataEntries( |
| allowed_browsing_data_model, |
| {{kTestHost, |
| data_key, |
| {{BrowsingDataModel::StorageType::kInterestGroup}, |
| /*storage_size=*/0, |
| /*cookie_count=*/0}}}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| AuctionWinReportedCorrectly) { |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url())); |
| JoinInterestGroup(web_contents(), https_test_server(), kTestHost); |
| |
| // Run an auction on `kTestHost2`. A different host is used to ensure the |
| // correct host (`kTestHost`) is reported as having accessed storage. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), https_test_server()->GetURL(kTestHost2, "/echo"))); |
| |
| auto* content_settings = |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()); |
| |
| // Validate that the allowed browsing data model is empty. |
| auto* allowed_browsing_data_model = |
| content_settings->allowed_browsing_data_model(); |
| ValidateBrowsingDataEntries(allowed_browsing_data_model, {}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 0u); |
| |
| RunAdAuction(web_contents(), https_test_server(), /*seller_host=*/kTestHost2, |
| /*buyer_host=*/kTestHost); |
| WaitForModelUpdate(allowed_browsing_data_model, 1); |
| |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| content::InterestGroupManager::InterestGroupDataKey data_key{testOrigin, |
| testOrigin}; |
| ValidateBrowsingDataEntries( |
| allowed_browsing_data_model, |
| {{kTestHost, |
| data_key, |
| {{BrowsingDataModel::StorageType::kInterestGroup}, |
| /*storage_size=*/0, |
| /*cookie_count=*/0}}}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| AttributionReportingAccessReportedCorrectly) { |
| const GURL kTestCases[] = { |
| https_test_server()->GetURL( |
| "a.test", "/attribution_reporting/register_source_headers.html"), |
| https_test_server()->GetURL( |
| "a.test", "/attribution_reporting/register_trigger_headers.html")}; |
| |
| for (const auto& register_url : kTestCases) { |
| // Navigate to test page. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url())); |
| auto* content_settings = |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()); |
| |
| // Validate that the allowed browsing data model is empty. |
| auto* allowed_browsing_data_model = |
| content_settings->allowed_browsing_data_model(); |
| ValidateBrowsingDataEntries(allowed_browsing_data_model, {}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 0u); |
| |
| // Register a source. |
| ASSERT_TRUE(ExecJs(web_contents(), content::JsReplace(R"( |
| const img = document.createElement('img'); |
| img.attributionSrc = $1;)", |
| register_url))); |
| |
| WaitForModelUpdate(allowed_browsing_data_model, 1); |
| |
| // Validate that an attribution reporting datakey is reported to the |
| // browsing data model. |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| content::AttributionDataModel::DataKey data_key{testOrigin}; |
| ValidateBrowsingDataEntries( |
| allowed_browsing_data_model, |
| {{kTestHost, |
| data_key, |
| {{BrowsingDataModel::StorageType::kAttributionReporting}, |
| /*storage_size=*/0, |
| /*cookie_count=*/0}}}); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| PrivateAggregationHandledCorrectly) { |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url())); |
| |
| // Validate that there are no entries in the browsing data model. |
| std::unique_ptr<BrowsingDataModel> browsing_data_model = |
| BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| |
| GURL out_script_url; |
| ExecuteScriptInSharedStorageWorklet(web_contents(), R"( |
| privateAggregation.contributeToHistogram({bucket: 1n, value: 2}); |
| )", |
| &out_script_url, https_test_server()); |
| |
| do { |
| browsing_data_model = BuildBrowsingDataModel(); |
| base::PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
| } while (browsing_data_model->size() < 1); |
| |
| // Validate that a private aggregation data key is added. |
| url::Origin test_origin = https_test_server()->GetOrigin(kTestHost); |
| content::PrivateAggregationDataModel::DataKey data_key{test_origin}; |
| |
| ValidateBrowsingDataEntries( |
| browsing_data_model.get(), |
| {{kTestHost, |
| data_key, |
| {{BrowsingDataModel::StorageType::kPrivateAggregation}, |
| /*storage_size=*/100, |
| /*cookie_count=*/0}}}); |
| |
| // Remove datakey from aggregation service and private budgeter. |
| RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost); |
| |
| // Rebuild Browsing Data Model and verify entries are empty. |
| browsing_data_model = BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| TopicsAccessReportedCorrectly) { |
| // Navigate to test page. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url())); |
| |
| auto* content_settings = |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()); |
| |
| // Validate that the allowed browsing data model is empty. |
| auto* allowed_browsing_data_model = |
| content_settings->allowed_browsing_data_model(); |
| ValidateBrowsingDataEntries(allowed_browsing_data_model, {}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 0u); |
| |
| // Get Topics |
| AccessTopics(web_contents()); |
| |
| WaitForModelUpdate(allowed_browsing_data_model, 1); |
| |
| // Validate Topics are reported correctly |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| ValidateBrowsingDataEntries( |
| allowed_browsing_data_model, |
| {{kTestHost, |
| testOrigin, |
| {{static_cast<BrowsingDataModel::StorageType>( |
| ChromeBrowsingDataModelDelegate::StorageType::kTopics)}, |
| /*storage_size=*/0, |
| /*cookie_count=*/0}}}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 1u); |
| |
| // Clear Topic via BDM |
| RemoveBrowsingDataForDataOwner(allowed_browsing_data_model, kTestHost); |
| |
| // Validate that the allowed browsing data model is cleared. |
| ValidateBrowsingDataEntries(allowed_browsing_data_model, {}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 0u); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| IsolatedWebAppUsageInDefaultStoragePartitionModel) { |
| // Check that no IWAs are installed at the beginning of the test. |
| std::unique_ptr<BrowsingDataModel> browsing_data_model = |
| BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| ASSERT_EQ(browsing_data_model->size(), 0u); |
| |
| Profile* profile = browser()->profile(); |
| |
| std::unique_ptr<web_app::ScopedBundledIsolatedWebApp> app1 = |
| web_app::IsolatedWebAppBuilder(web_app::ManifestBuilder()).BuildBundle(); |
| ASSERT_OK_AND_ASSIGN(web_app::IsolatedWebAppUrlInfo iwa_url_info1, |
| app1->Install(profile)); |
| auto* iwa_frame1 = |
| web_app::OpenIsolatedWebApp(profile, iwa_url_info1.app_id()); |
| AddLocalStorageUsage(iwa_frame1, 100); |
| |
| std::unique_ptr<web_app::ScopedBundledIsolatedWebApp> app2 = |
| web_app::IsolatedWebAppBuilder(web_app::ManifestBuilder()).BuildBundle(); |
| ASSERT_OK_AND_ASSIGN(web_app::IsolatedWebAppUrlInfo iwa_url_info2, |
| app2->Install(profile)); |
| auto* iwa_frame2 = |
| web_app::OpenIsolatedWebApp(profile, iwa_url_info2.app_id()); |
| AddLocalStorageUsage(iwa_frame2, 500); |
| |
| browsing_data_model = BuildBrowsingDataModel(); |
| |
| ValidateBrowsingDataEntries( |
| browsing_data_model.get(), |
| {{iwa_url_info1.origin(), |
| iwa_url_info1.origin(), |
| {{static_cast<BrowsingDataModel::StorageType>( |
| ChromeBrowsingDataModelDelegate::StorageType::kIsolatedWebApp)}, |
| /*storage_size=*/105, |
| /*cookie_count=*/0}}, |
| {iwa_url_info2.origin(), |
| iwa_url_info2.origin(), |
| {{static_cast<BrowsingDataModel::StorageType>( |
| ChromeBrowsingDataModelDelegate::StorageType::kIsolatedWebApp)}, |
| /*storage_size=*/505, |
| /*cookie_count=*/0}}}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| QuotaStorageHandledCorrectly) { |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), |
| https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html"))); |
| // Ensure that there isn't any data fetched. |
| std::unique_ptr<BrowsingDataModel> browsing_data_model = |
| BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| ASSERT_EQ(browsing_data_model->size(), 0u); |
| |
| std::vector<std::string> quota_storage_data_types = { |
| "ServiceWorker", "IndexedDb", "FileSystem"}; |
| |
| for (auto data_type : quota_storage_data_types) { |
| SetDataForType(data_type, web_contents()); |
| ASSERT_TRUE(HasDataForType(data_type, web_contents())); |
| |
| // Ensure that quota data is fetched |
| browsing_data_model = BuildBrowsingDataModel(); |
| |
| // Validate that quota data is fetched to browsing data model. |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| auto data_key = blink::StorageKey::CreateFirstParty(testOrigin); |
| ValidateBrowsingDataEntriesNonZeroUsage( |
| browsing_data_model.get(), |
| {{kTestHost, |
| data_key, |
| {{BrowsingDataModel::StorageType::kQuotaStorage}, |
| /*storage_size=*/0, |
| /*cookie_count=*/0}}}); |
| |
| ASSERT_EQ(browsing_data_model->size(), 1u); |
| |
| // Remove quota entry. |
| RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost); |
| |
| // Rebuild Browsing Data Model and verify entries are empty. |
| browsing_data_model = BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| ASSERT_EQ(browsing_data_model->size(), 0u); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| LocalStorageHandledCorrectly) { |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), |
| https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html"))); |
| // Ensure that there isn't any data fetched. |
| std::unique_ptr<BrowsingDataModel> browsing_data_model = |
| BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| ASSERT_EQ(browsing_data_model->size(), 0u); |
| |
| SetDataForType("LocalStorage", web_contents()); |
| |
| // Flush storage size to disk. |
| auto* storage_partition = browser()->profile()->GetDefaultStoragePartition(); |
| storage_partition->Flush(); |
| |
| // To ensure that flushing is completed. |
| base::RunLoop().RunUntilIdle(); |
| |
| auto* dom_storage_context = storage_partition->GetDOMStorageContext(); |
| |
| // Fetch local storage size from backend. |
| base::test::TestFuture<uint64_t> test_entry_storage_size; |
| dom_storage_context->GetLocalStorageUsage(base::BindLambdaForTesting( |
| [&](const std::vector<content::StorageUsageInfo>& storage_usage_info) { |
| ASSERT_EQ(1U, storage_usage_info.size()); |
| test_entry_storage_size.SetValue( |
| storage_usage_info[0].total_size_bytes); |
| })); |
| |
| // Ensure that local storage is fetched |
| browsing_data_model = BuildBrowsingDataModel(); |
| |
| // Validate that local storage is fetched to browsing data model. |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| auto data_key = blink::StorageKey::CreateFirstParty(testOrigin); |
| ValidateBrowsingDataEntries( |
| browsing_data_model.get(), |
| {{kTestHost, |
| data_key, |
| {{BrowsingDataModel::StorageType::kLocalStorage}, |
| test_entry_storage_size.Get(), |
| /*cookie_count=*/0}}}); |
| ASSERT_EQ(browsing_data_model->size(), 1u); |
| |
| // Remove local storage entry. |
| RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost); |
| |
| // Rebuild Browsing Data Model and verify entries are empty. |
| browsing_data_model = BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| ASSERT_EQ(browsing_data_model->size(), 0u); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| LocalStorageAccessReportedCorrectly) { |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), |
| https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html"))); |
| |
| auto* content_settings = |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()); |
| |
| // Validate that the allowed browsing data model is empty. |
| auto* allowed_browsing_data_model = |
| content_settings->allowed_browsing_data_model(); |
| ValidateBrowsingDataEntries(allowed_browsing_data_model, {}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 0u); |
| |
| SetDataForType("LocalStorage", web_contents()); |
| WaitForModelUpdate(allowed_browsing_data_model, /*expected_size=*/1); |
| |
| // Validate Local Storage is reported. |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| auto data_key = blink::StorageKey::CreateFirstParty(testOrigin); |
| ValidateBrowsingDataEntries( |
| allowed_browsing_data_model, |
| {{kTestHost, |
| data_key, |
| {{BrowsingDataModel::StorageType::kLocalStorage}, |
| /*storage_size=*/0, |
| /*cookie_count=*/0}}}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 1u); |
| |
| // Delete Local Storage |
| RemoveBrowsingDataForDataOwner(allowed_browsing_data_model, kTestHost); |
| // Validate that the allowed browsing data model is empty. |
| ValidateBrowsingDataEntries(allowed_browsing_data_model, {}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 0u); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| SessionStorageAccessReportedCorrectly) { |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), |
| https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html"))); |
| |
| auto* content_settings = |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()); |
| |
| // Validate that the allowed browsing data model is empty. |
| auto* allowed_browsing_data_model = |
| content_settings->allowed_browsing_data_model(); |
| ValidateBrowsingDataEntries(allowed_browsing_data_model, {}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 0u); |
| |
| SetDataForType("SessionStorage", web_contents()); |
| WaitForModelUpdate(allowed_browsing_data_model, /*expected_size=*/1); |
| |
| // Validate Session Storage is reported. |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| auto storage_key = blink::StorageKey::CreateFirstParty(testOrigin); |
| |
| // Obtaining Session Storage namespace_id from the navigation controller. |
| const auto& session_storage_namespace_map = |
| web_contents()->GetController().GetSessionStorageNamespaceMap(); |
| const auto& storage_partition_config = |
| content::StoragePartitionConfig::CreateDefault( |
| web_contents()->GetBrowserContext()); |
| const auto& namespace_id = |
| session_storage_namespace_map.at(storage_partition_config); |
| |
| content::SessionStorageUsageInfo data_key{storage_key, namespace_id->id()}; |
| |
| ValidateBrowsingDataEntries( |
| allowed_browsing_data_model, |
| {{kTestHost, |
| data_key, |
| {{BrowsingDataModel::StorageType::kSessionStorage}, |
| /*storage_size=*/0, |
| /*cookie_count=*/0}}}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 1u); |
| |
| // Delete Session Storage |
| RemoveBrowsingDataForDataOwner(allowed_browsing_data_model, kTestHost); |
| |
| // Validate that the allowed browsing data model is empty. |
| ValidateBrowsingDataEntries(allowed_browsing_data_model, {}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 0u); |
| // Reloading the page to ensure the renderer reflects deletion before checking |
| // if the storage type still exists on disk. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), |
| https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html"))); |
| ASSERT_FALSE(HasDataForType("SessionStorage", web_contents())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| QuotaStorageAccessReportedCorrectly) { |
| // Keeping the `ServiceWorker` type last as checking it after deletion counts |
| // as a new access report and repopulates the model, this way we keep it from |
| // affecting other quota storage types test. |
| std::vector<std::string> quota_storage_data_types = { |
| "IndexedDb", "FileSystem", "ServiceWorker"}; |
| |
| for (auto data_type : quota_storage_data_types) { |
| // Re-Navigate to the page for every data type, to prevent any cached data |
| // access results from impacting whether access is reported or not. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), https_test_server()->GetURL( |
| kTestHost, "/browsing_data/site_data.html"))); |
| |
| auto* content_settings = |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()); |
| |
| // Validate that the allowed browsing data model is empty. |
| auto* allowed_browsing_data_model = |
| content_settings->allowed_browsing_data_model(); |
| ValidateBrowsingDataEntries(allowed_browsing_data_model, {}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 0u); |
| |
| SetDataForType(data_type, web_contents()); |
| WaitForModelUpdate(allowed_browsing_data_model, /*expected_size=*/1); |
| |
| // Validate quota storage is reported. |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| auto data_key = blink::StorageKey::CreateFirstParty(testOrigin); |
| ValidateBrowsingDataEntries( |
| allowed_browsing_data_model, |
| {{kTestHost, |
| data_key, |
| {{BrowsingDataModel::StorageType::kQuotaStorage}, |
| /*storage_size=*/0, |
| /*cookie_count=*/0}}}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 1u); |
| |
| // Delete quota storage |
| RemoveBrowsingDataForDataOwner(allowed_browsing_data_model, kTestHost); |
| // Validate that the allowed browsing data model is empty. |
| ValidateBrowsingDataEntries(allowed_browsing_data_model, {}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 0u); |
| ASSERT_FALSE(HasDataForType(data_type, web_contents())); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| SharedWorkerAccessReportedCorrectly) { |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), |
| https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html"))); |
| |
| auto* content_settings = |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()); |
| |
| // Validate that the allowed browsing data model is empty. |
| auto* allowed_browsing_data_model = |
| content_settings->allowed_browsing_data_model(); |
| ValidateBrowsingDataEntries(allowed_browsing_data_model, {}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 0u); |
| |
| SetDataForType("SharedWorker", web_contents()); |
| WaitForModelUpdate(allowed_browsing_data_model, /*expected_size=*/1); |
| |
| // Validate Shared Worker is reported. |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| GURL::Replacements replacements; |
| replacements.SetPathStr("browsing_data/shared_worker.js"); |
| GURL worker = testOrigin.GetURL().ReplaceComponents(replacements); |
| browsing_data::SharedWorkerInfo data_key( |
| worker, /*name=*/"", blink::StorageKey::CreateFirstParty(testOrigin), |
| blink::mojom::SharedWorkerSameSiteCookies::kAll); |
| ValidateBrowsingDataEntries( |
| allowed_browsing_data_model, |
| {{kTestHost, |
| data_key, |
| {{BrowsingDataModel::StorageType::kSharedWorker}, |
| /*storage_size=*/0, |
| /*cookie_count=*/0}}}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 1u); |
| |
| // Delete Shared Worker |
| RemoveBrowsingDataForDataOwner(allowed_browsing_data_model, kTestHost); |
| // Validate that the allowed browsing data model is empty. |
| ValidateBrowsingDataEntries(allowed_browsing_data_model, {}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 0u); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| LocalStorageRemovedBasedOnPartition) { |
| // Build BDM from disk. |
| std::unique_ptr<BrowsingDataModel> browsing_data_model = |
| BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| |
| // Navigate to a.test. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), https_test_server()->GetURL( |
| kTestHost, "/browsing_data/embedded_site_data.html"))); |
| |
| // Set local storage (a on a). |
| SetDataForType("LocalStorage", content::ChildFrameAt(web_contents(), 0)); |
| |
| // Navigate to b.test. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), https_test_server()->GetURL( |
| kTestHost2, "/browsing_data/embedded_site_data.html"))); |
| |
| // Set local storage (a on b). |
| SetDataForType("LocalStorage", content::ChildFrameAt(web_contents(), 0)); |
| |
| // Navigate to c.test. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), https_test_server()->GetURL( |
| kTestHost3, "/browsing_data/embedded_site_data.html"))); |
| |
| // Set local storage (a on c). |
| SetDataForType("LocalStorage", content::ChildFrameAt(web_contents(), 0)); |
| |
| // Flush storage size to disk. |
| auto* storage_partition = browser()->profile()->GetDefaultStoragePartition(); |
| storage_partition->Flush(); |
| |
| // To ensure that flushing is completed. |
| base::RunLoop().RunUntilIdle(); |
| |
| auto* dom_storage_context = storage_partition->GetDOMStorageContext(); |
| |
| // Fetch local storage size from backend. |
| std::array<base::test::TestFuture<uint64_t>, 3> test_entry_storage_size; |
| dom_storage_context->GetLocalStorageUsage(base::BindLambdaForTesting( |
| [&](const std::vector<content::StorageUsageInfo>& storage_usage_info) { |
| ASSERT_EQ(3U, storage_usage_info.size()); |
| test_entry_storage_size[0].SetValue( |
| storage_usage_info[0].total_size_bytes); |
| |
| test_entry_storage_size[1].SetValue( |
| storage_usage_info[1].total_size_bytes); |
| |
| test_entry_storage_size[2].SetValue( |
| storage_usage_info[2].total_size_bytes); |
| })); |
| |
| // Rebuild from disk. |
| browsing_data_model = BuildBrowsingDataModel(); |
| |
| auto testHostOrigin = https_test_server()->GetOrigin(kTestHost); |
| auto top_level_site_a = net::SchemefulSite(GURL("https://a.test")); |
| auto storage_key_a = |
| blink::StorageKey::Create(testHostOrigin, top_level_site_a, |
| blink::mojom::AncestorChainBit::kSameSite); |
| |
| auto top_level_site_b = net::SchemefulSite(GURL("https://b.test")); |
| auto storage_key_b = |
| blink::StorageKey::Create(testHostOrigin, top_level_site_b, |
| blink::mojom::AncestorChainBit::kCrossSite); |
| |
| auto top_level_site_c = net::SchemefulSite(GURL("https://c.test")); |
| auto storage_key_c = |
| blink::StorageKey::Create(testHostOrigin, top_level_site_c, |
| blink::mojom::AncestorChainBit::kCrossSite); |
| |
| // Validate entries {{a on a}, {a on b}, {a on c}}. |
| ValidateBrowsingDataEntries( |
| browsing_data_model.get(), |
| {{kTestHost, |
| storage_key_a, |
| {{BrowsingDataModel::StorageType::kLocalStorage}, |
| test_entry_storage_size[0].Get(), |
| /*cookie_count=*/0}}, |
| {kTestHost, |
| storage_key_b, |
| {{BrowsingDataModel::StorageType::kLocalStorage}, |
| test_entry_storage_size[1].Get(), |
| /*cookie_count=*/0}}, |
| {kTestHost, |
| storage_key_c, |
| {{BrowsingDataModel::StorageType::kLocalStorage}, |
| test_entry_storage_size[2].Get(), |
| /*cookie_count=*/0}}}); |
| |
| // Remove {a on b}. |
| { |
| base::RunLoop run_loop; |
| browsing_data_model->RemovePartitionedBrowsingData( |
| kTestHost, top_level_site_b, run_loop.QuitClosure()); |
| run_loop.Run(); |
| } |
| |
| // Rebuild from disk. |
| browsing_data_model = BuildBrowsingDataModel(); |
| |
| // Validate entries {{a on a}, {a on c}}. |
| ValidateBrowsingDataEntries( |
| browsing_data_model.get(), |
| {{kTestHost, |
| storage_key_a, |
| {{BrowsingDataModel::StorageType::kLocalStorage}, |
| test_entry_storage_size[0].Get(), |
| /*cookie_count=*/0}}, |
| {kTestHost, |
| storage_key_c, |
| {{BrowsingDataModel::StorageType::kLocalStorage}, |
| test_entry_storage_size[2].Get(), |
| /*cookie_count=*/0}}}); |
| |
| // Remove {a on a} |
| { |
| base::RunLoop run_loop; |
| browsing_data_model->RemoveUnpartitionedBrowsingData( |
| kTestHost, run_loop.QuitClosure()); |
| run_loop.Run(); |
| } |
| |
| // Rebuild from disk. |
| browsing_data_model = BuildBrowsingDataModel(); |
| |
| // Validate entries {{a on c}}. |
| ValidateBrowsingDataEntries( |
| browsing_data_model.get(), |
| {{kTestHost, |
| storage_key_c, |
| {{BrowsingDataModel::StorageType::kLocalStorage}, |
| test_entry_storage_size[2].Get(), |
| /*cookie_count=*/0}}}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| SharedDictionaryHandledCorrectly) { |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), |
| https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html"))); |
| // Ensure that there isn't any data fetched. |
| std::unique_ptr<BrowsingDataModel> browsing_data_model = |
| BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| ASSERT_EQ(browsing_data_model->size(), 0u); |
| |
| SetDataForType("SharedDictionary", web_contents()); |
| |
| // Ensure that shared dictionary is fetched |
| browsing_data_model = BuildBrowsingDataModel(); |
| |
| // Validate that shared dictionary is fetched to browsing data model. |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| auto isolation_key = net::SharedDictionaryIsolationKey( |
| testOrigin, net::SchemefulSite(testOrigin)); |
| ValidateBrowsingDataEntriesNonZeroUsage( |
| browsing_data_model.get(), |
| {{kTestHost, |
| isolation_key, |
| {{BrowsingDataModel::StorageType::kSharedDictionary}, |
| /*storage_size=*/0, |
| /*cookie_count=*/0}}}); |
| ASSERT_EQ(browsing_data_model->size(), 1u); |
| |
| // Remove shared dictionary entry. |
| RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost); |
| |
| // Shared dictionary must have been removed. |
| EXPECT_FALSE(HasDataForType("SharedDictionary", web_contents())); |
| |
| // Rebuild Browsing Data Model and verify entries are empty. |
| browsing_data_model = BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| ASSERT_EQ(browsing_data_model->size(), 0u); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| SharedDictionaryAccessReportedCorrectly) { |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), |
| https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html"))); |
| auto* content_settings = |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()); |
| // Validate that the allowed browsing data model is empty. |
| ValidateBrowsingDataEntries(content_settings->allowed_browsing_data_model(), |
| {}); |
| SetDataForType("SharedDictionary", web_contents()); |
| // Calling SetDataForType("SharedDictionary") registers a shared dictionary. |
| // This must be reported to the data model. |
| WaitForModelUpdate(content_settings->allowed_browsing_data_model(), 1); |
| |
| // Validate that the allowed browsing data model is populated with |
| // SharedDictionary entry for `kTestHost`. |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| auto isolation_key = net::SharedDictionaryIsolationKey( |
| testOrigin, net::SchemefulSite(testOrigin)); |
| ValidateBrowsingDataEntries( |
| content_settings->allowed_browsing_data_model(), |
| {{kTestHost, |
| isolation_key, |
| {{BrowsingDataModel::StorageType::kSharedDictionary}, |
| /*storage_size=*/0, |
| /*cookie_count=*/0}}}); |
| |
| // Navigate to about:blank to clear the browsing data model state. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL("about:blank"))); |
| // Validate that the allowed browsing data model is empty. |
| ValidateBrowsingDataEntries( |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()) |
| ->allowed_browsing_data_model(), |
| {}); |
| |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), |
| https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html"))); |
| // Validate that the allowed browsing data model is empty. |
| ValidateBrowsingDataEntries( |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()) |
| ->allowed_browsing_data_model(), |
| {}); |
| |
| // Need this polling because the shared dictionary is used only if the |
| // metadata database has been read when sending the HTTP request. |
| while (!HasDataForType("SharedDictionary", web_contents())) { |
| base::PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
| } |
| |
| // Checking HasDataForType("SharedDictionary") accesses the registered |
| // shared dictionary. This must be reported to the data model. |
| content_settings = content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()); |
| WaitForModelUpdate(content_settings->allowed_browsing_data_model(), 1); |
| |
| // Validate that the allowed browsing data model is populated with |
| // SharedDictionary entry for `kTestHost`. |
| ValidateBrowsingDataEntries( |
| content_settings->allowed_browsing_data_model(), |
| {{kTestHost, |
| isolation_key, |
| {{BrowsingDataModel::StorageType::kSharedDictionary}, |
| /*storage_size=*/0, |
| /*cookie_count=*/0}}}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| SharedDictionaryAccessForNavigationReportedCorrectly) { |
| // Registers a shared dictionary. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), |
| https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html"))); |
| SetDataForType("SharedDictionary", web_contents()); |
| |
| // Navigate to about:blank to clear the browsing data model state. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL("about:blank"))); |
| // Validate that the allowed browsing data model is empty. |
| ValidateBrowsingDataEntries( |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()) |
| ->allowed_browsing_data_model(), |
| {}); |
| |
| // Need this polling because the shared dictionary is used only if the |
| // metadata database has been read when sending the HTTP request. |
| int retry = 0; |
| while (true) { |
| const std::string kExpectedResult = |
| "This is compressed test data using a test dictionary"; |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), |
| https_test_server()->GetURL( |
| kTestHost, |
| base::StringPrintf( |
| "/shared_dictionary/path/compressed.data?retry=%d", ++retry)))); |
| const std::string innerText = |
| EvalJs(web_contents()->GetPrimaryMainFrame(), "document.body.innerText") |
| .ExtractString(); |
| if (innerText == kExpectedResult) { |
| break; |
| } |
| } |
| |
| auto* content_settings = |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()); |
| WaitForModelUpdate(content_settings->allowed_browsing_data_model(), 1); |
| |
| // Validate that the allowed browsing data model is populated with |
| // SharedDictionary entry for `kTestHost`. |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| auto isolation_key = net::SharedDictionaryIsolationKey( |
| testOrigin, net::SchemefulSite(testOrigin)); |
| ValidateBrowsingDataEntries( |
| content_settings->allowed_browsing_data_model(), |
| {{kTestHost, |
| isolation_key, |
| {{BrowsingDataModel::StorageType::kSharedDictionary}, |
| /*storage_size=*/0, |
| /*cookie_count=*/0}}}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F( |
| BrowsingDataModelBrowserTest, |
| SharedDictionaryAccessForIframeNavigationReportedCorrectly) { |
| // Registers a shared dictionary. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), |
| https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html"))); |
| SetDataForType("SharedDictionary", web_contents()); |
| |
| // Navigate to about:blank to clear the browsing data model state. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL("about:blank"))); |
| // Validate that the allowed browsing data model is empty. |
| ValidateBrowsingDataEntries( |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()) |
| ->allowed_browsing_data_model(), |
| {}); |
| // Return to the test page. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), |
| https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html"))); |
| // Validate that the allowed browsing data model is empty. |
| ValidateBrowsingDataEntries( |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()) |
| ->allowed_browsing_data_model(), |
| {}); |
| |
| // Need this polling because the shared dictionary is used only if the |
| // metadata database has been read when sending the HTTP request. |
| while (true) { |
| const std::string kExpectedResult = |
| "This is compressed test data using a test dictionary"; |
| const std::string iframeInnerText = |
| EvalJs(web_contents()->GetPrimaryMainFrame(), R"( |
| (async () => { |
| const iframe = document.createElement('iframe'); |
| iframe.src = '/shared_dictionary/path/compressed.data'; |
| const promise = |
| new Promise(resolve => { iframe.addEventListener('load', resolve); }); |
| document.body.appendChild(iframe); |
| await promise; |
| return iframe.contentDocument.body.innerText; |
| })())") |
| .ExtractString(); |
| if (iframeInnerText == kExpectedResult) { |
| break; |
| } |
| } |
| |
| auto* content_settings = |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()); |
| WaitForModelUpdate(content_settings->allowed_browsing_data_model(), 1); |
| |
| // Validate that the allowed browsing data model is populated with |
| // SharedDictionary entry for `kTestHost`. |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| auto isolation_key = net::SharedDictionaryIsolationKey( |
| testOrigin, net::SchemefulSite(testOrigin)); |
| ValidateBrowsingDataEntries( |
| content_settings->allowed_browsing_data_model(), |
| {{kTestHost, |
| isolation_key, |
| {{BrowsingDataModel::StorageType::kSharedDictionary}, |
| /*storage_size=*/0, |
| /*cookie_count=*/0}}}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, CookiesHandledCorrectly) { |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), |
| https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html"))); |
| // Ensure that there isn't any data fetched. |
| std::unique_ptr<BrowsingDataModel> browsing_data_model = |
| BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| ASSERT_EQ(browsing_data_model->size(), 0u); |
| |
| SetDataForType("Cookie", web_contents()); |
| |
| // Ensure that cookie is fetched. |
| browsing_data_model = BuildBrowsingDataModel(); |
| |
| // Validate that cookie is fetched to browsing data model. |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| std::unique_ptr<net::CanonicalCookie> data_key = |
| net::CanonicalCookie::CreateForTesting(testOrigin.GetURL(), |
| "foo=bar; Path=/browsing_data", |
| base::Time::Now()); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), |
| {{kTestHost, |
| *(data_key.get()), |
| {{BrowsingDataModel::StorageType::kCookie}, |
| /*storage_size=*/0, |
| /*cookie_count=*/1}}}); |
| ASSERT_EQ(browsing_data_model->size(), 1u); |
| |
| // Remove cookie entry. |
| RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost); |
| |
| // Rebuild Browsing Data Model and verify entries are empty. |
| browsing_data_model = BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| ASSERT_EQ(browsing_data_model->size(), 0u); |
| ASSERT_FALSE(HasDataForType("Cookie", web_contents())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| CookiesAccessReportedCorrectly) { |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), |
| https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html"))); |
| |
| auto* content_settings = |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()); |
| |
| // Validate that the allowed browsing data model is empty. |
| auto* allowed_browsing_data_model = |
| content_settings->allowed_browsing_data_model(); |
| ValidateBrowsingDataEntries(allowed_browsing_data_model, {}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 0u); |
| |
| SetDataForType("Cookie", web_contents()); |
| WaitForModelUpdate(allowed_browsing_data_model, /*expected_size=*/1); |
| |
| // Validate that cookie is fetched to browsing data model. |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| std::unique_ptr<net::CanonicalCookie> data_key = |
| net::CanonicalCookie::CreateForTesting(testOrigin.GetURL(), |
| "foo=bar; Path=/browsing_data", |
| base::Time::Now()); |
| ValidateBrowsingDataEntries(allowed_browsing_data_model, |
| {{kTestHost, |
| *(data_key.get()), |
| {{BrowsingDataModel::StorageType::kCookie}, |
| /*storage_size=*/0, |
| /*cookie_count=*/1}}}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 1u); |
| |
| // Remove cookie entry. |
| RemoveBrowsingDataForDataOwner(allowed_browsing_data_model, kTestHost); |
| // Validate that the allowed browsing data model is empty. |
| ValidateBrowsingDataEntries(allowed_browsing_data_model, {}); |
| ASSERT_EQ(allowed_browsing_data_model->size(), 0u); |
| ASSERT_FALSE(HasDataForType("Cookie", web_contents())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| FederatedIdentityHandledCorrectly) { |
| // Setup identity provider (IDP). |
| idp_server()->SetConfigResponseDetails(BuildValidConfigDetails()); |
| |
| // Navigate to test page. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), https_test_server()->GetURL(kTestHost, "/title1.html"))); |
| |
| // Validate that the browsing data model built from disk is empty. |
| std::unique_ptr<BrowsingDataModel> browsing_data_model = |
| BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| ASSERT_EQ(browsing_data_model->size(), 0u); |
| |
| // Run FedCM and grant sharing permission by selecting an account. |
| RunFedCm(web_contents(), https_test_server()); |
| |
| // Waiting for the browsing data model to be populated, otherwise the test is |
| // flaky. |
| do { |
| browsing_data_model = BuildBrowsingDataModel(); |
| base::PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
| } while (browsing_data_model->size() != 1); |
| |
| // Validate that an entry for FederatedIdentity is added to the browsing data |
| // model. |
| url::Origin testRpOrigin = https_test_server()->GetOrigin(kTestHost); |
| url::Origin testIdpOrigin = |
| url::Origin::Create(GURL(GetIdpConfigUrl(https_test_server()))); |
| webid::FederatedIdentityDataModel::DataKey data_key{ |
| testRpOrigin, testRpOrigin, testIdpOrigin, kAccountId}; |
| ValidateBrowsingDataEntries( |
| browsing_data_model.get(), |
| {{kTestHost, |
| data_key, |
| {{static_cast<BrowsingDataModel::StorageType>( |
| ChromeBrowsingDataModelDelegate::StorageType::kFederatedIdentity)}, |
| /*storage_size=*/100, |
| /*cookie_count=*/0}}}); |
| |
| // Clear FederatedIdentity in browsing data model using relying party embedder |
| // (data owner). |
| RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost); |
| |
| // Rebuild browsing data model and verify entries are empty. |
| browsing_data_model = BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| } |
| |
| #if BUILDFLAG(ENABLE_LIBRARY_CDMS) |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| CdmStorageHandledCorrectly) { |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), |
| https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html"))); |
| // Ensure that there isn't any data fetched. |
| std::unique_ptr<BrowsingDataModel> browsing_data_model = |
| BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| ASSERT_EQ(browsing_data_model->size(), 0u); |
| |
| SetDataForType("MediaLicense", web_contents()); |
| browsing_data_model = BuildBrowsingDataModel(); |
| |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| auto storage_key = blink::StorageKey::CreateFirstParty(testOrigin); |
| |
| ValidateBrowsingDataEntries(browsing_data_model.get(), |
| {{kTestHost, |
| storage_key, |
| {{BrowsingDataModel::StorageType::kCdmStorage}, |
| /*storage_size=*/112, |
| /*cookie_count=*/0}}}); |
| |
| RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost); |
| |
| // Rebuild browsing data model and verify entries are empty. |
| browsing_data_model = BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| } |
| #endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) |
| |
| #if BUILDFLAG(ENABLE_DEVICE_BOUND_SESSIONS) |
| IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, |
| DeviceBoundSessionsStoredCorrectly) { |
| // Check that no device bound sessions exist at the beginning of the test. |
| std::unique_ptr<BrowsingDataModel> browsing_data_model = |
| BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| ASSERT_EQ(browsing_data_model->size(), 0u); |
| |
| // Register a session |
| base::RunLoop run_loop; |
| TestDeviceBoundSessionAccessObserver observer(web_contents(), |
| run_loop.QuitClosure()); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), https_test_server()->GetURL(kTestHost, "/dbsc_required"))); |
| run_loop.Run(); |
| |
| // Validate the device bound session and the cookie it protects are added |
| url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost); |
| std::unique_ptr<net::CanonicalCookie> cookie_data_key = |
| net::CanonicalCookie::CreateForTesting(testOrigin.GetURL(), |
| "auth_cookie=abcdef0123; Path=/", |
| base::Time::Now()); |
| net::device_bound_sessions::SessionKey session_data_key( |
| net::SchemefulSite(https_test_server()->GetURL(kTestHost, "/")), |
| net::device_bound_sessions::SessionKey::Id("session_id")); |
| |
| browsing_data_model = BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries( |
| browsing_data_model.get(), |
| {{kTestHost, |
| session_data_key, |
| {{BrowsingDataModel::StorageType::kDeviceBoundSession}, |
| /*storage_size=*/100, |
| /*cookie_count=*/0}}, |
| |
| {kTestHost, |
| *(cookie_data_key.get()), |
| {{BrowsingDataModel::StorageType::kCookie}, |
| /*storage_size=*/0, |
| /*cookie_count=*/1}}}); |
| |
| // Remove device bound session |
| RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost); |
| |
| // Rebuild Browsing Data Model and verify entries are empty. |
| browsing_data_model = BuildBrowsingDataModel(); |
| ValidateBrowsingDataEntries(browsing_data_model.get(), {}); |
| } |
| #endif // BUILDFLAG(ENABLE_DEVICE_BOUND_SESSIONS) |