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