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.
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.
9 #include "chrome/browser/extensions/api/browsing_data/browsing_data_api.h"
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"
26 using content::BrowserThread
;
28 namespace extension_browsing_data_api_constants
{
30 // Parameter name keys.
31 const char kDataRemovalPermittedKey
[] = "dataRemovalPermitted";
32 const char kDataToRemoveKey
[] = "dataToRemove";
33 const char kOptionsKey
[] = "options";
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 kCacheStorageKey
[] = "cacheStorage";
50 const char kWebSQLKey
[] = "webSQL";
53 const char kExtensionsKey
[] = "extension";
54 const char kOriginTypesKey
[] = "originTypes";
55 const char kProtectedWebKey
[] = "protectedWeb";
56 const char kSinceKey
[] = "since";
57 const char kUnprotectedWebKey
[] = "unprotectedWeb";
60 // The placeholder will be filled by the name of the affected data type (e.g.,
62 const char kBadDataTypeDetails
[] = "Invalid value for data type '%s'.";
63 const char kDeleteProhibitedError
[] = "Browsing history and downloads are not "
64 "permitted to be removed.";
65 const char kOneAtATimeError
[] = "Only one 'browsingData' API call can run at "
68 } // namespace extension_browsing_data_api_constants
71 int MaskForKey(const char* key
) {
72 if (strcmp(key
, extension_browsing_data_api_constants::kAppCacheKey
) == 0)
73 return BrowsingDataRemover::REMOVE_APPCACHE
;
74 if (strcmp(key
, extension_browsing_data_api_constants::kCacheKey
) == 0)
75 return BrowsingDataRemover::REMOVE_CACHE
;
76 if (strcmp(key
, extension_browsing_data_api_constants::kCookiesKey
) == 0) {
77 return BrowsingDataRemover::REMOVE_COOKIES
|
78 BrowsingDataRemover::REMOVE_WEBRTC_IDENTITY
;
80 if (strcmp(key
, extension_browsing_data_api_constants::kDownloadsKey
) == 0)
81 return BrowsingDataRemover::REMOVE_DOWNLOADS
;
82 if (strcmp(key
, extension_browsing_data_api_constants::kFileSystemsKey
) == 0)
83 return BrowsingDataRemover::REMOVE_FILE_SYSTEMS
;
84 if (strcmp(key
, extension_browsing_data_api_constants::kFormDataKey
) == 0)
85 return BrowsingDataRemover::REMOVE_FORM_DATA
;
86 if (strcmp(key
, extension_browsing_data_api_constants::kHistoryKey
) == 0)
87 return BrowsingDataRemover::REMOVE_HISTORY
;
88 if (strcmp(key
, extension_browsing_data_api_constants::kIndexedDBKey
) == 0)
89 return BrowsingDataRemover::REMOVE_INDEXEDDB
;
90 if (strcmp(key
, extension_browsing_data_api_constants::kLocalStorageKey
) == 0)
91 return BrowsingDataRemover::REMOVE_LOCAL_STORAGE
;
93 extension_browsing_data_api_constants::kChannelIDsKey
) == 0)
94 return BrowsingDataRemover::REMOVE_CHANNEL_IDS
;
95 if (strcmp(key
, extension_browsing_data_api_constants::kPasswordsKey
) == 0)
96 return BrowsingDataRemover::REMOVE_PASSWORDS
;
97 if (strcmp(key
, extension_browsing_data_api_constants::kPluginDataKey
) == 0)
98 return BrowsingDataRemover::REMOVE_PLUGIN_DATA
;
99 if (strcmp(key
, extension_browsing_data_api_constants::kServiceWorkersKey
) ==
101 return BrowsingDataRemover::REMOVE_SERVICE_WORKERS
;
102 if (strcmp(key
, extension_browsing_data_api_constants::kCacheStorageKey
) == 0)
103 return BrowsingDataRemover::REMOVE_CACHE_STORAGE
;
104 if (strcmp(key
, extension_browsing_data_api_constants::kWebSQLKey
) == 0)
105 return BrowsingDataRemover::REMOVE_WEBSQL
;
110 // Returns false if any of the selected data types are not allowed to be
112 bool IsRemovalPermitted(int removal_mask
, PrefService
* prefs
) {
113 // Enterprise policy or user preference might prohibit deleting browser or
115 if ((removal_mask
& BrowsingDataRemover::REMOVE_HISTORY
) ||
116 (removal_mask
& BrowsingDataRemover::REMOVE_DOWNLOADS
)) {
117 return prefs
->GetBoolean(prefs::kAllowDeletingBrowserHistory
);
124 bool BrowsingDataSettingsFunction::RunSync() {
125 PrefService
* prefs
= GetProfile()->GetPrefs();
127 // Fill origin types.
128 // The "cookies" and "hosted apps" UI checkboxes both map to
129 // REMOVE_SITE_DATA in browsing_data_remover.h, the former for the unprotected
130 // web, the latter for protected web data. There is no UI control for
132 scoped_ptr
<base::DictionaryValue
> origin_types(new base::DictionaryValue
);
133 origin_types
->SetBoolean(
134 extension_browsing_data_api_constants::kUnprotectedWebKey
,
135 prefs
->GetBoolean(prefs::kDeleteCookies
));
136 origin_types
->SetBoolean(
137 extension_browsing_data_api_constants::kProtectedWebKey
,
138 prefs
->GetBoolean(prefs::kDeleteHostedAppsData
));
139 origin_types
->SetBoolean(
140 extension_browsing_data_api_constants::kExtensionsKey
, false);
142 // Fill deletion time period.
143 int period_pref
= prefs
->GetInteger(prefs::kDeleteTimePeriod
);
144 BrowsingDataRemover::TimePeriod period
=
145 static_cast<BrowsingDataRemover::TimePeriod
>(period_pref
);
147 if (period
!= BrowsingDataRemover::EVERYTHING
) {
148 base::Time time
= BrowsingDataRemover::CalculateBeginDeleteTime(period
);
149 since
= time
.ToJsTime();
152 scoped_ptr
<base::DictionaryValue
> options(new base::DictionaryValue
);
153 options
->Set(extension_browsing_data_api_constants::kOriginTypesKey
,
154 origin_types
.release());
155 options
->SetDouble(extension_browsing_data_api_constants::kSinceKey
, since
);
157 // Fill dataToRemove and dataRemovalPermitted.
158 scoped_ptr
<base::DictionaryValue
> selected(new base::DictionaryValue
);
159 scoped_ptr
<base::DictionaryValue
> permitted(new base::DictionaryValue
);
161 bool delete_site_data
= prefs
->GetBoolean(prefs::kDeleteCookies
) ||
162 prefs
->GetBoolean(prefs::kDeleteHostedAppsData
);
164 SetDetails(selected
.get(), permitted
.get(),
165 extension_browsing_data_api_constants::kAppCacheKey
,
167 SetDetails(selected
.get(), permitted
.get(),
168 extension_browsing_data_api_constants::kCookiesKey
,
170 SetDetails(selected
.get(), permitted
.get(),
171 extension_browsing_data_api_constants::kFileSystemsKey
,
173 SetDetails(selected
.get(), permitted
.get(),
174 extension_browsing_data_api_constants::kIndexedDBKey
,
176 SetDetails(selected
.get(), permitted
.get(),
177 extension_browsing_data_api_constants::kLocalStorageKey
,
179 SetDetails(selected
.get(), permitted
.get(),
180 extension_browsing_data_api_constants::kWebSQLKey
,
182 SetDetails(selected
.get(), permitted
.get(),
183 extension_browsing_data_api_constants::kChannelIDsKey
,
185 SetDetails(selected
.get(), permitted
.get(),
186 extension_browsing_data_api_constants::kServiceWorkersKey
,
188 SetDetails(selected
.get(), permitted
.get(),
189 extension_browsing_data_api_constants::kCacheStorageKey
,
192 SetDetails(selected
.get(), permitted
.get(),
193 extension_browsing_data_api_constants::kPluginDataKey
,
194 delete_site_data
&& prefs
->GetBoolean(prefs::kClearPluginLSODataEnabled
));
196 SetDetails(selected
.get(), permitted
.get(),
197 extension_browsing_data_api_constants::kHistoryKey
,
198 prefs
->GetBoolean(prefs::kDeleteBrowsingHistory
));
199 SetDetails(selected
.get(), permitted
.get(),
200 extension_browsing_data_api_constants::kDownloadsKey
,
201 prefs
->GetBoolean(prefs::kDeleteDownloadHistory
));
202 SetDetails(selected
.get(), permitted
.get(),
203 extension_browsing_data_api_constants::kCacheKey
,
204 prefs
->GetBoolean(prefs::kDeleteCache
));
205 SetDetails(selected
.get(), permitted
.get(),
206 extension_browsing_data_api_constants::kFormDataKey
,
207 prefs
->GetBoolean(prefs::kDeleteFormData
));
208 SetDetails(selected
.get(), permitted
.get(),
209 extension_browsing_data_api_constants::kPasswordsKey
,
210 prefs
->GetBoolean(prefs::kDeletePasswords
));
212 scoped_ptr
<base::DictionaryValue
> result(new base::DictionaryValue
);
213 result
->Set(extension_browsing_data_api_constants::kOptionsKey
,
215 result
->Set(extension_browsing_data_api_constants::kDataToRemoveKey
,
217 result
->Set(extension_browsing_data_api_constants::kDataRemovalPermittedKey
,
218 permitted
.release());
219 SetResult(result
.release());
223 void BrowsingDataSettingsFunction::SetDetails(
224 base::DictionaryValue
* selected_dict
,
225 base::DictionaryValue
* permitted_dict
,
226 const char* data_type
,
229 IsRemovalPermitted(MaskForKey(data_type
), GetProfile()->GetPrefs());
230 selected_dict
->SetBoolean(data_type
, is_selected
&& is_permitted
);
231 permitted_dict
->SetBoolean(data_type
, is_permitted
);
234 void BrowsingDataRemoverFunction::OnBrowsingDataRemoverDone() {
235 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
236 this->SendResponse(true);
238 Release(); // Balanced in RunAsync.
241 bool BrowsingDataRemoverFunction::RunAsync() {
242 // If we don't have a profile, something's pretty wrong.
243 DCHECK(GetProfile());
245 // Grab the initial |options| parameter, and parse out the arguments.
246 base::DictionaryValue
* options
;
247 EXTENSION_FUNCTION_VALIDATE(args_
->GetDictionary(0, &options
));
250 origin_type_mask_
= ParseOriginTypeMask(*options
);
252 // If |ms_since_epoch| isn't set, default it to 0.
253 double ms_since_epoch
;
254 if (!options
->GetDouble(extension_browsing_data_api_constants::kSinceKey
,
258 // base::Time takes a double that represents seconds since epoch. JavaScript
259 // gives developers milliseconds, so do a quick conversion before populating
260 // the object. Also, Time::FromDoubleT converts double time 0 to empty Time
261 // object. So we need to do special handling here.
262 remove_since_
= (ms_since_epoch
== 0) ?
263 base::Time::UnixEpoch() :
264 base::Time::FromDoubleT(ms_since_epoch
/ 1000.0);
266 removal_mask_
= GetRemovalMask();
270 // Check for prohibited data types.
271 if (!IsRemovalPermitted(removal_mask_
, GetProfile()->GetPrefs())) {
272 error_
= extension_browsing_data_api_constants::kDeleteProhibitedError
;
276 if (removal_mask_
& BrowsingDataRemover::REMOVE_PLUGIN_DATA
) {
277 // If we're being asked to remove plugin data, check whether it's actually
279 BrowserThread::PostTask(
283 &BrowsingDataRemoverFunction::CheckRemovingPluginDataSupported
,
285 PluginPrefs::GetForProfile(GetProfile())));
290 // Will finish asynchronously.
294 void BrowsingDataRemoverFunction::CheckRemovingPluginDataSupported(
295 scoped_refptr
<PluginPrefs
> plugin_prefs
) {
296 if (!PluginDataRemoverHelper::IsSupported(plugin_prefs
.get()))
297 removal_mask_
&= ~BrowsingDataRemover::REMOVE_PLUGIN_DATA
;
299 BrowserThread::PostTask(
300 BrowserThread::UI
, FROM_HERE
,
301 base::Bind(&BrowsingDataRemoverFunction::StartRemoving
, this));
304 void BrowsingDataRemoverFunction::StartRemoving() {
305 if (BrowsingDataRemover::is_removing()) {
306 error_
= extension_browsing_data_api_constants::kOneAtATimeError
;
311 // If we're good to go, add a ref (Balanced in OnBrowsingDataRemoverDone)
314 // Create a BrowsingDataRemover, set the current object as an observer (so
315 // that we're notified after removal) and call remove() with the arguments
316 // we've generated above. We can use a raw pointer here, as the browsing data
317 // remover is responsible for deleting itself once data removal is complete.
318 BrowsingDataRemover
* remover
= BrowsingDataRemover::CreateForRange(
319 GetProfile(), remove_since_
, base::Time::Max());
320 remover
->AddObserver(this);
321 remover
->Remove(removal_mask_
, origin_type_mask_
);
324 int BrowsingDataRemoverFunction::ParseOriginTypeMask(
325 const base::DictionaryValue
& options
) {
326 // Parse the |options| dictionary to generate the origin set mask. Default to
327 // UNPROTECTED_WEB if the developer doesn't specify anything.
328 int mask
= BrowsingDataHelper::UNPROTECTED_WEB
;
330 const base::DictionaryValue
* d
= NULL
;
331 if (options
.HasKey(extension_browsing_data_api_constants::kOriginTypesKey
)) {
332 EXTENSION_FUNCTION_VALIDATE(options
.GetDictionary(
333 extension_browsing_data_api_constants::kOriginTypesKey
, &d
));
336 // The developer specified something! Reset to 0 and parse the dictionary.
340 if (d
->HasKey(extension_browsing_data_api_constants::kUnprotectedWebKey
)) {
341 EXTENSION_FUNCTION_VALIDATE(d
->GetBoolean(
342 extension_browsing_data_api_constants::kUnprotectedWebKey
, &value
));
343 mask
|= value
? BrowsingDataHelper::UNPROTECTED_WEB
: 0;
347 if (d
->HasKey(extension_browsing_data_api_constants::kProtectedWebKey
)) {
348 EXTENSION_FUNCTION_VALIDATE(d
->GetBoolean(
349 extension_browsing_data_api_constants::kProtectedWebKey
, &value
));
350 mask
|= value
? BrowsingDataHelper::PROTECTED_WEB
: 0;
354 if (d
->HasKey(extension_browsing_data_api_constants::kExtensionsKey
)) {
355 EXTENSION_FUNCTION_VALIDATE(d
->GetBoolean(
356 extension_browsing_data_api_constants::kExtensionsKey
, &value
));
357 mask
|= value
? BrowsingDataHelper::EXTENSION
: 0;
364 // Parses the |dataToRemove| argument to generate the removal mask. Sets
365 // |bad_message_| (like EXTENSION_FUNCTION_VALIDATE would if this were a bool
366 // method) if 'dataToRemove' is not present or any data-type keys don't have
367 // supported (boolean) values.
368 int BrowsingDataRemoveFunction::GetRemovalMask() {
369 base::DictionaryValue
* data_to_remove
;
370 if (!args_
->GetDictionary(1, &data_to_remove
)) {
375 int removal_mask
= 0;
377 for (base::DictionaryValue::Iterator
i(*data_to_remove
);
380 bool selected
= false;
381 if (!i
.value().GetAsBoolean(&selected
)) {
386 removal_mask
|= MaskForKey(i
.key().c_str());
392 int BrowsingDataRemoveAppcacheFunction::GetRemovalMask() {
393 return BrowsingDataRemover::REMOVE_APPCACHE
;
396 int BrowsingDataRemoveCacheFunction::GetRemovalMask() {
397 return BrowsingDataRemover::REMOVE_CACHE
;
400 int BrowsingDataRemoveCookiesFunction::GetRemovalMask() {
401 return BrowsingDataRemover::REMOVE_COOKIES
|
402 BrowsingDataRemover::REMOVE_CHANNEL_IDS
|
403 BrowsingDataRemover::REMOVE_WEBRTC_IDENTITY
;
406 int BrowsingDataRemoveDownloadsFunction::GetRemovalMask() {
407 return BrowsingDataRemover::REMOVE_DOWNLOADS
;
410 int BrowsingDataRemoveFileSystemsFunction::GetRemovalMask() {
411 return BrowsingDataRemover::REMOVE_FILE_SYSTEMS
;
414 int BrowsingDataRemoveFormDataFunction::GetRemovalMask() {
415 return BrowsingDataRemover::REMOVE_FORM_DATA
;
418 int BrowsingDataRemoveHistoryFunction::GetRemovalMask() {
419 return BrowsingDataRemover::REMOVE_HISTORY
;
422 int BrowsingDataRemoveIndexedDBFunction::GetRemovalMask() {
423 return BrowsingDataRemover::REMOVE_INDEXEDDB
;
426 int BrowsingDataRemoveLocalStorageFunction::GetRemovalMask() {
427 return BrowsingDataRemover::REMOVE_LOCAL_STORAGE
;
430 int BrowsingDataRemovePluginDataFunction::GetRemovalMask() {
431 return BrowsingDataRemover::REMOVE_PLUGIN_DATA
;
434 int BrowsingDataRemovePasswordsFunction::GetRemovalMask() {
435 return BrowsingDataRemover::REMOVE_PASSWORDS
;
438 int BrowsingDataRemoveServiceWorkersFunction::GetRemovalMask() {
439 return BrowsingDataRemover::REMOVE_SERVICE_WORKERS
;
442 int BrowsingDataRemoveCacheStorageFunction::GetRemovalMask() {
443 return BrowsingDataRemover::REMOVE_CACHE_STORAGE
;
446 int BrowsingDataRemoveWebSQLFunction::GetRemovalMask() {
447 return BrowsingDataRemover::REMOVE_WEBSQL
;