blob: 60a8e24494576746ddc83ad1ed320358cb6839ca [file] [log] [blame]
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/site_permissions_helper.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_service_test_with_install.h"
#include "chrome/browser/extensions/permissions_updater.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/test_browser_window.h"
#include "components/crx_file/id_util.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/web_contents_tester.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/permissions/permissions_data.h"
namespace extensions {
namespace {
std::unique_ptr<base::ListValue> ToListValue(
const std::vector<std::string>& permissions) {
extensions::ListBuilder builder;
for (const std::string& permission : permissions)
builder.Append(permission);
return builder.Build();
}
} // namespace
using SiteAccess = SitePermissionsHelper::SiteAccess;
using SiteInteraction = SitePermissionsHelper::SiteInteraction;
class SitePermissionsHelperUnitTest : public ExtensionServiceTestWithInstall {
public:
scoped_refptr<const extensions::Extension> InstallExtension(
const std::string& name);
scoped_refptr<const extensions::Extension> InstallExtensionWithPermissions(
const std::string& name,
const std::vector<std::string>& host_permissions,
const std::vector<std::string>& permissions = {});
// Adds a new tab with `url` to the tab strip, and returns the WebContents
// associated with it.
content::WebContents* AddTab(const GURL& url);
Browser* browser();
SitePermissionsHelper* permissions_helper() {
return permissions_helper_.get();
}
// ExtensionServiceTestBase:
void SetUp() override;
void TearDown() override;
private:
// The browser and accompaying window.
std::unique_ptr<Browser> browser_;
std::unique_ptr<TestBrowserWindow> browser_window_;
// Site permissions helper being tested.
std::unique_ptr<SitePermissionsHelper> permissions_helper_;
};
scoped_refptr<const extensions::Extension>
SitePermissionsHelperUnitTest::InstallExtension(const std::string& name) {
return InstallExtensionWithPermissions(name, {}, {});
}
scoped_refptr<const extensions::Extension>
SitePermissionsHelperUnitTest::InstallExtensionWithPermissions(
const std::string& name,
const std::vector<std::string>& host_permissions,
const std::vector<std::string>& permissions) {
auto extension =
extensions::ExtensionBuilder(name)
.SetManifestVersion(3)
.SetManifestKey("host_permissions", ToListValue(host_permissions))
.AddPermissions(permissions)
.SetID(crx_file::id_util::GenerateId(name))
.Build();
service()->AddExtension(extension.get());
return extension;
}
content::WebContents* SitePermissionsHelperUnitTest::AddTab(const GURL& url) {
std::unique_ptr<content::WebContents> web_contents(
content::WebContentsTester::CreateTestWebContents(profile(), nullptr));
content::WebContents* raw_contents = web_contents.get();
browser()->tab_strip_model()->AppendWebContents(std::move(web_contents),
true);
EXPECT_EQ(browser()->tab_strip_model()->GetActiveWebContents(), raw_contents);
content::NavigationSimulator::NavigateAndCommitFromBrowser(raw_contents, url);
EXPECT_EQ(url, raw_contents->GetLastCommittedURL());
return raw_contents;
}
Browser* SitePermissionsHelperUnitTest::browser() {
if (!browser_) {
Browser::CreateParams params(profile(), true);
browser_window_ = std::make_unique<TestBrowserWindow>();
params.window = browser_window_.get();
browser_.reset(Browser::Create(params));
}
return browser_.get();
}
void SitePermissionsHelperUnitTest::SetUp() {
ExtensionServiceTestBase::SetUp();
InitializeEmptyExtensionService();
permissions_helper_ = std::make_unique<SitePermissionsHelper>(profile());
}
void SitePermissionsHelperUnitTest::TearDown() {
// Remove any tabs in the tab strip; else the test crashes.
if (browser_) {
while (!browser_->tab_strip_model()->empty())
browser_->tab_strip_model()->DetachAndDeleteWebContentsAt(0);
}
ExtensionServiceTestBase::TearDown();
}
TEST_F(SitePermissionsHelperUnitTest, SiteAccessAndInteraction_AllUrls) {
auto extension =
InstallExtensionWithPermissions("AllUrls Extension", {"<all_urls>"});
{
// Verify a non-restricted url has "on all sites" site access and "active"
// site interaction when the extension has all urls permission.
const GURL non_restricted_url("http://www.non-restricted-url.com");
auto* web_contents = AddTab(non_restricted_url);
EXPECT_EQ(
permissions_helper()->GetSiteAccess(*extension, non_restricted_url),
SiteAccess::kOnAllSites);
EXPECT_EQ(
permissions_helper()->GetSiteInteraction(*extension, web_contents),
SiteInteraction::kActive);
}
{
// Verify a restricted url has "none" site interaction even when the
// extension has all urls permission
const GURL restricted_url("chrome://extensions");
auto* web_contents = AddTab(restricted_url);
EXPECT_EQ(
permissions_helper()->GetSiteInteraction(*extension, web_contents),
SiteInteraction::kNone);
}
}
TEST_F(SitePermissionsHelperUnitTest, SiteAccessAndInteraction_RequestedUrl) {
const GURL requested_url("http://www.requested.com");
auto extension = InstallExtensionWithPermissions("Requested Extension",
{requested_url.spec()});
{
// Verify a non-restricted url has "on site" site access and "active" site
// interaction by default when the extension requests it.
auto* web_contents = AddTab(requested_url);
EXPECT_EQ(permissions_helper()->GetSiteAccess(*extension, requested_url),
SiteAccess::kOnSite);
EXPECT_EQ(
permissions_helper()->GetSiteInteraction(*extension, web_contents),
SiteInteraction::kActive);
}
{
// Verify a non-restricted url has "none" site interaction when the
// extension does not request it.
const GURL non_requested_url("http://www.non-requested.com");
auto* web_contents = AddTab(non_requested_url);
EXPECT_EQ(
permissions_helper()->GetSiteInteraction(*extension, web_contents),
SiteInteraction::kNone);
}
}
TEST_F(SitePermissionsHelperUnitTest, SiteAccessAndInteraction_ActiveTab) {
auto extension = InstallExtensionWithPermissions(
"ActiveTab Extension",
/*host_permissions=*/{}, /*permissions=*/{"activeTab"});
{
// Verify a non-restricted url has "on click" site access and "pending" site
// interaction when the extension only has active tab permission.
const GURL non_restricted_url("http://www.non-restricted.com");
auto* web_contents = AddTab(non_restricted_url);
EXPECT_EQ(
permissions_helper()->GetSiteAccess(*extension, non_restricted_url),
SiteAccess::kOnClick);
EXPECT_EQ(
permissions_helper()->GetSiteInteraction(*extension, web_contents),
SiteInteraction::kPending);
}
{
// Verify a restricted url has "none" site interaction even if the extension
// has active tab permission.
const GURL restricted_url("chrome://extensions");
auto* web_contents = AddTab(restricted_url);
EXPECT_EQ(
permissions_helper()->GetSiteInteraction(*extension, web_contents),
SiteInteraction::kNone);
}
}
TEST_F(SitePermissionsHelperUnitTest,
SiteAccessAndInteraction_ActiveTabAndRequestedUrl) {
const GURL requested_url("http://www.requested.com");
auto extension = InstallExtensionWithPermissions(
"ActiveTab Extension",
/*host_permissions=*/{requested_url.spec()},
/*permissions=*/{"activeTab"});
{
// Verify a non-restricted url has "on site" site access and "active" site
// interaction by default when the extension requests it, regardless if the
// extension also has active tab permission.
auto* web_contents = AddTab(requested_url);
EXPECT_EQ(permissions_helper()->GetSiteAccess(*extension, requested_url),
SiteAccess::kOnSite);
EXPECT_EQ(
permissions_helper()->GetSiteInteraction(*extension, web_contents),
SiteInteraction::kActive);
}
{
// Verify a non-restricted url has "on click" site access and "pending"
// site interaction when the extension does not request it but has active
// tab permission.
const GURL non_requested_url("http://www.non-requested.com");
auto* web_contents = AddTab(non_requested_url);
EXPECT_EQ(
permissions_helper()->GetSiteAccess(*extension, non_requested_url),
SiteAccess::kOnClick);
EXPECT_EQ(
permissions_helper()->GetSiteInteraction(*extension, web_contents),
SiteInteraction::kPending);
}
}
TEST_F(SitePermissionsHelperUnitTest,
SiteAccessAndInteraction_NoHostPermissions) {
auto extension = InstallExtension("Requested Extension");
// Verify any url has "none" site interaction when the extension has no host
// permissions.
const GURL url("http://www.example.com");
auto* web_contents = AddTab(url);
EXPECT_EQ(permissions_helper()->GetSiteInteraction(*extension, web_contents),
SiteInteraction::kNone);
}
TEST_F(SitePermissionsHelperUnitTest, CanSelectSiteAccess_AllUrls) {
auto extension =
InstallExtensionWithPermissions("AllUrls Extension", {"<all_urls>"});
// Verify "on click", "on site" and "on all sites" site access can be selected
// for a non-restricted url.
const GURL url("http://www.example.com");
EXPECT_TRUE(permissions_helper()->CanSelectSiteAccess(*extension, url,
SiteAccess::kOnClick));
EXPECT_TRUE(permissions_helper()->CanSelectSiteAccess(*extension, url,
SiteAccess::kOnSite));
EXPECT_TRUE(permissions_helper()->CanSelectSiteAccess(
*extension, url, SiteAccess::kOnAllSites));
// Verify "on click", "on site" and "on all sites" cannot be selected for a
// restricted url.
const GURL chrome_url("chrome://settings");
EXPECT_FALSE(permissions_helper()->CanSelectSiteAccess(*extension, chrome_url,
SiteAccess::kOnClick));
EXPECT_FALSE(permissions_helper()->CanSelectSiteAccess(*extension, chrome_url,
SiteAccess::kOnSite));
EXPECT_FALSE(permissions_helper()->CanSelectSiteAccess(
*extension, chrome_url, SiteAccess::kOnAllSites));
}
TEST_F(SitePermissionsHelperUnitTest, CanSelectSiteAccess_SpecificUrl) {
const GURL url_a("http://www.a.com");
auto extension =
InstallExtensionWithPermissions("A Extension", {url_a.spec()});
// Verify "on click" and "on site" can be selected for the specific url, but
// "on all sites" cannot be selected.
EXPECT_TRUE(permissions_helper()->CanSelectSiteAccess(*extension, url_a,
SiteAccess::kOnClick));
EXPECT_TRUE(permissions_helper()->CanSelectSiteAccess(*extension, url_a,
SiteAccess::kOnSite));
EXPECT_FALSE(permissions_helper()->CanSelectSiteAccess(
*extension, url_a, SiteAccess::kOnAllSites));
// Verify "on click", "on site" and "on all sites" cannot be selected for any
// other url.
const GURL url_b("http://www.b.com");
EXPECT_FALSE(permissions_helper()->CanSelectSiteAccess(*extension, url_b,
SiteAccess::kOnClick));
EXPECT_FALSE(permissions_helper()->CanSelectSiteAccess(*extension, url_b,
SiteAccess::kOnSite));
EXPECT_FALSE(permissions_helper()->CanSelectSiteAccess(
*extension, url_b, SiteAccess::kOnAllSites));
}
TEST_F(SitePermissionsHelperUnitTest, CanSelectSiteAccess_NoHostPermissions) {
auto extension = InstallExtension("Extension");
// Verify "on click", "on site" and "on all sites" cannot be selected for any
// url.
const GURL url("http://www.example.com");
EXPECT_FALSE(permissions_helper()->CanSelectSiteAccess(*extension, url,
SiteAccess::kOnClick));
EXPECT_FALSE(permissions_helper()->CanSelectSiteAccess(*extension, url,
SiteAccess::kOnSite));
EXPECT_FALSE(permissions_helper()->CanSelectSiteAccess(
*extension, url, SiteAccess::kOnAllSites));
}
TEST_F(SitePermissionsHelperUnitTest, CanSelectSiteAccess_ActiveTab) {
auto extension = InstallExtensionWithPermissions(
"ActiveTab Extension",
/*host_permissions=*/{}, /*permissions=*/{"activeTab"});
// Verify "on click" can be selected for the specific url, but "on site" and
// "on all sites" cannot be selected.
const GURL url("http://www.example.com");
EXPECT_TRUE(permissions_helper()->CanSelectSiteAccess(*extension, url,
SiteAccess::kOnClick));
EXPECT_FALSE(permissions_helper()->CanSelectSiteAccess(*extension, url,
SiteAccess::kOnSite));
EXPECT_FALSE(permissions_helper()->CanSelectSiteAccess(
*extension, url, SiteAccess::kOnAllSites));
}
} // namespace extensions