blob: 3caf69c94e25f7efd0ff2eb0fc332cb9b1b8ae47 [file] [log] [blame]
// Copyright 2024 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/extensions/permissions/permissions_updater.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/permissions/permissions_test_util.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "extensions/browser/script_injection_tracker.h"
#include "extensions/buildflags/buildflags.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest_handlers/permissions_parser.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/url_pattern.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/test_extension_dir.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));
namespace extensions {
class PermissionsUpdaterBrowserTest : public ExtensionBrowserTest {
public:
PermissionsUpdaterBrowserTest() = default;
PermissionsUpdaterBrowserTest(const PermissionsUpdaterBrowserTest&) = delete;
const PermissionsUpdaterBrowserTest& operator=(
const PermissionsUpdaterBrowserTest&) = delete;
~PermissionsUpdaterBrowserTest() override = default;
void SetUpOnMainThread() override {
ExtensionBrowserTest::SetUpOnMainThread();
host_resolver()->AddRule("*", "127.0.0.1");
content::SetupCrossSiteRedirector(embedded_test_server());
}
};
// Tests that updating the permissions of a disabled extension doesn't update
// the renderer.
IN_PROC_BROWSER_TEST_F(PermissionsUpdaterBrowserTest,
UpdatePermissions_DisabledExtension) {
ASSERT_TRUE(embedded_test_server()->Start());
// Step 1: Install extension with <all_urls> optional host permission and
// dynamic content script with a.com matches.
TestExtensionDir dir;
const char kManifestTemplate[] = R"(
{
"name": "ScriptingAPI - Update host permissions",
"version": "1.0",
"manifest_version": 3,
"permissions": [ "scripting" ],
"optional_host_permissions": ["<all_urls>"],
"background": { "service_worker": "worker.js" }
} )";
const char kWorkerScript[] = R"(
var scripts = [{
id: 'script1',
matches: ['*://a.com/*'],
js: ['content_script.js'],
runAt: 'document_end'
}];
chrome.runtime.onInstalled.addListener(function(details) {
chrome.scripting.registerContentScripts(scripts, () => {
chrome.test.sendMessage('SCRIPT_LOADED');
});
}); )";
dir.WriteManifest(kManifestTemplate);
dir.WriteFile(FILE_PATH_LITERAL("worker.js"), kWorkerScript);
const char kContentScript[] = R"(
window.didInjectContentScript = true;
)";
dir.WriteFile(FILE_PATH_LITERAL("content_script.js"), kContentScript);
ExtensionTestMessageListener script_loaded_listener("SCRIPT_LOADED");
const Extension* extension = LoadExtension(dir.UnpackedPath());
ASSERT_TRUE(extension);
ASSERT_TRUE(script_loaded_listener.WaitUntilSatisfied());
// Step 2: Navigate to a.com.
content::WebContents* web_contents = GetActiveWebContents();
GURL optional_url = embedded_test_server()->GetURL("a.com", "/title1.html");
ASSERT_TRUE(content::NavigateToURL(web_contents, optional_url));
content::WaitForLoadStop(web_contents);
// Verify extension's active permissions don't include a.com and renderer
// hasn't injected the extension's script.
EXPECT_FALSE(extension->permissions_data()
->active_permissions()
.HasEffectiveAccessToURL(optional_url));
EXPECT_EQ(base::Value(),
content::EvalJs(web_contents, "window.didInjectContentScript"));
EXPECT_FALSE(ScriptInjectionTracker::DidProcessRunContentScriptFromExtension(
*web_contents->GetPrimaryMainFrame()->GetProcess(), extension->id()));
// Step 3: Disable extension.
DisableExtension(extension->id());
// Step 4: Grant optional permissions.
permissions_test_util::GrantOptionalPermissionsAndWaitForCompletion(
profile(), *extension,
PermissionsParser::GetOptionalPermissions(extension));
// Verify extension's active permissions include a.com. However, since
// extension is disabled, renderer doesn't inject the extensions's script.
EXPECT_TRUE(extension->permissions_data()
->active_permissions()
.HasEffectiveAccessToURL(optional_url));
EXPECT_EQ(base::Value(),
content::EvalJs(web_contents, "window.didInjectContentScript"));
EXPECT_FALSE(ScriptInjectionTracker::DidProcessRunContentScriptFromExtension(
*web_contents->GetPrimaryMainFrame()->GetProcess(), extension->id()));
}
} // namespace extensions