manifest.cc 12 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/manifest.h"
  5. #include <utility>
  6. #include "base/check.h"
  7. #include "base/logging.h"
  8. #include "base/memory/ptr_util.h"
  9. #include "base/notreached.h"
  10. #include "base/strings/strcat.h"
  11. #include "base/strings/utf_string_conversions.h"
  12. #include "extensions/common/api/shared_module.h"
  13. #include "extensions/common/error_utils.h"
  14. #include "extensions/common/features/feature.h"
  15. #include "extensions/common/features/feature_provider.h"
  16. #include "extensions/common/install_warning.h"
  17. #include "extensions/common/manifest_constants.h"
  18. #include "extensions/common/manifest_handler_helpers.h"
  19. using extensions::mojom::ManifestLocation;
  20. namespace extensions {
  21. namespace keys = manifest_keys;
  22. namespace {
  23. // Rank extension locations in a way that allows
  24. // Manifest::GetHigherPriorityLocation() to compare locations.
  25. // An extension installed from two locations will have the location
  26. // with the higher rank, as returned by this function. The actual
  27. // integer values may change, and should never be persisted.
  28. int GetLocationRank(ManifestLocation location) {
  29. const int kInvalidRank = -1;
  30. int rank = kInvalidRank; // Will CHECK that rank is not kInvalidRank.
  31. switch (location) {
  32. // Component extensions can not be overridden by any other type.
  33. case ManifestLocation::kComponent:
  34. rank = 9;
  35. break;
  36. case ManifestLocation::kExternalComponent:
  37. rank = 8;
  38. break;
  39. // Policy controlled extensions may not be overridden by any type
  40. // that is not part of chrome.
  41. case ManifestLocation::kExternalPolicy:
  42. rank = 7;
  43. break;
  44. case ManifestLocation::kExternalPolicyDownload:
  45. rank = 6;
  46. break;
  47. // A developer-loaded extension should override any installed type
  48. // that a user can disable. Anything specified on the command-line should
  49. // override one loaded via the extensions UI.
  50. case ManifestLocation::kCommandLine:
  51. rank = 5;
  52. break;
  53. case ManifestLocation::kUnpacked:
  54. rank = 4;
  55. break;
  56. // The relative priority of various external sources is not important,
  57. // but having some order ensures deterministic behavior.
  58. case ManifestLocation::kExternalRegistry:
  59. rank = 3;
  60. break;
  61. case ManifestLocation::kExternalPref:
  62. rank = 2;
  63. break;
  64. case ManifestLocation::kExternalPrefDownload:
  65. rank = 1;
  66. break;
  67. // User installed extensions are overridden by any external type.
  68. case ManifestLocation::kInternal:
  69. rank = 0;
  70. break;
  71. // kInvalidLocation should never be passed to this function.
  72. case ManifestLocation::kInvalidLocation:
  73. break;
  74. }
  75. CHECK(rank != kInvalidRank);
  76. return rank;
  77. }
  78. int GetManifestVersion(const base::DictionaryValue& manifest_value,
  79. Manifest::Type type) {
  80. // Platform apps were launched after manifest version 2 was the preferred
  81. // version, so they default to that.
  82. return manifest_value.FindIntKey(keys::kManifestVersion)
  83. .value_or(type == Manifest::TYPE_PLATFORM_APP ? 2 : 1);
  84. }
  85. // Helper class to filter available values from a manifest.
  86. class AvailableValuesFilter {
  87. public:
  88. // Filters `manifest.values()` removing any unavailable keys.
  89. static base::Value Filter(const Manifest& manifest) {
  90. return FilterInternal(manifest, *manifest.value(), "");
  91. }
  92. private:
  93. // Returns a DictionaryValue corresponding to |input_dict| for the given
  94. // |manifest|, with all unavailable keys removed.
  95. static base::Value FilterInternal(const Manifest& manifest,
  96. const base::Value& input_dict,
  97. std::string current_path) {
  98. base::Value output_dict(base::Value::Type::DICTIONARY);
  99. DCHECK(input_dict.is_dict());
  100. DCHECK(CanAccessFeature(manifest, current_path));
  101. for (auto it : input_dict.DictItems()) {
  102. std::string child_path = CombineKeys(current_path, it.first);
  103. // Unavailable key, skip it.
  104. if (!CanAccessFeature(manifest, child_path))
  105. continue;
  106. // If |child_path| corresponds to a leaf node, copy it.
  107. bool is_leaf_node = !it.second.is_dict();
  108. if (is_leaf_node) {
  109. output_dict.SetKey(it.first, it.second.Clone());
  110. continue;
  111. }
  112. // Child dictionary. Populate it recursively.
  113. output_dict.SetKey(it.first,
  114. FilterInternal(manifest, it.second, child_path));
  115. }
  116. return output_dict;
  117. }
  118. // Returns true if the manifest feature corresponding to |feature_path| is
  119. // available to this manifest. Note: This doesn't check parent feature
  120. // availability. This is ok since we check feature availability in a
  121. // breadth-first manner below which ensures that we only ever check a child
  122. // feature if its parent is available. Note that api features don't follow
  123. // similar availability semantics i.e. we can have child api features be
  124. // available even if the parent feature is not (e.g.,
  125. // runtime.sendMessage()).
  126. static bool CanAccessFeature(const Manifest& manifest,
  127. const std::string& feature_path) {
  128. const Feature* feature =
  129. FeatureProvider::GetManifestFeatures()->GetFeature(feature_path);
  130. // TODO(crbug.com/1171466): We assume that if a feature does not exist,
  131. // it is available. This is ok for child features (if its parent is
  132. // available) but is probably not correct for top-level features. We
  133. // should see if false can be returned for these non-existent top-level
  134. // features here.
  135. if (!feature)
  136. return true;
  137. return feature
  138. ->IsAvailableToManifest(
  139. manifest.hashed_id(), manifest.type(), manifest.location(),
  140. manifest.manifest_version(), kUnspecifiedContextId)
  141. .is_available();
  142. }
  143. static std::string CombineKeys(const std::string& parent,
  144. const std::string& child) {
  145. if (parent.empty())
  146. return child;
  147. return base::StrCat({parent, ".", child});
  148. }
  149. };
  150. } // namespace
  151. // static
  152. ManifestLocation Manifest::GetHigherPriorityLocation(ManifestLocation loc1,
  153. ManifestLocation loc2) {
  154. if (loc1 == loc2)
  155. return loc1;
  156. int loc1_rank = GetLocationRank(loc1);
  157. int loc2_rank = GetLocationRank(loc2);
  158. // If two different locations have the same rank, then we can not
  159. // deterministicly choose a location.
  160. CHECK(loc1_rank != loc2_rank);
  161. // Highest rank has highest priority.
  162. return (loc1_rank > loc2_rank ? loc1 : loc2 );
  163. }
  164. // static
  165. Manifest::Type Manifest::GetTypeFromManifestValue(
  166. const base::DictionaryValue& value,
  167. bool for_login_screen) {
  168. Type type = TYPE_UNKNOWN;
  169. if (value.FindKey(keys::kTheme)) {
  170. type = TYPE_THEME;
  171. } else if (value.FindKey(api::shared_module::ManifestKeys::kExport)) {
  172. type = TYPE_SHARED_MODULE;
  173. } else if (value.FindKey(keys::kApp)) {
  174. if (value.Get(keys::kWebURLs, nullptr) ||
  175. value.Get(keys::kLaunchWebURL, nullptr)) {
  176. type = TYPE_HOSTED_APP;
  177. } else if (value.Get(keys::kPlatformAppBackground, nullptr)) {
  178. type = TYPE_PLATFORM_APP;
  179. } else {
  180. type = TYPE_LEGACY_PACKAGED_APP;
  181. }
  182. } else if (value.FindKey(keys::kChromeOSSystemExtension)) {
  183. type = TYPE_CHROMEOS_SYSTEM_EXTENSION;
  184. } else if (for_login_screen) {
  185. type = TYPE_LOGIN_SCREEN_EXTENSION;
  186. } else {
  187. type = TYPE_EXTENSION;
  188. }
  189. DCHECK_NE(type, TYPE_UNKNOWN);
  190. return type;
  191. }
  192. // static
  193. bool Manifest::ShouldAlwaysLoadExtension(ManifestLocation location,
  194. bool is_theme) {
  195. if (location == ManifestLocation::kComponent)
  196. return true; // Component extensions are always allowed.
  197. if (is_theme)
  198. return true; // Themes are allowed, even with --disable-extensions.
  199. // TODO(devlin): This seems wrong. See https://crbug.com/833540.
  200. if (Manifest::IsExternalLocation(location))
  201. return true;
  202. return false;
  203. }
  204. // static
  205. std::unique_ptr<Manifest> Manifest::CreateManifestForLoginScreen(
  206. ManifestLocation location,
  207. std::unique_ptr<base::DictionaryValue> value,
  208. ExtensionId extension_id) {
  209. CHECK(IsPolicyLocation(location));
  210. // Use base::WrapUnique + new because the constructor is private.
  211. return base::WrapUnique(
  212. new Manifest(location, std::move(value), std::move(extension_id), true));
  213. }
  214. Manifest::Manifest(ManifestLocation location,
  215. std::unique_ptr<base::DictionaryValue> value,
  216. ExtensionId extension_id)
  217. : Manifest(location, std::move(value), std::move(extension_id), false) {}
  218. Manifest::Manifest(ManifestLocation location,
  219. std::unique_ptr<base::DictionaryValue> value,
  220. ExtensionId extension_id,
  221. bool for_login_screen)
  222. : extension_id_(std::move(extension_id)),
  223. hashed_id_(HashedExtensionId(extension_id_)),
  224. location_(location),
  225. value_(std::move(value)),
  226. type_(GetTypeFromManifestValue(*value_, for_login_screen)),
  227. manifest_version_(GetManifestVersion(*value_, type_)) {
  228. DCHECK(!extension_id_.empty());
  229. available_values_ = base::DictionaryValue::From(
  230. base::Value::ToUniquePtrValue(AvailableValuesFilter::Filter(*this)));
  231. }
  232. Manifest::~Manifest() = default;
  233. bool Manifest::ValidateManifest(
  234. std::string* error,
  235. std::vector<InstallWarning>* warnings) const {
  236. *error = "";
  237. // Check every feature to see if it's in the manifest. Note that this means
  238. // we will ignore keys that are not features; we do this for forward
  239. // compatibility.
  240. const FeatureProvider* manifest_feature_provider =
  241. FeatureProvider::GetManifestFeatures();
  242. for (const auto& map_entry : manifest_feature_provider->GetAllFeatures()) {
  243. // Use Get instead of HasKey because the former uses path expansion.
  244. if (!value_->Get(map_entry.first, nullptr))
  245. continue;
  246. Feature::Availability result = map_entry.second->IsAvailableToManifest(
  247. hashed_id_, type_, location_, manifest_version_, kUnspecifiedContextId);
  248. if (!result.is_available())
  249. warnings->push_back(InstallWarning(result.message(), map_entry.first));
  250. }
  251. // Also generate warnings for keys that are not features.
  252. for (base::DictionaryValue::Iterator it(*value_); !it.IsAtEnd();
  253. it.Advance()) {
  254. if (!manifest_feature_provider->GetFeature(it.key())) {
  255. warnings->push_back(InstallWarning(
  256. ErrorUtils::FormatErrorMessage(
  257. manifest_errors::kUnrecognizedManifestKey, it.key()),
  258. it.key()));
  259. }
  260. }
  261. if (IsUnpackedLocation(location_) &&
  262. value_->FindPath(manifest_keys::kDifferentialFingerprint)) {
  263. warnings->push_back(
  264. InstallWarning(manifest_errors::kHasDifferentialFingerprint,
  265. manifest_keys::kDifferentialFingerprint));
  266. }
  267. return true;
  268. }
  269. const base::Value* Manifest::FindKey(base::StringPiece key) const {
  270. return available_values_->FindKey(key);
  271. }
  272. const base::Value* Manifest::FindPath(base::StringPiece path) const {
  273. return available_values_->FindPath(path);
  274. }
  275. absl::optional<bool> Manifest::FindBoolPath(base::StringPiece path) const {
  276. return available_values_->FindBoolPath(path);
  277. }
  278. absl::optional<int> Manifest::FindIntPath(base::StringPiece path) const {
  279. return available_values_->FindIntPath(path);
  280. }
  281. const std::string* Manifest::FindStringPath(base::StringPiece path) const {
  282. return available_values_->FindStringPath(path);
  283. }
  284. bool Manifest::GetDictionary(
  285. const std::string& path, const base::DictionaryValue** out_value) const {
  286. return available_values_->GetDictionary(path, out_value);
  287. }
  288. bool Manifest::GetDictionary(const std::string& path,
  289. const base::Value** out_value) const {
  290. const std::vector<base::StringPiece> components =
  291. manifest_handler_helpers::TokenizeDictionaryPath(path);
  292. *out_value = available_values_->FindPathOfType(components,
  293. base::Value::Type::DICTIONARY);
  294. return *out_value != nullptr;
  295. }
  296. bool Manifest::GetList(const std::string& path,
  297. const base::Value** out_value) const {
  298. const std::vector<base::StringPiece> components =
  299. manifest_handler_helpers::TokenizeDictionaryPath(path);
  300. *out_value =
  301. available_values_->FindPathOfType(components, base::Value::Type::LIST);
  302. return *out_value != nullptr;
  303. }
  304. bool Manifest::EqualsForTesting(const Manifest& other) const {
  305. return *value_ == *other.value() && location_ == other.location_ &&
  306. extension_id_ == other.extension_id_;
  307. }
  308. } // namespace extensions