Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / extensions / common / manifest_handlers / shared_module_info.cc
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::IsExportAllowedByWhitelist(const Extension* extension,
88                                                   const std::string& other_id) {
89   const SharedModuleInfo& info = GetSharedModuleInfo(extension);
90   if (info.export_whitelist_.empty())
91     return true;
92   if (info.export_whitelist_.find(other_id) != info.export_whitelist_.end())
93     return true;
94   return false;
95 }
96
97 // static
98 bool SharedModuleInfo::ImportsExtensionById(const Extension* extension,
99                                             const std::string& other_id) {
100   const SharedModuleInfo& info = GetSharedModuleInfo(extension);
101   for (size_t i = 0; i < info.imports_.size(); i++) {
102     if (info.imports_[i].extension_id == other_id)
103       return true;
104   }
105   return false;
106 }
107
108 // static
109 bool SharedModuleInfo::ImportsModules(const Extension* extension) {
110   return GetSharedModuleInfo(extension).imports_.size() > 0;
111 }
112
113 // static
114 const std::vector<SharedModuleInfo::ImportInfo>& SharedModuleInfo::GetImports(
115     const Extension* extension) {
116   return GetSharedModuleInfo(extension).imports_;
117 }
118
119 bool SharedModuleInfo::Parse(const Extension* extension,
120                              base::string16* error) {
121   bool has_import = extension->manifest()->HasKey(keys::kImport);
122   bool has_export = extension->manifest()->HasKey(keys::kExport);
123   if (!has_import && !has_export)
124     return true;
125
126   if (has_import && has_export) {
127     *error = base::ASCIIToUTF16(errors::kInvalidImportAndExport);
128     return false;
129   }
130
131   if (has_export) {
132     const base::DictionaryValue* export_value = NULL;
133     if (!extension->manifest()->GetDictionary(keys::kExport, &export_value)) {
134       *error = base::ASCIIToUTF16(errors::kInvalidExport);
135       return false;
136     }
137     const base::ListValue* resources_list = NULL;
138     if (!export_value->GetList(keys::kResources, &resources_list)) {
139       *error = base::ASCIIToUTF16(errors::kInvalidExportResources);
140       return false;
141     }
142     if (export_value->HasKey(keys::kWhitelist)) {
143       const base::ListValue* whitelist = NULL;
144       if (!export_value->GetList(keys::kWhitelist, &whitelist)) {
145         *error = base::ASCIIToUTF16(errors::kInvalidExportWhitelist);
146         return false;
147       }
148       for (size_t i = 0; i < whitelist->GetSize(); ++i) {
149         std::string extension_id;
150         if (!whitelist->GetString(i, &extension_id) ||
151             !Extension::IdIsValid(extension_id)) {
152           *error = ErrorUtils::FormatErrorMessageUTF16(
153               errors::kInvalidExportWhitelistString, base::IntToString(i));
154           return false;
155         }
156         export_whitelist_.insert(extension_id);
157       }
158     }
159     for (size_t i = 0; i < resources_list->GetSize(); ++i) {
160       std::string resource_path;
161       if (!resources_list->GetString(i, &resource_path)) {
162         *error = ErrorUtils::FormatErrorMessageUTF16(
163             errors::kInvalidExportResourcesString, base::IntToString(i));
164         return false;
165       }
166       const GURL& resolved_path = extension->url().Resolve(resource_path);
167       if (!resolved_path.is_valid()) {
168         *error = ErrorUtils::FormatErrorMessageUTF16(
169             errors::kInvalidExportResourcesString, base::IntToString(i));
170         return false;
171       }
172       exported_set_.AddPattern(
173           URLPattern(URLPattern::SCHEME_EXTENSION, resolved_path.spec()));
174     }
175   }
176
177   if (has_import) {
178     const base::ListValue* import_list = NULL;
179     if (!extension->manifest()->GetList(keys::kImport, &import_list)) {
180       *error = base::ASCIIToUTF16(errors::kInvalidImport);
181       return false;
182     }
183     for (size_t i = 0; i < import_list->GetSize(); ++i) {
184       const base::DictionaryValue* import_entry = NULL;
185       if (!import_list->GetDictionary(i, &import_entry)) {
186         *error = base::ASCIIToUTF16(errors::kInvalidImport);
187         return false;
188       }
189       std::string extension_id;
190       imports_.push_back(ImportInfo());
191       if (!import_entry->GetString(keys::kId, &extension_id) ||
192           !Extension::IdIsValid(extension_id)) {
193         *error = ErrorUtils::FormatErrorMessageUTF16(
194             errors::kInvalidImportId, base::IntToString(i));
195         return false;
196       }
197       imports_.back().extension_id = extension_id;
198       if (import_entry->HasKey(keys::kMinimumVersion)) {
199         std::string min_version;
200         if (!import_entry->GetString(keys::kMinimumVersion, &min_version)) {
201           *error = ErrorUtils::FormatErrorMessageUTF16(
202               errors::kInvalidImportVersion, base::IntToString(i));
203           return false;
204         }
205         imports_.back().minimum_version = min_version;
206         Version v(min_version);
207         if (!v.IsValid()) {
208           *error = ErrorUtils::FormatErrorMessageUTF16(
209               errors::kInvalidImportVersion, base::IntToString(i));
210           return false;
211         }
212       }
213     }
214   }
215   return true;
216 }
217
218
219 SharedModuleHandler::SharedModuleHandler() {
220 }
221
222 SharedModuleHandler::~SharedModuleHandler() {
223 }
224
225 bool SharedModuleHandler::Parse(Extension* extension, base::string16* error) {
226   scoped_ptr<SharedModuleInfo> info(new SharedModuleInfo);
227   if (!info->Parse(extension, error))
228     return false;
229   extension->SetManifestData(kSharedModule, info.release());
230   return true;
231 }
232
233 bool SharedModuleHandler::Validate(
234     const Extension* extension,
235     std::string* error,
236     std::vector<InstallWarning>* warnings) const {
237   // Extensions that export resources should not have any permissions of their
238   // own, instead they rely on the permissions of the extensions which import
239   // them.
240   if (SharedModuleInfo::IsSharedModule(extension) &&
241       !extension->GetActivePermissions()->IsEmpty()) {
242     *error = errors::kInvalidExportPermissions;
243     return false;
244   }
245   return true;
246 }
247
248 const std::vector<std::string> SharedModuleHandler::Keys() const {
249   static const char* keys[] = {
250     keys::kExport,
251     keys::kImport
252   };
253   return std::vector<std::string>(keys, keys + arraysize(keys));
254 }
255
256 }  // namespace extensions