Index: extensions/common/features/simple_feature.cc |
diff --git a/extensions/common/features/simple_feature.cc b/extensions/common/features/simple_feature.cc |
index 7d1e06e35b11dffe0a7f4b469fc35bc61cb60e96..6a5bece485df46b7ccc9db8ef21c5d62a521ba93 100644 |
--- a/extensions/common/features/simple_feature.cc |
+++ b/extensions/common/features/simple_feature.cc |
@@ -4,13 +4,13 @@ |
#include "extensions/common/features/simple_feature.h" |
+#include <algorithm> |
#include <map> |
#include <vector> |
#include "base/bind.h" |
#include "base/command_line.h" |
#include "base/debug/alias.h" |
-#include "base/lazy_instance.h" |
#include "base/sha1.h" |
#include "base/stl_util.h" |
#include "base/strings/string_number_conversions.h" |
@@ -43,56 +43,23 @@ Feature::Availability IsAvailableToContextForBind(const Extension* extension, |
return feature->IsAvailableToContext(extension, context, url, platform); |
} |
-struct Mappings { |
- Mappings() { |
- extension_types["extension"] = Manifest::TYPE_EXTENSION; |
- extension_types["theme"] = Manifest::TYPE_THEME; |
- extension_types["legacy_packaged_app"] = Manifest::TYPE_LEGACY_PACKAGED_APP; |
- extension_types["hosted_app"] = Manifest::TYPE_HOSTED_APP; |
- extension_types["platform_app"] = Manifest::TYPE_PLATFORM_APP; |
- extension_types["shared_module"] = Manifest::TYPE_SHARED_MODULE; |
- |
- contexts["blessed_extension"] = Feature::BLESSED_EXTENSION_CONTEXT; |
- contexts["unblessed_extension"] = Feature::UNBLESSED_EXTENSION_CONTEXT; |
- contexts["content_script"] = Feature::CONTENT_SCRIPT_CONTEXT; |
- contexts["web_page"] = Feature::WEB_PAGE_CONTEXT; |
- contexts["blessed_web_page"] = Feature::BLESSED_WEB_PAGE_CONTEXT; |
- contexts["webui"] = Feature::WEBUI_CONTEXT; |
- |
- locations["component"] = SimpleFeature::COMPONENT_LOCATION; |
- locations["external_component"] = |
- SimpleFeature::EXTERNAL_COMPONENT_LOCATION; |
- locations["policy"] = SimpleFeature::POLICY_LOCATION; |
- |
- platforms["chromeos"] = Feature::CHROMEOS_PLATFORM; |
- platforms["linux"] = Feature::LINUX_PLATFORM; |
- platforms["mac"] = Feature::MACOSX_PLATFORM; |
- platforms["win"] = Feature::WIN_PLATFORM; |
- } |
- |
- std::map<std::string, Manifest::Type> extension_types; |
- std::map<std::string, Feature::Context> contexts; |
- std::map<std::string, SimpleFeature::Location> locations; |
- std::map<std::string, Feature::Platform> platforms; |
-}; |
- |
-base::LazyInstance<Mappings> g_mappings = LAZY_INSTANCE_INITIALIZER; |
- |
// TODO(aa): Can we replace all this manual parsing with JSON schema stuff? |
-void ParseSet(const base::DictionaryValue* value, |
- const std::string& property, |
- std::set<std::string>* set) { |
+void ParseVector(const base::Value* value, |
+ std::vector<std::string>* vector) { |
const base::ListValue* list_value = NULL; |
- if (!value->GetList(property, &list_value)) |
+ if (!value->GetAsList(&list_value)) |
return; |
- set->clear(); |
- for (size_t i = 0; i < list_value->GetSize(); ++i) { |
+ vector->clear(); |
+ size_t list_size = list_value->GetSize(); |
+ vector->reserve(list_size); |
+ for (size_t i = 0; i < list_size; ++i) { |
std::string str_val; |
- CHECK(list_value->GetString(i, &str_val)) << property << " " << i; |
- set->insert(str_val); |
+ CHECK(list_value->GetString(i, &str_val)); |
+ vector->push_back(str_val); |
} |
+ std::sort(vector->begin(), vector->end()); |
} |
template<typename T> |
@@ -124,31 +91,30 @@ void ParseEnum(const base::DictionaryValue* value, |
} |
template<typename T> |
-void ParseEnumSet(const base::DictionaryValue* value, |
- const std::string& property, |
- std::set<T>* enum_set, |
- const std::map<std::string, T>& mapping) { |
- if (!value->HasKey(property)) |
- return; |
- |
- enum_set->clear(); |
- |
+void ParseEnumVector(const base::Value* value, |
+ std::vector<T>* enum_vector, |
+ const std::map<std::string, T>& mapping) { |
+ enum_vector->clear(); |
std::string property_string; |
- if (value->GetString(property, &property_string)) { |
+ if (value->GetAsString(&property_string)) { |
if (property_string == "all") { |
+ enum_vector->reserve(mapping.size()); |
for (const auto& it : mapping) |
- enum_set->insert(it.second); |
+ enum_vector->push_back(it.second); |
} |
+ std::sort(enum_vector->begin(), enum_vector->end()); |
return; |
} |
- std::set<std::string> string_set; |
- ParseSet(value, property, &string_set); |
- for (const auto& str : string_set) { |
+ std::vector<std::string> string_vector; |
+ ParseVector(value, &string_vector); |
+ enum_vector->reserve(string_vector.size()); |
+ for (const auto& str : string_vector) { |
T enum_value = static_cast<T>(0); |
ParseEnum(str, &enum_value, mapping); |
- enum_set->insert(enum_value); |
+ enum_vector->push_back(enum_value); |
} |
+ std::sort(enum_vector->begin(), enum_vector->end()); |
} |
void ParseURLPatterns(const base::DictionaryValue* value, |
@@ -258,6 +224,39 @@ bool IsCommandLineSwitchEnabled(const std::string& switch_name) { |
} // namespace |
+struct SimpleFeature::Mappings { |
+ Mappings() { |
+ extension_types["extension"] = Manifest::TYPE_EXTENSION; |
+ extension_types["theme"] = Manifest::TYPE_THEME; |
+ extension_types["legacy_packaged_app"] = Manifest::TYPE_LEGACY_PACKAGED_APP; |
+ extension_types["hosted_app"] = Manifest::TYPE_HOSTED_APP; |
+ extension_types["platform_app"] = Manifest::TYPE_PLATFORM_APP; |
+ extension_types["shared_module"] = Manifest::TYPE_SHARED_MODULE; |
+ |
+ contexts["blessed_extension"] = Feature::BLESSED_EXTENSION_CONTEXT; |
+ contexts["unblessed_extension"] = Feature::UNBLESSED_EXTENSION_CONTEXT; |
+ contexts["content_script"] = Feature::CONTENT_SCRIPT_CONTEXT; |
+ contexts["web_page"] = Feature::WEB_PAGE_CONTEXT; |
+ contexts["blessed_web_page"] = Feature::BLESSED_WEB_PAGE_CONTEXT; |
+ contexts["webui"] = Feature::WEBUI_CONTEXT; |
+ |
+ locations["component"] = SimpleFeature::COMPONENT_LOCATION; |
+ locations["external_component"] = |
+ SimpleFeature::EXTERNAL_COMPONENT_LOCATION; |
+ locations["policy"] = SimpleFeature::POLICY_LOCATION; |
+ |
+ platforms["chromeos"] = Feature::CHROMEOS_PLATFORM; |
+ platforms["linux"] = Feature::LINUX_PLATFORM; |
+ platforms["mac"] = Feature::MACOSX_PLATFORM; |
+ platforms["win"] = Feature::WIN_PLATFORM; |
+ } |
+ |
+ std::map<std::string, Manifest::Type> extension_types; |
+ std::map<std::string, Feature::Context> contexts; |
+ std::map<std::string, SimpleFeature::Location> locations; |
+ std::map<std::string, Feature::Platform> platforms; |
+}; |
+ |
SimpleFeature::SimpleFeature() |
: location_(UNSPECIFIED_LOCATION), |
min_manifest_version_(0), |
@@ -274,29 +273,49 @@ void SimpleFeature::AddFilter(scoped_ptr<SimpleFeatureFilter> filter) { |
filters_.push_back(filter.release()); |
} |
-std::string SimpleFeature::Parse(const base::DictionaryValue* value) { |
- ParseURLPatterns(value, "matches", &matches_); |
- ParseSet(value, "blacklist", &blacklist_); |
- ParseSet(value, "whitelist", &whitelist_); |
- ParseSet(value, "dependencies", &dependencies_); |
- ParseEnumSet<Manifest::Type>(value, "extension_types", &extension_types_, |
- g_mappings.Get().extension_types); |
- ParseEnumSet<Context>(value, "contexts", &contexts_, |
- g_mappings.Get().contexts); |
- ParseEnum<Location>(value, "location", &location_, |
- g_mappings.Get().locations); |
- ParseEnumSet<Platform>(value, "platforms", &platforms_, |
- g_mappings.Get().platforms); |
- value->GetInteger("min_manifest_version", &min_manifest_version_); |
- value->GetInteger("max_manifest_version", &max_manifest_version_); |
+std::string SimpleFeature::Parse(const base::DictionaryValue* dictionary) { |
+ static base::LazyInstance<SimpleFeature::Mappings> mappings = |
+ LAZY_INSTANCE_INITIALIZER; |
no_parent_ = false; |
- value->GetBoolean("noparent", &no_parent_); |
- |
- value->GetBoolean("component_extensions_auto_granted", |
- &component_extensions_auto_granted_); |
- |
- value->GetString("command_line_switch", &command_line_switch_); |
+ for (base::DictionaryValue::Iterator it(*dictionary); |
+ !it.IsAtEnd(); |
+ it.Advance()) { |
+ std::string key = it.key(); |
+ const base::Value* value = &it.value(); |
+ if (key == "matches") { |
+ ParseURLPatterns(dictionary, "matches", &matches_); |
+ } else if (key == "blacklist") { |
+ ParseVector(value, &blacklist_); |
+ } else if (key == "whitelist") { |
+ ParseVector(value, &whitelist_); |
+ } else if (key == "dependencies") { |
+ ParseVector(value, &dependencies_); |
+ } else if (key == "extension_types") { |
+ ParseEnumVector<Manifest::Type>(value, &extension_types_, |
+ mappings.Get().extension_types); |
+ } else if (key == "contexts") { |
+ ParseEnumVector<Context>(value, &contexts_, |
+ mappings.Get().contexts); |
+ } else if (key == "location") { |
+ ParseEnum<Location>(dictionary, "location", &location_, |
+ mappings.Get().locations); |
+ } else if (key == "platforms") { |
+ ParseEnumVector<Platform>(value, &platforms_, |
+ mappings.Get().platforms); |
+ } else if (key == "min_manifest_version") { |
+ dictionary->GetInteger("min_manifest_version", &min_manifest_version_); |
+ } else if (key == "max_manifest_version") { |
+ dictionary->GetInteger("max_manifest_version", &max_manifest_version_); |
+ } else if (key == "noparent") { |
+ dictionary->GetBoolean("noparent", &no_parent_); |
+ } else if (key == "component_extensions_auto_granted") { |
+ dictionary->GetBoolean("component_extensions_auto_granted", |
+ &component_extensions_auto_granted_); |
+ } else if (key == "command_line_switch") { |
+ dictionary->GetString("command_line_switch", &command_line_switch_); |
+ } |
+ } |
// NOTE: ideally we'd sanity check that "matches" can be specified if and |
// only if there's a "web_page" or "webui" context, but without |
@@ -309,7 +328,7 @@ std::string SimpleFeature::Parse(const base::DictionaryValue* value) { |
std::string result; |
for (const auto& filter : filters_) { |
- result = filter->Parse(value); |
+ result = filter->Parse(dictionary); |
if (!result.empty()) |
break; |
} |
@@ -330,7 +349,7 @@ Feature::Availability SimpleFeature::IsAvailableToManifest( |
Manifest::Type type_to_check = (type == Manifest::TYPE_USER_SCRIPT) ? |
Manifest::TYPE_EXTENSION : type; |
if (!extension_types_.empty() && |
- !ContainsKey(extension_types_, type_to_check)) { |
+ !ContainsValue(extension_types_, type_to_check)) { |
return CreateAvailability(INVALID_TYPE, type); |
} |
@@ -363,7 +382,7 @@ Feature::Availability SimpleFeature::IsAvailableToManifest( |
if (!MatchesManifestLocation(location)) |
return CreateAvailability(INVALID_LOCATION, type); |
- if (!platforms_.empty() && !ContainsKey(platforms_, platform)) |
+ if (!platforms_.empty() && !ContainsValue(platforms_, platform)) |
return CreateAvailability(INVALID_PLATFORM, type); |
if (min_manifest_version_ != 0 && manifest_version < min_manifest_version_) |
@@ -407,7 +426,7 @@ Feature::Availability SimpleFeature::IsAvailableToContext( |
return result; |
} |
- if (!contexts_.empty() && !ContainsKey(contexts_, context)) |
+ if (!contexts_.empty() && !ContainsValue(contexts_, context)) |
return CreateAvailability(INVALID_CONTEXT, context); |
// TODO(kalman): Consider checking |matches_| regardless of context type. |
@@ -539,17 +558,27 @@ bool SimpleFeature::IsIdInWhitelist(const std::string& extension_id) const { |
} |
// static |
+bool SimpleFeature::IsIdInArray(const std::string& extension_id, |
+ const char* const array[], |
+ size_t array_length) { |
+ if (!IsValidExtensionId(extension_id)) |
+ return false; |
+ |
+ const char* const* start = array; |
+ const char* const* end = array + array_length; |
+ |
+ return ((std::find(start, end, extension_id) != end) || |
+ (std::find(start, end, HashExtensionId(extension_id)) != end)); |
+} |
+ |
+// static |
bool SimpleFeature::IsIdInList(const std::string& extension_id, |
- const std::set<std::string>& list) { |
- // Belt-and-suspenders philosophy here. We should be pretty confident by this |
- // point that we've validated the extension ID format, but in case something |
- // slips through, we avoid a class of attack where creative ID manipulation |
- // leads to hash collisions. |
- if (extension_id.length() != 32) // 128 bits / 4 = 32 mpdecimal characters |
+ const std::vector<std::string>& list) { |
+ if (!IsValidExtensionId(extension_id)) |
return false; |
- return (ContainsKey(list, extension_id) || |
- ContainsKey(list, HashExtensionId(extension_id))); |
+ return (ContainsValue(list, extension_id) || |
+ ContainsValue(list, HashExtensionId(extension_id))); |
} |
bool SimpleFeature::MatchesManifestLocation( |
@@ -583,4 +612,14 @@ Feature::Availability SimpleFeature::CheckDependencies( |
return CreateAvailability(IS_AVAILABLE); |
} |
+// static |
+bool SimpleFeature::IsValidExtensionId(const std::string& extension_id) { |
+ // Belt-and-suspenders philosophy here. We should be pretty confident by this |
+ // point that we've validated the extension ID format, but in case something |
+ // slips through, we avoid a class of attack where creative ID manipulation |
+ // leads to hash collisions. |
+ // 128 bits / 4 = 32 mpdecimal characters |
+ return (extension_id.length() == 32); |
+} |
+ |
} // namespace extensions |