extension_api.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. // Copyright 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "extensions/common/extension_api.h"
  5. #include <stddef.h>
  6. #include <algorithm>
  7. #include <string>
  8. #include <utility>
  9. #include <vector>
  10. #include "base/check_op.h"
  11. #include "base/json/json_reader.h"
  12. #include "base/json/json_writer.h"
  13. #include "base/lazy_instance.h"
  14. #include "base/strings/string_number_conversions.h"
  15. #include "base/strings/string_split.h"
  16. #include "base/strings/string_util.h"
  17. #include "base/values.h"
  18. #include "extensions/common/extension.h"
  19. #include "extensions/common/extensions_client.h"
  20. #include "extensions/common/features/feature.h"
  21. #include "extensions/common/features/feature_provider.h"
  22. #include "extensions/common/features/simple_feature.h"
  23. #include "extensions/common/permissions/permission_set.h"
  24. #include "extensions/common/permissions/permissions_data.h"
  25. #include "url/gurl.h"
  26. namespace extensions {
  27. namespace {
  28. const char* const kChildKinds[] = {"functions", "events"};
  29. std::unique_ptr<base::DictionaryValue> LoadSchemaDictionary(
  30. const std::string& name,
  31. const base::StringPiece& schema) {
  32. auto result = base::JSONReader::ReadAndReturnValueWithError(schema);
  33. // Tracking down http://crbug.com/121424
  34. char buf[128];
  35. base::snprintf(buf, std::size(buf), "%s: (%d) '%s'", name.c_str(),
  36. result.has_value() ? static_cast<int>(result->type()) : -1,
  37. !result.has_value() ? result.error().message.c_str() : "");
  38. CHECK(result.has_value())
  39. << result.error().message << " for schema " << schema;
  40. CHECK(result->is_dict()) << " for schema " << schema;
  41. return base::DictionaryValue::From(
  42. base::Value::ToUniquePtrValue(std::move(*result)));
  43. }
  44. const base::DictionaryValue* FindListItem(const base::ListValue* list,
  45. const std::string& property_name,
  46. const std::string& property_value) {
  47. for (const base::Value& item_value : list->GetList()) {
  48. CHECK(item_value.is_dict()) << property_value << "/" << property_name;
  49. const base::DictionaryValue* item =
  50. static_cast<const base::DictionaryValue*>(&item_value);
  51. std::string value;
  52. if (item->GetString(property_name, &value) && value == property_value)
  53. return item;
  54. }
  55. return NULL;
  56. }
  57. const base::DictionaryValue* GetSchemaChild(
  58. const base::DictionaryValue* schema_node,
  59. const std::string& child_name) {
  60. const base::DictionaryValue* child_node = NULL;
  61. for (size_t i = 0; i < std::size(kChildKinds); ++i) {
  62. const base::ListValue* list_node = NULL;
  63. if (!schema_node->GetList(kChildKinds[i], &list_node))
  64. continue;
  65. child_node = FindListItem(list_node, "name", child_name);
  66. if (child_node)
  67. return child_node;
  68. }
  69. return NULL;
  70. }
  71. struct ExtensionAPIStatic {
  72. ExtensionAPIStatic() : api(ExtensionAPI::CreateWithDefaultConfiguration()) {}
  73. std::unique_ptr<ExtensionAPI> api;
  74. };
  75. base::LazyInstance<ExtensionAPIStatic>::Leaky g_extension_api_static =
  76. LAZY_INSTANCE_INITIALIZER;
  77. // May override |g_extension_api_static| for a test.
  78. ExtensionAPI* g_shared_instance_for_test = NULL;
  79. } // namespace
  80. // static
  81. ExtensionAPI* ExtensionAPI::GetSharedInstance() {
  82. return g_shared_instance_for_test ? g_shared_instance_for_test
  83. : g_extension_api_static.Get().api.get();
  84. }
  85. // static
  86. ExtensionAPI* ExtensionAPI::CreateWithDefaultConfiguration() {
  87. ExtensionAPI* api = new ExtensionAPI();
  88. api->InitDefaultConfiguration();
  89. return api;
  90. }
  91. // static
  92. void ExtensionAPI::SplitDependencyName(const std::string& full_name,
  93. std::string* feature_type,
  94. std::string* feature_name) {
  95. size_t colon_index = full_name.find(':');
  96. if (colon_index == std::string::npos) {
  97. // TODO(aa): Remove this code when all API descriptions have been updated.
  98. *feature_type = "api";
  99. *feature_name = full_name;
  100. return;
  101. }
  102. *feature_type = full_name.substr(0, colon_index);
  103. *feature_name = full_name.substr(colon_index + 1);
  104. }
  105. ExtensionAPI::OverrideSharedInstanceForTest::OverrideSharedInstanceForTest(
  106. ExtensionAPI* testing_api)
  107. : original_api_(g_shared_instance_for_test) {
  108. g_shared_instance_for_test = testing_api;
  109. }
  110. ExtensionAPI::OverrideSharedInstanceForTest::~OverrideSharedInstanceForTest() {
  111. g_shared_instance_for_test = original_api_;
  112. }
  113. void ExtensionAPI::LoadSchema(const std::string& name,
  114. const base::StringPiece& schema) {
  115. lock_.AssertAcquired();
  116. std::unique_ptr<base::DictionaryValue> schema_dict(
  117. LoadSchemaDictionary(name, schema));
  118. std::string schema_namespace;
  119. CHECK(schema_dict->GetString("namespace", &schema_namespace));
  120. schemas_[schema_namespace] = std::move(schema_dict);
  121. }
  122. ExtensionAPI::ExtensionAPI() = default;
  123. ExtensionAPI::~ExtensionAPI() = default;
  124. void ExtensionAPI::InitDefaultConfiguration() {
  125. const constexpr char* const names[] = {"api", "behavior", "manifest",
  126. "permission"};
  127. for (const char* const name : names)
  128. RegisterDependencyProvider(name, FeatureProvider::GetByName(name));
  129. default_configuration_initialized_ = true;
  130. }
  131. void ExtensionAPI::RegisterDependencyProvider(const std::string& name,
  132. const FeatureProvider* provider) {
  133. dependency_providers_[name] = provider;
  134. }
  135. bool ExtensionAPI::IsAnyFeatureAvailableToContext(const Feature& api,
  136. const Extension* extension,
  137. Feature::Context context,
  138. const GURL& url,
  139. CheckAliasStatus check_alias,
  140. int context_id) {
  141. auto provider = dependency_providers_.find("api");
  142. CHECK(provider != dependency_providers_.end());
  143. if (api.IsAvailableToContext(extension, context, url, context_id)
  144. .is_available())
  145. return true;
  146. // Check to see if there are any parts of this API that are allowed in this
  147. // context.
  148. const std::vector<const Feature*> features =
  149. provider->second->GetChildren(api);
  150. for (const Feature* feature : features) {
  151. if (feature->IsAvailableToContext(extension, context, url, context_id)
  152. .is_available())
  153. return true;
  154. }
  155. if (check_alias != CheckAliasStatus::ALLOWED)
  156. return false;
  157. const std::string& alias_name = api.alias();
  158. if (alias_name.empty())
  159. return false;
  160. const Feature* alias = provider->second->GetFeature(alias_name);
  161. CHECK(alias) << "Cannot find alias feature " << alias_name
  162. << " for API feature " << api.name();
  163. return IsAnyFeatureAvailableToContext(*alias, extension, context, url,
  164. CheckAliasStatus::NOT_ALLOWED,
  165. context_id);
  166. }
  167. Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name,
  168. const Extension* extension,
  169. Feature::Context context,
  170. const GURL& url,
  171. CheckAliasStatus check_alias,
  172. int context_id) {
  173. const Feature* feature = GetFeatureDependency(full_name);
  174. if (!feature) {
  175. return Feature::Availability(Feature::NOT_PRESENT,
  176. std::string("Unknown feature: ") + full_name);
  177. }
  178. Feature::Availability availability =
  179. feature->IsAvailableToContext(extension, context, url, context_id);
  180. if (availability.is_available() || check_alias != CheckAliasStatus::ALLOWED)
  181. return availability;
  182. Feature::Availability alias_availability = IsAliasAvailable(
  183. full_name, *feature, extension, context, url, context_id);
  184. return alias_availability.is_available() ? alias_availability : availability;
  185. }
  186. base::StringPiece ExtensionAPI::GetSchemaStringPiece(
  187. const std::string& api_name) {
  188. base::AutoLock lock(lock_);
  189. return GetSchemaStringPieceUnsafe(api_name);
  190. }
  191. const base::DictionaryValue* ExtensionAPI::GetSchema(
  192. const std::string& full_name) {
  193. base::AutoLock lock(lock_);
  194. std::string child_name;
  195. std::string api_name = GetAPINameFromFullNameUnsafe(full_name, &child_name);
  196. const base::DictionaryValue* result = NULL;
  197. auto maybe_schema = schemas_.find(api_name);
  198. if (maybe_schema != schemas_.end()) {
  199. result = maybe_schema->second.get();
  200. } else {
  201. base::StringPiece schema_string = GetSchemaStringPieceUnsafe(api_name);
  202. if (schema_string.empty())
  203. return nullptr;
  204. LoadSchema(api_name, schema_string);
  205. maybe_schema = schemas_.find(api_name);
  206. CHECK(schemas_.end() != maybe_schema);
  207. result = maybe_schema->second.get();
  208. }
  209. if (!child_name.empty())
  210. result = GetSchemaChild(result, child_name);
  211. return result;
  212. }
  213. const Feature* ExtensionAPI::GetFeatureDependency(
  214. const std::string& full_name) {
  215. std::string feature_type;
  216. std::string feature_name;
  217. SplitDependencyName(full_name, &feature_type, &feature_name);
  218. auto provider = dependency_providers_.find(feature_type);
  219. if (provider == dependency_providers_.end())
  220. return NULL;
  221. const Feature* feature = provider->second->GetFeature(feature_name);
  222. // Try getting the feature for the parent API, if this was a child.
  223. if (!feature) {
  224. std::string child_name;
  225. feature = provider->second->GetFeature(
  226. GetAPINameFromFullName(feature_name, &child_name));
  227. }
  228. return feature;
  229. }
  230. std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name,
  231. std::string* child_name) {
  232. base::AutoLock lock(lock_);
  233. return GetAPINameFromFullNameUnsafe(full_name, child_name);
  234. }
  235. bool ExtensionAPI::IsKnownAPI(const std::string& name,
  236. ExtensionsClient* client) {
  237. lock_.AssertAcquired();
  238. return schemas_.find(name) != schemas_.end() ||
  239. client->IsAPISchemaGenerated(name);
  240. }
  241. Feature::Availability ExtensionAPI::IsAliasAvailable(
  242. const std::string& full_name,
  243. const Feature& feature,
  244. const Extension* extension,
  245. Feature::Context context,
  246. const GURL& url,
  247. int context_id) {
  248. const std::string& alias = feature.alias();
  249. if (alias.empty())
  250. return Feature::Availability(Feature::NOT_PRESENT, "Alias not defined");
  251. auto provider = dependency_providers_.find("api");
  252. CHECK(provider != dependency_providers_.end());
  253. // Check if there is a child feature associated with full name for alias API.
  254. // This is to ensure that the availability of the feature associated with the
  255. // aliased |full_name| is properly determined in case the feature in question
  256. // is a child feature. For example, if API foo has an alias fooAlias, which
  257. // has a child feature fooAlias.method, aliased foo.method availability should
  258. // be determined using fooAlias.method feature, rather than fooAlias feature.
  259. std::string child_name;
  260. GetAPINameFromFullName(full_name, &child_name);
  261. std::string full_alias_name = alias + "." + child_name;
  262. const Feature* alias_feature = provider->second->GetFeature(full_alias_name);
  263. // If there is no child feature, use the alias API feature to check
  264. // availability.
  265. if (!alias_feature)
  266. alias_feature = provider->second->GetFeature(alias);
  267. CHECK(alias_feature) << "Cannot find alias feature " << alias
  268. << " for API feature " << feature.name();
  269. return alias_feature->IsAvailableToContext(extension, context, url,
  270. context_id);
  271. }
  272. base::StringPiece ExtensionAPI::GetSchemaStringPieceUnsafe(
  273. const std::string& api_name) {
  274. lock_.AssertAcquired();
  275. DCHECK_EQ(api_name, GetAPINameFromFullNameUnsafe(api_name, nullptr));
  276. ExtensionsClient* client = ExtensionsClient::Get();
  277. DCHECK(client);
  278. if (!default_configuration_initialized_)
  279. return base::StringPiece();
  280. base::StringPiece schema = client->GetAPISchema(api_name);
  281. return schema;
  282. }
  283. std::string ExtensionAPI::GetAPINameFromFullNameUnsafe(
  284. const std::string& full_name,
  285. std::string* child_name) {
  286. lock_.AssertAcquired();
  287. std::string api_name_candidate = full_name;
  288. ExtensionsClient* extensions_client = ExtensionsClient::Get();
  289. DCHECK(extensions_client);
  290. while (true) {
  291. if (IsKnownAPI(api_name_candidate, extensions_client)) {
  292. if (child_name) {
  293. if (api_name_candidate.length() < full_name.length())
  294. *child_name = full_name.substr(api_name_candidate.length() + 1);
  295. else
  296. *child_name = "";
  297. }
  298. return api_name_candidate;
  299. }
  300. size_t last_dot_index = api_name_candidate.rfind('.');
  301. if (last_dot_index == std::string::npos)
  302. break;
  303. api_name_candidate = api_name_candidate.substr(0, last_dot_index);
  304. }
  305. if (child_name)
  306. *child_name = "";
  307. return std::string();
  308. }
  309. } // namespace extensions