Home | History | Annotate | Download | only in manifest_handlers
      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_handlers/shared_module_info.h"
      6 
      7 #include "base/lazy_instance.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/strings/string_number_conversions.h"
     10 #include "base/strings/string_util.h"
     11 #include "base/strings/utf_string_conversions.h"
     12 #include "base/version.h"
     13 #include "extensions/common/constants.h"
     14 #include "extensions/common/error_utils.h"
     15 #include "extensions/common/manifest_constants.h"
     16 #include "extensions/common/permissions/permission_set.h"
     17 #include "extensions/common/permissions/permissions_data.h"
     18 
     19 namespace extensions {
     20 
     21 namespace keys = manifest_keys;
     22 namespace values = manifest_values;
     23 namespace errors = manifest_errors;
     24 
     25 namespace {
     26 
     27 const char kSharedModule[] = "shared_module";
     28 
     29 static base::LazyInstance<SharedModuleInfo> g_empty_shared_module_info =
     30     LAZY_INSTANCE_INITIALIZER;
     31 
     32 const SharedModuleInfo& GetSharedModuleInfo(const Extension* extension) {
     33   SharedModuleInfo* info = static_cast<SharedModuleInfo*>(
     34       extension->GetManifestData(kSharedModule));
     35   if (!info)
     36     return g_empty_shared_module_info.Get();
     37   return *info;
     38 }
     39 
     40 }  // namespace
     41 
     42 SharedModuleInfo::SharedModuleInfo() {
     43 }
     44 
     45 SharedModuleInfo::~SharedModuleInfo() {
     46 }
     47 
     48 // static
     49 void SharedModuleInfo::ParseImportedPath(const std::string& path,
     50                                          std::string* import_id,
     51                                          std::string* import_relative_path) {
     52   std::vector<std::string> tokens;
     53   Tokenize(path, std::string("/"), &tokens);
     54   if (tokens.size() > 2 && tokens[0] == kModulesDir &&
     55       Extension::IdIsValid(tokens[1])) {
     56     *import_id = tokens[1];
     57     *import_relative_path = tokens[2];
     58     for (size_t i = 3; i < tokens.size(); ++i)
     59       *import_relative_path += "/" + tokens[i];
     60   }
     61 }
     62 
     63 // static
     64 bool SharedModuleInfo::IsImportedPath(const std::string& path) {
     65   std::vector<std::string> tokens;
     66   Tokenize(path, std::string("/"), &tokens);
     67   if (tokens.size() > 2 && tokens[0] == kModulesDir &&
     68       Extension::IdIsValid(tokens[1])) {
     69     return true;
     70   }
     71   return false;
     72 }
     73 
     74 // static
     75 bool SharedModuleInfo::IsSharedModule(const Extension* extension) {
     76   CHECK(extension);
     77   return extension->manifest()->is_shared_module();
     78 }
     79 
     80 // static
     81 bool SharedModuleInfo::IsExportAllowed(const Extension* extension,
     82                                        const std::string& relative_path) {
     83   return GetSharedModuleInfo(extension).
     84       exported_set_.MatchesURL(extension->url().Resolve(relative_path));
     85 }
     86 
     87 // static
     88 bool SharedModuleInfo::IsExportAllowedByWhitelist(const Extension* extension,
     89                                                   const std::string& other_id) {
     90   // Sanity check. In case the caller did not check |extension| to make sure it
     91   // is a shared module, we do not want it to appear that the extension with
     92   // |other_id| importing |extension| is valid.
     93   if (!SharedModuleInfo::IsSharedModule(extension))
     94     return false;
     95   const SharedModuleInfo& info = GetSharedModuleInfo(extension);
     96   if (info.export_whitelist_.empty())
     97     return true;
     98   if (info.export_whitelist_.find(other_id) != info.export_whitelist_.end())
     99     return true;
    100   return false;
    101 }
    102 
    103 // static
    104 bool SharedModuleInfo::ImportsExtensionById(const Extension* extension,
    105                                             const std::string& other_id) {
    106   const SharedModuleInfo& info = GetSharedModuleInfo(extension);
    107   for (size_t i = 0; i < info.imports_.size(); i++) {
    108     if (info.imports_[i].extension_id == other_id)
    109       return true;
    110   }
    111   return false;
    112 }
    113 
    114 // static
    115 bool SharedModuleInfo::ImportsModules(const Extension* extension) {
    116   return GetSharedModuleInfo(extension).imports_.size() > 0;
    117 }
    118 
    119 // static
    120 const std::vector<SharedModuleInfo::ImportInfo>& SharedModuleInfo::GetImports(
    121     const Extension* extension) {
    122   return GetSharedModuleInfo(extension).imports_;
    123 }
    124 
    125 bool SharedModuleInfo::Parse(const Extension* extension,
    126                              base::string16* error) {
    127   bool has_import = extension->manifest()->HasKey(keys::kImport);
    128   bool has_export = extension->manifest()->HasKey(keys::kExport);
    129   if (!has_import && !has_export)
    130     return true;
    131 
    132   if (has_import && has_export) {
    133     *error = base::ASCIIToUTF16(errors::kInvalidImportAndExport);
    134     return false;
    135   }
    136 
    137   if (has_export) {
    138     const base::DictionaryValue* export_value = NULL;
    139     if (!extension->manifest()->GetDictionary(keys::kExport, &export_value)) {
    140       *error = base::ASCIIToUTF16(errors::kInvalidExport);
    141       return false;
    142     }
    143     const base::ListValue* resources_list = NULL;
    144     if (!export_value->GetList(keys::kResources, &resources_list)) {
    145       *error = base::ASCIIToUTF16(errors::kInvalidExportResources);
    146       return false;
    147     }
    148     if (export_value->HasKey(keys::kWhitelist)) {
    149       const base::ListValue* whitelist = NULL;
    150       if (!export_value->GetList(keys::kWhitelist, &whitelist)) {
    151         *error = base::ASCIIToUTF16(errors::kInvalidExportWhitelist);
    152         return false;
    153       }
    154       for (size_t i = 0; i < whitelist->GetSize(); ++i) {
    155         std::string extension_id;
    156         if (!whitelist->GetString(i, &extension_id) ||
    157             !Extension::IdIsValid(extension_id)) {
    158           *error = ErrorUtils::FormatErrorMessageUTF16(
    159               errors::kInvalidExportWhitelistString, base::IntToString(i));
    160           return false;
    161         }
    162         export_whitelist_.insert(extension_id);
    163       }
    164     }
    165     for (size_t i = 0; i < resources_list->GetSize(); ++i) {
    166       std::string resource_path;
    167       if (!resources_list->GetString(i, &resource_path)) {
    168         *error = ErrorUtils::FormatErrorMessageUTF16(
    169             errors::kInvalidExportResourcesString, base::IntToString(i));
    170         return false;
    171       }
    172       const GURL& resolved_path = extension->url().Resolve(resource_path);
    173       if (!resolved_path.is_valid()) {
    174         *error = ErrorUtils::FormatErrorMessageUTF16(
    175             errors::kInvalidExportResourcesString, base::IntToString(i));
    176         return false;
    177       }
    178       exported_set_.AddPattern(
    179           URLPattern(URLPattern::SCHEME_EXTENSION, resolved_path.spec()));
    180     }
    181   }
    182 
    183   if (has_import) {
    184     const base::ListValue* import_list = NULL;
    185     if (!extension->manifest()->GetList(keys::kImport, &import_list)) {
    186       *error = base::ASCIIToUTF16(errors::kInvalidImport);
    187       return false;
    188     }
    189     for (size_t i = 0; i < import_list->GetSize(); ++i) {
    190       const base::DictionaryValue* import_entry = NULL;
    191       if (!import_list->GetDictionary(i, &import_entry)) {
    192         *error = base::ASCIIToUTF16(errors::kInvalidImport);
    193         return false;
    194       }
    195       std::string extension_id;
    196       imports_.push_back(ImportInfo());
    197       if (!import_entry->GetString(keys::kId, &extension_id) ||
    198           !Extension::IdIsValid(extension_id)) {
    199         *error = ErrorUtils::FormatErrorMessageUTF16(
    200             errors::kInvalidImportId, base::IntToString(i));
    201         return false;
    202       }
    203       imports_.back().extension_id = extension_id;
    204       if (import_entry->HasKey(keys::kMinimumVersion)) {
    205         std::string min_version;
    206         if (!import_entry->GetString(keys::kMinimumVersion, &min_version)) {
    207           *error = ErrorUtils::FormatErrorMessageUTF16(
    208               errors::kInvalidImportVersion, base::IntToString(i));
    209           return false;
    210         }
    211         imports_.back().minimum_version = min_version;
    212         Version v(min_version);
    213         if (!v.IsValid()) {
    214           *error = ErrorUtils::FormatErrorMessageUTF16(
    215               errors::kInvalidImportVersion, base::IntToString(i));
    216           return false;
    217         }
    218       }
    219     }
    220   }
    221   return true;
    222 }
    223 
    224 
    225 SharedModuleHandler::SharedModuleHandler() {
    226 }
    227 
    228 SharedModuleHandler::~SharedModuleHandler() {
    229 }
    230 
    231 bool SharedModuleHandler::Parse(Extension* extension, base::string16* error) {
    232   scoped_ptr<SharedModuleInfo> info(new SharedModuleInfo);
    233   if (!info->Parse(extension, error))
    234     return false;
    235   extension->SetManifestData(kSharedModule, info.release());
    236   return true;
    237 }
    238 
    239 bool SharedModuleHandler::Validate(
    240     const Extension* extension,
    241     std::string* error,
    242     std::vector<InstallWarning>* warnings) const {
    243   // Extensions that export resources should not have any permissions of their
    244   // own, instead they rely on the permissions of the extensions which import
    245   // them.
    246   if (SharedModuleInfo::IsSharedModule(extension) &&
    247       !extension->permissions_data()->active_permissions()->IsEmpty()) {
    248     *error = errors::kInvalidExportPermissions;
    249     return false;
    250   }
    251   return true;
    252 }
    253 
    254 const std::vector<std::string> SharedModuleHandler::Keys() const {
    255   static const char* keys[] = {
    256     keys::kExport,
    257     keys::kImport
    258   };
    259   return std::vector<std::string>(keys, keys + arraysize(keys));
    260 }
    261 
    262 }  // namespace extensions
    263