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