Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: chrome/common/extensions/api/extension_api.cc

Issue 9460002: Convert app_bindings.js to the schema_generated_bindings.js infrastructure. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: make test extension ID tests pass Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « chrome/common/extensions/api/extension_api.h ('k') | chrome/common/extensions/api/extension_api_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698