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/extensions/manifest_handlers/app_isolation_info.h" 15 #include "chrome/common/url_constants.h" 16 #include "components/content_settings/core/common/content_settings.h" 17 #include "components/content_settings/core/common/content_settings_types.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 storage::SpecialStoragePolicy; 29 30 ExtensionSpecialStoragePolicy::ExtensionSpecialStoragePolicy( 31 CookieSettings* cookie_settings) 32 : cookie_settings_(cookie_settings) {} 33 34 ExtensionSpecialStoragePolicy::~ExtensionSpecialStoragePolicy() {} 35 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 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 55 bool ExtensionSpecialStoragePolicy::IsStorageSessionOnly(const GURL& origin) { 56 if (cookie_settings_.get() == NULL) 57 return false; 58 return cookie_settings_->IsCookieSessionOnly(origin); 59 } 60 61 bool ExtensionSpecialStoragePolicy::CanQueryDiskSize(const GURL& origin) { 62 return installed_apps_.Contains(origin); 63 } 64 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 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 86 bool ExtensionSpecialStoragePolicy::HasIsolatedStorage(const GURL& origin) { 87 base::AutoLock locker(lock_); 88 return isolated_extensions_.Contains(origin); 89 } 90 91 bool ExtensionSpecialStoragePolicy::NeedsProtection( 92 const extensions::Extension* extension) { 93 return extension->is_hosted_app() && !extension->from_bookmark(); 94 } 95 96 const extensions::ExtensionSet* 97 ExtensionSpecialStoragePolicy::ExtensionsProtectingOrigin( 98 const GURL& origin) { 99 base::AutoLock locker(lock_); 100 return protected_apps_.ExtensionsContaining(origin); 101 } 102 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 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 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 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 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 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 237 ExtensionSpecialStoragePolicy::SpecialCollection::SpecialCollection() {} 238 239 ExtensionSpecialStoragePolicy::SpecialCollection::~SpecialCollection() { 240 STLDeleteValues(&cached_results_); 241 } 242 243 bool ExtensionSpecialStoragePolicy::SpecialCollection::Contains( 244 const GURL& origin) { 245 return !ExtensionsContaining(origin)->is_empty(); 246 } 247 248 const extensions::ExtensionSet* 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 265 bool ExtensionSpecialStoragePolicy::SpecialCollection::ContainsExtension( 266 const std::string& extension_id) { 267 return extensions_.Contains(extension_id); 268 } 269 270 bool ExtensionSpecialStoragePolicy::SpecialCollection::Add( 271 const extensions::Extension* extension) { 272 ClearCache(); 273 return extensions_.Insert(extension); 274 } 275 276 bool ExtensionSpecialStoragePolicy::SpecialCollection::Remove( 277 const extensions::Extension* extension) { 278 ClearCache(); 279 return extensions_.Remove(extension->id()); 280 } 281 282 void ExtensionSpecialStoragePolicy::SpecialCollection::Clear() { 283 ClearCache(); 284 extensions_.Clear(); 285 } 286 287 void ExtensionSpecialStoragePolicy::SpecialCollection::ClearCache() { 288 STLDeleteValues(&cached_results_); 289 cached_results_.clear(); 290 } 291