| // Copyright 2020 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 "base/strings/stringprintf.h" |
| #include "base/values.h" |
| #include "chrome/app/chrome_command_ids.h" |
| #include "chrome/browser/devtools/devtools_window_testing.h" |
| #include "chrome/browser/policy/policy_test_utils.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/common/url_constants.h" |
| #include "chrome/test/base/in_process_browser_test.h" |
| #include "chrome/test/base/ui_test_utils.h" |
| #include "components/policy/core/common/policy_map.h" |
| #include "components/policy/policy_constants.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/test_utils.h" |
| #include "extensions/browser/api/messaging/messaging_delegate.h" |
| |
| namespace policy { |
| |
| namespace { |
| |
| // Utility for waiting until the dev-mode controls are visible/hidden |
| // Uses a MutationObserver on the attributes of the DOM element. |
| void WaitForExtensionsDevModeControlsVisibility( |
| content::WebContents* contents, |
| const char* dev_controls_accessor_js, |
| const char* dev_controls_visibility_check_js, |
| bool expected_visible) { |
| bool done = false; |
| ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| contents, |
| base::StringPrintf( |
| "var screenElement = %s;" |
| "function SendReplyIfAsExpected() {" |
| " var is_visible = %s;" |
| " if (is_visible != %s)" |
| " return false;" |
| " observer.disconnect();" |
| " domAutomationController.send(true);" |
| " return true;" |
| "}" |
| "var observer = new MutationObserver(SendReplyIfAsExpected);" |
| "if (!SendReplyIfAsExpected()) {" |
| " var options = { 'attributes': true };" |
| " observer.observe(screenElement, options);" |
| "}", |
| dev_controls_accessor_js, dev_controls_visibility_check_js, |
| (expected_visible ? "true" : "false")), |
| &done)); |
| } |
| |
| } // namespace |
| |
| IN_PROC_BROWSER_TEST_F(PolicyTest, DeveloperToolsDisabledByLegacyPolicy) { |
| // Verifies that access to the developer tools can be disabled by setting the |
| // legacy DeveloperToolsDisabled policy. |
| |
| // Open devtools. |
| EXPECT_TRUE(chrome::ExecuteCommand(browser(), IDC_DEV_TOOLS)); |
| content::WebContents* contents = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| DevToolsWindow* devtools_window = |
| DevToolsWindow::GetInstanceForInspectedWebContents(contents); |
| EXPECT_TRUE(devtools_window); |
| |
| // Disable devtools via policy. |
| PolicyMap policies; |
| policies.Set(key::kDeveloperToolsDisabled, POLICY_LEVEL_MANDATORY, |
| POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, base::Value(true), |
| nullptr); |
| content::WebContentsDestroyedWatcher close_observer( |
| DevToolsWindowTesting::Get(devtools_window)->main_web_contents()); |
| UpdateProviderPolicy(policies); |
| // wait for devtools close |
| close_observer.Wait(); |
| // The existing devtools window should have closed. |
| EXPECT_FALSE(DevToolsWindow::GetInstanceForInspectedWebContents(contents)); |
| // And it's not possible to open it again. |
| EXPECT_FALSE(chrome::ExecuteCommand(browser(), IDC_DEV_TOOLS)); |
| EXPECT_FALSE(DevToolsWindow::GetInstanceForInspectedWebContents(contents)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PolicyTest, |
| DeveloperToolsDisabledByDeveloperToolsAvailability) { |
| // Verifies that access to the developer tools can be disabled by setting the |
| // DeveloperToolsAvailability policy. |
| |
| // Open devtools. |
| EXPECT_TRUE(chrome::ExecuteCommand(browser(), IDC_DEV_TOOLS)); |
| content::WebContents* contents = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| DevToolsWindow* devtools_window = |
| DevToolsWindow::GetInstanceForInspectedWebContents(contents); |
| EXPECT_TRUE(devtools_window); |
| |
| // Disable devtools via policy. |
| PolicyMap policies; |
| policies.Set(key::kDeveloperToolsAvailability, POLICY_LEVEL_MANDATORY, |
| POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, |
| base::Value(2 /* DeveloperToolsDisallowed */), nullptr); |
| content::WebContentsDestroyedWatcher close_observer( |
| DevToolsWindowTesting::Get(devtools_window)->main_web_contents()); |
| UpdateProviderPolicy(policies); |
| // wait for devtools close |
| close_observer.Wait(); |
| // The existing devtools window should have closed. |
| EXPECT_FALSE(DevToolsWindow::GetInstanceForInspectedWebContents(contents)); |
| // And it's not possible to open it again. |
| EXPECT_FALSE(chrome::ExecuteCommand(browser(), IDC_DEV_TOOLS)); |
| EXPECT_FALSE(DevToolsWindow::GetInstanceForInspectedWebContents(contents)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PolicyTest, DeveloperToolsDisabledExtensionsDevMode) { |
| // Verifies that when DeveloperToolsDisabled policy is set, the "dev mode" |
| // in chrome://extensions is actively turned off and the checkbox |
| // is disabled. |
| // Note: We don't test the indicator as it is tested in the policy pref test |
| // for kDeveloperToolsDisabled and kDeveloperToolsAvailability. |
| |
| // This test depends on the following helper methods to locate the DOM |
| // elements to be tested. |
| const char define_helpers_js[] = |
| R"(function getToolbar() { |
| const manager = document.querySelector('extensions-manager'); |
| return manager.$$('extensions-toolbar'); |
| } |
| |
| function getToggle() { |
| return getToolbar().$.devMode; |
| } |
| |
| function getControls() { |
| return getToolbar().$.devDrawer; |
| } |
| )"; |
| |
| const char toggle_dev_mode_accessor_js[] = "getToggle()"; |
| const char dev_controls_accessor_js[] = "getControls()"; |
| const char dev_controls_visibility_check_js[] = |
| "getControls().hasAttribute('expanded')"; |
| |
| // Navigate to the extensions frame and enabled "Developer mode" |
| ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIExtensionsURL)); |
| |
| content::WebContents* contents = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| EXPECT_TRUE(content::ExecuteScript(contents, std::string(define_helpers_js))); |
| |
| EXPECT_TRUE(content::ExecuteScript( |
| contents, base::StringPrintf("domAutomationController.send(%s.click());", |
| toggle_dev_mode_accessor_js))); |
| |
| WaitForExtensionsDevModeControlsVisibility(contents, dev_controls_accessor_js, |
| dev_controls_visibility_check_js, |
| true); |
| |
| // Disable devtools via policy. |
| PolicyMap policies; |
| policies.Set(key::kDeveloperToolsAvailability, POLICY_LEVEL_MANDATORY, |
| POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, |
| base::Value(2 /*DeveloperToolsDisallowed*/), nullptr); |
| UpdateProviderPolicy(policies); |
| |
| // Expect devcontrols to be hidden now... |
| WaitForExtensionsDevModeControlsVisibility(contents, dev_controls_accessor_js, |
| dev_controls_visibility_check_js, |
| false); |
| |
| // ... and checkbox is disabled |
| bool is_toggle_dev_mode_checkbox_disabled = false; |
| EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
| contents, |
| base::StringPrintf( |
| "domAutomationController.send(%s.hasAttribute('disabled'))", |
| toggle_dev_mode_accessor_js), |
| &is_toggle_dev_mode_checkbox_disabled)); |
| EXPECT_TRUE(is_toggle_dev_mode_checkbox_disabled); |
| } |
| |
| } // namespace policy |