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
;
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
));
38 return g_empty_shared_module_info
.Get();
44 SharedModuleInfo::SharedModuleInfo() {
47 SharedModuleInfo::~SharedModuleInfo() {
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
];
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])) {
77 bool SharedModuleInfo::IsSharedModule(const Extension
* extension
) {
79 return extension
->manifest()->is_shared_module();
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
))
90 const SharedModuleInfo
& info
= GetSharedModuleInfo(extension
);
91 if (info
.export_whitelist_
.empty())
93 if (info
.export_whitelist_
.find(other_id
) != info
.export_whitelist_
.end())
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
)
110 bool SharedModuleInfo::ImportsModules(const Extension
* extension
) {
111 return GetSharedModuleInfo(extension
).imports_
.size() > 0;
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
)
127 if (has_import
&& has_export
) {
128 *error
= base::ASCIIToUTF16(errors::kInvalidImportAndExport
);
133 const base::DictionaryValue
* export_value
= NULL
;
134 if (!extension
->manifest()->GetDictionary(keys::kExport
, &export_value
)) {
135 *error
= base::ASCIIToUTF16(errors::kInvalidExport
);
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
);
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
));
152 export_whitelist_
.insert(extension_id
);
158 const base::ListValue
* import_list
= NULL
;
159 if (!extension
->manifest()->GetList(keys::kImport
, &import_list
)) {
160 *error
= base::ASCIIToUTF16(errors::kInvalidImport
);
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
);
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
));
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
));
185 imports_
.back().minimum_version
= min_version
;
186 Version
v(min_version
);
188 *error
= ErrorUtils::FormatErrorMessageUTF16(
189 errors::kInvalidImportVersion
, base::IntToString(i
));
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
))
209 extension
->SetManifestData(kSharedModule
, info
.release());
213 bool SharedModuleHandler::Validate(
214 const Extension
* extension
,
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
220 if (SharedModuleInfo::IsSharedModule(extension
) &&
221 !extension
->permissions_data()->active_permissions()->IsEmpty()) {
222 *error
= errors::kInvalidExportPermissions
;
228 const std::vector
<std::string
> SharedModuleHandler::Keys() const {
229 static const char* keys
[] = {
233 return std::vector
<std::string
>(keys
, keys
+ arraysize(keys
));
236 } // namespace extensions