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.
4
5 #include "chrome/browser/extensions/extension_special_storage_policy.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/stl_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/content_settings/cookie_settings.h"
13 #include "chrome/common/chrome_switches.h"
14 #include "chrome/common/content_settings.h"
15 #include "chrome/common/content_settings_types.h"
16 #include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
17 #include "chrome/common/url_constants.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/common/url_constants.h"
20 #include "extensions/common/constants.h"
21 #include "extensions/common/extension.h"
22 #include "extensions/common/extension_set.h"
23 #include "extensions/common/permissions/permissions_data.h"
24
25 using content::BrowserThread;
26 using extensions::APIPermission;
27 using extensions::Extension;
28 using quota::SpecialStoragePolicy;
29
ExtensionSpecialStoragePolicy(CookieSettings * cookie_settings)30 ExtensionSpecialStoragePolicy::ExtensionSpecialStoragePolicy(
31 CookieSettings* cookie_settings)
32 : cookie_settings_(cookie_settings) {}
33
~ExtensionSpecialStoragePolicy()34 ExtensionSpecialStoragePolicy::~ExtensionSpecialStoragePolicy() {}
35
IsStorageProtected(const GURL & origin)36 bool ExtensionSpecialStoragePolicy::IsStorageProtected(const GURL& origin) {
37 if (origin.SchemeIs(extensions::kExtensionScheme))
38 return true;
39 base::AutoLock locker(lock_);
40 return protected_apps_.Contains(origin);
41 }
42
IsStorageUnlimited(const GURL & origin)43 bool ExtensionSpecialStoragePolicy::IsStorageUnlimited(const GURL& origin) {
44 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUnlimitedStorage))
45 return true;
46
47 if (origin.SchemeIs(content::kChromeDevToolsScheme) &&
48 origin.host() == chrome::kChromeUIDevToolsHost)
49 return true;
50
51 base::AutoLock locker(lock_);
52 return unlimited_extensions_.Contains(origin);
53 }
54
IsStorageSessionOnly(const GURL & origin)55 bool ExtensionSpecialStoragePolicy::IsStorageSessionOnly(const GURL& origin) {
56 if (cookie_settings_.get() == NULL)
57 return false;
58 return cookie_settings_->IsCookieSessionOnly(origin);
59 }
60
CanQueryDiskSize(const GURL & origin)61 bool ExtensionSpecialStoragePolicy::CanQueryDiskSize(const GURL& origin) {
62 return installed_apps_.Contains(origin);
63 }
64
HasSessionOnlyOrigins()65 bool ExtensionSpecialStoragePolicy::HasSessionOnlyOrigins() {
66 if (cookie_settings_.get() == NULL)
67 return false;
68 if (cookie_settings_->GetDefaultCookieSetting(NULL) ==
69 CONTENT_SETTING_SESSION_ONLY)
70 return true;
71 ContentSettingsForOneType entries;
72 cookie_settings_->GetCookieSettings(&entries);
73 for (size_t i = 0; i < entries.size(); ++i) {
74 if (entries[i].setting == CONTENT_SETTING_SESSION_ONLY)
75 return true;
76 }
77 return false;
78 }
79
IsFileHandler(const std::string & extension_id)80 bool ExtensionSpecialStoragePolicy::IsFileHandler(
81 const std::string& extension_id) {
82 base::AutoLock locker(lock_);
83 return file_handler_extensions_.ContainsExtension(extension_id);
84 }
85
HasIsolatedStorage(const GURL & origin)86 bool ExtensionSpecialStoragePolicy::HasIsolatedStorage(const GURL& origin) {
87 base::AutoLock locker(lock_);
88 return isolated_extensions_.Contains(origin);
89 }
90
NeedsProtection(const extensions::Extension * extension)91 bool ExtensionSpecialStoragePolicy::NeedsProtection(
92 const extensions::Extension* extension) {
93 return extension->is_hosted_app() && !extension->from_bookmark();
94 }
95
96 const extensions::ExtensionSet*
ExtensionsProtectingOrigin(const GURL & origin)97 ExtensionSpecialStoragePolicy::ExtensionsProtectingOrigin(
98 const GURL& origin) {
99 base::AutoLock locker(lock_);
100 return protected_apps_.ExtensionsContaining(origin);
101 }
102
GrantRightsForExtension(const extensions::Extension * extension)103 void ExtensionSpecialStoragePolicy::GrantRightsForExtension(
104 const extensions::Extension* extension) {
105 DCHECK(extension);
106 if (!(NeedsProtection(extension) ||
107 extension->permissions_data()->HasAPIPermission(
108 APIPermission::kUnlimitedStorage) ||
109 extension->permissions_data()->HasAPIPermission(
110 APIPermission::kFileBrowserHandler) ||
111 extensions::AppIsolationInfo::HasIsolatedStorage(extension) ||
112 extension->is_app())) {
113 return;
114 }
115
116 int change_flags = 0;
117 {
118 base::AutoLock locker(lock_);
119 if (NeedsProtection(extension) && protected_apps_.Add(extension))
120 change_flags |= SpecialStoragePolicy::STORAGE_PROTECTED;
121 // FIXME: Does GrantRightsForExtension imply |extension| is installed?
122 if (extension->is_app())
123 installed_apps_.Add(extension);
124
125 if (extension->permissions_data()->HasAPIPermission(
126 APIPermission::kUnlimitedStorage) &&
127 unlimited_extensions_.Add(extension))
128 change_flags |= SpecialStoragePolicy::STORAGE_UNLIMITED;
129
130 if (extension->permissions_data()->HasAPIPermission(
131 APIPermission::kFileBrowserHandler))
132 file_handler_extensions_.Add(extension);
133
134 if (extensions::AppIsolationInfo::HasIsolatedStorage(extension))
135 isolated_extensions_.Add(extension);
136 }
137
138 if (change_flags) {
139 NotifyGranted(Extension::GetBaseURLFromExtensionId(extension->id()),
140 change_flags);
141 }
142 }
143
RevokeRightsForExtension(const extensions::Extension * extension)144 void ExtensionSpecialStoragePolicy::RevokeRightsForExtension(
145 const extensions::Extension* extension) {
146 DCHECK(extension);
147 if (!(NeedsProtection(extension) ||
148 extension->permissions_data()->HasAPIPermission(
149 APIPermission::kUnlimitedStorage) ||
150 extension->permissions_data()->HasAPIPermission(
151 APIPermission::kFileBrowserHandler) ||
152 extensions::AppIsolationInfo::HasIsolatedStorage(extension) ||
153 extension->is_app())) {
154 return;
155 }
156 int change_flags = 0;
157 {
158 base::AutoLock locker(lock_);
159 if (NeedsProtection(extension) && protected_apps_.Remove(extension))
160 change_flags |= SpecialStoragePolicy::STORAGE_PROTECTED;
161
162 if (extension->is_app())
163 installed_apps_.Remove(extension);
164
165 if (extension->permissions_data()->HasAPIPermission(
166 APIPermission::kUnlimitedStorage) &&
167 unlimited_extensions_.Remove(extension))
168 change_flags |= SpecialStoragePolicy::STORAGE_UNLIMITED;
169
170 if (extension->permissions_data()->HasAPIPermission(
171 APIPermission::kFileBrowserHandler))
172 file_handler_extensions_.Remove(extension);
173
174 if (extensions::AppIsolationInfo::HasIsolatedStorage(extension))
175 isolated_extensions_.Remove(extension);
176 }
177
178 if (change_flags) {
179 NotifyRevoked(Extension::GetBaseURLFromExtensionId(extension->id()),
180 change_flags);
181 }
182 }
183
RevokeRightsForAllExtensions()184 void ExtensionSpecialStoragePolicy::RevokeRightsForAllExtensions() {
185 {
186 base::AutoLock locker(lock_);
187 protected_apps_.Clear();
188 installed_apps_.Clear();
189 unlimited_extensions_.Clear();
190 file_handler_extensions_.Clear();
191 isolated_extensions_.Clear();
192 }
193
194 NotifyCleared();
195 }
196
NotifyGranted(const GURL & origin,int change_flags)197 void ExtensionSpecialStoragePolicy::NotifyGranted(
198 const GURL& origin,
199 int change_flags) {
200 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
201 BrowserThread::PostTask(
202 BrowserThread::IO, FROM_HERE,
203 base::Bind(&ExtensionSpecialStoragePolicy::NotifyGranted, this,
204 origin, change_flags));
205 return;
206 }
207 SpecialStoragePolicy::NotifyGranted(origin, change_flags);
208 }
209
NotifyRevoked(const GURL & origin,int change_flags)210 void ExtensionSpecialStoragePolicy::NotifyRevoked(
211 const GURL& origin,
212 int change_flags) {
213 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
214 BrowserThread::PostTask(
215 BrowserThread::IO, FROM_HERE,
216 base::Bind(&ExtensionSpecialStoragePolicy::NotifyRevoked, this,
217 origin, change_flags));
218 return;
219 }
220 SpecialStoragePolicy::NotifyRevoked(origin, change_flags);
221 }
222
NotifyCleared()223 void ExtensionSpecialStoragePolicy::NotifyCleared() {
224 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
225 BrowserThread::PostTask(
226 BrowserThread::IO, FROM_HERE,
227 base::Bind(&ExtensionSpecialStoragePolicy::NotifyCleared, this));
228 return;
229 }
230 SpecialStoragePolicy::NotifyCleared();
231 }
232
233 //-----------------------------------------------------------------------------
234 // SpecialCollection helper class
235 //-----------------------------------------------------------------------------
236
SpecialCollection()237 ExtensionSpecialStoragePolicy::SpecialCollection::SpecialCollection() {}
238
~SpecialCollection()239 ExtensionSpecialStoragePolicy::SpecialCollection::~SpecialCollection() {
240 STLDeleteValues(&cached_results_);
241 }
242
Contains(const GURL & origin)243 bool ExtensionSpecialStoragePolicy::SpecialCollection::Contains(
244 const GURL& origin) {
245 return !ExtensionsContaining(origin)->is_empty();
246 }
247
248 const extensions::ExtensionSet*
ExtensionsContaining(const GURL & origin)249 ExtensionSpecialStoragePolicy::SpecialCollection::ExtensionsContaining(
250 const GURL& origin) {
251 CachedResults::const_iterator found = cached_results_.find(origin);
252 if (found != cached_results_.end())
253 return found->second;
254
255 extensions::ExtensionSet* result = new extensions::ExtensionSet();
256 for (extensions::ExtensionSet::const_iterator iter = extensions_.begin();
257 iter != extensions_.end(); ++iter) {
258 if ((*iter)->OverlapsWithOrigin(origin))
259 result->Insert(*iter);
260 }
261 cached_results_[origin] = result;
262 return result;
263 }
264
ContainsExtension(const std::string & extension_id)265 bool ExtensionSpecialStoragePolicy::SpecialCollection::ContainsExtension(
266 const std::string& extension_id) {
267 return extensions_.Contains(extension_id);
268 }
269
Add(const extensions::Extension * extension)270 bool ExtensionSpecialStoragePolicy::SpecialCollection::Add(
271 const extensions::Extension* extension) {
272 ClearCache();
273 return extensions_.Insert(extension);
274 }
275
Remove(const extensions::Extension * extension)276 bool ExtensionSpecialStoragePolicy::SpecialCollection::Remove(
277 const extensions::Extension* extension) {
278 ClearCache();
279 return extensions_.Remove(extension->id());
280 }
281
Clear()282 void ExtensionSpecialStoragePolicy::SpecialCollection::Clear() {
283 ClearCache();
284 extensions_.Clear();
285 }
286
ClearCache()287 void ExtensionSpecialStoragePolicy::SpecialCollection::ClearCache() {
288 STLDeleteValues(&cached_results_);
289 cached_results_.clear();
290 }
291