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
;
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.
35 // Component extensions can not be overriden by any other type.
36 case Manifest::COMPONENT
:
40 case Manifest::EXTERNAL_COMPONENT
:
44 // Policy controlled extensions may not be overridden by any type
45 // that is not part of chrome.
46 case Manifest::EXTERNAL_POLICY
:
50 case Manifest::EXTERNAL_POLICY_DOWNLOAD
:
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
:
61 case Manifest::UNPACKED
:
65 // The relative priority of various external sources is not important,
66 // but having some order ensures deterministic behavior.
67 case Manifest::EXTERNAL_REGISTRY
:
71 case Manifest::EXTERNAL_PREF
:
75 case Manifest::EXTERNAL_PREF_DOWNLOAD
:
79 // User installed extensions are overridden by any external type.
80 case Manifest::INTERNAL
:
85 NOTREACHED() << "Need to add new extension location " << location
;
88 CHECK(rank
!= kInvalidRank
);
95 Manifest::Location
Manifest::GetHigherPriorityLocation(
96 Location loc1
, Location loc2
) {
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
)) {
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
;
126 type_
= TYPE_LEGACY_PACKAGED_APP
;
129 type_
= TYPE_EXTENSION
;
131 CHECK_NE(type_
, TYPE_UNKNOWN
);
134 Manifest::~Manifest() {
137 bool Manifest::ValidateManifest(
139 std::vector
<InstallWarning
>* warnings
) const {
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
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
))
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();
169 if (!manifest_feature_provider
->GetFeature(it
.key())) {
170 warnings
->push_back(InstallWarning(
171 ErrorUtils::FormatErrorMessage(
172 manifest_errors::kUnrecognizedManifestKey
, it
.key()),
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
);
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_
);
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 {
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
))
254 bool Manifest::CanAccessKey(const std::string
& key
) const {
255 Feature
* feature
= FeatureProvider::GetManifestFeatures()->GetFeature(key
);
259 return feature
->IsAvailableToManifest(
260 extension_id_
, type_
, location_
, GetManifestVersion())
264 } // namespace extensions