Skip to content

Commit

Permalink
Add Storage Access API service skeleton
Browse files Browse the repository at this point in the history
This creates a new service and a corresponding tab helper which
observes non-main-frame user interactions. The service currently does
not do anything, but will eventually renew Storage Access API
permission grants at most once per day per grant per profile.

Bug: 1450356
Change-Id: I7beebaf5b977d0c7fc5853b8f8f29028263402e5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4574776
Reviewed-by: Shuran Huang <shuuran@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Commit-Queue: Chris Fredrickson <cfredric@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1153513}
  • Loading branch information
cfredric authored and Chromium LUCI CQ committed Jun 5, 2023
1 parent 2e626a0 commit b1a163a
Show file tree
Hide file tree
Showing 16 changed files with 479 additions and 5 deletions.
4 changes: 2 additions & 2 deletions chrome/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -1896,7 +1896,7 @@ static_library("browser") {
# TODO(crbug.com/1335199): break this dep when favicon is in its own target
"//chrome/browser/share",
"//chrome/browser/ui",
"//chrome/browser/storage_access_api:permissions",
"//chrome/browser/storage_access_api",
"//chrome/browser/top_level_storage_access_api:permissions",
"//chrome/browser/safe_browsing",
"//chrome/browser/safe_browsing:verdict_cache_manager_factory",
Expand Down Expand Up @@ -2018,7 +2018,7 @@ static_library("browser") {
"//chrome/browser/sharing:buildflags",
"//chrome/browser/sharing/proto",
"//chrome/browser/signin:identity_manager_provider",
"//chrome/browser/storage_access_api:permissions",
"//chrome/browser/storage_access_api",
"//chrome/browser/thumbnail",
"//chrome/browser/top_level_storage_access_api:permissions",
"//chrome/browser/touch_to_fill",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@
#include "chrome/browser/ssl/https_first_mode_settings_tracker.h"
#include "chrome/browser/ssl/sct_reporting_service_factory.h"
#include "chrome/browser/ssl/stateful_ssl_host_state_delegate_factory.h"
#include "chrome/browser/storage_access_api/storage_access_api_service_factory.h"
#include "chrome/browser/subresource_filter/subresource_filter_profile_context_factory.h"
#include "chrome/browser/sync/model_type_store_service_factory.h"
#include "chrome/browser/sync/sync_service_factory.h"
Expand Down Expand Up @@ -994,6 +995,7 @@ void ChromeBrowserMainExtraPartsProfiles::
#if BUILDFLAG(ENABLE_SPELLCHECK)
SpellcheckServiceFactory::GetInstance();
#endif
StorageAccessAPIServiceFactory::GetInstance();
#if !BUILDFLAG(IS_ANDROID)
StorageNotificationServiceFactory::GetInstance();
#endif
Expand Down
9 changes: 8 additions & 1 deletion chrome/browser/storage_access_api/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

source_set("permissions") {
source_set("storage_access_api") {
sources = [
"storage_access_api_service.h",
"storage_access_api_service_factory.cc",
"storage_access_api_service_factory.h",
"storage_access_api_service_impl.cc",
"storage_access_api_service_impl.h",
"storage_access_api_tab_helper.cc",
"storage_access_api_tab_helper.h",
"storage_access_grant_permission_context.cc",
"storage_access_grant_permission_context.h",
]
Expand Down
25 changes: 25 additions & 0 deletions chrome/browser/storage_access_api/storage_access_api_service.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// 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_STORAGE_ACCESS_API_STORAGE_ACCESS_API_SERVICE_H_
#define CHROME_BROWSER_STORAGE_ACCESS_API_STORAGE_ACCESS_API_SERVICE_H_

namespace url {
class Origin;
} // namespace url

// An abstract class providing the interface for the Storage Access API service.
// This class exists so that a different implementation may be used in tests.
class StorageAccessAPIService {
public:
// May renew Storage Access API permission grants associated with the given
// origins.
//
// The implementations of this method may apply rate limiting and caching in
// order to avoid unnecessary disk writes.
virtual void RenewPermissionGrant(const url::Origin& embedded_origin,
const url::Origin& top_frame_origin) = 0;
};

#endif // CHROME_BROWSER_STORAGE_ACCESS_API_STORAGE_ACCESS_API_SERVICE_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// 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/storage_access_api/storage_access_api_service_factory.h"

#include "base/no_destructor.h"
#include "chrome/browser/profiles/profile_keyed_service_factory.h"
#include "chrome/browser/profiles/profile_selections.h"
#include "chrome/browser/storage_access_api/storage_access_api_service_impl.h"

// static
StorageAccessAPIServiceImpl*
StorageAccessAPIServiceFactory::GetForBrowserContext(
content::BrowserContext* context) {
return static_cast<StorageAccessAPIServiceImpl*>(
StorageAccessAPIServiceFactory::GetInstance()
->GetServiceForBrowserContext(context, /*create=*/true));
}

// static
StorageAccessAPIServiceFactory* StorageAccessAPIServiceFactory::GetInstance() {
static base::NoDestructor<StorageAccessAPIServiceFactory> instance;
return instance.get();
}

StorageAccessAPIServiceFactory::StorageAccessAPIServiceFactory()
: ProfileKeyedServiceFactory(
"StorageAccessAPIService",
ProfileSelections::Builder()
.WithRegular(ProfileSelection::kOwnInstance)
.WithGuest(ProfileSelection::kOwnInstance)
.WithSystem(ProfileSelection::kNone)
.Build()) {}

StorageAccessAPIServiceFactory::~StorageAccessAPIServiceFactory() = default;

std::unique_ptr<KeyedService>
StorageAccessAPIServiceFactory::BuildServiceInstanceForBrowserContext(
content::BrowserContext* context) const {
return std::make_unique<StorageAccessAPIServiceImpl>(context);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 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_STORAGE_ACCESS_API_STORAGE_ACCESS_API_SERVICE_FACTORY_H_
#define CHROME_BROWSER_STORAGE_ACCESS_API_STORAGE_ACCESS_API_SERVICE_FACTORY_H_

#include "base/no_destructor.h"
#include "chrome/browser/profiles/profile_keyed_service_factory.h"

namespace content {
class BrowserContext;
} // namespace content

class StorageAccessAPIServiceImpl;

// Singleton that owns StorageAccessAPIServiceImpl objects and associates them
// with corresponding Profiles.
//
// Listens for each Profile's destruction notification and cleans up the
// associated StorageAccessAPIServiceImpl.
class StorageAccessAPIServiceFactory : public ProfileKeyedServiceFactory {
public:
StorageAccessAPIServiceFactory(const StorageAccessAPIServiceFactory&) =
delete;
StorageAccessAPIServiceFactory& operator=(
const StorageAccessAPIServiceFactory&) = delete;

static StorageAccessAPIServiceImpl* GetForBrowserContext(
content::BrowserContext* context);

static StorageAccessAPIServiceFactory* GetInstance();

private:
friend base::NoDestructor<StorageAccessAPIServiceFactory>;

StorageAccessAPIServiceFactory();
~StorageAccessAPIServiceFactory() override;

// BrowserContextKeyedServiceFactory:
std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
content::BrowserContext* context) const override;
};

#endif // CHROME_BROWSER_STORAGE_ACCESS_API_STORAGE_ACCESS_API_SERVICE_FACTORY_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 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/storage_access_api/storage_access_api_service_factory.h"

#include "base/memory/raw_ptr.h"
#include "chrome/browser/storage_access_api/storage_access_api_service_impl.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"

class StorageAccessAPIServiceFactoryTest : public testing::Test {
public:
StorageAccessAPIServiceFactoryTest() = default;

void SetUp() override {
ASSERT_TRUE(profile_manager_.SetUp());
profile_ = profile_manager_.CreateTestingProfile("Profile");
}

void TearDown() override { profile_manager_.DeleteAllTestingProfiles(); }

TestingProfile* profile() { return profile_; }

private:
content::BrowserTaskEnvironment env_;
TestingProfileManager profile_manager_ =
TestingProfileManager(TestingBrowserProcess::GetGlobal());
raw_ptr<TestingProfile> profile_ = nullptr;
};

TEST_F(StorageAccessAPIServiceFactoryTest, RegularProfile_ServiceCreated) {
EXPECT_NE(nullptr,
StorageAccessAPIServiceFactory::GetForBrowserContext(profile()));
}

TEST_F(StorageAccessAPIServiceFactoryTest, OffTheRecordProfile_OwnInstance) {
StorageAccessAPIServiceImpl* original_service =
StorageAccessAPIServiceFactory::GetForBrowserContext(
profile()->GetOriginalProfile());

ASSERT_NE(nullptr, original_service);

auto otr_profile_id = Profile::OTRProfileID::CreateUniqueForTesting();
auto* otr_service = StorageAccessAPIServiceFactory::GetForBrowserContext(
profile()->GetOffTheRecordProfile(otr_profile_id,
/*create_if_needed=*/true));

EXPECT_NE(nullptr, otr_service);
EXPECT_NE(original_service, otr_service);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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 <utility>

#include "chrome/browser/storage_access_api/storage_access_api_service_impl.h"

StorageAccessAPIServiceImpl::StorageAccessAPIServiceImpl(
content::BrowserContext* browser_context) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(browser_context);
}

StorageAccessAPIServiceImpl::~StorageAccessAPIServiceImpl() = default;

void StorageAccessAPIServiceImpl::RenewPermissionGrant(
const url::Origin& embedded_origin,
const url::Origin& top_frame_origin) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

// TODO(https://crbug.com/1450356): implement grant renewal.
}

void StorageAccessAPIServiceImpl::Shutdown() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// 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_STORAGE_ACCESS_API_STORAGE_ACCESS_API_SERVICE_IMPL_H_
#define CHROME_BROWSER_STORAGE_ACCESS_API_STORAGE_ACCESS_API_SERVICE_IMPL_H_

#include "base/sequence_checker.h"
#include "chrome/browser/storage_access_api/storage_access_api_service.h"
#include "components/keyed_service/core/keyed_service.h"

namespace content {
class BrowserContext;
} // namespace content

namespace url {
class Origin;
} // namespace url

// A profile keyed service for Storage Access API state.
//
// This service always exists for a Profile, regardless of whether the Storage
// Access API feature is enabled.
class StorageAccessAPIServiceImpl : public StorageAccessAPIService,
public KeyedService {
public:
explicit StorageAccessAPIServiceImpl(content::BrowserContext* context);
StorageAccessAPIServiceImpl(const StorageAccessAPIServiceImpl&) = delete;
StorageAccessAPIServiceImpl& operator=(const StorageAccessAPIServiceImpl&) =
delete;
~StorageAccessAPIServiceImpl() override;

// StorageAccessAPIService:
void RenewPermissionGrant(const url::Origin& embedded_origin,
const url::Origin& top_frame_origin) override;

// KeyedService:
void Shutdown() override;

private:
SEQUENCE_CHECKER(sequence_checker_);
};

#endif // CHROME_BROWSER_STORAGE_ACCESS_API_STORAGE_ACCESS_API_SERVICE_IMPL_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// 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/storage_access_api/storage_access_api_service_impl.h"

#include "base/memory/raw_ptr.h"
#include "chrome/browser/storage_access_api/storage_access_api_service_factory.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

class StorageAccessAPIServiceImplTest : public testing::Test {
public:
StorageAccessAPIServiceImplTest() = default;

void SetUp() override {
profile_manager_ = std::make_unique<TestingProfileManager>(
TestingBrowserProcess::GetGlobal());
ASSERT_TRUE(profile_manager_->SetUp());
profile_ = profile_manager_->CreateTestingProfile("TestProfile");
service_ = StorageAccessAPIServiceFactory::GetForBrowserContext(profile_);
ASSERT_NE(service_, nullptr);
}

void TearDown() override {
DCHECK(service_);
// Even though we reassign this in SetUp, service may be persisted between
// tests if the factory has already created a service for the testing
// profile being used.
profile_manager_->DeleteAllTestingProfiles();
profile_manager_.reset();
}

content::BrowserTaskEnvironment& env() { return env_; }

protected:
Profile* profile() { return profile_; }
StorageAccessAPIServiceImpl* service() { return service_; }

private:
content::BrowserTaskEnvironment env_;
std::unique_ptr<TestingProfileManager> profile_manager_;
raw_ptr<Profile> profile_;
raw_ptr<StorageAccessAPIServiceImpl> service_;
};

TEST_F(StorageAccessAPIServiceImplTest, RenewPermissionGrant) {
StorageAccessAPIServiceImpl* service =
StorageAccessAPIServiceFactory::GetForBrowserContext(profile());

ASSERT_NE(nullptr, service);

// TODO(https://crbug.com/1450356): test grant renewal.
}
40 changes: 40 additions & 0 deletions chrome/browser/storage_access_api/storage_access_api_tab_helper.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// 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/storage_access_api/storage_access_api_tab_helper.h"

#include "chrome/browser/storage_access_api/storage_access_api_service.h"
#include "chrome/browser/storage_access_api/storage_access_api_service_factory.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"

StorageAccessAPITabHelper::~StorageAccessAPITabHelper() = default;

void StorageAccessAPITabHelper::FrameReceivedUserActivation(
content::RenderFrameHost* rfh) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(service_);

if (rfh->IsInPrimaryMainFrame()) {
// No need to do anything in a main frame.
return;
}

service_->RenewPermissionGrant(
rfh->GetLastCommittedOrigin(),
rfh->GetParentOrOuterDocument()->GetLastCommittedOrigin());
}

StorageAccessAPITabHelper::StorageAccessAPITabHelper(
content::WebContents* web_contents,
StorageAccessAPIService* service)
: content::WebContentsObserver(web_contents),
content::WebContentsUserData<StorageAccessAPITabHelper>(*web_contents),
service_(service) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(service_);
}

WEB_CONTENTS_USER_DATA_KEY_IMPL(StorageAccessAPITabHelper);

0 comments on commit b1a163a

Please sign in to comment.