| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 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/plugins_handler.h" | |
| 6 | |
| 7 #include <memory> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/bind_helpers.h" | |
| 12 #include "base/files/file_path.h" | |
| 13 #include "base/path_service.h" | |
| 14 #include "base/strings/utf_string_conversions.h" | |
| 15 #include "chrome/browser/chrome_notification_types.h" | |
| 16 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" | |
| 17 #include "chrome/browser/plugins/plugin_finder.h" | |
| 18 #include "chrome/browser/plugins/plugin_metadata.h" | |
| 19 #include "chrome/browser/plugins/plugin_prefs.h" | |
| 20 #include "chrome/browser/profiles/profile.h" | |
| 21 #include "chrome/common/chrome_content_client.h" | |
| 22 #include "chrome/common/chrome_paths.h" | |
| 23 #include "chrome/common/features.h" | |
| 24 #include "chrome/common/pepper_flash.h" | |
| 25 #include "chrome/common/pref_names.h" | |
| 26 #include "chrome/grit/generated_resources.h" | |
| 27 #include "components/content_settings/core/browser/host_content_settings_map.h" | |
| 28 #include "components/prefs/pref_service.h" | |
| 29 #include "components/prefs/scoped_user_pref_update.h" | |
| 30 #include "content/public/browser/notification_observer.h" | |
| 31 #include "content/public/browser/plugin_service.h" | |
| 32 #include "content/public/browser/web_ui.h" | |
| 33 #include "content/public/common/content_constants.h" | |
| 34 #include "ui/base/l10n/l10n_util.h" | |
| 35 | |
| 36 using content::WebPluginInfo; | |
| 37 // Holds grouped plugins. The key is the group identifier and | |
| 38 // the value is the list of plugins belonging to the group. | |
| 39 using PluginGroups = | |
| 40 base::hash_map<std::string, std::vector<const content::WebPluginInfo*>>; | |
| 41 | |
| 42 namespace { | |
| 43 | |
| 44 base::string16 PluginTypeToString(int type) { | |
| 45 // The type is stored as an |int|, but doing the switch on the right | |
| 46 // enumeration type gives us better build-time error checking (if someone adds | |
| 47 // a new type). | |
| 48 switch (static_cast<WebPluginInfo::PluginType>(type)) { | |
| 49 case WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS: | |
| 50 return l10n_util::GetStringUTF16(IDS_PLUGINS_PPAPI_IN_PROCESS); | |
| 51 case WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS: | |
| 52 return l10n_util::GetStringUTF16(IDS_PLUGINS_PPAPI_OUT_OF_PROCESS); | |
| 53 case WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN: | |
| 54 return l10n_util::GetStringUTF16(IDS_PLUGINS_BROWSER_PLUGIN); | |
| 55 } | |
| 56 NOTREACHED(); | |
| 57 return base::string16(); | |
| 58 } | |
| 59 | |
| 60 base::string16 GetPluginDescription(const WebPluginInfo& plugin) { | |
| 61 // If this plugin is Pepper Flash, and the plugin path is the same as the | |
| 62 // path for the Pepper Flash System plugin, then mark this plugin | |
| 63 // description as the system plugin to help the user disambiguate the | |
| 64 // two plugins. | |
| 65 base::string16 desc = plugin.desc; | |
| 66 if (plugin.is_pepper_plugin() && | |
| 67 plugin.name == base::ASCIIToUTF16(content::kFlashPluginName)) { | |
| 68 base::FilePath system_flash_path; | |
| 69 PathService::Get(chrome::FILE_PEPPER_FLASH_SYSTEM_PLUGIN, | |
| 70 &system_flash_path); | |
| 71 if (base::FilePath::CompareEqualIgnoreCase(plugin.path.value(), | |
| 72 system_flash_path.value())) { | |
| 73 if (chrome::IsSystemFlashScriptDebuggerPresent()) | |
| 74 desc += base::ASCIIToUTF16(" Debug"); | |
| 75 else | |
| 76 desc += base::ASCIIToUTF16(" System"); | |
| 77 } | |
| 78 } | |
| 79 return desc; | |
| 80 } | |
| 81 | |
| 82 std::vector<mojom::MimeTypePtr> GeneratePluginMimeTypes( | |
| 83 const WebPluginInfo& plugin) { | |
| 84 std::vector<mojom::MimeTypePtr> mime_types; | |
| 85 mime_types.reserve(plugin.mime_types.size()); | |
| 86 for (const auto& plugin_mime_type : plugin.mime_types) { | |
| 87 mojom::MimeTypePtr mime_type(mojom::MimeType::New()); | |
| 88 mime_type->description = base::UTF16ToUTF8(plugin_mime_type.description); | |
| 89 mime_type->mime_type = plugin_mime_type.mime_type; | |
| 90 mime_type->file_extensions = plugin_mime_type.file_extensions; | |
| 91 mime_types.push_back(std::move(mime_type)); | |
| 92 } | |
| 93 | |
| 94 return mime_types; | |
| 95 } | |
| 96 | |
| 97 } // namespace | |
| 98 | |
| 99 PluginsPageHandler::PluginsPageHandler( | |
| 100 content::WebUI* web_ui, | |
| 101 mojo::InterfaceRequest<mojom::PluginsPageHandler> request) | |
| 102 : web_ui_(web_ui), | |
| 103 binding_(this, std::move(request)), | |
| 104 weak_ptr_factory_(this) { | |
| 105 Profile* profile = Profile::FromWebUI(web_ui_); | |
| 106 PrefService* prefs = profile->GetPrefs(); | |
| 107 show_details_.Init(prefs::kPluginsShowDetails, prefs); | |
| 108 | |
| 109 registrar_.Add(this, chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED, | |
| 110 content::Source<Profile>(profile)); | |
| 111 } | |
| 112 | |
| 113 PluginsPageHandler::~PluginsPageHandler() {} | |
| 114 | |
| 115 void PluginsPageHandler::GetShowDetails( | |
| 116 const GetShowDetailsCallback& callback) { | |
| 117 callback.Run(show_details_.GetValue()); | |
| 118 } | |
| 119 | |
| 120 void PluginsPageHandler::SaveShowDetailsToPrefs(bool details_mode) { | |
| 121 show_details_.SetValue(details_mode); | |
| 122 } | |
| 123 | |
| 124 void PluginsPageHandler::SetPluginAlwaysAllowed(const std::string& plugin, | |
| 125 bool allowed) { | |
| 126 Profile* profile = Profile::FromWebUI(web_ui_); | |
| 127 HostContentSettingsMapFactory::GetForProfile(profile) | |
| 128 ->SetContentSettingCustomScope( | |
| 129 ContentSettingsPattern::Wildcard(), | |
| 130 ContentSettingsPattern::Wildcard(), CONTENT_SETTINGS_TYPE_PLUGINS, | |
| 131 plugin, allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_DEFAULT); | |
| 132 | |
| 133 // Keep track of the whitelist separately, so that we can distinguish plugins | |
| 134 // whitelisted by the user from automatically whitelisted ones. | |
| 135 DictionaryPrefUpdate update(profile->GetPrefs(), | |
| 136 prefs::kContentSettingsPluginWhitelist); | |
| 137 update->SetBoolean(plugin, allowed); | |
| 138 } | |
| 139 | |
| 140 void PluginsPageHandler::GetPluginsData( | |
| 141 const GetPluginsDataCallback& callback) { | |
| 142 if (weak_ptr_factory_.HasWeakPtrs()) | |
| 143 return; | |
| 144 | |
| 145 content::PluginService::GetInstance()->GetPlugins( | |
| 146 base::Bind(&PluginsPageHandler::RespondWithPluginsData, | |
| 147 weak_ptr_factory_.GetWeakPtr(), callback)); | |
| 148 } | |
| 149 | |
| 150 void PluginsPageHandler::SetClientPage(mojom::PluginsPagePtr page) { | |
| 151 page_ = std::move(page); | |
| 152 } | |
| 153 | |
| 154 void PluginsPageHandler::Observe(int type, | |
| 155 const content::NotificationSource& source, | |
| 156 const content::NotificationDetails& details) { | |
| 157 DCHECK_EQ(chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED, type); | |
| 158 | |
| 159 if (weak_ptr_factory_.HasWeakPtrs()) | |
| 160 return; | |
| 161 | |
| 162 content::PluginService::GetInstance()->GetPlugins( | |
| 163 base::Bind(&PluginsPageHandler::NotifyWithPluginsData, | |
| 164 weak_ptr_factory_.GetWeakPtr())); | |
| 165 } | |
| 166 | |
| 167 void PluginsPageHandler::RespondWithPluginsData( | |
| 168 const GetPluginsDataCallback& callback, | |
| 169 const std::vector<WebPluginInfo>& plugins) { | |
| 170 callback.Run(GeneratePluginsData(plugins)); | |
| 171 } | |
| 172 | |
| 173 void PluginsPageHandler::NotifyWithPluginsData( | |
| 174 const std::vector<WebPluginInfo>& plugins) { | |
| 175 if (page_) | |
| 176 page_->OnPluginsUpdated(GeneratePluginsData(plugins)); | |
| 177 } | |
| 178 | |
| 179 std::vector<mojom::PluginDataPtr> PluginsPageHandler::GeneratePluginsData( | |
| 180 const std::vector<WebPluginInfo>& plugins) { | |
| 181 Profile* profile = Profile::FromWebUI(web_ui_); | |
| 182 PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile).get(); | |
| 183 | |
| 184 PluginFinder* plugin_finder = PluginFinder::GetInstance(); | |
| 185 // Group plugins by identifier. This is done to be able to display | |
| 186 // the plugins in UI in a grouped fashion. | |
| 187 PluginGroups groups; | |
| 188 for (size_t i = 0; i < plugins.size(); ++i) { | |
| 189 std::unique_ptr<PluginMetadata> plugin( | |
| 190 plugin_finder->GetPluginMetadata(plugins[i])); | |
| 191 groups[plugin->identifier()].push_back(&plugins[i]); | |
| 192 } | |
| 193 | |
| 194 std::vector<mojom::PluginDataPtr> plugins_data; | |
| 195 plugins_data.reserve(groups.size()); | |
| 196 for (PluginGroups::const_iterator it = groups.begin(); it != groups.end(); | |
| 197 ++it) { | |
| 198 mojom::PluginDataPtr plugin_data(mojom::PluginData::New()); | |
| 199 const std::vector<const WebPluginInfo*>& group_plugins = it->second; | |
| 200 | |
| 201 std::unique_ptr<PluginMetadata> plugin_metadata( | |
| 202 plugin_finder->GetPluginMetadata(*group_plugins[0])); | |
| 203 std::string group_identifier = plugin_metadata->identifier(); | |
| 204 plugin_data->id = group_identifier; | |
| 205 | |
| 206 const WebPluginInfo* active_plugin = nullptr; | |
| 207 bool group_enabled = false; | |
| 208 | |
| 209 std::vector<mojom::PluginFilePtr> plugin_files; | |
| 210 plugin_files.reserve(group_plugins.size()); | |
| 211 for (const auto* group_plugin : group_plugins) { | |
| 212 bool plugin_enabled = plugin_prefs->IsPluginEnabled(*group_plugin); | |
| 213 | |
| 214 plugin_files.push_back(GeneratePluginFile( | |
| 215 *group_plugin, plugin_metadata->name(), plugin_enabled)); | |
| 216 | |
| 217 // Update |active_plugin| and |group_enabled|. | |
| 218 if (!active_plugin || (plugin_enabled && !group_enabled)) | |
| 219 active_plugin = group_plugin; | |
| 220 group_enabled = plugin_enabled || group_enabled; | |
| 221 } | |
| 222 | |
| 223 plugin_data->enabled_mode = | |
| 224 GetPluginGroupEnabledMode(plugin_files, group_enabled); | |
| 225 | |
| 226 plugin_data->always_allowed = false; | |
| 227 plugin_data->trusted = false; | |
| 228 plugin_data->policy_click_to_play = GetClickToPlayPolicyEnabled(); | |
| 229 | |
| 230 if (group_enabled) { | |
| 231 if (plugin_metadata->GetSecurityStatus(*active_plugin) == | |
| 232 PluginMetadata::SECURITY_STATUS_FULLY_TRUSTED) { | |
| 233 plugin_data->trusted = true; | |
| 234 plugin_data->always_allowed = true; | |
| 235 } else if (!GetClickToPlayPolicyEnabled()) { | |
| 236 const base::DictionaryValue* whitelist = | |
| 237 profile->GetPrefs()->GetDictionary( | |
| 238 prefs::kContentSettingsPluginWhitelist); | |
| 239 whitelist->GetBoolean(group_identifier, &plugin_data->always_allowed); | |
| 240 } | |
| 241 } | |
| 242 | |
| 243 plugin_data->critical = false; | |
| 244 plugin_data->update_url = ""; | |
| 245 #if BUILDFLAG(ENABLE_PLUGIN_INSTALLATION) | |
| 246 bool out_of_date = plugin_metadata->GetSecurityStatus(*active_plugin) == | |
| 247 PluginMetadata::SECURITY_STATUS_OUT_OF_DATE; | |
| 248 plugin_data->critical = out_of_date; | |
| 249 plugin_data->update_url = plugin_metadata->plugin_url().spec(); | |
| 250 #endif | |
| 251 | |
| 252 plugin_data->description = base::UTF16ToUTF8(active_plugin->desc); | |
| 253 plugin_data->name = base::UTF16ToUTF8(plugin_metadata->name()); | |
| 254 plugin_data->plugin_files = std::move(plugin_files); | |
| 255 plugin_data->version = base::UTF16ToUTF8(active_plugin->version); | |
| 256 plugins_data.push_back(std::move(plugin_data)); | |
| 257 } | |
| 258 | |
| 259 return plugins_data; | |
| 260 } | |
| 261 | |
| 262 bool PluginsPageHandler::GetClickToPlayPolicyEnabled() const { | |
| 263 Profile* profile = Profile::FromWebUI(web_ui_); | |
| 264 HostContentSettingsMap* map = | |
| 265 HostContentSettingsMapFactory::GetForProfile(profile); | |
| 266 std::string provider_id; | |
| 267 ContentSetting setting = map->GetDefaultContentSetting( | |
| 268 CONTENT_SETTINGS_TYPE_PLUGINS, &provider_id); | |
| 269 return (setting == CONTENT_SETTING_ASK && provider_id == "policy"); | |
| 270 } | |
| 271 | |
| 272 mojom::PluginFilePtr PluginsPageHandler::GeneratePluginFile( | |
| 273 const WebPluginInfo& plugin, | |
| 274 const base::string16& group_name, | |
| 275 bool plugin_enabled) const { | |
| 276 mojom::PluginFilePtr plugin_file(mojom::PluginFile::New()); | |
| 277 plugin_file->description = base::UTF16ToUTF8(GetPluginDescription(plugin)); | |
| 278 plugin_file->enabled_mode = | |
| 279 GetPluginEnabledMode(plugin.name, group_name, plugin_enabled); | |
| 280 plugin_file->name = base::UTF16ToUTF8(plugin.name); | |
| 281 plugin_file->path = plugin.path.AsUTF8Unsafe(); | |
| 282 plugin_file->type = base::UTF16ToUTF8(PluginTypeToString(plugin.type)); | |
| 283 plugin_file->version = base::UTF16ToUTF8(plugin.version); | |
| 284 plugin_file->mime_types = GeneratePluginMimeTypes(plugin); | |
| 285 | |
| 286 return plugin_file; | |
| 287 } | |
| 288 | |
| 289 std::string PluginsPageHandler::GetPluginEnabledMode( | |
| 290 const base::string16& plugin_name, | |
| 291 const base::string16& group_name, | |
| 292 bool plugin_enabled) const { | |
| 293 Profile* profile = Profile::FromWebUI(web_ui_); | |
| 294 PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile).get(); | |
| 295 PluginPrefs::PolicyStatus plugin_status = | |
| 296 plugin_prefs->PolicyStatusForPlugin(plugin_name); | |
| 297 PluginPrefs::PolicyStatus group_status = | |
| 298 plugin_prefs->PolicyStatusForPlugin(group_name); | |
| 299 | |
| 300 if (plugin_status == PluginPrefs::POLICY_ENABLED || | |
| 301 group_status == PluginPrefs::POLICY_ENABLED) { | |
| 302 return "enabledByPolicy"; | |
| 303 } | |
| 304 if (plugin_status == PluginPrefs::POLICY_DISABLED || | |
| 305 group_status == PluginPrefs::POLICY_DISABLED) { | |
| 306 return "disabledByPolicy"; | |
| 307 } | |
| 308 return plugin_enabled ? "enabledByUser" : "disabledByUser"; | |
| 309 } | |
| 310 | |
| 311 std::string PluginsPageHandler::GetPluginGroupEnabledMode( | |
| 312 const std::vector<mojom::PluginFilePtr>& plugin_files, | |
| 313 bool group_enabled) const { | |
| 314 bool plugins_enabled_by_policy = true; | |
| 315 bool plugins_disabled_by_policy = true; | |
| 316 bool plugins_managed_by_policy = true; | |
| 317 | |
| 318 for (size_t i = 0; i < plugin_files.size(); i++) { | |
| 319 std::string plugin_enabled_mode = plugin_files[i]->enabled_mode; | |
| 320 | |
| 321 plugins_enabled_by_policy = | |
| 322 plugins_enabled_by_policy && plugin_enabled_mode == "enabledByPolicy"; | |
| 323 plugins_disabled_by_policy = | |
| 324 plugins_disabled_by_policy && plugin_enabled_mode == "disabledByPolicy"; | |
| 325 plugins_managed_by_policy = plugins_managed_by_policy && | |
| 326 (plugin_enabled_mode == "enabledByPolicy" || | |
| 327 plugin_enabled_mode == "disabledByPolicy"); | |
| 328 } | |
| 329 | |
| 330 if (plugins_enabled_by_policy) | |
| 331 return "enabledByPolicy"; | |
| 332 if (plugins_disabled_by_policy) | |
| 333 return "disabledByPolicy"; | |
| 334 if (plugins_managed_by_policy) | |
| 335 return "managedByPolicy"; | |
| 336 return group_enabled ? "enabledByUser" : "disabledByUser"; | |
| 337 } | |
| OLD | NEW |