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