| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 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 "webkit/glue/plugins/plugin_group.h" | |
| 6 | |
| 7 #include "base/linked_ptr.h" | |
| 8 #include "base/string_util.h" | |
| 9 #include "base/sys_string_conversions.h" | |
| 10 #include "base/utf_string_conversions.h" | |
| 11 #include "base/values.h" | |
| 12 #include "base/version.h" | |
| 13 #include "webkit/glue/plugins/plugin_list.h" | |
| 14 #include "webkit/glue/plugins/webplugininfo.h" | |
| 15 | |
| 16 const char* PluginGroup::kAdobeReaderGroupName = "Adobe Reader"; | |
| 17 | |
| 18 /*static*/ | |
| 19 std::set<string16>* PluginGroup::policy_disabled_plugin_patterns_; | |
| 20 | |
| 21 /*static*/ | |
| 22 void PluginGroup::SetPolicyDisabledPluginPatterns( | |
| 23 const std::set<string16>& set) { | |
| 24 if (!policy_disabled_plugin_patterns_) | |
| 25 policy_disabled_plugin_patterns_ = new std::set<string16>(set); | |
| 26 else | |
| 27 *policy_disabled_plugin_patterns_ = set; | |
| 28 } | |
| 29 | |
| 30 /*static*/ | |
| 31 bool PluginGroup::IsPluginNameDisabledByPolicy(const string16& plugin_name) { | |
| 32 if (!policy_disabled_plugin_patterns_) | |
| 33 return false; | |
| 34 | |
| 35 std::set<string16>::const_iterator pattern( | |
| 36 policy_disabled_plugin_patterns_->begin()); | |
| 37 while (pattern != policy_disabled_plugin_patterns_->end()) { | |
| 38 if (MatchPattern(plugin_name, *pattern)) | |
| 39 return true; | |
| 40 ++pattern; | |
| 41 } | |
| 42 | |
| 43 return false; | |
| 44 } | |
| 45 | |
| 46 /*static*/ | |
| 47 bool PluginGroup::IsPluginPathDisabledByPolicy(const FilePath& plugin_path) { | |
| 48 std::vector<WebPluginInfo> plugins; | |
| 49 NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins); | |
| 50 for (std::vector<WebPluginInfo>::const_iterator it = plugins.begin(); | |
| 51 it != plugins.end(); | |
| 52 ++it) { | |
| 53 if (FilePath::CompareEqualIgnoreCase(it->path.value(), | |
| 54 plugin_path.value()) && IsPluginNameDisabledByPolicy(it->name)) { | |
| 55 return true; | |
| 56 } | |
| 57 } | |
| 58 return false; | |
| 59 } | |
| 60 | |
| 61 VersionRange::VersionRange(VersionRangeDefinition definition) | |
| 62 : low_str(definition.version_matcher_low), | |
| 63 high_str(definition.version_matcher_high), | |
| 64 min_str(definition.min_version) { | |
| 65 if (!low_str.empty()) | |
| 66 low.reset(Version::GetVersionFromString(low_str)); | |
| 67 if (!high_str.empty()) | |
| 68 high.reset(Version::GetVersionFromString(high_str)); | |
| 69 if (!min_str.empty()) | |
| 70 min.reset(Version::GetVersionFromString(min_str)); | |
| 71 } | |
| 72 | |
| 73 VersionRange::VersionRange(const VersionRange& other) { | |
| 74 InitFrom(other); | |
| 75 } | |
| 76 | |
| 77 VersionRange& VersionRange::operator=(const VersionRange& other) { | |
| 78 InitFrom(other); | |
| 79 return *this; | |
| 80 } | |
| 81 | |
| 82 VersionRange::~VersionRange() {} | |
| 83 | |
| 84 void VersionRange::InitFrom(const VersionRange& other) { | |
| 85 low_str = other.low_str; | |
| 86 high_str = other.high_str; | |
| 87 min_str = other.min_str; | |
| 88 low.reset(Version::GetVersionFromString(other.low_str)); | |
| 89 high.reset(Version::GetVersionFromString(other.high_str)); | |
| 90 min.reset(Version::GetVersionFromString(other.min_str)); | |
| 91 } | |
| 92 | |
| 93 PluginGroup::PluginGroup(const string16& group_name, | |
| 94 const string16& name_matcher, | |
| 95 const std::string& update_url, | |
| 96 const std::string& identifier) | |
| 97 : identifier_(identifier), | |
| 98 group_name_(group_name), | |
| 99 name_matcher_(name_matcher), | |
| 100 update_url_(update_url), | |
| 101 enabled_(false), | |
| 102 version_(Version::GetVersionFromString("0")) { | |
| 103 } | |
| 104 | |
| 105 void PluginGroup::InitFrom(const PluginGroup& other) { | |
| 106 identifier_ = other.identifier_; | |
| 107 group_name_ = other.group_name_; | |
| 108 name_matcher_ = other.name_matcher_; | |
| 109 description_ = other.description_; | |
| 110 update_url_ = other.update_url_; | |
| 111 enabled_ = other.enabled_; | |
| 112 for (size_t i = 0; i < other.version_ranges_.size(); ++i) | |
| 113 version_ranges_.push_back(other.version_ranges_[i]); | |
| 114 DCHECK_EQ(other.web_plugin_infos_.size(), other.web_plugin_positions_.size()); | |
| 115 for (size_t i = 0; i < other.web_plugin_infos_.size(); ++i) | |
| 116 AddPlugin(other.web_plugin_infos_[i], other.web_plugin_positions_[i]); | |
| 117 if (!version_.get()) | |
| 118 version_.reset(Version::GetVersionFromString("0")); | |
| 119 } | |
| 120 | |
| 121 PluginGroup::PluginGroup(const PluginGroup& other) { | |
| 122 InitFrom(other); | |
| 123 } | |
| 124 | |
| 125 PluginGroup& PluginGroup::operator=(const PluginGroup& other) { | |
| 126 version_ranges_.clear(); | |
| 127 InitFrom(other); | |
| 128 return *this; | |
| 129 } | |
| 130 | |
| 131 /*static*/ | |
| 132 PluginGroup* PluginGroup::FromPluginGroupDefinition( | |
| 133 const PluginGroupDefinition& definition) { | |
| 134 PluginGroup* group = new PluginGroup(ASCIIToUTF16(definition.name), | |
| 135 ASCIIToUTF16(definition.name_matcher), | |
| 136 definition.update_url, | |
| 137 definition.identifier); | |
| 138 for (size_t i = 0; i < definition.num_versions; ++i) | |
| 139 group->version_ranges_.push_back(VersionRange(definition.versions[i])); | |
| 140 return group; | |
| 141 } | |
| 142 | |
| 143 PluginGroup::~PluginGroup() { } | |
| 144 | |
| 145 /*static*/ | |
| 146 std::string PluginGroup::GetIdentifier(const WebPluginInfo& wpi) { | |
| 147 #if defined(OS_POSIX) | |
| 148 return wpi.path.BaseName().value(); | |
| 149 #elif defined(OS_WIN) | |
| 150 return base::SysWideToUTF8(wpi.path.BaseName().value()); | |
| 151 #endif | |
| 152 } | |
| 153 | |
| 154 /*static*/ | |
| 155 std::string PluginGroup::GetLongIdentifier(const WebPluginInfo& wpi) { | |
| 156 #if defined(OS_POSIX) | |
| 157 return wpi.path.value(); | |
| 158 #elif defined(OS_WIN) | |
| 159 return base::SysWideToUTF8(wpi.path.value()); | |
| 160 #endif | |
| 161 } | |
| 162 | |
| 163 /*static*/ | |
| 164 PluginGroup* PluginGroup::FromWebPluginInfo(const WebPluginInfo& wpi) { | |
| 165 // Create a matcher from the name of this plugin. | |
| 166 return new PluginGroup(wpi.name, wpi.name, std::string(), | |
| 167 GetIdentifier(wpi)); | |
| 168 } | |
| 169 | |
| 170 bool PluginGroup::Match(const WebPluginInfo& plugin) const { | |
| 171 if (name_matcher_.empty()) { | |
| 172 return false; | |
| 173 } | |
| 174 | |
| 175 // Look for the name matcher anywhere in the plugin name. | |
| 176 if (plugin.name.find(name_matcher_) == string16::npos) { | |
| 177 return false; | |
| 178 } | |
| 179 | |
| 180 if (version_ranges_.empty()) { | |
| 181 return true; | |
| 182 } | |
| 183 | |
| 184 // There's at least one version range, the plugin's version must be in it. | |
| 185 scoped_ptr<Version> plugin_version( | |
| 186 Version::GetVersionFromString(UTF16ToWide(plugin.version))); | |
| 187 if (plugin_version.get() == NULL) { | |
| 188 // No version could be extracted, assume we don't match the range. | |
| 189 return false; | |
| 190 } | |
| 191 | |
| 192 // Match if the plugin is contained in any of the defined VersionRanges. | |
| 193 for (size_t i = 0; i < version_ranges_.size(); ++i) { | |
| 194 if (IsVersionInRange(*plugin_version, version_ranges_[i])) { | |
| 195 return true; | |
| 196 } | |
| 197 } | |
| 198 // None of the VersionRanges matched. | |
| 199 return false; | |
| 200 } | |
| 201 | |
| 202 /* static */ | |
| 203 Version* PluginGroup::CreateVersionFromString(const string16& version_string) { | |
| 204 // Remove spaces and ')' from the version string, | |
| 205 // Replace any instances of 'r', ',' or '(' with a dot. | |
| 206 std::wstring version = UTF16ToWide(version_string); | |
| 207 RemoveChars(version, L") ", &version); | |
| 208 std::replace(version.begin(), version.end(), 'r', '.'); | |
| 209 std::replace(version.begin(), version.end(), ',', '.'); | |
| 210 std::replace(version.begin(), version.end(), '(', '.'); | |
| 211 | |
| 212 return Version::GetVersionFromString(version); | |
| 213 } | |
| 214 | |
| 215 void PluginGroup::UpdateActivePlugin(const WebPluginInfo& plugin) { | |
| 216 // A group is enabled if any of the files are enabled. | |
| 217 if (plugin.enabled) { | |
| 218 if (!enabled_) { | |
| 219 // If this is the first enabled plugin, use its description. | |
| 220 enabled_ = true; | |
| 221 UpdateDescriptionAndVersion(plugin); | |
| 222 } | |
| 223 } else { | |
| 224 // If this is the first plugin and it's disabled, | |
| 225 // use its description for now. | |
| 226 if (description_.empty()) | |
| 227 UpdateDescriptionAndVersion(plugin); | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 void PluginGroup::UpdateDescriptionAndVersion(const WebPluginInfo& plugin) { | |
| 232 description_ = plugin.desc; | |
| 233 if (Version* new_version = CreateVersionFromString(plugin.version)) | |
| 234 version_.reset(new_version); | |
| 235 else | |
| 236 version_.reset(Version::GetVersionFromString("0")); | |
| 237 } | |
| 238 | |
| 239 void PluginGroup::AddPlugin(const WebPluginInfo& plugin, int position) { | |
| 240 // Check if this group already contains this plugin. | |
| 241 for (size_t i = 0; i < web_plugin_infos_.size(); ++i) { | |
| 242 if (web_plugin_infos_[i].name == plugin.name && | |
| 243 web_plugin_infos_[i].version == plugin.version && | |
| 244 FilePath::CompareEqualIgnoreCase(web_plugin_infos_[i].path.value(), | |
| 245 plugin.path.value())) { | |
| 246 return; | |
| 247 } | |
| 248 } | |
| 249 web_plugin_infos_.push_back(plugin); | |
| 250 // The position of this plugin relative to the global list of plugins. | |
| 251 web_plugin_positions_.push_back(position); | |
| 252 UpdateActivePlugin(plugin); | |
| 253 } | |
| 254 | |
| 255 string16 PluginGroup::GetGroupName() const { | |
| 256 if (!group_name_.empty()) | |
| 257 return group_name_; | |
| 258 DCHECK_EQ(1u, web_plugin_infos_.size()); | |
| 259 FilePath::StringType path = | |
| 260 web_plugin_infos_[0].path.BaseName().RemoveExtension().value(); | |
| 261 #if defined(OS_POSIX) | |
| 262 return UTF8ToUTF16(path); | |
| 263 #elif defined(OS_WIN) | |
| 264 return WideToUTF16(path); | |
| 265 #endif | |
| 266 } | |
| 267 | |
| 268 DictionaryValue* PluginGroup::GetSummary() const { | |
| 269 DictionaryValue* result = new DictionaryValue(); | |
| 270 result->SetString("name", GetGroupName()); | |
| 271 result->SetBoolean("enabled", enabled_); | |
| 272 return result; | |
| 273 } | |
| 274 | |
| 275 DictionaryValue* PluginGroup::GetDataForUI() const { | |
| 276 string16 name = GetGroupName(); | |
| 277 DictionaryValue* result = new DictionaryValue(); | |
| 278 result->SetString("name", name); | |
| 279 result->SetString("description", description_); | |
| 280 result->SetString("version", version_->GetString()); | |
| 281 result->SetString("update_url", update_url_); | |
| 282 result->SetBoolean("critical", IsVulnerable()); | |
| 283 | |
| 284 bool group_disabled_by_policy = IsPluginNameDisabledByPolicy(name); | |
| 285 ListValue* plugin_files = new ListValue(); | |
| 286 bool all_plugins_disabled_by_policy = true; | |
| 287 for (size_t i = 0; i < web_plugin_infos_.size(); ++i) { | |
| 288 const WebPluginInfo& web_plugin = web_plugin_infos_[i]; | |
| 289 int priority = web_plugin_positions_[i]; | |
| 290 DictionaryValue* plugin_file = new DictionaryValue(); | |
| 291 plugin_file->SetString("name", web_plugin.name); | |
| 292 plugin_file->SetString("description", web_plugin.desc); | |
| 293 plugin_file->SetString("path", web_plugin.path.value()); | |
| 294 plugin_file->SetString("version", web_plugin.version); | |
| 295 bool plugin_disabled_by_policy = group_disabled_by_policy || | |
| 296 IsPluginNameDisabledByPolicy(web_plugin.name); | |
| 297 if (plugin_disabled_by_policy) { | |
| 298 plugin_file->SetString("enabledMode", "disabledByPolicy"); | |
| 299 } else { | |
| 300 all_plugins_disabled_by_policy = false; | |
| 301 plugin_file->SetString("enabledMode", | |
| 302 web_plugin.enabled ? "enabled" : "disabledByUser"); | |
| 303 } | |
| 304 plugin_file->SetInteger("priority", priority); | |
| 305 | |
| 306 ListValue* mime_types = new ListValue(); | |
| 307 for (std::vector<WebPluginMimeType>::const_iterator type_it = | |
| 308 web_plugin.mime_types.begin(); | |
| 309 type_it != web_plugin.mime_types.end(); | |
| 310 ++type_it) { | |
| 311 DictionaryValue* mime_type = new DictionaryValue(); | |
| 312 mime_type->SetString("mimeType", type_it->mime_type); | |
| 313 mime_type->SetString("description", type_it->description); | |
| 314 | |
| 315 ListValue* file_extensions = new ListValue(); | |
| 316 for (std::vector<std::string>::const_iterator ext_it = | |
| 317 type_it->file_extensions.begin(); | |
| 318 ext_it != type_it->file_extensions.end(); | |
| 319 ++ext_it) { | |
| 320 file_extensions->Append(new StringValue(*ext_it)); | |
| 321 } | |
| 322 mime_type->Set("fileExtensions", file_extensions); | |
| 323 | |
| 324 mime_types->Append(mime_type); | |
| 325 } | |
| 326 plugin_file->Set("mimeTypes", mime_types); | |
| 327 | |
| 328 plugin_files->Append(plugin_file); | |
| 329 } | |
| 330 | |
| 331 if (group_disabled_by_policy || all_plugins_disabled_by_policy) { | |
| 332 result->SetString("enabledMode", "disabledByPolicy"); | |
| 333 } else { | |
| 334 result->SetString("enabledMode", enabled_ ? "enabled" : "disabledByUser"); | |
| 335 } | |
| 336 result->Set("plugin_files", plugin_files); | |
| 337 | |
| 338 return result; | |
| 339 } | |
| 340 | |
| 341 /*static*/ | |
| 342 bool PluginGroup::IsVersionInRange(const Version& version, | |
| 343 const VersionRange& range) { | |
| 344 DCHECK(range.low.get() != NULL || range.high.get() == NULL) | |
| 345 << "Lower bound of version range must be defined."; | |
| 346 return (range.low.get() == NULL && range.high.get() == NULL) || | |
| 347 (range.low->CompareTo(version) <= 0 && | |
| 348 (range.high.get() == NULL || range.high->CompareTo(version) > 0)); | |
| 349 } | |
| 350 | |
| 351 /*static*/ | |
| 352 bool PluginGroup::IsPluginOutdated(const Version& plugin_version, | |
| 353 const VersionRange& version_range) { | |
| 354 if (IsVersionInRange(plugin_version, version_range)) { | |
| 355 if (version_range.min.get() && | |
| 356 plugin_version.CompareTo(*version_range.min) < 0) { | |
| 357 return true; | |
| 358 } | |
| 359 } | |
| 360 return false; | |
| 361 } | |
| 362 | |
| 363 // Returns true if the latest version of this plugin group is vulnerable. | |
| 364 bool PluginGroup::IsVulnerable() const { | |
| 365 for (size_t i = 0; i < version_ranges_.size(); ++i) { | |
| 366 if (IsPluginOutdated(*version_, version_ranges_[i])) | |
| 367 return true; | |
| 368 } | |
| 369 return false; | |
| 370 } | |
| 371 | |
| 372 void PluginGroup::DisableOutdatedPlugins() { | |
| 373 description_ = string16(); | |
| 374 enabled_ = false; | |
| 375 | |
| 376 for (std::vector<WebPluginInfo>::iterator it = | |
| 377 web_plugin_infos_.begin(); | |
| 378 it != web_plugin_infos_.end(); ++it) { | |
| 379 scoped_ptr<Version> version(CreateVersionFromString(it->version)); | |
| 380 if (version.get()) { | |
| 381 for (size_t i = 0; i < version_ranges_.size(); ++i) { | |
| 382 if (IsPluginOutdated(*version, version_ranges_[i])) { | |
| 383 it->enabled = false; | |
| 384 NPAPI::PluginList::Singleton()->DisablePlugin(it->path); | |
| 385 } | |
| 386 } | |
| 387 } | |
| 388 UpdateActivePlugin(*it); | |
| 389 } | |
| 390 } | |
| 391 | |
| 392 void PluginGroup::Enable(bool enable) { | |
| 393 bool enabled_plugin_exists = false; | |
| 394 for (std::vector<WebPluginInfo>::iterator it = | |
| 395 web_plugin_infos_.begin(); | |
| 396 it != web_plugin_infos_.end(); ++it) { | |
| 397 if (enable && !IsPluginNameDisabledByPolicy(it->name)) { | |
| 398 NPAPI::PluginList::Singleton()->EnablePlugin(it->path); | |
| 399 it->enabled = true; | |
| 400 enabled_plugin_exists = true; | |
| 401 } else { | |
| 402 it->enabled = false; | |
| 403 NPAPI::PluginList::Singleton()->DisablePlugin(it->path); | |
| 404 } | |
| 405 } | |
| 406 enabled_ = enabled_plugin_exists; | |
| 407 } | |
| OLD | NEW |