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