1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/pepper_broker_infobar_delegate.h"
6
7#include "base/prefs/pref_service.h"
8#include "chrome/browser/content_settings/host_content_settings_map.h"
9#include "chrome/browser/content_settings/tab_specific_content_settings.h"
10#include "chrome/browser/infobars/infobar_service.h"
11#include "chrome/browser/plugins/plugin_finder.h"
12#include "chrome/browser/plugins/plugin_metadata.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/common/pref_names.h"
15#include "content/public/browser/page_navigator.h"
16#include "content/public/browser/plugin_service.h"
17#include "content/public/browser/user_metrics.h"
18#include "content/public/browser/web_contents.h"
19#include "content/public/common/referrer.h"
20#include "content/public/common/webplugininfo.h"
21#include "grit/generated_resources.h"
22#include "grit/theme_resources.h"
23#include "net/base/net_util.h"
24#include "ui/base/l10n/l10n_util.h"
25
26#if defined(GOOGLE_TV)
27#include "base/android/context_types.h"
28#endif
29
30
31// static
32void PepperBrokerInfoBarDelegate::Create(
33    content::WebContents* web_contents,
34    const GURL& url,
35    const base::FilePath& plugin_path,
36    const base::Callback<void(bool)>& callback) {
37  Profile* profile =
38      Profile::FromBrowserContext(web_contents->GetBrowserContext());
39  // TODO(wad): Add ephemeral device ID support for broker in guest mode.
40  if (profile->IsGuestSession()) {
41    callback.Run(false);
42    return;
43  }
44
45  TabSpecificContentSettings* tab_content_settings =
46      TabSpecificContentSettings::FromWebContents(web_contents);
47
48#if defined(OS_CHROMEOS)
49  // On ChromeOS, we're ok with granting broker access to the Netflix and
50  // Widevine plugins, since they can only come installed with the OS.
51  const char kWidevinePluginFileName[] = "libwidevinecdmadapter.so";
52  const char kNetflixDomain[] = "netflix.com";
53
54  base::FilePath plugin_file_name = plugin_path.BaseName();
55  if (plugin_file_name.value() == FILE_PATH_LITERAL(kWidevinePluginFileName) &&
56      url.DomainIs(kNetflixDomain)) {
57    tab_content_settings->SetPepperBrokerAllowed(true);
58    callback.Run(true);
59    return;
60  }
61#endif
62
63#if defined(GOOGLE_TV)
64  // On GoogleTV, Netflix crypto/mdx plugin and DRM server adapter plugin can
65  // only come pre-installed with the OS, so we're willing to auto-grant access
66  // to them. PluginRootName should be matched with PEPPER_PLUGIN_ROOT
67  // in PepperPluginManager.java.
68  const char kPluginRootName[] = "/system/lib/pepperplugin";
69  const char kNetflixCryptoPluginFileName[] = "libnrddpicrypto.so";
70  const char kNetflixMdxPluginFileName[] = "libnrdmdx.so";
71  const char kDrmServerAdapterPluginFileName[] = "libdrmserveradapter.so";
72  base::FilePath::StringType plugin_dir_name = plugin_path.DirName().value();
73  base::FilePath::StringType plugin_file_name = plugin_path.BaseName().value();
74  if (base::android::IsRunningInWebapp() &&
75      plugin_dir_name == FILE_PATH_LITERAL(kPluginRootName) &&
76      (plugin_file_name == FILE_PATH_LITERAL(kNetflixCryptoPluginFileName) ||
77       plugin_file_name == FILE_PATH_LITERAL(kNetflixMdxPluginFileName) ||
78       plugin_file_name ==
79          FILE_PATH_LITERAL(kDrmServerAdapterPluginFileName))) {
80    tab_content_settings->SetPepperBrokerAllowed(true);
81    callback.Run(true);
82    return;
83  }
84#endif
85
86  HostContentSettingsMap* content_settings =
87      profile->GetHostContentSettingsMap();
88  ContentSetting setting =
89      content_settings->GetContentSetting(url, url,
90                                          CONTENT_SETTINGS_TYPE_PPAPI_BROKER,
91                                          std::string());
92
93  if (setting == CONTENT_SETTING_ASK) {
94    content::RecordAction(
95        content::UserMetricsAction("PPAPI.BrokerInfobarDisplayed"));
96    InfoBarService* infobar_service =
97        InfoBarService::FromWebContents(web_contents);
98    infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
99        new PepperBrokerInfoBarDelegate(
100            infobar_service, url, plugin_path,
101            profile->GetPrefs()->GetString(prefs::kAcceptLanguages),
102            content_settings, tab_content_settings, callback)));
103    return;
104  }
105
106  bool allowed = (setting == CONTENT_SETTING_ALLOW);
107  content::RecordAction(allowed ?
108      content::UserMetricsAction("PPAPI.BrokerSettingAllow") :
109      content::UserMetricsAction("PPAPI.BrokerSettingDeny"));
110  tab_content_settings->SetPepperBrokerAllowed(allowed);
111  callback.Run(allowed);
112}
113
114PepperBrokerInfoBarDelegate::PepperBrokerInfoBarDelegate(
115    InfoBarService* infobar_service,
116    const GURL& url,
117    const base::FilePath& plugin_path,
118    const std::string& languages,
119    HostContentSettingsMap* content_settings,
120    TabSpecificContentSettings* tab_content_settings,
121    const base::Callback<void(bool)>& callback)
122    : ConfirmInfoBarDelegate(infobar_service),
123      url_(url),
124      plugin_path_(plugin_path),
125      languages_(languages),
126      content_settings_(content_settings),
127      tab_content_settings_(tab_content_settings),
128      callback_(callback) {
129}
130
131PepperBrokerInfoBarDelegate::~PepperBrokerInfoBarDelegate() {
132  if (!callback_.is_null())
133    callback_.Run(false);
134}
135
136int PepperBrokerInfoBarDelegate::GetIconID() const {
137  return IDR_INFOBAR_PLUGIN_INSTALL;
138}
139
140string16 PepperBrokerInfoBarDelegate::GetMessageText() const {
141  content::PluginService* plugin_service =
142      content::PluginService::GetInstance();
143  content::WebPluginInfo plugin;
144  bool success = plugin_service->GetPluginInfoByPath(plugin_path_, &plugin);
145  DCHECK(success);
146  scoped_ptr<PluginMetadata> plugin_metadata(
147      PluginFinder::GetInstance()->GetPluginMetadata(plugin));
148  return l10n_util::GetStringFUTF16(IDS_PEPPER_BROKER_MESSAGE,
149                                    plugin_metadata->name(),
150                                    net::FormatUrl(url_.GetOrigin(),
151                                                   languages_));
152}
153
154string16 PepperBrokerInfoBarDelegate::GetButtonLabel(
155    InfoBarButton button) const {
156  return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
157      IDS_PEPPER_BROKER_ALLOW_BUTTON : IDS_PEPPER_BROKER_DENY_BUTTON);
158}
159
160bool PepperBrokerInfoBarDelegate::Accept() {
161  DispatchCallback(true);
162  return true;
163}
164
165bool PepperBrokerInfoBarDelegate::Cancel() {
166  DispatchCallback(false);
167  return true;
168}
169
170string16 PepperBrokerInfoBarDelegate::GetLinkText() const {
171  return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
172}
173
174bool PepperBrokerInfoBarDelegate::LinkClicked(
175    WindowOpenDisposition disposition) {
176  GURL learn_more_url("https://support.google.com/chrome/?p=ib_pepper_broker");
177  web_contents()->OpenURL(content::OpenURLParams(
178      learn_more_url, content::Referrer(),
179      (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition,
180      content::PAGE_TRANSITION_LINK, false));
181  return false;
182}
183
184void PepperBrokerInfoBarDelegate::DispatchCallback(bool result) {
185  content::RecordAction(result ?
186      content::UserMetricsAction("PPAPI.BrokerInfobarClickedAllow") :
187      content::UserMetricsAction("PPAPI.BrokerInfobarClickedDeny"));
188  callback_.Run(result);
189  callback_ = base::Callback<void(bool)>();
190  content_settings_->SetContentSetting(
191      ContentSettingsPattern::FromURLNoWildcard(url_),
192      ContentSettingsPattern::Wildcard(),
193      CONTENT_SETTINGS_TYPE_PPAPI_BROKER,
194      std::string(), result ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK);
195  tab_content_settings_->SetPepperBrokerAllowed(result);
196}
197