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() {}
49 InfoMap::InfoMap() : signin_process_id_(-1) {
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::RegisterExtensionWorkerProcess(const std::string& extension_id,
134 int site_instance_id) {
135 if (!worker_process_map_.Insert(extension_id, process_id, site_instance_id)) {
136 NOTREACHED() << "Duplicate extension worker process registration for: "
137 << extension_id << "," << process_id << ".";
141 void InfoMap::UnregisterExtensionWorkerProcess(int process_id) {
142 worker_process_map_.RemoveAllFromProcess(process_id);
145 void InfoMap::GetExtensionsWithAPIPermissionForSecurityOrigin(
148 APIPermission::ID permission,
149 ExtensionSet* extensions) const {
152 if (origin.SchemeIs(kExtensionScheme)) {
153 const std::string& id = origin.host();
154 const Extension* extension = extensions_.GetByID(id);
156 extension->permissions_data()->HasAPIPermission(permission) &&
157 process_map_.Contains(id, process_id)) {
158 extensions->Insert(extension);
163 ExtensionSet::const_iterator i = extensions_.begin();
164 for (; i != extensions_.end(); ++i) {
165 if ((*i)->web_extent().MatchesSecurityOrigin(origin) &&
166 process_map_.Contains((*i)->id(), process_id) &&
167 (*i)->permissions_data()->HasAPIPermission(permission)) {
168 extensions->Insert(*i);
173 bool InfoMap::SecurityOriginHasAPIPermission(const GURL& origin,
175 APIPermission::ID permission)
177 ExtensionSet extensions;
178 GetExtensionsWithAPIPermissionForSecurityOrigin(
179 origin, process_id, permission, &extensions);
180 return !extensions.is_empty();
183 // This function is security sensitive. Bugs could cause problems that break
184 // restrictions on local file access or NaCl's validation caching. If you modify
185 // this function, please get a security review from a NaCl person.
186 bool InfoMap::MapUrlToLocalFilePath(const GURL& file_url,
187 bool use_blocking_api,
188 base::FilePath* file_path) {
189 // Check that the URL is recognized by the extension system.
190 const Extension* extension = extensions_.GetExtensionOrAppByURL(file_url);
194 // This is a short-cut which avoids calling a blocking file operation
195 // (GetFilePath()), so that this can be called on the IO thread. It only
196 // handles a subset of the urls.
197 if (!use_blocking_api) {
198 if (file_url.SchemeIs(extensions::kExtensionScheme)) {
199 std::string path = file_url.path();
200 base::TrimString(path, "/", &path); // Remove first slash
201 *file_path = extension->path().AppendASCII(path);
207 std::string path = file_url.path();
208 ExtensionResource resource;
210 if (SharedModuleInfo::IsImportedPath(path)) {
211 // Check if this is a valid path that is imported for this extension.
212 std::string new_extension_id;
213 std::string new_relative_path;
214 SharedModuleInfo::ParseImportedPath(
215 path, &new_extension_id, &new_relative_path);
216 const Extension* new_extension = extensions_.GetByID(new_extension_id);
220 if (!SharedModuleInfo::ImportsExtensionById(extension, new_extension_id) ||
221 !SharedModuleInfo::IsExportAllowed(new_extension, new_relative_path)) {
225 resource = new_extension->GetResource(new_relative_path);
227 // Check that the URL references a resource in the extension.
228 resource = extension->GetResource(path);
231 if (resource.empty())
234 // GetFilePath is a blocking function call.
235 const base::FilePath resource_file_path = resource.GetFilePath();
236 if (resource_file_path.empty())
239 *file_path = resource_file_path;
243 QuotaService* InfoMap::GetQuotaService() {
244 CheckOnValidThread();
246 quota_service_.reset(new QuotaService());
247 return quota_service_.get();
250 void InfoMap::SetSigninProcess(int process_id) {
251 signin_process_id_ = process_id;
254 bool InfoMap::IsSigninProcess(int process_id) const {
255 return process_id == signin_process_id_;
258 void InfoMap::SetNotificationsDisabled(
259 const std::string& extension_id,
260 bool notifications_disabled) {
261 ExtraDataMap::iterator iter = extra_data_.find(extension_id);
262 if (iter != extra_data_.end())
263 iter->second.notifications_disabled = notifications_disabled;
266 bool InfoMap::AreNotificationsDisabled(
267 const std::string& extension_id) const {
268 ExtraDataMap::const_iterator iter = extra_data_.find(extension_id);
269 if (iter != extra_data_.end())
270 return iter->second.notifications_disabled;
274 void InfoMap::SetContentVerifier(ContentVerifier* verifier) {
275 content_verifier_ = verifier;
278 InfoMap::~InfoMap() {
279 if (quota_service_) {
280 BrowserThread::DeleteSoon(
281 BrowserThread::IO, FROM_HERE, quota_service_.release());
285 } // namespace extensions