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 bool InfoMap::SecurityOriginHasAPIPermission(
135 APIPermission::ID permission
) const {
136 CheckOnValidThread();
137 if (origin
.SchemeIs(kExtensionScheme
)) {
138 const std::string
& id
= origin
.host();
139 const Extension
* extension
= extensions_
.GetByID(id
);
141 extension
->permissions_data()->HasAPIPermission(permission
) &&
142 process_map_
.Contains(id
, process_id
);
144 for (const auto& extension
: extensions_
) {
145 if (extension
->web_extent().MatchesSecurityOrigin(origin
) &&
146 extension
->permissions_data()->HasAPIPermission(permission
) &&
147 process_map_
.Contains(extension
->id(), process_id
)) {
154 // This function is security sensitive. Bugs could cause problems that break
155 // restrictions on local file access or NaCl's validation caching. If you modify
156 // this function, please get a security review from a NaCl person.
157 bool InfoMap::MapUrlToLocalFilePath(const GURL
& file_url
,
158 bool use_blocking_api
,
159 base::FilePath
* file_path
) {
160 // Check that the URL is recognized by the extension system.
161 const Extension
* extension
= extensions_
.GetExtensionOrAppByURL(file_url
);
165 // This is a short-cut which avoids calling a blocking file operation
166 // (GetFilePath()), so that this can be called on the IO thread. It only
167 // handles a subset of the urls.
168 if (!use_blocking_api
) {
169 if (file_url
.SchemeIs(extensions::kExtensionScheme
)) {
170 std::string path
= file_url
.path();
171 base::TrimString(path
, "/", &path
); // Remove first slash
172 *file_path
= extension
->path().AppendASCII(path
);
178 std::string path
= file_url
.path();
179 ExtensionResource resource
;
181 if (SharedModuleInfo::IsImportedPath(path
)) {
182 // Check if this is a valid path that is imported for this extension.
183 std::string new_extension_id
;
184 std::string new_relative_path
;
185 SharedModuleInfo::ParseImportedPath(
186 path
, &new_extension_id
, &new_relative_path
);
187 const Extension
* new_extension
= extensions_
.GetByID(new_extension_id
);
191 if (!SharedModuleInfo::ImportsExtensionById(extension
, new_extension_id
))
194 resource
= new_extension
->GetResource(new_relative_path
);
196 // Check that the URL references a resource in the extension.
197 resource
= extension
->GetResource(path
);
200 if (resource
.empty())
203 // GetFilePath is a blocking function call.
204 const base::FilePath resource_file_path
= resource
.GetFilePath();
205 if (resource_file_path
.empty())
208 *file_path
= resource_file_path
;
212 QuotaService
* InfoMap::GetQuotaService() {
213 CheckOnValidThread();
215 quota_service_
.reset(new QuotaService());
216 return quota_service_
.get();
219 void InfoMap::SetNotificationsDisabled(
220 const std::string
& extension_id
,
221 bool notifications_disabled
) {
222 ExtraDataMap::iterator iter
= extra_data_
.find(extension_id
);
223 if (iter
!= extra_data_
.end())
224 iter
->second
.notifications_disabled
= notifications_disabled
;
227 bool InfoMap::AreNotificationsDisabled(
228 const std::string
& extension_id
) const {
229 ExtraDataMap::const_iterator iter
= extra_data_
.find(extension_id
);
230 if (iter
!= extra_data_
.end())
231 return iter
->second
.notifications_disabled
;
235 void InfoMap::SetContentVerifier(ContentVerifier
* verifier
) {
236 content_verifier_
= verifier
;
239 InfoMap::~InfoMap() {
240 if (quota_service_
) {
241 BrowserThread::DeleteSoon(
242 BrowserThread::IO
, FROM_HERE
, quota_service_
.release());
246 } // namespace extensions