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