• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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