| 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 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 227 // TODO(aa): Remove this code when all API descriptions have been updated. | 227 // TODO(aa): Remove this code when all API descriptions have been updated. |
| 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) { | |
| 238 std::string api_name = GetAPINameFromFullName(full_name, NULL); | |
| 239 return features_.find(api_name) != features_.end(); | |
| 240 } | |
| 241 | |
| 242 void ExtensionAPI::LoadSchema(const std::string& name, | 237 void ExtensionAPI::LoadSchema(const std::string& name, |
| 243 const base::StringPiece& schema) { | 238 const base::StringPiece& schema) { |
| 244 scoped_ptr<ListValue> schema_list(LoadSchemaList(name, schema)); | 239 scoped_ptr<ListValue> schema_list(LoadSchemaList(name, schema)); |
| 245 std::string schema_namespace; | 240 std::string schema_namespace; |
| 246 | 241 |
| 247 while (!schema_list->empty()) { | 242 while (!schema_list->empty()) { |
| 248 DictionaryValue* schema = NULL; | 243 DictionaryValue* schema = NULL; |
| 249 { | 244 { |
| 250 Value* value = NULL; | 245 Value* value = NULL; |
| 251 schema_list->Remove(schema_list->GetSize() - 1, &value); | 246 schema_list->Remove(schema_list->GetSize() - 1, &value); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 325 child_feature->set_name(schema_namespace + "." + child_name); | 320 child_feature->set_name(schema_namespace + "." + child_name); |
| 326 CHECK(schema_features->insert( | 321 CHECK(schema_features->insert( |
| 327 std::make_pair(child_name, | 322 std::make_pair(child_name, |
| 328 make_linked_ptr(child_feature.release()))).second); | 323 make_linked_ptr(child_feature.release()))).second); |
| 329 } | 324 } |
| 330 } | 325 } |
| 331 } | 326 } |
| 332 } | 327 } |
| 333 | 328 |
| 334 ExtensionAPI::ExtensionAPI() { | 329 ExtensionAPI::ExtensionAPI() { |
| 335 RegisterDependencyProvider("api", this); | |
| 336 | |
| 337 // TODO(aa): Can remove this when all JSON files are converted. | |
| 338 RegisterDependencyProvider("", this); | |
| 339 } | 330 } |
| 340 | 331 |
| 341 ExtensionAPI::~ExtensionAPI() { | 332 ExtensionAPI::~ExtensionAPI() { |
| 342 } | 333 } |
| 343 | 334 |
| 344 void ExtensionAPI::InitDefaultConfiguration() { | 335 void ExtensionAPI::InitDefaultConfiguration() { |
| 345 RegisterDependencyProvider( | 336 RegisterDependencyProvider( |
| 337 "api", BaseFeatureProvider::GetApiFeatures()); |
| 338 RegisterDependencyProvider( |
| 346 "manifest", BaseFeatureProvider::GetManifestFeatures()); | 339 "manifest", BaseFeatureProvider::GetManifestFeatures()); |
| 347 RegisterDependencyProvider( | 340 RegisterDependencyProvider( |
| 348 "permission", BaseFeatureProvider::GetPermissionFeatures()); | 341 "permission", BaseFeatureProvider::GetPermissionFeatures()); |
| 349 | 342 |
| 350 // Schemas to be loaded from resources. | 343 // Schemas to be loaded from resources. |
| 351 CHECK(unloaded_schemas_.empty()); | 344 CHECK(unloaded_schemas_.empty()); |
| 352 RegisterSchema("app", ReadFromResource( | 345 RegisterSchema("app", ReadFromResource( |
| 353 IDR_EXTENSION_API_JSON_APP)); | 346 IDR_EXTENSION_API_JSON_APP)); |
| 354 RegisterSchema("browserAction", ReadFromResource( | 347 RegisterSchema("browserAction", ReadFromResource( |
| 355 IDR_EXTENSION_API_JSON_BROWSERACTION)); | 348 IDR_EXTENSION_API_JSON_BROWSERACTION)); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 415 | 408 |
| 416 void ExtensionAPI::RegisterDependencyProvider(const std::string& name, | 409 void ExtensionAPI::RegisterDependencyProvider(const std::string& name, |
| 417 FeatureProvider* provider) { | 410 FeatureProvider* provider) { |
| 418 dependency_providers_[name] = provider; | 411 dependency_providers_[name] = provider; |
| 419 } | 412 } |
| 420 | 413 |
| 421 Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name, | 414 Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name, |
| 422 const Extension* extension, | 415 const Extension* extension, |
| 423 Feature::Context context, | 416 Feature::Context context, |
| 424 const GURL& url) { | 417 const GURL& url) { |
| 425 std::set<std::string> dependency_names; | 418 std::string feature_type; |
| 426 dependency_names.insert(full_name); | 419 std::string feature_name; |
| 427 ResolveDependencies(&dependency_names); | 420 SplitDependencyName(full_name, &feature_type, &feature_name); |
| 421 |
| 422 std::string child_name; |
| 423 std::string api_name = GetAPINameFromFullName(feature_name, &child_name); |
| 424 |
| 425 Feature* feature = GetFeatureDependency(full_name); |
| 428 | 426 |
| 429 // Check APIs not using the feature system first. | 427 // Check APIs not using the feature system first. |
| 430 if (!UsesFeatureSystem(full_name)) { | 428 if (!feature) { |
| 431 return IsNonFeatureAPIAvailable(full_name, context, extension, url) ? | 429 return IsNonFeatureAPIAvailable(api_name, context, extension, url) ? |
| 432 Feature::CreateAvailability(Feature::IS_AVAILABLE, "") : | 430 Feature::CreateAvailability(Feature::IS_AVAILABLE, "") : |
| 433 Feature::CreateAvailability(Feature::INVALID_CONTEXT, | 431 Feature::CreateAvailability(Feature::INVALID_CONTEXT, |
| 434 kUnavailableMessage); | 432 kUnavailableMessage); |
| 435 } | 433 } |
| 436 | 434 |
| 437 for (std::set<std::string>::iterator iter = dependency_names.begin(); | 435 Feature::Availability availability = |
| 438 iter != dependency_names.end(); ++iter) { | 436 feature->IsAvailableToContext(extension, context, url); |
| 439 Feature* feature = GetFeatureDependency(*iter); | 437 if (!availability.is_available()) |
| 440 CHECK(feature) << *iter; | 438 return availability; |
| 441 | 439 |
| 442 Feature::Availability availability = | 440 for (std::set<std::string>::iterator iter = feature->dependencies().begin(); |
| 443 feature->IsAvailableToContext(extension, context, url); | 441 iter != feature->dependencies().end(); ++iter) { |
| 444 if (!availability.is_available()) | 442 Feature::Availability dependency_availability = |
| 445 return availability; | 443 IsAvailable(*iter, extension, context, url); |
| 444 if (!dependency_availability.is_available()) |
| 445 return dependency_availability; |
| 446 } | 446 } |
| 447 | 447 |
| 448 return Feature::CreateAvailability(Feature::IS_AVAILABLE, ""); | 448 return Feature::CreateAvailability(Feature::IS_AVAILABLE, ""); |
| 449 } | 449 } |
| 450 | 450 |
| 451 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { | 451 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { |
| 452 std::string child_name; | 452 std::string child_name; |
| 453 std::string api_name = GetAPINameFromFullName(full_name, &child_name); | 453 std::string api_name = GetAPINameFromFullName(full_name, &child_name); |
| 454 Feature* feature = GetFeatureDependency(full_name); |
| 454 | 455 |
| 455 // First try to use the feature system. | 456 // First try to use the feature system. |
| 456 Feature* feature(GetFeature(full_name)); | |
| 457 if (feature) { | 457 if (feature) { |
| 458 // An API is 'privileged' if it or any of its dependencies can only be run | 458 // An API is 'privileged' if it can only be run in a blessed context. |
| 459 // in a blessed context. | 459 return feature->GetContexts()->size() == |
| 460 std::set<std::string> resolved_dependencies; | 460 feature->GetContexts()->count(Feature::BLESSED_EXTENSION_CONTEXT); |
| 461 resolved_dependencies.insert(full_name); | |
| 462 ResolveDependencies(&resolved_dependencies); | |
| 463 for (std::set<std::string>::iterator iter = resolved_dependencies.begin(); | |
| 464 iter != resolved_dependencies.end(); ++iter) { | |
| 465 Feature* dependency = GetFeatureDependency(*iter); | |
| 466 for (std::set<Feature::Context>::iterator context = | |
| 467 dependency->GetContexts()->begin(); | |
| 468 context != dependency->GetContexts()->end(); ++context) { | |
| 469 if (*context != Feature::BLESSED_EXTENSION_CONTEXT) | |
| 470 return false; | |
| 471 } | |
| 472 } | |
| 473 return true; | |
| 474 } | 461 } |
| 475 | 462 |
| 463 // Get the schema now to populate |completely_unprivileged_apis_|. |
| 464 const DictionaryValue* schema = GetSchema(api_name); |
| 476 // If this API hasn't been converted yet, fall back to the old system. | 465 // If this API hasn't been converted yet, fall back to the old system. |
| 477 if (completely_unprivileged_apis_.count(api_name)) | 466 if (completely_unprivileged_apis_.count(api_name)) |
| 478 return false; | 467 return false; |
| 479 | 468 |
| 480 const DictionaryValue* schema = GetSchema(api_name); | |
| 481 if (partially_unprivileged_apis_.count(api_name)) | 469 if (partially_unprivileged_apis_.count(api_name)) |
| 482 return IsChildNamePrivileged(schema, child_name); | 470 return IsChildNamePrivileged(schema, child_name); |
| 483 | 471 |
| 484 return true; | 472 return true; |
| 485 } | 473 } |
| 486 | 474 |
| 487 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node, | 475 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node, |
| 488 const std::string& child_name) { | 476 const std::string& child_name) { |
| 489 bool unprivileged = false; | 477 bool unprivileged = false; |
| 490 const DictionaryValue* child = GetSchemaChild(name_space_node, child_name); | 478 const DictionaryValue* child = GetSchemaChild(name_space_node, child_name); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 542 | 530 |
| 543 return true; | 531 return true; |
| 544 } | 532 } |
| 545 | 533 |
| 546 } // namespace | 534 } // namespace |
| 547 | 535 |
| 548 bool ExtensionAPI::IsNonFeatureAPIAvailable(const std::string& name, | 536 bool ExtensionAPI::IsNonFeatureAPIAvailable(const std::string& name, |
| 549 Feature::Context context, | 537 Feature::Context context, |
| 550 const Extension* extension, | 538 const Extension* extension, |
| 551 const GURL& url) { | 539 const GURL& url) { |
| 540 // Make sure schema is loaded. |
| 541 GetSchema(name); |
| 552 switch (context) { | 542 switch (context) { |
| 553 case Feature::UNSPECIFIED_CONTEXT: | 543 case Feature::UNSPECIFIED_CONTEXT: |
| 554 break; | 544 break; |
| 555 | 545 |
| 556 case Feature::BLESSED_EXTENSION_CONTEXT: | 546 case Feature::BLESSED_EXTENSION_CONTEXT: |
| 557 if (extension) { | 547 if (extension) { |
| 558 // Availability is determined by the permissions of the extension. | 548 // Availability is determined by the permissions of the extension. |
| 559 if (!IsAPIAllowed(name, extension)) | 549 if (!IsAPIAllowed(name, extension)) |
| 560 return false; | 550 return false; |
| 561 if (!IsFeatureAllowedForExtension(name, *extension)) | 551 if (!IsFeatureAllowedForExtension(name, *extension)) |
| (...skipping 28 matching lines...) Expand all Loading... |
| 590 std::set<std::string> result; | 580 std::set<std::string> result; |
| 591 for (SchemaMap::iterator i = schemas_.begin(); i != schemas_.end(); ++i) | 581 for (SchemaMap::iterator i = schemas_.begin(); i != schemas_.end(); ++i) |
| 592 result.insert(i->first); | 582 result.insert(i->first); |
| 593 for (UnloadedSchemaMap::iterator i = unloaded_schemas_.begin(); | 583 for (UnloadedSchemaMap::iterator i = unloaded_schemas_.begin(); |
| 594 i != unloaded_schemas_.end(); ++i) { | 584 i != unloaded_schemas_.end(); ++i) { |
| 595 result.insert(i->first); | 585 result.insert(i->first); |
| 596 } | 586 } |
| 597 return result; | 587 return result; |
| 598 } | 588 } |
| 599 | 589 |
| 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) { | 590 Feature* ExtensionAPI::GetFeatureDependency(const std::string& full_name) { |
| 631 std::string feature_type; | 591 std::string feature_type; |
| 632 std::string feature_name; | 592 std::string feature_name; |
| 633 SplitDependencyName(full_name, &feature_type, &feature_name); | 593 SplitDependencyName(full_name, &feature_type, &feature_name); |
| 634 | 594 |
| 635 FeatureProviderMap::iterator provider = | 595 FeatureProviderMap::iterator provider = |
| 636 dependency_providers_.find(feature_type); | 596 dependency_providers_.find(feature_type); |
| 637 CHECK(provider != dependency_providers_.end()) << full_name; | 597 if (provider == dependency_providers_.end()) |
| 598 return NULL; |
| 638 | 599 |
| 639 Feature* feature = provider->second->GetFeature(feature_name); | 600 Feature* feature = provider->second->GetFeature(feature_name); |
| 640 CHECK(feature) << full_name; | 601 // Try getting the feature for the parent API, if this was a child. |
| 641 | 602 if (!feature) { |
| 603 std::string child_name; |
| 604 feature = provider->second->GetFeature( |
| 605 GetAPINameFromFullName(feature_name, &child_name)); |
| 606 } |
| 642 return feature; | 607 return feature; |
| 643 } | 608 } |
| 644 | 609 |
| 645 std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name, | 610 std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name, |
| 646 std::string* child_name) { | 611 std::string* child_name) { |
| 647 std::string api_name_candidate = full_name; | 612 std::string api_name_candidate = full_name; |
| 648 while (true) { | 613 while (true) { |
| 649 if (features_.find(api_name_candidate) != features_.end() || | 614 if (features_.find(api_name_candidate) != features_.end() || |
| 650 schemas_.find(api_name_candidate) != schemas_.end() || | 615 schemas_.find(api_name_candidate) != schemas_.end() || |
| 651 unloaded_schemas_.find(api_name_candidate) != unloaded_schemas_.end()) { | 616 unloaded_schemas_.find(api_name_candidate) != unloaded_schemas_.end()) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 671 *child_name = ""; | 636 *child_name = ""; |
| 672 return ""; | 637 return ""; |
| 673 } | 638 } |
| 674 | 639 |
| 675 bool ExtensionAPI::IsAPIAllowed(const std::string& name, | 640 bool ExtensionAPI::IsAPIAllowed(const std::string& name, |
| 676 const Extension* extension) { | 641 const Extension* extension) { |
| 677 return extension->required_permission_set()->HasAnyAccessToAPI(name) || | 642 return extension->required_permission_set()->HasAnyAccessToAPI(name) || |
| 678 extension->optional_permission_set()->HasAnyAccessToAPI(name); | 643 extension->optional_permission_set()->HasAnyAccessToAPI(name); |
| 679 } | 644 } |
| 680 | 645 |
| 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) { | 646 bool ExtensionAPI::IsPrivilegedAPI(const std::string& name) { |
| 723 return completely_unprivileged_apis_.count(name) || | 647 return completely_unprivileged_apis_.count(name) || |
| 724 partially_unprivileged_apis_.count(name); | 648 partially_unprivileged_apis_.count(name); |
| 725 } | 649 } |
| 726 | 650 |
| 727 } // namespace extensions | 651 } // namespace extensions |
| OLD | NEW |