| 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 <algorithm> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <utility> | 9 #include <utility> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 46 } | 46 } |
| 47 | 47 |
| 48 Feature::Availability IsAvailableToContextForBind(const Extension* extension, | 48 Feature::Availability IsAvailableToContextForBind(const Extension* extension, |
| 49 Feature::Context context, | 49 Feature::Context context, |
| 50 const GURL& url, | 50 const GURL& url, |
| 51 Feature::Platform platform, | 51 Feature::Platform platform, |
| 52 const Feature* feature) { | 52 const Feature* feature) { |
| 53 return feature->IsAvailableToContext(extension, context, url, platform); | 53 return feature->IsAvailableToContext(extension, context, url, platform); |
| 54 } | 54 } |
| 55 | 55 |
| 56 // TODO(aa): Can we replace all this manual parsing with JSON schema stuff? | |
| 57 | |
| 58 void ParseVector(const base::Value* value, | |
| 59 std::vector<std::string>* vector) { | |
| 60 const base::ListValue* list_value = NULL; | |
| 61 if (!value->GetAsList(&list_value)) | |
| 62 return; | |
| 63 | |
| 64 vector->clear(); | |
| 65 size_t list_size = list_value->GetSize(); | |
| 66 vector->reserve(list_size); | |
| 67 for (size_t i = 0; i < list_size; ++i) { | |
| 68 std::string str_val; | |
| 69 CHECK(list_value->GetString(i, &str_val)); | |
| 70 vector->push_back(str_val); | |
| 71 } | |
| 72 std::sort(vector->begin(), vector->end()); | |
| 73 } | |
| 74 | |
| 75 template<typename T> | |
| 76 void ParseEnum(const std::string& string_value, | |
| 77 T* enum_value, | |
| 78 const std::map<std::string, T>& mapping) { | |
| 79 const auto& iter = mapping.find(string_value); | |
| 80 if (iter == mapping.end()) | |
| 81 CRASH_WITH_MINIDUMP("Enum value not found: " + string_value); | |
| 82 *enum_value = iter->second; | |
| 83 } | |
| 84 | |
| 85 template <typename T> | |
| 86 void ParseEnum(const base::Value* value, | |
| 87 T* enum_value, | |
| 88 const std::map<std::string, T>& mapping) { | |
| 89 std::string string_value; | |
| 90 if (!value->GetAsString(&string_value)) | |
| 91 return; | |
| 92 | |
| 93 ParseEnum(string_value, enum_value, mapping); | |
| 94 } | |
| 95 | |
| 96 template<typename T> | |
| 97 void ParseEnumVector(const base::Value* value, | |
| 98 std::vector<T>* enum_vector, | |
| 99 const std::map<std::string, T>& mapping) { | |
| 100 enum_vector->clear(); | |
| 101 std::string property_string; | |
| 102 if (value->GetAsString(&property_string)) { | |
| 103 if (property_string == "all") { | |
| 104 enum_vector->reserve(mapping.size()); | |
| 105 for (const auto& it : mapping) | |
| 106 enum_vector->push_back(it.second); | |
| 107 } | |
| 108 std::sort(enum_vector->begin(), enum_vector->end()); | |
| 109 return; | |
| 110 } | |
| 111 | |
| 112 std::vector<std::string> string_vector; | |
| 113 ParseVector(value, &string_vector); | |
| 114 enum_vector->reserve(string_vector.size()); | |
| 115 for (const auto& str : string_vector) { | |
| 116 T enum_value = static_cast<T>(0); | |
| 117 ParseEnum(str, &enum_value, mapping); | |
| 118 enum_vector->push_back(enum_value); | |
| 119 } | |
| 120 std::sort(enum_vector->begin(), enum_vector->end()); | |
| 121 } | |
| 122 | |
| 123 void ParseURLPatterns(const base::DictionaryValue* value, | |
| 124 const std::string& key, | |
| 125 URLPatternSet* set) { | |
| 126 const base::ListValue* matches = NULL; | |
| 127 if (value->GetList(key, &matches)) { | |
| 128 set->ClearPatterns(); | |
| 129 for (size_t i = 0; i < matches->GetSize(); ++i) { | |
| 130 std::string pattern; | |
| 131 CHECK(matches->GetString(i, &pattern)); | |
| 132 set->AddPattern(URLPattern(URLPattern::SCHEME_ALL, pattern)); | |
| 133 } | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 // Gets a human-readable name for the given extension type, suitable for giving | 56 // Gets a human-readable name for the given extension type, suitable for giving |
| 138 // to developers in an error message. | 57 // to developers in an error message. |
| 139 std::string GetDisplayName(Manifest::Type type) { | 58 std::string GetDisplayName(Manifest::Type type) { |
| 140 switch (type) { | 59 switch (type) { |
| 141 case Manifest::TYPE_UNKNOWN: | 60 case Manifest::TYPE_UNKNOWN: |
| 142 return "unknown"; | 61 return "unknown"; |
| 143 case Manifest::TYPE_EXTENSION: | 62 case Manifest::TYPE_EXTENSION: |
| 144 return "extension"; | 63 return "extension"; |
| 145 case Manifest::TYPE_HOSTED_APP: | 64 case Manifest::TYPE_HOSTED_APP: |
| 146 return "hosted app"; | 65 return "hosted app"; |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 const std::string& id) | 177 const std::string& id) |
| 259 : previous_id_(g_whitelisted_extension_id) { | 178 : previous_id_(g_whitelisted_extension_id) { |
| 260 g_whitelisted_extension_id = new std::string(id); | 179 g_whitelisted_extension_id = new std::string(id); |
| 261 } | 180 } |
| 262 | 181 |
| 263 SimpleFeature::ScopedWhitelistForTest::~ScopedWhitelistForTest() { | 182 SimpleFeature::ScopedWhitelistForTest::~ScopedWhitelistForTest() { |
| 264 delete g_whitelisted_extension_id; | 183 delete g_whitelisted_extension_id; |
| 265 g_whitelisted_extension_id = previous_id_; | 184 g_whitelisted_extension_id = previous_id_; |
| 266 } | 185 } |
| 267 | 186 |
| 268 struct SimpleFeature::Mappings { | |
| 269 Mappings() { | |
| 270 extension_types["extension"] = Manifest::TYPE_EXTENSION; | |
| 271 extension_types["theme"] = Manifest::TYPE_THEME; | |
| 272 extension_types["legacy_packaged_app"] = Manifest::TYPE_LEGACY_PACKAGED_APP; | |
| 273 extension_types["hosted_app"] = Manifest::TYPE_HOSTED_APP; | |
| 274 extension_types["platform_app"] = Manifest::TYPE_PLATFORM_APP; | |
| 275 extension_types["shared_module"] = Manifest::TYPE_SHARED_MODULE; | |
| 276 | |
| 277 contexts["blessed_extension"] = Feature::BLESSED_EXTENSION_CONTEXT; | |
| 278 contexts["unblessed_extension"] = Feature::UNBLESSED_EXTENSION_CONTEXT; | |
| 279 contexts["content_script"] = Feature::CONTENT_SCRIPT_CONTEXT; | |
| 280 contexts["web_page"] = Feature::WEB_PAGE_CONTEXT; | |
| 281 contexts["blessed_web_page"] = Feature::BLESSED_WEB_PAGE_CONTEXT; | |
| 282 contexts["webui"] = Feature::WEBUI_CONTEXT; | |
| 283 contexts["extension_service_worker"] = Feature::SERVICE_WORKER_CONTEXT; | |
| 284 | |
| 285 locations["component"] = SimpleFeature::COMPONENT_LOCATION; | |
| 286 locations["external_component"] = | |
| 287 SimpleFeature::EXTERNAL_COMPONENT_LOCATION; | |
| 288 locations["policy"] = SimpleFeature::POLICY_LOCATION; | |
| 289 | |
| 290 platforms["chromeos"] = Feature::CHROMEOS_PLATFORM; | |
| 291 platforms["linux"] = Feature::LINUX_PLATFORM; | |
| 292 platforms["mac"] = Feature::MACOSX_PLATFORM; | |
| 293 platforms["win"] = Feature::WIN_PLATFORM; | |
| 294 | |
| 295 channels["trunk"] = version_info::Channel::UNKNOWN; | |
| 296 channels["canary"] = version_info::Channel::CANARY; | |
| 297 channels["dev"] = version_info::Channel::DEV; | |
| 298 channels["beta"] = version_info::Channel::BETA; | |
| 299 channels["stable"] = version_info::Channel::STABLE; | |
| 300 } | |
| 301 | |
| 302 std::map<std::string, Manifest::Type> extension_types; | |
| 303 std::map<std::string, Feature::Context> contexts; | |
| 304 std::map<std::string, SimpleFeature::Location> locations; | |
| 305 std::map<std::string, Feature::Platform> platforms; | |
| 306 std::map<std::string, version_info::Channel> channels; | |
| 307 }; | |
| 308 | |
| 309 SimpleFeature::SimpleFeature() | 187 SimpleFeature::SimpleFeature() |
| 310 : location_(UNSPECIFIED_LOCATION), | 188 : location_(UNSPECIFIED_LOCATION), |
| 311 min_manifest_version_(0), | 189 min_manifest_version_(0), |
| 312 max_manifest_version_(0), | 190 max_manifest_version_(0), |
| 313 component_extensions_auto_granted_(true), | 191 component_extensions_auto_granted_(true), |
| 314 is_internal_(false) {} | 192 is_internal_(false) {} |
| 315 | 193 |
| 316 SimpleFeature::~SimpleFeature() {} | 194 SimpleFeature::~SimpleFeature() {} |
| 317 | 195 |
| 318 void SimpleFeature::Parse(const base::DictionaryValue* dictionary) { | |
| 319 static base::LazyInstance<SimpleFeature::Mappings> mappings = | |
| 320 LAZY_INSTANCE_INITIALIZER; | |
| 321 | |
| 322 no_parent_ = false; | |
| 323 for (base::DictionaryValue::Iterator it(*dictionary); | |
| 324 !it.IsAtEnd(); | |
| 325 it.Advance()) { | |
| 326 const std::string& key = it.key(); | |
| 327 const base::Value* value = &it.value(); | |
| 328 if (key == "matches") { | |
| 329 ParseURLPatterns(dictionary, "matches", &matches_); | |
| 330 } else if (key == "blacklist") { | |
| 331 ParseVector(value, &blacklist_); | |
| 332 } else if (key == "whitelist") { | |
| 333 ParseVector(value, &whitelist_); | |
| 334 } else if (key == "dependencies") { | |
| 335 ParseVector(value, &dependencies_); | |
| 336 } else if (key == "extension_types") { | |
| 337 ParseEnumVector<Manifest::Type>(value, &extension_types_, | |
| 338 mappings.Get().extension_types); | |
| 339 } else if (key == "contexts") { | |
| 340 ParseEnumVector<Context>(value, &contexts_, | |
| 341 mappings.Get().contexts); | |
| 342 } else if (key == "location") { | |
| 343 ParseEnum<Location>(value, &location_, mappings.Get().locations); | |
| 344 } else if (key == "platforms") { | |
| 345 ParseEnumVector<Platform>(value, &platforms_, | |
| 346 mappings.Get().platforms); | |
| 347 } else if (key == "min_manifest_version") { | |
| 348 dictionary->GetInteger("min_manifest_version", &min_manifest_version_); | |
| 349 } else if (key == "max_manifest_version") { | |
| 350 dictionary->GetInteger("max_manifest_version", &max_manifest_version_); | |
| 351 } else if (key == "noparent") { | |
| 352 dictionary->GetBoolean("noparent", &no_parent_); | |
| 353 } else if (key == "component_extensions_auto_granted") { | |
| 354 dictionary->GetBoolean("component_extensions_auto_granted", | |
| 355 &component_extensions_auto_granted_); | |
| 356 } else if (key == "command_line_switch") { | |
| 357 dictionary->GetString("command_line_switch", &command_line_switch_); | |
| 358 } else if (key == "channel") { | |
| 359 channel_.reset(new version_info::Channel(version_info::Channel::UNKNOWN)); | |
| 360 ParseEnum<version_info::Channel>(value, channel_.get(), | |
| 361 mappings.Get().channels); | |
| 362 } else if (key == "internal") { | |
| 363 value->GetAsBoolean(&is_internal_); | |
| 364 } | |
| 365 } | |
| 366 | |
| 367 // NOTE: ideally we'd sanity check that "matches" can be specified if and | |
| 368 // only if there's a "web_page" or "webui" context, but without | |
| 369 // (Simple)Features being aware of their own heirarchy this is impossible. | |
| 370 // | |
| 371 // For example, we might have feature "foo" available to "web_page" context | |
| 372 // and "matches" google.com/*. Then a sub-feature "foo.bar" might override | |
| 373 // "matches" to be chromium.org/*. That sub-feature doesn't need to specify | |
| 374 // "web_page" context because it's inherited, but we don't know that here. | |
| 375 } | |
| 376 | |
| 377 bool SimpleFeature::Validate(std::string* error) { | |
| 378 DCHECK(error); | |
| 379 // All features must be channel-restricted, either directly or through | |
| 380 // dependents. | |
| 381 if (!channel_ && dependencies_.empty()) { | |
| 382 *error = name() + ": Must supply a value for channel or dependencies."; | |
| 383 return false; | |
| 384 } | |
| 385 | |
| 386 return true; | |
| 387 } | |
| 388 | |
| 389 Feature::Availability SimpleFeature::IsAvailableToManifest( | 196 Feature::Availability SimpleFeature::IsAvailableToManifest( |
| 390 const std::string& extension_id, | 197 const std::string& extension_id, |
| 391 Manifest::Type type, | 198 Manifest::Type type, |
| 392 Manifest::Location location, | 199 Manifest::Location location, |
| 393 int manifest_version, | 200 int manifest_version, |
| 394 Platform platform) const { | 201 Platform platform) const { |
| 395 // Check extension type first to avoid granting platform app permissions | 202 // Check extension type first to avoid granting platform app permissions |
| 396 // to component extensions. | 203 // to component extensions. |
| 397 // HACK(kalman): user script -> extension. Solve this in a more generic way | 204 // HACK(kalman): user script -> extension. Solve this in a more generic way |
| 398 // when we compile feature files. | 205 // when we compile feature files. |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 701 void SimpleFeature::set_platforms(std::initializer_list<Platform> platforms) { | 508 void SimpleFeature::set_platforms(std::initializer_list<Platform> platforms) { |
| 702 platforms_ = platforms; | 509 platforms_ = platforms; |
| 703 } | 510 } |
| 704 | 511 |
| 705 void SimpleFeature::set_whitelist( | 512 void SimpleFeature::set_whitelist( |
| 706 std::initializer_list<const char* const> whitelist) { | 513 std::initializer_list<const char* const> whitelist) { |
| 707 whitelist_.assign(whitelist.begin(), whitelist.end()); | 514 whitelist_.assign(whitelist.begin(), whitelist.end()); |
| 708 } | 515 } |
| 709 | 516 |
| 710 } // namespace extensions | 517 } // namespace extensions |
| OLD | NEW |