Adding Peter Thatcher to the owners file.
[chromium-blink-merge.git] / extensions / common / manifest_handlers / shared_module_info.cc
blob70f6ea93f89f72b2d2cc7be81d2b0fadfcf65fcf
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_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"
20 namespace extensions {
22 namespace keys = manifest_keys;
23 namespace values = manifest_values;
24 namespace errors = manifest_errors;
26 namespace {
28 const char kSharedModule[] = "shared_module";
30 static base::LazyInstance<SharedModuleInfo> g_empty_shared_module_info =
31 LAZY_INSTANCE_INITIALIZER;
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;
41 } // namespace
43 SharedModuleInfo::SharedModuleInfo() {
46 SharedModuleInfo::~SharedModuleInfo() {
49 // static
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];
64 // static
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;
72 return false;
75 // static
76 bool SharedModuleInfo::IsSharedModule(const Extension* extension) {
77 CHECK(extension);
78 return extension->manifest()->is_shared_module();
81 // static
82 bool SharedModuleInfo::IsExportAllowedByWhitelist(const Extension* extension,
83 const std::string& other_id) {
84 // Sanity check. In case the caller did not check |extension| to make sure it
85 // is a shared module, we do not want it to appear that the extension with
86 // |other_id| importing |extension| is valid.
87 if (!SharedModuleInfo::IsSharedModule(extension))
88 return false;
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;
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;
105 return false;
108 // static
109 bool SharedModuleInfo::ImportsModules(const Extension* extension) {
110 return GetSharedModuleInfo(extension).imports_.size() > 0;
113 // static
114 const std::vector<SharedModuleInfo::ImportInfo>& SharedModuleInfo::GetImports(
115 const Extension* extension) {
116 return GetSharedModuleInfo(extension).imports_;
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;
126 if (has_import && has_export) {
127 *error = base::ASCIIToUTF16(errors::kInvalidImportAndExport);
128 return false;
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;
137 if (export_value->HasKey(keys::kWhitelist)) {
138 const base::ListValue* whitelist = NULL;
139 if (!export_value->GetList(keys::kWhitelist, &whitelist)) {
140 *error = base::ASCIIToUTF16(errors::kInvalidExportWhitelist);
141 return false;
143 for (size_t i = 0; i < whitelist->GetSize(); ++i) {
144 std::string extension_id;
145 if (!whitelist->GetString(i, &extension_id) ||
146 !crx_file::id_util::IdIsValid(extension_id)) {
147 *error = ErrorUtils::FormatErrorMessageUTF16(
148 errors::kInvalidExportWhitelistString, base::IntToString(i));
149 return false;
151 export_whitelist_.insert(extension_id);
156 if (has_import) {
157 const base::ListValue* import_list = NULL;
158 if (!extension->manifest()->GetList(keys::kImport, &import_list)) {
159 *error = base::ASCIIToUTF16(errors::kInvalidImport);
160 return false;
162 for (size_t i = 0; i < import_list->GetSize(); ++i) {
163 const base::DictionaryValue* import_entry = NULL;
164 if (!import_list->GetDictionary(i, &import_entry)) {
165 *error = base::ASCIIToUTF16(errors::kInvalidImport);
166 return false;
168 std::string extension_id;
169 imports_.push_back(ImportInfo());
170 if (!import_entry->GetString(keys::kId, &extension_id) ||
171 !crx_file::id_util::IdIsValid(extension_id)) {
172 *error = ErrorUtils::FormatErrorMessageUTF16(
173 errors::kInvalidImportId, base::IntToString(i));
174 return false;
176 imports_.back().extension_id = extension_id;
177 if (import_entry->HasKey(keys::kMinimumVersion)) {
178 std::string min_version;
179 if (!import_entry->GetString(keys::kMinimumVersion, &min_version)) {
180 *error = ErrorUtils::FormatErrorMessageUTF16(
181 errors::kInvalidImportVersion, base::IntToString(i));
182 return false;
184 imports_.back().minimum_version = min_version;
185 Version v(min_version);
186 if (!v.IsValid()) {
187 *error = ErrorUtils::FormatErrorMessageUTF16(
188 errors::kInvalidImportVersion, base::IntToString(i));
189 return false;
194 return true;
198 SharedModuleHandler::SharedModuleHandler() {
201 SharedModuleHandler::~SharedModuleHandler() {
204 bool SharedModuleHandler::Parse(Extension* extension, base::string16* error) {
205 scoped_ptr<SharedModuleInfo> info(new SharedModuleInfo);
206 if (!info->Parse(extension, error))
207 return false;
208 extension->SetManifestData(kSharedModule, info.release());
209 return true;
212 bool SharedModuleHandler::Validate(
213 const Extension* extension,
214 std::string* error,
215 std::vector<InstallWarning>* warnings) const {
216 // Extensions that export resources should not have any permissions of their
217 // own, instead they rely on the permissions of the extensions which import
218 // them.
219 if (SharedModuleInfo::IsSharedModule(extension) &&
220 !extension->permissions_data()->active_permissions()->IsEmpty()) {
221 *error = errors::kInvalidExportPermissions;
222 return false;
224 return true;
227 const std::vector<std::string> SharedModuleHandler::Keys() const {
228 static const char* keys[] = {
229 keys::kExport,
230 keys::kImport
232 return std::vector<std::string>(keys, keys + arraysize(keys));
235 } // namespace extensions