diff --git a/browser/ui/BUILD.gn b/browser/ui/BUILD.gn index 66481460d3f4..3cb9217b099b 100644 --- a/browser/ui/BUILD.gn +++ b/browser/ui/BUILD.gn @@ -6,6 +6,8 @@ source_set("ui") { "brave_browser_command_controller.h", "brave_pages.cc", "brave_pages.h", + "content_settings/brave_content_setting_bubble_model.cc", + "content_settings/brave_content_setting_bubble_model.h", "toolbar/brave_app_menu_model.cc", "toolbar/brave_app_menu_model.h", "views/importer/brave_import_lock_dialog_view.cc", diff --git a/browser/ui/content_settings/brave_content_setting_bubble_model.cc b/browser/ui/content_settings/brave_content_setting_bubble_model.cc new file mode 100644 index 000000000000..b9d7efd3adc5 --- /dev/null +++ b/browser/ui/content_settings/brave_content_setting_bubble_model.cc @@ -0,0 +1,65 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/ui/content_settings/brave_content_setting_bubble_model.h" + +#include "brave/components/brave_shields/common/brave_shield_constants.h" +#include "chrome/browser/content_settings/host_content_settings_map_factory.h" +#include "chrome/browser/plugins/plugin_utils.h" +#include "chrome/browser/subresource_filter/chrome_subresource_filter_client.h" +#include "chrome/browser/ui/content_settings/content_setting_bubble_model_delegate.h" +#include "chrome/grit/generated_resources.h" +#include "components/content_settings/core/browser/host_content_settings_map.h" +#include "ui/base/l10n/l10n_util.h" + +BraveContentSettingPluginBubbleModel::BraveContentSettingPluginBubbleModel( + Delegate* delegate, content::WebContents* web_contents, Profile* profile) + : ContentSettingSimpleBubbleModel(delegate, + web_contents, + profile, + CONTENT_SETTINGS_TYPE_PLUGINS), profile_(profile) { + content_settings::SettingInfo info; + HostContentSettingsMap* map = + HostContentSettingsMapFactory::GetForProfile(profile); + GURL url = web_contents->GetURL(); + std::unique_ptr value = + map->GetWebsiteSetting(url, url, content_type(), std::string(), &info); + // If the setting is not managed by the user, hide the "Manage" button. + if (info.source != content_settings::SETTING_SOURCE_USER) + set_manage_text_style(ContentSettingBubbleModel::ManageTextStyle::kNone); + set_custom_link(l10n_util::GetStringUTF16(IDS_BLOCKED_PLUGINS_LOAD_ALL)); + set_custom_link_enabled( + web_contents && + TabSpecificContentSettings::FromWebContents(web_contents) + ->load_plugins_link_enabled()); + set_show_learn_more(true); +} + +void BraveContentSettingPluginBubbleModel::OnLearnMoreClicked() { + if (delegate()) + delegate()->ShowLearnMorePage(CONTENT_SETTINGS_TYPE_PLUGINS); +} + +void BraveContentSettingPluginBubbleModel::OnCustomLinkClicked() { + RunPluginsOnPage(); +} + +void BraveContentSettingPluginBubbleModel::RunPluginsOnPage() { + // Web contents can be NULL if the tab was closed while the plugins + // settings bubble is visible. + if (!web_contents()) + return; + + HostContentSettingsMap* map = + HostContentSettingsMapFactory::GetForProfile(profile_); + map->SetContentSettingDefaultScope( + web_contents()->GetURL(), + GURL(), + CONTENT_SETTINGS_TYPE_PLUGINS, + std::string(), + CONTENT_SETTING_DETECT_IMPORTANT_CONTENT); + + ChromeSubresourceFilterClient::FromWebContents(web_contents()) + ->OnReloadRequested(); +} diff --git a/browser/ui/content_settings/brave_content_setting_bubble_model.h b/browser/ui/content_settings/brave_content_setting_bubble_model.h new file mode 100644 index 000000000000..e6738e192e6e --- /dev/null +++ b/browser/ui/content_settings/brave_content_setting_bubble_model.h @@ -0,0 +1,23 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "chrome/browser/ui/content_settings/content_setting_bubble_model.h" + +class Profile; + +class BraveContentSettingPluginBubbleModel : public ContentSettingSimpleBubbleModel { + public: + BraveContentSettingPluginBubbleModel(Delegate* delegate, + content::WebContents* web_contents, + Profile* profile); + + private: + void OnLearnMoreClicked() override; + void OnCustomLinkClicked() override; + + void RunPluginsOnPage(); + Profile* profile_; + + DISALLOW_COPY_AND_ASSIGN(BraveContentSettingPluginBubbleModel); +}; diff --git a/components/content_settings/core/browser/brave_host_content_settings_map.cc b/components/content_settings/core/browser/brave_host_content_settings_map.cc index 93aa4ad4010f..8769c4aa4285 100644 --- a/components/content_settings/core/browser/brave_host_content_settings_map.cc +++ b/components/content_settings/core/browser/brave_host_content_settings_map.cc @@ -18,6 +18,7 @@ BraveHostContentSettingsMap::BraveHostContentSettingsMap( InitializeReferrerContentSetting(); InitializeCookieContentSetting(); InitializeBraveShieldsContentSetting(); + InitializeFlashContentSetting(); } BraveHostContentSettingsMap::~BraveHostContentSettingsMap() { @@ -60,3 +61,14 @@ void BraveHostContentSettingsMap::InitializeBraveShieldsContentSetting() { brave_shields::kBraveShields, CONTENT_SETTING_ALLOW); } + +void BraveHostContentSettingsMap::InitializeFlashContentSetting() { + SetContentSettingCustomScope( + ContentSettingsPattern::Wildcard(), + ContentSettingsPattern::Wildcard(), + CONTENT_SETTINGS_TYPE_PLUGINS, + // One would think this should be brave_shields::kFlash; however, if you + // use it, it will always ask and click-to-play will not work. + std::string(), + CONTENT_SETTING_BLOCK); +} diff --git a/components/content_settings/core/browser/brave_host_content_settings_map.h b/components/content_settings/core/browser/brave_host_content_settings_map.h index e93734c87fb2..dd26cf9e5a6c 100644 --- a/components/content_settings/core/browser/brave_host_content_settings_map.h +++ b/components/content_settings/core/browser/brave_host_content_settings_map.h @@ -18,6 +18,7 @@ class BraveHostContentSettingsMap : public HostContentSettingsMap { void InitializeReferrerContentSetting(); void InitializeCookieContentSetting(); void InitializeBraveShieldsContentSetting(); + void InitializeFlashContentSetting(); ~BraveHostContentSettingsMap() override; }; diff --git a/patches/chrome-browser-ui-content_settings-content_setting_bubble_model.cc.patch b/patches/chrome-browser-ui-content_settings-content_setting_bubble_model.cc.patch new file mode 100644 index 000000000000..47dc691388b0 --- /dev/null +++ b/patches/chrome-browser-ui-content_settings-content_setting_bubble_model.cc.patch @@ -0,0 +1,21 @@ +diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc +index 0e1bec53e5c64024528e949d8a7a51e3877f3056..e99590efc9a2c0850e4958a76bccda53a2a09a36 100644 +--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc ++++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc +@@ -15,6 +15,7 @@ + #include "base/metrics/user_metrics.h" + #include "base/stl_util.h" + #include "base/strings/utf_string_conversions.h" ++#include "brave/browser/ui/content_settings/brave_content_setting_bubble_model.h" + #include "chrome/browser/browser_process.h" + #include "chrome/browser/chrome_notification_types.h" + #include "chrome/browser/content_settings/chrome_content_settings_utils.h" +@@ -1712,7 +1713,7 @@ ContentSettingBubbleModel* + profile, content_type); + } + if (content_type == CONTENT_SETTINGS_TYPE_PLUGINS) { +- return new ContentSettingPluginBubbleModel(delegate, web_contents, profile); ++ return new BraveContentSettingPluginBubbleModel(delegate, web_contents, profile); + } + if (content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT) { + return new ContentSettingMixedScriptBubbleModel(delegate, web_contents, diff --git a/renderer/brave_content_settings_observer_flash_browsertest.cc b/renderer/brave_content_settings_observer_flash_browsertest.cc new file mode 100644 index 000000000000..75bef28018bf --- /dev/null +++ b/renderer/brave_content_settings_observer_flash_browsertest.cc @@ -0,0 +1,199 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "base/path_service.h" +#include "brave/browser/brave_content_browser_client.h" +#include "brave/common/brave_paths.h" +#include "brave/components/brave_shields/common/brave_shield_constants.h" +#include "chrome/browser/content_settings/host_content_settings_map_factory.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h" +#include "chrome/common/chrome_content_client.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/common/content_switches.h" +#include "content/public/test/browser_test_utils.h" +#include "content/public/test/ppapi_test_utils.h" +#include "components/content_settings/core/browser/host_content_settings_map.h" +#include "components/content_settings/core/common/content_settings.h" +#include "components/content_settings/core/common/content_settings_types.h" +#include "net/dns/mock_host_resolver.h" + +const char kFlashPluginExists[] = + "domAutomationController.send(Array.from(navigator.plugins).filter(" + " x => Array.from(x).some(" + " y => y.type === 'application/x-shockwave-flash')).length)"; + +namespace { + +class PageReloadWaiter { + public: + explicit PageReloadWaiter(content::WebContents* web_contents) + : web_contents_(web_contents), + navigation_observer_(web_contents, + web_contents->GetLastCommittedURL()) {} + + bool Wait() { + navigation_observer_.WaitForNavigationFinished(); + return content::WaitForLoadStop(web_contents_); + } + + private: + content::WebContents* web_contents_; + content::TestNavigationManager navigation_observer_; +}; + +} // namespace + +class BraveContentSettingsObserverFlashBrowserTest : public InProcessBrowserTest { + public: + void SetUpOnMainThread() override { + InProcessBrowserTest::SetUpOnMainThread(); + + content_client_.reset(new ChromeContentClient); + content::SetContentClient(content_client_.get()); + browser_content_client_.reset(new BraveContentBrowserClient()); + content::SetBrowserClientForTesting(browser_content_client_.get()); + + host_resolver()->AddRule("*", "127.0.0.1"); + content::SetupCrossSiteRedirector(embedded_test_server()); + + brave::RegisterPathProvider(); + base::FilePath test_data_dir; + PathService::Get(brave::DIR_TEST_DATA, &test_data_dir); + embedded_test_server()->ServeFilesFromDirectory(test_data_dir); + + ASSERT_TRUE(embedded_test_server()->Start()); + + url_ = embedded_test_server()->GetURL("a.com", "/flash.html"); + top_level_page_pattern_ = + ContentSettingsPattern::FromString("http://a.com/*"); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + InProcessBrowserTest::SetUpCommandLine(command_line); + ASSERT_TRUE(ppapi::RegisterFlashTestPlugin(command_line)); + // These tests are for the permission prompt to add and remove Flash from + // navigator.plugins. We disable Plugin Power Saver, because its plugin + // throttling make it harder to test if Flash was succcessfully enabled. + command_line->AppendSwitchASCII( + switches::kOverridePluginPowerSaverForTesting, "never"); + } + + void TearDown() override { + browser_content_client_.reset(); + content_client_.reset(); + } + + const GURL& url() { return url_; } + + const ContentSettingsPattern& top_level_page_pattern() { + return top_level_page_pattern_; + } + + const ContentSettingsPattern& empty_pattern() { + return empty_pattern_; + } + + HostContentSettingsMap * content_settings() { + return HostContentSettingsMapFactory::GetForProfile(browser()->profile()); + } + + void UnblockFlash() { + content_settings()->SetContentSettingCustomScope( + top_level_page_pattern_, + ContentSettingsPattern::Wildcard(), + CONTENT_SETTINGS_TYPE_PLUGINS, + std::string(), + CONTENT_SETTING_DETECT_IMPORTANT_CONTENT); + } + + void AllowFlash() { + content_settings()->SetContentSettingCustomScope( + top_level_page_pattern_, + ContentSettingsPattern::Wildcard(), + CONTENT_SETTINGS_TYPE_PLUGINS, + std::string(), + CONTENT_SETTING_ALLOW); + } + + content::WebContents* contents() { + return browser()->tab_strip_model()->GetActiveWebContents(); + } + + bool NavigateToURLUntilLoadStop(const GURL& url) { + ui_test_utils::NavigateToURL(browser(), url); + return WaitForLoadStop(contents()); + } + + private: + GURL url_; + ContentSettingsPattern top_level_page_pattern_; + ContentSettingsPattern empty_pattern_; + std::unique_ptr content_client_; + std::unique_ptr browser_content_client_; + + base::ScopedTempDir temp_user_data_dir_; +}; + +// Flash is blocked by default +IN_PROC_BROWSER_TEST_F(BraveContentSettingsObserverFlashBrowserTest, + BlockFlashByDefault) { + NavigateToURLUntilLoadStop(url()); + int len; + ASSERT_TRUE(ExecuteScriptAndExtractInt(contents(), + kFlashPluginExists, &len)); + ASSERT_EQ(len, 0); +} + +// Flash is unblocked and click to play eventually allows +IN_PROC_BROWSER_TEST_F(BraveContentSettingsObserverFlashBrowserTest, + UnblockFlash) { + UnblockFlash(); + NavigateToURLUntilLoadStop(url()); + int len; + ASSERT_TRUE(ExecuteScriptAndExtractInt(contents(), + kFlashPluginExists, &len)); + ASSERT_EQ(len, 0); + + PermissionRequestManager* manager = PermissionRequestManager::FromWebContents( + contents()); + + auto popup_prompt_factory = + std::make_unique(manager); + + EXPECT_EQ(0, popup_prompt_factory->TotalRequestCount()); + popup_prompt_factory->set_response_type(PermissionRequestManager::ACCEPT_ALL); + + PageReloadWaiter reload_waiter(contents()); + + bool value; + EXPECT_TRUE(ExecuteScriptAndExtractBool(contents(), "triggerPrompt();", + &value)); + EXPECT_TRUE(value); + EXPECT_TRUE(reload_waiter.Wait()); + + EXPECT_EQ(1, popup_prompt_factory->TotalRequestCount()); + + // Shut down the popup window tab, as the normal test teardown assumes there + // is only one test tab. + popup_prompt_factory.reset(); + + ASSERT_TRUE(ExecuteScriptAndExtractInt(contents(), + kFlashPluginExists, &len)); + ASSERT_GT(len, 0); +} + +// Flash is explicitly allowed +IN_PROC_BROWSER_TEST_F(BraveContentSettingsObserverFlashBrowserTest, + AllowFlashExplicitAllows) { + AllowFlash(); + NavigateToURLUntilLoadStop(url()); + int len; + ASSERT_TRUE(ExecuteScriptAndExtractInt(contents(), + kFlashPluginExists, &len)); + ASSERT_GT(len, 0); +} + diff --git a/test/BUILD.gn b/test/BUILD.gn index 5843d5315084..11f46e295cf3 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -77,6 +77,7 @@ test("brave_browser_tests") { "//brave/components/brave_shields/browser/tracking_protection_service_browsertest.cc", "//brave/extensions/browser/brave_extension_provider_browsertest.cc", "//brave/renderer/brave_content_settings_observer_browsertest.cc", + "//brave/renderer/brave_content_settings_observer_flash_browsertest.cc", "//chrome/browser/extensions/browsertest_util.cc", "//chrome/browser/extensions/browsertest_util.h", "//chrome/browser/extensions/extension_browsertest.cc", @@ -90,6 +91,11 @@ test("brave_browser_tests") { deps = [ "//chrome/browser/ui", "//chrome/test:browser_tests_runner", + "//ppapi/features", ":brave_browser_tests_deps", ] + data_deps = [ + "//ppapi:ppapi_tests", + "//ppapi:power_saver_test_plugin", + ] } diff --git a/test/data/flash.html b/test/data/flash.html new file mode 100644 index 000000000000..31ff2ed4a787 --- /dev/null +++ b/test/data/flash.html @@ -0,0 +1,22 @@ + + + + + + + + Flash not supported. +
+ + Download Flash. + +
+ + +