diff --git a/renderer/brave_content_settings_observer.cc b/renderer/brave_content_settings_observer.cc index 8a9e2c84f84c..2034aacc0800 100644 --- a/renderer/brave_content_settings_observer.cc +++ b/renderer/brave_content_settings_observer.cc @@ -209,8 +209,58 @@ bool BraveContentSettingsObserver::AllowAutoplay(bool default_value) { return true; bool allow = ContentSettingsObserver::AllowAutoplay(default_value); - if (allow) { + if (allow) return true; + + // respect user's site blocklist, if any + const GURL& primary_url = GetOriginOrURL(frame); + const GURL& secondary_url = url::Origin(frame->GetDocument().GetSecurityOrigin()).GetURL(); + for (const auto& rule : content_setting_rules_->autoplay_rules) { + if (rule.primary_pattern == ContentSettingsPattern::Wildcard()) + continue; + ContentSettingsPattern secondary_pattern = rule.secondary_pattern; + if (rule.secondary_pattern == + ContentSettingsPattern::FromString("https://firstParty/*")) { + secondary_pattern = ContentSettingsPattern::FromString( + "[*.]" + GetOriginOrURL(frame).HostNoBrackets()); + } + if (rule.primary_pattern.Matches(primary_url) && + (secondary_pattern == ContentSettingsPattern::Wildcard() || + secondary_pattern.Matches(secondary_url))) { + if (rule.GetContentSetting() == CONTENT_SETTING_BLOCK) + return false; + } + } + + // in the absence of an explicit block rule, whitelist the following sites + std::string kWhitelistPatterns[] = { + "[*.]example.com", + "[*.]youtube.com", + "[*.]khanacademy.org", + "[*.]twitch.tv", + "[*.]vimeo.com", + "[*.]udemy.com", + "[*.]duolingo.com", + "[*.]giphy.com", + "[*.]imgur.com", + "[*.]netflix.com", + "[*.]hulu.com", + "[*.]primevideo.com", + "[*.]dailymotion.com", + "[*.]tv.com", + "[*.]viewster.com", + "[*.]metacafe.com", + "[*.]d.tube", + "[*.]spotify.com", + "[*.]lynda.com", + "[*.]soundcloud.com", + "[*.]pandora.com", + "[*.]periscope.tv", + "[*.]pscp.tv", + }; + for (const auto& pattern : kWhitelistPatterns) { + if (ContentSettingsPattern::FromString(pattern).Matches(primary_url)) + return true; } blink::mojom::blink::PermissionServicePtr permission_service; diff --git a/renderer/brave_content_settings_observer_autoplay_browsertest.cc b/renderer/brave_content_settings_observer_autoplay_browsertest.cc new file mode 100644 index 000000000000..01395d7df2b0 --- /dev/null +++ b/renderer/brave_content_settings_observer_autoplay_browsertest.cc @@ -0,0 +1,140 @@ +/* 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 "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/test/browser_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 kVideoPlaying[] = "Video playing"; +const char kVideoPlayingDetect[] = + "window.domAutomationController.send(document.getElementById('status')." + "textContent);"; + +class BraveContentSettingsObserverAutoplayTest : 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; + base::PathService::Get(brave::DIR_TEST_DATA, &test_data_dir); + embedded_test_server()->ServeFilesFromDirectory(test_data_dir); + + ASSERT_TRUE(embedded_test_server()->Start()); + + whitelisted_url_ = embedded_test_server()->GetURL("example.com", "/autoplay/autoplay_by_attr.html"); + + user_blocklist_pattern_ = + ContentSettingsPattern::FromString("http://example.com/*"); + } + + void TearDown() override { + browser_content_client_.reset(); + content_client_.reset(); + } + + const GURL& whitelisted_url() { return whitelisted_url_; } + + const ContentSettingsPattern& user_blocklist_pattern() { + return user_blocklist_pattern_; + } + + HostContentSettingsMap * content_settings() { + return HostContentSettingsMapFactory::GetForProfile(browser()->profile()); + } + + void BlockAutoplay() { + content_settings()->SetContentSettingCustomScope( + user_blocklist_pattern_, + ContentSettingsPattern::Wildcard(), + CONTENT_SETTINGS_TYPE_AUTOPLAY, + std::string(), + CONTENT_SETTING_BLOCK); + } + + content::WebContents* contents() { + return browser()->tab_strip_model()->GetActiveWebContents(); + } + + bool NavigateToURLUntilLoadStop(const GURL& url) { + ui_test_utils::NavigateToURL(browser(), url); + return WaitForLoadStop(contents()); + } + + void WaitForPlaying() { + std::string msg_from_renderer; + ASSERT_TRUE(ExecuteScriptAndExtractString(contents(), "notifyWhenPlaying();", + &msg_from_renderer)); + ASSERT_EQ("PLAYING", msg_from_renderer); + } + + private: + GURL whitelisted_url_; + ContentSettingsPattern user_blocklist_pattern_; + std::unique_ptr content_client_; + std::unique_ptr browser_content_client_; +}; + +// Allow autoplay on whitelisted URL by default +IN_PROC_BROWSER_TEST_F(BraveContentSettingsObserverAutoplayTest, AllowAutoplay) { + std::string result; + PermissionRequestManager* manager = PermissionRequestManager::FromWebContents( + contents()); + auto popup_prompt_factory = + std::make_unique(manager); + + EXPECT_EQ(0, popup_prompt_factory->TotalRequestCount()); + + NavigateToURLUntilLoadStop(whitelisted_url()); + EXPECT_FALSE(popup_prompt_factory->is_visible()); + EXPECT_FALSE(popup_prompt_factory->RequestTypeSeen( + PermissionRequestType::PERMISSION_AUTOPLAY)); + EXPECT_EQ(0, popup_prompt_factory->TotalRequestCount()); + WaitForPlaying(); + EXPECT_TRUE(ExecuteScriptAndExtractString(contents(), + kVideoPlayingDetect, &result)); + EXPECT_EQ(result, kVideoPlaying); +} + +// Block autoplay, even on whitelisted URL, if user has a blocklist pattern that +// matches the whitelisted URL +IN_PROC_BROWSER_TEST_F(BraveContentSettingsObserverAutoplayTest, BlockAutoplay) { + std::string result; + BlockAutoplay(); + PermissionRequestManager* manager = PermissionRequestManager::FromWebContents( + contents()); + auto popup_prompt_factory = + std::make_unique(manager); + + EXPECT_EQ(0, popup_prompt_factory->TotalRequestCount()); + + NavigateToURLUntilLoadStop(whitelisted_url()); + EXPECT_FALSE(popup_prompt_factory->is_visible()); + EXPECT_FALSE(popup_prompt_factory->RequestTypeSeen( + PermissionRequestType::PERMISSION_AUTOPLAY)); + EXPECT_EQ(0, popup_prompt_factory->TotalRequestCount()); + EXPECT_TRUE(ExecuteScriptAndExtractString(contents(), + kVideoPlayingDetect, &result)); + EXPECT_NE(result, kVideoPlaying); +} diff --git a/test/BUILD.gn b/test/BUILD.gn index c0cafeb448fc..71d5dd2dc0be 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -215,6 +215,7 @@ test("brave_browser_tests") { "//brave/components/brave_shields/browser/tracking_protection_service_browsertest.cc", "//brave/browser/extensions/brave_extension_provider_browsertest.cc", "//brave/renderer/brave_content_settings_observer_browsertest.cc", + "//brave/renderer/brave_content_settings_observer_autoplay_browsertest.cc", "//brave/renderer/brave_content_settings_observer_flash_browsertest.cc", "//brave/browser/themes/brave_theme_service_browsertest.cc", "//chrome/browser/extensions/browsertest_util.cc",