| 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 |
| 11 #include "base/json/json_reader.h" | 11 #include "base/json/json_reader.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/string_split.h" | 13 #include "base/string_split.h" |
| 14 #include "base/string_util.h" | 14 #include "base/string_util.h" |
| 15 #include "base/values.h" | 15 #include "base/values.h" |
| 16 #include "chrome/common/extensions/extension.h" | 16 #include "chrome/common/extensions/extension.h" |
| 17 #include "chrome/common/extensions/extension_permission_set.h" | 17 #include "chrome/common/extensions/extension_permission_set.h" |
| 18 #include "googleurl/src/gurl.h" |
| 18 #include "grit/common_resources.h" | 19 #include "grit/common_resources.h" |
| 19 #include "ui/base/resource/resource_bundle.h" | 20 #include "ui/base/resource/resource_bundle.h" |
| 20 | 21 |
| 21 namespace extensions { | 22 namespace extensions { |
| 22 | 23 |
| 23 namespace { | 24 namespace { |
| 24 | 25 |
| 25 // Adds any APIs listed in "dependencies" found in |schema| but not in | |
| 26 // |reference| to |out|. | |
| 27 void GetMissingDependencies( | |
| 28 const DictionaryValue& schema, | |
| 29 const ExtensionAPI::SchemaMap& reference, | |
| 30 std::set<std::string>* out) { | |
| 31 ListValue* dependencies = NULL; | |
| 32 if (!schema.GetList("dependencies", &dependencies)) | |
| 33 return; | |
| 34 for (size_t i = 0; i < dependencies->GetSize(); ++i) { | |
| 35 std::string api_name; | |
| 36 if (dependencies->GetString(i, &api_name) && !reference.count(api_name)) | |
| 37 out->insert(api_name); | |
| 38 } | |
| 39 } | |
| 40 | |
| 41 // Returns whether the list at |name_space_node|.|child_kind| contains any | 26 // Returns whether the list at |name_space_node|.|child_kind| contains any |
| 42 // children with an { "unprivileged": true } property. | 27 // children with an { "unprivileged": true } property. |
| 43 bool HasUnprivilegedChild(const DictionaryValue* name_space_node, | 28 bool HasUnprivilegedChild(const DictionaryValue* name_space_node, |
| 44 const std::string& child_kind) { | 29 const std::string& child_kind) { |
| 45 ListValue* child_list = NULL; | 30 ListValue* child_list = NULL; |
| 46 name_space_node->GetList(child_kind, &child_list); | 31 name_space_node->GetList(child_kind, &child_list); |
| 47 if (!child_list) | 32 if (!child_list) |
| 48 return false; | 33 return false; |
| 49 | 34 |
| 50 for (size_t i = 0; i < child_list->GetSize(); ++i) { | 35 for (size_t i = 0; i < child_list->GetSize(); ++i) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 loaded->Remove(loaded->GetSize() - 1, &value); | 73 loaded->Remove(loaded->GetSize() - 1, &value); |
| 89 CHECK(value->IsType(Value::TYPE_DICTIONARY)); | 74 CHECK(value->IsType(Value::TYPE_DICTIONARY)); |
| 90 const DictionaryValue* schema = static_cast<const DictionaryValue*>(value); | 75 const DictionaryValue* schema = static_cast<const DictionaryValue*>(value); |
| 91 CHECK(schema->GetString("namespace", &schema_namespace)); | 76 CHECK(schema->GetString("namespace", &schema_namespace)); |
| 92 schemas_[schema_namespace] = linked_ptr<const DictionaryValue>(schema); | 77 schemas_[schema_namespace] = linked_ptr<const DictionaryValue>(schema); |
| 93 } | 78 } |
| 94 } | 79 } |
| 95 | 80 |
| 96 ExtensionAPI::ExtensionAPI() { | 81 ExtensionAPI::ExtensionAPI() { |
| 97 static int kJsonApiResourceIds[] = { | 82 static int kJsonApiResourceIds[] = { |
| 83 IDR_EXTENSION_API_JSON_APP, |
| 98 IDR_EXTENSION_API_JSON_BOOKMARKS, | 84 IDR_EXTENSION_API_JSON_BOOKMARKS, |
| 99 IDR_EXTENSION_API_JSON_BROWSERACTION, | 85 IDR_EXTENSION_API_JSON_BROWSERACTION, |
| 100 IDR_EXTENSION_API_JSON_BROWSING_DATA, | 86 IDR_EXTENSION_API_JSON_BROWSING_DATA, |
| 101 IDR_EXTENSION_API_JSON_CHROMEAUTHPRIVATE, | 87 IDR_EXTENSION_API_JSON_CHROMEAUTHPRIVATE, |
| 102 IDR_EXTENSION_API_JSON_CHROMEOSINFOPRIVATE, | 88 IDR_EXTENSION_API_JSON_CHROMEOSINFOPRIVATE, |
| 103 IDR_EXTENSION_API_JSON_CHROMEPRIVATE, | 89 IDR_EXTENSION_API_JSON_CHROMEPRIVATE, |
| 104 IDR_EXTENSION_API_JSON_CONTENTSETTINGS, | 90 IDR_EXTENSION_API_JSON_CONTENTSETTINGS, |
| 105 IDR_EXTENSION_API_JSON_CONTEXTMENUS, | 91 IDR_EXTENSION_API_JSON_CONTEXTMENUS, |
| 106 IDR_EXTENSION_API_JSON_COOKIES, | 92 IDR_EXTENSION_API_JSON_COOKIES, |
| 107 IDR_EXTENSION_API_JSON_DEBUGGER, | 93 IDR_EXTENSION_API_JSON_DEBUGGER, |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 continue; | 158 continue; |
| 173 } | 159 } |
| 174 | 160 |
| 175 // Only need to look at functions/events; even though there are unprivileged | 161 // Only need to look at functions/events; even though there are unprivileged |
| 176 // properties (e.g. in extensions), access to those never reaches C++ land. | 162 // properties (e.g. in extensions), access to those never reaches C++ land. |
| 177 if (HasUnprivilegedChild(it->second.get(), "functions") || | 163 if (HasUnprivilegedChild(it->second.get(), "functions") || |
| 178 HasUnprivilegedChild(it->second.get(), "events")) { | 164 HasUnprivilegedChild(it->second.get(), "events")) { |
| 179 partially_unprivileged_apis_.insert(it->first); | 165 partially_unprivileged_apis_.insert(it->first); |
| 180 } | 166 } |
| 181 } | 167 } |
| 168 |
| 169 // Populate |url_matching_apis_|. |
| 170 for (SchemaMap::const_iterator it = schemas_.begin(); |
| 171 it != schemas_.end(); ++it) { |
| 172 ListValue* matches = NULL; |
| 173 { |
| 174 Value* matches_value = NULL; |
| 175 if (!it->second->Get("matches", &matches_value)) |
| 176 continue; |
| 177 CHECK_EQ(Value::TYPE_LIST, matches_value->GetType()); |
| 178 matches = static_cast<ListValue*>(matches_value); |
| 179 } |
| 180 URLPatternSet pattern_set; |
| 181 for (size_t i = 0; i < matches->GetSize(); ++i) { |
| 182 std::string pattern; |
| 183 CHECK(matches->GetString(i, &pattern)); |
| 184 pattern_set.AddPattern( |
| 185 URLPattern(UserScript::kValidUserScriptSchemes, pattern)); |
| 186 } |
| 187 url_matching_apis_[it->first] = pattern_set; |
| 188 } |
| 182 } | 189 } |
| 183 | 190 |
| 184 ExtensionAPI::~ExtensionAPI() { | 191 ExtensionAPI::~ExtensionAPI() { |
| 185 } | 192 } |
| 186 | 193 |
| 187 bool ExtensionAPI::IsPrivileged(const std::string& full_name) const { | 194 bool ExtensionAPI::IsPrivileged(const std::string& full_name) const { |
| 188 std::string api_name; | 195 std::string api_name; |
| 189 std::string child_name; | 196 std::string child_name; |
| 190 | 197 |
| 191 { | 198 { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 | 258 |
| 252 return !unprivileged; | 259 return !unprivileged; |
| 253 } | 260 } |
| 254 | 261 |
| 255 const base::DictionaryValue* ExtensionAPI::GetSchema( | 262 const base::DictionaryValue* ExtensionAPI::GetSchema( |
| 256 const std::string& api_name) const { | 263 const std::string& api_name) const { |
| 257 SchemaMap::const_iterator maybe_schema = schemas_.find(api_name); | 264 SchemaMap::const_iterator maybe_schema = schemas_.find(api_name); |
| 258 return maybe_schema != schemas_.end() ? maybe_schema->second.get() : NULL; | 265 return maybe_schema != schemas_.end() ? maybe_schema->second.get() : NULL; |
| 259 } | 266 } |
| 260 | 267 |
| 261 void ExtensionAPI::GetSchemasForExtension(const Extension& extension, | 268 scoped_ptr<std::set<std::string> > ExtensionAPI::GetAPIsForContext( |
| 262 GetSchemasFilter filter, | 269 Feature::Context context, |
| 263 SchemaMap* out) const { | 270 const Extension* extension, |
| 264 // Check both required_permissions and optional_permissions since we need | 271 const GURL& url) const { |
| 265 // to return all schemas that might be needed. | 272 scoped_ptr<std::set<std::string> > result(new std::set<std::string>()); |
| 266 GetSchemasForPermissions(*extension.required_permission_set(), filter, out); | |
| 267 GetSchemasForPermissions(*extension.optional_permission_set(), filter, out); | |
| 268 | 273 |
| 269 // Note that dependency resolution might introduce APIs outside of the filter | 274 switch (context) { |
| 270 // (for example, "extensions" has unprivileged componenents but relies on | 275 case Feature::UNSPECIFIED_CONTEXT: |
| 271 // "tabs" which doesn't). It doesn't matter because schema_generated_bindings | 276 break; |
| 272 // does individual function/event based checking anyway, but it's a shame. | 277 |
| 273 ResolveDependencies(out); | 278 case Feature::PRIVILEGED_CONTEXT: |
| 279 // Availability is determined by the permissions of the extension. |
| 280 CHECK(extension); |
| 281 GetAllowedAPIs(extension, result.get()); |
| 282 ResolveDependencies(result.get()); |
| 283 break; |
| 284 |
| 285 case Feature::UNPRIVILEGED_CONTEXT: |
| 286 case Feature::CONTENT_SCRIPT_CONTEXT: |
| 287 // Same as PRIVILEGED_CONTEXT, but only those APIs that are unprivileged. |
| 288 CHECK(extension); |
| 289 GetAllowedAPIs(extension, result.get()); |
| 290 // Resolving dependencies before removing unprivileged APIs means that |
| 291 // some unprivileged APIs may have unrealised dependencies. Too bad! |
| 292 ResolveDependencies(result.get()); |
| 293 RemovePrivilegedAPIs(result.get()); |
| 294 break; |
| 295 |
| 296 case Feature::WEB_PAGE_CONTEXT: |
| 297 // Availablility is determined by the url. |
| 298 CHECK(url.is_valid()); |
| 299 GetAPIsMatchingURL(url, result.get()); |
| 300 break; |
| 301 } |
| 302 |
| 303 return result.Pass(); |
| 274 } | 304 } |
| 275 | 305 |
| 276 void ExtensionAPI::ResolveDependencies(SchemaMap* out) const { | 306 void ExtensionAPI::GetAllowedAPIs( |
| 277 std::set<std::string> missing_dependencies; | 307 const Extension* extension, std::set<std::string>* out) const { |
| 278 for (SchemaMap::const_iterator i = out->begin(); i != out->end(); ++i) | 308 for (SchemaMap::const_iterator i = schemas_.begin(); i != schemas_.end(); |
| 279 GetMissingDependencies(*i->second, *out, &missing_dependencies); | 309 ++i) { |
| 280 | 310 if (extension->required_permission_set()->HasAnyAccessToAPI(i->first) || |
| 281 while (missing_dependencies.size()) { | 311 extension->optional_permission_set()->HasAnyAccessToAPI(i->first)) { |
| 282 std::string api_name = *missing_dependencies.begin(); | 312 out->insert(i->first); |
| 283 missing_dependencies.erase(api_name); | 313 } |
| 284 linked_ptr<const DictionaryValue> schema = schemas_.find(api_name)->second; | |
| 285 (*out)[api_name] = schema; | |
| 286 GetMissingDependencies(*schema, *out, &missing_dependencies); | |
| 287 } | 314 } |
| 288 } | 315 } |
| 289 | 316 |
| 290 void ExtensionAPI::GetDefaultSchemas(GetSchemasFilter filter, | 317 void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) const { |
| 291 SchemaMap* out) const { | 318 std::set<std::string> missing_dependencies; |
| 292 scoped_refptr<ExtensionPermissionSet> default_permissions( | 319 for (std::set<std::string>::iterator i = out->begin(); i != out->end(); ++i) |
| 293 new ExtensionPermissionSet()); | 320 GetMissingDependencies(*i, *out, &missing_dependencies); |
| 294 GetSchemasForPermissions(*default_permissions, filter, out); | |
| 295 ResolveDependencies(out); | |
| 296 } | |
| 297 | 321 |
| 298 void ExtensionAPI::GetSchemasForPermissions( | 322 while (missing_dependencies.size()) { |
| 299 const ExtensionPermissionSet& permissions, | 323 std::string next = *missing_dependencies.begin(); |
| 300 GetSchemasFilter filter, | 324 missing_dependencies.erase(next); |
| 301 SchemaMap* out) const { | 325 out->insert(next); |
| 302 for (SchemaMap::const_iterator it = schemas_.begin(); it != schemas_.end(); | 326 GetMissingDependencies(next, *out, &missing_dependencies); |
| 303 ++it) { | |
| 304 if (filter == ONLY_UNPRIVILEGED && IsWholeAPIPrivileged(it->first)) | |
| 305 continue; | |
| 306 if (permissions.HasAnyAccessToAPI(it->first)) | |
| 307 (*out)[it->first] = it->second; | |
| 308 } | 327 } |
| 309 } | 328 } |
| 310 | 329 |
| 311 bool ExtensionAPI::IsWholeAPIPrivileged(const std::string& api_name) const { | 330 void ExtensionAPI::GetMissingDependencies( |
| 312 return !completely_unprivileged_apis_.count(api_name) && | 331 const std::string& api_name, |
| 313 !partially_unprivileged_apis_.count(api_name); | 332 const std::set<std::string>& excluding, |
| 333 std::set<std::string>* out) const { |
| 334 const base::DictionaryValue* schema = GetSchema(api_name); |
| 335 CHECK(schema) << "Schema for " << api_name << " not found"; |
| 336 |
| 337 ListValue* dependencies = NULL; |
| 338 if (!schema->GetList("dependencies", &dependencies)) |
| 339 return; |
| 340 |
| 341 for (size_t i = 0; i < dependencies->GetSize(); ++i) { |
| 342 std::string api_name; |
| 343 if (dependencies->GetString(i, &api_name) && !excluding.count(api_name)) |
| 344 out->insert(api_name); |
| 345 } |
| 346 } |
| 347 |
| 348 void ExtensionAPI::RemovePrivilegedAPIs(std::set<std::string>* apis) const { |
| 349 std::set<std::string> privileged_apis; |
| 350 for (std::set<std::string>::iterator i = apis->begin(); i != apis->end(); |
| 351 ++i) { |
| 352 if (!completely_unprivileged_apis_.count(*i) && |
| 353 !partially_unprivileged_apis_.count(*i)) { |
| 354 privileged_apis.insert(*i); |
| 355 } |
| 356 } |
| 357 for (std::set<std::string>::iterator i = privileged_apis.begin(); |
| 358 i != privileged_apis.end(); ++i) { |
| 359 apis->erase(*i); |
| 360 } |
| 361 } |
| 362 |
| 363 void ExtensionAPI::GetAPIsMatchingURL(const GURL& url, |
| 364 std::set<std::string>* out) const { |
| 365 for (std::map<std::string, URLPatternSet>::const_iterator i = |
| 366 url_matching_apis_.begin(); i != url_matching_apis_.end(); ++i) { |
| 367 if (i->second.MatchesURL(url)) |
| 368 out->insert(i->first); |
| 369 } |
| 314 } | 370 } |
| 315 | 371 |
| 316 } // namespace extensions | 372 } // namespace extensions |
| OLD | NEW |