| 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 |