| // Copyright 2016 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "extensions/browser/api/web_request/web_request_permissions.h" |
| |
| #include "base/memory/scoped_refptr.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "components/safe_browsing/core/common/features.h" |
| #include "components/safe_browsing/core/common/hashprefix_realtime/hash_realtime_utils.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "extensions/browser/api/extensions_api_client.h" |
| #include "extensions/browser/api/web_request/permission_helper.h" |
| #include "extensions/browser/api/web_request/web_request_info.h" |
| #include "extensions/browser/api/web_request/web_request_resource_type.h" |
| #include "extensions/browser/extension_registry.h" |
| #include "extensions/browser/extensions_test.h" |
| #include "extensions/browser/process_map.h" |
| #include "extensions/common/constants.h" |
| #include "extensions/common/extension.h" |
| #include "extensions/common/extension_builder.h" |
| #include "extensions/common/permissions/permission_set.h" |
| #include "extensions/common/permissions/permissions_data.h" |
| #include "extensions/common/url_pattern.h" |
| #include "extensions/common/url_pattern_set.h" |
| #include "services/network/public/mojom/fetch_api.mojom-shared.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| #include "url/origin.h" |
| |
| namespace extensions { |
| |
| using ExtensionWebRequestPermissionsTest = ExtensionsTest; |
| |
| constexpr char kTestRelayUrl[] = "https://ohttp.endpoint.test/"; |
| |
| class ExtensionWebRequestPermissionsWithHashRealTimeDependenceTest |
| : public ExtensionsTest, |
| public testing::WithParamInterface<bool> { |
| public: |
| void SetUp() override { |
| ExtensionsTest::SetUp(); |
| if (GetParam()) { |
| feature_list_.InitWithFeaturesAndParameters( |
| /*enabled_features=*/ |
| {{safe_browsing::kHashPrefixRealTimeLookups, |
| {{"SafeBrowsingHashPrefixRealTimeLookupsRelayUrl", |
| kTestRelayUrl}}}}, |
| /*disabled_features=*/{}); |
| } else { |
| feature_list_.InitWithFeatures( |
| /*enabled_features=*/{}, |
| /*disabled_features=*/{safe_browsing::kHashPrefixRealTimeLookups}); |
| } |
| } |
| |
| private: |
| safe_browsing::hash_realtime_utils::GoogleChromeBrandingPretenderForTesting |
| apply_branding_; |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| ExtensionWebRequestPermissionsWithHashRealTimeDependenceTest, |
| testing::Bool()); |
| |
| TEST_P(ExtensionWebRequestPermissionsWithHashRealTimeDependenceTest, |
| TestHideRequestForURL) { |
| enum HideRequestMask { |
| HIDE_NONE = 0, |
| HIDE_RENDERER_REQUEST = 1, |
| HIDE_SUB_FRAME_NAVIGATION = 2, |
| HIDE_MAIN_FRAME_NAVIGATION = 4, |
| HIDE_BROWSER_SUB_RESOURCE_REQUEST = 8, |
| HIDE_ALL = HIDE_RENDERER_REQUEST | HIDE_SUB_FRAME_NAVIGATION | |
| HIDE_MAIN_FRAME_NAVIGATION | HIDE_BROWSER_SUB_RESOURCE_REQUEST, |
| }; |
| |
| ExtensionsAPIClient api_client; |
| auto* permission_helper = PermissionHelper::Get(browser_context()); |
| |
| struct TestCase { |
| const char* url; |
| int expected_hide_request_mask; |
| }; |
| std::vector<TestCase> cases = { |
| {"https://www.google.com", HIDE_BROWSER_SUB_RESOURCE_REQUEST}, |
| {"http://www.example.com", HIDE_BROWSER_SUB_RESOURCE_REQUEST}, |
| {"https://www.example.com", HIDE_BROWSER_SUB_RESOURCE_REQUEST}, |
| {"https://clients.google.com", |
| HIDE_BROWSER_SUB_RESOURCE_REQUEST | HIDE_SUB_FRAME_NAVIGATION}, |
| {"http://clients4.google.com", |
| HIDE_BROWSER_SUB_RESOURCE_REQUEST | HIDE_SUB_FRAME_NAVIGATION}, |
| {"https://clients4.google.com", |
| HIDE_BROWSER_SUB_RESOURCE_REQUEST | HIDE_SUB_FRAME_NAVIGATION}, |
| {"https://clients9999.google.com", |
| HIDE_BROWSER_SUB_RESOURCE_REQUEST | HIDE_SUB_FRAME_NAVIGATION}, |
| {"https://clients9999..google.com", HIDE_BROWSER_SUB_RESOURCE_REQUEST}, |
| {"https://clients9999.example.google.com", |
| HIDE_BROWSER_SUB_RESOURCE_REQUEST}, |
| {"https://clients.google.com.", |
| HIDE_BROWSER_SUB_RESOURCE_REQUEST | HIDE_SUB_FRAME_NAVIGATION}, |
| {"https://.clients.google.com.", |
| HIDE_BROWSER_SUB_RESOURCE_REQUEST | HIDE_SUB_FRAME_NAVIGATION}, |
| {"https://test.clients.google.com", |
| HIDE_SUB_FRAME_NAVIGATION | HIDE_BROWSER_SUB_RESOURCE_REQUEST}, |
| {"http://google.example.com", HIDE_BROWSER_SUB_RESOURCE_REQUEST}, |
| {"http://www.example.com", HIDE_BROWSER_SUB_RESOURCE_REQUEST}, |
| {"https://www.example.com", HIDE_BROWSER_SUB_RESOURCE_REQUEST}, |
| {"https://sb-ssl.google.com", HIDE_ALL}, |
| {"https://sb-ssl.random.google.com", HIDE_BROWSER_SUB_RESOURCE_REQUEST}, |
| {"https://safebrowsing.googleapis.com", HIDE_ALL}, |
| // Unsupported scheme. |
| {"blob:https://safebrowsing.googleapis.com/" |
| "fc3f440b-78ed-469f-8af8-7a1717ff39ae", |
| HIDE_ALL}, |
| {"filesystem:https://safebrowsing.googleapis.com/path", HIDE_ALL}, |
| {"https://safebrowsing.googleapis.com.", HIDE_ALL}, |
| {"https://safebrowsing.googleapis.com/v4", HIDE_ALL}, |
| {"https://safebrowsing.googleapis.com:80/v4", HIDE_ALL}, |
| {"https://safebrowsing.googleapis.com./v4", HIDE_ALL}, |
| {"https://safebrowsing.googleapis.com/v5", HIDE_ALL}, |
| {"https://safebrowsing.google.com/safebrowsing", HIDE_ALL}, |
| {"https://safebrowsing.google.com/safebrowsing/anything", HIDE_ALL}, |
| {"https://safebrowsing.google.com", HIDE_BROWSER_SUB_RESOURCE_REQUEST}, |
| {"https://chrome.google.com", HIDE_BROWSER_SUB_RESOURCE_REQUEST}, |
| {"http://www.google.com/", HIDE_BROWSER_SUB_RESOURCE_REQUEST}, |
| {"https://chrome.google.com/webstore", HIDE_ALL}, |
| {"https://chrome.google.com./webstore", HIDE_ALL}, |
| {"https://chrome.google.com./webstore/", HIDE_ALL}, |
| {"https://chromewebstore.google.com", HIDE_ALL}, |
| {"https://chromewebstore.google.com/", HIDE_ALL}, |
| {"https://chromewebstore.google.com./", HIDE_ALL}, |
| {"https://chromewebstore.google.com:80/", HIDE_ALL}, |
| {"https://chromewebstore.google.com/?query", HIDE_ALL}, |
| // Unsupported scheme. |
| {"blob:https://chrome.google.com/fc3f440b-78ed-469f-8af8-7a1717ff39ae", |
| HIDE_ALL}, |
| // Unsupported scheme. |
| {"chrome://test/", HIDE_ALL}, |
| // Unsupported scheme. |
| {"chrome-untrusted://test/", HIDE_ALL}, |
| {"notregisteredscheme://www.foobar.com", HIDE_ALL}, |
| {"https://chrome.google.com:80/webstore", HIDE_ALL}, |
| {"https://chrome.google.com/webstore?query", HIDE_ALL}, |
| {"http://clients2.google.com/service/update2/crx", HIDE_ALL}, |
| {"https://clients2.google.com/service/update2/crx", HIDE_ALL}, |
| {"https://chrome.google.com/webstore/inlineinstall/detail/" |
| "kcnhkahnjcbndmmehfkdnkjomaanaooo", |
| HIDE_ALL}, |
| {"https://chromewebstore.googleapis.com/v2/items/" |
| "kcnhkahnjcbndmmehfkdnkjomaanaooo:fetchItemSnippet", |
| HIDE_ALL}, |
| }; |
| std::vector<TestCase> additional_cases; |
| if (GetParam()) { |
| additional_cases = { |
| {"https://ohttp.endpoint.test", HIDE_ALL}, |
| {"https://ohttp.endpoint.test/", HIDE_ALL}, |
| {"https://ohttp.endpoint.test/path", HIDE_BROWSER_SUB_RESOURCE_REQUEST}, |
| {"https://endpoint.test/", HIDE_BROWSER_SUB_RESOURCE_REQUEST}}; |
| } else { |
| additional_cases = { |
| {"https://ohttp.endpoint.test/", HIDE_BROWSER_SUB_RESOURCE_REQUEST}}; |
| } |
| cases.insert(cases.end(), additional_cases.begin(), additional_cases.end()); |
| |
| const int kRendererProcessId = 1; |
| const int kBrowserProcessId = -1; |
| |
| // Returns a WebRequestInfoInitParams instance constructed as per the given |
| // parameters. |
| auto create_request_params = [](const GURL& url, |
| WebRequestResourceType web_request_type, |
| int render_process_id) { |
| WebRequestInfoInitParams request; |
| request.url = url; |
| request.render_process_id = render_process_id; |
| request.web_request_type = web_request_type; |
| request.is_navigation_request = |
| web_request_type == WebRequestResourceType::MAIN_FRAME || |
| web_request_type == WebRequestResourceType::SUB_FRAME; |
| return request; |
| }; |
| |
| for (const TestCase& test_case : cases) { |
| SCOPED_TRACE(test_case.url); |
| |
| GURL request_url(test_case.url); |
| ASSERT_TRUE(request_url.is_valid()); |
| |
| { |
| SCOPED_TRACE("Renderer initiated sub-resource request"); |
| WebRequestInfo request(create_request_params( |
| request_url, WebRequestResourceType::OTHER, kRendererProcessId)); |
| bool expect_hidden = |
| test_case.expected_hide_request_mask & HIDE_RENDERER_REQUEST; |
| EXPECT_EQ(expect_hidden, |
| WebRequestPermissions::HideRequest(permission_helper, request)); |
| } |
| |
| { |
| SCOPED_TRACE( |
| "Renderer initiated sub-resource request from " |
| "chrome-untrusted://"); |
| auto request_init_params = create_request_params( |
| request_url, WebRequestResourceType::OTHER, kRendererProcessId); |
| GURL url("chrome-untrusted://test/"); |
| request_init_params.initiator = url::Origin::Create(url); |
| |
| WebRequestInfo request(std::move(request_init_params)); |
| // Always hide requests from chrome-untrusted:// |
| EXPECT_TRUE( |
| WebRequestPermissions::HideRequest(permission_helper, request)); |
| } |
| |
| { |
| SCOPED_TRACE("Browser initiated sub-resource request"); |
| WebRequestInfo request(create_request_params( |
| request_url, WebRequestResourceType::OTHER, kBrowserProcessId)); |
| bool expect_hidden = test_case.expected_hide_request_mask & |
| HIDE_BROWSER_SUB_RESOURCE_REQUEST; |
| EXPECT_EQ(expect_hidden, |
| WebRequestPermissions::HideRequest(permission_helper, request)); |
| } |
| |
| { |
| SCOPED_TRACE("Main-frame navigation"); |
| WebRequestInfo request(create_request_params( |
| request_url, WebRequestResourceType::MAIN_FRAME, kBrowserProcessId)); |
| bool expect_hidden = |
| test_case.expected_hide_request_mask & HIDE_MAIN_FRAME_NAVIGATION; |
| EXPECT_EQ(expect_hidden, |
| WebRequestPermissions::HideRequest(permission_helper, request)); |
| } |
| |
| { |
| SCOPED_TRACE("Sub-frame navigation"); |
| WebRequestInfo request(create_request_params( |
| request_url, WebRequestResourceType::SUB_FRAME, kBrowserProcessId)); |
| bool expect_hidden = |
| test_case.expected_hide_request_mask & HIDE_SUB_FRAME_NAVIGATION; |
| EXPECT_EQ(expect_hidden, |
| WebRequestPermissions::HideRequest(permission_helper, request)); |
| } |
| } |
| |
| // Check protection of requests originating from the frame showing the Chrome |
| // WebStore. Normally this request is not protected: |
| GURL non_sensitive_url("http://www.google.com/test.js"); |
| |
| { |
| WebRequestInfo non_sensitive_request(create_request_params( |
| non_sensitive_url, WebRequestResourceType::SCRIPT, kRendererProcessId)); |
| EXPECT_FALSE(WebRequestPermissions::HideRequest(permission_helper, |
| non_sensitive_request)); |
| } |
| |
| // If the origin is labeled by the WebStoreAppId, it becomes protected. |
| { |
| const int kWebstoreProcessId = 42; |
| ProcessMap::Get(browser_context()) |
| ->Insert(extensions::kWebStoreAppId, kWebstoreProcessId); |
| WebRequestInfo sensitive_request_info(create_request_params( |
| non_sensitive_url, WebRequestResourceType::SCRIPT, kWebstoreProcessId)); |
| EXPECT_TRUE(WebRequestPermissions::HideRequest(permission_helper, |
| sensitive_request_info)); |
| } |
| // If the request is initiated by the new webstore domain it becomes |
| // protected. |
| { |
| auto request_init_params = create_request_params( |
| non_sensitive_url, WebRequestResourceType::SCRIPT, kRendererProcessId); |
| GURL webstore_url("https://chromewebstore.google.com/"); |
| request_init_params.initiator = url::Origin::Create(webstore_url); |
| |
| WebRequestInfo sensitive_request_info(std::move(request_init_params)); |
| EXPECT_TRUE(WebRequestPermissions::HideRequest(permission_helper, |
| sensitive_request_info)); |
| } |
| // Requests initiated in opaque origins with the webstore as a precursor will |
| // also be protected. |
| { |
| auto request_init_params = create_request_params( |
| non_sensitive_url, WebRequestResourceType::SCRIPT, kRendererProcessId); |
| GURL webstore_url("https://chromewebstore.google.com/"); |
| auto opaque_origin = |
| url::Origin::Create(webstore_url).DeriveNewOpaqueOrigin(); |
| EXPECT_TRUE(opaque_origin.opaque()); |
| request_init_params.initiator = std::move(opaque_origin); |
| |
| WebRequestInfo sensitive_request_info(std::move(request_init_params)); |
| EXPECT_TRUE(WebRequestPermissions::HideRequest(permission_helper, |
| sensitive_request_info)); |
| } |
| } |
| |
| // Tests that subresource requests to Web origins initiated from |
| // chrome-untrusted:// pages can't be inspected. |
| TEST_F(ExtensionWebRequestPermissionsTest, |
| CanNotAccessSubresourceRequestsFromChromeUntrustedPage) { |
| ExtensionsAPIClient api_client; |
| auto* permission_helper = PermissionHelper::Get(browser_context()); |
| |
| auto create_sub_resource_request = [](const GURL& url, |
| WebRequestResourceType type) { |
| WebRequestInfoInitParams request; |
| request.url = url; |
| request.render_process_id = 1; |
| request.web_request_type = type; |
| request.initiator = url::Origin::Create(GURL("chrome-untrusted://test/")); |
| |
| return WebRequestInfo(std::move(request)); |
| }; |
| |
| EXPECT_TRUE(WebRequestPermissions::HideRequest( |
| permission_helper, |
| create_sub_resource_request(GURL("https:://example.com/a.jpg"), |
| WebRequestResourceType::IMAGE))); |
| EXPECT_TRUE(WebRequestPermissions::HideRequest( |
| permission_helper, |
| create_sub_resource_request(GURL("https:://example.com/a.mp4"), |
| WebRequestResourceType::MEDIA))); |
| EXPECT_TRUE(WebRequestPermissions::HideRequest( |
| permission_helper, |
| create_sub_resource_request(GURL("https:://example.com/xhr"), |
| WebRequestResourceType::XHR))); |
| EXPECT_TRUE(WebRequestPermissions::HideRequest( |
| permission_helper, |
| create_sub_resource_request(GURL("https:://example.com/a.js"), |
| WebRequestResourceType::SCRIPT))); |
| EXPECT_TRUE(WebRequestPermissions::HideRequest( |
| permission_helper, |
| create_sub_resource_request(GURL("https:://example.com/a.css"), |
| WebRequestResourceType::STYLESHEET))); |
| } |
| |
| // Tests that subframe navigation requests to Web origins initiated from |
| // chrome-untrusted:// pages can't be inspected. |
| TEST_F(ExtensionWebRequestPermissionsTest, |
| CanNotAccessSubframeNavigationRequestsFromChromeUntrustedPage) { |
| ExtensionsAPIClient api_client; |
| auto* permission_helper = PermissionHelper::Get(browser_context()); |
| |
| auto create_sub_frame_navigation_request = [](const GURL& url) { |
| WebRequestInfoInitParams request; |
| request.url = url; |
| request.render_process_id = 1; |
| request.web_request_type = WebRequestResourceType::SUB_FRAME; |
| request.is_navigation_request = true; |
| request.initiator = url::Origin::Create(GURL("chrome-untrusted://test/")); |
| |
| return WebRequestInfo(std::move(request)); |
| }; |
| |
| EXPECT_TRUE(WebRequestPermissions::HideRequest( |
| permission_helper, |
| create_sub_frame_navigation_request(GURL("https:://example.com/")))); |
| } |
| |
| // Tests that main frame navigations to non-WebUI origins initiated from |
| // chrome-untrusted:// pages can be inspected. |
| TEST_F(ExtensionWebRequestPermissionsTest, |
| CanAccessMainFrameNavigationsToWebOriginsFromChromeUntrustedPage) { |
| ExtensionsAPIClient api_client; |
| auto* permission_helper = PermissionHelper::Get(browser_context()); |
| |
| auto create_main_frame_request_info = [](const GURL& url) { |
| WebRequestInfoInitParams request; |
| request.url = url; |
| request.render_process_id = 1; |
| request.web_request_type = WebRequestResourceType::MAIN_FRAME; |
| request.is_navigation_request = true; |
| request.initiator = url::Origin::Create(GURL("chrome-untrusted://test/")); |
| |
| return WebRequestInfo(std::move(request)); |
| }; |
| |
| EXPECT_FALSE(WebRequestPermissions::HideRequest( |
| permission_helper, |
| create_main_frame_request_info(GURL("https://example.com/")))); |
| EXPECT_TRUE(WebRequestPermissions::HideRequest( |
| permission_helper, |
| create_main_frame_request_info(GURL("chrome://version/")))); |
| EXPECT_TRUE(WebRequestPermissions::HideRequest( |
| permission_helper, |
| create_main_frame_request_info(GURL("chrome-untrusted://test2/")))); |
| } |
| |
| TEST_F(ExtensionWebRequestPermissionsTest, |
| CanExtensionAccessURLWithWithheldPermissions) { |
| ExtensionsAPIClient api_client; |
| scoped_refptr<const Extension> extension = |
| ExtensionBuilder("ext").AddHostPermission("<all_urls>").Build(); |
| URLPatternSet all_urls( |
| {URLPattern(Extension::kValidHostPermissionSchemes, "<all_urls>")}); |
| // Simulate withholding the <all_urls> permission. |
| extension->permissions_data()->SetPermissions( |
| std::make_unique<PermissionSet>(), // active permissions. |
| std::make_unique<PermissionSet>( |
| APIPermissionSet(), ManifestPermissionSet(), all_urls.Clone(), |
| URLPatternSet()) /* withheld permissions */); |
| |
| ExtensionRegistry::Get(browser_context())->AddEnabled(extension); |
| |
| auto get_access = [extension, this]( |
| const GURL& url, |
| const std::optional<url::Origin>& initiator, |
| const WebRequestResourceType type) { |
| constexpr int kTabId = 42; |
| constexpr WebRequestPermissions::HostPermissionsCheck kPermissionsCheck = |
| WebRequestPermissions::REQUIRE_HOST_PERMISSION_FOR_URL; |
| return WebRequestPermissions::CanExtensionAccessURL( |
| PermissionHelper::Get(browser_context()), extension->id(), url, kTabId, |
| false /* crosses incognito */, kPermissionsCheck, initiator, type); |
| }; |
| |
| const GURL example_com("https://example.com"); |
| const GURL chromium_org("https://chromium.org"); |
| const url::Origin example_com_origin(url::Origin::Create(example_com)); |
| const url::Origin chromium_org_origin(url::Origin::Create(chromium_org)); |
| |
| GURL urls[] = {example_com, chromium_org}; |
| std::optional<url::Origin> initiators[] = {std::nullopt, example_com_origin, |
| chromium_org_origin}; |
| WebRequestResourceType types[] = {WebRequestResourceType::OTHER, |
| WebRequestResourceType::MAIN_FRAME}; |
| |
| // With all permissions withheld, the result of any request should be |
| // kWithheld. |
| for (const auto& url : urls) { |
| for (const auto& initiator : initiators) { |
| for (const auto& type : types) { |
| EXPECT_EQ(PermissionsData::PageAccess::kWithheld, |
| get_access(url, initiator, type)); |
| } |
| } |
| } |
| |
| // Grant access to chromium.org. |
| URLPatternSet chromium_org_patterns({URLPattern( |
| Extension::kValidHostPermissionSchemes, "https://chromium.org/*")}); |
| extension->permissions_data()->SetPermissions( |
| std::make_unique<PermissionSet>( |
| APIPermissionSet(), ManifestPermissionSet(), |
| std::move(chromium_org_patterns), URLPatternSet()), |
| std::make_unique<PermissionSet>(APIPermissionSet(), |
| ManifestPermissionSet(), all_urls.Clone(), |
| URLPatternSet())); |
| |
| // example.com isn't granted, so without an initiator or with an initiator |
| // that the extension doesn't have access to, access is withheld. |
| EXPECT_EQ( |
| PermissionsData::PageAccess::kWithheld, |
| get_access(example_com, std::nullopt, WebRequestResourceType::OTHER)); |
| EXPECT_EQ(PermissionsData::PageAccess::kWithheld, |
| get_access(example_com, example_com_origin, |
| WebRequestResourceType::MAIN_FRAME)); |
| |
| // However, if a sub-resource request is made to example.com from an initiator |
| // that the extension has access to, access is allowed. This is functionally |
| // necessary for any extension with webRequest to work with the runtime host |
| // permissions feature. See https://crbug.com/851722. |
| EXPECT_EQ(PermissionsData::PageAccess::kAllowed, |
| get_access(example_com, chromium_org_origin, |
| WebRequestResourceType::OTHER)); |
| EXPECT_EQ(PermissionsData::PageAccess::kWithheld, |
| get_access(example_com, chromium_org_origin, |
| WebRequestResourceType::SUB_FRAME)); |
| EXPECT_EQ(PermissionsData::PageAccess::kWithheld, |
| get_access(example_com, chromium_org_origin, |
| WebRequestResourceType::MAIN_FRAME)); |
| |
| // With access to the requested origin, access is always allowed for |
| // REQUIRE_HOST_PERMISSION_FOR_URL, independent of initiator. |
| for (const auto& initiator : initiators) { |
| for (const auto& type : types) { |
| EXPECT_EQ(PermissionsData::PageAccess::kAllowed, |
| get_access(chromium_org, initiator, type)); |
| } |
| } |
| } |
| |
| TEST_F(ExtensionWebRequestPermissionsTest, |
| RequireAccessToURLAndInitiatorWithWithheldPermissions) { |
| ExtensionsAPIClient api_client; |
| |
| const char* kGoogleCom = "https://google.com/"; |
| const char* kExampleCom = "https://example.com/"; |
| const char* kYahooCom = "https://yahoo.com"; |
| |
| // Set up the extension to have access to kGoogleCom and withheld access to |
| // kExampleCom. |
| scoped_refptr<const Extension> extension = |
| ExtensionBuilder("ext") |
| .AddHostPermissions({kGoogleCom, kExampleCom}) |
| .Build(); |
| |
| URLPatternSet kActivePatternSet( |
| {URLPattern(Extension::kValidHostPermissionSchemes, kGoogleCom)}); |
| URLPatternSet kWithheldPatternSet( |
| {URLPattern(Extension::kValidHostPermissionSchemes, kExampleCom)}); |
| |
| extension->permissions_data()->SetPermissions( |
| std::make_unique<PermissionSet>( |
| APIPermissionSet(), ManifestPermissionSet(), |
| kActivePatternSet.Clone(), |
| kActivePatternSet.Clone()), // active permissions. |
| std::make_unique<PermissionSet>( |
| APIPermissionSet(), ManifestPermissionSet(), |
| kWithheldPatternSet.Clone(), |
| kWithheldPatternSet.Clone()) /* withheld permissions */); |
| |
| ExtensionRegistry::Get(browser_context())->AddEnabled(extension); |
| |
| auto get_access = [extension, this]( |
| const GURL& url, |
| const std::optional<url::Origin>& initiator, |
| WebRequestResourceType type) { |
| constexpr int kTabId = 42; |
| constexpr WebRequestPermissions::HostPermissionsCheck kPermissionsCheck = |
| WebRequestPermissions::REQUIRE_HOST_PERMISSION_FOR_URL_AND_INITIATOR; |
| return WebRequestPermissions::CanExtensionAccessURL( |
| PermissionHelper::Get(browser_context()), extension->id(), url, kTabId, |
| false /* crosses incognito */, kPermissionsCheck, initiator, type); |
| }; |
| |
| using PageAccess = PermissionsData::PageAccess; |
| const GURL kAllowedUrl(kGoogleCom); |
| const GURL kWithheldUrl(kExampleCom); |
| const GURL kDeniedUrl(kYahooCom); |
| const url::Origin kAllowedOrigin(url::Origin::Create(kAllowedUrl)); |
| const url::Origin kWithheldOrigin(url::Origin::Create(kWithheldUrl)); |
| const url::Origin kDeniedOrigin(url::Origin::Create(kDeniedUrl)); |
| const url::Origin kOpaqueOrigin; |
| struct { |
| std::optional<url::Origin> initiator; |
| GURL url; |
| PermissionsData::PageAccess expected_access_subresource; |
| PermissionsData::PageAccess expected_access_navigation; |
| } cases[] = { |
| {std::nullopt, kAllowedUrl, PageAccess::kAllowed, PageAccess::kAllowed}, |
| {std::nullopt, kWithheldUrl, PageAccess::kWithheld, |
| PageAccess::kWithheld}, |
| {std::nullopt, kDeniedUrl, PageAccess::kDenied, PageAccess::kDenied}, |
| |
| {kOpaqueOrigin, kAllowedUrl, PageAccess::kAllowed, PageAccess::kAllowed}, |
| {kOpaqueOrigin, kWithheldUrl, PageAccess::kWithheld, |
| PageAccess::kWithheld}, |
| {kOpaqueOrigin, kDeniedUrl, PageAccess::kDenied, PageAccess::kDenied}, |
| |
| {kDeniedOrigin, kAllowedUrl, PageAccess::kDenied, PageAccess::kAllowed}, |
| {kDeniedOrigin, kWithheldUrl, PageAccess::kDenied, PageAccess::kWithheld}, |
| {kDeniedOrigin, kDeniedUrl, PageAccess::kDenied, PageAccess::kDenied}, |
| {kAllowedOrigin, kDeniedUrl, PageAccess::kDenied, PageAccess::kDenied}, |
| {kWithheldOrigin, kDeniedUrl, PageAccess::kDenied, PageAccess::kDenied}, |
| |
| {kWithheldOrigin, kWithheldUrl, PageAccess::kWithheld, |
| PageAccess::kWithheld}, |
| {kWithheldOrigin, kAllowedUrl, PageAccess::kWithheld, |
| PageAccess::kAllowed}, |
| {kAllowedOrigin, kWithheldUrl, PageAccess::kAllowed, |
| PageAccess::kWithheld}, |
| {kAllowedOrigin, kAllowedUrl, PageAccess::kAllowed, PageAccess::kAllowed}, |
| }; |
| |
| for (const auto& test_case : cases) { |
| SCOPED_TRACE(base::StringPrintf( |
| "url-%s initiator-%s", test_case.url.spec().c_str(), |
| test_case.initiator ? test_case.initiator->Serialize().c_str() |
| : "empty")); |
| EXPECT_EQ(get_access(test_case.url, test_case.initiator, |
| WebRequestResourceType::OTHER), |
| test_case.expected_access_subresource); |
| EXPECT_EQ(get_access(test_case.url, test_case.initiator, |
| WebRequestResourceType::SUB_FRAME), |
| test_case.expected_access_navigation); |
| EXPECT_EQ(get_access(test_case.url, test_case.initiator, |
| WebRequestResourceType::MAIN_FRAME), |
| test_case.expected_access_navigation); |
| } |
| } |
| |
| } // namespace extensions |