| 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 <map> | 7 #include <map> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 DCHECK(id_hash.length() == base::kSHA1Length); | 220 DCHECK(id_hash.length() == base::kSHA1Length); |
| 221 return base::HexEncode(id_hash.c_str(), id_hash.length()); | 221 return base::HexEncode(id_hash.c_str(), id_hash.length()); |
| 222 } | 222 } |
| 223 | 223 |
| 224 } // namespace | 224 } // namespace |
| 225 | 225 |
| 226 SimpleFeature::SimpleFeature() | 226 SimpleFeature::SimpleFeature() |
| 227 : location_(UNSPECIFIED_LOCATION), | 227 : location_(UNSPECIFIED_LOCATION), |
| 228 min_manifest_version_(0), | 228 min_manifest_version_(0), |
| 229 max_manifest_version_(0), | 229 max_manifest_version_(0), |
| 230 has_parent_(false) {} | 230 has_parent_(false), |
| 231 component_extensions_auto_granted_(true) {} |
| 231 | 232 |
| 232 SimpleFeature::~SimpleFeature() {} | 233 SimpleFeature::~SimpleFeature() {} |
| 233 | 234 |
| 234 void SimpleFeature::AddFilter(scoped_ptr<SimpleFeatureFilter> filter) { | 235 void SimpleFeature::AddFilter(scoped_ptr<SimpleFeatureFilter> filter) { |
| 235 filters_.push_back(make_linked_ptr(filter.release())); | 236 filters_.push_back(make_linked_ptr(filter.release())); |
| 236 } | 237 } |
| 237 | 238 |
| 238 std::string SimpleFeature::Parse(const base::DictionaryValue* value) { | 239 std::string SimpleFeature::Parse(const base::DictionaryValue* value) { |
| 239 ParseURLPatterns(value, "matches", &matches_); | 240 ParseURLPatterns(value, "matches", &matches_); |
| 241 ParseSet(value, "blacklist", &blacklist_); |
| 240 ParseSet(value, "whitelist", &whitelist_); | 242 ParseSet(value, "whitelist", &whitelist_); |
| 241 ParseSet(value, "dependencies", &dependencies_); | 243 ParseSet(value, "dependencies", &dependencies_); |
| 242 ParseEnumSet<Manifest::Type>(value, "extension_types", &extension_types_, | 244 ParseEnumSet<Manifest::Type>(value, "extension_types", &extension_types_, |
| 243 g_mappings.Get().extension_types); | 245 g_mappings.Get().extension_types); |
| 244 ParseEnumSet<Context>(value, "contexts", &contexts_, | 246 ParseEnumSet<Context>(value, "contexts", &contexts_, |
| 245 g_mappings.Get().contexts); | 247 g_mappings.Get().contexts); |
| 246 ParseEnum<Location>(value, "location", &location_, | 248 ParseEnum<Location>(value, "location", &location_, |
| 247 g_mappings.Get().locations); | 249 g_mappings.Get().locations); |
| 248 ParseEnumSet<Platform>(value, "platforms", &platforms_, | 250 ParseEnumSet<Platform>(value, "platforms", &platforms_, |
| 249 g_mappings.Get().platforms); | 251 g_mappings.Get().platforms); |
| 250 value->GetInteger("min_manifest_version", &min_manifest_version_); | 252 value->GetInteger("min_manifest_version", &min_manifest_version_); |
| 251 value->GetInteger("max_manifest_version", &max_manifest_version_); | 253 value->GetInteger("max_manifest_version", &max_manifest_version_); |
| 252 | 254 |
| 253 no_parent_ = false; | 255 no_parent_ = false; |
| 254 value->GetBoolean("noparent", &no_parent_); | 256 value->GetBoolean("noparent", &no_parent_); |
| 255 | 257 |
| 258 component_extensions_auto_granted_ = true; |
| 259 value->GetBoolean("component_extensions_auto_granted", |
| 260 &component_extensions_auto_granted_); |
| 261 |
| 256 if (matches_.is_empty() && contexts_.count(WEB_PAGE_CONTEXT) != 0) { | 262 if (matches_.is_empty() && contexts_.count(WEB_PAGE_CONTEXT) != 0) { |
| 257 return name() + ": Allowing web_page contexts requires supplying a value " + | 263 return name() + ": Allowing web_page contexts requires supplying a value " + |
| 258 "for matches."; | 264 "for matches."; |
| 259 } | 265 } |
| 260 | 266 |
| 261 for (FilterList::iterator filter_iter = filters_.begin(); | 267 for (FilterList::iterator filter_iter = filters_.begin(); |
| 262 filter_iter != filters_.end(); | 268 filter_iter != filters_.end(); |
| 263 ++filter_iter) { | 269 ++filter_iter) { |
| 264 std::string result = (*filter_iter)->Parse(value); | 270 std::string result = (*filter_iter)->Parse(value); |
| 265 if (!result.empty()) { | 271 if (!result.empty()) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 280 // to component extensions. | 286 // to component extensions. |
| 281 // HACK(kalman): user script -> extension. Solve this in a more generic way | 287 // HACK(kalman): user script -> extension. Solve this in a more generic way |
| 282 // when we compile feature files. | 288 // when we compile feature files. |
| 283 Manifest::Type type_to_check = (type == Manifest::TYPE_USER_SCRIPT) ? | 289 Manifest::Type type_to_check = (type == Manifest::TYPE_USER_SCRIPT) ? |
| 284 Manifest::TYPE_EXTENSION : type; | 290 Manifest::TYPE_EXTENSION : type; |
| 285 if (!extension_types_.empty() && | 291 if (!extension_types_.empty() && |
| 286 extension_types_.find(type_to_check) == extension_types_.end()) { | 292 extension_types_.find(type_to_check) == extension_types_.end()) { |
| 287 return CreateAvailability(INVALID_TYPE, type); | 293 return CreateAvailability(INVALID_TYPE, type); |
| 288 } | 294 } |
| 289 | 295 |
| 296 if (IsIdInBlacklist(extension_id)) |
| 297 return CreateAvailability(FOUND_IN_BLACKLIST, type); |
| 298 |
| 299 // TODO(benwells): don't grant all component extensions. |
| 300 // See http://crbug.com/370375 for more details. |
| 290 // Component extensions can access any feature. | 301 // Component extensions can access any feature. |
| 291 // TODO(kalman/asargent): Should this match EXTERNAL_COMPONENT too? | 302 // NOTE: Deliberately does not match EXTERNAL_COMPONENT. |
| 292 if (location == Manifest::COMPONENT) | 303 if (component_extensions_auto_granted_ && location == Manifest::COMPONENT) |
| 293 return CreateAvailability(IS_AVAILABLE, type); | 304 return CreateAvailability(IS_AVAILABLE, type); |
| 294 | 305 |
| 295 if (!whitelist_.empty()) { | 306 if (!whitelist_.empty()) { |
| 296 if (!IsIdInWhitelist(extension_id)) { | 307 if (!IsIdInWhitelist(extension_id)) { |
| 297 // TODO(aa): This is gross. There should be a better way to test the | 308 // TODO(aa): This is gross. There should be a better way to test the |
| 298 // whitelist. | 309 // whitelist. |
| 299 CommandLine* command_line = CommandLine::ForCurrentProcess(); | 310 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 300 if (!command_line->HasSwitch(switches::kWhitelistedExtensionID)) | 311 if (!command_line->HasSwitch(switches::kWhitelistedExtensionID)) |
| 301 return CreateAvailability(NOT_FOUND_IN_WHITELIST, type); | 312 return CreateAvailability(NOT_FOUND_IN_WHITELIST, type); |
| 302 | 313 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 368 | 379 |
| 369 std::string SimpleFeature::GetAvailabilityMessage( | 380 std::string SimpleFeature::GetAvailabilityMessage( |
| 370 AvailabilityResult result, | 381 AvailabilityResult result, |
| 371 Manifest::Type type, | 382 Manifest::Type type, |
| 372 const GURL& url, | 383 const GURL& url, |
| 373 Context context) const { | 384 Context context) const { |
| 374 switch (result) { | 385 switch (result) { |
| 375 case IS_AVAILABLE: | 386 case IS_AVAILABLE: |
| 376 return std::string(); | 387 return std::string(); |
| 377 case NOT_FOUND_IN_WHITELIST: | 388 case NOT_FOUND_IN_WHITELIST: |
| 389 case FOUND_IN_BLACKLIST: |
| 378 return base::StringPrintf( | 390 return base::StringPrintf( |
| 379 "'%s' is not allowed for specified extension ID.", | 391 "'%s' is not allowed for specified extension ID.", |
| 380 name().c_str()); | 392 name().c_str()); |
| 381 case INVALID_URL: | 393 case INVALID_URL: |
| 382 return base::StringPrintf("'%s' is not allowed on %s.", | 394 return base::StringPrintf("'%s' is not allowed on %s.", |
| 383 name().c_str(), url.spec().c_str()); | 395 name().c_str(), url.spec().c_str()); |
| 384 case INVALID_TYPE: | 396 case INVALID_TYPE: |
| 385 return base::StringPrintf( | 397 return base::StringPrintf( |
| 386 "'%s' is only allowed for %s, but this is a %s.", | 398 "'%s' is only allowed for %s, but this is a %s.", |
| 387 name().c_str(), | 399 name().c_str(), |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 459 std::set<Feature::Context>* SimpleFeature::GetContexts() { | 471 std::set<Feature::Context>* SimpleFeature::GetContexts() { |
| 460 return &contexts_; | 472 return &contexts_; |
| 461 } | 473 } |
| 462 | 474 |
| 463 bool SimpleFeature::IsInternal() const { | 475 bool SimpleFeature::IsInternal() const { |
| 464 return false; | 476 return false; |
| 465 } | 477 } |
| 466 | 478 |
| 467 bool SimpleFeature::IsBlockedInServiceWorker() const { return false; } | 479 bool SimpleFeature::IsBlockedInServiceWorker() const { return false; } |
| 468 | 480 |
| 481 bool SimpleFeature::IsIdInBlacklist(const std::string& extension_id) const { |
| 482 return IsIdInList(extension_id, blacklist_); |
| 483 } |
| 484 |
| 469 bool SimpleFeature::IsIdInWhitelist(const std::string& extension_id) const { | 485 bool SimpleFeature::IsIdInWhitelist(const std::string& extension_id) const { |
| 470 return IsIdInWhitelist(extension_id, whitelist_); | 486 return IsIdInList(extension_id, whitelist_); |
| 471 } | 487 } |
| 472 | 488 |
| 473 // static | 489 // static |
| 474 bool SimpleFeature::IsIdInWhitelist(const std::string& extension_id, | 490 bool SimpleFeature::IsIdInList(const std::string& extension_id, |
| 475 const std::set<std::string>& whitelist) { | 491 const std::set<std::string>& list) { |
| 476 // Belt-and-suspenders philosophy here. We should be pretty confident by this | 492 // Belt-and-suspenders philosophy here. We should be pretty confident by this |
| 477 // point that we've validated the extension ID format, but in case something | 493 // point that we've validated the extension ID format, but in case something |
| 478 // slips through, we avoid a class of attack where creative ID manipulation | 494 // slips through, we avoid a class of attack where creative ID manipulation |
| 479 // leads to hash collisions. | 495 // leads to hash collisions. |
| 480 if (extension_id.length() != 32) // 128 bits / 4 = 32 mpdecimal characters | 496 if (extension_id.length() != 32) // 128 bits / 4 = 32 mpdecimal characters |
| 481 return false; | 497 return false; |
| 482 | 498 |
| 483 if (whitelist.find(extension_id) != whitelist.end() || | 499 if (list.find(extension_id) != list.end() || |
| 484 whitelist.find(HashExtensionId(extension_id)) != whitelist.end()) { | 500 list.find(HashExtensionId(extension_id)) != list.end()) { |
| 485 return true; | 501 return true; |
| 486 } | 502 } |
| 487 | 503 |
| 488 return false; | 504 return false; |
| 489 } | 505 } |
| 490 | 506 |
| 491 bool SimpleFeature::MatchesManifestLocation( | 507 bool SimpleFeature::MatchesManifestLocation( |
| 492 Manifest::Location manifest_location) const { | 508 Manifest::Location manifest_location) const { |
| 493 switch (location_) { | 509 switch (location_) { |
| 494 case SimpleFeature::UNSPECIFIED_LOCATION: | 510 case SimpleFeature::UNSPECIFIED_LOCATION: |
| 495 return true; | 511 return true; |
| 496 case SimpleFeature::COMPONENT_LOCATION: | 512 case SimpleFeature::COMPONENT_LOCATION: |
| 497 // TODO(kalman/asargent): Should this include EXTERNAL_COMPONENT too? | 513 // TODO(kalman/asargent): Should this include EXTERNAL_COMPONENT too? |
| 498 return manifest_location == Manifest::COMPONENT; | 514 return manifest_location == Manifest::COMPONENT; |
| 499 case SimpleFeature::POLICY_LOCATION: | 515 case SimpleFeature::POLICY_LOCATION: |
| 500 return manifest_location == Manifest::EXTERNAL_POLICY || | 516 return manifest_location == Manifest::EXTERNAL_POLICY || |
| 501 manifest_location == Manifest::EXTERNAL_POLICY_DOWNLOAD; | 517 manifest_location == Manifest::EXTERNAL_POLICY_DOWNLOAD; |
| 502 } | 518 } |
| 503 NOTREACHED(); | 519 NOTREACHED(); |
| 504 return false; | 520 return false; |
| 505 } | 521 } |
| 506 | 522 |
| 507 } // namespace extensions | 523 } // namespace extensions |
| OLD | NEW |