Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / extensions / browser / info_map.cc
blob00b2437b682d7a7f2f67c6973fcafc8a5ef1b4e9
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"
17 #include "url/gurl.h"
19 using content::BrowserThread;
21 namespace extensions {
23 namespace {
25 void CheckOnValidThread() { DCHECK_CURRENTLY_ON(BrowserThread::IO); }
27 } // namespace
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;
39 ExtraData();
40 ~ExtraData();
43 InfoMap::ExtraData::ExtraData()
44 : incognito_enabled(false), notifications_disabled(false) {
47 InfoMap::ExtraData::~ExtraData() {}
49 InfoMap::InfoMap() {
52 void InfoMap::AddExtension(const Extension* extension,
53 base::Time install_time,
54 bool incognito_enabled,
55 bool notifications_disabled) {
56 CheckOnValidThread();
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) {
67 CheckOnValidThread();
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);
72 if (extension) {
73 if (!was_uninstalled)
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);
80 } else {
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;
93 return base::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;
101 return false;
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,
111 int process_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,
120 int process_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(
133 const GURL& origin,
134 int process_id,
135 APIPermission::ID permission,
136 ExtensionSet* extensions) const {
137 DCHECK(extensions);
139 if (origin.SchemeIs(kExtensionScheme)) {
140 const std::string& id = origin.host();
141 const Extension* extension = extensions_.GetByID(id);
142 if (extension &&
143 extension->permissions_data()->HasAPIPermission(permission) &&
144 process_map_.Contains(id, process_id)) {
145 extensions->Insert(extension);
147 return;
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,
161 int process_id,
162 APIPermission::ID permission)
163 const {
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);
178 if (!extension)
179 return false;
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);
189 return true;
191 return false;
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);
204 if (!new_extension)
205 return false;
207 if (!SharedModuleInfo::ImportsExtensionById(extension, new_extension_id))
208 return false;
210 resource = new_extension->GetResource(new_relative_path);
211 } else {
212 // Check that the URL references a resource in the extension.
213 resource = extension->GetResource(path);
216 if (resource.empty())
217 return false;
219 // GetFilePath is a blocking function call.
220 const base::FilePath resource_file_path = resource.GetFilePath();
221 if (resource_file_path.empty())
222 return false;
224 *file_path = resource_file_path;
225 return true;
228 QuotaService* InfoMap::GetQuotaService() {
229 CheckOnValidThread();
230 if (!quota_service_)
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;
248 return false;
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