Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / common / manifest.cc
blobc552de7136a10c044e1ebbe29be7f3dba7cae073
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.
5 #include "extensions/common/manifest.h"
7 #include "base/basictypes.h"
8 #include "base/lazy_instance.h"
9 #include "base/logging.h"
10 #include "base/strings/string_split.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.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"
19 namespace extensions {
21 namespace keys = manifest_keys;
23 namespace {
25 // Rank extension locations in a way that allows
26 // Manifest::GetHigherPriorityLocation() to compare locations.
27 // An extension installed from two locations will have the location
28 // with the higher rank, as returned by this function. The actual
29 // integer values may change, and should never be persisted.
30 int GetLocationRank(Manifest::Location location) {
31 const int kInvalidRank = -1;
32 int rank = kInvalidRank; // Will CHECK that rank is not kInvalidRank.
34 switch (location) {
35 // Component extensions can not be overriden by any other type.
36 case Manifest::COMPONENT:
37 rank = 9;
38 break;
40 case Manifest::EXTERNAL_COMPONENT:
41 rank = 8;
42 break;
44 // Policy controlled extensions may not be overridden by any type
45 // that is not part of chrome.
46 case Manifest::EXTERNAL_POLICY:
47 rank = 7;
48 break;
50 case Manifest::EXTERNAL_POLICY_DOWNLOAD:
51 rank = 6;
52 break;
54 // A developer-loaded extension should override any installed type
55 // that a user can disable. Anything specified on the command-line should
56 // override one loaded via the extensions UI.
57 case Manifest::COMMAND_LINE:
58 rank = 5;
59 break;
61 case Manifest::UNPACKED:
62 rank = 4;
63 break;
65 // The relative priority of various external sources is not important,
66 // but having some order ensures deterministic behavior.
67 case Manifest::EXTERNAL_REGISTRY:
68 rank = 3;
69 break;
71 case Manifest::EXTERNAL_PREF:
72 rank = 2;
73 break;
75 case Manifest::EXTERNAL_PREF_DOWNLOAD:
76 rank = 1;
77 break;
79 // User installed extensions are overridden by any external type.
80 case Manifest::INTERNAL:
81 rank = 0;
82 break;
84 default:
85 NOTREACHED() << "Need to add new extension location " << location;
88 CHECK(rank != kInvalidRank);
89 return rank;
92 } // namespace
94 // static
95 Manifest::Location Manifest::GetHigherPriorityLocation(
96 Location loc1, Location loc2) {
97 if (loc1 == loc2)
98 return loc1;
100 int loc1_rank = GetLocationRank(loc1);
101 int loc2_rank = GetLocationRank(loc2);
103 // If two different locations have the same rank, then we can not
104 // deterministicly choose a location.
105 CHECK(loc1_rank != loc2_rank);
107 // Highest rank has highest priority.
108 return (loc1_rank > loc2_rank ? loc1 : loc2 );
111 Manifest::Manifest(Location location, scoped_ptr<base::DictionaryValue> value)
112 : location_(location),
113 value_(value.Pass()),
114 type_(TYPE_UNKNOWN) {
115 if (value_->HasKey(keys::kTheme)) {
116 type_ = TYPE_THEME;
117 } else if (value_->HasKey(keys::kExport)) {
118 type_ = TYPE_SHARED_MODULE;
119 } else if (value_->HasKey(keys::kApp)) {
120 if (value_->Get(keys::kWebURLs, NULL) ||
121 value_->Get(keys::kLaunchWebURL, NULL)) {
122 type_ = TYPE_HOSTED_APP;
123 } else if (value_->Get(keys::kPlatformAppBackground, NULL)) {
124 type_ = TYPE_PLATFORM_APP;
125 } else {
126 type_ = TYPE_LEGACY_PACKAGED_APP;
128 } else {
129 type_ = TYPE_EXTENSION;
131 CHECK_NE(type_, TYPE_UNKNOWN);
134 Manifest::~Manifest() {
137 bool Manifest::ValidateManifest(
138 std::string* error,
139 std::vector<InstallWarning>* warnings) const {
140 *error = "";
142 // Check every feature to see if its in the manifest. Note that this means
143 // we will ignore keys that are not features; we do this for forward
144 // compatibility.
145 // TODO(aa): Consider having an error here in the case of strict error
146 // checking to let developers know when they screw up.
148 const FeatureProvider* manifest_feature_provider =
149 FeatureProvider::GetManifestFeatures();
150 const std::vector<std::string>& feature_names =
151 manifest_feature_provider->GetAllFeatureNames();
152 for (std::vector<std::string>::const_iterator feature_name =
153 feature_names.begin();
154 feature_name != feature_names.end(); ++feature_name) {
155 // Use Get instead of HasKey because the former uses path expansion.
156 if (!value_->Get(*feature_name, NULL))
157 continue;
159 Feature* feature = manifest_feature_provider->GetFeature(*feature_name);
160 Feature::Availability result = feature->IsAvailableToManifest(
161 extension_id_, type_, location_, GetManifestVersion());
162 if (!result.is_available())
163 warnings->push_back(InstallWarning(result.message(), *feature_name));
166 // Also generate warnings for keys that are not features.
167 for (base::DictionaryValue::Iterator it(*value_); !it.IsAtEnd();
168 it.Advance()) {
169 if (!manifest_feature_provider->GetFeature(it.key())) {
170 warnings->push_back(InstallWarning(
171 ErrorUtils::FormatErrorMessage(
172 manifest_errors::kUnrecognizedManifestKey, it.key()),
173 it.key()));
176 return true;
179 bool Manifest::HasKey(const std::string& key) const {
180 return CanAccessKey(key) && value_->HasKey(key);
183 bool Manifest::HasPath(const std::string& path) const {
184 base::Value* ignored = NULL;
185 return CanAccessPath(path) && value_->Get(path, &ignored);
188 bool Manifest::Get(
189 const std::string& path, const base::Value** out_value) const {
190 return CanAccessPath(path) && value_->Get(path, out_value);
193 bool Manifest::GetBoolean(
194 const std::string& path, bool* out_value) const {
195 return CanAccessPath(path) && value_->GetBoolean(path, out_value);
198 bool Manifest::GetInteger(
199 const std::string& path, int* out_value) const {
200 return CanAccessPath(path) && value_->GetInteger(path, out_value);
203 bool Manifest::GetString(
204 const std::string& path, std::string* out_value) const {
205 return CanAccessPath(path) && value_->GetString(path, out_value);
208 bool Manifest::GetString(
209 const std::string& path, base::string16* out_value) const {
210 return CanAccessPath(path) && value_->GetString(path, out_value);
213 bool Manifest::GetDictionary(
214 const std::string& path, const base::DictionaryValue** out_value) const {
215 return CanAccessPath(path) && value_->GetDictionary(path, out_value);
218 bool Manifest::GetList(
219 const std::string& path, const base::ListValue** out_value) const {
220 return CanAccessPath(path) && value_->GetList(path, out_value);
223 Manifest* Manifest::DeepCopy() const {
224 Manifest* manifest = new Manifest(
225 location_, scoped_ptr<base::DictionaryValue>(value_->DeepCopy()));
226 manifest->set_extension_id(extension_id_);
227 return manifest;
230 bool Manifest::Equals(const Manifest* other) const {
231 return other && value_->Equals(other->value());
234 int Manifest::GetManifestVersion() const {
235 // Platform apps were launched after manifest version 2 was the preferred
236 // version, so they default to that.
237 int manifest_version = type_ == TYPE_PLATFORM_APP ? 2 : 1;
238 value_->GetInteger(keys::kManifestVersion, &manifest_version);
239 return manifest_version;
242 bool Manifest::CanAccessPath(const std::string& path) const {
243 std::string key;
244 for (const base::StringPiece& component : base::SplitStringPiece(
245 path, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
246 component.AppendToString(&key);
247 if (!CanAccessKey(key))
248 return false;
249 key += '.';
251 return true;
254 bool Manifest::CanAccessKey(const std::string& key) const {
255 Feature* feature = FeatureProvider::GetManifestFeatures()->GetFeature(key);
256 if (!feature)
257 return true;
259 return feature->IsAvailableToManifest(
260 extension_id_, type_, location_, GetManifestVersion())
261 .is_available();
264 } // namespace extensions