Skip to content

Commit

Permalink
Issue 1985: Properly show the widevine absence prompt.
Browse files Browse the repository at this point in the history
Fixes brave/brave-browser#1985
Replacing a set of hardcoded urls with a blink hook and a corresponding
tab helper that updates the widevine content settings icon.
  • Loading branch information
Ivan Efremov authored and bbondy committed Dec 12, 2018
1 parent 7175045 commit c125186
Show file tree
Hide file tree
Showing 15 changed files with 256 additions and 70 deletions.
2 changes: 2 additions & 0 deletions browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ source_set("browser_process") {
"brave_browser_main_parts_mac.h",
"brave_browser_process_impl.cc",
"brave_browser_process_impl.h",
"brave_drm_tab_helper.cc",
"brave_drm_tab_helper.h",
"brave_local_state_prefs.cc",
"brave_local_state_prefs.h",
"brave_profile_prefs.cc",
Expand Down
44 changes: 44 additions & 0 deletions browser/brave_drm_tab_helper.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* 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/brave_drm_tab_helper.h"

#include "brave/common/pref_names.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/navigation_handle.h"

BraveDrmTabHelper::BraveDrmTabHelper(content::WebContents* contents)
: WebContentsObserver(contents), bindings_(contents, this) {}

BraveDrmTabHelper::~BraveDrmTabHelper() {}

bool BraveDrmTabHelper::ShouldShowWidevineOptIn() const {
// If the user already opted in, don't offer it.
PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
if (prefs->GetBoolean(kWidevineOptedIn)) {
return false;
}

return is_widevine_requested_;
}

void BraveDrmTabHelper::DidStartNavigation(
content::NavigationHandle* navigation_handle) {
if (!navigation_handle->IsInMainFrame() ||
navigation_handle->IsSameDocument()) {
return;
}
is_widevine_requested_ = false;
}

void BraveDrmTabHelper::OnWidevineKeySystemAccessRequest() {
is_widevine_requested_ = true;

Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
browser->window()->UpdateToolbar(web_contents());
}
38 changes: 38 additions & 0 deletions browser/brave_drm_tab_helper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* 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/. */

#ifndef BRAVE_BROWSER_DRM_TAB_HELPER_H_
#define BRAVE_BROWSER_DRM_TAB_HELPER_H_

#include "content/public/browser/web_contents_binding_set.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "third_party/blink/public/platform/brave_drm.mojom.h"

// Reacts to DRM content detected on the renderer side.
class BraveDrmTabHelper final
: public content::WebContentsObserver,
public content::WebContentsUserData<BraveDrmTabHelper>,
public blink::mojom::BraveDRM {
public:
BraveDrmTabHelper(content::WebContents* contents);
~BraveDrmTabHelper() override;

bool ShouldShowWidevineOptIn() const;

// content::WebContentsObserver
void DidStartNavigation(
content::NavigationHandle* navigation_handle) override;

// blink::mojom::BraveDRM
void OnWidevineKeySystemAccessRequest() override;

private:
content::WebContentsFrameBindingSet<blink::mojom::BraveDRM> bindings_;

// True if we are notified that a page requested widevine availability.
bool is_widevine_requested_ = false;
};

#endif // BRAVE_BROWSER_DRM_TAB_HELPER_H_
2 changes: 2 additions & 0 deletions browser/brave_tab_helpers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "brave/browser/brave_tab_helpers.h"

#include "brave/browser/brave_drm_tab_helper.h"
#include "brave/components/brave_ads/browser/ads_tab_helper.h"
#include "brave/components/brave_rewards/browser/buildflags/buildflags.h"
#include "content/public/browser/web_contents.h"
Expand All @@ -26,6 +27,7 @@ void AttachTabHelpers(content::WebContents* web_contents) {
brave_rewards::RewardsHelper::CreateForWebContents(web_contents);
#endif
// Add tab helpers here unless they are intended for android too
BraveDrmTabHelper::CreateForWebContents(web_contents);
#endif

brave_ads::AdsTabHelper::CreateForWebContents(web_contents);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ void BraveGenerateContentSettingImageModels(
std::vector<std::unique_ptr<ContentSettingImageModel>>& result) {
// Remove the cookies content setting image model
// https://github.com/brave/brave-browser/issues/1197
// TODO(iefremov): This changes break internal image models ordering which is
// based on enum values. This breaks tests and probably should be fixed
// (by adding more diff of course).
for (size_t i = 0; i < result.size(); i++) {
if (result[i]->image_type() ==
ContentSettingImageModel::ImageType::COOKIES) {
Expand Down
18 changes: 4 additions & 14 deletions browser/ui/content_settings/brave_widevine_blocked_image_model.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@

#include "brave/browser/ui/content_settings/brave_widevine_blocked_image_model.h"

#include "brave/common/pref_names.h"
#include "brave/common/shield_exceptions.h"
#include "brave/browser/brave_drm_tab_helper.h"
#include "brave/browser/ui/content_settings/brave_widevine_content_setting_bubble_model.h"
#include "brave/grit/brave_generated_resources.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/paint_vector_icon.h"
Expand All @@ -31,16 +28,9 @@ void BraveWidevineBlockedImageModel::UpdateFromWebContents(
if (!web_contents)
return;

// If the user alraedy opted in, don't show more UI
PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
if (prefs->GetBoolean(kWidevineOptedIn)) {
return;
}

// If the URL isn't one that we whitelist as a site that gets UI for
// Widevine to be installable, then don't show naything.
GURL url = web_contents->GetURL();
if (!brave::IsWidevineInstallableURL(url)) {
BraveDrmTabHelper* drm_helper =
BraveDrmTabHelper::FromWebContents(web_contents);
if (!drm_helper->ShouldShowWidevineOptIn()) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,24 @@
#include "brave/browser/ui/content_settings/brave_content_setting_bubble_model.h"
#include "brave/browser/ui/content_settings/brave_widevine_blocked_image_model.h"
#include "brave/browser/ui/content_settings/brave_widevine_content_setting_bubble_model.h"
#include "brave/browser/ui/views/location_bar/brave_location_bar_view.h"
#include "brave/common/brave_paths.h"
#include "brave/common/pref_names.h"
#include "brave/common/url_constants.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/location_bar/location_bar.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/test/browser_test_utils.h"
#include "components/prefs/pref_service.h"
#include "content/public/test/test_navigation_observer.h"
#include "net/dns/mock_host_resolver.h"
#include "third_party/widevine/cdm/buildflags.h"

using content::WebContents;
using ImageType = ContentSettingImageModel::ImageType;
Expand All @@ -41,11 +46,6 @@ class BraveWidevineBlockedImageModelBrowserTest : public InProcessBrowserTest {
return browser()->tab_strip_model()->GetActiveWebContents();
}

bool NavigateToURLUntilLoadStop(const GURL& url) {
ui_test_utils::NavigateToURL(browser(), url);
return WaitForLoadStop(active_contents());
}

std::unique_ptr<BraveWidevineBlockedImageModel> CreateModel() {
return std::make_unique<BraveWidevineBlockedImageModel>(
BraveWidevineBlockedImageModel::ImageType::PLUGINS,
Expand Down Expand Up @@ -115,7 +115,7 @@ IN_PROC_BROWSER_TEST_F(BraveWidevineBlockedImageModelBrowserTest,
IN_PROC_BROWSER_TEST_F(BraveWidevineBlockedImageModelBrowserTest,
RunPluginsOnPageClicked) {
GURL url = embedded_test_server()->GetURL("www.netflix.com", "/blank.html");
NavigateToURLUntilLoadStop(url);
ui_test_utils::NavigateToURL(browser(), url);

auto model = CreateModel();
Profile* profile = browser()->profile();
Expand Down Expand Up @@ -147,7 +147,7 @@ IN_PROC_BROWSER_TEST_F(BraveWidevineBlockedImageModelBrowserTest,
prefs->SetBoolean(kWidevineOptedIn, true);

GURL url = embedded_test_server()->GetURL("www.netflix.com", "/blank.html");
NavigateToURLUntilLoadStop(url);
ui_test_utils::NavigateToURL(browser(), url);

auto model = CreateModel();

Expand All @@ -162,3 +162,86 @@ IN_PROC_BROWSER_TEST_F(BraveWidevineBlockedImageModelBrowserTest,

ASSERT_FALSE(model->is_visible());
}

#if BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)
class BraveWidevineIconVisibilityBrowserTest : public InProcessBrowserTest {
public:
BraveWidevineIconVisibilityBrowserTest()
: https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}

void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();
host_resolver()->AddRule("*", "127.0.0.1");

// Chromium allows the API under test only on HTTPS domains.
base::FilePath test_data_dir;
base::PathService::Get(brave::DIR_TEST_DATA, &test_data_dir);
https_server_.ServeFilesFromDirectory(test_data_dir);
ASSERT_TRUE(https_server_.Start());
}

void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitchASCII(
"enable-blink-features",
"EncryptedMediaEncryptionSchemeQuery");
}

content::WebContents* active_contents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}

bool IsWidevineIconVisible() {
auto* location_bar = static_cast<BraveLocationBarView*>(
browser()->window()->GetLocationBar());

// TODO(iefremov): the hack with getting the proper view index is caused by
// changes in brave_content_setting_image_models.cc. Probably we need to
// refactor this to keep original indexes correct.
ContentSettingImageView* view =
location_bar->GetContentSettingsImageViewForTesting(
static_cast<size_t>(
ContentSettingImageModel::ImageType::NUM_IMAGE_TYPES)-1);
return view->visible();
}

protected:
net::EmbeddedTestServer https_server_;
};

IN_PROC_BROWSER_TEST_F(BraveWidevineIconVisibilityBrowserTest,
SuggestOptInIfWidevineDetected) {
GURL url = https_server_.GetURL("a.com", "/simple.html");
ui_test_utils::NavigateToURL(browser(), url);
EXPECT_FALSE(IsWidevineIconVisible());

const std::string drm_js =
"var config = [{initDataTypes: ['cenc']}];"
"navigator.requestMediaKeySystemAccess($1, config);";
const std::string widevine_js = content::JsReplace(drm_js,
"com.widevine.alpha");

EXPECT_TRUE(content::ExecuteScript(active_contents(), widevine_js));
EXPECT_TRUE(IsWidevineIconVisible());

// The icon should disappear after reload.
content::TestNavigationObserver observer(active_contents());
chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
observer.Wait();
EXPECT_FALSE(IsWidevineIconVisible());

// Navigate to a page with some videos.
url = https_server_.GetURL("a.com", "/media/youtube.html");
ui_test_utils::NavigateToURL(browser(), url);
EXPECT_FALSE(IsWidevineIconVisible());

// Check that non-widevine DRM is ignored.
EXPECT_TRUE(
content::ExecuteScript(active_contents(),
content::JsReplace(drm_js, "org.w3.clearkey")));
EXPECT_FALSE(IsWidevineIconVisible());

// Finally check the widevine request.
EXPECT_TRUE(content::ExecuteScript(active_contents(), widevine_js));
EXPECT_TRUE(IsWidevineIconVisible());
}
#endif // BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)
6 changes: 6 additions & 0 deletions browser/ui/views/location_bar/brave_location_bar_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ void BraveLocationBarView::ChildPreferredSizeChanged(views::View* child) {
Layout();
}

ContentSettingImageView*
BraveLocationBarView::GetContentSettingsImageViewForTesting(size_t idx) {
DCHECK(idx < content_setting_views_.size());
return content_setting_views_[idx];
}

// Provide base class implementation for Update override that has been added to
// header via a patch. This should never be called as the only instantiated
// implementation should be our |BraveLocationBarView|.
Expand Down
2 changes: 2 additions & 0 deletions browser/ui/views/location_bar/brave_location_bar_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class BraveLocationBarView : public LocationBarView {
void OnThemeChanged() override;
void ChildPreferredSizeChanged(views::View* child) override;

ContentSettingImageView* GetContentSettingsImageViewForTesting(size_t idx);

private:
void UpdateBookmarkStarVisibility() override;
OmniboxTint GetTint() override;
Expand Down
17 changes: 0 additions & 17 deletions common/shield_exceptions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -124,21 +124,4 @@ bool IsWhitelistedCookieExeption(const GURL& firstPartyOrigin,
});
}

bool IsWidevineInstallableURL(const GURL& url) {
static std::vector<URLPattern> patterns({
URLPattern(URLPattern::SCHEME_ALL, "https://www.netflix.com/*"),
URLPattern(URLPattern::SCHEME_ALL, "https://bitmovin.com/*"),
URLPattern(URLPattern::SCHEME_ALL, "https://www.primevideo.com/*"),
URLPattern(URLPattern::SCHEME_ALL, "https://www.spotify.com/*"),
URLPattern(URLPattern::SCHEME_ALL, "https://shaka-player-demo.appspot.com/*"),
URLPattern(URLPattern::SCHEME_ALL, "https://*.hulu.com/*"),
// Used for tests
URLPattern(URLPattern::SCHEME_ALL, "http://www.netflix.com:*/*")
});
return std::any_of(patterns.begin(), patterns.end(),
[&url](URLPattern pattern){
return pattern.MatchesURL(url);
});
}

}
1 change: 0 additions & 1 deletion common/shield_exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,5 @@ bool IsWhitelistedCookieExeption(const GURL& firstPartyOrigin,
const GURL& subresourceUrl);
bool IsWhitelistedReferrer(const GURL& firstPartyOrigin,
const GURL& subresourceUrl);
bool IsWidevineInstallableURL(const GURL& url);

} // namespace brave
31 changes: 0 additions & 31 deletions common/shield_exceptions_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,6 @@ namespace {
typedef testing::Test BraveShieldsExceptionsTest;
using brave::IsWhitelistedReferrer;

TEST_F(BraveShieldsExceptionsTest, WidevineInstallableURL) {
std::vector<GURL> urls({
GURL("https://www.netflix.com/"),
GURL("https://bitmovin.com/"),
GURL("https://www.primevideo.com/"),
GURL("https://www.spotify.com/"),
GURL("https://shaka-player-demo.appspot.com"),
GURL("https://www.netflix.com/subdir"),
GURL("https://bitmovin.com/subdir"),
GURL("https://www.primevideo.com/subdir"),
GURL("https://www.spotify.com/subdir"),
GURL("https://shaka-player-demo.appspot.com/subdir"),
GURL("https://hulu.com/watch/bf77880c-2f2e-4e09-b26d-5c7cc1de47ce")
});
std::for_each(urls.begin(), urls.end(),
[this](GURL url){
EXPECT_TRUE(brave::IsWidevineInstallableURL(url));
});
}

TEST_F(BraveShieldsExceptionsTest, NotWidevineInstallableURL) {
std::vector<GURL> urls({
GURL("https://www.brave.com/"),
GURL("https://widevine.com/")
});
std::for_each(urls.begin(), urls.end(),
[this](GURL url){
EXPECT_FALSE(brave::IsWidevineInstallableURL(url));
});
}

TEST_F(BraveShieldsExceptionsTest, IsWhitelistedReferrer) {
// *.fbcdn.net not allowed on some other URL
EXPECT_FALSE(IsWhitelistedReferrer(GURL("https://test.com"),
Expand Down
Loading

0 comments on commit c125186

Please sign in to comment.