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