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/browser/info_map.h"
7 #include "base/strings/string_util.h"
8 #include "content/public/browser/browser_thread.h"
9 #include "extensions/browser/content_verifier.h"
10 #include "extensions/common/constants.h"
11 #include "extensions/common/extension.h"
12 #include "extensions/common/extension_resource.h"
13 #include "extensions/common/extension_set.h"
14 #include "extensions/common/manifest_handlers/incognito_info.h"
15 #include "extensions/common/manifest_handlers/shared_module_info.h"
16 #include "extensions/common/permissions/permissions_data.h"
19 using content::BrowserThread
;
21 namespace extensions
{
25 void CheckOnValidThread() { DCHECK_CURRENTLY_ON(BrowserThread::IO
); }
29 struct InfoMap::ExtraData
{
30 // When the extension was installed.
31 base::Time install_time
;
33 // True if the user has allowed this extension to run in incognito mode.
34 bool incognito_enabled
;
36 // True if the user has disabled notifications for this extension manually.
37 bool notifications_disabled
;
43 InfoMap::ExtraData::ExtraData()
44 : incognito_enabled(false), notifications_disabled(false) {
47 InfoMap::ExtraData::~ExtraData() {}
52 void InfoMap::AddExtension(const Extension
* extension
,
53 base::Time install_time
,
54 bool incognito_enabled
,
55 bool notifications_disabled
) {
57 extensions_
.Insert(extension
);
58 disabled_extensions_
.Remove(extension
->id());
60 extra_data_
[extension
->id()].install_time
= install_time
;
61 extra_data_
[extension
->id()].incognito_enabled
= incognito_enabled
;
62 extra_data_
[extension
->id()].notifications_disabled
= notifications_disabled
;
65 void InfoMap::RemoveExtension(const std::string
& extension_id
,
66 const UnloadedExtensionInfo::Reason reason
) {
68 const Extension
* extension
= extensions_
.GetByID(extension_id
);
69 extra_data_
.erase(extension_id
); // we don't care about disabled extra data
70 bool was_uninstalled
= (reason
!= UnloadedExtensionInfo::REASON_DISABLE
&&
71 reason
!= UnloadedExtensionInfo::REASON_TERMINATE
);
74 disabled_extensions_
.Insert(extension
);
75 extensions_
.Remove(extension_id
);
76 } else if (was_uninstalled
) {
77 // If the extension was uninstalled, make sure it's removed from the map of
78 // disabled extensions.
79 disabled_extensions_
.Remove(extension_id
);
81 // NOTE: This can currently happen if we receive multiple unload
82 // notifications, e.g. setting incognito-enabled state for a
83 // disabled extension (e.g., via sync). See
84 // http://code.google.com/p/chromium/issues/detail?id=50582 .
85 NOTREACHED() << extension_id
;
89 base::Time
InfoMap::GetInstallTime(const std::string
& extension_id
) const {
90 ExtraDataMap::const_iterator iter
= extra_data_
.find(extension_id
);
91 if (iter
!= extra_data_
.end())
92 return iter
->second
.install_time
;
96 bool InfoMap::IsIncognitoEnabled(const std::string
& extension_id
) const {
97 // Keep in sync with duplicate in extensions/browser/process_manager.cc.
98 ExtraDataMap::const_iterator iter
= extra_data_
.find(extension_id
);
99 if (iter
!= extra_data_
.end())
100 return iter
->second
.incognito_enabled
;
104 bool InfoMap::CanCrossIncognito(const Extension
* extension
) const {
105 // This is duplicated from ExtensionService :(.
106 return IsIncognitoEnabled(extension
->id()) &&
107 !IncognitoInfo::IsSplitMode(extension
);
110 void InfoMap::RegisterExtensionProcess(const std::string
& extension_id
,
112 int site_instance_id
) {
113 if (!process_map_
.Insert(extension_id
, process_id
, site_instance_id
)) {
114 NOTREACHED() << "Duplicate extension process registration for: "
115 << extension_id
<< "," << process_id
<< ".";
119 void InfoMap::UnregisterExtensionProcess(const std::string
& extension_id
,
121 int site_instance_id
) {
122 if (!process_map_
.Remove(extension_id
, process_id
, site_instance_id
)) {
123 NOTREACHED() << "Unknown extension process registration for: "
124 << extension_id
<< "," << process_id
<< ".";
128 void InfoMap::UnregisterAllExtensionsInProcess(int process_id
) {
129 process_map_
.RemoveAllFromProcess(process_id
);
132 void InfoMap::GetExtensionsWithAPIPermissionForSecurityOrigin(
135 APIPermission::ID permission
,
136 ExtensionSet
* extensions
) const {
139 if (origin
.SchemeIs(kExtensionScheme
)) {
140 const std::string
& id
= origin
.host();
141 const Extension
* extension
= extensions_
.GetByID(id
);
143 extension
->permissions_data()->HasAPIPermission(permission
) &&
144 process_map_
.Contains(id
, process_id
)) {
145 extensions
->Insert(extension
);
150 ExtensionSet::const_iterator i
= extensions_
.begin();
151 for (; i
!= extensions_
.end(); ++i
) {
152 if ((*i
)->web_extent().MatchesSecurityOrigin(origin
) &&
153 process_map_
.Contains((*i
)->id(), process_id
) &&
154 (*i
)->permissions_data()->HasAPIPermission(permission
)) {
155 extensions
->Insert(*i
);
160 bool InfoMap::SecurityOriginHasAPIPermission(const GURL
& origin
,
162 APIPermission::ID permission
)
164 ExtensionSet extensions
;
165 GetExtensionsWithAPIPermissionForSecurityOrigin(
166 origin
, process_id
, permission
, &extensions
);
167 return !extensions
.is_empty();
170 // This function is security sensitive. Bugs could cause problems that break
171 // restrictions on local file access or NaCl's validation caching. If you modify
172 // this function, please get a security review from a NaCl person.
173 bool InfoMap::MapUrlToLocalFilePath(const GURL
& file_url
,
174 bool use_blocking_api
,
175 base::FilePath
* file_path
) {
176 // Check that the URL is recognized by the extension system.
177 const Extension
* extension
= extensions_
.GetExtensionOrAppByURL(file_url
);
181 // This is a short-cut which avoids calling a blocking file operation
182 // (GetFilePath()), so that this can be called on the IO thread. It only
183 // handles a subset of the urls.
184 if (!use_blocking_api
) {
185 if (file_url
.SchemeIs(extensions::kExtensionScheme
)) {
186 std::string path
= file_url
.path();
187 base::TrimString(path
, "/", &path
); // Remove first slash
188 *file_path
= extension
->path().AppendASCII(path
);
194 std::string path
= file_url
.path();
195 ExtensionResource resource
;
197 if (SharedModuleInfo::IsImportedPath(path
)) {
198 // Check if this is a valid path that is imported for this extension.
199 std::string new_extension_id
;
200 std::string new_relative_path
;
201 SharedModuleInfo::ParseImportedPath(
202 path
, &new_extension_id
, &new_relative_path
);
203 const Extension
* new_extension
= extensions_
.GetByID(new_extension_id
);
207 if (!SharedModuleInfo::ImportsExtensionById(extension
, new_extension_id
))
210 resource
= new_extension
->GetResource(new_relative_path
);
212 // Check that the URL references a resource in the extension.
213 resource
= extension
->GetResource(path
);
216 if (resource
.empty())
219 // GetFilePath is a blocking function call.
220 const base::FilePath resource_file_path
= resource
.GetFilePath();
221 if (resource_file_path
.empty())
224 *file_path
= resource_file_path
;
228 QuotaService
* InfoMap::GetQuotaService() {
229 CheckOnValidThread();
231 quota_service_
.reset(new QuotaService());
232 return quota_service_
.get();
235 void InfoMap::SetNotificationsDisabled(
236 const std::string
& extension_id
,
237 bool notifications_disabled
) {
238 ExtraDataMap::iterator iter
= extra_data_
.find(extension_id
);
239 if (iter
!= extra_data_
.end())
240 iter
->second
.notifications_disabled
= notifications_disabled
;
243 bool InfoMap::AreNotificationsDisabled(
244 const std::string
& extension_id
) const {
245 ExtraDataMap::const_iterator iter
= extra_data_
.find(extension_id
);
246 if (iter
!= extra_data_
.end())
247 return iter
->second
.notifications_disabled
;
251 void InfoMap::SetContentVerifier(ContentVerifier
* verifier
) {
252 content_verifier_
= verifier
;
255 InfoMap::~InfoMap() {
256 if (quota_service_
) {
257 BrowserThread::DeleteSoon(
258 BrowserThread::IO
, FROM_HERE
, quota_service_
.release());
262 } // namespace extensions