Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / plugins_ui.cc
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/ui/webui/plugins_ui.h"
6
7 #include <algorithm>
8 #include <string>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/memory/ref_counted_memory.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/memory/singleton.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/path_service.h"
19 #include "base/prefs/pref_member.h"
20 #include "base/prefs/pref_service.h"
21 #include "base/prefs/scoped_user_pref_update.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/values.h"
24 #include "chrome/browser/chrome_notification_types.h"
25 #include "chrome/browser/content_settings/host_content_settings_map.h"
26 #include "chrome/browser/plugins/plugin_finder.h"
27 #include "chrome/browser/plugins/plugin_metadata.h"
28 #include "chrome/browser/plugins/plugin_prefs.h"
29 #include "chrome/browser/profiles/profile.h"
30 #include "chrome/browser/ui/browser.h"
31 #include "chrome/browser/ui/browser_window.h"
32 #include "chrome/common/chrome_content_client.h"
33 #include "chrome/common/chrome_paths.h"
34 #include "chrome/common/pref_names.h"
35 #include "chrome/common/url_constants.h"
36 #include "components/user_prefs/pref_registry_syncable.h"
37 #include "content/public/browser/notification_source.h"
38 #include "content/public/browser/plugin_service.h"
39 #include "content/public/browser/web_contents.h"
40 #include "content/public/browser/web_ui.h"
41 #include "content/public/browser/web_ui_data_source.h"
42 #include "content/public/browser/web_ui_message_handler.h"
43 #include "grit/browser_resources.h"
44 #include "grit/generated_resources.h"
45 #include "grit/theme_resources.h"
46 #include "ui/base/l10n/l10n_util.h"
47 #include "ui/base/resource/resource_bundle.h"
48
49 #if defined(OS_CHROMEOS)
50 #include "chrome/browser/ui/webui/chromeos/ui_account_tweaks.h"
51 #endif
52
53 using content::PluginService;
54 using content::WebContents;
55 using content::WebPluginInfo;
56 using content::WebUIMessageHandler;
57
58 namespace {
59
60 // Callback function to process result of EnablePlugin method.
61 void AssertPluginEnabled(bool did_enable) {
62   DCHECK(did_enable);
63 }
64
65 content::WebUIDataSource* CreatePluginsUIHTMLSource(Profile* profile) {
66   content::WebUIDataSource* source =
67       content::WebUIDataSource::Create(chrome::kChromeUIPluginsHost);
68   source->SetUseJsonJSFormatV2();
69
70   source->AddLocalizedString("pluginsTitle", IDS_PLUGINS_TITLE);
71   source->AddLocalizedString("pluginsDetailsModeLink",
72                              IDS_PLUGINS_DETAILS_MODE_LINK);
73   source->AddLocalizedString("pluginsNoneInstalled",
74                              IDS_PLUGINS_NONE_INSTALLED);
75   source->AddLocalizedString("pluginDisabled", IDS_PLUGINS_DISABLED_PLUGIN);
76   source->AddLocalizedString("pluginDisabledByPolicy",
77                              IDS_PLUGINS_DISABLED_BY_POLICY_PLUGIN);
78   source->AddLocalizedString("pluginEnabledByPolicy",
79                              IDS_PLUGINS_ENABLED_BY_POLICY_PLUGIN);
80   source->AddLocalizedString("pluginGroupManagedByPolicy",
81                              IDS_PLUGINS_GROUP_MANAGED_BY_POLICY);
82   source->AddLocalizedString("pluginDownload", IDS_PLUGINS_DOWNLOAD);
83   source->AddLocalizedString("pluginName", IDS_PLUGINS_NAME);
84   source->AddLocalizedString("pluginVersion", IDS_PLUGINS_VERSION);
85   source->AddLocalizedString("pluginDescription", IDS_PLUGINS_DESCRIPTION);
86   source->AddLocalizedString("pluginPath", IDS_PLUGINS_PATH);
87   source->AddLocalizedString("pluginType", IDS_PLUGINS_TYPE);
88   source->AddLocalizedString("pluginMimeTypes", IDS_PLUGINS_MIME_TYPES);
89   source->AddLocalizedString("pluginMimeTypesMimeType",
90                              IDS_PLUGINS_MIME_TYPES_MIME_TYPE);
91   source->AddLocalizedString("pluginMimeTypesDescription",
92                              IDS_PLUGINS_MIME_TYPES_DESCRIPTION);
93   source->AddLocalizedString("pluginMimeTypesFileExtensions",
94                              IDS_PLUGINS_MIME_TYPES_FILE_EXTENSIONS);
95   source->AddLocalizedString("disable", IDS_PLUGINS_DISABLE);
96   source->AddLocalizedString("enable", IDS_PLUGINS_ENABLE);
97   source->AddLocalizedString("alwaysAllowed", IDS_PLUGINS_ALWAYS_ALLOWED);
98   source->AddLocalizedString("noPlugins", IDS_PLUGINS_NO_PLUGINS);
99
100   source->SetJsonPath("strings.js");
101   source->AddResourcePath("plugins.js", IDR_PLUGINS_JS);
102   source->SetDefaultResource(IDR_PLUGINS_HTML);
103 #if defined(OS_CHROMEOS)
104   chromeos::AddAccountUITweaksLocalizedValues(source, profile);
105 #endif
106   return source;
107 }
108
109 base::string16 PluginTypeToString(int type) {
110   // The type is stored as an |int|, but doing the switch on the right
111   // enumeration type gives us better build-time error checking (if someone adds
112   // a new type).
113   switch (static_cast<WebPluginInfo::PluginType>(type)) {
114     case WebPluginInfo::PLUGIN_TYPE_NPAPI:
115       return l10n_util::GetStringUTF16(IDS_PLUGINS_NPAPI);
116     case WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS:
117       return l10n_util::GetStringUTF16(IDS_PLUGINS_PPAPI_IN_PROCESS);
118     case WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS:
119       return l10n_util::GetStringUTF16(IDS_PLUGINS_PPAPI_OUT_OF_PROCESS);
120     case WebPluginInfo::PLUGIN_TYPE_PEPPER_UNSANDBOXED:
121       return l10n_util::GetStringUTF16(IDS_PLUGINS_PPAPI_UNSANDBOXED);
122   }
123   NOTREACHED();
124   return base::string16();
125 }
126
127 ////////////////////////////////////////////////////////////////////////////////
128 //
129 // PluginsDOMHandler
130 //
131 ////////////////////////////////////////////////////////////////////////////////
132
133 // The handler for Javascript messages for the chrome://plugins/ page.
134 // TODO(viettrungluu): Make plugin list updates notify, and then observe
135 // changes; maybe replumb plugin list through plugin service?
136 // <http://crbug.com/39101>
137 class PluginsDOMHandler : public WebUIMessageHandler,
138                           public content::NotificationObserver {
139  public:
140   explicit PluginsDOMHandler();
141   virtual ~PluginsDOMHandler() {}
142
143   // WebUIMessageHandler implementation.
144   virtual void RegisterMessages() OVERRIDE;
145
146   // Callback for the "requestPluginsData" message.
147   void HandleRequestPluginsData(const base::ListValue* args);
148
149   // Callback for the "enablePlugin" message.
150   void HandleEnablePluginMessage(const base::ListValue* args);
151
152   // Callback for the "saveShowDetailsToPrefs" message.
153   void HandleSaveShowDetailsToPrefs(const base::ListValue* args);
154
155   // Calback for the "getShowDetails" message.
156   void HandleGetShowDetails(const base::ListValue* args);
157
158   // Callback for the "setPluginAlwaysAllowed" message.
159   void HandleSetPluginAlwaysAllowed(const base::ListValue* args);
160
161   // content::NotificationObserver method overrides
162   virtual void Observe(int type,
163                        const content::NotificationSource& source,
164                        const content::NotificationDetails& details) OVERRIDE;
165
166  private:
167   void LoadPlugins();
168
169   // Called on the UI thread when the plugin information is ready.
170   void PluginsLoaded(const std::vector<WebPluginInfo>& plugins);
171
172   content::NotificationRegistrar registrar_;
173
174   // Holds grouped plug-ins. The key is the group identifier and
175   // the value is the list of plug-ins belonging to the group.
176   typedef base::hash_map<std::string, std::vector<const WebPluginInfo*> >
177       PluginGroups;
178
179   // This pref guards the value whether about:plugins is in the details mode or
180   // not.
181   BooleanPrefMember show_details_;
182
183   base::WeakPtrFactory<PluginsDOMHandler> weak_ptr_factory_;
184
185   DISALLOW_COPY_AND_ASSIGN(PluginsDOMHandler);
186 };
187
188 PluginsDOMHandler::PluginsDOMHandler()
189     : weak_ptr_factory_(this) {
190 }
191
192 void PluginsDOMHandler::RegisterMessages() {
193   Profile* profile = Profile::FromWebUI(web_ui());
194
195   PrefService* prefs = profile->GetPrefs();
196   show_details_.Init(prefs::kPluginsShowDetails, prefs);
197
198   registrar_.Add(this,
199                  chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED,
200                  content::Source<Profile>(profile));
201
202   web_ui()->RegisterMessageCallback("requestPluginsData",
203       base::Bind(&PluginsDOMHandler::HandleRequestPluginsData,
204                  base::Unretained(this)));
205   web_ui()->RegisterMessageCallback("enablePlugin",
206       base::Bind(&PluginsDOMHandler::HandleEnablePluginMessage,
207                  base::Unretained(this)));
208   web_ui()->RegisterMessageCallback("setPluginAlwaysAllowed",
209       base::Bind(&PluginsDOMHandler::HandleSetPluginAlwaysAllowed,
210                  base::Unretained(this)));
211   web_ui()->RegisterMessageCallback("saveShowDetailsToPrefs",
212       base::Bind(&PluginsDOMHandler::HandleSaveShowDetailsToPrefs,
213                  base::Unretained(this)));
214   web_ui()->RegisterMessageCallback("getShowDetails",
215       base::Bind(&PluginsDOMHandler::HandleGetShowDetails,
216                  base::Unretained(this)));
217 }
218
219 void PluginsDOMHandler::HandleRequestPluginsData(const base::ListValue* args) {
220   LoadPlugins();
221 }
222
223 void PluginsDOMHandler::HandleEnablePluginMessage(const base::ListValue* args) {
224   Profile* profile = Profile::FromWebUI(web_ui());
225
226   // Be robust in accepting badness since plug-ins display HTML (hence
227   // JavaScript).
228   if (args->GetSize() != 3) {
229     NOTREACHED();
230     return;
231   }
232
233   std::string enable_str;
234   std::string is_group_str;
235   if (!args->GetString(1, &enable_str) || !args->GetString(2, &is_group_str)) {
236     NOTREACHED();
237     return;
238   }
239   bool enable = enable_str == "true";
240
241   PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile).get();
242   if (is_group_str == "true") {
243     base::string16 group_name;
244     if (!args->GetString(0, &group_name)) {
245       NOTREACHED();
246       return;
247     }
248
249     plugin_prefs->EnablePluginGroup(enable, group_name);
250     if (enable) {
251       // See http://crbug.com/50105 for background.
252       base::string16 adobereader = base::ASCIIToUTF16(
253           PluginMetadata::kAdobeReaderGroupName);
254       base::string16 internalpdf =
255           base::ASCIIToUTF16(ChromeContentClient::kPDFPluginName);
256       if (group_name == adobereader)
257         plugin_prefs->EnablePluginGroup(false, internalpdf);
258       else if (group_name == internalpdf)
259         plugin_prefs->EnablePluginGroup(false, adobereader);
260     }
261   } else {
262     base::FilePath::StringType file_path;
263     if (!args->GetString(0, &file_path)) {
264       NOTREACHED();
265       return;
266     }
267
268     plugin_prefs->EnablePlugin(enable, base::FilePath(file_path),
269                                base::Bind(&AssertPluginEnabled));
270   }
271 }
272
273 void PluginsDOMHandler::HandleSaveShowDetailsToPrefs(
274     const base::ListValue* args) {
275   std::string details_mode;
276   if (!args->GetString(0, &details_mode)) {
277     NOTREACHED();
278     return;
279   }
280   show_details_.SetValue(details_mode == "true");
281 }
282
283 void PluginsDOMHandler::HandleGetShowDetails(const base::ListValue* args) {
284   base::FundamentalValue show_details(show_details_.GetValue());
285   web_ui()->CallJavascriptFunction("loadShowDetailsFromPrefs", show_details);
286 }
287
288 void PluginsDOMHandler::HandleSetPluginAlwaysAllowed(
289     const base::ListValue* args) {
290   // Be robust in the input parameters, but crash in a Debug build.
291   if (args->GetSize() != 2) {
292     NOTREACHED();
293     return;
294   }
295
296   std::string plugin;
297   bool allowed = false;
298   if (!args->GetString(0, &plugin) || !args->GetBoolean(1, &allowed)) {
299     NOTREACHED();
300     return;
301   }
302   Profile* profile = Profile::FromWebUI(web_ui());
303   profile->GetHostContentSettingsMap()->SetContentSetting(
304       ContentSettingsPattern::Wildcard(),
305       ContentSettingsPattern::Wildcard(),
306       CONTENT_SETTINGS_TYPE_PLUGINS,
307       plugin,
308       allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_DEFAULT);
309
310   // Keep track of the whitelist separately, so that we can distinguish plug-ins
311   // whitelisted by the user from automatically whitelisted ones.
312   DictionaryPrefUpdate update(profile->GetPrefs(),
313                               prefs::kContentSettingsPluginWhitelist);
314   update->SetBoolean(plugin, allowed);
315 }
316
317 void PluginsDOMHandler::Observe(int type,
318                                 const content::NotificationSource& source,
319                                 const content::NotificationDetails& details) {
320   DCHECK_EQ(chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED, type);
321   LoadPlugins();
322 }
323
324 void PluginsDOMHandler::LoadPlugins() {
325   if (weak_ptr_factory_.HasWeakPtrs())
326     return;
327
328   PluginService::GetInstance()->GetPlugins(
329       base::Bind(&PluginsDOMHandler::PluginsLoaded,
330                  weak_ptr_factory_.GetWeakPtr()));
331 }
332
333 void PluginsDOMHandler::PluginsLoaded(
334     const std::vector<WebPluginInfo>& plugins) {
335   Profile* profile = Profile::FromWebUI(web_ui());
336   PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile).get();
337
338   ContentSettingsPattern wildcard = ContentSettingsPattern::Wildcard();
339
340   PluginFinder* plugin_finder = PluginFinder::GetInstance();
341   // Group plug-ins by identifier. This is done to be able to display
342   // the plug-ins in UI in a grouped fashion.
343   PluginGroups groups;
344   for (size_t i = 0; i < plugins.size(); ++i) {
345     scoped_ptr<PluginMetadata> plugin(
346         plugin_finder->GetPluginMetadata(plugins[i]));
347     groups[plugin->identifier()].push_back(&plugins[i]);
348   }
349
350   // Construct DictionaryValues to return to UI.
351   base::ListValue* plugin_groups_data = new base::ListValue();
352   for (PluginGroups::const_iterator it = groups.begin();
353       it != groups.end(); ++it) {
354     const std::vector<const WebPluginInfo*>& group_plugins = it->second;
355     base::ListValue* plugin_files = new base::ListValue();
356     scoped_ptr<PluginMetadata> plugin_metadata(
357         plugin_finder->GetPluginMetadata(*group_plugins[0]));
358     base::string16 group_name = plugin_metadata->name();
359     std::string group_identifier = plugin_metadata->identifier();
360     bool group_enabled = false;
361     bool all_plugins_enabled_by_policy = true;
362     bool all_plugins_disabled_by_policy = true;
363     bool all_plugins_managed_by_policy = true;
364     const WebPluginInfo* active_plugin = NULL;
365     for (size_t j = 0; j < group_plugins.size(); ++j) {
366       const WebPluginInfo& group_plugin = *group_plugins[j];
367
368       base::DictionaryValue* plugin_file = new base::DictionaryValue();
369       plugin_file->SetString("name", group_plugin.name);
370       plugin_file->SetString("description", group_plugin.desc);
371       plugin_file->SetString("path", group_plugin.path.value());
372       plugin_file->SetString("version", group_plugin.version);
373       plugin_file->SetString("type", PluginTypeToString(group_plugin.type));
374
375       base::ListValue* mime_types = new base::ListValue();
376       const std::vector<content::WebPluginMimeType>& plugin_mime_types =
377           group_plugin.mime_types;
378       for (size_t k = 0; k < plugin_mime_types.size(); ++k) {
379         base::DictionaryValue* mime_type = new base::DictionaryValue();
380         mime_type->SetString("mimeType", plugin_mime_types[k].mime_type);
381         mime_type->SetString("description", plugin_mime_types[k].description);
382
383         base::ListValue* file_extensions = new base::ListValue();
384         const std::vector<std::string>& mime_file_extensions =
385             plugin_mime_types[k].file_extensions;
386         for (size_t l = 0; l < mime_file_extensions.size(); ++l) {
387           file_extensions->Append(
388               new base::StringValue(mime_file_extensions[l]));
389         }
390         mime_type->Set("fileExtensions", file_extensions);
391
392         mime_types->Append(mime_type);
393       }
394       plugin_file->Set("mimeTypes", mime_types);
395
396       bool plugin_enabled = plugin_prefs->IsPluginEnabled(group_plugin);
397
398       if (!active_plugin || (plugin_enabled && !group_enabled))
399         active_plugin = &group_plugin;
400       group_enabled = plugin_enabled || group_enabled;
401
402       std::string enabled_mode;
403       PluginPrefs::PolicyStatus plugin_status =
404           plugin_prefs->PolicyStatusForPlugin(group_plugin.name);
405       PluginPrefs::PolicyStatus group_status =
406           plugin_prefs->PolicyStatusForPlugin(group_name);
407       if (plugin_status == PluginPrefs::POLICY_ENABLED ||
408           group_status == PluginPrefs::POLICY_ENABLED) {
409         enabled_mode = "enabledByPolicy";
410         all_plugins_disabled_by_policy = false;
411       } else {
412         all_plugins_enabled_by_policy = false;
413         if (plugin_status == PluginPrefs::POLICY_DISABLED ||
414             group_status == PluginPrefs::POLICY_DISABLED) {
415           enabled_mode = "disabledByPolicy";
416         } else {
417           all_plugins_disabled_by_policy = false;
418           all_plugins_managed_by_policy = false;
419           if (plugin_enabled) {
420             enabled_mode = "enabledByUser";
421           } else {
422             enabled_mode = "disabledByUser";
423           }
424         }
425       }
426       plugin_file->SetString("enabledMode", enabled_mode);
427
428       plugin_files->Append(plugin_file);
429     }
430     base::DictionaryValue* group_data = new base::DictionaryValue();
431
432     group_data->Set("plugin_files", plugin_files);
433     group_data->SetString("name", group_name);
434     group_data->SetString("id", group_identifier);
435     group_data->SetString("description", active_plugin->desc);
436     group_data->SetString("version", active_plugin->version);
437
438 #if defined(ENABLE_PLUGIN_INSTALLATION)
439     bool out_of_date = plugin_metadata->GetSecurityStatus(*active_plugin) ==
440         PluginMetadata::SECURITY_STATUS_OUT_OF_DATE;
441     group_data->SetBoolean("critical", out_of_date);
442     group_data->SetString("update_url", plugin_metadata->plugin_url().spec());
443 #endif
444
445     std::string enabled_mode;
446     if (all_plugins_enabled_by_policy) {
447       enabled_mode = "enabledByPolicy";
448     } else if (all_plugins_disabled_by_policy) {
449       enabled_mode = "disabledByPolicy";
450     } else if (all_plugins_managed_by_policy) {
451       enabled_mode = "managedByPolicy";
452     } else if (group_enabled) {
453       enabled_mode = "enabledByUser";
454     } else {
455       enabled_mode = "disabledByUser";
456     }
457     group_data->SetString("enabledMode", enabled_mode);
458
459     bool always_allowed = false;
460     if (group_enabled) {
461       const base::DictionaryValue* whitelist =
462           profile->GetPrefs()->GetDictionary(
463               prefs::kContentSettingsPluginWhitelist);
464       whitelist->GetBoolean(group_identifier, &always_allowed);
465     }
466     group_data->SetBoolean("alwaysAllowed", always_allowed);
467
468     plugin_groups_data->Append(group_data);
469   }
470   base::DictionaryValue results;
471   results.Set("plugins", plugin_groups_data);
472   web_ui()->CallJavascriptFunction("returnPluginsData", results);
473 }
474
475 }  // namespace
476
477 ///////////////////////////////////////////////////////////////////////////////
478 //
479 // PluginsUI
480 //
481 ///////////////////////////////////////////////////////////////////////////////
482
483 PluginsUI::PluginsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
484   web_ui->AddMessageHandler(new PluginsDOMHandler());
485
486   // Set up the chrome://plugins/ source.
487   Profile* profile = Profile::FromWebUI(web_ui);
488   content::WebUIDataSource::Add(profile, CreatePluginsUIHTMLSource(profile));
489 }
490
491 // static
492 base::RefCountedMemory* PluginsUI::GetFaviconResourceBytes(
493       ui::ScaleFactor scale_factor) {
494   return ResourceBundle::GetSharedInstance().
495       LoadDataResourceBytesForScale(IDR_PLUGINS_FAVICON, scale_factor);
496 }
497
498 // static
499 void PluginsUI::RegisterProfilePrefs(
500     user_prefs::PrefRegistrySyncable* registry) {
501   registry->RegisterBooleanPref(
502       prefs::kPluginsShowDetails,
503       false,
504       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
505   registry->RegisterDictionaryPref(
506       prefs::kContentSettingsPluginWhitelist,
507       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
508 }