Index: chrome/common/extensions/api/extension_api.cc |
diff --git a/chrome/common/extensions/api/extension_api.cc b/chrome/common/extensions/api/extension_api.cc |
index c9988e55859afcf51739c3027444ac6cf5aab99c..c2a9cce97931c24a04b16ad3b7f1e8a911e57e13 100644 |
--- a/chrome/common/extensions/api/extension_api.cc |
+++ b/chrome/common/extensions/api/extension_api.cc |
@@ -36,6 +36,10 @@ using api::GeneratedSchemas; |
namespace { |
+const char kUnavailableMessage[] = "You do not have permission to access this " |
+ "API. Ensure that the required permission " |
+ "or manifest property is included in your " |
+ "manifest.json."; |
const char* kChildKinds[] = { |
"functions", |
"events" |
@@ -230,6 +234,11 @@ void ExtensionAPI::SplitDependencyName(const std::string& full_name, |
*feature_name = full_name.substr(colon_index + 1); |
} |
+bool ExtensionAPI::UsesFeatureSystem(const std::string& full_name) { |
+ std::string api_name = GetAPINameFromFullName(full_name, NULL); |
+ return features_.find(api_name) != features_.end(); |
+} |
+ |
void ExtensionAPI::LoadSchema(const std::string& name, |
const base::StringPiece& schema) { |
scoped_ptr<ListValue> schema_list(LoadSchemaList(name, schema)); |
@@ -250,7 +259,7 @@ void ExtensionAPI::LoadSchema(const std::string& name, |
CHECK_EQ(1u, unloaded_schemas_.erase(schema_namespace)); |
// Populate |{completely,partially}_unprivileged_apis_|. |
- // |
+ |
// For "partially", only need to look at functions/events; even though |
// there are unprivileged properties (e.g. in extensions), access to those |
// never reaches C++ land. |
@@ -263,27 +272,28 @@ void ExtensionAPI::LoadSchema(const std::string& name, |
partially_unprivileged_apis_.insert(schema_namespace); |
} |
- // Populate |url_matching_apis_|. |
- ListValue* matches = NULL; |
- if (schema->GetList("matches", &matches)) { |
- URLPatternSet pattern_set; |
- for (size_t i = 0; i < matches->GetSize(); ++i) { |
- std::string pattern; |
- CHECK(matches->GetString(i, &pattern)); |
- pattern_set.AddPattern( |
- URLPattern(UserScript::ValidUserScriptSchemes(), pattern)); |
+ bool uses_feature_system = false; |
+ schema->GetBoolean("uses_feature_system", &uses_feature_system); |
+ |
+ if (!uses_feature_system) { |
+ // Populate |url_matching_apis_|. |
+ ListValue* matches = NULL; |
+ if (schema->GetList("matches", &matches)) { |
+ URLPatternSet pattern_set; |
+ for (size_t i = 0; i < matches->GetSize(); ++i) { |
+ std::string pattern; |
+ CHECK(matches->GetString(i, &pattern)); |
+ pattern_set.AddPattern( |
+ URLPattern(UserScript::ValidUserScriptSchemes(), pattern)); |
+ } |
+ url_matching_apis_[schema_namespace] = pattern_set; |
} |
- url_matching_apis_[schema_namespace] = pattern_set; |
+ continue; |
} |
// Populate feature maps. |
// TODO(aa): Consider not storing features that can never run on the current |
// machine (e.g., because of platform restrictions). |
- bool uses_feature_system = false; |
- schema->GetBoolean("uses_feature_system", &uses_feature_system); |
- if (!uses_feature_system) |
- continue; |
- |
SimpleFeature* feature = new SimpleFeature(); |
feature->set_name(schema_namespace); |
feature->Parse(schema); |
@@ -408,25 +418,34 @@ void ExtensionAPI::RegisterDependencyProvider(const std::string& name, |
dependency_providers_[name] = provider; |
} |
-bool ExtensionAPI::IsAvailable(const std::string& full_name, |
- const Extension* extension, |
- Feature::Context context) { |
+Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name, |
+ const Extension* extension, |
+ Feature::Context context, |
+ const GURL& url) { |
std::set<std::string> dependency_names; |
dependency_names.insert(full_name); |
ResolveDependencies(&dependency_names); |
+ // Check APIs not using the feature system first. |
+ if (!UsesFeatureSystem(full_name)) { |
+ return IsNonFeatureAPIAvailable(full_name, context, extension, url) ? |
+ Feature::CreateAvailability(Feature::IS_AVAILABLE, "") : |
+ Feature::CreateAvailability(Feature::INVALID_CONTEXT, |
+ kUnavailableMessage); |
+ } |
+ |
for (std::set<std::string>::iterator iter = dependency_names.begin(); |
iter != dependency_names.end(); ++iter) { |
- Feature* feature = GetFeatureDependency(full_name); |
+ Feature* feature = GetFeatureDependency(*iter); |
CHECK(feature) << *iter; |
Feature::Availability availability = |
- feature->IsAvailableToContext(extension, context); |
+ feature->IsAvailableToContext(extension, context, url); |
if (!availability.is_available()) |
- return false; |
+ return availability; |
} |
- return true; |
+ return Feature::CreateAvailability(Feature::IS_AVAILABLE, ""); |
} |
bool ExtensionAPI::IsPrivileged(const std::string& full_name) { |
@@ -524,46 +543,12 @@ bool IsFeatureAllowedForExtension(const std::string& feature, |
return true; |
} |
-// Removes APIs from |apis| that should not be allowed for |extension|. |
-// TODO(kalman/asargent) - Make it possible to specify these rules |
-// declaratively. |
-void RemoveDisallowedAPIs(const Extension& extension, |
- std::set<std::string>* apis) { |
- CHECK(apis); |
- std::set<std::string>::iterator i = apis->begin(); |
- while (i != apis->end()) { |
- if (!IsFeatureAllowedForExtension(*i, extension)) { |
- apis->erase(i++); |
- } else { |
- ++i; |
- } |
- } |
-} |
- |
} // namespace |
-std::set<std::string> ExtensionAPI::GetAPIsForContext( |
- Feature::Context context, const Extension* extension, const GURL& url) { |
- // We're forced to load all schemas now because we need to know the metadata |
- // about every API -- and the metadata is stored in the schemas themselves. |
- // This is a shame. |
- // TODO(aa/kalman): store metadata in a separate file and don't load all |
- // schemas. |
- LoadAllSchemas(); |
- |
- std::set<std::string> temp_result; |
- |
- // First handle all the APIs that have been converted to the feature system. |
- if (extension) { |
- for (APIFeatureMap::iterator iter = features_.begin(); |
- iter != features_.end(); ++iter) { |
- if (IsAvailable(iter->first, extension, context)) |
- temp_result.insert(iter->first); |
- } |
- } |
- |
- // Second, fall back to the old way. |
- // TODO(aa): Remove this when all APIs have been converted. |
+bool ExtensionAPI::IsNonFeatureAPIAvailable(const std::string& name, |
+ Feature::Context context, |
+ const Extension* extension, |
+ const GURL& url) { |
switch (context) { |
case Feature::UNSPECIFIED_CONTEXT: |
break; |
@@ -571,9 +556,10 @@ std::set<std::string> ExtensionAPI::GetAPIsForContext( |
case Feature::BLESSED_EXTENSION_CONTEXT: |
if (extension) { |
// Availability is determined by the permissions of the extension. |
- GetAllowedAPIs(extension, &temp_result); |
- ResolveDependencies(&temp_result); |
- RemoveDisallowedAPIs(*extension, &temp_result); |
+ if (!IsAPIAllowed(name, extension)) |
+ return false; |
+ if (!IsFeatureAllowedForExtension(name, *extension)) |
+ return false; |
} |
break; |
@@ -582,35 +568,22 @@ std::set<std::string> ExtensionAPI::GetAPIsForContext( |
if (extension) { |
// Same as BLESSED_EXTENSION_CONTEXT, but only those APIs that are |
// unprivileged. |
- GetAllowedAPIs(extension, &temp_result); |
- // Resolving dependencies before removing unprivileged APIs means that |
- // some unprivileged APIs may have unrealised dependencies. Too bad! |
- ResolveDependencies(&temp_result); |
- RemovePrivilegedAPIs(&temp_result); |
+ if (!IsAPIAllowed(name, extension)) |
+ return false; |
+ if (!IsPrivilegedAPI(name)) |
+ return false; |
} |
break; |
case Feature::WEB_PAGE_CONTEXT: |
- if (url.is_valid()) { |
- // Availablility is determined by the url. |
- GetAPIsMatchingURL(url, &temp_result); |
- } |
- break; |
- } |
- |
- // Filter out all non-API features and remove the feature type part of the |
- // name. |
- std::set<std::string> result; |
- for (std::set<std::string>::iterator iter = temp_result.begin(); |
- iter != temp_result.end(); ++iter) { |
- std::string feature_type; |
- std::string feature_name; |
- SplitDependencyName(*iter, &feature_type, &feature_name); |
- if (feature_type == "api") |
- result.insert(feature_name); |
+ if (!url_matching_apis_.count(name)) |
+ return false; |
+ CHECK(url.is_valid()); |
+ // Availablility is determined by the url. |
+ return url_matching_apis_[name].MatchesURL(url); |
} |
- return result; |
+ return true; |
} |
std::set<std::string> ExtensionAPI::GetAllAPINames() { |
@@ -699,20 +672,10 @@ std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name, |
return ""; |
} |
-void ExtensionAPI::GetAllowedAPIs( |
- const Extension* extension, std::set<std::string>* out) { |
- for (SchemaMap::const_iterator i = schemas_.begin(); i != schemas_.end(); |
- ++i) { |
- if (features_.find(i->first) != features_.end()) { |
- // This API is controlled by the feature system. Nothing to do here. |
- continue; |
- } |
- |
- if (extension->required_permission_set()->HasAnyAccessToAPI(i->first) || |
- extension->optional_permission_set()->HasAnyAccessToAPI(i->first)) { |
- out->insert(i->first); |
- } |
- } |
+bool ExtensionAPI::IsAPIAllowed(const std::string& name, |
+ const Extension* extension) { |
+ return extension->required_permission_set()->HasAnyAccessToAPI(name) || |
+ extension->optional_permission_set()->HasAnyAccessToAPI(name); |
} |
void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) { |
@@ -756,41 +719,9 @@ void ExtensionAPI::GetMissingDependencies( |
} |
} |
-void ExtensionAPI::RemovePrivilegedAPIs(std::set<std::string>* apis) { |
- std::set<std::string> privileged_apis; |
- for (std::set<std::string>::iterator i = apis->begin(); i != apis->end(); |
- ++i) { |
- if (!completely_unprivileged_apis_.count(*i) && |
- !partially_unprivileged_apis_.count(*i)) { |
- privileged_apis.insert(*i); |
- } |
- } |
- for (std::set<std::string>::iterator i = privileged_apis.begin(); |
- i != privileged_apis.end(); ++i) { |
- apis->erase(*i); |
- } |
-} |
- |
-void ExtensionAPI::GetAPIsMatchingURL(const GURL& url, |
- std::set<std::string>* out) { |
- for (std::map<std::string, URLPatternSet>::const_iterator i = |
- url_matching_apis_.begin(); i != url_matching_apis_.end(); ++i) { |
- if (features_.find(i->first) != features_.end()) { |
- // This API is controlled by the feature system. Nothing to do. |
- continue; |
- } |
- |
- if (i->second.MatchesURL(url)) |
- out->insert(i->first); |
- } |
-} |
- |
-void ExtensionAPI::LoadAllSchemas() { |
- while (unloaded_schemas_.size()) { |
- std::map<std::string, base::StringPiece>::iterator it = |
- unloaded_schemas_.begin(); |
- LoadSchema(it->first, it->second); |
- } |
+bool ExtensionAPI::IsPrivilegedAPI(const std::string& name) { |
+ return completely_unprivileged_apis_.count(name) || |
+ partially_unprivileged_apis_.count(name); |
} |
} // namespace extensions |