• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetSharedModuleInfo(const Extension * extension)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 
SharedModuleInfo()42 SharedModuleInfo::SharedModuleInfo() {
43 }
44 
~SharedModuleInfo()45 SharedModuleInfo::~SharedModuleInfo() {
46 }
47 
48 // static
ParseImportedPath(const std::string & path,std::string * import_id,std::string * import_relative_path)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
IsImportedPath(const std::string & path)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
IsSharedModule(const Extension * extension)75 bool SharedModuleInfo::IsSharedModule(const Extension* extension) {
76   CHECK(extension);
77   return extension->manifest()->is_shared_module();
78 }
79 
80 // static
IsExportAllowed(const Extension * extension,const std::string & relative_path)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
IsExportAllowedByWhitelist(const Extension * extension,const std::string & other_id)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
ImportsExtensionById(const Extension * extension,const std::string & other_id)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
ImportsModules(const Extension * extension)115 bool SharedModuleInfo::ImportsModules(const Extension* extension) {
116   return GetSharedModuleInfo(extension).imports_.size() > 0;
117 }
118 
119 // static
GetImports(const Extension * extension)120 const std::vector<SharedModuleInfo::ImportInfo>& SharedModuleInfo::GetImports(
121     const Extension* extension) {
122   return GetSharedModuleInfo(extension).imports_;
123 }
124 
Parse(const Extension * extension,base::string16 * error)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 
SharedModuleHandler()225 SharedModuleHandler::SharedModuleHandler() {
226 }
227 
~SharedModuleHandler()228 SharedModuleHandler::~SharedModuleHandler() {
229 }
230 
Parse(Extension * extension,base::string16 * error)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 
Validate(const Extension * extension,std::string * error,std::vector<InstallWarning> * warnings) const239 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 
Keys() const254 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