summaryrefslogtreecommitdiffstats
path: root/webkit/plugins/npapi/plugin_group.cc
diff options
context:
space:
mode:
Diffstat (limited to 'webkit/plugins/npapi/plugin_group.cc')
-rw-r--r--webkit/plugins/npapi/plugin_group.cc413
1 files changed, 413 insertions, 0 deletions
diff --git a/webkit/plugins/npapi/plugin_group.cc b/webkit/plugins/npapi/plugin_group.cc
new file mode 100644
index 0000000..ec1b537
--- /dev/null
+++ b/webkit/plugins/npapi/plugin_group.cc
@@ -0,0 +1,413 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "webkit/plugins/npapi/plugin_group.h"
+
+#include "base/linked_ptr.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "base/version.h"
+#include "webkit/plugins/npapi/plugin_list.h"
+#include "webkit/plugins/npapi/webplugininfo.h"
+
+namespace webkit {
+namespace npapi {
+
+const char* PluginGroup::kAdobeReaderGroupName = "Adobe Reader";
+
+/*static*/
+std::set<string16>* PluginGroup::policy_disabled_plugin_patterns_;
+
+/*static*/
+void PluginGroup::SetPolicyDisabledPluginPatterns(
+ const std::set<string16>& set) {
+ if (!policy_disabled_plugin_patterns_)
+ policy_disabled_plugin_patterns_ = new std::set<string16>(set);
+ else
+ *policy_disabled_plugin_patterns_ = set;
+}
+
+/*static*/
+bool PluginGroup::IsPluginNameDisabledByPolicy(const string16& plugin_name) {
+ if (!policy_disabled_plugin_patterns_)
+ return false;
+
+ std::set<string16>::const_iterator pattern(
+ policy_disabled_plugin_patterns_->begin());
+ while (pattern != policy_disabled_plugin_patterns_->end()) {
+ if (MatchPattern(plugin_name, *pattern))
+ return true;
+ ++pattern;
+ }
+
+ return false;
+}
+
+/*static*/
+bool PluginGroup::IsPluginPathDisabledByPolicy(const FilePath& plugin_path) {
+ std::vector<WebPluginInfo> plugins;
+ PluginList::Singleton()->GetPlugins(false, &plugins);
+ for (std::vector<WebPluginInfo>::const_iterator it = plugins.begin();
+ it != plugins.end();
+ ++it) {
+ if (FilePath::CompareEqualIgnoreCase(it->path.value(),
+ plugin_path.value()) && IsPluginNameDisabledByPolicy(it->name)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+VersionRange::VersionRange(VersionRangeDefinition definition)
+ : low_str(definition.version_matcher_low),
+ high_str(definition.version_matcher_high),
+ min_str(definition.min_version) {
+ if (!low_str.empty())
+ low.reset(Version::GetVersionFromString(low_str));
+ if (!high_str.empty())
+ high.reset(Version::GetVersionFromString(high_str));
+ if (!min_str.empty())
+ min.reset(Version::GetVersionFromString(min_str));
+}
+
+VersionRange::VersionRange(const VersionRange& other) {
+ InitFrom(other);
+}
+
+VersionRange& VersionRange::operator=(const VersionRange& other) {
+ InitFrom(other);
+ return *this;
+}
+
+VersionRange::~VersionRange() {}
+
+void VersionRange::InitFrom(const VersionRange& other) {
+ low_str = other.low_str;
+ high_str = other.high_str;
+ min_str = other.min_str;
+ low.reset(Version::GetVersionFromString(other.low_str));
+ high.reset(Version::GetVersionFromString(other.high_str));
+ min.reset(Version::GetVersionFromString(other.min_str));
+}
+
+PluginGroup::PluginGroup(const string16& group_name,
+ const string16& name_matcher,
+ const std::string& update_url,
+ const std::string& identifier)
+ : identifier_(identifier),
+ group_name_(group_name),
+ name_matcher_(name_matcher),
+ update_url_(update_url),
+ enabled_(false),
+ version_(Version::GetVersionFromString("0")) {
+}
+
+void PluginGroup::InitFrom(const PluginGroup& other) {
+ identifier_ = other.identifier_;
+ group_name_ = other.group_name_;
+ name_matcher_ = other.name_matcher_;
+ description_ = other.description_;
+ update_url_ = other.update_url_;
+ enabled_ = other.enabled_;
+ for (size_t i = 0; i < other.version_ranges_.size(); ++i)
+ version_ranges_.push_back(other.version_ranges_[i]);
+ DCHECK_EQ(other.web_plugin_infos_.size(), other.web_plugin_positions_.size());
+ for (size_t i = 0; i < other.web_plugin_infos_.size(); ++i)
+ AddPlugin(other.web_plugin_infos_[i], other.web_plugin_positions_[i]);
+ if (!version_.get())
+ version_.reset(Version::GetVersionFromString("0"));
+}
+
+PluginGroup::PluginGroup(const PluginGroup& other) {
+ InitFrom(other);
+}
+
+PluginGroup& PluginGroup::operator=(const PluginGroup& other) {
+ version_ranges_.clear();
+ InitFrom(other);
+ return *this;
+}
+
+/*static*/
+PluginGroup* PluginGroup::FromPluginGroupDefinition(
+ const PluginGroupDefinition& definition) {
+ PluginGroup* group = new PluginGroup(ASCIIToUTF16(definition.name),
+ ASCIIToUTF16(definition.name_matcher),
+ definition.update_url,
+ definition.identifier);
+ for (size_t i = 0; i < definition.num_versions; ++i)
+ group->version_ranges_.push_back(VersionRange(definition.versions[i]));
+ return group;
+}
+
+PluginGroup::~PluginGroup() { }
+
+/*static*/
+std::string PluginGroup::GetIdentifier(const WebPluginInfo& wpi) {
+#if defined(OS_POSIX)
+ return wpi.path.BaseName().value();
+#elif defined(OS_WIN)
+ return base::SysWideToUTF8(wpi.path.BaseName().value());
+#endif
+}
+
+/*static*/
+std::string PluginGroup::GetLongIdentifier(const WebPluginInfo& wpi) {
+#if defined(OS_POSIX)
+ return wpi.path.value();
+#elif defined(OS_WIN)
+ return base::SysWideToUTF8(wpi.path.value());
+#endif
+}
+
+/*static*/
+PluginGroup* PluginGroup::FromWebPluginInfo(const WebPluginInfo& wpi) {
+ // Create a matcher from the name of this plugin.
+ return new PluginGroup(wpi.name, wpi.name, std::string(),
+ GetIdentifier(wpi));
+}
+
+bool PluginGroup::Match(const WebPluginInfo& plugin) const {
+ if (name_matcher_.empty()) {
+ return false;
+ }
+
+ // Look for the name matcher anywhere in the plugin name.
+ if (plugin.name.find(name_matcher_) == string16::npos) {
+ return false;
+ }
+
+ if (version_ranges_.empty()) {
+ return true;
+ }
+
+ // There's at least one version range, the plugin's version must be in it.
+ scoped_ptr<Version> plugin_version(
+ Version::GetVersionFromString(UTF16ToWide(plugin.version)));
+ if (plugin_version.get() == NULL) {
+ // No version could be extracted, assume we don't match the range.
+ return false;
+ }
+
+ // Match if the plugin is contained in any of the defined VersionRanges.
+ for (size_t i = 0; i < version_ranges_.size(); ++i) {
+ if (IsVersionInRange(*plugin_version, version_ranges_[i])) {
+ return true;
+ }
+ }
+ // None of the VersionRanges matched.
+ return false;
+}
+
+/* static */
+Version* PluginGroup::CreateVersionFromString(const string16& version_string) {
+ // Remove spaces and ')' from the version string,
+ // Replace any instances of 'r', ',' or '(' with a dot.
+ std::wstring version = UTF16ToWide(version_string);
+ RemoveChars(version, L") ", &version);
+ std::replace(version.begin(), version.end(), 'r', '.');
+ std::replace(version.begin(), version.end(), ',', '.');
+ std::replace(version.begin(), version.end(), '(', '.');
+
+ return Version::GetVersionFromString(version);
+}
+
+void PluginGroup::UpdateActivePlugin(const WebPluginInfo& plugin) {
+ // A group is enabled if any of the files are enabled.
+ if (plugin.enabled) {
+ if (!enabled_) {
+ // If this is the first enabled plugin, use its description.
+ enabled_ = true;
+ UpdateDescriptionAndVersion(plugin);
+ }
+ } else {
+ // If this is the first plugin and it's disabled,
+ // use its description for now.
+ if (description_.empty())
+ UpdateDescriptionAndVersion(plugin);
+ }
+}
+
+void PluginGroup::UpdateDescriptionAndVersion(const WebPluginInfo& plugin) {
+ description_ = plugin.desc;
+ if (Version* new_version = CreateVersionFromString(plugin.version))
+ version_.reset(new_version);
+ else
+ version_.reset(Version::GetVersionFromString("0"));
+}
+
+void PluginGroup::AddPlugin(const WebPluginInfo& plugin, int position) {
+ // Check if this group already contains this plugin.
+ for (size_t i = 0; i < web_plugin_infos_.size(); ++i) {
+ if (web_plugin_infos_[i].name == plugin.name &&
+ web_plugin_infos_[i].version == plugin.version &&
+ FilePath::CompareEqualIgnoreCase(web_plugin_infos_[i].path.value(),
+ plugin.path.value())) {
+ return;
+ }
+ }
+ web_plugin_infos_.push_back(plugin);
+ // The position of this plugin relative to the global list of plugins.
+ web_plugin_positions_.push_back(position);
+ UpdateActivePlugin(plugin);
+}
+
+string16 PluginGroup::GetGroupName() const {
+ if (!group_name_.empty())
+ return group_name_;
+ DCHECK_EQ(1u, web_plugin_infos_.size());
+ FilePath::StringType path =
+ web_plugin_infos_[0].path.BaseName().RemoveExtension().value();
+#if defined(OS_POSIX)
+ return UTF8ToUTF16(path);
+#elif defined(OS_WIN)
+ return WideToUTF16(path);
+#endif
+}
+
+DictionaryValue* PluginGroup::GetSummary() const {
+ DictionaryValue* result = new DictionaryValue();
+ result->SetString("name", GetGroupName());
+ result->SetBoolean("enabled", enabled_);
+ return result;
+}
+
+DictionaryValue* PluginGroup::GetDataForUI() const {
+ string16 name = GetGroupName();
+ DictionaryValue* result = new DictionaryValue();
+ result->SetString("name", name);
+ result->SetString("description", description_);
+ result->SetString("version", version_->GetString());
+ result->SetString("update_url", update_url_);
+ result->SetBoolean("critical", IsVulnerable());
+
+ bool group_disabled_by_policy = IsPluginNameDisabledByPolicy(name);
+ ListValue* plugin_files = new ListValue();
+ bool all_plugins_disabled_by_policy = true;
+ for (size_t i = 0; i < web_plugin_infos_.size(); ++i) {
+ const WebPluginInfo& web_plugin = web_plugin_infos_[i];
+ int priority = web_plugin_positions_[i];
+ DictionaryValue* plugin_file = new DictionaryValue();
+ plugin_file->SetString("name", web_plugin.name);
+ plugin_file->SetString("description", web_plugin.desc);
+ plugin_file->SetString("path", web_plugin.path.value());
+ plugin_file->SetString("version", web_plugin.version);
+ bool plugin_disabled_by_policy = group_disabled_by_policy ||
+ IsPluginNameDisabledByPolicy(web_plugin.name);
+ if (plugin_disabled_by_policy) {
+ plugin_file->SetString("enabledMode", "disabledByPolicy");
+ } else {
+ all_plugins_disabled_by_policy = false;
+ plugin_file->SetString("enabledMode",
+ web_plugin.enabled ? "enabled" : "disabledByUser");
+ }
+ plugin_file->SetInteger("priority", priority);
+
+ ListValue* mime_types = new ListValue();
+ for (std::vector<WebPluginMimeType>::const_iterator type_it =
+ web_plugin.mime_types.begin();
+ type_it != web_plugin.mime_types.end();
+ ++type_it) {
+ DictionaryValue* mime_type = new DictionaryValue();
+ mime_type->SetString("mimeType", type_it->mime_type);
+ mime_type->SetString("description", type_it->description);
+
+ ListValue* file_extensions = new ListValue();
+ for (std::vector<std::string>::const_iterator ext_it =
+ type_it->file_extensions.begin();
+ ext_it != type_it->file_extensions.end();
+ ++ext_it) {
+ file_extensions->Append(new StringValue(*ext_it));
+ }
+ mime_type->Set("fileExtensions", file_extensions);
+
+ mime_types->Append(mime_type);
+ }
+ plugin_file->Set("mimeTypes", mime_types);
+
+ plugin_files->Append(plugin_file);
+ }
+
+ if (group_disabled_by_policy || all_plugins_disabled_by_policy) {
+ result->SetString("enabledMode", "disabledByPolicy");
+ } else {
+ result->SetString("enabledMode", enabled_ ? "enabled" : "disabledByUser");
+ }
+ result->Set("plugin_files", plugin_files);
+
+ return result;
+}
+
+/*static*/
+bool PluginGroup::IsVersionInRange(const Version& version,
+ const VersionRange& range) {
+ DCHECK(range.low.get() != NULL || range.high.get() == NULL)
+ << "Lower bound of version range must be defined.";
+ return (range.low.get() == NULL && range.high.get() == NULL) ||
+ (range.low->CompareTo(version) <= 0 &&
+ (range.high.get() == NULL || range.high->CompareTo(version) > 0));
+}
+
+/*static*/
+bool PluginGroup::IsPluginOutdated(const Version& plugin_version,
+ const VersionRange& version_range) {
+ if (IsVersionInRange(plugin_version, version_range)) {
+ if (version_range.min.get() &&
+ plugin_version.CompareTo(*version_range.min) < 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Returns true if the latest version of this plugin group is vulnerable.
+bool PluginGroup::IsVulnerable() const {
+ for (size_t i = 0; i < version_ranges_.size(); ++i) {
+ if (IsPluginOutdated(*version_, version_ranges_[i]))
+ return true;
+ }
+ return false;
+}
+
+void PluginGroup::DisableOutdatedPlugins() {
+ description_ = string16();
+ enabled_ = false;
+
+ for (std::vector<WebPluginInfo>::iterator it =
+ web_plugin_infos_.begin();
+ it != web_plugin_infos_.end(); ++it) {
+ scoped_ptr<Version> version(CreateVersionFromString(it->version));
+ if (version.get()) {
+ for (size_t i = 0; i < version_ranges_.size(); ++i) {
+ if (IsPluginOutdated(*version, version_ranges_[i])) {
+ it->enabled = false;
+ PluginList::Singleton()->DisablePlugin(it->path);
+ }
+ }
+ }
+ UpdateActivePlugin(*it);
+ }
+}
+
+void PluginGroup::Enable(bool enable) {
+ bool enabled_plugin_exists = false;
+ for (std::vector<WebPluginInfo>::iterator it =
+ web_plugin_infos_.begin();
+ it != web_plugin_infos_.end(); ++it) {
+ if (enable && !IsPluginNameDisabledByPolicy(it->name)) {
+ PluginList::Singleton()->EnablePlugin(it->path);
+ it->enabled = true;
+ enabled_plugin_exists = true;
+ } else {
+ it->enabled = false;
+ PluginList::Singleton()->DisablePlugin(it->path);
+ }
+ }
+ enabled_ = enabled_plugin_exists;
+}
+
+} // namespace npapi
+} // namespace webkit