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/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