1 // Copyright 2016 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 "components/browsing_data/core/browsing_data_utils.h"
6 
7 #include <string>
8 #include <vector>
9 
10 #include "base/macros.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/metrics/user_metrics.h"
13 #include "base/no_destructor.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "components/browsing_data/core/counters/autofill_counter.h"
16 #include "components/browsing_data/core/counters/history_counter.h"
17 #include "components/browsing_data/core/counters/passwords_counter.h"
18 #include "components/browsing_data/core/pref_names.h"
19 #include "components/prefs/pref_service.h"
20 #include "components/strings/grit/components_strings.h"
21 #include "ui/base/l10n/l10n_util.h"
22 
23 namespace browsing_data {
24 
25 // Creates a string like "for a.com, b.com, and 4 more".
CreateDomainExamples(int password_count,const std::vector<std::string> domain_examples)26 base::string16 CreateDomainExamples(
27     int password_count,
28     const std::vector<std::string> domain_examples) {
29   DCHECK_GE(password_count,
30             base::checked_cast<browsing_data::BrowsingDataCounter::ResultInt>(
31                 domain_examples.size()));
32   DCHECK_EQ(domain_examples.empty(), password_count == 0);
33   std::vector<base::string16> replacements;
34 
35   replacements.emplace_back(base::UTF8ToUTF16(domain_examples[0]));
36   if (domain_examples.size() > 1) {
37     replacements.emplace_back(base::UTF8ToUTF16(domain_examples[1]));
38   }
39   if (password_count > 2 && domain_examples.size() > 1) {
40     replacements.emplace_back(l10n_util::GetPluralStringFUTF16(
41         IDS_DEL_PASSWORDS_COUNTER_AND_X_MORE, password_count - 2));
42   }
43   base::string16 domains_list = base::ReplaceStringPlaceholders(
44       l10n_util::GetPluralStringFUTF16(IDS_DEL_PASSWORDS_DOMAINS_DISPLAY,
45                                        (domain_examples.size() > 1)
46                                            ? password_count
47                                            : domain_examples.size()),
48       replacements, nullptr);
49   return domains_list;
50 }
51 
CalculateBeginDeleteTime(TimePeriod time_period)52 base::Time CalculateBeginDeleteTime(TimePeriod time_period) {
53   base::TimeDelta diff;
54   base::Time delete_begin_time = base::Time::Now();
55   switch (time_period) {
56     case TimePeriod::LAST_HOUR:
57       diff = base::TimeDelta::FromHours(1);
58       break;
59     case TimePeriod::LAST_DAY:
60       diff = base::TimeDelta::FromHours(24);
61       break;
62     case TimePeriod::LAST_WEEK:
63       diff = base::TimeDelta::FromHours(7 * 24);
64       break;
65     case TimePeriod::FOUR_WEEKS:
66       diff = base::TimeDelta::FromHours(4 * 7 * 24);
67       break;
68     case TimePeriod::ALL_TIME:
69     case TimePeriod::OLDER_THAN_30_DAYS:
70       delete_begin_time = base::Time();
71       break;
72   }
73   return delete_begin_time - diff;
74 }
75 
CalculateEndDeleteTime(TimePeriod time_period)76 base::Time CalculateEndDeleteTime(TimePeriod time_period) {
77   if (time_period == TimePeriod::OLDER_THAN_30_DAYS) {
78     return base::Time::Now() - base::TimeDelta::FromDays(30);
79   }
80   return base::Time::Max();
81 }
82 
RecordDeletionForPeriod(TimePeriod period)83 void RecordDeletionForPeriod(TimePeriod period) {
84   switch (period) {
85     case TimePeriod::LAST_HOUR:
86       base::RecordAction(base::UserMetricsAction("ClearBrowsingData_LastHour"));
87       break;
88     case TimePeriod::LAST_DAY:
89       base::RecordAction(base::UserMetricsAction("ClearBrowsingData_LastDay"));
90       break;
91     case TimePeriod::LAST_WEEK:
92       base::RecordAction(base::UserMetricsAction("ClearBrowsingData_LastWeek"));
93       break;
94     case TimePeriod::FOUR_WEEKS:
95       base::RecordAction(
96           base::UserMetricsAction("ClearBrowsingData_LastMonth"));
97       break;
98     case TimePeriod::ALL_TIME:
99       base::RecordAction(
100           base::UserMetricsAction("ClearBrowsingData_Everything"));
101       break;
102     case TimePeriod::OLDER_THAN_30_DAYS:
103       base::RecordAction(
104           base::UserMetricsAction("ClearBrowsingData_OlderThan30Days"));
105       break;
106   }
107 }
108 
RecordTimePeriodChange(TimePeriod period)109 void RecordTimePeriodChange(TimePeriod period) {
110   switch (period) {
111     case TimePeriod::LAST_HOUR:
112       base::RecordAction(base::UserMetricsAction(
113           "ClearBrowsingData_TimePeriodChanged_LastHour"));
114       break;
115     case TimePeriod::LAST_DAY:
116       base::RecordAction(base::UserMetricsAction(
117           "ClearBrowsingData_TimePeriodChanged_LastDay"));
118       break;
119     case TimePeriod::LAST_WEEK:
120       base::RecordAction(base::UserMetricsAction(
121           "ClearBrowsingData_TimePeriodChanged_LastWeek"));
122       break;
123     case TimePeriod::FOUR_WEEKS:
124       base::RecordAction(base::UserMetricsAction(
125           "ClearBrowsingData_TimePeriodChanged_LastMonth"));
126       break;
127     case TimePeriod::ALL_TIME:
128       base::RecordAction(base::UserMetricsAction(
129           "ClearBrowsingData_TimePeriodChanged_Everything"));
130       break;
131     case TimePeriod::OLDER_THAN_30_DAYS:
132       base::RecordAction(base::UserMetricsAction(
133           "ClearBrowsingData_TimePeriodChanged_OlderThan30Days"));
134       break;
135   }
136 }
137 
GetCounterTextFromResult(const BrowsingDataCounter::Result * result)138 base::string16 GetCounterTextFromResult(
139     const BrowsingDataCounter::Result* result) {
140   std::string pref_name = result->source()->GetPrefName();
141 
142   if (!result->Finished()) {
143     // The counter is still counting.
144     return l10n_util::GetStringUTF16(IDS_CLEAR_BROWSING_DATA_CALCULATING);
145   }
146 
147   if (pref_name == prefs::kDeletePasswords) {
148     const PasswordsCounter::PasswordsResult* password_result =
149         static_cast<const PasswordsCounter::PasswordsResult*>(result);
150 
151     std::vector<base::string16> parts;
152     BrowsingDataCounter::ResultInt profile_passwords = password_result->Value();
153 
154     if (profile_passwords) {
155       parts.emplace_back(base::ReplaceStringPlaceholders(
156           l10n_util::GetPluralStringFUTF16(
157               password_result->is_sync_enabled()
158                   ? IDS_DEL_PASSWORDS_COUNTER_SYNCED
159                   : IDS_DEL_PASSWORDS_COUNTER,
160               profile_passwords),
161           {CreateDomainExamples(profile_passwords,
162                                 password_result->domain_examples())},
163           nullptr));
164     }
165 
166     if (password_result->account_passwords()) {
167       parts.emplace_back(base::ReplaceStringPlaceholders(
168           l10n_util::GetPluralStringFUTF16(
169               IDS_DEL_ACCOUNT_PASSWORDS_COUNTER,
170               password_result->account_passwords()),
171           {CreateDomainExamples(password_result->account_passwords(),
172                                 password_result->account_domain_examples())},
173           nullptr));
174     }
175 
176     switch (parts.size()) {
177       case 0:
178         return l10n_util::GetStringUTF16(
179             IDS_DEL_PASSWORDS_AND_SIGNIN_DATA_COUNTER_NONE);
180       case 1:
181         return parts[0];
182       case 2:
183         return l10n_util::GetStringFUTF16(
184             IDS_DEL_PASSWORDS_AND_SIGNIN_DATA_COUNTER_COMBINATION, parts[0],
185             parts[1]);
186       default:
187         NOTREACHED();
188     }
189   }
190 
191   if (pref_name == prefs::kDeleteDownloadHistory) {
192     BrowsingDataCounter::ResultInt count =
193         static_cast<const BrowsingDataCounter::FinishedResult*>(result)
194             ->Value();
195     return l10n_util::GetPluralStringFUTF16(IDS_DEL_DOWNLOADS_COUNTER, count);
196   }
197 
198   if (pref_name == prefs::kDeleteSiteSettings) {
199     BrowsingDataCounter::ResultInt count =
200         static_cast<const BrowsingDataCounter::FinishedResult*>(result)
201             ->Value();
202     return l10n_util::GetPluralStringFUTF16(IDS_DEL_SITE_SETTINGS_COUNTER,
203                                             count);
204   }
205 
206   if (pref_name == prefs::kDeleteBrowsingHistoryBasic) {
207     // The basic tab doesn't show history counter results.
208     NOTREACHED();
209   }
210 
211   if (pref_name == prefs::kDeleteBrowsingHistory) {
212     // History counter.
213     const HistoryCounter::HistoryResult* history_result =
214         static_cast<const HistoryCounter::HistoryResult*>(result);
215     BrowsingDataCounter::ResultInt local_item_count = history_result->Value();
216     bool has_synced_visits = history_result->has_synced_visits();
217     return has_synced_visits
218                ? l10n_util::GetPluralStringFUTF16(
219                      IDS_DEL_BROWSING_HISTORY_COUNTER_SYNCED, local_item_count)
220                : l10n_util::GetPluralStringFUTF16(
221                      IDS_DEL_BROWSING_HISTORY_COUNTER, local_item_count);
222   }
223 
224   if (pref_name == prefs::kDeleteFormData) {
225     // Autofill counter.
226     const AutofillCounter::AutofillResult* autofill_result =
227         static_cast<const AutofillCounter::AutofillResult*>(result);
228     AutofillCounter::ResultInt num_suggestions = autofill_result->Value();
229     AutofillCounter::ResultInt num_credit_cards =
230         autofill_result->num_credit_cards();
231     AutofillCounter::ResultInt num_addresses = autofill_result->num_addresses();
232 
233     std::vector<base::string16> displayed_strings;
234 
235     if (num_credit_cards) {
236       displayed_strings.push_back(l10n_util::GetPluralStringFUTF16(
237           IDS_DEL_AUTOFILL_COUNTER_CREDIT_CARDS, num_credit_cards));
238     }
239     if (num_addresses) {
240       displayed_strings.push_back(l10n_util::GetPluralStringFUTF16(
241           IDS_DEL_AUTOFILL_COUNTER_ADDRESSES, num_addresses));
242     }
243     if (num_suggestions) {
244       // We use a different wording for autocomplete suggestions based on the
245       // length of the entire string.
246       switch (displayed_strings.size()) {
247         case 0:
248           displayed_strings.push_back(l10n_util::GetPluralStringFUTF16(
249               IDS_DEL_AUTOFILL_COUNTER_SUGGESTIONS, num_suggestions));
250           break;
251         case 1:
252           displayed_strings.push_back(l10n_util::GetPluralStringFUTF16(
253               IDS_DEL_AUTOFILL_COUNTER_SUGGESTIONS_LONG, num_suggestions));
254           break;
255         case 2:
256           displayed_strings.push_back(l10n_util::GetPluralStringFUTF16(
257               IDS_DEL_AUTOFILL_COUNTER_SUGGESTIONS_SHORT, num_suggestions));
258           break;
259         default:
260           NOTREACHED();
261       }
262     }
263 
264     bool synced = autofill_result->is_sync_enabled();
265 
266     // Construct the resulting string from the sections in |displayed_strings|.
267     switch (displayed_strings.size()) {
268       case 0:
269         return l10n_util::GetStringUTF16(IDS_DEL_AUTOFILL_COUNTER_EMPTY);
270         break;
271       case 1:
272         return synced ? l10n_util::GetStringFUTF16(
273                             IDS_DEL_AUTOFILL_COUNTER_ONE_TYPE_SYNCED,
274                             displayed_strings[0])
275                       : displayed_strings[0];
276         break;
277       case 2:
278         return l10n_util::GetStringFUTF16(
279             synced ? IDS_DEL_AUTOFILL_COUNTER_TWO_TYPES_SYNCED
280                    : IDS_DEL_AUTOFILL_COUNTER_TWO_TYPES,
281             displayed_strings[0], displayed_strings[1]);
282         break;
283       case 3:
284         return l10n_util::GetStringFUTF16(
285             synced ? IDS_DEL_AUTOFILL_COUNTER_THREE_TYPES_SYNCED
286                    : IDS_DEL_AUTOFILL_COUNTER_THREE_TYPES,
287             displayed_strings[0], displayed_strings[1], displayed_strings[2]);
288         break;
289       default:
290         NOTREACHED();
291     }
292   }
293 
294   NOTREACHED();
295   return base::string16();
296 }
297 
GetTimePeriodPreferenceName(ClearBrowsingDataTab clear_browsing_data_tab)298 const char* GetTimePeriodPreferenceName(
299     ClearBrowsingDataTab clear_browsing_data_tab) {
300   return clear_browsing_data_tab == ClearBrowsingDataTab::BASIC
301              ? prefs::kDeleteTimePeriodBasic
302              : prefs::kDeleteTimePeriod;
303 }
304 
GetDeletionPreferenceFromDataType(BrowsingDataType data_type,ClearBrowsingDataTab clear_browsing_data_tab,std::string * out_pref)305 bool GetDeletionPreferenceFromDataType(
306     BrowsingDataType data_type,
307     ClearBrowsingDataTab clear_browsing_data_tab,
308     std::string* out_pref) {
309   if (clear_browsing_data_tab == ClearBrowsingDataTab::BASIC) {
310     switch (data_type) {
311       case BrowsingDataType::HISTORY:
312         *out_pref = prefs::kDeleteBrowsingHistoryBasic;
313         return true;
314       case BrowsingDataType::CACHE:
315         *out_pref = prefs::kDeleteCacheBasic;
316         return true;
317       case BrowsingDataType::COOKIES:
318         *out_pref = prefs::kDeleteCookiesBasic;
319         return true;
320       case BrowsingDataType::PASSWORDS:
321       case BrowsingDataType::FORM_DATA:
322       case BrowsingDataType::BOOKMARKS:
323       case BrowsingDataType::SITE_SETTINGS:
324       case BrowsingDataType::DOWNLOADS:
325       case BrowsingDataType::HOSTED_APPS_DATA:
326         return false;  // No corresponding preference on basic tab.
327       case BrowsingDataType::NUM_TYPES:
328         // This is not an actual type.
329         NOTREACHED();
330         return false;
331     }
332   }
333   switch (data_type) {
334     case BrowsingDataType::HISTORY:
335       *out_pref = prefs::kDeleteBrowsingHistory;
336       return true;
337     case BrowsingDataType::CACHE:
338       *out_pref = prefs::kDeleteCache;
339       return true;
340     case BrowsingDataType::COOKIES:
341       *out_pref = prefs::kDeleteCookies;
342       return true;
343     case BrowsingDataType::PASSWORDS:
344       *out_pref = prefs::kDeletePasswords;
345       return true;
346     case BrowsingDataType::FORM_DATA:
347       *out_pref = prefs::kDeleteFormData;
348       return true;
349     case BrowsingDataType::BOOKMARKS:
350       // Bookmarks are deleted on the Android side. No corresponding deletion
351       // preference. Not implemented on Desktop.
352       return false;
353     case BrowsingDataType::SITE_SETTINGS:
354       *out_pref = prefs::kDeleteSiteSettings;
355       return true;
356     case BrowsingDataType::DOWNLOADS:
357       *out_pref = prefs::kDeleteDownloadHistory;
358       return true;
359     case BrowsingDataType::HOSTED_APPS_DATA:
360       *out_pref = prefs::kDeleteHostedAppsData;
361       return true;
362     case BrowsingDataType::NUM_TYPES:
363       NOTREACHED();  // This is not an actual type.
364       return false;
365   }
366   NOTREACHED();
367   return false;
368 }
369 
GetDataTypeFromDeletionPreference(const std::string & pref_name)370 BrowsingDataType GetDataTypeFromDeletionPreference(
371     const std::string& pref_name) {
372   using DataTypeMap = base::flat_map<std::string, BrowsingDataType>;
373   static base::NoDestructor<DataTypeMap> preference_to_datatype(
374       std::initializer_list<DataTypeMap::value_type>{
375           {prefs::kDeleteBrowsingHistory, BrowsingDataType::HISTORY},
376           {prefs::kDeleteBrowsingHistoryBasic, BrowsingDataType::HISTORY},
377           {prefs::kDeleteCache, BrowsingDataType::CACHE},
378           {prefs::kDeleteCacheBasic, BrowsingDataType::CACHE},
379           {prefs::kDeleteCookies, BrowsingDataType::COOKIES},
380           {prefs::kDeleteCookiesBasic, BrowsingDataType::COOKIES},
381           {prefs::kDeletePasswords, BrowsingDataType::PASSWORDS},
382           {prefs::kDeleteFormData, BrowsingDataType::FORM_DATA},
383           {prefs::kDeleteSiteSettings, BrowsingDataType::SITE_SETTINGS},
384           {prefs::kDeleteDownloadHistory, BrowsingDataType::DOWNLOADS},
385           {prefs::kDeleteHostedAppsData, BrowsingDataType::HOSTED_APPS_DATA},
386       });
387 
388   auto iter = preference_to_datatype->find(pref_name);
389   DCHECK(iter != preference_to_datatype->end());
390   return iter->second;
391 }
392 
393 }  // namespace browsing_data
394