Home | History | Annotate | Download | only in browsing_data
      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 // Defines the Chrome Extensions BrowsingData API functions, which entail
      6 // clearing browsing data, and clearing the browser's cache (which, let's be
      7 // honest, are the same thing), as specified in the extension API JSON.
      8 
      9 #include "chrome/browser/extensions/api/browsing_data/browsing_data_api.h"
     10 
     11 #include <string>
     12 
     13 #include "base/strings/stringprintf.h"
     14 #include "base/values.h"
     15 #include "chrome/browser/browsing_data/browsing_data_helper.h"
     16 #include "chrome/browser/browsing_data/browsing_data_remover.h"
     17 #include "chrome/browser/plugins/plugin_data_remover_helper.h"
     18 #include "chrome/browser/plugins/plugin_prefs.h"
     19 #include "chrome/browser/profiles/profile.h"
     20 #include "chrome/browser/ui/browser.h"
     21 #include "chrome/common/pref_names.h"
     22 #include "content/public/browser/browser_thread.h"
     23 #include "extensions/common/error_utils.h"
     24 #include "extensions/common/extension.h"
     25 
     26 using content::BrowserThread;
     27 
     28 namespace extension_browsing_data_api_constants {
     29 
     30 // Parameter name keys.
     31 const char kDataRemovalPermittedKey[] = "dataRemovalPermitted";
     32 const char kDataToRemoveKey[] = "dataToRemove";
     33 const char kOptionsKey[] = "options";
     34 
     35 // Type keys.
     36 const char kAppCacheKey[] = "appcache";
     37 const char kCacheKey[] = "cache";
     38 const char kChannelIDsKey[] = "serverBoundCertificates";
     39 const char kCookiesKey[] = "cookies";
     40 const char kDownloadsKey[] = "downloads";
     41 const char kFileSystemsKey[] = "fileSystems";
     42 const char kFormDataKey[] = "formData";
     43 const char kHistoryKey[] = "history";
     44 const char kIndexedDBKey[] = "indexedDB";
     45 const char kLocalStorageKey[] = "localStorage";
     46 const char kPasswordsKey[] = "passwords";
     47 const char kPluginDataKey[] = "pluginData";
     48 const char kServiceWorkersKey[] = "serviceWorkers";
     49 const char kWebSQLKey[] = "webSQL";
     50 
     51 // Option keys.
     52 const char kExtensionsKey[] = "extension";
     53 const char kOriginTypesKey[] = "originTypes";
     54 const char kProtectedWebKey[] = "protectedWeb";
     55 const char kSinceKey[] = "since";
     56 const char kUnprotectedWebKey[] = "unprotectedWeb";
     57 
     58 // Errors!
     59 // The placeholder will be filled by the name of the affected data type (e.g.,
     60 // "history").
     61 const char kBadDataTypeDetails[] = "Invalid value for data type '%s'.";
     62 const char kDeleteProhibitedError[] = "Browsing history and downloads are not "
     63                                       "permitted to be removed.";
     64 const char kOneAtATimeError[] = "Only one 'browsingData' API call can run at "
     65                                 "a time.";
     66 
     67 }  // namespace extension_browsing_data_api_constants
     68 
     69 namespace {
     70 int MaskForKey(const char* key) {
     71   if (strcmp(key, extension_browsing_data_api_constants::kAppCacheKey) == 0)
     72     return BrowsingDataRemover::REMOVE_APPCACHE;
     73   if (strcmp(key, extension_browsing_data_api_constants::kCacheKey) == 0)
     74     return BrowsingDataRemover::REMOVE_CACHE;
     75   if (strcmp(key, extension_browsing_data_api_constants::kCookiesKey) == 0)
     76     return BrowsingDataRemover::REMOVE_COOKIES;
     77   if (strcmp(key, extension_browsing_data_api_constants::kDownloadsKey) == 0)
     78     return BrowsingDataRemover::REMOVE_DOWNLOADS;
     79   if (strcmp(key, extension_browsing_data_api_constants::kFileSystemsKey) == 0)
     80     return BrowsingDataRemover::REMOVE_FILE_SYSTEMS;
     81   if (strcmp(key, extension_browsing_data_api_constants::kFormDataKey) == 0)
     82     return BrowsingDataRemover::REMOVE_FORM_DATA;
     83   if (strcmp(key, extension_browsing_data_api_constants::kHistoryKey) == 0)
     84     return BrowsingDataRemover::REMOVE_HISTORY;
     85   if (strcmp(key, extension_browsing_data_api_constants::kIndexedDBKey) == 0)
     86     return BrowsingDataRemover::REMOVE_INDEXEDDB;
     87   if (strcmp(key, extension_browsing_data_api_constants::kLocalStorageKey) == 0)
     88     return BrowsingDataRemover::REMOVE_LOCAL_STORAGE;
     89   if (strcmp(key,
     90              extension_browsing_data_api_constants::kChannelIDsKey) == 0)
     91     return BrowsingDataRemover::REMOVE_CHANNEL_IDS;
     92   if (strcmp(key, extension_browsing_data_api_constants::kPasswordsKey) == 0)
     93     return BrowsingDataRemover::REMOVE_PASSWORDS;
     94   if (strcmp(key, extension_browsing_data_api_constants::kPluginDataKey) == 0)
     95     return BrowsingDataRemover::REMOVE_PLUGIN_DATA;
     96   if (strcmp(key, extension_browsing_data_api_constants::kServiceWorkersKey) ==
     97       0)
     98     return BrowsingDataRemover::REMOVE_SERVICE_WORKERS;
     99   if (strcmp(key, extension_browsing_data_api_constants::kWebSQLKey) == 0)
    100     return BrowsingDataRemover::REMOVE_WEBSQL;
    101 
    102   return 0;
    103 }
    104 
    105 // Returns false if any of the selected data types are not allowed to be
    106 // deleted.
    107 bool IsRemovalPermitted(int removal_mask, PrefService* prefs) {
    108   // Enterprise policy or user preference might prohibit deleting browser or
    109   // download history.
    110   if ((removal_mask & BrowsingDataRemover::REMOVE_HISTORY) ||
    111       (removal_mask & BrowsingDataRemover::REMOVE_DOWNLOADS)) {
    112     return prefs->GetBoolean(prefs::kAllowDeletingBrowserHistory);
    113   }
    114   return true;
    115 }
    116 
    117 }  // namespace
    118 
    119 bool BrowsingDataSettingsFunction::RunSync() {
    120   PrefService* prefs = GetProfile()->GetPrefs();
    121 
    122   // Fill origin types.
    123   // The "cookies" and "hosted apps" UI checkboxes both map to
    124   // REMOVE_SITE_DATA in browsing_data_remover.h, the former for the unprotected
    125   // web, the latter for  protected web data. There is no UI control for
    126   // extension data.
    127   scoped_ptr<base::DictionaryValue> origin_types(new base::DictionaryValue);
    128   origin_types->SetBoolean(
    129       extension_browsing_data_api_constants::kUnprotectedWebKey,
    130       prefs->GetBoolean(prefs::kDeleteCookies));
    131   origin_types->SetBoolean(
    132       extension_browsing_data_api_constants::kProtectedWebKey,
    133       prefs->GetBoolean(prefs::kDeleteHostedAppsData));
    134   origin_types->SetBoolean(
    135       extension_browsing_data_api_constants::kExtensionsKey, false);
    136 
    137   // Fill deletion time period.
    138   int period_pref = prefs->GetInteger(prefs::kDeleteTimePeriod);
    139   BrowsingDataRemover::TimePeriod period =
    140       static_cast<BrowsingDataRemover::TimePeriod>(period_pref);
    141   double since = 0;
    142   if (period != BrowsingDataRemover::EVERYTHING) {
    143     base::Time time = BrowsingDataRemover::CalculateBeginDeleteTime(period);
    144     since = time.ToJsTime();
    145   }
    146 
    147   scoped_ptr<base::DictionaryValue> options(new base::DictionaryValue);
    148   options->Set(extension_browsing_data_api_constants::kOriginTypesKey,
    149                origin_types.release());
    150   options->SetDouble(extension_browsing_data_api_constants::kSinceKey, since);
    151 
    152   // Fill dataToRemove and dataRemovalPermitted.
    153   scoped_ptr<base::DictionaryValue> selected(new base::DictionaryValue);
    154   scoped_ptr<base::DictionaryValue> permitted(new base::DictionaryValue);
    155 
    156   bool delete_site_data = prefs->GetBoolean(prefs::kDeleteCookies) ||
    157                           prefs->GetBoolean(prefs::kDeleteHostedAppsData);
    158 
    159   SetDetails(selected.get(), permitted.get(),
    160              extension_browsing_data_api_constants::kAppCacheKey,
    161              delete_site_data);
    162   SetDetails(selected.get(), permitted.get(),
    163              extension_browsing_data_api_constants::kCookiesKey,
    164              delete_site_data);
    165   SetDetails(selected.get(), permitted.get(),
    166              extension_browsing_data_api_constants::kFileSystemsKey,
    167              delete_site_data);
    168   SetDetails(selected.get(), permitted.get(),
    169              extension_browsing_data_api_constants::kIndexedDBKey,
    170              delete_site_data);
    171   SetDetails(selected.get(), permitted.get(),
    172       extension_browsing_data_api_constants::kLocalStorageKey,
    173       delete_site_data);
    174   SetDetails(selected.get(), permitted.get(),
    175              extension_browsing_data_api_constants::kWebSQLKey,
    176              delete_site_data);
    177   SetDetails(selected.get(), permitted.get(),
    178       extension_browsing_data_api_constants::kChannelIDsKey,
    179       delete_site_data);
    180   SetDetails(selected.get(), permitted.get(),
    181              extension_browsing_data_api_constants::kServiceWorkersKey,
    182              delete_site_data);
    183 
    184   SetDetails(selected.get(), permitted.get(),
    185       extension_browsing_data_api_constants::kPluginDataKey,
    186       delete_site_data && prefs->GetBoolean(prefs::kClearPluginLSODataEnabled));
    187 
    188   SetDetails(selected.get(), permitted.get(),
    189              extension_browsing_data_api_constants::kHistoryKey,
    190              prefs->GetBoolean(prefs::kDeleteBrowsingHistory));
    191   SetDetails(selected.get(), permitted.get(),
    192              extension_browsing_data_api_constants::kDownloadsKey,
    193              prefs->GetBoolean(prefs::kDeleteDownloadHistory));
    194   SetDetails(selected.get(), permitted.get(),
    195              extension_browsing_data_api_constants::kCacheKey,
    196              prefs->GetBoolean(prefs::kDeleteCache));
    197   SetDetails(selected.get(), permitted.get(),
    198              extension_browsing_data_api_constants::kFormDataKey,
    199              prefs->GetBoolean(prefs::kDeleteFormData));
    200   SetDetails(selected.get(), permitted.get(),
    201              extension_browsing_data_api_constants::kPasswordsKey,
    202              prefs->GetBoolean(prefs::kDeletePasswords));
    203 
    204   scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
    205   result->Set(extension_browsing_data_api_constants::kOptionsKey,
    206               options.release());
    207   result->Set(extension_browsing_data_api_constants::kDataToRemoveKey,
    208               selected.release());
    209   result->Set(extension_browsing_data_api_constants::kDataRemovalPermittedKey,
    210               permitted.release());
    211   SetResult(result.release());
    212   return true;
    213 }
    214 
    215 void BrowsingDataSettingsFunction::SetDetails(
    216     base::DictionaryValue* selected_dict,
    217     base::DictionaryValue* permitted_dict,
    218     const char* data_type,
    219     bool is_selected) {
    220   bool is_permitted =
    221       IsRemovalPermitted(MaskForKey(data_type), GetProfile()->GetPrefs());
    222   selected_dict->SetBoolean(data_type, is_selected && is_permitted);
    223   permitted_dict->SetBoolean(data_type, is_permitted);
    224 }
    225 
    226 void BrowsingDataRemoverFunction::OnBrowsingDataRemoverDone() {
    227   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    228   this->SendResponse(true);
    229 
    230   Release();  // Balanced in RunAsync.
    231 }
    232 
    233 bool BrowsingDataRemoverFunction::RunAsync() {
    234   // If we don't have a profile, something's pretty wrong.
    235   DCHECK(GetProfile());
    236 
    237   // Grab the initial |options| parameter, and parse out the arguments.
    238   base::DictionaryValue* options;
    239   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options));
    240   DCHECK(options);
    241 
    242   origin_set_mask_ = ParseOriginSetMask(*options);
    243 
    244   // If |ms_since_epoch| isn't set, default it to 0.
    245   double ms_since_epoch;
    246   if (!options->GetDouble(extension_browsing_data_api_constants::kSinceKey,
    247                           &ms_since_epoch))
    248     ms_since_epoch = 0;
    249 
    250   // base::Time takes a double that represents seconds since epoch. JavaScript
    251   // gives developers milliseconds, so do a quick conversion before populating
    252   // the object. Also, Time::FromDoubleT converts double time 0 to empty Time
    253   // object. So we need to do special handling here.
    254   remove_since_ = (ms_since_epoch == 0) ?
    255       base::Time::UnixEpoch() :
    256       base::Time::FromDoubleT(ms_since_epoch / 1000.0);
    257 
    258   removal_mask_ = GetRemovalMask();
    259   if (bad_message_)
    260     return false;
    261 
    262   // Check for prohibited data types.
    263   if (!IsRemovalPermitted(removal_mask_, GetProfile()->GetPrefs())) {
    264     error_ = extension_browsing_data_api_constants::kDeleteProhibitedError;
    265     return false;
    266   }
    267 
    268   if (removal_mask_ & BrowsingDataRemover::REMOVE_PLUGIN_DATA) {
    269     // If we're being asked to remove plugin data, check whether it's actually
    270     // supported.
    271     BrowserThread::PostTask(
    272         BrowserThread::FILE,
    273         FROM_HERE,
    274         base::Bind(
    275             &BrowsingDataRemoverFunction::CheckRemovingPluginDataSupported,
    276             this,
    277             PluginPrefs::GetForProfile(GetProfile())));
    278   } else {
    279     StartRemoving();
    280   }
    281 
    282   // Will finish asynchronously.
    283   return true;
    284 }
    285 
    286 void BrowsingDataRemoverFunction::CheckRemovingPluginDataSupported(
    287     scoped_refptr<PluginPrefs> plugin_prefs) {
    288   if (!PluginDataRemoverHelper::IsSupported(plugin_prefs.get()))
    289     removal_mask_ &= ~BrowsingDataRemover::REMOVE_PLUGIN_DATA;
    290 
    291   BrowserThread::PostTask(
    292       BrowserThread::UI, FROM_HERE,
    293       base::Bind(&BrowsingDataRemoverFunction::StartRemoving, this));
    294 }
    295 
    296 void BrowsingDataRemoverFunction::StartRemoving() {
    297   if (BrowsingDataRemover::is_removing()) {
    298     error_ = extension_browsing_data_api_constants::kOneAtATimeError;
    299     SendResponse(false);
    300     return;
    301   }
    302 
    303   // If we're good to go, add a ref (Balanced in OnBrowsingDataRemoverDone)
    304   AddRef();
    305 
    306   // Create a BrowsingDataRemover, set the current object as an observer (so
    307   // that we're notified after removal) and call remove() with the arguments
    308   // we've generated above. We can use a raw pointer here, as the browsing data
    309   // remover is responsible for deleting itself once data removal is complete.
    310   BrowsingDataRemover* remover = BrowsingDataRemover::CreateForRange(
    311       GetProfile(), remove_since_, base::Time::Max());
    312   remover->AddObserver(this);
    313   remover->Remove(removal_mask_, origin_set_mask_);
    314 }
    315 
    316 int BrowsingDataRemoverFunction::ParseOriginSetMask(
    317     const base::DictionaryValue& options) {
    318   // Parse the |options| dictionary to generate the origin set mask. Default to
    319   // UNPROTECTED_WEB if the developer doesn't specify anything.
    320   int mask = BrowsingDataHelper::UNPROTECTED_WEB;
    321 
    322   const base::DictionaryValue* d = NULL;
    323   if (options.HasKey(extension_browsing_data_api_constants::kOriginTypesKey)) {
    324     EXTENSION_FUNCTION_VALIDATE(options.GetDictionary(
    325         extension_browsing_data_api_constants::kOriginTypesKey, &d));
    326     bool value;
    327 
    328     // The developer specified something! Reset to 0 and parse the dictionary.
    329     mask = 0;
    330 
    331     // Unprotected web.
    332     if (d->HasKey(extension_browsing_data_api_constants::kUnprotectedWebKey)) {
    333       EXTENSION_FUNCTION_VALIDATE(d->GetBoolean(
    334           extension_browsing_data_api_constants::kUnprotectedWebKey, &value));
    335       mask |= value ? BrowsingDataHelper::UNPROTECTED_WEB : 0;
    336     }
    337 
    338     // Protected web.
    339     if (d->HasKey(extension_browsing_data_api_constants::kProtectedWebKey)) {
    340       EXTENSION_FUNCTION_VALIDATE(d->GetBoolean(
    341           extension_browsing_data_api_constants::kProtectedWebKey, &value));
    342       mask |= value ? BrowsingDataHelper::PROTECTED_WEB : 0;
    343     }
    344 
    345     // Extensions.
    346     if (d->HasKey(extension_browsing_data_api_constants::kExtensionsKey)) {
    347       EXTENSION_FUNCTION_VALIDATE(d->GetBoolean(
    348           extension_browsing_data_api_constants::kExtensionsKey, &value));
    349       mask |= value ? BrowsingDataHelper::EXTENSION : 0;
    350     }
    351   }
    352 
    353   return mask;
    354 }
    355 
    356 // Parses the |dataToRemove| argument to generate the removal mask. Sets
    357 // |bad_message_| (like EXTENSION_FUNCTION_VALIDATE would if this were a bool
    358 // method) if 'dataToRemove' is not present or any data-type keys don't have
    359 // supported (boolean) values.
    360 int BrowsingDataRemoveFunction::GetRemovalMask() {
    361   base::DictionaryValue* data_to_remove;
    362   if (!args_->GetDictionary(1, &data_to_remove)) {
    363     bad_message_ = true;
    364     return 0;
    365   }
    366 
    367   int removal_mask = 0;
    368 
    369   for (base::DictionaryValue::Iterator i(*data_to_remove);
    370        !i.IsAtEnd();
    371        i.Advance()) {
    372     bool selected = false;
    373     if (!i.value().GetAsBoolean(&selected)) {
    374       bad_message_ = true;
    375       return 0;
    376     }
    377     if (selected)
    378       removal_mask |= MaskForKey(i.key().c_str());
    379   }
    380 
    381   return removal_mask;
    382 }
    383 
    384 int BrowsingDataRemoveAppcacheFunction::GetRemovalMask() {
    385   return BrowsingDataRemover::REMOVE_APPCACHE;
    386 }
    387 
    388 int BrowsingDataRemoveCacheFunction::GetRemovalMask() {
    389   return BrowsingDataRemover::REMOVE_CACHE;
    390 }
    391 
    392 int BrowsingDataRemoveCookiesFunction::GetRemovalMask() {
    393   return BrowsingDataRemover::REMOVE_COOKIES |
    394          BrowsingDataRemover::REMOVE_CHANNEL_IDS;
    395 }
    396 
    397 int BrowsingDataRemoveDownloadsFunction::GetRemovalMask() {
    398   return BrowsingDataRemover::REMOVE_DOWNLOADS;
    399 }
    400 
    401 int BrowsingDataRemoveFileSystemsFunction::GetRemovalMask() {
    402   return BrowsingDataRemover::REMOVE_FILE_SYSTEMS;
    403 }
    404 
    405 int BrowsingDataRemoveFormDataFunction::GetRemovalMask() {
    406   return BrowsingDataRemover::REMOVE_FORM_DATA;
    407 }
    408 
    409 int BrowsingDataRemoveHistoryFunction::GetRemovalMask() {
    410   return BrowsingDataRemover::REMOVE_HISTORY;
    411 }
    412 
    413 int BrowsingDataRemoveIndexedDBFunction::GetRemovalMask() {
    414   return BrowsingDataRemover::REMOVE_INDEXEDDB;
    415 }
    416 
    417 int BrowsingDataRemoveLocalStorageFunction::GetRemovalMask() {
    418   return BrowsingDataRemover::REMOVE_LOCAL_STORAGE;
    419 }
    420 
    421 int BrowsingDataRemovePluginDataFunction::GetRemovalMask() {
    422   return BrowsingDataRemover::REMOVE_PLUGIN_DATA;
    423 }
    424 
    425 int BrowsingDataRemovePasswordsFunction::GetRemovalMask() {
    426   return BrowsingDataRemover::REMOVE_PASSWORDS;
    427 }
    428 
    429 int BrowsingDataRemoveServiceWorkersFunction::GetRemovalMask() {
    430   return BrowsingDataRemover::REMOVE_SERVICE_WORKERS;
    431 }
    432 
    433 int BrowsingDataRemoveWebSQLFunction::GetRemovalMask() {
    434   return BrowsingDataRemover::REMOVE_WEBSQL;
    435 }
    436