OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/common/features/simple_feature.h" | 5 #include "extensions/common/features/simple_feature.h" |
6 | 6 |
| 7 #include <algorithm> |
7 #include <map> | 8 #include <map> |
8 #include <vector> | 9 #include <vector> |
9 | 10 |
10 #include "base/bind.h" | 11 #include "base/bind.h" |
11 #include "base/command_line.h" | 12 #include "base/command_line.h" |
12 #include "base/debug/alias.h" | 13 #include "base/debug/alias.h" |
13 #include "base/lazy_instance.h" | |
14 #include "base/sha1.h" | 14 #include "base/sha1.h" |
15 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
16 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
17 #include "base/strings/string_util.h" | 17 #include "base/strings/string_util.h" |
18 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
19 #include "extensions/common/extension_api.h" | 19 #include "extensions/common/extension_api.h" |
20 #include "extensions/common/features/feature_provider.h" | 20 #include "extensions/common/features/feature_provider.h" |
21 #include "extensions/common/switches.h" | 21 #include "extensions/common/switches.h" |
22 | 22 |
23 namespace extensions { | 23 namespace extensions { |
(...skipping 12 matching lines...) Expand all Loading... |
36 } | 36 } |
37 | 37 |
38 Feature::Availability IsAvailableToContextForBind(const Extension* extension, | 38 Feature::Availability IsAvailableToContextForBind(const Extension* extension, |
39 Feature::Context context, | 39 Feature::Context context, |
40 const GURL& url, | 40 const GURL& url, |
41 Feature::Platform platform, | 41 Feature::Platform platform, |
42 const Feature* feature) { | 42 const Feature* feature) { |
43 return feature->IsAvailableToContext(extension, context, url, platform); | 43 return feature->IsAvailableToContext(extension, context, url, platform); |
44 } | 44 } |
45 | 45 |
46 struct Mappings { | |
47 Mappings() { | |
48 extension_types["extension"] = Manifest::TYPE_EXTENSION; | |
49 extension_types["theme"] = Manifest::TYPE_THEME; | |
50 extension_types["legacy_packaged_app"] = Manifest::TYPE_LEGACY_PACKAGED_APP; | |
51 extension_types["hosted_app"] = Manifest::TYPE_HOSTED_APP; | |
52 extension_types["platform_app"] = Manifest::TYPE_PLATFORM_APP; | |
53 extension_types["shared_module"] = Manifest::TYPE_SHARED_MODULE; | |
54 | |
55 contexts["blessed_extension"] = Feature::BLESSED_EXTENSION_CONTEXT; | |
56 contexts["unblessed_extension"] = Feature::UNBLESSED_EXTENSION_CONTEXT; | |
57 contexts["content_script"] = Feature::CONTENT_SCRIPT_CONTEXT; | |
58 contexts["web_page"] = Feature::WEB_PAGE_CONTEXT; | |
59 contexts["blessed_web_page"] = Feature::BLESSED_WEB_PAGE_CONTEXT; | |
60 contexts["webui"] = Feature::WEBUI_CONTEXT; | |
61 | |
62 locations["component"] = SimpleFeature::COMPONENT_LOCATION; | |
63 locations["external_component"] = | |
64 SimpleFeature::EXTERNAL_COMPONENT_LOCATION; | |
65 locations["policy"] = SimpleFeature::POLICY_LOCATION; | |
66 | |
67 platforms["chromeos"] = Feature::CHROMEOS_PLATFORM; | |
68 platforms["linux"] = Feature::LINUX_PLATFORM; | |
69 platforms["mac"] = Feature::MACOSX_PLATFORM; | |
70 platforms["win"] = Feature::WIN_PLATFORM; | |
71 } | |
72 | |
73 std::map<std::string, Manifest::Type> extension_types; | |
74 std::map<std::string, Feature::Context> contexts; | |
75 std::map<std::string, SimpleFeature::Location> locations; | |
76 std::map<std::string, Feature::Platform> platforms; | |
77 }; | |
78 | |
79 base::LazyInstance<Mappings> g_mappings = LAZY_INSTANCE_INITIALIZER; | |
80 | |
81 // TODO(aa): Can we replace all this manual parsing with JSON schema stuff? | 46 // TODO(aa): Can we replace all this manual parsing with JSON schema stuff? |
82 | 47 |
83 void ParseSet(const base::DictionaryValue* value, | 48 void ParseVector(const base::Value* value, |
84 const std::string& property, | 49 std::vector<std::string>* vector) { |
85 std::set<std::string>* set) { | |
86 const base::ListValue* list_value = NULL; | 50 const base::ListValue* list_value = NULL; |
87 if (!value->GetList(property, &list_value)) | 51 if (!value->GetAsList(&list_value)) |
88 return; | 52 return; |
89 | 53 |
90 set->clear(); | 54 vector->clear(); |
91 for (size_t i = 0; i < list_value->GetSize(); ++i) { | 55 size_t list_size = list_value->GetSize(); |
| 56 vector->reserve(list_size); |
| 57 for (size_t i = 0; i < list_size; ++i) { |
92 std::string str_val; | 58 std::string str_val; |
93 CHECK(list_value->GetString(i, &str_val)) << property << " " << i; | 59 CHECK(list_value->GetString(i, &str_val)); |
94 set->insert(str_val); | 60 vector->push_back(str_val); |
95 } | 61 } |
| 62 std::sort(vector->begin(), vector->end()); |
96 } | 63 } |
97 | 64 |
98 template<typename T> | 65 template<typename T> |
99 void ParseEnum(const std::string& string_value, | 66 void ParseEnum(const std::string& string_value, |
100 T* enum_value, | 67 T* enum_value, |
101 const std::map<std::string, T>& mapping) { | 68 const std::map<std::string, T>& mapping) { |
102 const auto& iter = mapping.find(string_value); | 69 const auto& iter = mapping.find(string_value); |
103 if (iter == mapping.end()) { | 70 if (iter == mapping.end()) { |
104 // For http://crbug.com/365192. | 71 // For http://crbug.com/365192. |
105 char minidump[256]; | 72 char minidump[256]; |
(...skipping 11 matching lines...) Expand all Loading... |
117 T* enum_value, | 84 T* enum_value, |
118 const std::map<std::string, T>& mapping) { | 85 const std::map<std::string, T>& mapping) { |
119 std::string string_value; | 86 std::string string_value; |
120 if (!value->GetString(property, &string_value)) | 87 if (!value->GetString(property, &string_value)) |
121 return; | 88 return; |
122 | 89 |
123 ParseEnum(string_value, enum_value, mapping); | 90 ParseEnum(string_value, enum_value, mapping); |
124 } | 91 } |
125 | 92 |
126 template<typename T> | 93 template<typename T> |
127 void ParseEnumSet(const base::DictionaryValue* value, | 94 void ParseEnumVector(const base::Value* value, |
128 const std::string& property, | 95 std::vector<T>* enum_vector, |
129 std::set<T>* enum_set, | 96 const std::map<std::string, T>& mapping) { |
130 const std::map<std::string, T>& mapping) { | 97 enum_vector->clear(); |
131 if (!value->HasKey(property)) | |
132 return; | |
133 | |
134 enum_set->clear(); | |
135 | |
136 std::string property_string; | 98 std::string property_string; |
137 if (value->GetString(property, &property_string)) { | 99 if (value->GetAsString(&property_string)) { |
138 if (property_string == "all") { | 100 if (property_string == "all") { |
| 101 enum_vector->reserve(mapping.size()); |
139 for (const auto& it : mapping) | 102 for (const auto& it : mapping) |
140 enum_set->insert(it.second); | 103 enum_vector->push_back(it.second); |
141 } | 104 } |
| 105 std::sort(enum_vector->begin(), enum_vector->end()); |
142 return; | 106 return; |
143 } | 107 } |
144 | 108 |
145 std::set<std::string> string_set; | 109 std::vector<std::string> string_vector; |
146 ParseSet(value, property, &string_set); | 110 ParseVector(value, &string_vector); |
147 for (const auto& str : string_set) { | 111 enum_vector->reserve(string_vector.size()); |
| 112 for (const auto& str : string_vector) { |
148 T enum_value = static_cast<T>(0); | 113 T enum_value = static_cast<T>(0); |
149 ParseEnum(str, &enum_value, mapping); | 114 ParseEnum(str, &enum_value, mapping); |
150 enum_set->insert(enum_value); | 115 enum_vector->push_back(enum_value); |
151 } | 116 } |
| 117 std::sort(enum_vector->begin(), enum_vector->end()); |
152 } | 118 } |
153 | 119 |
154 void ParseURLPatterns(const base::DictionaryValue* value, | 120 void ParseURLPatterns(const base::DictionaryValue* value, |
155 const std::string& key, | 121 const std::string& key, |
156 URLPatternSet* set) { | 122 URLPatternSet* set) { |
157 const base::ListValue* matches = NULL; | 123 const base::ListValue* matches = NULL; |
158 if (value->GetList(key, &matches)) { | 124 if (value->GetList(key, &matches)) { |
159 set->ClearPatterns(); | 125 set->ClearPatterns(); |
160 for (size_t i = 0; i < matches->GetSize(); ++i) { | 126 for (size_t i = 0; i < matches->GetSize(); ++i) { |
161 std::string pattern; | 127 std::string pattern; |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | 217 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
252 if (command_line->HasSwitch(switch_name + "=1")) | 218 if (command_line->HasSwitch(switch_name + "=1")) |
253 return true; | 219 return true; |
254 if (command_line->HasSwitch(std::string("enable-") + switch_name)) | 220 if (command_line->HasSwitch(std::string("enable-") + switch_name)) |
255 return true; | 221 return true; |
256 return false; | 222 return false; |
257 } | 223 } |
258 | 224 |
259 } // namespace | 225 } // namespace |
260 | 226 |
| 227 struct SimpleFeature::Mappings { |
| 228 Mappings() { |
| 229 extension_types["extension"] = Manifest::TYPE_EXTENSION; |
| 230 extension_types["theme"] = Manifest::TYPE_THEME; |
| 231 extension_types["legacy_packaged_app"] = Manifest::TYPE_LEGACY_PACKAGED_APP; |
| 232 extension_types["hosted_app"] = Manifest::TYPE_HOSTED_APP; |
| 233 extension_types["platform_app"] = Manifest::TYPE_PLATFORM_APP; |
| 234 extension_types["shared_module"] = Manifest::TYPE_SHARED_MODULE; |
| 235 |
| 236 contexts["blessed_extension"] = Feature::BLESSED_EXTENSION_CONTEXT; |
| 237 contexts["unblessed_extension"] = Feature::UNBLESSED_EXTENSION_CONTEXT; |
| 238 contexts["content_script"] = Feature::CONTENT_SCRIPT_CONTEXT; |
| 239 contexts["web_page"] = Feature::WEB_PAGE_CONTEXT; |
| 240 contexts["blessed_web_page"] = Feature::BLESSED_WEB_PAGE_CONTEXT; |
| 241 contexts["webui"] = Feature::WEBUI_CONTEXT; |
| 242 |
| 243 locations["component"] = SimpleFeature::COMPONENT_LOCATION; |
| 244 locations["external_component"] = |
| 245 SimpleFeature::EXTERNAL_COMPONENT_LOCATION; |
| 246 locations["policy"] = SimpleFeature::POLICY_LOCATION; |
| 247 |
| 248 platforms["chromeos"] = Feature::CHROMEOS_PLATFORM; |
| 249 platforms["linux"] = Feature::LINUX_PLATFORM; |
| 250 platforms["mac"] = Feature::MACOSX_PLATFORM; |
| 251 platforms["win"] = Feature::WIN_PLATFORM; |
| 252 } |
| 253 |
| 254 std::map<std::string, Manifest::Type> extension_types; |
| 255 std::map<std::string, Feature::Context> contexts; |
| 256 std::map<std::string, SimpleFeature::Location> locations; |
| 257 std::map<std::string, Feature::Platform> platforms; |
| 258 }; |
| 259 |
261 SimpleFeature::SimpleFeature() | 260 SimpleFeature::SimpleFeature() |
262 : location_(UNSPECIFIED_LOCATION), | 261 : location_(UNSPECIFIED_LOCATION), |
263 min_manifest_version_(0), | 262 min_manifest_version_(0), |
264 max_manifest_version_(0), | 263 max_manifest_version_(0), |
265 component_extensions_auto_granted_(true) {} | 264 component_extensions_auto_granted_(true) {} |
266 | 265 |
267 SimpleFeature::~SimpleFeature() {} | 266 SimpleFeature::~SimpleFeature() {} |
268 | 267 |
269 bool SimpleFeature::HasDependencies() const { | 268 bool SimpleFeature::HasDependencies() const { |
270 return !dependencies_.empty(); | 269 return !dependencies_.empty(); |
271 } | 270 } |
272 | 271 |
273 void SimpleFeature::AddFilter(scoped_ptr<SimpleFeatureFilter> filter) { | 272 void SimpleFeature::AddFilter(scoped_ptr<SimpleFeatureFilter> filter) { |
274 filters_.push_back(filter.release()); | 273 filters_.push_back(filter.release()); |
275 } | 274 } |
276 | 275 |
277 std::string SimpleFeature::Parse(const base::DictionaryValue* value) { | 276 std::string SimpleFeature::Parse(const base::DictionaryValue* dictionary) { |
278 ParseURLPatterns(value, "matches", &matches_); | 277 static base::LazyInstance<SimpleFeature::Mappings> mappings = |
279 ParseSet(value, "blacklist", &blacklist_); | 278 LAZY_INSTANCE_INITIALIZER; |
280 ParseSet(value, "whitelist", &whitelist_); | |
281 ParseSet(value, "dependencies", &dependencies_); | |
282 ParseEnumSet<Manifest::Type>(value, "extension_types", &extension_types_, | |
283 g_mappings.Get().extension_types); | |
284 ParseEnumSet<Context>(value, "contexts", &contexts_, | |
285 g_mappings.Get().contexts); | |
286 ParseEnum<Location>(value, "location", &location_, | |
287 g_mappings.Get().locations); | |
288 ParseEnumSet<Platform>(value, "platforms", &platforms_, | |
289 g_mappings.Get().platforms); | |
290 value->GetInteger("min_manifest_version", &min_manifest_version_); | |
291 value->GetInteger("max_manifest_version", &max_manifest_version_); | |
292 | 279 |
293 no_parent_ = false; | 280 no_parent_ = false; |
294 value->GetBoolean("noparent", &no_parent_); | 281 for (base::DictionaryValue::Iterator it(*dictionary); |
295 | 282 !it.IsAtEnd(); |
296 value->GetBoolean("component_extensions_auto_granted", | 283 it.Advance()) { |
297 &component_extensions_auto_granted_); | 284 std::string key = it.key(); |
298 | 285 const base::Value* value = &it.value(); |
299 value->GetString("command_line_switch", &command_line_switch_); | 286 if (key == "matches") { |
| 287 ParseURLPatterns(dictionary, "matches", &matches_); |
| 288 } else if (key == "blacklist") { |
| 289 ParseVector(value, &blacklist_); |
| 290 } else if (key == "whitelist") { |
| 291 ParseVector(value, &whitelist_); |
| 292 } else if (key == "dependencies") { |
| 293 ParseVector(value, &dependencies_); |
| 294 } else if (key == "extension_types") { |
| 295 ParseEnumVector<Manifest::Type>(value, &extension_types_, |
| 296 mappings.Get().extension_types); |
| 297 } else if (key == "contexts") { |
| 298 ParseEnumVector<Context>(value, &contexts_, |
| 299 mappings.Get().contexts); |
| 300 } else if (key == "location") { |
| 301 ParseEnum<Location>(dictionary, "location", &location_, |
| 302 mappings.Get().locations); |
| 303 } else if (key == "platforms") { |
| 304 ParseEnumVector<Platform>(value, &platforms_, |
| 305 mappings.Get().platforms); |
| 306 } else if (key == "min_manifest_version") { |
| 307 dictionary->GetInteger("min_manifest_version", &min_manifest_version_); |
| 308 } else if (key == "max_manifest_version") { |
| 309 dictionary->GetInteger("max_manifest_version", &max_manifest_version_); |
| 310 } else if (key == "noparent") { |
| 311 dictionary->GetBoolean("noparent", &no_parent_); |
| 312 } else if (key == "component_extensions_auto_granted") { |
| 313 dictionary->GetBoolean("component_extensions_auto_granted", |
| 314 &component_extensions_auto_granted_); |
| 315 } else if (key == "command_line_switch") { |
| 316 dictionary->GetString("command_line_switch", &command_line_switch_); |
| 317 } |
| 318 } |
300 | 319 |
301 // NOTE: ideally we'd sanity check that "matches" can be specified if and | 320 // NOTE: ideally we'd sanity check that "matches" can be specified if and |
302 // only if there's a "web_page" or "webui" context, but without | 321 // only if there's a "web_page" or "webui" context, but without |
303 // (Simple)Features being aware of their own heirarchy this is impossible. | 322 // (Simple)Features being aware of their own heirarchy this is impossible. |
304 // | 323 // |
305 // For example, we might have feature "foo" available to "web_page" context | 324 // For example, we might have feature "foo" available to "web_page" context |
306 // and "matches" google.com/*. Then a sub-feature "foo.bar" might override | 325 // and "matches" google.com/*. Then a sub-feature "foo.bar" might override |
307 // "matches" to be chromium.org/*. That sub-feature doesn't need to specify | 326 // "matches" to be chromium.org/*. That sub-feature doesn't need to specify |
308 // "web_page" context because it's inherited, but we don't know that here. | 327 // "web_page" context because it's inherited, but we don't know that here. |
309 | 328 |
310 std::string result; | 329 std::string result; |
311 for (const auto& filter : filters_) { | 330 for (const auto& filter : filters_) { |
312 result = filter->Parse(value); | 331 result = filter->Parse(dictionary); |
313 if (!result.empty()) | 332 if (!result.empty()) |
314 break; | 333 break; |
315 } | 334 } |
316 | 335 |
317 return result; | 336 return result; |
318 } | 337 } |
319 | 338 |
320 Feature::Availability SimpleFeature::IsAvailableToManifest( | 339 Feature::Availability SimpleFeature::IsAvailableToManifest( |
321 const std::string& extension_id, | 340 const std::string& extension_id, |
322 Manifest::Type type, | 341 Manifest::Type type, |
323 Manifest::Location location, | 342 Manifest::Location location, |
324 int manifest_version, | 343 int manifest_version, |
325 Platform platform) const { | 344 Platform platform) const { |
326 // Check extension type first to avoid granting platform app permissions | 345 // Check extension type first to avoid granting platform app permissions |
327 // to component extensions. | 346 // to component extensions. |
328 // HACK(kalman): user script -> extension. Solve this in a more generic way | 347 // HACK(kalman): user script -> extension. Solve this in a more generic way |
329 // when we compile feature files. | 348 // when we compile feature files. |
330 Manifest::Type type_to_check = (type == Manifest::TYPE_USER_SCRIPT) ? | 349 Manifest::Type type_to_check = (type == Manifest::TYPE_USER_SCRIPT) ? |
331 Manifest::TYPE_EXTENSION : type; | 350 Manifest::TYPE_EXTENSION : type; |
332 if (!extension_types_.empty() && | 351 if (!extension_types_.empty() && |
333 !ContainsKey(extension_types_, type_to_check)) { | 352 !ContainsValue(extension_types_, type_to_check)) { |
334 return CreateAvailability(INVALID_TYPE, type); | 353 return CreateAvailability(INVALID_TYPE, type); |
335 } | 354 } |
336 | 355 |
337 if (IsIdInBlacklist(extension_id)) | 356 if (IsIdInBlacklist(extension_id)) |
338 return CreateAvailability(FOUND_IN_BLACKLIST, type); | 357 return CreateAvailability(FOUND_IN_BLACKLIST, type); |
339 | 358 |
340 // TODO(benwells): don't grant all component extensions. | 359 // TODO(benwells): don't grant all component extensions. |
341 // See http://crbug.com/370375 for more details. | 360 // See http://crbug.com/370375 for more details. |
342 // Component extensions can access any feature. | 361 // Component extensions can access any feature. |
343 // NOTE: Deliberately does not match EXTERNAL_COMPONENT. | 362 // NOTE: Deliberately does not match EXTERNAL_COMPONENT. |
(...skipping 12 matching lines...) Expand all Loading... |
356 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 375 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
357 switches::kWhitelistedExtensionID); | 376 switches::kWhitelistedExtensionID); |
358 if (extension_id != whitelist_switch_value) | 377 if (extension_id != whitelist_switch_value) |
359 return CreateAvailability(NOT_FOUND_IN_WHITELIST, type); | 378 return CreateAvailability(NOT_FOUND_IN_WHITELIST, type); |
360 } | 379 } |
361 } | 380 } |
362 | 381 |
363 if (!MatchesManifestLocation(location)) | 382 if (!MatchesManifestLocation(location)) |
364 return CreateAvailability(INVALID_LOCATION, type); | 383 return CreateAvailability(INVALID_LOCATION, type); |
365 | 384 |
366 if (!platforms_.empty() && !ContainsKey(platforms_, platform)) | 385 if (!platforms_.empty() && !ContainsValue(platforms_, platform)) |
367 return CreateAvailability(INVALID_PLATFORM, type); | 386 return CreateAvailability(INVALID_PLATFORM, type); |
368 | 387 |
369 if (min_manifest_version_ != 0 && manifest_version < min_manifest_version_) | 388 if (min_manifest_version_ != 0 && manifest_version < min_manifest_version_) |
370 return CreateAvailability(INVALID_MIN_MANIFEST_VERSION, type); | 389 return CreateAvailability(INVALID_MIN_MANIFEST_VERSION, type); |
371 | 390 |
372 if (max_manifest_version_ != 0 && manifest_version > max_manifest_version_) | 391 if (max_manifest_version_ != 0 && manifest_version > max_manifest_version_) |
373 return CreateAvailability(INVALID_MAX_MANIFEST_VERSION, type); | 392 return CreateAvailability(INVALID_MAX_MANIFEST_VERSION, type); |
374 | 393 |
375 if (!command_line_switch_.empty() && | 394 if (!command_line_switch_.empty() && |
376 !IsCommandLineSwitchEnabled(command_line_switch_)) { | 395 !IsCommandLineSwitchEnabled(command_line_switch_)) { |
(...skipping 23 matching lines...) Expand all Loading... |
400 if (extension) { | 419 if (extension) { |
401 Availability result = IsAvailableToManifest(extension->id(), | 420 Availability result = IsAvailableToManifest(extension->id(), |
402 extension->GetType(), | 421 extension->GetType(), |
403 extension->location(), | 422 extension->location(), |
404 extension->manifest_version(), | 423 extension->manifest_version(), |
405 platform); | 424 platform); |
406 if (!result.is_available()) | 425 if (!result.is_available()) |
407 return result; | 426 return result; |
408 } | 427 } |
409 | 428 |
410 if (!contexts_.empty() && !ContainsKey(contexts_, context)) | 429 if (!contexts_.empty() && !ContainsValue(contexts_, context)) |
411 return CreateAvailability(INVALID_CONTEXT, context); | 430 return CreateAvailability(INVALID_CONTEXT, context); |
412 | 431 |
413 // TODO(kalman): Consider checking |matches_| regardless of context type. | 432 // TODO(kalman): Consider checking |matches_| regardless of context type. |
414 // Fewer surprises, and if the feature configuration wants to isolate | 433 // Fewer surprises, and if the feature configuration wants to isolate |
415 // "matches" from say "blessed_extension" then they can use complex features. | 434 // "matches" from say "blessed_extension" then they can use complex features. |
416 if ((context == WEB_PAGE_CONTEXT || context == WEBUI_CONTEXT) && | 435 if ((context == WEB_PAGE_CONTEXT || context == WEBUI_CONTEXT) && |
417 !matches_.MatchesURL(url)) { | 436 !matches_.MatchesURL(url)) { |
418 return CreateAvailability(INVALID_URL, url); | 437 return CreateAvailability(INVALID_URL, url); |
419 } | 438 } |
420 | 439 |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
532 | 551 |
533 bool SimpleFeature::IsIdInBlacklist(const std::string& extension_id) const { | 552 bool SimpleFeature::IsIdInBlacklist(const std::string& extension_id) const { |
534 return IsIdInList(extension_id, blacklist_); | 553 return IsIdInList(extension_id, blacklist_); |
535 } | 554 } |
536 | 555 |
537 bool SimpleFeature::IsIdInWhitelist(const std::string& extension_id) const { | 556 bool SimpleFeature::IsIdInWhitelist(const std::string& extension_id) const { |
538 return IsIdInList(extension_id, whitelist_); | 557 return IsIdInList(extension_id, whitelist_); |
539 } | 558 } |
540 | 559 |
541 // static | 560 // static |
| 561 bool SimpleFeature::IsIdInArray(const std::string& extension_id, |
| 562 const char* const array[], |
| 563 size_t array_length) { |
| 564 if (!IsValidExtensionId(extension_id)) |
| 565 return false; |
| 566 |
| 567 const char* const* start = array; |
| 568 const char* const* end = array + array_length; |
| 569 |
| 570 return ((std::find(start, end, extension_id) != end) || |
| 571 (std::find(start, end, HashExtensionId(extension_id)) != end)); |
| 572 } |
| 573 |
| 574 // static |
542 bool SimpleFeature::IsIdInList(const std::string& extension_id, | 575 bool SimpleFeature::IsIdInList(const std::string& extension_id, |
543 const std::set<std::string>& list) { | 576 const std::vector<std::string>& list) { |
544 // Belt-and-suspenders philosophy here. We should be pretty confident by this | 577 if (!IsValidExtensionId(extension_id)) |
545 // point that we've validated the extension ID format, but in case something | |
546 // slips through, we avoid a class of attack where creative ID manipulation | |
547 // leads to hash collisions. | |
548 if (extension_id.length() != 32) // 128 bits / 4 = 32 mpdecimal characters | |
549 return false; | 578 return false; |
550 | 579 |
551 return (ContainsKey(list, extension_id) || | 580 return (ContainsValue(list, extension_id) || |
552 ContainsKey(list, HashExtensionId(extension_id))); | 581 ContainsValue(list, HashExtensionId(extension_id))); |
553 } | 582 } |
554 | 583 |
555 bool SimpleFeature::MatchesManifestLocation( | 584 bool SimpleFeature::MatchesManifestLocation( |
556 Manifest::Location manifest_location) const { | 585 Manifest::Location manifest_location) const { |
557 switch (location_) { | 586 switch (location_) { |
558 case SimpleFeature::UNSPECIFIED_LOCATION: | 587 case SimpleFeature::UNSPECIFIED_LOCATION: |
559 return true; | 588 return true; |
560 case SimpleFeature::COMPONENT_LOCATION: | 589 case SimpleFeature::COMPONENT_LOCATION: |
561 return manifest_location == Manifest::COMPONENT; | 590 return manifest_location == Manifest::COMPONENT; |
562 case SimpleFeature::EXTERNAL_COMPONENT_LOCATION: | 591 case SimpleFeature::EXTERNAL_COMPONENT_LOCATION: |
(...skipping 13 matching lines...) Expand all Loading... |
576 ExtensionAPI::GetSharedInstance()->GetFeatureDependency(dep_name); | 605 ExtensionAPI::GetSharedInstance()->GetFeatureDependency(dep_name); |
577 if (!dependency) | 606 if (!dependency) |
578 return CreateAvailability(NOT_PRESENT); | 607 return CreateAvailability(NOT_PRESENT); |
579 Availability dependency_availability = checker.Run(dependency); | 608 Availability dependency_availability = checker.Run(dependency); |
580 if (!dependency_availability.is_available()) | 609 if (!dependency_availability.is_available()) |
581 return dependency_availability; | 610 return dependency_availability; |
582 } | 611 } |
583 return CreateAvailability(IS_AVAILABLE); | 612 return CreateAvailability(IS_AVAILABLE); |
584 } | 613 } |
585 | 614 |
| 615 // static |
| 616 bool SimpleFeature::IsValidExtensionId(const std::string& extension_id) { |
| 617 // Belt-and-suspenders philosophy here. We should be pretty confident by this |
| 618 // point that we've validated the extension ID format, but in case something |
| 619 // slips through, we avoid a class of attack where creative ID manipulation |
| 620 // leads to hash collisions. |
| 621 // 128 bits / 4 = 32 mpdecimal characters |
| 622 return (extension_id.length() == 32); |
| 623 } |
| 624 |
586 } // namespace extensions | 625 } // namespace extensions |
OLD | NEW |