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 18 namespace extensions { 19 20 namespace keys = manifest_keys; 21 namespace values = manifest_values; 22 namespace errors = manifest_errors; 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