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
;
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
));
37 return g_empty_shared_module_info
.Get();
43 SharedModuleInfo::SharedModuleInfo() {
46 SharedModuleInfo::~SharedModuleInfo() {
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
];
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])) {
76 bool SharedModuleInfo::IsSharedModule(const Extension
* extension
) {
78 return extension
->manifest()->is_shared_module();
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
))
89 const SharedModuleInfo
& info
= GetSharedModuleInfo(extension
);
90 if (info
.export_whitelist_
.empty())
92 if (info
.export_whitelist_
.find(other_id
) != info
.export_whitelist_
.end())
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
)
109 bool SharedModuleInfo::ImportsModules(const Extension
* extension
) {
110 return GetSharedModuleInfo(extension
).imports_
.size() > 0;
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
)
126 if (has_import
&& has_export
) {
127 *error
= base::ASCIIToUTF16(errors::kInvalidImportAndExport
);
132 const base::DictionaryValue
* export_value
= NULL
;
133 if (!extension
->manifest()->GetDictionary(keys::kExport
, &export_value
)) {
134 *error
= base::ASCIIToUTF16(errors::kInvalidExport
);
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
);
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
));
151 export_whitelist_
.insert(extension_id
);
157 const base::ListValue
* import_list
= NULL
;
158 if (!extension
->manifest()->GetList(keys::kImport
, &import_list
)) {
159 *error
= base::ASCIIToUTF16(errors::kInvalidImport
);
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
);
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
));
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
));
184 imports_
.back().minimum_version
= min_version
;
185 Version
v(min_version
);
187 *error
= ErrorUtils::FormatErrorMessageUTF16(
188 errors::kInvalidImportVersion
, base::IntToString(i
));
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
))
208 extension
->SetManifestData(kSharedModule
, info
.release());
212 bool SharedModuleHandler::Validate(
213 const Extension
* extension
,
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
219 if (SharedModuleInfo::IsSharedModule(extension
) &&
220 !extension
->permissions_data()->active_permissions()->IsEmpty()) {
221 *error
= errors::kInvalidExportPermissions
;
227 const std::vector
<std::string
> SharedModuleHandler::Keys() const {
228 static const char* keys
[] = {
232 return std::vector
<std::string
>(keys
, keys
+ arraysize(keys
));
235 } // namespace extensions