Upstreaming browser/ui/uikit_ui_util from iOS.
[chromium-blink-merge.git] / extensions / common / manifest_handlers / shared_module_info.cc
blob99efe8828fdc9fa1c7be4aacac5ee8c1dbbce662
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.
5 #include "extensions/common/manifest_handlers/shared_module_info.h"
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_split.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/version.h"
14 #include "components/crx_file/id_util.h"
15 #include "extensions/common/constants.h"
16 #include "extensions/common/error_utils.h"
17 #include "extensions/common/manifest_constants.h"
18 #include "extensions/common/permissions/permission_set.h"
19 #include "extensions/common/permissions/permissions_data.h"
21 namespace extensions {
23 namespace keys = manifest_keys;
24 namespace values = manifest_values;
25 namespace errors = manifest_errors;
27 namespace {
29 const char kSharedModule[] = "shared_module";
31 static base::LazyInstance<SharedModuleInfo> g_empty_shared_module_info =
32 LAZY_INSTANCE_INITIALIZER;
34 const SharedModuleInfo& GetSharedModuleInfo(const Extension* extension) {
35 SharedModuleInfo* info = static_cast<SharedModuleInfo*>(
36 extension->GetManifestData(kSharedModule));
37 if (!info)
38 return g_empty_shared_module_info.Get();
39 return *info;
42 } // namespace
44 SharedModuleInfo::SharedModuleInfo() {
47 SharedModuleInfo::~SharedModuleInfo() {
50 // static
51 void SharedModuleInfo::ParseImportedPath(const std::string& path,
52 std::string* import_id,
53 std::string* import_relative_path) {
54 std::vector<std::string> tokens = base::SplitString(
55 path, "/", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
56 if (tokens.size() > 2 && tokens[0] == kModulesDir &&
57 crx_file::id_util::IdIsValid(tokens[1])) {
58 *import_id = tokens[1];
59 *import_relative_path = tokens[2];
60 for (size_t i = 3; i < tokens.size(); ++i)
61 *import_relative_path += "/" + tokens[i];
65 // static
66 bool SharedModuleInfo::IsImportedPath(const std::string& path) {
67 std::vector<std::string> tokens = base::SplitString(
68 path, "/", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
69 if (tokens.size() > 2 && tokens[0] == kModulesDir &&
70 crx_file::id_util::IdIsValid(tokens[1])) {
71 return true;
73 return false;
76 // static
77 bool SharedModuleInfo::IsSharedModule(const Extension* extension) {
78 CHECK(extension);
79 return extension->manifest()->is_shared_module();
82 // static
83 bool SharedModuleInfo::IsExportAllowedByWhitelist(const Extension* extension,
84 const std::string& other_id) {
85 // Sanity check. In case the caller did not check |extension| to make sure it
86 // is a shared module, we do not want it to appear that the extension with
87 // |other_id| importing |extension| is valid.
88 if (!SharedModuleInfo::IsSharedModule(extension))
89 return false;
90 const SharedModuleInfo& info = GetSharedModuleInfo(extension);
91 if (info.export_whitelist_.empty())
92 return true;
93 if (info.export_whitelist_.find(other_id) != info.export_whitelist_.end())
94 return true;
95 return false;
98 // static
99 bool SharedModuleInfo::ImportsExtensionById(const Extension* extension,
100 const std::string& other_id) {
101 const SharedModuleInfo& info = GetSharedModuleInfo(extension);
102 for (size_t i = 0; i < info.imports_.size(); i++) {
103 if (info.imports_[i].extension_id == other_id)
104 return true;
106 return false;
109 // static
110 bool SharedModuleInfo::ImportsModules(const Extension* extension) {
111 return GetSharedModuleInfo(extension).imports_.size() > 0;
114 // static
115 const std::vector<SharedModuleInfo::ImportInfo>& SharedModuleInfo::GetImports(
116 const Extension* extension) {
117 return GetSharedModuleInfo(extension).imports_;
120 bool SharedModuleInfo::Parse(const Extension* extension,
121 base::string16* error) {
122 bool has_import = extension->manifest()->HasKey(keys::kImport);
123 bool has_export = extension->manifest()->HasKey(keys::kExport);
124 if (!has_import && !has_export)
125 return true;
127 if (has_import && has_export) {
128 *error = base::ASCIIToUTF16(errors::kInvalidImportAndExport);
129 return false;
132 if (has_export) {
133 const base::DictionaryValue* export_value = NULL;
134 if (!extension->manifest()->GetDictionary(keys::kExport, &export_value)) {
135 *error = base::ASCIIToUTF16(errors::kInvalidExport);
136 return false;
138 if (export_value->HasKey(keys::kWhitelist)) {
139 const base::ListValue* whitelist = NULL;
140 if (!export_value->GetList(keys::kWhitelist, &whitelist)) {
141 *error = base::ASCIIToUTF16(errors::kInvalidExportWhitelist);
142 return false;
144 for (size_t i = 0; i < whitelist->GetSize(); ++i) {
145 std::string extension_id;
146 if (!whitelist->GetString(i, &extension_id) ||
147 !crx_file::id_util::IdIsValid(extension_id)) {
148 *error = ErrorUtils::FormatErrorMessageUTF16(
149 errors::kInvalidExportWhitelistString, base::IntToString(i));
150 return false;
152 export_whitelist_.insert(extension_id);
157 if (has_import) {
158 const base::ListValue* import_list = NULL;
159 if (!extension->manifest()->GetList(keys::kImport, &import_list)) {
160 *error = base::ASCIIToUTF16(errors::kInvalidImport);
161 return false;
163 for (size_t i = 0; i < import_list->GetSize(); ++i) {
164 const base::DictionaryValue* import_entry = NULL;
165 if (!import_list->GetDictionary(i, &import_entry)) {
166 *error = base::ASCIIToUTF16(errors::kInvalidImport);
167 return false;
169 std::string extension_id;
170 imports_.push_back(ImportInfo());
171 if (!import_entry->GetString(keys::kId, &extension_id) ||
172 !crx_file::id_util::IdIsValid(extension_id)) {
173 *error = ErrorUtils::FormatErrorMessageUTF16(
174 errors::kInvalidImportId, base::IntToString(i));
175 return false;
177 imports_.back().extension_id = extension_id;
178 if (import_entry->HasKey(keys::kMinimumVersion)) {
179 std::string min_version;
180 if (!import_entry->GetString(keys::kMinimumVersion, &min_version)) {
181 *error = ErrorUtils::FormatErrorMessageUTF16(
182 errors::kInvalidImportVersion, base::IntToString(i));
183 return false;
185 imports_.back().minimum_version = min_version;
186 Version v(min_version);
187 if (!v.IsValid()) {
188 *error = ErrorUtils::FormatErrorMessageUTF16(
189 errors::kInvalidImportVersion, base::IntToString(i));
190 return false;
195 return true;
199 SharedModuleHandler::SharedModuleHandler() {
202 SharedModuleHandler::~SharedModuleHandler() {
205 bool SharedModuleHandler::Parse(Extension* extension, base::string16* error) {
206 scoped_ptr<SharedModuleInfo> info(new SharedModuleInfo);
207 if (!info->Parse(extension, error))
208 return false;
209 extension->SetManifestData(kSharedModule, info.release());
210 return true;
213 bool SharedModuleHandler::Validate(
214 const Extension* extension,
215 std::string* error,
216 std::vector<InstallWarning>* warnings) const {
217 // Extensions that export resources should not have any permissions of their
218 // own, instead they rely on the permissions of the extensions which import
219 // them.
220 if (SharedModuleInfo::IsSharedModule(extension) &&
221 !extension->permissions_data()->active_permissions()->IsEmpty()) {
222 *error = errors::kInvalidExportPermissions;
223 return false;
225 return true;
228 const std::vector<std::string> SharedModuleHandler::Keys() const {
229 static const char* keys[] = {
230 keys::kExport,
231 keys::kImport
233 return std::vector<std::string>(keys, keys + arraysize(keys));
236 } // namespace extensions