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
5 #include "extensions/common/manifest.h"
6
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"
18
19 namespace extensions {
20
21 namespace keys = manifest_keys;
22
23 namespace {
24
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.
GetLocationRank(Manifest::Location location)30 int GetLocationRank(Manifest::Location location) {
31 const int kInvalidRank = -1;
32 int rank = kInvalidRank; // Will CHECK that rank is not kInvalidRank.
33
34 switch (location) {
35 // Component extensions can not be overriden by any other type.
36 case Manifest::COMPONENT:
37 rank = 9;
38 break;
39
40 case Manifest::EXTERNAL_COMPONENT:
41 rank = 8;
42 break;
43
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;
49
50 case Manifest::EXTERNAL_POLICY_DOWNLOAD:
51 rank = 6;
52 break;
53
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;
60
61 case Manifest::UNPACKED:
62 rank = 4;
63 break;
64
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;
70
71 case Manifest::EXTERNAL_PREF:
72 rank = 2;
73 break;
74
75 case Manifest::EXTERNAL_PREF_DOWNLOAD:
76 rank = 1;
77 break;
78
79 // User installed extensions are overridden by any external type.
80 case Manifest::INTERNAL:
81 rank = 0;
82 break;
83
84 default:
85 NOTREACHED() << "Need to add new extension location " << location;
86 }
87
88 CHECK(rank != kInvalidRank);
89 return rank;
90 }
91
92 } // namespace
93
94 // static
GetHigherPriorityLocation(Location loc1,Location loc2)95 Manifest::Location Manifest::GetHigherPriorityLocation(
96 Location loc1, Location loc2) {
97 if (loc1 == loc2)
98 return loc1;
99
100 int loc1_rank = GetLocationRank(loc1);
101 int loc2_rank = GetLocationRank(loc2);
102
103 // If two different locations have the same rank, then we can not
104 // deterministicly choose a location.
105 CHECK(loc1_rank != loc2_rank);
106
107 // Highest rank has highest priority.
108 return (loc1_rank > loc2_rank ? loc1 : loc2 );
109 }
110
Manifest(Location location,scoped_ptr<base::DictionaryValue> value)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 value_->Get(keys::kPlatformAppServiceWorker, NULL)) {
125 type_ = TYPE_PLATFORM_APP;
126 } else {
127 type_ = TYPE_LEGACY_PACKAGED_APP;
128 }
129 } else {
130 type_ = TYPE_EXTENSION;
131 }
132 CHECK_NE(type_, TYPE_UNKNOWN);
133 }
134
~Manifest()135 Manifest::~Manifest() {
136 }
137
ValidateManifest(std::string * error,std::vector<InstallWarning> * warnings) const138 bool Manifest::ValidateManifest(
139 std::string* error,
140 std::vector<InstallWarning>* warnings) const {
141 *error = "";
142
143 // Check every feature to see if its in the manifest. Note that this means
144 // we will ignore keys that are not features; we do this for forward
145 // compatibility.
146 // TODO(aa): Consider having an error here in the case of strict error
147 // checking to let developers know when they screw up.
148
149 const FeatureProvider* manifest_feature_provider =
150 FeatureProvider::GetManifestFeatures();
151 const std::vector<std::string>& feature_names =
152 manifest_feature_provider->GetAllFeatureNames();
153 for (std::vector<std::string>::const_iterator feature_name =
154 feature_names.begin();
155 feature_name != feature_names.end(); ++feature_name) {
156 // Use Get instead of HasKey because the former uses path expansion.
157 if (!value_->Get(*feature_name, NULL))
158 continue;
159
160 Feature* feature = manifest_feature_provider->GetFeature(*feature_name);
161 Feature::Availability result = feature->IsAvailableToManifest(
162 extension_id_, type_, location_, GetManifestVersion());
163 if (!result.is_available())
164 warnings->push_back(InstallWarning(result.message(), *feature_name));
165 }
166
167 // Also generate warnings for keys that are not features.
168 for (base::DictionaryValue::Iterator it(*value_); !it.IsAtEnd();
169 it.Advance()) {
170 if (!manifest_feature_provider->GetFeature(it.key())) {
171 warnings->push_back(InstallWarning(
172 ErrorUtils::FormatErrorMessage(
173 manifest_errors::kUnrecognizedManifestKey, it.key()),
174 it.key()));
175 }
176 }
177 return true;
178 }
179
HasKey(const std::string & key) const180 bool Manifest::HasKey(const std::string& key) const {
181 return CanAccessKey(key) && value_->HasKey(key);
182 }
183
HasPath(const std::string & path) const184 bool Manifest::HasPath(const std::string& path) const {
185 base::Value* ignored = NULL;
186 return CanAccessPath(path) && value_->Get(path, &ignored);
187 }
188
Get(const std::string & path,const base::Value ** out_value) const189 bool Manifest::Get(
190 const std::string& path, const base::Value** out_value) const {
191 return CanAccessPath(path) && value_->Get(path, out_value);
192 }
193
GetBoolean(const std::string & path,bool * out_value) const194 bool Manifest::GetBoolean(
195 const std::string& path, bool* out_value) const {
196 return CanAccessPath(path) && value_->GetBoolean(path, out_value);
197 }
198
GetInteger(const std::string & path,int * out_value) const199 bool Manifest::GetInteger(
200 const std::string& path, int* out_value) const {
201 return CanAccessPath(path) && value_->GetInteger(path, out_value);
202 }
203
GetString(const std::string & path,std::string * out_value) const204 bool Manifest::GetString(
205 const std::string& path, std::string* out_value) const {
206 return CanAccessPath(path) && value_->GetString(path, out_value);
207 }
208
GetString(const std::string & path,base::string16 * out_value) const209 bool Manifest::GetString(
210 const std::string& path, base::string16* out_value) const {
211 return CanAccessPath(path) && value_->GetString(path, out_value);
212 }
213
GetDictionary(const std::string & path,const base::DictionaryValue ** out_value) const214 bool Manifest::GetDictionary(
215 const std::string& path, const base::DictionaryValue** out_value) const {
216 return CanAccessPath(path) && value_->GetDictionary(path, out_value);
217 }
218
GetList(const std::string & path,const base::ListValue ** out_value) const219 bool Manifest::GetList(
220 const std::string& path, const base::ListValue** out_value) const {
221 return CanAccessPath(path) && value_->GetList(path, out_value);
222 }
223
DeepCopy() const224 Manifest* Manifest::DeepCopy() const {
225 Manifest* manifest = new Manifest(
226 location_, scoped_ptr<base::DictionaryValue>(value_->DeepCopy()));
227 manifest->set_extension_id(extension_id_);
228 return manifest;
229 }
230
Equals(const Manifest * other) const231 bool Manifest::Equals(const Manifest* other) const {
232 return other && value_->Equals(other->value());
233 }
234
GetManifestVersion() const235 int Manifest::GetManifestVersion() const {
236 // Platform apps were launched after manifest version 2 was the preferred
237 // version, so they default to that.
238 int manifest_version = type_ == TYPE_PLATFORM_APP ? 2 : 1;
239 value_->GetInteger(keys::kManifestVersion, &manifest_version);
240 return manifest_version;
241 }
242
CanAccessPath(const std::string & path) const243 bool Manifest::CanAccessPath(const std::string& path) const {
244 std::vector<std::string> components;
245 base::SplitString(path, '.', &components);
246 std::string key;
247 for (size_t i = 0; i < components.size(); ++i) {
248 key += components[i];
249 if (!CanAccessKey(key))
250 return false;
251 key += '.';
252 }
253 return true;
254 }
255
CanAccessKey(const std::string & key) const256 bool Manifest::CanAccessKey(const std::string& key) const {
257 Feature* feature = FeatureProvider::GetManifestFeatures()->GetFeature(key);
258 if (!feature)
259 return true;
260
261 return feature->IsAvailableToManifest(
262 extension_id_, type_, location_, GetManifestVersion())
263 .is_available();
264 }
265
266 } // namespace extensions
267