1 // Copyright (c) 2015 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 <memory>
6 
7 #include "base/bind.h"
8 #include "base/run_loop.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "chrome/browser/password_manager/account_password_store_factory.h"
12 #include "chrome/browser/password_manager/password_store_factory.h"
13 #include "chrome/browser/sync/profile_sync_service_factory.h"
14 #include "chrome/browser/sync/test/integration/passwords_helper.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/test/base/in_process_browser_test.h"
17 #include "components/browsing_data/core/browsing_data_utils.h"
18 #include "components/browsing_data/core/counters/passwords_counter.h"
19 #include "components/browsing_data/core/pref_names.h"
20 #include "components/password_manager/core/browser/password_form.h"
21 #include "components/prefs/pref_service.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/test/browser_test.h"
24 
25 namespace {
26 
27 using browsing_data::BrowsingDataCounter;
28 using password_manager::PasswordForm;
29 
30 class PasswordsCounterTest : public InProcessBrowserTest {
31  public:
SetUpOnMainThread()32   void SetUpOnMainThread() override {
33     finished_ = false;
34     time_ = base::Time::Now();
35     times_used_ = 0;
36     store_ = PasswordStoreFactory::GetForProfile(
37         browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS);
38     SetPasswordsDeletionPref(true);
39     SetDeletionPeriodPref(browsing_data::TimePeriod::ALL_TIME);
40   }
41 
AddLogin(const std::string & origin,const std::string & username,bool blocked_by_user)42   void AddLogin(const std::string& origin,
43                 const std::string& username,
44                 bool blocked_by_user) {
45     // Add login and wait until the password store actually changes.
46     // on the database thread.
47     passwords_helper::AddLogin(
48         store_.get(), CreateCredentials(origin, username, blocked_by_user));
49   }
50 
RemoveLogin(const std::string & origin,const std::string & username,bool blocked_by_user)51   void RemoveLogin(const std::string& origin,
52                    const std::string& username,
53                    bool blocked_by_user) {
54     // Remove login and wait until the password store actually changes
55     // on the database thread.
56     passwords_helper::RemoveLogin(
57         store_.get(), CreateCredentials(origin, username, blocked_by_user));
58   }
59 
SetPasswordsDeletionPref(bool value)60   void SetPasswordsDeletionPref(bool value) {
61     browser()->profile()->GetPrefs()->SetBoolean(
62         browsing_data::prefs::kDeletePasswords, value);
63   }
64 
SetDeletionPeriodPref(browsing_data::TimePeriod period)65   void SetDeletionPeriodPref(browsing_data::TimePeriod period) {
66     browser()->profile()->GetPrefs()->SetInteger(
67         browsing_data::prefs::kDeleteTimePeriod, static_cast<int>(period));
68   }
69 
RevertTimeInDays(int days)70   void RevertTimeInDays(int days) {
71     time_ -= base::TimeDelta::FromDays(days);
72   }
73 
SetTimesUsed(int occurrences)74   void SetTimesUsed(int occurrences) { times_used_ = occurrences; }
75 
WaitForCounting()76   void WaitForCounting() {
77     // The counting takes place on the database thread. Wait until it finishes.
78     base::WaitableEvent waitable_event(
79         base::WaitableEvent::ResetPolicy::AUTOMATIC,
80         base::WaitableEvent::InitialState::NOT_SIGNALED);
81     store_->ScheduleTask(base::BindOnce(&base::WaitableEvent::Signal,
82                                         base::Unretained(&waitable_event)));
83     waitable_event.Wait();
84 
85     // At this point, the calculation on DB thread should have finished, and
86     // a callback should be scheduled on the UI thread. Process the tasks until
87     // we get a finished result.
88     run_loop_ = std::make_unique<base::RunLoop>();
89     run_loop_->Run();
90   }
91 
GetResult()92   BrowsingDataCounter::ResultInt GetResult() {
93     DCHECK(finished_);
94     return result_;
95   }
96 
GetDomainExamples()97   std::vector<std::string> GetDomainExamples() {
98     DCHECK(finished_);
99     return domain_examples_;
100   }
101 
Callback(std::unique_ptr<BrowsingDataCounter::Result> result)102   void Callback(std::unique_ptr<BrowsingDataCounter::Result> result) {
103     DCHECK(result);
104     finished_ = result->Finished();
105 
106     if (finished_) {
107       auto* password_result =
108           static_cast<browsing_data::PasswordsCounter::PasswordsResult*>(
109               result.get());
110       result_ = password_result->Value();
111       domain_examples_ = password_result->domain_examples();
112     }
113     if (run_loop_ && finished_)
114       run_loop_->Quit();
115   }
116 
WaitForUICallbacksFromAddingLogins()117   void WaitForUICallbacksFromAddingLogins() {
118     base::RunLoop loop;
119     loop.RunUntilIdle();
120   }
121 
122  private:
CreateCredentials(const std::string & origin,const std::string & username,bool blocked_by_user)123   PasswordForm CreateCredentials(const std::string& origin,
124                                  const std::string& username,
125                                  bool blocked_by_user) {
126     PasswordForm result;
127     result.signon_realm = origin;
128     result.url = GURL(origin);
129     result.username_value = base::ASCIIToUTF16(username);
130     result.password_value = base::ASCIIToUTF16("hunter2");
131     result.blocked_by_user = blocked_by_user;
132     result.date_created = time_;
133     result.times_used = times_used_;
134     return result;
135   }
136 
137   scoped_refptr<password_manager::PasswordStore> store_;
138 
139   std::unique_ptr<base::RunLoop> run_loop_;
140   base::Time time_;
141   int times_used_;
142 
143   bool finished_;
144   BrowsingDataCounter::ResultInt result_;
145   std::vector<std::string> domain_examples_;
146 };
147 
148 // Tests that the counter correctly counts each individual credential on
149 // the same domain.
IN_PROC_BROWSER_TEST_F(PasswordsCounterTest,SameDomain)150 IN_PROC_BROWSER_TEST_F(PasswordsCounterTest, SameDomain) {
151   AddLogin("https://www.google.com", "user1", false);
152   AddLogin("https://www.google.com", "user2", false);
153   AddLogin("https://www.google.com", "user3", false);
154   AddLogin("https://www.chrome.com", "user1", false);
155   AddLogin("https://www.chrome.com", "user2", false);
156   WaitForUICallbacksFromAddingLogins();
157 
158   Profile* profile = browser()->profile();
159   browsing_data::PasswordsCounter counter(
160       PasswordStoreFactory::GetForProfile(profile,
161                                           ServiceAccessType::EXPLICIT_ACCESS),
162       AccountPasswordStoreFactory::GetForProfile(
163           profile, ServiceAccessType::EXPLICIT_ACCESS),
164       ProfileSyncServiceFactory::GetForProfile(profile));
165   counter.Init(
166       profile->GetPrefs(), browsing_data::ClearBrowsingDataTab::ADVANCED,
167       base::Bind(&PasswordsCounterTest::Callback, base::Unretained(this)));
168   counter.Restart();
169 
170   WaitForCounting();
171   EXPECT_EQ(5u, GetResult());
172 }
173 
174 // Tests that the counter doesn't count blocklisted entries.
IN_PROC_BROWSER_TEST_F(PasswordsCounterTest,blocklisted)175 IN_PROC_BROWSER_TEST_F(PasswordsCounterTest, blocklisted) {
176   AddLogin("https://www.google.com", "user1", false);
177   AddLogin("https://www.google.com", "user2", true);
178   AddLogin("https://www.chrome.com", "user3", true);
179   WaitForUICallbacksFromAddingLogins();
180 
181   Profile* profile = browser()->profile();
182   browsing_data::PasswordsCounter counter(
183       PasswordStoreFactory::GetForProfile(profile,
184                                           ServiceAccessType::EXPLICIT_ACCESS),
185       AccountPasswordStoreFactory::GetForProfile(
186           profile, ServiceAccessType::EXPLICIT_ACCESS),
187       ProfileSyncServiceFactory::GetForProfile(profile));
188 
189   counter.Init(
190       profile->GetPrefs(), browsing_data::ClearBrowsingDataTab::ADVANCED,
191       base::Bind(&PasswordsCounterTest::Callback, base::Unretained(this)));
192   counter.Restart();
193 
194   WaitForCounting();
195   EXPECT_EQ(1u, GetResult());
196 }
197 
198 // Tests that the counter starts counting automatically when the deletion
199 // pref changes to true.
IN_PROC_BROWSER_TEST_F(PasswordsCounterTest,PrefChanged)200 IN_PROC_BROWSER_TEST_F(PasswordsCounterTest, PrefChanged) {
201   SetPasswordsDeletionPref(false);
202   AddLogin("https://www.google.com", "user", false);
203   AddLogin("https://www.chrome.com", "user", false);
204   WaitForUICallbacksFromAddingLogins();
205 
206   Profile* profile = browser()->profile();
207   browsing_data::PasswordsCounter counter(
208       PasswordStoreFactory::GetForProfile(profile,
209                                           ServiceAccessType::EXPLICIT_ACCESS),
210       AccountPasswordStoreFactory::GetForProfile(
211           profile, ServiceAccessType::EXPLICIT_ACCESS),
212       ProfileSyncServiceFactory::GetForProfile(profile));
213   counter.Init(
214       profile->GetPrefs(), browsing_data::ClearBrowsingDataTab::ADVANCED,
215       base::Bind(&PasswordsCounterTest::Callback, base::Unretained(this)));
216   SetPasswordsDeletionPref(true);
217 
218   WaitForCounting();
219   EXPECT_EQ(2u, GetResult());
220 }
221 
222 // Tests that the counter starts counting automatically when
223 // the password store changes.
IN_PROC_BROWSER_TEST_F(PasswordsCounterTest,StoreChanged)224 IN_PROC_BROWSER_TEST_F(PasswordsCounterTest, StoreChanged) {
225   AddLogin("https://www.google.com", "user", false);
226   WaitForUICallbacksFromAddingLogins();
227 
228   Profile* profile = browser()->profile();
229   browsing_data::PasswordsCounter counter(
230       PasswordStoreFactory::GetForProfile(profile,
231                                           ServiceAccessType::EXPLICIT_ACCESS),
232       AccountPasswordStoreFactory::GetForProfile(
233           profile, ServiceAccessType::EXPLICIT_ACCESS),
234       ProfileSyncServiceFactory::GetForProfile(profile));
235   counter.Init(
236       profile->GetPrefs(), browsing_data::ClearBrowsingDataTab::ADVANCED,
237       base::Bind(&PasswordsCounterTest::Callback, base::Unretained(this)));
238   counter.Restart();
239 
240   WaitForCounting();
241   EXPECT_EQ(1u, GetResult());
242 
243   AddLogin("https://www.chrome.com", "user", false);
244   WaitForCounting();
245   EXPECT_EQ(2u, GetResult());
246 
247   RemoveLogin("https://www.chrome.com", "user", false);
248   WaitForCounting();
249   EXPECT_EQ(1u, GetResult());
250 }
251 
252 // Tests that changing the deletion period restarts the counting, and that
253 // the result takes login creation dates into account.
IN_PROC_BROWSER_TEST_F(PasswordsCounterTest,PeriodChanged)254 IN_PROC_BROWSER_TEST_F(PasswordsCounterTest, PeriodChanged) {
255   AddLogin("https://www.google.com", "user", false);
256   RevertTimeInDays(2);
257   AddLogin("https://example.com", "user1", false);
258   RevertTimeInDays(3);
259   AddLogin("https://example.com", "user2", false);
260   RevertTimeInDays(30);
261   AddLogin("https://www.chrome.com", "user", false);
262   WaitForUICallbacksFromAddingLogins();
263 
264   Profile* profile = browser()->profile();
265   browsing_data::PasswordsCounter counter(
266       PasswordStoreFactory::GetForProfile(profile,
267                                           ServiceAccessType::EXPLICIT_ACCESS),
268       AccountPasswordStoreFactory::GetForProfile(
269           profile, ServiceAccessType::EXPLICIT_ACCESS),
270       ProfileSyncServiceFactory::GetForProfile(profile));
271   counter.Init(
272       profile->GetPrefs(), browsing_data::ClearBrowsingDataTab::ADVANCED,
273       base::Bind(&PasswordsCounterTest::Callback, base::Unretained(this)));
274 
275   SetDeletionPeriodPref(browsing_data::TimePeriod::LAST_HOUR);
276   WaitForCounting();
277   EXPECT_EQ(1u, GetResult());
278 
279   SetDeletionPeriodPref(browsing_data::TimePeriod::LAST_DAY);
280   WaitForCounting();
281   EXPECT_EQ(1u, GetResult());
282 
283   SetDeletionPeriodPref(browsing_data::TimePeriod::LAST_WEEK);
284   WaitForCounting();
285   EXPECT_EQ(3u, GetResult());
286 
287   SetDeletionPeriodPref(browsing_data::TimePeriod::FOUR_WEEKS);
288   WaitForCounting();
289   EXPECT_EQ(3u, GetResult());
290 
291   SetDeletionPeriodPref(browsing_data::TimePeriod::OLDER_THAN_30_DAYS);
292   WaitForCounting();
293   EXPECT_EQ(1u, GetResult());
294 
295   SetDeletionPeriodPref(browsing_data::TimePeriod::ALL_TIME);
296   WaitForCounting();
297   EXPECT_EQ(4u, GetResult());
298 }
299 
300 // Tests that the two most commonly used domains are chosen as the listed domain
301 // examples.
IN_PROC_BROWSER_TEST_F(PasswordsCounterTest,MostCommonDomains)302 IN_PROC_BROWSER_TEST_F(PasswordsCounterTest, MostCommonDomains) {
303   SetTimesUsed(3);
304   AddLogin("https://www.google.com", "user", false);
305   SetTimesUsed(4);
306   AddLogin("https://wwww.maps.google.com", "user", false);
307   SetTimesUsed(1);
308   AddLogin("https://www.example.com", "user", false);
309   SetTimesUsed(2);
310   AddLogin("https://www.chrome.com", "user", false);
311   WaitForUICallbacksFromAddingLogins();
312 
313   Profile* profile = browser()->profile();
314   browsing_data::PasswordsCounter counter(
315       PasswordStoreFactory::GetForProfile(profile,
316                                           ServiceAccessType::EXPLICIT_ACCESS),
317       AccountPasswordStoreFactory::GetForProfile(
318           profile, ServiceAccessType::EXPLICIT_ACCESS),
319       ProfileSyncServiceFactory::GetForProfile(profile));
320   counter.Init(
321       profile->GetPrefs(), browsing_data::ClearBrowsingDataTab::ADVANCED,
322       base::Bind(&PasswordsCounterTest::Callback, base::Unretained(this)));
323   counter.Restart();
324 
325   WaitForCounting();
326   std::vector<std::string> domain_examples = {"google.com", "chrome.com"};
327   EXPECT_EQ(domain_examples, GetDomainExamples());
328 }
329 
330 }  // namespace
331