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 |