| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 "chrome/common/extensions/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 "chrome/common/extensions/features/feature.h" | |
| 14 #include "extensions/common/error_utils.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. | |
| 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 = 7; | |
| 38 break; | |
| 39 | |
| 40 // Policy controlled extensions may not be overridden by any type | |
| 41 // that is not part of chrome. | |
| 42 case Manifest::EXTERNAL_POLICY_DOWNLOAD: | |
| 43 rank = 6; | |
| 44 break; | |
| 45 | |
| 46 // A developer-loaded extension should override any installed type | |
| 47 // that a user can disable. Anything specified on the command-line should | |
| 48 // override one loaded via the extensions UI. | |
| 49 case Manifest::COMMAND_LINE: | |
| 50 rank = 5; | |
| 51 break; | |
| 52 | |
| 53 case Manifest::UNPACKED: | |
| 54 rank = 4; | |
| 55 break; | |
| 56 | |
| 57 // The relative priority of various external sources is not important, | |
| 58 // but having some order ensures deterministic behavior. | |
| 59 case Manifest::EXTERNAL_REGISTRY: | |
| 60 rank = 3; | |
| 61 break; | |
| 62 | |
| 63 case Manifest::EXTERNAL_PREF: | |
| 64 rank = 2; | |
| 65 break; | |
| 66 | |
| 67 case Manifest::EXTERNAL_PREF_DOWNLOAD: | |
| 68 rank = 1; | |
| 69 break; | |
| 70 | |
| 71 // User installed extensions are overridden by any external type. | |
| 72 case Manifest::INTERNAL: | |
| 73 rank = 0; | |
| 74 break; | |
| 75 | |
| 76 default: | |
| 77 NOTREACHED() << "Need to add new extension location " << location; | |
| 78 } | |
| 79 | |
| 80 CHECK(rank != kInvalidRank); | |
| 81 return rank; | |
| 82 } | |
| 83 | |
| 84 } // namespace | |
| 85 | |
| 86 // static | |
| 87 Manifest::Location Manifest::GetHigherPriorityLocation( | |
| 88 Location loc1, Location loc2) { | |
| 89 if (loc1 == loc2) | |
| 90 return loc1; | |
| 91 | |
| 92 int loc1_rank = GetLocationRank(loc1); | |
| 93 int loc2_rank = GetLocationRank(loc2); | |
| 94 | |
| 95 // If two different locations have the same rank, then we can not | |
| 96 // deterministicly choose a location. | |
| 97 CHECK(loc1_rank != loc2_rank); | |
| 98 | |
| 99 // Highest rank has highest priority. | |
| 100 return (loc1_rank > loc2_rank ? loc1 : loc2 ); | |
| 101 } | |
| 102 | |
| 103 Manifest::Manifest(Location location, scoped_ptr<base::DictionaryValue> value) | |
| 104 : location_(location), | |
| 105 value_(value.Pass()), | |
| 106 type_(TYPE_UNKNOWN) { | |
| 107 if (value_->HasKey(keys::kTheme)) { | |
| 108 type_ = TYPE_THEME; | |
| 109 } else if (value_->HasKey(keys::kExport)) { | |
| 110 type_ = TYPE_SHARED_MODULE; | |
| 111 } else if (value_->HasKey(keys::kApp)) { | |
| 112 if (value_->Get(keys::kWebURLs, NULL) || | |
| 113 value_->Get(keys::kLaunchWebURL, NULL)) { | |
| 114 type_ = TYPE_HOSTED_APP; | |
| 115 } else if (value_->Get(keys::kPlatformAppBackground, NULL)) { | |
| 116 type_ = TYPE_PLATFORM_APP; | |
| 117 } else { | |
| 118 type_ = TYPE_LEGACY_PACKAGED_APP; | |
| 119 } | |
| 120 } else { | |
| 121 type_ = TYPE_EXTENSION; | |
| 122 } | |
| 123 CHECK_NE(type_, TYPE_UNKNOWN); | |
| 124 } | |
| 125 | |
| 126 Manifest::~Manifest() { | |
| 127 } | |
| 128 | |
| 129 bool Manifest::ValidateManifest( | |
| 130 std::string* error, | |
| 131 std::vector<InstallWarning>* warnings) const { | |
| 132 *error = ""; | |
| 133 | |
| 134 // Check every feature to see if its in the manifest. Note that this means | |
| 135 // we will ignore keys that are not features; we do this for forward | |
| 136 // compatibility. | |
| 137 // TODO(aa): Consider having an error here in the case of strict error | |
| 138 // checking to let developers know when they screw up. | |
| 139 | |
| 140 FeatureProvider* provider = FeatureProvider::GetByName("manifest"); | |
| 141 const std::vector<std::string>& feature_names = | |
| 142 provider->GetAllFeatureNames(); | |
| 143 for (std::vector<std::string>::const_iterator feature_name = | |
| 144 feature_names.begin(); | |
| 145 feature_name != feature_names.end(); ++feature_name) { | |
| 146 // Use Get instead of HasKey because the former uses path expansion. | |
| 147 if (!value_->Get(*feature_name, NULL)) | |
| 148 continue; | |
| 149 | |
| 150 Feature* feature = provider->GetFeature(*feature_name); | |
| 151 Feature::Availability result = feature->IsAvailableToManifest( | |
| 152 extension_id_, type_, Feature::ConvertLocation(location_), | |
| 153 GetManifestVersion()); | |
| 154 if (!result.is_available()) | |
| 155 warnings->push_back(InstallWarning(result.message(), *feature_name)); | |
| 156 } | |
| 157 | |
| 158 // Also generate warnings for keys that are not features. | |
| 159 for (base::DictionaryValue::Iterator it(*value_); !it.IsAtEnd(); | |
| 160 it.Advance()) { | |
| 161 if (!provider->GetFeature(it.key())) { | |
| 162 warnings->push_back(InstallWarning( | |
| 163 base::StringPrintf("Unrecognized manifest key '%s'.", | |
| 164 it.key().c_str()), | |
| 165 it.key())); | |
| 166 } | |
| 167 } | |
| 168 return true; | |
| 169 } | |
| 170 | |
| 171 bool Manifest::HasKey(const std::string& key) const { | |
| 172 return CanAccessKey(key) && value_->HasKey(key); | |
| 173 } | |
| 174 | |
| 175 bool Manifest::HasPath(const std::string& path) const { | |
| 176 base::Value* ignored = NULL; | |
| 177 return CanAccessPath(path) && value_->Get(path, &ignored); | |
| 178 } | |
| 179 | |
| 180 bool Manifest::Get( | |
| 181 const std::string& path, const base::Value** out_value) const { | |
| 182 return CanAccessPath(path) && value_->Get(path, out_value); | |
| 183 } | |
| 184 | |
| 185 bool Manifest::GetBoolean( | |
| 186 const std::string& path, bool* out_value) const { | |
| 187 return CanAccessPath(path) && value_->GetBoolean(path, out_value); | |
| 188 } | |
| 189 | |
| 190 bool Manifest::GetInteger( | |
| 191 const std::string& path, int* out_value) const { | |
| 192 return CanAccessPath(path) && value_->GetInteger(path, out_value); | |
| 193 } | |
| 194 | |
| 195 bool Manifest::GetString( | |
| 196 const std::string& path, std::string* out_value) const { | |
| 197 return CanAccessPath(path) && value_->GetString(path, out_value); | |
| 198 } | |
| 199 | |
| 200 bool Manifest::GetString( | |
| 201 const std::string& path, string16* out_value) const { | |
| 202 return CanAccessPath(path) && value_->GetString(path, out_value); | |
| 203 } | |
| 204 | |
| 205 bool Manifest::GetDictionary( | |
| 206 const std::string& path, const base::DictionaryValue** out_value) const { | |
| 207 return CanAccessPath(path) && value_->GetDictionary(path, out_value); | |
| 208 } | |
| 209 | |
| 210 bool Manifest::GetList( | |
| 211 const std::string& path, const base::ListValue** out_value) const { | |
| 212 return CanAccessPath(path) && value_->GetList(path, out_value); | |
| 213 } | |
| 214 | |
| 215 Manifest* Manifest::DeepCopy() const { | |
| 216 Manifest* manifest = new Manifest( | |
| 217 location_, scoped_ptr<base::DictionaryValue>(value_->DeepCopy())); | |
| 218 manifest->set_extension_id(extension_id_); | |
| 219 return manifest; | |
| 220 } | |
| 221 | |
| 222 bool Manifest::Equals(const Manifest* other) const { | |
| 223 return other && value_->Equals(other->value()); | |
| 224 } | |
| 225 | |
| 226 int Manifest::GetManifestVersion() const { | |
| 227 // Platform apps were launched after manifest version 2 was the preferred | |
| 228 // version, so they default to that. | |
| 229 int manifest_version = type_ == TYPE_PLATFORM_APP ? 2 : 1; | |
| 230 value_->GetInteger(keys::kManifestVersion, &manifest_version); | |
| 231 return manifest_version; | |
| 232 } | |
| 233 | |
| 234 bool Manifest::CanAccessPath(const std::string& path) const { | |
| 235 std::vector<std::string> components; | |
| 236 base::SplitString(path, '.', &components); | |
| 237 std::string key; | |
| 238 for (size_t i = 0; i < components.size(); ++i) { | |
| 239 key += components[i]; | |
| 240 if (!CanAccessKey(key)) | |
| 241 return false; | |
| 242 key += '.'; | |
| 243 } | |
| 244 return true; | |
| 245 } | |
| 246 | |
| 247 bool Manifest::CanAccessKey(const std::string& key) const { | |
| 248 Feature* feature = FeatureProvider::GetByName("manifest")->GetFeature(key); | |
| 249 if (!feature) | |
| 250 return true; | |
| 251 | |
| 252 return feature->IsAvailableToManifest( | |
| 253 extension_id_, type_, Feature::ConvertLocation(location_), | |
| 254 GetManifestVersion()).is_available(); | |
| 255 } | |
| 256 | |
| 257 } // namespace extensions | |
| OLD | NEW |