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