Add a webstorePrivate API to show a permission prompt for delegated bundle installs
[chromium-blink-merge.git] / chrome / browser / extensions / extension_special_storage_policy.cc
blob102d11bb3cb522a58bdb772fab8b8e84388760c5
1 // Copyright (c) 2012 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 "chrome/browser/extensions/extension_special_storage_policy.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/metrics/histogram.h"
12 #include "base/stl_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/content_settings/cookie_settings.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
17 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
18 #include "chrome/common/url_constants.h"
19 #include "components/content_settings/core/common/content_settings.h"
20 #include "components/content_settings/core/common/content_settings_types.h"
21 #include "content/public/browser/browser_context.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/storage_partition.h"
24 #include "content/public/common/url_constants.h"
25 #include "extensions/common/constants.h"
26 #include "extensions/common/extension.h"
27 #include "extensions/common/extension_set.h"
28 #include "extensions/common/manifest_handlers/content_capabilities_handler.h"
29 #include "extensions/common/permissions/permissions_data.h"
30 #include "storage/browser/quota/quota_manager.h"
31 #include "storage/common/quota/quota_status_code.h"
32 #include "storage/common/quota/quota_types.h"
34 using content::BrowserThread;
35 using extensions::APIPermission;
36 using extensions::Extension;
37 using storage::SpecialStoragePolicy;
39 namespace {
41 void ReportQuotaUsage(storage::QuotaStatusCode code, int64 usage, int64 quota) {
42 if (code == storage::kQuotaStatusOk) {
43 // We're interested in the amount of space hosted apps are using. Record it
44 // when the extension is granted the unlimited storage permission (once per
45 // extension load, so on average once per run).
46 UMA_HISTOGRAM_MEMORY_KB("Extensions.HostedAppUnlimitedStorageUsage", usage);
50 // Log the usage for a hosted app with unlimited storage.
51 void LogHostedAppUnlimitedStorageUsage(
52 scoped_refptr<const Extension> extension,
53 content::BrowserContext* browser_context) {
54 GURL launch_url =
55 extensions::AppLaunchInfo::GetLaunchWebURL(extension.get()).GetOrigin();
56 content::StoragePartition* partition =
57 browser_context ? // |browser_context| can be NULL in unittests.
58 content::BrowserContext::GetStoragePartitionForSite(browser_context,
59 launch_url) :
60 NULL;
61 if (partition) {
62 // We only have to query for kStorageTypePersistent data usage, because apps
63 // cannot ask for any more temporary storage, according to
64 // https://developers.google.com/chrome/whitepapers/storage.
65 BrowserThread::PostTask(
66 BrowserThread::IO,
67 FROM_HERE,
68 base::Bind(&storage::QuotaManager::GetUsageAndQuotaForWebApps,
69 partition->GetQuotaManager(),
70 launch_url,
71 storage::kStorageTypePersistent,
72 base::Bind(&ReportQuotaUsage)));
76 } // namespace
78 ExtensionSpecialStoragePolicy::ExtensionSpecialStoragePolicy(
79 CookieSettings* cookie_settings)
80 : cookie_settings_(cookie_settings) {}
82 ExtensionSpecialStoragePolicy::~ExtensionSpecialStoragePolicy() {}
84 bool ExtensionSpecialStoragePolicy::IsStorageProtected(const GURL& origin) {
85 if (origin.SchemeIs(extensions::kExtensionScheme))
86 return true;
87 base::AutoLock locker(lock_);
88 return protected_apps_.Contains(origin);
91 bool ExtensionSpecialStoragePolicy::IsStorageUnlimited(const GURL& origin) {
92 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
93 switches::kUnlimitedStorage))
94 return true;
96 if (origin.SchemeIs(content::kChromeDevToolsScheme) &&
97 origin.host() == chrome::kChromeUIDevToolsHost)
98 return true;
100 base::AutoLock locker(lock_);
101 return unlimited_extensions_.Contains(origin) ||
102 content_capabilities_unlimited_extensions_.GrantsCapabilitiesTo(
103 origin);
106 bool ExtensionSpecialStoragePolicy::IsStorageSessionOnly(const GURL& origin) {
107 if (cookie_settings_.get() == NULL)
108 return false;
109 return cookie_settings_->IsCookieSessionOnly(origin);
112 bool ExtensionSpecialStoragePolicy::CanQueryDiskSize(const GURL& origin) {
113 base::AutoLock locker(lock_);
114 return installed_apps_.Contains(origin);
117 bool ExtensionSpecialStoragePolicy::HasSessionOnlyOrigins() {
118 if (cookie_settings_.get() == NULL)
119 return false;
120 if (cookie_settings_->GetDefaultCookieSetting(NULL) ==
121 CONTENT_SETTING_SESSION_ONLY)
122 return true;
123 ContentSettingsForOneType entries;
124 cookie_settings_->GetCookieSettings(&entries);
125 for (size_t i = 0; i < entries.size(); ++i) {
126 if (entries[i].setting == CONTENT_SETTING_SESSION_ONLY)
127 return true;
129 return false;
132 bool ExtensionSpecialStoragePolicy::HasIsolatedStorage(const GURL& origin) {
133 base::AutoLock locker(lock_);
134 return isolated_extensions_.Contains(origin);
137 bool ExtensionSpecialStoragePolicy::NeedsProtection(
138 const extensions::Extension* extension) {
139 return extension->is_hosted_app() && !extension->from_bookmark();
142 const extensions::ExtensionSet*
143 ExtensionSpecialStoragePolicy::ExtensionsProtectingOrigin(
144 const GURL& origin) {
145 base::AutoLock locker(lock_);
146 return protected_apps_.ExtensionsContaining(origin);
149 void ExtensionSpecialStoragePolicy::GrantRightsForExtension(
150 const extensions::Extension* extension,
151 content::BrowserContext* browser_context) {
152 base::AutoLock locker(lock_);
153 DCHECK(extension);
155 int change_flags = 0;
156 if (extensions::ContentCapabilitiesInfo::Get(extension)
157 .permissions.count(APIPermission::kUnlimitedStorage) > 0) {
158 content_capabilities_unlimited_extensions_.Add(extension);
159 change_flags |= SpecialStoragePolicy::STORAGE_UNLIMITED;
162 if (NeedsProtection(extension) ||
163 extension->permissions_data()->HasAPIPermission(
164 APIPermission::kUnlimitedStorage) ||
165 extension->permissions_data()->HasAPIPermission(
166 APIPermission::kFileBrowserHandler) ||
167 extensions::AppIsolationInfo::HasIsolatedStorage(extension) ||
168 extension->is_app()) {
169 if (NeedsProtection(extension) && protected_apps_.Add(extension))
170 change_flags |= SpecialStoragePolicy::STORAGE_PROTECTED;
171 // FIXME: Does GrantRightsForExtension imply |extension| is installed?
172 if (extension->is_app())
173 installed_apps_.Add(extension);
175 if (extension->permissions_data()->HasAPIPermission(
176 APIPermission::kUnlimitedStorage) &&
177 unlimited_extensions_.Add(extension)) {
178 if (extension->is_hosted_app())
179 LogHostedAppUnlimitedStorageUsage(extension, browser_context);
180 change_flags |= SpecialStoragePolicy::STORAGE_UNLIMITED;
183 if (extension->permissions_data()->HasAPIPermission(
184 APIPermission::kFileBrowserHandler))
185 file_handler_extensions_.Add(extension);
187 if (extensions::AppIsolationInfo::HasIsolatedStorage(extension))
188 isolated_extensions_.Add(extension);
191 if (change_flags) {
192 NotifyGranted(Extension::GetBaseURLFromExtensionId(extension->id()),
193 change_flags);
197 void ExtensionSpecialStoragePolicy::RevokeRightsForExtension(
198 const extensions::Extension* extension) {
199 base::AutoLock locker(lock_);
200 DCHECK(extension);
202 int change_flags = 0;
203 if (extensions::ContentCapabilitiesInfo::Get(extension)
204 .permissions.count(APIPermission::kUnlimitedStorage) > 0) {
205 content_capabilities_unlimited_extensions_.Remove(extension);
206 change_flags |= SpecialStoragePolicy::STORAGE_UNLIMITED;
209 if (NeedsProtection(extension) ||
210 extension->permissions_data()->HasAPIPermission(
211 APIPermission::kUnlimitedStorage) ||
212 extension->permissions_data()->HasAPIPermission(
213 APIPermission::kFileBrowserHandler) ||
214 extensions::AppIsolationInfo::HasIsolatedStorage(extension) ||
215 extension->is_app()) {
216 if (NeedsProtection(extension) && protected_apps_.Remove(extension))
217 change_flags |= SpecialStoragePolicy::STORAGE_PROTECTED;
219 if (extension->is_app())
220 installed_apps_.Remove(extension);
222 if (extension->permissions_data()->HasAPIPermission(
223 APIPermission::kUnlimitedStorage) &&
224 unlimited_extensions_.Remove(extension))
225 change_flags |= SpecialStoragePolicy::STORAGE_UNLIMITED;
227 if (extension->permissions_data()->HasAPIPermission(
228 APIPermission::kFileBrowserHandler))
229 file_handler_extensions_.Remove(extension);
231 if (extensions::AppIsolationInfo::HasIsolatedStorage(extension))
232 isolated_extensions_.Remove(extension);
235 if (change_flags) {
236 NotifyRevoked(Extension::GetBaseURLFromExtensionId(extension->id()),
237 change_flags);
241 void ExtensionSpecialStoragePolicy::RevokeRightsForAllExtensions() {
243 base::AutoLock locker(lock_);
244 protected_apps_.Clear();
245 installed_apps_.Clear();
246 unlimited_extensions_.Clear();
247 file_handler_extensions_.Clear();
248 isolated_extensions_.Clear();
249 content_capabilities_unlimited_extensions_.Clear();
252 NotifyCleared();
255 void ExtensionSpecialStoragePolicy::NotifyGranted(
256 const GURL& origin,
257 int change_flags) {
258 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
259 BrowserThread::PostTask(
260 BrowserThread::IO, FROM_HERE,
261 base::Bind(&ExtensionSpecialStoragePolicy::NotifyGranted, this,
262 origin, change_flags));
263 return;
265 SpecialStoragePolicy::NotifyGranted(origin, change_flags);
268 void ExtensionSpecialStoragePolicy::NotifyRevoked(
269 const GURL& origin,
270 int change_flags) {
271 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
272 BrowserThread::PostTask(
273 BrowserThread::IO, FROM_HERE,
274 base::Bind(&ExtensionSpecialStoragePolicy::NotifyRevoked, this,
275 origin, change_flags));
276 return;
278 SpecialStoragePolicy::NotifyRevoked(origin, change_flags);
281 void ExtensionSpecialStoragePolicy::NotifyCleared() {
282 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
283 BrowserThread::PostTask(
284 BrowserThread::IO, FROM_HERE,
285 base::Bind(&ExtensionSpecialStoragePolicy::NotifyCleared, this));
286 return;
288 SpecialStoragePolicy::NotifyCleared();
291 //-----------------------------------------------------------------------------
292 // SpecialCollection helper class
293 //-----------------------------------------------------------------------------
295 ExtensionSpecialStoragePolicy::SpecialCollection::SpecialCollection() {}
297 ExtensionSpecialStoragePolicy::SpecialCollection::~SpecialCollection() {
298 STLDeleteValues(&cached_results_);
301 bool ExtensionSpecialStoragePolicy::SpecialCollection::Contains(
302 const GURL& origin) {
303 return !ExtensionsContaining(origin)->is_empty();
306 bool ExtensionSpecialStoragePolicy::SpecialCollection::GrantsCapabilitiesTo(
307 const GURL& origin) {
308 for (scoped_refptr<const Extension> extension : extensions_) {
309 if (extensions::ContentCapabilitiesInfo::Get(extension.get())
310 .url_patterns.MatchesURL(origin)) {
311 return true;
314 return false;
317 const extensions::ExtensionSet*
318 ExtensionSpecialStoragePolicy::SpecialCollection::ExtensionsContaining(
319 const GURL& origin) {
320 CachedResults::const_iterator found = cached_results_.find(origin);
321 if (found != cached_results_.end())
322 return found->second;
324 extensions::ExtensionSet* result = new extensions::ExtensionSet();
325 for (extensions::ExtensionSet::const_iterator iter = extensions_.begin();
326 iter != extensions_.end(); ++iter) {
327 if ((*iter)->OverlapsWithOrigin(origin))
328 result->Insert(*iter);
330 cached_results_[origin] = result;
331 return result;
334 bool ExtensionSpecialStoragePolicy::SpecialCollection::ContainsExtension(
335 const std::string& extension_id) {
336 return extensions_.Contains(extension_id);
339 bool ExtensionSpecialStoragePolicy::SpecialCollection::Add(
340 const extensions::Extension* extension) {
341 ClearCache();
342 return extensions_.Insert(extension);
345 bool ExtensionSpecialStoragePolicy::SpecialCollection::Remove(
346 const extensions::Extension* extension) {
347 ClearCache();
348 return extensions_.Remove(extension->id());
351 void ExtensionSpecialStoragePolicy::SpecialCollection::Clear() {
352 ClearCache();
353 extensions_.Clear();
356 void ExtensionSpecialStoragePolicy::SpecialCollection::ClearCache() {
357 STLDeleteValues(&cached_results_);