| 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 |