- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / browsing_data / browsing_data_api.cc
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/extensions/extension.h"
22 #include "chrome/common/pref_names.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "extensions/common/error_utils.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 }