Home | History | Annotate | Download | only in extensions
      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/extension.h"
     17 #include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
     18 #include "chrome/common/url_constants.h"
     19 #include "content/public/browser/browser_thread.h"
     20 #include "extensions/common/constants.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