Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/common/extensions/api/extension_api.h" | 5 #include "chrome/common/extensions/api/extension_api.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 228 *feature_type = "api"; | 228 *feature_type = "api"; |
| 229 *feature_name = full_name; | 229 *feature_name = full_name; |
| 230 return; | 230 return; |
| 231 } | 231 } |
| 232 | 232 |
| 233 *feature_type = full_name.substr(0, colon_index); | 233 *feature_type = full_name.substr(0, colon_index); |
| 234 *feature_name = full_name.substr(colon_index + 1); | 234 *feature_name = full_name.substr(colon_index + 1); |
| 235 } | 235 } |
| 236 | 236 |
| 237 bool ExtensionAPI::UsesFeatureSystem(const std::string& full_name) { | 237 bool ExtensionAPI::UsesFeatureSystem(const std::string& full_name) { |
| 238 std::string api_name = GetAPINameFromFullName(full_name, NULL); | 238 return TryGetFeatureDependency(full_name) != NULL; |
| 239 return features_.find(api_name) != features_.end(); | |
| 240 } | 239 } |
| 241 | 240 |
| 242 void ExtensionAPI::LoadSchema(const std::string& name, | 241 void ExtensionAPI::LoadSchema(const std::string& name, |
| 243 const base::StringPiece& schema) { | 242 const base::StringPiece& schema) { |
| 244 scoped_ptr<ListValue> schema_list(LoadSchemaList(name, schema)); | 243 scoped_ptr<ListValue> schema_list(LoadSchemaList(name, schema)); |
| 245 std::string schema_namespace; | 244 std::string schema_namespace; |
| 246 | 245 |
| 247 while (!schema_list->empty()) { | 246 while (!schema_list->empty()) { |
| 248 DictionaryValue* schema = NULL; | 247 DictionaryValue* schema = NULL; |
| 249 { | 248 { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 325 child_feature->set_name(schema_namespace + "." + child_name); | 324 child_feature->set_name(schema_namespace + "." + child_name); |
| 326 CHECK(schema_features->insert( | 325 CHECK(schema_features->insert( |
| 327 std::make_pair(child_name, | 326 std::make_pair(child_name, |
| 328 make_linked_ptr(child_feature.release()))).second); | 327 make_linked_ptr(child_feature.release()))).second); |
| 329 } | 328 } |
| 330 } | 329 } |
| 331 } | 330 } |
| 332 } | 331 } |
| 333 | 332 |
| 334 ExtensionAPI::ExtensionAPI() { | 333 ExtensionAPI::ExtensionAPI() { |
| 335 RegisterDependencyProvider("api", this); | |
| 336 | |
| 337 // TODO(aa): Can remove this when all JSON files are converted. | |
| 338 RegisterDependencyProvider("", this); | |
| 339 } | 334 } |
| 340 | 335 |
| 341 ExtensionAPI::~ExtensionAPI() { | 336 ExtensionAPI::~ExtensionAPI() { |
| 342 } | 337 } |
| 343 | 338 |
| 344 void ExtensionAPI::InitDefaultConfiguration() { | 339 void ExtensionAPI::InitDefaultConfiguration() { |
| 345 RegisterDependencyProvider( | 340 RegisterDependencyProvider( |
| 341 "api", BaseFeatureProvider::GetApiFeatures()); | |
| 342 RegisterDependencyProvider( | |
| 346 "manifest", BaseFeatureProvider::GetManifestFeatures()); | 343 "manifest", BaseFeatureProvider::GetManifestFeatures()); |
| 347 RegisterDependencyProvider( | 344 RegisterDependencyProvider( |
| 348 "permission", BaseFeatureProvider::GetPermissionFeatures()); | 345 "permission", BaseFeatureProvider::GetPermissionFeatures()); |
| 349 | 346 |
| 350 // Schemas to be loaded from resources. | 347 // Schemas to be loaded from resources. |
| 351 CHECK(unloaded_schemas_.empty()); | 348 CHECK(unloaded_schemas_.empty()); |
| 352 RegisterSchema("app", ReadFromResource( | 349 RegisterSchema("app", ReadFromResource( |
| 353 IDR_EXTENSION_API_JSON_APP)); | 350 IDR_EXTENSION_API_JSON_APP)); |
| 354 RegisterSchema("browserAction", ReadFromResource( | 351 RegisterSchema("browserAction", ReadFromResource( |
| 355 IDR_EXTENSION_API_JSON_BROWSERACTION)); | 352 IDR_EXTENSION_API_JSON_BROWSERACTION)); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 415 | 412 |
| 416 void ExtensionAPI::RegisterDependencyProvider(const std::string& name, | 413 void ExtensionAPI::RegisterDependencyProvider(const std::string& name, |
| 417 FeatureProvider* provider) { | 414 FeatureProvider* provider) { |
| 418 dependency_providers_[name] = provider; | 415 dependency_providers_[name] = provider; |
| 419 } | 416 } |
| 420 | 417 |
| 421 Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name, | 418 Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name, |
| 422 const Extension* extension, | 419 const Extension* extension, |
| 423 Feature::Context context, | 420 Feature::Context context, |
| 424 const GURL& url) { | 421 const GURL& url) { |
| 425 std::set<std::string> dependency_names; | 422 std::string feature_type; |
| 426 dependency_names.insert(full_name); | 423 std::string feature_name; |
| 427 ResolveDependencies(&dependency_names); | 424 SplitDependencyName(full_name, &feature_type, &feature_name); |
| 428 | 425 |
| 426 std::string child_name; | |
| 427 std::string api_name = GetAPINameFromFullName(feature_name, &child_name); | |
|
not at google - send to devlin
2013/03/26 00:34:48
nit: eyes want a newline after api_name.
cduvall
2013/03/26 19:24:05
Done.
| |
| 429 // Check APIs not using the feature system first. | 428 // Check APIs not using the feature system first. |
| 430 if (!UsesFeatureSystem(full_name)) { | 429 if (!UsesFeatureSystem(api_name)) { |
| 431 return IsNonFeatureAPIAvailable(full_name, context, extension, url) ? | 430 // Make sure schema is loaded. |
| 431 GetSchema(api_name); | |
| 432 return IsNonFeatureAPIAvailable(api_name, context, extension, url) ? | |
|
not at google - send to devlin
2013/03/26 00:34:48
I think the GetSchema thing should go in IsNonFeat
cduvall
2013/03/26 19:24:05
Done.
| |
| 432 Feature::CreateAvailability(Feature::IS_AVAILABLE, "") : | 433 Feature::CreateAvailability(Feature::IS_AVAILABLE, "") : |
| 433 Feature::CreateAvailability(Feature::INVALID_CONTEXT, | 434 Feature::CreateAvailability(Feature::INVALID_CONTEXT, |
| 434 kUnavailableMessage); | 435 kUnavailableMessage); |
| 435 } | 436 } |
| 436 | 437 |
| 437 for (std::set<std::string>::iterator iter = dependency_names.begin(); | 438 Feature* feature = GetFeatureDependency(full_name); |
| 438 iter != dependency_names.end(); ++iter) { | 439 CHECK(feature) << full_name; |
|
not at google - send to devlin
2013/03/26 00:34:48
yeah, here we're CHECKing anyway.
cduvall
2013/03/26 19:24:05
Done.
| |
| 439 Feature* feature = GetFeatureDependency(*iter); | 440 Feature::Availability availability = |
| 440 CHECK(feature) << *iter; | 441 feature->IsAvailableToContext(extension, context, url); |
| 442 if (!availability.is_available()) | |
| 443 return availability; | |
| 441 | 444 |
| 442 Feature::Availability availability = | 445 for (std::set<std::string>::iterator iter = feature->dependencies().begin(); |
| 443 feature->IsAvailableToContext(extension, context, url); | 446 iter != feature->dependencies().end(); ++iter) { |
| 444 if (!availability.is_available()) | 447 Feature::Availability dependency_availability = |
| 445 return availability; | 448 IsAvailable(*iter, extension, context, url); |
| 449 if (!dependency_availability.is_available()) | |
| 450 return dependency_availability; | |
| 446 } | 451 } |
| 447 | 452 |
| 448 return Feature::CreateAvailability(Feature::IS_AVAILABLE, ""); | 453 return Feature::CreateAvailability(Feature::IS_AVAILABLE, ""); |
| 449 } | 454 } |
| 450 | 455 |
| 451 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { | 456 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { |
| 452 std::string child_name; | 457 std::string child_name; |
| 453 std::string api_name = GetAPINameFromFullName(full_name, &child_name); | 458 std::string api_name = GetAPINameFromFullName(full_name, &child_name); |
| 454 | 459 |
| 455 // First try to use the feature system. | 460 // First try to use the feature system. |
| 456 Feature* feature(GetFeature(full_name)); | 461 if (UsesFeatureSystem(full_name)) { |
| 457 if (feature) { | |
| 458 // An API is 'privileged' if it or any of its dependencies can only be run | 462 // An API is 'privileged' if it or any of its dependencies can only be run |
| 459 // in a blessed context. | 463 // in a blessed context. |
|
not at google - send to devlin
2013/03/26 00:34:48
I don't think this checking dependencies really ma
cduvall
2013/03/26 19:24:05
Taking out the dependency checks causes ExtensionA
not at google - send to devlin
2013/03/26 21:31:21
I can't find this. Are you referring to privileged
cduvall
2013/03/26 22:08:48
Ok, I removed dependency checking from IsPrivilege
| |
| 460 std::set<std::string> resolved_dependencies; | 464 Feature* feature = GetFeatureDependency(full_name); |
|
not at google - send to devlin
2013/03/26 00:34:48
and here we could assign Feature up on line 460 an
cduvall
2013/03/26 19:24:05
Done.
| |
| 461 resolved_dependencies.insert(full_name); | 465 std::set<std::string> dependencies = feature->dependencies(); |
| 462 ResolveDependencies(&resolved_dependencies); | 466 for (std::set<Feature::Context>::iterator context = |
| 463 for (std::set<std::string>::iterator iter = resolved_dependencies.begin(); | 467 feature->GetContexts()->begin(); |
| 464 iter != resolved_dependencies.end(); ++iter) { | 468 context != feature->GetContexts()->end(); ++context) { |
| 465 Feature* dependency = GetFeatureDependency(*iter); | 469 if (*context != Feature::BLESSED_EXTENSION_CONTEXT) |
| 466 for (std::set<Feature::Context>::iterator context = | 470 return false; |
| 467 dependency->GetContexts()->begin(); | 471 } |
| 468 context != dependency->GetContexts()->end(); ++context) { | 472 for (std::set<std::string>::iterator iter = dependencies.begin(); |
| 469 if (*context != Feature::BLESSED_EXTENSION_CONTEXT) | 473 iter != dependencies.end(); ++iter) { |
| 470 return false; | 474 if (!IsPrivileged(*iter)) |
| 471 } | 475 return false; |
| 472 } | 476 } |
| 473 return true; | 477 return true; |
| 474 } | 478 } |
| 475 | 479 |
| 480 const DictionaryValue* schema = GetSchema(api_name); | |
|
not at google - send to devlin
2013/03/26 00:34:48
nice catch.
// get now to populate |completely_un
cduvall
2013/03/26 19:24:05
Done.
| |
| 476 // If this API hasn't been converted yet, fall back to the old system. | 481 // If this API hasn't been converted yet, fall back to the old system. |
| 477 if (completely_unprivileged_apis_.count(api_name)) | 482 if (completely_unprivileged_apis_.count(api_name)) |
| 478 return false; | 483 return false; |
| 479 | 484 |
| 480 const DictionaryValue* schema = GetSchema(api_name); | |
| 481 if (partially_unprivileged_apis_.count(api_name)) | 485 if (partially_unprivileged_apis_.count(api_name)) |
| 482 return IsChildNamePrivileged(schema, child_name); | 486 return IsChildNamePrivileged(schema, child_name); |
| 483 | 487 |
| 484 return true; | 488 return true; |
| 485 } | 489 } |
| 486 | 490 |
| 487 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node, | 491 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node, |
| 488 const std::string& child_name) { | 492 const std::string& child_name) { |
| 489 bool unprivileged = false; | 493 bool unprivileged = false; |
| 490 const DictionaryValue* child = GetSchemaChild(name_space_node, child_name); | 494 const DictionaryValue* child = GetSchemaChild(name_space_node, child_name); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 590 std::set<std::string> result; | 594 std::set<std::string> result; |
| 591 for (SchemaMap::iterator i = schemas_.begin(); i != schemas_.end(); ++i) | 595 for (SchemaMap::iterator i = schemas_.begin(); i != schemas_.end(); ++i) |
| 592 result.insert(i->first); | 596 result.insert(i->first); |
| 593 for (UnloadedSchemaMap::iterator i = unloaded_schemas_.begin(); | 597 for (UnloadedSchemaMap::iterator i = unloaded_schemas_.begin(); |
| 594 i != unloaded_schemas_.end(); ++i) { | 598 i != unloaded_schemas_.end(); ++i) { |
| 595 result.insert(i->first); | 599 result.insert(i->first); |
| 596 } | 600 } |
| 597 return result; | 601 return result; |
| 598 } | 602 } |
| 599 | 603 |
| 600 Feature* ExtensionAPI::GetFeature(const std::string& full_name) { | |
| 601 // Ensure it's loaded. | |
| 602 GetSchema(full_name); | |
| 603 | |
| 604 std::string child_name; | |
| 605 std::string api_namespace = GetAPINameFromFullName(full_name, &child_name); | |
| 606 | |
| 607 APIFeatureMap::iterator feature_map = features_.find(api_namespace); | |
| 608 if (feature_map == features_.end()) | |
| 609 return NULL; | |
| 610 | |
| 611 Feature* result = NULL; | |
| 612 FeatureMap::iterator child_feature = feature_map->second->find(child_name); | |
| 613 if (child_feature != feature_map->second->end()) { | |
| 614 result = child_feature->second.get(); | |
| 615 } else { | |
| 616 FeatureMap::iterator parent_feature = feature_map->second->find(""); | |
| 617 CHECK(parent_feature != feature_map->second->end()); | |
| 618 result = parent_feature->second.get(); | |
| 619 } | |
| 620 | |
| 621 if (result->GetContexts()->empty()) { | |
| 622 LOG(ERROR) << "API feature '" << full_name | |
| 623 << "' must specify at least one context."; | |
| 624 return NULL; | |
| 625 } | |
| 626 | |
| 627 return result; | |
| 628 } | |
| 629 | |
| 630 Feature* ExtensionAPI::GetFeatureDependency(const std::string& full_name) { | 604 Feature* ExtensionAPI::GetFeatureDependency(const std::string& full_name) { |
| 605 Feature* feature = TryGetFeatureDependency(full_name); | |
| 606 CHECK(feature) << full_name; | |
| 607 return feature; | |
| 608 } | |
| 609 | |
| 610 Feature* ExtensionAPI::TryGetFeatureDependency(const std::string& full_name) { | |
|
not at google - send to devlin
2013/03/26 00:34:48
I think this is my favourite method. Let's delete
cduvall
2013/03/26 19:24:05
Done.
| |
| 631 std::string feature_type; | 611 std::string feature_type; |
| 632 std::string feature_name; | 612 std::string feature_name; |
| 633 SplitDependencyName(full_name, &feature_type, &feature_name); | 613 SplitDependencyName(full_name, &feature_type, &feature_name); |
| 634 | 614 |
| 635 FeatureProviderMap::iterator provider = | 615 FeatureProviderMap::iterator provider = |
| 636 dependency_providers_.find(feature_type); | 616 dependency_providers_.find(feature_type); |
| 637 CHECK(provider != dependency_providers_.end()) << full_name; | 617 if (provider == dependency_providers_.end()) |
| 618 return NULL; | |
| 638 | 619 |
| 639 Feature* feature = provider->second->GetFeature(feature_name); | 620 Feature* feature = provider->second->GetFeature(feature_name); |
| 640 CHECK(feature) << full_name; | 621 // Try getting the feature for the parent API, if this was a child. |
|
not at google - send to devlin
2013/03/26 00:34:48
In the general case I think we need to step all th
cduvall
2013/03/26 19:24:05
GetAPINameFromFullName() guarantees to either retu
not at google - send to devlin
2013/03/26 21:31:21
Oh ok, never mind.
| |
| 641 | 622 if (!feature) { |
| 623 std::string child_name; | |
| 624 feature = provider->second->GetFeature( | |
| 625 GetAPINameFromFullName(feature_name, &child_name)); | |
| 626 } | |
| 642 return feature; | 627 return feature; |
| 643 } | 628 } |
| 644 | 629 |
| 645 std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name, | 630 std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name, |
| 646 std::string* child_name) { | 631 std::string* child_name) { |
| 647 std::string api_name_candidate = full_name; | 632 std::string api_name_candidate = full_name; |
| 648 while (true) { | 633 while (true) { |
| 649 if (features_.find(api_name_candidate) != features_.end() || | 634 if (features_.find(api_name_candidate) != features_.end() || |
| 650 schemas_.find(api_name_candidate) != schemas_.end() || | 635 schemas_.find(api_name_candidate) != schemas_.end() || |
| 651 unloaded_schemas_.find(api_name_candidate) != unloaded_schemas_.end()) { | 636 unloaded_schemas_.find(api_name_candidate) != unloaded_schemas_.end()) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 671 *child_name = ""; | 656 *child_name = ""; |
| 672 return ""; | 657 return ""; |
| 673 } | 658 } |
| 674 | 659 |
| 675 bool ExtensionAPI::IsAPIAllowed(const std::string& name, | 660 bool ExtensionAPI::IsAPIAllowed(const std::string& name, |
| 676 const Extension* extension) { | 661 const Extension* extension) { |
| 677 return extension->required_permission_set()->HasAnyAccessToAPI(name) || | 662 return extension->required_permission_set()->HasAnyAccessToAPI(name) || |
| 678 extension->optional_permission_set()->HasAnyAccessToAPI(name); | 663 extension->optional_permission_set()->HasAnyAccessToAPI(name); |
| 679 } | 664 } |
| 680 | 665 |
| 681 void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) { | |
| 682 std::set<std::string> missing_dependencies; | |
| 683 for (std::set<std::string>::iterator i = out->begin(); i != out->end(); ++i) | |
| 684 GetMissingDependencies(*i, *out, &missing_dependencies); | |
| 685 | |
| 686 while (missing_dependencies.size()) { | |
| 687 std::string next = *missing_dependencies.begin(); | |
| 688 missing_dependencies.erase(next); | |
| 689 out->insert(next); | |
| 690 GetMissingDependencies(next, *out, &missing_dependencies); | |
| 691 } | |
| 692 } | |
| 693 | |
| 694 void ExtensionAPI::GetMissingDependencies( | |
| 695 const std::string& api_name, | |
| 696 const std::set<std::string>& excluding, | |
| 697 std::set<std::string>* out) { | |
| 698 std::string feature_type; | |
| 699 std::string feature_name; | |
| 700 SplitDependencyName(api_name, &feature_type, &feature_name); | |
| 701 | |
| 702 // Only API features can have dependencies for now. | |
| 703 if (feature_type != "api") | |
| 704 return; | |
| 705 | |
| 706 const DictionaryValue* schema = GetSchema(feature_name); | |
| 707 CHECK(schema) << "Schema for " << feature_name << " not found"; | |
| 708 | |
| 709 const ListValue* dependencies = NULL; | |
| 710 if (!schema->GetList("dependencies", &dependencies)) | |
| 711 return; | |
| 712 | |
| 713 for (size_t i = 0; i < dependencies->GetSize(); ++i) { | |
| 714 std::string dependency_name; | |
| 715 if (dependencies->GetString(i, &dependency_name) && | |
| 716 !excluding.count(dependency_name)) { | |
| 717 out->insert(dependency_name); | |
| 718 } | |
| 719 } | |
| 720 } | |
| 721 | |
| 722 bool ExtensionAPI::IsPrivilegedAPI(const std::string& name) { | 666 bool ExtensionAPI::IsPrivilegedAPI(const std::string& name) { |
| 723 return completely_unprivileged_apis_.count(name) || | 667 return completely_unprivileged_apis_.count(name) || |
| 724 partially_unprivileged_apis_.count(name); | 668 partially_unprivileged_apis_.count(name); |
| 725 } | 669 } |
| 726 | 670 |
| 727 } // namespace extensions | 671 } // namespace extensions |
| OLD | NEW |