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 28 matching lines...) Expand all Loading... | |
39 | 39 |
40 const char kUnavailableMessage[] = "You do not have permission to access this " | 40 const char kUnavailableMessage[] = "You do not have permission to access this " |
41 "API. Ensure that the required permission " | 41 "API. Ensure that the required permission " |
42 "or manifest property is included in your " | 42 "or manifest property is included in your " |
43 "manifest.json."; | 43 "manifest.json."; |
44 const char* kChildKinds[] = { | 44 const char* kChildKinds[] = { |
45 "functions", | 45 "functions", |
46 "events" | 46 "events" |
47 }; | 47 }; |
48 | 48 |
49 // Returns true if |dict| has an unprivileged "true" property. | |
50 bool IsUnprivileged(const DictionaryValue* dict) { | |
51 bool unprivileged = false; | |
52 return dict->GetBoolean("unprivileged", &unprivileged) && unprivileged; | |
53 } | |
54 | |
55 // Returns whether the list at |name_space_node|.|child_kind| contains any | |
56 // children with an { "unprivileged": true } property. | |
57 bool HasUnprivilegedChild(const DictionaryValue* name_space_node, | |
58 const std::string& child_kind) { | |
59 const ListValue* child_list = NULL; | |
60 const DictionaryValue* child_dict = NULL; | |
61 | |
62 if (name_space_node->GetList(child_kind, &child_list)) { | |
63 for (size_t i = 0; i < child_list->GetSize(); ++i) { | |
64 const DictionaryValue* item = NULL; | |
65 CHECK(child_list->GetDictionary(i, &item)); | |
66 if (IsUnprivileged(item)) | |
67 return true; | |
68 } | |
69 } else if (name_space_node->GetDictionary(child_kind, &child_dict)) { | |
70 for (DictionaryValue::Iterator it(*child_dict); !it.IsAtEnd(); | |
71 it.Advance()) { | |
72 const DictionaryValue* item = NULL; | |
73 CHECK(it.value().GetAsDictionary(&item)); | |
74 if (IsUnprivileged(item)) | |
75 return true; | |
76 } | |
77 } | |
78 | |
79 return false; | |
80 } | |
81 | |
82 base::StringPiece ReadFromResource(int resource_id) { | 49 base::StringPiece ReadFromResource(int resource_id) { |
83 return ResourceBundle::GetSharedInstance().GetRawDataResource( | 50 return ResourceBundle::GetSharedInstance().GetRawDataResource( |
84 resource_id); | 51 resource_id); |
85 } | 52 } |
86 | 53 |
87 scoped_ptr<ListValue> LoadSchemaList(const std::string& name, | 54 scoped_ptr<ListValue> LoadSchemaList(const std::string& name, |
88 const base::StringPiece& schema) { | 55 const base::StringPiece& schema) { |
89 std::string error_message; | 56 std::string error_message; |
90 scoped_ptr<Value> result( | 57 scoped_ptr<Value> result( |
91 base::JSONReader::ReadAndReturnError( | 58 base::JSONReader::ReadAndReturnError( |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
192 CHECK(schema->GetList("types", &types)); | 159 CHECK(schema->GetList("types", &types)); |
193 for (size_t i = 0; i < types->GetSize(); ++i) { | 160 for (size_t i = 0; i < types->GetSize(); ++i) { |
194 DictionaryValue *type = NULL; | 161 DictionaryValue *type = NULL; |
195 CHECK(types->GetDictionary(i, &type)); | 162 CHECK(types->GetDictionary(i, &type)); |
196 MaybePrefixFieldWithNamespace(schema_namespace, type, "id"); | 163 MaybePrefixFieldWithNamespace(schema_namespace, type, "id"); |
197 MaybePrefixFieldWithNamespace(schema_namespace, type, "customBindings"); | 164 MaybePrefixFieldWithNamespace(schema_namespace, type, "customBindings"); |
198 } | 165 } |
199 } | 166 } |
200 | 167 |
201 // Modify the schema so that all types are fully qualified. | 168 // Modify the schema so that all types are fully qualified. |
202 void PrefixWithNamespace(const std::string& schema_namespace, | 169 void PrefixWithNamespace(const std::string& schema_namespace, |
not at google - send to devlin
2013/05/23 00:09:40
I would love to delete this method. Another time p
| |
203 DictionaryValue* schema) { | 170 DictionaryValue* schema) { |
204 PrefixTypesWithNamespace(schema_namespace, schema); | 171 PrefixTypesWithNamespace(schema_namespace, schema); |
205 PrefixRefsWithNamespace(schema_namespace, schema); | 172 PrefixRefsWithNamespace(schema_namespace, schema); |
206 } | 173 } |
207 | 174 |
208 } // namespace | 175 } // namespace |
209 | 176 |
210 // static | 177 // static |
211 ExtensionAPI* ExtensionAPI::GetSharedInstance() { | 178 ExtensionAPI* ExtensionAPI::GetSharedInstance() { |
212 return g_lazy_instance.Get().api.get(); | 179 return g_lazy_instance.Get().api.get(); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
245 { | 212 { |
246 Value* value = NULL; | 213 Value* value = NULL; |
247 schema_list->Remove(schema_list->GetSize() - 1, &value); | 214 schema_list->Remove(schema_list->GetSize() - 1, &value); |
248 CHECK(value->IsType(Value::TYPE_DICTIONARY)); | 215 CHECK(value->IsType(Value::TYPE_DICTIONARY)); |
249 schema = static_cast<DictionaryValue*>(value); | 216 schema = static_cast<DictionaryValue*>(value); |
250 } | 217 } |
251 | 218 |
252 CHECK(schema->GetString("namespace", &schema_namespace)); | 219 CHECK(schema->GetString("namespace", &schema_namespace)); |
253 PrefixWithNamespace(schema_namespace, schema); | 220 PrefixWithNamespace(schema_namespace, schema); |
254 schemas_[schema_namespace] = make_linked_ptr(schema); | 221 schemas_[schema_namespace] = make_linked_ptr(schema); |
255 CHECK_EQ(1u, unloaded_schemas_.erase(schema_namespace)); | 222 if (!GeneratedSchemas::IsGenerated(schema_namespace)) { |
not at google - send to devlin
2013/05/23 00:09:40
don't need {}s anymore.
cduvall
2013/05/24 03:13:49
Done.
| |
256 | 223 CHECK_EQ(1u, unloaded_schemas_.erase(schema_namespace)); |
257 // Populate |{completely,partially}_unprivileged_apis_|. | |
258 | |
259 // For "partially", only need to look at functions/events; even though | |
260 // there are unprivileged properties (e.g. in extensions), access to those | |
261 // never reaches C++ land. | |
262 bool unprivileged = false; | |
263 if (schema->GetBoolean("unprivileged", &unprivileged) && unprivileged) { | |
264 completely_unprivileged_apis_.insert(schema_namespace); | |
265 } else if (HasUnprivilegedChild(schema, "functions") || | |
266 HasUnprivilegedChild(schema, "events") || | |
267 HasUnprivilegedChild(schema, "properties")) { | |
268 partially_unprivileged_apis_.insert(schema_namespace); | |
269 } | 224 } |
270 } | 225 } |
271 } | 226 } |
272 | 227 |
273 ExtensionAPI::ExtensionAPI() { | 228 ExtensionAPI::ExtensionAPI() { |
274 } | 229 } |
275 | 230 |
276 ExtensionAPI::~ExtensionAPI() { | 231 ExtensionAPI::~ExtensionAPI() { |
277 } | 232 } |
278 | 233 |
279 void ExtensionAPI::InitDefaultConfiguration() { | 234 void ExtensionAPI::InitDefaultConfiguration() { |
280 RegisterDependencyProvider( | 235 RegisterDependencyProvider( |
281 "api", BaseFeatureProvider::GetByName("api")); | 236 "api", BaseFeatureProvider::GetByName("api")); |
282 RegisterDependencyProvider( | 237 RegisterDependencyProvider( |
283 "manifest", BaseFeatureProvider::GetByName("manifest")); | 238 "manifest", BaseFeatureProvider::GetByName("manifest")); |
284 RegisterDependencyProvider( | 239 RegisterDependencyProvider( |
285 "permission", BaseFeatureProvider::GetByName("permission")); | 240 "permission", BaseFeatureProvider::GetByName("permission")); |
286 | 241 |
287 // Schemas to be loaded from resources. | 242 // Schemas to be loaded from resources. |
288 CHECK(unloaded_schemas_.empty()); | 243 CHECK(unloaded_schemas_.empty()); |
289 RegisterSchema("app", ReadFromResource( | 244 RegisterSchemaResource("app", IDR_EXTENSION_API_JSON_APP); |
290 IDR_EXTENSION_API_JSON_APP)); | 245 RegisterSchemaResource("browserAction", IDR_EXTENSION_API_JSON_BROWSERACTION); |
291 RegisterSchema("browserAction", ReadFromResource( | 246 RegisterSchemaResource("browsingData", IDR_EXTENSION_API_JSON_BROWSINGDATA); |
292 IDR_EXTENSION_API_JSON_BROWSERACTION)); | 247 RegisterSchemaResource("commands", IDR_EXTENSION_API_JSON_COMMANDS); |
293 RegisterSchema("browsingData", ReadFromResource( | 248 RegisterSchemaResource("declarativeContent", |
294 IDR_EXTENSION_API_JSON_BROWSINGDATA)); | 249 IDR_EXTENSION_API_JSON_DECLARATIVE_CONTENT); |
295 RegisterSchema("commands", ReadFromResource( | 250 RegisterSchemaResource("declarativeWebRequest", |
296 IDR_EXTENSION_API_JSON_COMMANDS)); | 251 IDR_EXTENSION_API_JSON_DECLARATIVE_WEBREQUEST); |
297 RegisterSchema("declarativeContent", ReadFromResource( | 252 RegisterSchemaResource("experimental.input.virtualKeyboard", |
298 IDR_EXTENSION_API_JSON_DECLARATIVE_CONTENT)); | 253 IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_VIRTUALKEYBOARD); |
299 RegisterSchema("declarativeWebRequest", ReadFromResource( | 254 RegisterSchemaResource("experimental.processes", |
300 IDR_EXTENSION_API_JSON_DECLARATIVE_WEBREQUEST)); | 255 IDR_EXTENSION_API_JSON_EXPERIMENTAL_PROCESSES); |
301 RegisterSchema("experimental.input.virtualKeyboard", ReadFromResource( | 256 RegisterSchemaResource("experimental.rlz", |
302 IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_VIRTUALKEYBOARD)); | 257 IDR_EXTENSION_API_JSON_EXPERIMENTAL_RLZ); |
303 RegisterSchema("experimental.processes", ReadFromResource( | 258 RegisterSchemaResource("runtime", IDR_EXTENSION_API_JSON_RUNTIME); |
304 IDR_EXTENSION_API_JSON_EXPERIMENTAL_PROCESSES)); | 259 RegisterSchemaResource("fileBrowserHandler", |
305 RegisterSchema("experimental.rlz", ReadFromResource( | 260 IDR_EXTENSION_API_JSON_FILEBROWSERHANDLER); |
306 IDR_EXTENSION_API_JSON_EXPERIMENTAL_RLZ)); | 261 RegisterSchemaResource("fileBrowserPrivate", |
307 RegisterSchema("runtime", ReadFromResource( | 262 IDR_EXTENSION_API_JSON_FILEBROWSERPRIVATE); |
308 IDR_EXTENSION_API_JSON_RUNTIME)); | 263 RegisterSchemaResource("input.ime", IDR_EXTENSION_API_JSON_INPUT_IME); |
309 RegisterSchema("fileBrowserHandler", ReadFromResource( | 264 RegisterSchemaResource("inputMethodPrivate", |
310 IDR_EXTENSION_API_JSON_FILEBROWSERHANDLER)); | 265 IDR_EXTENSION_API_JSON_INPUTMETHODPRIVATE); |
311 RegisterSchema("fileBrowserPrivate", ReadFromResource( | 266 RegisterSchemaResource("pageAction", IDR_EXTENSION_API_JSON_PAGEACTION); |
312 IDR_EXTENSION_API_JSON_FILEBROWSERPRIVATE)); | 267 RegisterSchemaResource("pageActions", IDR_EXTENSION_API_JSON_PAGEACTIONS); |
313 RegisterSchema("input.ime", ReadFromResource( | 268 RegisterSchemaResource("privacy", IDR_EXTENSION_API_JSON_PRIVACY); |
314 IDR_EXTENSION_API_JSON_INPUT_IME)); | 269 RegisterSchemaResource("proxy", IDR_EXTENSION_API_JSON_PROXY); |
315 RegisterSchema("inputMethodPrivate", ReadFromResource( | 270 RegisterSchemaResource("scriptBadge", IDR_EXTENSION_API_JSON_SCRIPTBADGE); |
316 IDR_EXTENSION_API_JSON_INPUTMETHODPRIVATE)); | 271 RegisterSchemaResource("streamsPrivate", |
317 RegisterSchema("pageAction", ReadFromResource( | 272 IDR_EXTENSION_API_JSON_STREAMSPRIVATE); |
318 IDR_EXTENSION_API_JSON_PAGEACTION)); | 273 RegisterSchemaResource("ttsEngine", IDR_EXTENSION_API_JSON_TTSENGINE); |
319 RegisterSchema("pageActions", ReadFromResource( | 274 RegisterSchemaResource("tts", IDR_EXTENSION_API_JSON_TTS); |
320 IDR_EXTENSION_API_JSON_PAGEACTIONS)); | 275 RegisterSchemaResource("types", IDR_EXTENSION_API_JSON_TYPES); |
321 RegisterSchema("privacy", ReadFromResource( | 276 RegisterSchemaResource("webRequestInternal", |
322 IDR_EXTENSION_API_JSON_PRIVACY)); | 277 IDR_EXTENSION_API_JSON_WEBREQUESTINTERNAL); |
323 RegisterSchema("proxy", ReadFromResource( | 278 RegisterSchemaResource("webstore", IDR_EXTENSION_API_JSON_WEBSTORE); |
324 IDR_EXTENSION_API_JSON_PROXY)); | 279 RegisterSchemaResource("webstorePrivate", |
325 RegisterSchema("scriptBadge", ReadFromResource( | 280 IDR_EXTENSION_API_JSON_WEBSTOREPRIVATE); |
326 IDR_EXTENSION_API_JSON_SCRIPTBADGE)); | |
327 RegisterSchema("streamsPrivate", ReadFromResource( | |
328 IDR_EXTENSION_API_JSON_STREAMSPRIVATE)); | |
329 RegisterSchema("ttsEngine", ReadFromResource( | |
330 IDR_EXTENSION_API_JSON_TTSENGINE)); | |
331 RegisterSchema("tts", ReadFromResource( | |
332 IDR_EXTENSION_API_JSON_TTS)); | |
333 RegisterSchema("types", ReadFromResource( | |
334 IDR_EXTENSION_API_JSON_TYPES)); | |
335 RegisterSchema("webRequestInternal", ReadFromResource( | |
336 IDR_EXTENSION_API_JSON_WEBREQUESTINTERNAL)); | |
337 RegisterSchema("webstore", ReadFromResource( | |
338 IDR_EXTENSION_API_JSON_WEBSTORE)); | |
339 RegisterSchema("webstorePrivate", ReadFromResource( | |
340 IDR_EXTENSION_API_JSON_WEBSTOREPRIVATE)); | |
341 | |
342 // Schemas to be loaded via JSON generated from IDL files. | |
343 GeneratedSchemas::Get(&unloaded_schemas_); | |
344 } | 281 } |
345 | 282 |
346 void ExtensionAPI::RegisterSchema(const std::string& name, | 283 void ExtensionAPI::RegisterSchemaResource(const std::string& name, |
347 const base::StringPiece& source) { | 284 int resource_id) { |
348 unloaded_schemas_[name] = source; | 285 unloaded_schemas_[name] = resource_id; |
349 } | 286 } |
350 | 287 |
351 void ExtensionAPI::RegisterDependencyProvider(const std::string& name, | 288 void ExtensionAPI::RegisterDependencyProvider(const std::string& name, |
352 FeatureProvider* provider) { | 289 FeatureProvider* provider) { |
353 dependency_providers_[name] = provider; | 290 dependency_providers_[name] = provider; |
354 } | 291 } |
355 | 292 |
356 bool ExtensionAPI::IsAnyFeatureAvailableToContext(const std::string& api_name, | 293 bool ExtensionAPI::IsAnyFeatureAvailableToContext(const std::string& api_name, |
357 Feature::Context context, | 294 Feature::Context context, |
358 const GURL& url) { | 295 const GURL& url) { |
359 FeatureProviderMap::iterator provider = dependency_providers_.find("api"); | 296 FeatureProviderMap::iterator provider = dependency_providers_.find("api"); |
360 CHECK(provider != dependency_providers_.end()); | 297 CHECK(provider != dependency_providers_.end()); |
361 std::set<std::string> features = provider->second->GetAllFeatureNames(); | 298 std::vector<std::string> features = provider->second->GetAllFeatureNames(); |
not at google - send to devlin
2013/05/23 00:09:40
maybe we should make the providers cache their fea
cduvall
2013/05/24 03:13:49
Done.
| |
362 | 299 |
363 // Check to see if there are any parts of this API that are allowed in this | 300 // Check to see if there are any parts of this API that are allowed in this |
364 // context. | 301 // context. |
365 for (std::set<std::string>::iterator i = features.begin(); | 302 for (std::vector<std::string>::iterator i = features.begin(); |
366 i != features.end(); ++i) { | 303 i != features.end(); ++i) { |
367 const std::string& feature_name = *i; | 304 const std::string& feature_name = *i; |
368 if (feature_name != api_name && feature_name.find(api_name + ".") == 0) { | 305 if (feature_name != api_name && feature_name.find(api_name + ".") == 0) { |
369 if (IsAvailable(feature_name, NULL, context, url).is_available()) | 306 if (IsAvailable(feature_name, NULL, context, url).is_available()) |
370 return true; | 307 return true; |
371 } | 308 } |
372 } | 309 } |
373 return IsAvailable(api_name, NULL, context, url).is_available(); | 310 return IsAvailable(api_name, NULL, context, url).is_available(); |
374 } | 311 } |
375 | 312 |
376 Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name, | 313 Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name, |
377 const Extension* extension, | 314 const Extension* extension, |
378 Feature::Context context, | 315 Feature::Context context, |
379 const GURL& url) { | 316 const GURL& url) { |
380 std::string feature_type; | 317 std::string feature_type; |
381 std::string feature_name; | 318 std::string feature_name; |
382 SplitDependencyName(full_name, &feature_type, &feature_name); | 319 SplitDependencyName(full_name, &feature_type, &feature_name); |
383 | 320 |
384 std::string child_name; | 321 std::string child_name; |
385 std::string api_name = GetAPINameFromFullName(feature_name, &child_name); | 322 std::string api_name = GetAPINameFromFullName(feature_name, &child_name); |
386 | 323 |
387 Feature* feature = GetFeatureDependency(full_name); | 324 Feature* feature = GetFeatureDependency(full_name); |
388 | 325 CHECK(feature); |
389 // Check APIs not using the feature system first. | |
390 if (!feature) { | |
391 return IsNonFeatureAPIAvailable(api_name, context, extension, url) | |
392 ? Feature::CreateAvailability(Feature::IS_AVAILABLE, | |
393 std::string()) | |
394 : Feature::CreateAvailability(Feature::INVALID_CONTEXT, | |
395 kUnavailableMessage); | |
396 } | |
397 | 326 |
398 Feature::Availability availability = | 327 Feature::Availability availability = |
399 feature->IsAvailableToContext(extension, context, url); | 328 feature->IsAvailableToContext(extension, context, url); |
400 if (!availability.is_available()) | 329 if (!availability.is_available()) |
401 return availability; | 330 return availability; |
402 | 331 |
403 for (std::set<std::string>::iterator iter = feature->dependencies().begin(); | 332 for (std::set<std::string>::iterator iter = feature->dependencies().begin(); |
404 iter != feature->dependencies().end(); ++iter) { | 333 iter != feature->dependencies().end(); ++iter) { |
405 Feature::Availability dependency_availability = | 334 Feature::Availability dependency_availability = |
406 IsAvailable(*iter, extension, context, url); | 335 IsAvailable(*iter, extension, context, url); |
407 if (!dependency_availability.is_available()) | 336 if (!dependency_availability.is_available()) |
408 return dependency_availability; | 337 return dependency_availability; |
409 } | 338 } |
410 | 339 |
411 return Feature::CreateAvailability(Feature::IS_AVAILABLE, std::string()); | 340 return Feature::CreateAvailability(Feature::IS_AVAILABLE, std::string()); |
412 } | 341 } |
413 | 342 |
414 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { | 343 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { |
415 std::string child_name; | 344 std::string child_name; |
416 std::string api_name = GetAPINameFromFullName(full_name, &child_name); | 345 std::string api_name = GetAPINameFromFullName(full_name, &child_name); |
417 Feature* feature = GetFeatureDependency(full_name); | 346 Feature* feature = GetFeatureDependency(full_name); |
418 | 347 |
419 // First try to use the feature system. | 348 CHECK(feature); |
420 if (feature) { | 349 // An API is 'privileged' if it can only be run in a blessed context. |
421 // An API is 'privileged' if it can only be run in a blessed context. | 350 return feature->GetContexts()->size() == |
422 return feature->GetContexts()->size() == | 351 feature->GetContexts()->count(Feature::BLESSED_EXTENSION_CONTEXT); |
not at google - send to devlin
2013/05/23 00:09:40
neat (unless it's empty, but well we're checking t
| |
423 feature->GetContexts()->count(Feature::BLESSED_EXTENSION_CONTEXT); | |
424 } | |
425 | |
426 // Get the schema now to populate |completely_unprivileged_apis_|. | |
427 const DictionaryValue* schema = GetSchema(api_name); | |
428 // If this API hasn't been converted yet, fall back to the old system. | |
429 if (completely_unprivileged_apis_.count(api_name)) | |
430 return false; | |
431 | |
432 if (partially_unprivileged_apis_.count(api_name)) | |
433 return IsChildNamePrivileged(schema, child_name); | |
434 | |
435 return true; | |
436 } | |
437 | |
438 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node, | |
439 const std::string& child_name) { | |
440 bool unprivileged = false; | |
441 const DictionaryValue* child = GetSchemaChild(name_space_node, child_name); | |
442 if (!child || !child->GetBoolean("unprivileged", &unprivileged)) | |
443 return true; | |
444 | |
445 return !unprivileged; | |
446 } | 352 } |
447 | 353 |
448 const DictionaryValue* ExtensionAPI::GetSchema(const std::string& full_name) { | 354 const DictionaryValue* ExtensionAPI::GetSchema(const std::string& full_name) { |
449 std::string child_name; | 355 std::string child_name; |
450 std::string api_name = GetAPINameFromFullName(full_name, &child_name); | 356 std::string api_name = GetAPINameFromFullName(full_name, &child_name); |
451 | 357 |
452 const DictionaryValue* result = NULL; | 358 const DictionaryValue* result = NULL; |
453 SchemaMap::iterator maybe_schema = schemas_.find(api_name); | 359 SchemaMap::iterator maybe_schema = schemas_.find(api_name); |
454 if (maybe_schema != schemas_.end()) { | 360 if (maybe_schema != schemas_.end()) { |
455 result = maybe_schema->second.get(); | 361 result = maybe_schema->second.get(); |
456 } else { | 362 } else { |
457 // Might not have loaded yet; or might just not exist. | 363 // Might not have loaded yet; or might just not exist. |
458 std::map<std::string, base::StringPiece>::iterator maybe_schema_resource = | 364 UnloadedSchemaMap::iterator maybe_schema_resource = |
459 unloaded_schemas_.find(api_name); | 365 unloaded_schemas_.find(api_name); |
460 if (maybe_schema_resource == unloaded_schemas_.end()) | 366 if (maybe_schema_resource != unloaded_schemas_.end()) { |
367 LoadSchema(maybe_schema_resource->first, | |
368 ReadFromResource(maybe_schema_resource->second)); | |
369 } else if (GeneratedSchemas::IsGenerated(api_name)) { | |
370 LoadSchema(api_name, GeneratedSchemas::Get(api_name)); | |
371 } else { | |
461 return NULL; | 372 return NULL; |
373 } | |
462 | 374 |
463 LoadSchema(maybe_schema_resource->first, maybe_schema_resource->second); | |
464 maybe_schema = schemas_.find(api_name); | 375 maybe_schema = schemas_.find(api_name); |
465 CHECK(schemas_.end() != maybe_schema); | 376 CHECK(schemas_.end() != maybe_schema); |
466 result = maybe_schema->second.get(); | 377 result = maybe_schema->second.get(); |
467 } | 378 } |
468 | 379 |
469 if (!child_name.empty()) | 380 if (!child_name.empty()) |
470 result = GetSchemaChild(result, child_name); | 381 result = GetSchemaChild(result, child_name); |
471 | 382 |
472 return result; | 383 return result; |
473 } | 384 } |
474 | 385 |
475 namespace { | |
476 | |
477 const char* kDisallowedPlatformAppFeatures[] = { | |
478 // "app" refers to the the legacy app namespace for hosted apps. | |
479 "app", | |
480 "extension", | |
481 "tabs", | |
482 "windows" | |
483 }; | |
484 | |
485 bool IsFeatureAllowedForExtension(const std::string& feature, | |
486 const extensions::Extension& extension) { | |
487 if (extension.is_platform_app()) { | |
488 for (size_t i = 0; i < arraysize(kDisallowedPlatformAppFeatures); ++i) { | |
489 if (feature == kDisallowedPlatformAppFeatures[i]) | |
490 return false; | |
491 } | |
492 } | |
493 | |
494 return true; | |
495 } | |
496 | |
497 } // namespace | |
498 | |
499 bool ExtensionAPI::IsNonFeatureAPIAvailable(const std::string& name, | |
500 Feature::Context context, | |
501 const Extension* extension, | |
502 const GURL& url) { | |
503 // Make sure schema is loaded. | |
504 GetSchema(name); | |
505 switch (context) { | |
506 case Feature::UNSPECIFIED_CONTEXT: | |
507 break; | |
508 | |
509 case Feature::BLESSED_EXTENSION_CONTEXT: | |
510 if (extension) { | |
511 // Availability is determined by the permissions of the extension. | |
512 if (!IsAPIAllowed(name, extension)) | |
513 return false; | |
514 if (!IsFeatureAllowedForExtension(name, *extension)) | |
515 return false; | |
516 } | |
517 break; | |
518 | |
519 case Feature::UNBLESSED_EXTENSION_CONTEXT: | |
520 case Feature::CONTENT_SCRIPT_CONTEXT: | |
521 if (extension) { | |
522 // Same as BLESSED_EXTENSION_CONTEXT, but only those APIs that are | |
523 // unprivileged. | |
524 if (!IsAPIAllowed(name, extension)) | |
525 return false; | |
526 if (!IsPrivilegedAPI(name)) | |
527 return false; | |
528 } | |
529 break; | |
530 | |
531 case Feature::WEB_PAGE_CONTEXT: | |
532 return false; | |
533 } | |
534 | |
535 return true; | |
536 } | |
537 | |
538 std::set<std::string> ExtensionAPI::GetAllAPINames() { | |
539 std::set<std::string> result; | |
540 for (SchemaMap::iterator i = schemas_.begin(); i != schemas_.end(); ++i) | |
541 result.insert(i->first); | |
542 for (UnloadedSchemaMap::iterator i = unloaded_schemas_.begin(); | |
543 i != unloaded_schemas_.end(); ++i) { | |
544 result.insert(i->first); | |
545 } | |
546 return result; | |
547 } | |
548 | |
549 Feature* ExtensionAPI::GetFeatureDependency(const std::string& full_name) { | 386 Feature* ExtensionAPI::GetFeatureDependency(const std::string& full_name) { |
550 std::string feature_type; | 387 std::string feature_type; |
551 std::string feature_name; | 388 std::string feature_name; |
552 SplitDependencyName(full_name, &feature_type, &feature_name); | 389 SplitDependencyName(full_name, &feature_type, &feature_name); |
553 | 390 |
554 FeatureProviderMap::iterator provider = | 391 FeatureProviderMap::iterator provider = |
555 dependency_providers_.find(feature_type); | 392 dependency_providers_.find(feature_type); |
556 if (provider == dependency_providers_.end()) | 393 if (provider == dependency_providers_.end()) |
557 return NULL; | 394 return NULL; |
558 | 395 |
559 Feature* feature = provider->second->GetFeature(feature_name); | 396 Feature* feature = provider->second->GetFeature(feature_name); |
560 // Try getting the feature for the parent API, if this was a child. | 397 // Try getting the feature for the parent API, if this was a child. |
561 if (!feature) { | 398 if (!feature) { |
562 std::string child_name; | 399 std::string child_name; |
563 feature = provider->second->GetFeature( | 400 feature = provider->second->GetFeature( |
564 GetAPINameFromFullName(feature_name, &child_name)); | 401 GetAPINameFromFullName(feature_name, &child_name)); |
565 } | 402 } |
566 return feature; | 403 return feature; |
567 } | 404 } |
568 | 405 |
569 std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name, | 406 std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name, |
570 std::string* child_name) { | 407 std::string* child_name) { |
571 std::string api_name_candidate = full_name; | 408 std::string api_name_candidate = full_name; |
572 while (true) { | 409 while (true) { |
573 if (schemas_.find(api_name_candidate) != schemas_.end() || | 410 if (schemas_.find(api_name_candidate) != schemas_.end() || |
411 GeneratedSchemas::IsGenerated(api_name_candidate) || | |
574 unloaded_schemas_.find(api_name_candidate) != unloaded_schemas_.end()) { | 412 unloaded_schemas_.find(api_name_candidate) != unloaded_schemas_.end()) { |
575 std::string result = api_name_candidate; | 413 std::string result = api_name_candidate; |
576 | 414 |
577 if (child_name) { | 415 if (child_name) { |
578 if (result.length() < full_name.length()) | 416 if (result.length() < full_name.length()) |
579 *child_name = full_name.substr(result.length() + 1); | 417 *child_name = full_name.substr(result.length() + 1); |
580 else | 418 else |
581 *child_name = ""; | 419 *child_name = ""; |
582 } | 420 } |
583 | 421 |
584 return result; | 422 return result; |
585 } | 423 } |
586 | 424 |
587 size_t last_dot_index = api_name_candidate.rfind('.'); | 425 size_t last_dot_index = api_name_candidate.rfind('.'); |
588 if (last_dot_index == std::string::npos) | 426 if (last_dot_index == std::string::npos) |
589 break; | 427 break; |
590 | 428 |
591 api_name_candidate = api_name_candidate.substr(0, last_dot_index); | 429 api_name_candidate = api_name_candidate.substr(0, last_dot_index); |
592 } | 430 } |
593 | 431 |
594 *child_name = ""; | 432 *child_name = ""; |
595 return std::string(); | 433 return std::string(); |
596 } | 434 } |
597 | 435 |
598 bool ExtensionAPI::IsAPIAllowed(const std::string& name, | |
599 const Extension* extension) { | |
600 return PermissionsData::GetRequiredPermissions(extension)-> | |
601 HasAnyAccessToAPI(name) || | |
602 PermissionsData::GetOptionalPermissions(extension)-> | |
603 HasAnyAccessToAPI(name); | |
604 } | |
605 | |
606 bool ExtensionAPI::IsPrivilegedAPI(const std::string& name) { | |
607 return completely_unprivileged_apis_.count(name) || | |
608 partially_unprivileged_apis_.count(name); | |
609 } | |
610 | |
611 } // namespace extensions | 436 } // namespace extensions |
OLD | NEW |