1 // Copyright 2014 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/password_manager/core/browser/login_database.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include <memory>
11 #include <utility>
12 
13 #include "base/files/file_util.h"
14 #include "base/files/scoped_temp_dir.h"
15 #include "base/path_service.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/test/metrics/histogram_tester.h"
20 #include "base/test/task_environment.h"
21 #include "base/threading/thread_task_runner_handle.h"
22 #include "base/time/time.h"
23 #include "build/build_config.h"
24 #include "components/os_crypt/os_crypt.h"
25 #include "components/os_crypt/os_crypt_mocker.h"
26 #include "components/password_manager/core/browser/password_form.h"
27 #include "components/password_manager/core/browser/password_manager_test_utils.h"
28 #include "components/password_manager/core/browser/psl_matching_helper.h"
29 #include "components/password_manager/core/common/password_manager_features.h"
30 #include "components/password_manager/core/common/password_manager_pref_names.h"
31 #include "components/prefs/pref_registry_simple.h"
32 #include "components/prefs/testing_pref_service.h"
33 #include "sql/database.h"
34 #include "sql/statement.h"
35 #include "sql/test/test_helpers.h"
36 #include "testing/gmock/include/gmock/gmock.h"
37 #include "testing/gtest/include/gtest/gtest.h"
38 #include "url/origin.h"
39 
40 using autofill::GaiaIdHash;
41 using base::ASCIIToUTF16;
42 using base::UTF16ToASCII;
43 using ::testing::Eq;
44 using ::testing::Ne;
45 using ::testing::Pointee;
46 using ::testing::SizeIs;
47 using ::testing::UnorderedElementsAre;
48 
49 namespace password_manager {
50 namespace {
51 
AddChangeForForm(const PasswordForm & form)52 PasswordStoreChangeList AddChangeForForm(const PasswordForm& form) {
53   return PasswordStoreChangeList(
54       1, PasswordStoreChange(PasswordStoreChange::ADD, form));
55 }
56 
UpdateChangeForForm(const PasswordForm & form,const bool password_changed)57 PasswordStoreChangeList UpdateChangeForForm(const PasswordForm& form,
58                                             const bool password_changed) {
59   return PasswordStoreChangeList(
60       1,
61       PasswordStoreChange(PasswordStoreChange::UPDATE, form, password_changed));
62 }
63 
RemoveChangeForForm(const PasswordForm & form)64 PasswordStoreChangeList RemoveChangeForForm(const PasswordForm& form) {
65   return PasswordStoreChangeList(
66       1, PasswordStoreChange(PasswordStoreChange::REMOVE, form));
67 }
68 
GenerateExamplePasswordForm(PasswordForm * form)69 void GenerateExamplePasswordForm(PasswordForm* form) {
70   form->url = GURL("http://accounts.google.com/LoginAuth");
71   form->action = GURL("http://accounts.google.com/Login");
72   form->username_element = ASCIIToUTF16("Email");
73   form->username_value = ASCIIToUTF16("test@gmail.com");
74   form->password_element = ASCIIToUTF16("Passwd");
75   form->password_value = ASCIIToUTF16("test");
76   form->submit_element = ASCIIToUTF16("signIn");
77   form->signon_realm = "http://www.google.com/";
78   form->scheme = PasswordForm::Scheme::kHtml;
79   form->times_used = 1;
80   form->form_data.name = ASCIIToUTF16("form_name");
81   form->date_synced = base::Time::Now();
82   form->date_last_used = base::Time::Now();
83   form->display_name = ASCIIToUTF16("Mr. Smith");
84   form->icon_url = GURL("https://accounts.google.com/Icon");
85   form->federation_origin =
86       url::Origin::Create(GURL("https://accounts.google.com/"));
87   form->skip_zero_click = true;
88   form->in_store = PasswordForm::Store::kProfileStore;
89   form->moving_blocked_for_list.push_back(GaiaIdHash::FromGaiaId("user1"));
90   form->moving_blocked_for_list.push_back(GaiaIdHash::FromGaiaId("user2"));
91 }
92 
93 // Helper functions to read the value of the first column of an executed
94 // statement if we know its type. You must implement a specialization for
95 // every column type you use.
96 template <class T>
97 struct must_be_specialized {
98   static const bool is_specialized = false;
99 };
100 
101 template <class T>
GetFirstColumn(const sql::Statement & s)102 T GetFirstColumn(const sql::Statement& s) {
103   static_assert(must_be_specialized<T>::is_specialized,
104                 "Implement a specialization.");
105 }
106 
107 template <>
GetFirstColumn(const sql::Statement & s)108 int64_t GetFirstColumn(const sql::Statement& s) {
109   return s.ColumnInt64(0);
110 }
111 
112 template <>
GetFirstColumn(const sql::Statement & s)113 std::string GetFirstColumn(const sql::Statement& s) {
114   return s.ColumnString(0);
115 }
116 
117 // Returns an empty vector on failure. Otherwise returns values in the column
118 // |column_name| of the logins table. The order of the
119 // returned rows is well-defined.
120 template <class T>
GetColumnValuesFromDatabase(const base::FilePath & database_path,const std::string & column_name)121 std::vector<T> GetColumnValuesFromDatabase(const base::FilePath& database_path,
122                                            const std::string& column_name) {
123   sql::Database db;
124   std::vector<T> results;
125   CHECK(db.Open(database_path));
126 
127   std::string statement = base::StringPrintf(
128       "SELECT %s FROM logins ORDER BY username_value, %s DESC",
129       column_name.c_str(), column_name.c_str());
130   sql::Statement s(db.GetCachedStatement(SQL_FROM_HERE, statement.c_str()));
131   EXPECT_TRUE(s.is_valid());
132 
133   while (s.Step())
134     results.push_back(GetFirstColumn<T>(s));
135 
136   return results;
137 }
138 
AddZeroClickableLogin(LoginDatabase * db,const std::string & unique_string,const GURL & origin)139 bool AddZeroClickableLogin(LoginDatabase* db,
140                            const std::string& unique_string,
141                            const GURL& origin) {
142   // Example password form.
143   PasswordForm form;
144   form.url = origin;
145   form.username_element = ASCIIToUTF16(unique_string);
146   form.username_value = ASCIIToUTF16(unique_string);
147   form.password_element = ASCIIToUTF16(unique_string);
148   form.submit_element = ASCIIToUTF16("signIn");
149   form.signon_realm = form.url.spec();
150   form.display_name = ASCIIToUTF16(unique_string);
151   form.icon_url = origin;
152   form.federation_origin = url::Origin::Create(origin);
153   form.date_created = base::Time::Now();
154 
155   form.skip_zero_click = false;
156 
157   return db->AddLogin(form) == AddChangeForForm(form);
158 }
159 
160 MATCHER(IsGoogle1Account, "") {
161   return arg.url.spec() == "https://accounts.google.com/ServiceLogin" &&
162          arg.action.spec() == "https://accounts.google.com/ServiceLoginAuth" &&
163          arg.username_value == ASCIIToUTF16("theerikchen") &&
164          arg.scheme == PasswordForm::Scheme::kHtml;
165 }
166 
167 MATCHER(IsGoogle2Account, "") {
168   return arg.url.spec() == "https://accounts.google.com/ServiceLogin" &&
169          arg.action.spec() == "https://accounts.google.com/ServiceLoginAuth" &&
170          arg.username_value == ASCIIToUTF16("theerikchen2") &&
171          arg.scheme == PasswordForm::Scheme::kHtml;
172 }
173 
174 MATCHER(IsBasicAuthAccount, "") {
175   return arg.scheme == PasswordForm::Scheme::kBasic;
176 }
177 
178 }  // namespace
179 
180 // Serialization routines for vectors implemented in login_database.cc.
181 base::Pickle SerializeValueElementPairs(const ValueElementVector& vec);
182 ValueElementVector DeserializeValueElementPairs(const base::Pickle& pickle);
183 base::Pickle SerializeGaiaIdHashVector(const std::vector<GaiaIdHash>& hashes);
184 std::vector<GaiaIdHash> DeserializeGaiaIdHashVector(const base::Pickle& p);
185 
186 class LoginDatabaseTest : public testing::Test {
187  protected:
SetUp()188   void SetUp() override {
189     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
190     file_ = temp_dir_.GetPath().AppendASCII("TestMetadataStoreMacDatabase");
191     OSCryptMocker::SetUp();
192 
193     db_ = std::make_unique<LoginDatabase>(file_, IsAccountStore(false));
194     ASSERT_TRUE(db_->Init());
195   }
196 
TearDown()197   void TearDown() override { OSCryptMocker::TearDown(); }
198 
db()199   LoginDatabase& db() { return *db_; }
200 
TestNonHTMLFormPSLMatching(const PasswordForm::Scheme & scheme)201   void TestNonHTMLFormPSLMatching(const PasswordForm::Scheme& scheme) {
202     std::vector<std::unique_ptr<PasswordForm>> result;
203 
204     base::Time now = base::Time::Now();
205 
206     // Simple non-html auth form.
207     PasswordForm non_html_auth;
208     non_html_auth.url = GURL("http://example.com");
209     non_html_auth.username_value = ASCIIToUTF16("test@gmail.com");
210     non_html_auth.password_value = ASCIIToUTF16("test");
211     non_html_auth.signon_realm = "http://example.com/Realm";
212     non_html_auth.scheme = scheme;
213     non_html_auth.date_created = now;
214 
215     // Simple password form.
216     PasswordForm html_form(non_html_auth);
217     html_form.action = GURL("http://example.com/login");
218     html_form.username_element = ASCIIToUTF16("username");
219     html_form.username_value = ASCIIToUTF16("test2@gmail.com");
220     html_form.password_element = ASCIIToUTF16("password");
221     html_form.submit_element = ASCIIToUTF16("");
222     html_form.signon_realm = "http://example.com/";
223     html_form.scheme = PasswordForm::Scheme::kHtml;
224     html_form.date_created = now;
225 
226     // Add them and make sure they are there.
227     EXPECT_EQ(AddChangeForForm(non_html_auth), db().AddLogin(non_html_auth));
228     EXPECT_EQ(AddChangeForForm(html_form), db().AddLogin(html_form));
229     EXPECT_TRUE(db().GetAutofillableLogins(&result));
230     EXPECT_EQ(2U, result.size());
231     result.clear();
232 
233     PasswordStore::FormDigest second_non_html_auth = {
234         scheme, "http://second.example.com/Realm",
235         GURL("http://second.example.com")};
236 
237     // This shouldn't match anything.
238     EXPECT_TRUE(db().GetLogins(second_non_html_auth, &result));
239     EXPECT_EQ(0U, result.size());
240 
241     // non-html auth still matches against itself.
242     EXPECT_TRUE(
243         db().GetLogins(PasswordStore::FormDigest(non_html_auth), &result));
244     ASSERT_EQ(1U, result.size());
245     EXPECT_EQ(result[0]->signon_realm, "http://example.com/Realm");
246 
247     // Clear state.
248     db().RemoveLoginsCreatedBetween(now, base::Time(), /*changes=*/nullptr);
249   }
250 
251   // Checks that a form of a given |scheme|, once stored, can be successfully
252   // retrieved from the database.
TestRetrievingIPAddress(const PasswordForm::Scheme & scheme)253   void TestRetrievingIPAddress(const PasswordForm::Scheme& scheme) {
254     SCOPED_TRACE(testing::Message() << "scheme = " << scheme);
255     std::vector<std::unique_ptr<PasswordForm>> result;
256 
257     base::Time now = base::Time::Now();
258     std::string origin("http://56.7.8.90");
259 
260     PasswordForm ip_form;
261     ip_form.url = GURL(origin);
262     ip_form.username_value = ASCIIToUTF16("test@gmail.com");
263     ip_form.password_value = ASCIIToUTF16("test");
264     ip_form.signon_realm = origin;
265     ip_form.scheme = scheme;
266     ip_form.date_created = now;
267 
268     EXPECT_EQ(AddChangeForForm(ip_form), db().AddLogin(ip_form));
269     EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(ip_form), &result));
270     ASSERT_EQ(1U, result.size());
271     EXPECT_EQ(result[0]->signon_realm, origin);
272 
273     // Clear state.
274     db().RemoveLoginsCreatedBetween(now, base::Time(), /*changes=*/nullptr);
275   }
276 
277   base::ScopedTempDir temp_dir_;
278   base::FilePath file_;
279   std::unique_ptr<LoginDatabase> db_;
280   base::test::TaskEnvironment task_environment_;
281 };
282 
TEST_F(LoginDatabaseTest,Logins)283 TEST_F(LoginDatabaseTest, Logins) {
284   std::vector<std::unique_ptr<PasswordForm>> result;
285   PrimaryKeyToFormMap key_to_form_map;
286 
287   // Verify the database is empty.
288   EXPECT_TRUE(db().GetAutofillableLogins(&result));
289   EXPECT_EQ(0U, result.size());
290   EXPECT_TRUE(db().IsEmpty());
291 
292   EXPECT_EQ(db().GetAllLogins(&key_to_form_map), FormRetrievalResult::kSuccess);
293   EXPECT_EQ(0U, key_to_form_map.size());
294 
295   // Example password form.
296   PasswordForm form;
297   GenerateExamplePasswordForm(&form);
298 
299   // Add it and make sure it is there and that all the fields were retrieved
300   // correctly.
301   PasswordStoreChangeList changes = db().AddLogin(form);
302   ASSERT_EQ(AddChangeForForm(form), changes);
303   EXPECT_EQ(1, changes[0].primary_key());
304   EXPECT_TRUE(db().GetAutofillableLogins(&result));
305   ASSERT_EQ(1U, result.size());
306   EXPECT_EQ(form, *result[0]);
307   EXPECT_FALSE(db().IsEmpty());
308   result.clear();
309 
310   EXPECT_EQ(db().GetAllLogins(&key_to_form_map), FormRetrievalResult::kSuccess);
311   EXPECT_EQ(1U, key_to_form_map.size());
312   EXPECT_EQ(form, *key_to_form_map[1]);
313   key_to_form_map.clear();
314 
315   // Match against an exact copy.
316   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
317   ASSERT_EQ(1U, result.size());
318   EXPECT_EQ(form, *result[0]);
319   result.clear();
320 
321   // The example site changes...
322   PasswordForm form2(form);
323   form2.url = GURL("http://www.google.com/new/accounts/LoginAuth");
324   form2.submit_element = ASCIIToUTF16("reallySignIn");
325 
326   // Match against an inexact copy
327   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
328   EXPECT_EQ(1U, result.size());
329   result.clear();
330 
331   // Uh oh, the site changed origin & action URLs all at once!
332   PasswordForm form3(form2);
333   form3.action = GURL("http://www.google.com/new/accounts/Login");
334 
335   // signon_realm is the same, should match.
336   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form3), &result));
337   EXPECT_EQ(1U, result.size());
338   result.clear();
339 
340   // Imagine the site moves to a secure server for login.
341   PasswordForm form4(form3);
342   form4.signon_realm = "https://www.google.com/";
343 
344   // We have only an http record, so no match for this.
345   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form4), &result));
346   EXPECT_EQ(0U, result.size());
347 
348   // Let's imagine the user logs into the secure site.
349   changes = db().AddLogin(form4);
350   ASSERT_EQ(AddChangeForForm(form4), changes);
351   EXPECT_EQ(2, changes[0].primary_key());
352   EXPECT_TRUE(db().GetAutofillableLogins(&result));
353   EXPECT_EQ(2U, result.size());
354   result.clear();
355 
356   // Now the match works
357   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form4), &result));
358   EXPECT_EQ(1U, result.size());
359   result.clear();
360 
361   // The user chose to forget the original but not the new.
362   EXPECT_TRUE(db().RemoveLogin(form, &changes));
363   ASSERT_EQ(1U, changes.size());
364   EXPECT_EQ(1, changes[0].primary_key());
365   EXPECT_TRUE(db().GetAutofillableLogins(&result));
366   EXPECT_EQ(1U, result.size());
367   result.clear();
368 
369   // The old form wont match the new site (http vs https).
370   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
371   EXPECT_EQ(0U, result.size());
372 
373   // User changes their password.
374   PasswordForm form5(form4);
375   form5.password_value = ASCIIToUTF16("test6");
376   const base::Time kNow = base::Time::Now();
377   form5.date_last_used = kNow;
378 
379   // We update, and check to make sure it matches the
380   // old form, and there is only one record.
381   EXPECT_EQ(UpdateChangeForForm(form5, /*passwordchanged=*/true),
382             db().UpdateLogin(form5));
383   // matches
384   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form5), &result));
385   EXPECT_EQ(1U, result.size());
386   result.clear();
387   // Only one record.
388   EXPECT_TRUE(db().GetAutofillableLogins(&result));
389   EXPECT_EQ(1U, result.size());
390   // Password element was updated.
391   EXPECT_EQ(form5.password_value, result[0]->password_value);
392   // Date last used.
393   EXPECT_EQ(kNow, form5.date_last_used);
394   result.clear();
395 
396   // Make sure everything can disappear.
397   EXPECT_TRUE(db().RemoveLogin(form4, &changes));
398   ASSERT_EQ(1U, changes.size());
399   EXPECT_EQ(2, changes[0].primary_key());
400   EXPECT_TRUE(db().GetAutofillableLogins(&result));
401   EXPECT_EQ(0U, result.size());
402   EXPECT_TRUE(db().IsEmpty());
403 }
404 
TEST_F(LoginDatabaseTest,AddLoginReturnsPrimaryKey)405 TEST_F(LoginDatabaseTest, AddLoginReturnsPrimaryKey) {
406   std::vector<std::unique_ptr<PasswordForm>> result;
407 
408   // Verify the database is empty.
409   EXPECT_TRUE(db().GetAutofillableLogins(&result));
410   EXPECT_EQ(0U, result.size());
411 
412   // Example password form.
413   PasswordForm form;
414   GenerateExamplePasswordForm(&form);
415 
416   // Add it and make sure the primary key is returned in the
417   // PasswordStoreChange.
418   PasswordStoreChangeList change_list = db().AddLogin(form);
419   ASSERT_EQ(1U, change_list.size());
420   EXPECT_EQ(AddChangeForForm(form), change_list);
421   EXPECT_EQ(1, change_list[0].primary_key());
422 }
423 
TEST_F(LoginDatabaseTest,RemoveLoginsByPrimaryKey)424 TEST_F(LoginDatabaseTest, RemoveLoginsByPrimaryKey) {
425   std::vector<std::unique_ptr<PasswordForm>> result;
426 
427   // Verify the database is empty.
428   EXPECT_TRUE(db().GetAutofillableLogins(&result));
429   EXPECT_EQ(0U, result.size());
430 
431   // Example password form.
432   PasswordForm form;
433   GenerateExamplePasswordForm(&form);
434 
435   // Add it and make sure it is there and that all the fields were retrieved
436   // correctly.
437   PasswordStoreChangeList change_list = db().AddLogin(form);
438   ASSERT_EQ(1U, change_list.size());
439   int primary_key = change_list[0].primary_key();
440   EXPECT_EQ(AddChangeForForm(form), change_list);
441   EXPECT_TRUE(db().GetAutofillableLogins(&result));
442   ASSERT_EQ(1U, result.size());
443   EXPECT_EQ(form, *result[0]);
444   result.clear();
445 
446   // RemoveLoginByPrimaryKey() doesn't decrypt or fill the password value.
447   form.password_value = ASCIIToUTF16("");
448 
449   EXPECT_TRUE(db().RemoveLoginByPrimaryKey(primary_key, &change_list));
450   EXPECT_EQ(RemoveChangeForForm(form), change_list);
451   EXPECT_TRUE(db().GetAutofillableLogins(&result));
452   EXPECT_EQ(0U, result.size());
453 }
454 
TEST_F(LoginDatabaseTest,ShouldNotRecyclePrimaryKeys)455 TEST_F(LoginDatabaseTest, ShouldNotRecyclePrimaryKeys) {
456   std::vector<std::unique_ptr<PasswordForm>> result;
457 
458   // Example password form.
459   PasswordForm form;
460   GenerateExamplePasswordForm(&form);
461 
462   // Add the form.
463   PasswordStoreChangeList change_list = db().AddLogin(form);
464   ASSERT_EQ(1U, change_list.size());
465   int primary_key1 = change_list[0].primary_key();
466   change_list.clear();
467   // Delete the form
468   EXPECT_TRUE(db().RemoveLoginByPrimaryKey(primary_key1, &change_list));
469   ASSERT_EQ(1U, change_list.size());
470   // Add it again.
471   change_list = db().AddLogin(form);
472   ASSERT_EQ(1U, change_list.size());
473   EXPECT_NE(primary_key1, change_list[0].primary_key());
474 }
475 
TEST_F(LoginDatabaseTest,TestPublicSuffixDomainMatching)476 TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatching) {
477   std::vector<std::unique_ptr<PasswordForm>> result;
478 
479   // Verify the database is empty.
480   EXPECT_TRUE(db().GetAutofillableLogins(&result));
481   EXPECT_EQ(0U, result.size());
482 
483   // Example password form.
484   PasswordForm form;
485   form.url = GURL("https://foo.com/");
486   form.action = GURL("https://foo.com/login");
487   form.username_element = ASCIIToUTF16("username");
488   form.username_value = ASCIIToUTF16("test@gmail.com");
489   form.password_element = ASCIIToUTF16("password");
490   form.password_value = ASCIIToUTF16("test");
491   form.submit_element = ASCIIToUTF16("");
492   form.signon_realm = "https://foo.com/";
493   form.scheme = PasswordForm::Scheme::kHtml;
494 
495   // Add it and make sure it is there.
496   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
497   EXPECT_TRUE(db().GetAutofillableLogins(&result));
498   EXPECT_EQ(1U, result.size());
499   result.clear();
500 
501   // Match against an exact copy.
502   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
503   EXPECT_EQ(1U, result.size());
504   result.clear();
505 
506   // We go to the mobile site.
507   PasswordForm form2(form);
508   form2.url = GURL("https://mobile.foo.com/");
509   form2.action = GURL("https://mobile.foo.com/login");
510   form2.signon_realm = "https://mobile.foo.com/";
511 
512   // Match against the mobile site.
513   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
514   EXPECT_EQ(1U, result.size());
515   EXPECT_EQ("https://foo.com/", result[0]->signon_realm);
516   EXPECT_TRUE(result[0]->is_public_suffix_match);
517 }
518 
TEST_F(LoginDatabaseTest,TestFederatedMatching)519 TEST_F(LoginDatabaseTest, TestFederatedMatching) {
520   std::vector<std::unique_ptr<PasswordForm>> result;
521 
522   // Example password form.
523   PasswordForm form;
524   form.url = GURL("https://foo.com/");
525   form.action = GURL("https://foo.com/login");
526   form.username_value = ASCIIToUTF16("test@gmail.com");
527   form.password_value = ASCIIToUTF16("test");
528   form.signon_realm = "https://foo.com/";
529   form.scheme = PasswordForm::Scheme::kHtml;
530 
531   // We go to the mobile site.
532   PasswordForm form2(form);
533   form2.url = GURL("https://mobile.foo.com/");
534   form2.action = GURL("https://mobile.foo.com/login");
535   form2.signon_realm = "federation://mobile.foo.com/accounts.google.com";
536   form2.username_value = ASCIIToUTF16("test1@gmail.com");
537   form2.type = PasswordForm::Type::kApi;
538   form2.federation_origin =
539       url::Origin::Create(GURL("https://accounts.google.com/"));
540 
541   // Add it and make sure it is there.
542   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
543   EXPECT_EQ(AddChangeForForm(form2), db().AddLogin(form2));
544   EXPECT_TRUE(db().GetAutofillableLogins(&result));
545   EXPECT_EQ(2U, result.size());
546 
547   // When we retrieve the forms from the store, |in_store| should be set.
548   form.in_store = PasswordForm::Store::kProfileStore;
549   form2.in_store = PasswordForm::Store::kProfileStore;
550 
551   // Match against desktop.
552   PasswordStore::FormDigest form_request = {PasswordForm::Scheme::kHtml,
553                                             "https://foo.com/",
554                                             GURL("https://foo.com/")};
555   EXPECT_TRUE(db().GetLogins(form_request, &result));
556   // Both forms are matched, only form2 is a PSL match.
557   form.is_public_suffix_match = false;
558   form2.is_public_suffix_match = true;
559   EXPECT_THAT(result, UnorderedElementsAre(Pointee(form), Pointee(form2)));
560 
561   // Match against the mobile site.
562   form_request.url = GURL("https://mobile.foo.com/");
563   form_request.signon_realm = "https://mobile.foo.com/";
564   EXPECT_TRUE(db().GetLogins(form_request, &result));
565   // Both forms are matched, only form is a PSL match.
566   form.is_public_suffix_match = true;
567   form2.is_public_suffix_match = false;
568   EXPECT_THAT(result, UnorderedElementsAre(Pointee(form), Pointee(form2)));
569 }
570 
TEST_F(LoginDatabaseTest,TestFederatedMatchingLocalhost)571 TEST_F(LoginDatabaseTest, TestFederatedMatchingLocalhost) {
572   PasswordForm form;
573   form.url = GURL("http://localhost/");
574   form.signon_realm = "federation://localhost/accounts.google.com";
575   form.federation_origin =
576       url::Origin::Create(GURL("https://accounts.google.com/"));
577   form.username_value = ASCIIToUTF16("test@gmail.com");
578   form.type = PasswordForm::Type::kApi;
579   form.scheme = PasswordForm::Scheme::kHtml;
580 
581   PasswordForm form_with_port(form);
582   form_with_port.url = GURL("http://localhost:8080/");
583   form_with_port.signon_realm = "federation://localhost/accounts.google.com";
584 
585   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
586   EXPECT_EQ(AddChangeForForm(form_with_port), db().AddLogin(form_with_port));
587 
588   // When we retrieve the forms from the store, |in_store| should be set.
589   form.in_store = PasswordForm::Store::kProfileStore;
590   form_with_port.in_store = PasswordForm::Store::kProfileStore;
591 
592   // Match localhost with and without port.
593   PasswordStore::FormDigest form_request(PasswordForm::Scheme::kHtml,
594                                          "http://localhost/",
595                                          GURL("http://localhost/"));
596   std::vector<std::unique_ptr<PasswordForm>> result;
597   EXPECT_TRUE(db().GetLogins(form_request, &result));
598   EXPECT_THAT(result, UnorderedElementsAre(Pointee(form)));
599 
600   form_request.url = GURL("http://localhost:8080/");
601   form_request.signon_realm = "http://localhost:8080/";
602   EXPECT_TRUE(db().GetLogins(form_request, &result));
603   EXPECT_THAT(result, UnorderedElementsAre(Pointee(form_with_port)));
604 }
605 
TEST_F(LoginDatabaseTest,TestPublicSuffixDisabledForNonHTMLForms)606 TEST_F(LoginDatabaseTest, TestPublicSuffixDisabledForNonHTMLForms) {
607   TestNonHTMLFormPSLMatching(PasswordForm::Scheme::kBasic);
608   TestNonHTMLFormPSLMatching(PasswordForm::Scheme::kDigest);
609   TestNonHTMLFormPSLMatching(PasswordForm::Scheme::kOther);
610 }
611 
TEST_F(LoginDatabaseTest,TestIPAddressMatches_HTML)612 TEST_F(LoginDatabaseTest, TestIPAddressMatches_HTML) {
613   TestRetrievingIPAddress(PasswordForm::Scheme::kHtml);
614 }
615 
TEST_F(LoginDatabaseTest,TestIPAddressMatches_basic)616 TEST_F(LoginDatabaseTest, TestIPAddressMatches_basic) {
617   TestRetrievingIPAddress(PasswordForm::Scheme::kBasic);
618 }
619 
TEST_F(LoginDatabaseTest,TestIPAddressMatches_digest)620 TEST_F(LoginDatabaseTest, TestIPAddressMatches_digest) {
621   TestRetrievingIPAddress(PasswordForm::Scheme::kDigest);
622 }
623 
TEST_F(LoginDatabaseTest,TestIPAddressMatches_other)624 TEST_F(LoginDatabaseTest, TestIPAddressMatches_other) {
625   TestRetrievingIPAddress(PasswordForm::Scheme::kOther);
626 }
627 
TEST_F(LoginDatabaseTest,TestPublicSuffixDomainMatchingShouldMatchingApply)628 TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingShouldMatchingApply) {
629   std::vector<std::unique_ptr<PasswordForm>> result;
630 
631   // Verify the database is empty.
632   EXPECT_TRUE(db().GetAutofillableLogins(&result));
633   EXPECT_EQ(0U, result.size());
634 
635   // Saved password form on Google sign-in page.
636   PasswordForm form;
637   form.url = GURL("https://accounts.google.com/");
638   form.username_value = ASCIIToUTF16("test@gmail.com");
639   form.password_value = ASCIIToUTF16("test");
640   form.signon_realm = "https://accounts.google.com/";
641   form.scheme = PasswordForm::Scheme::kHtml;
642 
643   // Add it and make sure it is there.
644   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
645   EXPECT_TRUE(db().GetAutofillableLogins(&result));
646   EXPECT_EQ(1U, result.size());
647   result.clear();
648 
649   // Match against an exact copy.
650   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
651   ASSERT_EQ(1U, result.size());
652   EXPECT_EQ(form.signon_realm, result[0]->signon_realm);
653   result.clear();
654 
655   // Google change password should match to the saved sign-in form.
656   PasswordStore::FormDigest form2 = {PasswordForm::Scheme::kHtml,
657                                      "https://myaccount.google.com/",
658                                      GURL("https://myaccount.google.com/")};
659 
660   EXPECT_TRUE(db().GetLogins(form2, &result));
661   ASSERT_EQ(1U, result.size());
662   EXPECT_EQ(form.signon_realm, result[0]->signon_realm);
663   EXPECT_TRUE(result[0]->is_public_suffix_match);
664 
665   // There should be no PSL match on other subdomains.
666   PasswordStore::FormDigest form3 = {PasswordForm::Scheme::kHtml,
667                                      "https://some.other.google.com/",
668                                      GURL("https://some.other.google.com/")};
669 
670   EXPECT_TRUE(db().GetLogins(form3, &result));
671   EXPECT_EQ(0U, result.size());
672 }
673 
TEST_F(LoginDatabaseTest,TestFederatedMatchingWithoutPSLMatching)674 TEST_F(LoginDatabaseTest, TestFederatedMatchingWithoutPSLMatching) {
675   std::vector<std::unique_ptr<PasswordForm>> result;
676 
677   // Example password form.
678   PasswordForm form;
679   form.url = GURL("https://accounts.google.com/");
680   form.action = GURL("https://accounts.google.com/login");
681   form.username_value = ASCIIToUTF16("test@gmail.com");
682   form.password_value = ASCIIToUTF16("test");
683   form.signon_realm = "https://accounts.google.com/";
684   form.scheme = PasswordForm::Scheme::kHtml;
685 
686   // We go to a different site on the same domain where PSL is disabled.
687   PasswordForm form2(form);
688   form2.url = GURL("https://some.other.google.com/");
689   form2.action = GURL("https://some.other.google.com/login");
690   form2.signon_realm = "federation://some.other.google.com/accounts.google.com";
691   form2.username_value = ASCIIToUTF16("test1@gmail.com");
692   form2.type = PasswordForm::Type::kApi;
693   form2.federation_origin =
694       url::Origin::Create(GURL("https://accounts.google.com/"));
695 
696   // Add it and make sure it is there.
697   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
698   EXPECT_EQ(AddChangeForForm(form2), db().AddLogin(form2));
699   EXPECT_TRUE(db().GetAutofillableLogins(&result));
700   EXPECT_EQ(2U, result.size());
701 
702   // When we retrieve the forms from the store, |in_store| should be set.
703   form.in_store = PasswordForm::Store::kProfileStore;
704   form2.in_store = PasswordForm::Store::kProfileStore;
705 
706   // Match against the first one.
707   PasswordStore::FormDigest form_request = {PasswordForm::Scheme::kHtml,
708                                             form.signon_realm, form.url};
709   EXPECT_TRUE(db().GetLogins(form_request, &result));
710   EXPECT_THAT(result, testing::ElementsAre(Pointee(form)));
711 
712   // Match against the second one.
713   form_request.url = form2.url;
714   form_request.signon_realm = form2.signon_realm;
715   EXPECT_TRUE(db().GetLogins(form_request, &result));
716   form.is_public_suffix_match = true;
717   EXPECT_THAT(result, testing::ElementsAre(Pointee(form2)));
718 }
719 
TEST_F(LoginDatabaseTest,TestFederatedPSLMatching)720 TEST_F(LoginDatabaseTest, TestFederatedPSLMatching) {
721   // Save a federated credential for the PSL matched site.
722   PasswordForm form;
723   form.url = GURL("https://psl.example.com/");
724   form.action = GURL("https://psl.example.com/login");
725   form.signon_realm = "federation://psl.example.com/accounts.google.com";
726   form.username_value = ASCIIToUTF16("test1@gmail.com");
727   form.type = PasswordForm::Type::kApi;
728   form.federation_origin =
729       url::Origin::Create(GURL("https://accounts.google.com/"));
730   form.scheme = PasswordForm::Scheme::kHtml;
731   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
732 
733   // When we retrieve the form from the store, it should have |in_store| set.
734   form.in_store = PasswordForm::Store::kProfileStore;
735 
736   // Match against.
737   PasswordStore::FormDigest form_request = {PasswordForm::Scheme::kHtml,
738                                             "https://example.com/",
739                                             GURL("https://example.com/login")};
740   std::vector<std::unique_ptr<PasswordForm>> result;
741   EXPECT_TRUE(db().GetLogins(form_request, &result));
742   form.is_public_suffix_match = true;
743   EXPECT_THAT(result, testing::ElementsAre(Pointee(form)));
744 }
745 
746 // This test fails if the implementation of GetLogins uses GetCachedStatement
747 // instead of GetUniqueStatement, since REGEXP is in use. See
748 // http://crbug.com/248608.
TEST_F(LoginDatabaseTest,TestPublicSuffixDomainMatchingDifferentSites)749 TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingDifferentSites) {
750   std::vector<std::unique_ptr<PasswordForm>> result;
751 
752   // Verify the database is empty.
753   EXPECT_TRUE(db().GetAutofillableLogins(&result));
754   EXPECT_EQ(0U, result.size());
755 
756   // Example password form.
757   PasswordForm form;
758   form.url = GURL("https://foo.com/");
759   form.action = GURL("https://foo.com/login");
760   form.username_element = ASCIIToUTF16("username");
761   form.username_value = ASCIIToUTF16("test@gmail.com");
762   form.password_element = ASCIIToUTF16("password");
763   form.password_value = ASCIIToUTF16("test");
764   form.submit_element = ASCIIToUTF16("");
765   form.signon_realm = "https://foo.com/";
766   form.scheme = PasswordForm::Scheme::kHtml;
767 
768   // Add it and make sure it is there.
769   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
770   EXPECT_TRUE(db().GetAutofillableLogins(&result));
771   EXPECT_EQ(1U, result.size());
772   result.clear();
773 
774   // Match against an exact copy.
775   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
776   EXPECT_EQ(1U, result.size());
777   result.clear();
778 
779   // We go to the mobile site.
780   PasswordStore::FormDigest form2(form);
781   form2.url = GURL("https://mobile.foo.com/");
782   form2.signon_realm = "https://mobile.foo.com/";
783 
784   // Match against the mobile site.
785   EXPECT_TRUE(db().GetLogins(form2, &result));
786   EXPECT_EQ(1U, result.size());
787   EXPECT_EQ("https://foo.com/", result[0]->signon_realm);
788   EXPECT_TRUE(result[0]->is_public_suffix_match);
789   result.clear();
790 
791   // Add baz.com desktop site.
792   form.url = GURL("https://baz.com/login/");
793   form.action = GURL("https://baz.com/login/");
794   form.username_element = ASCIIToUTF16("email");
795   form.username_value = ASCIIToUTF16("test@gmail.com");
796   form.password_element = ASCIIToUTF16("password");
797   form.password_value = ASCIIToUTF16("test");
798   form.submit_element = ASCIIToUTF16("");
799   form.signon_realm = "https://baz.com/";
800   form.scheme = PasswordForm::Scheme::kHtml;
801 
802   // Add it and make sure it is there.
803   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
804   EXPECT_TRUE(db().GetAutofillableLogins(&result));
805   EXPECT_EQ(2U, result.size());
806   result.clear();
807 
808   // We go to the mobile site of baz.com.
809   PasswordStore::FormDigest form3(form);
810   form3.url = GURL("https://m.baz.com/login/");
811   form3.signon_realm = "https://m.baz.com/";
812 
813   // Match against the mobile site of baz.com.
814   EXPECT_TRUE(db().GetLogins(form3, &result));
815   EXPECT_EQ(1U, result.size());
816   EXPECT_EQ("https://baz.com/", result[0]->signon_realm);
817   EXPECT_TRUE(result[0]->is_public_suffix_match);
818   result.clear();
819 }
820 
GetFormWithNewSignonRealm(PasswordForm form,std::string signon_realm)821 PasswordForm GetFormWithNewSignonRealm(PasswordForm form,
822                                        std::string signon_realm) {
823   PasswordForm form2(form);
824   form2.url = GURL(signon_realm);
825   form2.action = GURL(signon_realm);
826   form2.signon_realm = signon_realm;
827   return form2;
828 }
829 
TEST_F(LoginDatabaseTest,TestPublicSuffixDomainMatchingRegexp)830 TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingRegexp) {
831   std::vector<std::unique_ptr<PasswordForm>> result;
832 
833   // Verify the database is empty.
834   EXPECT_TRUE(db().GetAutofillableLogins(&result));
835   EXPECT_EQ(0U, result.size());
836 
837   // Example password form.
838   PasswordForm form;
839   form.url = GURL("http://foo.com/");
840   form.action = GURL("http://foo.com/login");
841   form.username_element = ASCIIToUTF16("username");
842   form.username_value = ASCIIToUTF16("test@gmail.com");
843   form.password_element = ASCIIToUTF16("password");
844   form.password_value = ASCIIToUTF16("test");
845   form.submit_element = ASCIIToUTF16("");
846   form.signon_realm = "http://foo.com/";
847   form.scheme = PasswordForm::Scheme::kHtml;
848 
849   // Add it and make sure it is there.
850   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
851   EXPECT_TRUE(db().GetAutofillableLogins(&result));
852   EXPECT_EQ(1U, result.size());
853   result.clear();
854 
855   // Example password form that has - in the domain name.
856   PasswordForm form_dash =
857       GetFormWithNewSignonRealm(form, "http://www.foo-bar.com/");
858 
859   // Add it and make sure it is there.
860   EXPECT_EQ(AddChangeForForm(form_dash), db().AddLogin(form_dash));
861   EXPECT_TRUE(db().GetAutofillableLogins(&result));
862   EXPECT_EQ(2U, result.size());
863   result.clear();
864 
865   // Match against an exact copy.
866   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
867   EXPECT_EQ(1U, result.size());
868   result.clear();
869 
870   // www.foo.com should match.
871   PasswordForm form2 = GetFormWithNewSignonRealm(form, "http://www.foo.com/");
872   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
873   EXPECT_EQ(1U, result.size());
874   result.clear();
875 
876   // a.b.foo.com should match.
877   form2 = GetFormWithNewSignonRealm(form, "http://a.b.foo.com/");
878   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
879   EXPECT_EQ(1U, result.size());
880   result.clear();
881 
882   // a-b.foo.com should match.
883   form2 = GetFormWithNewSignonRealm(form, "http://a-b.foo.com/");
884   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
885   EXPECT_EQ(1U, result.size());
886   result.clear();
887 
888   // foo-bar.com should match.
889   form2 = GetFormWithNewSignonRealm(form, "http://foo-bar.com/");
890   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
891   EXPECT_EQ(1U, result.size());
892   result.clear();
893 
894   // www.foo-bar.com should match.
895   form2 = GetFormWithNewSignonRealm(form, "http://www.foo-bar.com/");
896   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
897   EXPECT_EQ(1U, result.size());
898   result.clear();
899 
900   // a.b.foo-bar.com should match.
901   form2 = GetFormWithNewSignonRealm(form, "http://a.b.foo-bar.com/");
902   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
903   EXPECT_EQ(1U, result.size());
904   result.clear();
905 
906   // a-b.foo-bar.com should match.
907   form2 = GetFormWithNewSignonRealm(form, "http://a-b.foo-bar.com/");
908   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
909   EXPECT_EQ(1U, result.size());
910   result.clear();
911 
912   // foo.com with port 1337 should not match.
913   form2 = GetFormWithNewSignonRealm(form, "http://foo.com:1337/");
914   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
915   EXPECT_EQ(0U, result.size());
916 
917   // http://foo.com should not match since the scheme is wrong.
918   form2 = GetFormWithNewSignonRealm(form, "https://foo.com/");
919   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
920   EXPECT_EQ(0U, result.size());
921 
922   // notfoo.com should not match.
923   form2 = GetFormWithNewSignonRealm(form, "http://notfoo.com/");
924   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
925   EXPECT_EQ(0U, result.size());
926 
927   // baz.com should not match.
928   form2 = GetFormWithNewSignonRealm(form, "http://baz.com/");
929   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
930   EXPECT_EQ(0U, result.size());
931 
932   // foo-baz.com should not match.
933   form2 = GetFormWithNewSignonRealm(form, "http://foo-baz.com/");
934   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
935   EXPECT_EQ(0U, result.size());
936 }
937 
AddTimestampedLogin(LoginDatabase * db,std::string url,const std::string & unique_string,const base::Time & time,bool date_is_creation)938 static bool AddTimestampedLogin(LoginDatabase* db,
939                                 std::string url,
940                                 const std::string& unique_string,
941                                 const base::Time& time,
942                                 bool date_is_creation) {
943   // Example password form.
944   PasswordForm form;
945   form.url = GURL(url + std::string("/LoginAuth"));
946   form.username_element = ASCIIToUTF16(unique_string);
947   form.username_value = ASCIIToUTF16(unique_string);
948   form.password_element = ASCIIToUTF16(unique_string);
949   form.submit_element = ASCIIToUTF16("signIn");
950   form.signon_realm = url;
951   form.display_name = ASCIIToUTF16(unique_string);
952   form.icon_url = GURL("https://accounts.google.com/Icon");
953   form.federation_origin =
954       url::Origin::Create(GURL("https://accounts.google.com/"));
955   form.skip_zero_click = true;
956 
957   if (date_is_creation)
958     form.date_created = time;
959   else
960     form.date_synced = time;
961   return db->AddLogin(form) == AddChangeForForm(form);
962 }
963 
TEST_F(LoginDatabaseTest,ClearPrivateData_SavedPasswords)964 TEST_F(LoginDatabaseTest, ClearPrivateData_SavedPasswords) {
965   std::vector<std::unique_ptr<PasswordForm>> result;
966 
967   // Verify the database is empty.
968   EXPECT_TRUE(db().GetAutofillableLogins(&result));
969   EXPECT_EQ(0U, result.size());
970 
971   base::Time now = base::Time::Now();
972   base::TimeDelta one_day = base::TimeDelta::FromDays(1);
973   base::Time back_30_days = now - base::TimeDelta::FromDays(30);
974   base::Time back_31_days = now - base::TimeDelta::FromDays(31);
975 
976   // Create one with a 0 time.
977   EXPECT_TRUE(
978       AddTimestampedLogin(&db(), "http://1.com", "foo1", base::Time(), true));
979   // Create one for now and +/- 1 day.
980   EXPECT_TRUE(
981       AddTimestampedLogin(&db(), "http://2.com", "foo2", now - one_day, true));
982   EXPECT_TRUE(AddTimestampedLogin(&db(), "http://3.com", "foo3", now, true));
983   EXPECT_TRUE(
984       AddTimestampedLogin(&db(), "http://4.com", "foo4", now + one_day, true));
985   // Create one with 31 days old.
986   EXPECT_TRUE(
987       AddTimestampedLogin(&db(), "http://5.com", "foo5", back_31_days, true));
988 
989   // Verify inserts worked.
990   EXPECT_TRUE(db().GetAutofillableLogins(&result));
991   EXPECT_EQ(5U, result.size());
992   result.clear();
993 
994   // Get everything from today's date and on.
995   PrimaryKeyToFormMap key_to_form_map;
996   EXPECT_TRUE(
997       db().GetLoginsCreatedBetween(now, base::Time(), &key_to_form_map));
998   EXPECT_EQ(2U, key_to_form_map.size());
999   key_to_form_map.clear();
1000 
1001   // Get all logins created more than 30 days back.
1002   EXPECT_TRUE(db().GetLoginsCreatedBetween(base::Time(), back_30_days,
1003                                            &key_to_form_map));
1004   EXPECT_EQ(2U, key_to_form_map.size());
1005   key_to_form_map.clear();
1006 
1007   // Delete everything from today's date and on.
1008   PasswordStoreChangeList changes;
1009   db().RemoveLoginsCreatedBetween(now, base::Time(), &changes);
1010   ASSERT_EQ(2U, changes.size());
1011   // The 3rd and the 4th should have been deleted.
1012   EXPECT_EQ(3, changes[0].primary_key());
1013   EXPECT_EQ(4, changes[1].primary_key());
1014 
1015   // Should have deleted two logins.
1016   EXPECT_TRUE(db().GetAutofillableLogins(&result));
1017   EXPECT_EQ(3U, result.size());
1018   result.clear();
1019 
1020   // Delete all logins created more than 30 days back.
1021   db().RemoveLoginsCreatedBetween(base::Time(), back_30_days, &changes);
1022   ASSERT_EQ(2U, changes.size());
1023   // The 1st and the 5th should have been deleted.
1024   EXPECT_EQ(1, changes[0].primary_key());
1025   EXPECT_EQ(5, changes[1].primary_key());
1026 
1027   // Should have deleted two logins.
1028   EXPECT_TRUE(db().GetAutofillableLogins(&result));
1029   EXPECT_EQ(1U, result.size());
1030   result.clear();
1031 
1032   // Delete with 0 date (should delete all).
1033   db().RemoveLoginsCreatedBetween(base::Time(), base::Time(), &changes);
1034   ASSERT_EQ(1U, changes.size());
1035   // The 2nd should have been deleted.
1036   EXPECT_EQ(2, changes[0].primary_key());
1037 
1038   // Verify nothing is left.
1039   EXPECT_TRUE(db().GetAutofillableLogins(&result));
1040   EXPECT_EQ(0U, result.size());
1041 }
1042 
TEST_F(LoginDatabaseTest,GetAutoSignInLogins)1043 TEST_F(LoginDatabaseTest, GetAutoSignInLogins) {
1044   PrimaryKeyToFormMap key_to_form_map;
1045 
1046   GURL origin("https://example.com");
1047   EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo1", origin));
1048   EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo2", origin));
1049   EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo3", origin));
1050   EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo4", origin));
1051 
1052   EXPECT_TRUE(db().GetAutoSignInLogins(&key_to_form_map));
1053   EXPECT_EQ(4U, key_to_form_map.size());
1054   for (const auto& pair : key_to_form_map)
1055     EXPECT_FALSE(pair.second->skip_zero_click);
1056 
1057   EXPECT_TRUE(db().DisableAutoSignInForOrigin(origin));
1058   EXPECT_TRUE(db().GetAutoSignInLogins(&key_to_form_map));
1059   EXPECT_EQ(0U, key_to_form_map.size());
1060 }
1061 
TEST_F(LoginDatabaseTest,DisableAutoSignInForOrigin)1062 TEST_F(LoginDatabaseTest, DisableAutoSignInForOrigin) {
1063   std::vector<std::unique_ptr<PasswordForm>> result;
1064 
1065   GURL origin1("https://google.com");
1066   GURL origin2("https://chrome.com");
1067   GURL origin3("http://example.com");
1068   GURL origin4("http://localhost");
1069   EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo1", origin1));
1070   EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo2", origin2));
1071   EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo3", origin3));
1072   EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo4", origin4));
1073 
1074   EXPECT_TRUE(db().GetAutofillableLogins(&result));
1075   for (const auto& form : result)
1076     EXPECT_FALSE(form->skip_zero_click);
1077 
1078   EXPECT_TRUE(db().DisableAutoSignInForOrigin(origin1));
1079   EXPECT_TRUE(db().DisableAutoSignInForOrigin(origin3));
1080   EXPECT_TRUE(db().GetAutofillableLogins(&result));
1081   for (const auto& form : result) {
1082     if (form->url == origin1 || form->url == origin3)
1083       EXPECT_TRUE(form->skip_zero_click);
1084     else
1085       EXPECT_FALSE(form->skip_zero_click);
1086   }
1087 }
1088 
TEST_F(LoginDatabaseTest,BlacklistedLogins)1089 TEST_F(LoginDatabaseTest, BlacklistedLogins) {
1090   std::vector<std::unique_ptr<PasswordForm>> result;
1091 
1092   // Verify the database is empty.
1093   EXPECT_TRUE(db().GetBlacklistLogins(&result));
1094   ASSERT_EQ(0U, result.size());
1095 
1096   // Save a form as blacklisted.
1097   PasswordForm form;
1098   form.url = GURL("http://accounts.google.com/LoginAuth");
1099   form.action = GURL("http://accounts.google.com/Login");
1100   form.username_element = ASCIIToUTF16("Email");
1101   form.password_element = ASCIIToUTF16("Passwd");
1102   form.submit_element = ASCIIToUTF16("signIn");
1103   form.signon_realm = "http://www.google.com/";
1104   form.blocked_by_user = true;
1105   form.scheme = PasswordForm::Scheme::kHtml;
1106   form.date_synced = base::Time::Now();
1107   form.date_last_used = base::Time::Now();
1108   form.display_name = ASCIIToUTF16("Mr. Smith");
1109   form.icon_url = GURL("https://accounts.google.com/Icon");
1110   form.federation_origin =
1111       url::Origin::Create(GURL("https://accounts.google.com/"));
1112   form.skip_zero_click = true;
1113   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
1114 
1115   // Get all non-blacklisted logins (should be none).
1116   EXPECT_TRUE(db().GetAutofillableLogins(&result));
1117   ASSERT_EQ(0U, result.size());
1118 
1119   // When we retrieve the form from the store, it should have |in_store| set.
1120   form.in_store = PasswordForm::Store::kProfileStore;
1121 
1122   // GetLogins should give the blacklisted result.
1123   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
1124   ASSERT_EQ(1U, result.size());
1125   EXPECT_EQ(form, *result[0]);
1126   result.clear();
1127 
1128   // So should GetBlacklistedLogins.
1129   EXPECT_TRUE(db().GetBlacklistLogins(&result));
1130   ASSERT_EQ(1U, result.size());
1131   EXPECT_EQ(form, *result[0]);
1132   result.clear();
1133 }
1134 
TEST_F(LoginDatabaseTest,VectorSerialization)1135 TEST_F(LoginDatabaseTest, VectorSerialization) {
1136   // Empty vector.
1137   ValueElementVector vec;
1138   base::Pickle temp = SerializeValueElementPairs(vec);
1139   ValueElementVector output = DeserializeValueElementPairs(temp);
1140   EXPECT_THAT(output, Eq(vec));
1141 
1142   // Normal data.
1143   vec.push_back({ASCIIToUTF16("first"), ASCIIToUTF16("id1")});
1144   vec.push_back({ASCIIToUTF16("second"), ASCIIToUTF16("id2")});
1145   vec.push_back({ASCIIToUTF16("third"), ASCIIToUTF16("id3")});
1146 
1147   temp = SerializeValueElementPairs(vec);
1148   output = DeserializeValueElementPairs(temp);
1149   EXPECT_THAT(output, Eq(vec));
1150 }
1151 
TEST_F(LoginDatabaseTest,GaiaIdHashVectorSerialization)1152 TEST_F(LoginDatabaseTest, GaiaIdHashVectorSerialization) {
1153   // Empty vector.
1154   std::vector<GaiaIdHash> vec;
1155   base::Pickle temp = SerializeGaiaIdHashVector(vec);
1156   std::vector<GaiaIdHash> output = DeserializeGaiaIdHashVector(temp);
1157   EXPECT_THAT(output, Eq(vec));
1158 
1159   // Normal data.
1160   vec.push_back(GaiaIdHash::FromGaiaId("first"));
1161   vec.push_back(GaiaIdHash::FromGaiaId("second"));
1162   vec.push_back(GaiaIdHash::FromGaiaId("third"));
1163 
1164   temp = SerializeGaiaIdHashVector(vec);
1165   output = DeserializeGaiaIdHashVector(temp);
1166   EXPECT_THAT(output, Eq(vec));
1167 }
1168 
TEST_F(LoginDatabaseTest,UpdateIncompleteCredentials)1169 TEST_F(LoginDatabaseTest, UpdateIncompleteCredentials) {
1170   std::vector<std::unique_ptr<PasswordForm>> result;
1171   // Verify the database is empty.
1172   EXPECT_TRUE(db().GetAutofillableLogins(&result));
1173   ASSERT_EQ(0U, result.size());
1174 
1175   // Save an incomplete form. Note that it only has a few fields set, ex. it's
1176   // missing 'action', 'username_element' and 'password_element'. Such forms
1177   // are sometimes inserted during import from other browsers (which may not
1178   // store this info).
1179   PasswordForm incomplete_form;
1180   incomplete_form.url = GURL("http://accounts.google.com/LoginAuth");
1181   incomplete_form.signon_realm = "http://accounts.google.com/";
1182   incomplete_form.username_value = ASCIIToUTF16("my_username");
1183   incomplete_form.password_value = ASCIIToUTF16("my_password");
1184   incomplete_form.date_last_used = base::Time::Now();
1185   incomplete_form.blocked_by_user = false;
1186   incomplete_form.scheme = PasswordForm::Scheme::kHtml;
1187   EXPECT_EQ(AddChangeForForm(incomplete_form), db().AddLogin(incomplete_form));
1188 
1189   // A form on some website. It should trigger a match with the stored one.
1190   PasswordForm encountered_form;
1191   encountered_form.url = GURL("http://accounts.google.com/LoginAuth");
1192   encountered_form.signon_realm = "http://accounts.google.com/";
1193   encountered_form.action = GURL("http://accounts.google.com/Login");
1194   encountered_form.username_element = ASCIIToUTF16("Email");
1195   encountered_form.password_element = ASCIIToUTF16("Passwd");
1196   encountered_form.submit_element = ASCIIToUTF16("signIn");
1197 
1198   // Get matches for encountered_form.
1199   EXPECT_TRUE(
1200       db().GetLogins(PasswordStore::FormDigest(encountered_form), &result));
1201   ASSERT_EQ(1U, result.size());
1202   EXPECT_EQ(incomplete_form.url, result[0]->url);
1203   EXPECT_EQ(incomplete_form.signon_realm, result[0]->signon_realm);
1204   EXPECT_EQ(incomplete_form.username_value, result[0]->username_value);
1205   EXPECT_EQ(incomplete_form.password_value, result[0]->password_value);
1206   EXPECT_EQ(incomplete_form.date_last_used, result[0]->date_last_used);
1207 
1208   // We should return empty 'action', 'username_element', 'password_element'
1209   // and 'submit_element' as we can't be sure if the credentials were entered
1210   // in this particular form on the page.
1211   EXPECT_EQ(GURL(), result[0]->action);
1212   EXPECT_TRUE(result[0]->username_element.empty());
1213   EXPECT_TRUE(result[0]->password_element.empty());
1214   EXPECT_TRUE(result[0]->submit_element.empty());
1215   result.clear();
1216 
1217   // Let's say this login form worked. Now update the stored credentials with
1218   // 'action', 'username_element', 'password_element' and 'submit_element' from
1219   // the encountered form.
1220   PasswordForm completed_form(incomplete_form);
1221   completed_form.action = encountered_form.action;
1222   completed_form.username_element = encountered_form.username_element;
1223   completed_form.password_element = encountered_form.password_element;
1224   completed_form.submit_element = encountered_form.submit_element;
1225   EXPECT_EQ(AddChangeForForm(completed_form), db().AddLogin(completed_form));
1226   EXPECT_TRUE(db().RemoveLogin(incomplete_form, /*changes=*/nullptr));
1227 
1228   // Get matches for encountered_form again.
1229   EXPECT_TRUE(
1230       db().GetLogins(PasswordStore::FormDigest(encountered_form), &result));
1231   ASSERT_EQ(1U, result.size());
1232 
1233   // This time we should have all the info available.
1234   PasswordForm expected_form(completed_form);
1235   // When we retrieve the form from the store, it should have |in_store| set.
1236   expected_form.in_store = PasswordForm::Store::kProfileStore;
1237   EXPECT_EQ(expected_form, *result[0]);
1238   result.clear();
1239 }
1240 
TEST_F(LoginDatabaseTest,UpdateOverlappingCredentials)1241 TEST_F(LoginDatabaseTest, UpdateOverlappingCredentials) {
1242   // Save an incomplete form. Note that it only has a few fields set, ex. it's
1243   // missing 'action', 'username_element' and 'password_element'. Such forms
1244   // are sometimes inserted during import from other browsers (which may not
1245   // store this info).
1246   PasswordForm incomplete_form;
1247   incomplete_form.url = GURL("http://accounts.google.com/LoginAuth");
1248   incomplete_form.signon_realm = "http://accounts.google.com/";
1249   incomplete_form.username_value = ASCIIToUTF16("my_username");
1250   incomplete_form.password_value = ASCIIToUTF16("my_password");
1251   incomplete_form.date_last_used = base::Time::Now();
1252   incomplete_form.blocked_by_user = false;
1253   incomplete_form.scheme = PasswordForm::Scheme::kHtml;
1254   EXPECT_EQ(AddChangeForForm(incomplete_form), db().AddLogin(incomplete_form));
1255 
1256   // Save a complete version of the previous form. Both forms could exist if
1257   // the user created the complete version before importing the incomplete
1258   // version from a different browser.
1259   PasswordForm complete_form = incomplete_form;
1260   complete_form.action = GURL("http://accounts.google.com/Login");
1261   complete_form.username_element = ASCIIToUTF16("username_element");
1262   complete_form.password_element = ASCIIToUTF16("password_element");
1263   complete_form.submit_element = ASCIIToUTF16("submit");
1264 
1265   // An update fails because the primary key for |complete_form| is different.
1266   EXPECT_EQ(PasswordStoreChangeList(), db().UpdateLogin(complete_form));
1267   EXPECT_EQ(AddChangeForForm(complete_form), db().AddLogin(complete_form));
1268 
1269   // Make sure both passwords exist.
1270   std::vector<std::unique_ptr<PasswordForm>> result;
1271   EXPECT_TRUE(db().GetAutofillableLogins(&result));
1272   ASSERT_EQ(2U, result.size());
1273   result.clear();
1274 
1275   // Simulate the user changing their password.
1276   complete_form.password_value = ASCIIToUTF16("new_password");
1277   complete_form.date_synced = base::Time::Now();
1278   EXPECT_EQ(UpdateChangeForForm(complete_form, /*passwordchanged=*/true),
1279             db().UpdateLogin(complete_form));
1280 
1281   // When we retrieve the forms from the store, |in_store| should be set.
1282   complete_form.in_store = PasswordForm::Store::kProfileStore;
1283   incomplete_form.in_store = PasswordForm::Store::kProfileStore;
1284 
1285   // Both still exist now.
1286   EXPECT_TRUE(db().GetAutofillableLogins(&result));
1287   ASSERT_EQ(2U, result.size());
1288 
1289   if (result[0]->username_element.empty())
1290     std::swap(result[0], result[1]);
1291   EXPECT_EQ(complete_form, *result[0]);
1292   EXPECT_EQ(incomplete_form, *result[1]);
1293 }
1294 
TEST_F(LoginDatabaseTest,DoubleAdd)1295 TEST_F(LoginDatabaseTest, DoubleAdd) {
1296   PasswordForm form;
1297   form.url = GURL("http://accounts.google.com/LoginAuth");
1298   form.signon_realm = "http://accounts.google.com/";
1299   form.username_value = ASCIIToUTF16("my_username");
1300   form.password_value = ASCIIToUTF16("my_password");
1301   form.blocked_by_user = false;
1302   form.scheme = PasswordForm::Scheme::kHtml;
1303   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
1304 
1305   // Add almost the same form again.
1306   form.times_used++;
1307   PasswordStoreChangeList list;
1308   list.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
1309   list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));
1310   EXPECT_EQ(list, db().AddLogin(form));
1311 }
1312 
TEST_F(LoginDatabaseTest,AddWrongForm)1313 TEST_F(LoginDatabaseTest, AddWrongForm) {
1314   PasswordForm form;
1315   // |origin| shouldn't be empty.
1316   form.url = GURL();
1317   form.signon_realm = "http://accounts.google.com/";
1318   form.username_value = ASCIIToUTF16("my_username");
1319   form.password_value = ASCIIToUTF16("my_password");
1320   form.blocked_by_user = false;
1321   form.scheme = PasswordForm::Scheme::kHtml;
1322   EXPECT_EQ(PasswordStoreChangeList(), db().AddLogin(form));
1323 
1324   // |signon_realm| shouldn't be empty.
1325   form.url = GURL("http://accounts.google.com/LoginAuth");
1326   form.signon_realm.clear();
1327   EXPECT_EQ(PasswordStoreChangeList(), db().AddLogin(form));
1328 }
1329 
TEST_F(LoginDatabaseTest,UpdateLogin)1330 TEST_F(LoginDatabaseTest, UpdateLogin) {
1331   PasswordForm form;
1332   form.url = GURL("http://accounts.google.com/LoginAuth");
1333   form.signon_realm = "http://accounts.google.com/";
1334   form.username_value = ASCIIToUTF16("my_username");
1335   form.password_value = ASCIIToUTF16("my_password");
1336   form.blocked_by_user = false;
1337   form.scheme = PasswordForm::Scheme::kHtml;
1338   form.date_last_used = base::Time::Now();
1339   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
1340 
1341   form.action = GURL("http://accounts.google.com/login");
1342   form.password_value = ASCIIToUTF16("my_new_password");
1343   form.all_possible_usernames.push_back(ValueElementPair(
1344       ASCIIToUTF16("my_new_username"), ASCIIToUTF16("new_username_id")));
1345   form.times_used = 20;
1346   form.submit_element = ASCIIToUTF16("submit_element");
1347   form.date_synced = base::Time::Now();
1348   form.date_created = base::Time::Now() - base::TimeDelta::FromDays(1);
1349   form.date_last_used = base::Time::Now() + base::TimeDelta::FromDays(1);
1350   form.blocked_by_user = true;
1351   form.scheme = PasswordForm::Scheme::kBasic;
1352   form.type = PasswordForm::Type::kGenerated;
1353   form.display_name = ASCIIToUTF16("Mr. Smith");
1354   form.icon_url = GURL("https://accounts.google.com/Icon");
1355   form.federation_origin =
1356       url::Origin::Create(GURL("https://accounts.google.com/"));
1357   form.skip_zero_click = true;
1358   form.moving_blocked_for_list.push_back(GaiaIdHash::FromGaiaId("gaia_id"));
1359 
1360   PasswordStoreChangeList changes = db().UpdateLogin(form);
1361   EXPECT_EQ(UpdateChangeForForm(form, /*passwordchanged=*/true), changes);
1362   ASSERT_EQ(1U, changes.size());
1363   EXPECT_EQ(1, changes[0].primary_key());
1364 
1365   // When we retrieve the form from the store, it should have |in_store| set.
1366   form.in_store = PasswordForm::Store::kProfileStore;
1367 
1368   std::vector<std::unique_ptr<PasswordForm>> result;
1369   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
1370   ASSERT_EQ(1U, result.size());
1371   EXPECT_EQ(form, *result[0]);
1372 }
1373 
TEST_F(LoginDatabaseTest,UpdateLoginWithoutPassword)1374 TEST_F(LoginDatabaseTest, UpdateLoginWithoutPassword) {
1375   PasswordForm form;
1376   form.url = GURL("http://accounts.google.com/LoginAuth");
1377   form.signon_realm = "http://accounts.google.com/";
1378   form.username_value = ASCIIToUTF16("my_username");
1379   form.password_value = ASCIIToUTF16("my_password");
1380   form.blocked_by_user = false;
1381   form.scheme = PasswordForm::Scheme::kHtml;
1382   form.date_last_used = base::Time::Now();
1383   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
1384 
1385   form.action = GURL("http://accounts.google.com/login");
1386   form.all_possible_usernames.push_back(ValueElementPair(
1387       ASCIIToUTF16("my_new_username"), ASCIIToUTF16("new_username_id")));
1388   form.times_used = 20;
1389   form.submit_element = ASCIIToUTF16("submit_element");
1390   form.date_synced = base::Time::Now();
1391   form.date_created = base::Time::Now() - base::TimeDelta::FromDays(1);
1392   form.date_last_used = base::Time::Now() + base::TimeDelta::FromDays(1);
1393   form.display_name = ASCIIToUTF16("Mr. Smith");
1394   form.icon_url = GURL("https://accounts.google.com/Icon");
1395   form.skip_zero_click = true;
1396   form.moving_blocked_for_list.push_back(GaiaIdHash::FromGaiaId("gaia_id"));
1397 
1398   PasswordStoreChangeList changes = db().UpdateLogin(form);
1399   EXPECT_EQ(UpdateChangeForForm(form, /*passwordchanged=*/false), changes);
1400   ASSERT_EQ(1U, changes.size());
1401   EXPECT_EQ(1, changes[0].primary_key());
1402 
1403   // When we retrieve the form from the store, it should have |in_store| set.
1404   form.in_store = PasswordForm::Store::kProfileStore;
1405 
1406   std::vector<std::unique_ptr<PasswordForm>> result;
1407   ASSERT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
1408   ASSERT_EQ(1U, result.size());
1409   EXPECT_EQ(form, *result[0]);
1410 }
1411 
TEST_F(LoginDatabaseTest,RemoveWrongForm)1412 TEST_F(LoginDatabaseTest, RemoveWrongForm) {
1413   PasswordForm form;
1414   // |origin| shouldn't be empty.
1415   form.url = GURL("http://accounts.google.com/LoginAuth");
1416   form.signon_realm = "http://accounts.google.com/";
1417   form.username_value = ASCIIToUTF16("my_username");
1418   form.password_value = ASCIIToUTF16("my_password");
1419   form.blocked_by_user = false;
1420   form.scheme = PasswordForm::Scheme::kHtml;
1421   // The form isn't in the database.
1422   EXPECT_FALSE(db().RemoveLogin(form, /*changes=*/nullptr));
1423 
1424   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
1425   EXPECT_TRUE(db().RemoveLogin(form, /*changes=*/nullptr));
1426   EXPECT_FALSE(db().RemoveLogin(form, /*changes=*/nullptr));
1427 }
1428 
1429 namespace {
1430 
AddMetricsTestData(LoginDatabase * db)1431 void AddMetricsTestData(LoginDatabase* db) {
1432   PasswordForm password_form;
1433   password_form.url = GURL("http://example.com");
1434   password_form.username_value = ASCIIToUTF16("test1@gmail.com");
1435   password_form.password_value = ASCIIToUTF16("test");
1436   password_form.signon_realm = "http://example.com/";
1437   password_form.times_used = 0;
1438   EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
1439 
1440   password_form.username_value = ASCIIToUTF16("test2@gmail.com");
1441   password_form.times_used = 1;
1442   EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
1443 
1444   password_form.url = GURL("http://second.example.com");
1445   password_form.signon_realm = "http://second.example.com";
1446   password_form.times_used = 3;
1447   EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
1448 
1449   password_form.username_value = ASCIIToUTF16("test3@gmail.com");
1450   password_form.type = PasswordForm::Type::kGenerated;
1451   password_form.times_used = 2;
1452   EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
1453 
1454   password_form.url = GURL("ftp://third.example.com/");
1455   password_form.signon_realm = "ftp://third.example.com/";
1456   password_form.times_used = 4;
1457   password_form.scheme = PasswordForm::Scheme::kOther;
1458   EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
1459 
1460   password_form.url = GURL("http://fourth.example.com/");
1461   password_form.signon_realm = "http://fourth.example.com/";
1462   password_form.type = PasswordForm::Type::kManual;
1463   password_form.username_value = ASCIIToUTF16("");
1464   password_form.times_used = 10;
1465   password_form.scheme = PasswordForm::Scheme::kHtml;
1466   EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
1467 
1468   password_form.url = GURL("https://fifth.example.com/");
1469   password_form.signon_realm = "https://fifth.example.com/";
1470   password_form.password_value = ASCIIToUTF16("");
1471   password_form.blocked_by_user = true;
1472   EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
1473 
1474   password_form.url = GURL("https://sixth.example.com/");
1475   password_form.signon_realm = "https://sixth.example.com/";
1476   password_form.username_value = ASCIIToUTF16("my_username");
1477   password_form.password_value = ASCIIToUTF16("my_password");
1478   password_form.blocked_by_user = false;
1479   EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
1480 
1481   password_form.url = GURL();
1482   password_form.signon_realm = "android://hash@com.example.android/";
1483   password_form.username_value = ASCIIToUTF16("JohnDoe");
1484   password_form.password_value = ASCIIToUTF16("my_password");
1485   password_form.blocked_by_user = false;
1486   EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
1487 
1488   password_form.username_value = ASCIIToUTF16("JaneDoe");
1489   EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
1490 
1491   password_form.url = GURL("http://rsolomakhin.github.io/autofill/");
1492   password_form.signon_realm = "http://rsolomakhin.github.io/";
1493   password_form.blocked_by_user = true;
1494   EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
1495 
1496   password_form.url = GURL("https://rsolomakhin.github.io/autofill/");
1497   password_form.signon_realm = "https://rsolomakhin.github.io/";
1498   password_form.blocked_by_user = true;
1499   EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
1500 
1501   password_form.url = GURL("http://rsolomakhin.github.io/autofill/123");
1502   password_form.signon_realm = "http://rsolomakhin.github.io/";
1503   password_form.blocked_by_user = true;
1504   EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
1505 
1506   password_form.url = GURL("https://rsolomakhin.github.io/autofill/1234");
1507   password_form.signon_realm = "https://rsolomakhin.github.io/";
1508   password_form.blocked_by_user = true;
1509   EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
1510 
1511   StatisticsTable& stats_table = db->stats_table();
1512   InteractionsStats stats;
1513   stats.origin_domain = GURL("https://example.com");
1514   stats.username_value = base::ASCIIToUTF16("user1");
1515   stats.dismissal_count = 10;
1516   stats.update_time = base::Time::FromTimeT(1);
1517   EXPECT_TRUE(stats_table.AddRow(stats));
1518   stats.username_value = base::ASCIIToUTF16("user2");
1519   stats.dismissal_count = 1;
1520   EXPECT_TRUE(stats_table.AddRow(stats));
1521   stats.username_value = base::ASCIIToUTF16("user3");
1522   stats.dismissal_count = 10;
1523   EXPECT_TRUE(stats_table.AddRow(stats));
1524   stats.origin_domain = GURL("https://foo.com");
1525   stats.dismissal_count = 10;
1526   EXPECT_TRUE(stats_table.AddRow(stats));
1527 }
1528 
1529 }  // namespace
1530 
TEST_F(LoginDatabaseTest,ReportMetricsTest)1531 TEST_F(LoginDatabaseTest, ReportMetricsTest) {
1532   AddMetricsTestData(&db());
1533 
1534   // Note: We also create and populate an account DB here and instruct it to
1535   // report metrics, even though all the checks below only test the profile DB.
1536   // This is to make sure that the account DB doesn't write to any of the same
1537   // histograms.
1538   base::FilePath account_db_file =
1539       temp_dir_.GetPath().AppendASCII("TestAccountStoreDatabase");
1540   LoginDatabase account_db(account_db_file, IsAccountStore(true));
1541   ASSERT_TRUE(account_db.Init());
1542   AddMetricsTestData(&account_db);
1543 
1544   base::HistogramTester histogram_tester;
1545   db().ReportMetrics("", false, BulkCheckDone(false));
1546   account_db.ReportMetrics("", false, BulkCheckDone(false));
1547 
1548   histogram_tester.ExpectUniqueSample(
1549       "PasswordManager.AccountsPerSiteHiRes.AutoGenerated."
1550       "WithoutCustomPassphrase",
1551       1, 2);
1552 
1553   histogram_tester.ExpectBucketCount(
1554       "PasswordManager.AccountsPerSiteHiRes.UserCreated."
1555       "WithoutCustomPassphrase",
1556       1, 3);
1557   histogram_tester.ExpectBucketCount(
1558       "PasswordManager.AccountsPerSiteHiRes.UserCreated."
1559       "WithoutCustomPassphrase",
1560       2, 2);
1561 
1562   histogram_tester.ExpectBucketCount(
1563       "PasswordManager.AccountsPerSiteHiRes.Overall.WithoutCustomPassphrase", 1,
1564       5);
1565   histogram_tester.ExpectBucketCount(
1566       "PasswordManager.AccountsPerSiteHiRes.Overall.WithoutCustomPassphrase", 2,
1567       2);
1568 
1569   histogram_tester.ExpectUniqueSample(
1570       "PasswordManager.TotalAccountsHiRes.ByType.AutoGenerated."
1571       "WithoutCustomPassphrase",
1572       2, 1);
1573 
1574   histogram_tester.ExpectUniqueSample(
1575       "PasswordManager.TotalAccountsHiRes.ByType.UserCreated."
1576       "WithoutCustomPassphrase",
1577       7, 1);
1578 
1579   histogram_tester.ExpectUniqueSample(
1580       "PasswordManager.TotalAccountsHiRes.ByType.Overall."
1581       "WithoutCustomPassphrase",
1582       9, 1);
1583 
1584   histogram_tester.ExpectUniqueSample(
1585       "PasswordManager.TotalAccountsHiRes.WithScheme.Android", 2, 1);
1586   histogram_tester.ExpectUniqueSample(
1587       "PasswordManager.TotalAccountsHiRes.WithScheme.Ftp", 1, 1);
1588   histogram_tester.ExpectUniqueSample(
1589       "PasswordManager.TotalAccountsHiRes.WithScheme.Http", 5, 1);
1590   histogram_tester.ExpectUniqueSample(
1591       "PasswordManager.TotalAccountsHiRes.WithScheme.Https", 1, 1);
1592   histogram_tester.ExpectUniqueSample(
1593       "PasswordManager.TotalAccountsHiRes.WithScheme.Other", 0, 1);
1594 
1595   histogram_tester.ExpectBucketCount(
1596       "PasswordManager.TimesPasswordUsed.AutoGenerated.WithoutCustomPassphrase",
1597       2, 1);
1598   histogram_tester.ExpectBucketCount(
1599       "PasswordManager.TimesPasswordUsed.AutoGenerated.WithoutCustomPassphrase",
1600       4, 1);
1601 
1602   histogram_tester.ExpectBucketCount(
1603       "PasswordManager.TimesPasswordUsed.UserCreated.WithoutCustomPassphrase",
1604       0, 1);
1605   histogram_tester.ExpectBucketCount(
1606       "PasswordManager.TimesPasswordUsed.UserCreated.WithoutCustomPassphrase",
1607       1, 1);
1608   histogram_tester.ExpectBucketCount(
1609       "PasswordManager.TimesPasswordUsed.UserCreated.WithoutCustomPassphrase",
1610       3, 1);
1611 
1612   histogram_tester.ExpectBucketCount(
1613       "PasswordManager.TimesPasswordUsed.Overall.WithoutCustomPassphrase", 0,
1614       1);
1615   histogram_tester.ExpectBucketCount(
1616       "PasswordManager.TimesPasswordUsed.Overall.WithoutCustomPassphrase", 1,
1617       1);
1618   histogram_tester.ExpectBucketCount(
1619       "PasswordManager.TimesPasswordUsed.Overall.WithoutCustomPassphrase", 2,
1620       1);
1621   // The bucket for 3 and 4 is the same. Thus we expect two samples here.
1622   histogram_tester.ExpectBucketCount(
1623       "PasswordManager.TimesPasswordUsed.Overall.WithoutCustomPassphrase", 3,
1624       2);
1625 
1626   histogram_tester.ExpectUniqueSample(
1627       "PasswordManager.EmptyUsernames.CountInDatabase", 1, 1);
1628   histogram_tester.ExpectUniqueSample("PasswordManager.InaccessiblePasswords",
1629                                       0, 1);
1630 #if !defined(OS_IOS) && !defined(OS_ANDROID)
1631   histogram_tester.ExpectUniqueSample(
1632       "PasswordManager.BubbleSuppression.AccountsInStatisticsTable", 4, 1);
1633 #endif  // !defined(OS_IOS) && !defined(OS_ANDROID)
1634 }
1635 
1636 // This test is mostly a copy of ReportMetricsTest, but covering the account
1637 // store instead of the profile store. Some metrics are not recorded for the
1638 // account store (e.g. BubbleSuppression ones) so these are missing here; all
1639 // the metrics that *are* covered have ".AccountStore" in their names.
TEST_F(LoginDatabaseTest,ReportAccountStoreMetricsTest)1640 TEST_F(LoginDatabaseTest, ReportAccountStoreMetricsTest) {
1641   // Note: We also populate the profile DB here and instruct it to report
1642   // metrics, even though all the checks below only test the account DB. This is
1643   // to make sure that the profile DB doesn't write to any of the same
1644   // histograms.
1645   AddMetricsTestData(&db());
1646 
1647   base::FilePath account_db_file =
1648       temp_dir_.GetPath().AppendASCII("TestAccountStoreDatabase");
1649   LoginDatabase account_db(account_db_file, IsAccountStore(true));
1650   ASSERT_TRUE(account_db.Init());
1651   AddMetricsTestData(&account_db);
1652 
1653   base::HistogramTester histogram_tester;
1654   db().ReportMetrics("", false, BulkCheckDone(false));
1655   account_db.ReportMetrics("", false, BulkCheckDone(false));
1656 
1657   histogram_tester.ExpectUniqueSample(
1658       "PasswordManager.AccountStore.AccountsPerSiteHiRes.AutoGenerated."
1659       "WithoutCustomPassphrase",
1660       1, 2);
1661 
1662   histogram_tester.ExpectBucketCount(
1663       "PasswordManager.AccountStore.AccountsPerSiteHiRes.UserCreated."
1664       "WithoutCustomPassphrase",
1665       1, 3);
1666   histogram_tester.ExpectBucketCount(
1667       "PasswordManager.AccountStore.AccountsPerSiteHiRes.UserCreated."
1668       "WithoutCustomPassphrase",
1669       2, 2);
1670 
1671   histogram_tester.ExpectBucketCount(
1672       "PasswordManager.AccountStore.AccountsPerSiteHiRes.Overall."
1673       "WithoutCustomPassphrase",
1674       1, 5);
1675   histogram_tester.ExpectBucketCount(
1676       "PasswordManager.AccountStore.AccountsPerSiteHiRes.Overall."
1677       "WithoutCustomPassphrase",
1678       2, 2);
1679 
1680   histogram_tester.ExpectUniqueSample(
1681       "PasswordManager.AccountStore.TotalAccountsHiRes.ByType.AutoGenerated."
1682       "WithoutCustomPassphrase",
1683       2, 1);
1684 
1685   histogram_tester.ExpectUniqueSample(
1686       "PasswordManager.AccountStore.TotalAccountsHiRes.ByType.UserCreated."
1687       "WithoutCustomPassphrase",
1688       7, 1);
1689 
1690   histogram_tester.ExpectUniqueSample(
1691       "PasswordManager.AccountStore.TotalAccountsHiRes.ByType.Overall."
1692       "WithoutCustomPassphrase",
1693       9, 1);
1694 
1695   histogram_tester.ExpectUniqueSample(
1696       "PasswordManager.AccountStore.TotalAccountsHiRes.WithScheme.Android", 2,
1697       1);
1698   histogram_tester.ExpectUniqueSample(
1699       "PasswordManager.AccountStore.TotalAccountsHiRes.WithScheme.Ftp", 1, 1);
1700   histogram_tester.ExpectUniqueSample(
1701       "PasswordManager.AccountStore.TotalAccountsHiRes.WithScheme.Http", 5, 1);
1702   histogram_tester.ExpectUniqueSample(
1703       "PasswordManager.AccountStore.TotalAccountsHiRes.WithScheme.Https", 1, 1);
1704   histogram_tester.ExpectUniqueSample(
1705       "PasswordManager.AccountStore.TotalAccountsHiRes.WithScheme.Other", 0, 1);
1706 
1707   histogram_tester.ExpectBucketCount(
1708       "PasswordManager.AccountStore.TimesPasswordUsed.AutoGenerated."
1709       "WithoutCustomPassphrase",
1710       2, 1);
1711   histogram_tester.ExpectBucketCount(
1712       "PasswordManager.AccountStore.TimesPasswordUsed.AutoGenerated."
1713       "WithoutCustomPassphrase",
1714       4, 1);
1715 
1716   histogram_tester.ExpectBucketCount(
1717       "PasswordManager.AccountStore.TimesPasswordUsed.UserCreated."
1718       "WithoutCustomPassphrase",
1719       0, 1);
1720   histogram_tester.ExpectBucketCount(
1721       "PasswordManager.AccountStore.TimesPasswordUsed.UserCreated."
1722       "WithoutCustomPassphrase",
1723       1, 1);
1724   histogram_tester.ExpectBucketCount(
1725       "PasswordManager.AccountStore.TimesPasswordUsed.UserCreated."
1726       "WithoutCustomPassphrase",
1727       3, 1);
1728 
1729   histogram_tester.ExpectBucketCount(
1730       "PasswordManager.AccountStore.TimesPasswordUsed.Overall."
1731       "WithoutCustomPassphrase",
1732       0, 1);
1733   histogram_tester.ExpectBucketCount(
1734       "PasswordManager.AccountStore.TimesPasswordUsed.Overall."
1735       "WithoutCustomPassphrase",
1736       1, 1);
1737   histogram_tester.ExpectBucketCount(
1738       "PasswordManager.AccountStore.TimesPasswordUsed.Overall."
1739       "WithoutCustomPassphrase",
1740       2, 1);
1741   // The bucket for 3 and 4 is the same. Thus we expect two samples here.
1742   histogram_tester.ExpectBucketCount(
1743       "PasswordManager.AccountStore.TimesPasswordUsed.Overall."
1744       "WithoutCustomPassphrase",
1745       3, 2);
1746 
1747   histogram_tester.ExpectUniqueSample(
1748       "PasswordManager.AccountStore.EmptyUsernames.CountInDatabase", 1, 1);
1749   histogram_tester.ExpectUniqueSample(
1750       "PasswordManager.AccountStore.InaccessiblePasswords", 0, 1);
1751 }
1752 
TEST_F(LoginDatabaseTest,DuplicatesMetrics_NoDuplicates)1753 TEST_F(LoginDatabaseTest, DuplicatesMetrics_NoDuplicates) {
1754   // No duplicate.
1755   PasswordForm password_form;
1756   password_form.signon_realm = "http://example1.com/";
1757   password_form.url = GURL("http://example1.com/");
1758   password_form.username_element = ASCIIToUTF16("userelem_1");
1759   password_form.username_value = ASCIIToUTF16("username_1");
1760   password_form.password_value = ASCIIToUTF16("password_1");
1761   ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
1762 
1763   // Different username -> no duplicate.
1764   password_form.signon_realm = "http://example2.com/";
1765   password_form.url = GURL("http://example2.com/");
1766   password_form.username_value = ASCIIToUTF16("username_1");
1767   ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
1768   password_form.username_value = ASCIIToUTF16("username_2");
1769   ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
1770 
1771   // Blacklisted forms don't count as duplicates (neither against other
1772   // blacklisted forms nor against actual saved credentials).
1773   password_form.signon_realm = "http://example3.com/";
1774   password_form.url = GURL("http://example3.com/");
1775   password_form.username_value = ASCIIToUTF16("username_1");
1776   ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
1777   password_form.blocked_by_user = true;
1778   password_form.username_value = ASCIIToUTF16("username_2");
1779   ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
1780   password_form.username_value = ASCIIToUTF16("username_3");
1781   ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
1782 
1783   base::HistogramTester histogram_tester;
1784   db().ReportMetrics("", false, BulkCheckDone(false));
1785 
1786   EXPECT_THAT(histogram_tester.GetAllSamples(
1787                   "PasswordManager.CredentialsWithDuplicates"),
1788               testing::ElementsAre(base::Bucket(0, 1)));
1789   EXPECT_THAT(histogram_tester.GetAllSamples(
1790                   "PasswordManager.CredentialsWithMismatchedDuplicates"),
1791               testing::ElementsAre(base::Bucket(0, 1)));
1792 }
1793 
TEST_F(LoginDatabaseTest,DuplicatesMetrics_ExactDuplicates)1794 TEST_F(LoginDatabaseTest, DuplicatesMetrics_ExactDuplicates) {
1795   // Add some PasswordForms that are "exact" duplicates (only the
1796   // username_element is different, which doesn't matter).
1797   PasswordForm password_form;
1798   password_form.signon_realm = "http://example1.com/";
1799   password_form.url = GURL("http://example1.com/");
1800   password_form.username_element = ASCIIToUTF16("userelem_1");
1801   password_form.username_value = ASCIIToUTF16("username_1");
1802   ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
1803   password_form.username_element = ASCIIToUTF16("userelem_2");
1804   ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
1805   // The number of "identical" credentials doesn't matter; we count the *sets*
1806   // of duplicates.
1807   password_form.username_element = ASCIIToUTF16("userelem_3");
1808   ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
1809 
1810   // Similarly, origin doesn't make forms "different" either.
1811   password_form.signon_realm = "http://example2.com/";
1812   password_form.url = GURL("http://example2.com/path1");
1813   ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
1814   password_form.url = GURL("http://example2.com/path2");
1815   ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
1816 
1817   base::HistogramTester histogram_tester;
1818   db().ReportMetrics("", false, BulkCheckDone(false));
1819 
1820   // There should be 2 groups of "exact" duplicates.
1821   EXPECT_THAT(histogram_tester.GetAllSamples(
1822                   "PasswordManager.CredentialsWithDuplicates"),
1823               testing::ElementsAre(base::Bucket(2, 1)));
1824   EXPECT_THAT(histogram_tester.GetAllSamples(
1825                   "PasswordManager.CredentialsWithMismatchedDuplicates"),
1826               testing::ElementsAre(base::Bucket(0, 1)));
1827 }
1828 
TEST_F(LoginDatabaseTest,DuplicatesMetrics_MismatchedDuplicates)1829 TEST_F(LoginDatabaseTest, DuplicatesMetrics_MismatchedDuplicates) {
1830   // Mismatched duplicates: Identical except for the password.
1831   PasswordForm password_form;
1832   password_form.signon_realm = "http://example1.com/";
1833   password_form.url = GURL("http://example1.com/");
1834   password_form.username_element = ASCIIToUTF16("userelem_1");
1835   password_form.username_value = ASCIIToUTF16("username_1");
1836   password_form.password_element = ASCIIToUTF16("passelem_1");
1837   password_form.password_value = ASCIIToUTF16("password_1");
1838   ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
1839   // Note: password_value is not part of the unique key, so we need to change
1840   // some other value to be able to insert the duplicate into the DB.
1841   password_form.password_element = ASCIIToUTF16("passelem_2");
1842   password_form.password_value = ASCIIToUTF16("password_2");
1843   ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
1844   // The number of "identical" credentials doesn't matter; we count the *sets*
1845   // of duplicates.
1846   password_form.password_element = ASCIIToUTF16("passelem_3");
1847   password_form.password_value = ASCIIToUTF16("password_3");
1848   ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
1849 
1850   base::HistogramTester histogram_tester;
1851   db().ReportMetrics("", false, BulkCheckDone(false));
1852 
1853   EXPECT_THAT(histogram_tester.GetAllSamples(
1854                   "PasswordManager.CredentialsWithDuplicates"),
1855               testing::ElementsAre(base::Bucket(0, 1)));
1856   EXPECT_THAT(histogram_tester.GetAllSamples(
1857                   "PasswordManager.CredentialsWithMismatchedDuplicates"),
1858               testing::ElementsAre(base::Bucket(1, 1)));
1859 }
1860 
TEST_F(LoginDatabaseTest,NoMetadata)1861 TEST_F(LoginDatabaseTest, NoMetadata) {
1862   std::unique_ptr<syncer::MetadataBatch> metadata_batch =
1863       db().GetAllSyncMetadata();
1864   ASSERT_THAT(metadata_batch, testing::NotNull());
1865   EXPECT_EQ(0u, metadata_batch->TakeAllMetadata().size());
1866   EXPECT_EQ(sync_pb::ModelTypeState().SerializeAsString(),
1867             metadata_batch->GetModelTypeState().SerializeAsString());
1868 }
1869 
TEST_F(LoginDatabaseTest,GetAllSyncMetadata)1870 TEST_F(LoginDatabaseTest, GetAllSyncMetadata) {
1871   sync_pb::EntityMetadata metadata;
1872   // Storage keys must be integers.
1873   const std::string kStorageKey1 = "1";
1874   const std::string kStorageKey2 = "2";
1875   metadata.set_sequence_number(1);
1876 
1877   EXPECT_TRUE(
1878       db().UpdateSyncMetadata(syncer::PASSWORDS, kStorageKey1, metadata));
1879 
1880   sync_pb::ModelTypeState model_type_state;
1881   model_type_state.set_initial_sync_done(true);
1882 
1883   EXPECT_TRUE(db().UpdateModelTypeState(syncer::PASSWORDS, model_type_state));
1884 
1885   metadata.set_sequence_number(2);
1886   EXPECT_TRUE(
1887       db().UpdateSyncMetadata(syncer::PASSWORDS, kStorageKey2, metadata));
1888 
1889   std::unique_ptr<syncer::MetadataBatch> metadata_batch =
1890       db().GetAllSyncMetadata();
1891   ASSERT_THAT(metadata_batch, testing::NotNull());
1892 
1893   EXPECT_TRUE(metadata_batch->GetModelTypeState().initial_sync_done());
1894 
1895   syncer::EntityMetadataMap metadata_records =
1896       metadata_batch->TakeAllMetadata();
1897 
1898   EXPECT_EQ(metadata_records.size(), 2u);
1899   EXPECT_EQ(metadata_records[kStorageKey1]->sequence_number(), 1);
1900   EXPECT_EQ(metadata_records[kStorageKey2]->sequence_number(), 2);
1901 
1902   // Now check that a model type state update replaces the old value
1903   model_type_state.set_initial_sync_done(false);
1904   EXPECT_TRUE(db().UpdateModelTypeState(syncer::PASSWORDS, model_type_state));
1905 
1906   metadata_batch = db().GetAllSyncMetadata();
1907   ASSERT_THAT(metadata_batch, testing::NotNull());
1908   EXPECT_FALSE(metadata_batch->GetModelTypeState().initial_sync_done());
1909 }
1910 
TEST_F(LoginDatabaseTest,DeleteAllSyncMetadata)1911 TEST_F(LoginDatabaseTest, DeleteAllSyncMetadata) {
1912   sync_pb::EntityMetadata metadata;
1913   // Storage keys must be integers.
1914   const std::string kStorageKey1 = "1";
1915   const std::string kStorageKey2 = "2";
1916   metadata.set_sequence_number(1);
1917 
1918   EXPECT_TRUE(
1919       db().UpdateSyncMetadata(syncer::PASSWORDS, kStorageKey1, metadata));
1920 
1921   sync_pb::ModelTypeState model_type_state;
1922   model_type_state.set_initial_sync_done(true);
1923 
1924   EXPECT_TRUE(db().UpdateModelTypeState(syncer::PASSWORDS, model_type_state));
1925 
1926   metadata.set_sequence_number(2);
1927   EXPECT_TRUE(
1928       db().UpdateSyncMetadata(syncer::PASSWORDS, kStorageKey2, metadata));
1929 
1930   std::unique_ptr<syncer::MetadataBatch> metadata_batch =
1931       db().GetAllSyncMetadata();
1932   ASSERT_THAT(metadata_batch, testing::NotNull());
1933   ASSERT_EQ(metadata_batch->TakeAllMetadata().size(), 2u);
1934 
1935   db().DeleteAllSyncMetadata();
1936 
1937   std::unique_ptr<syncer::MetadataBatch> empty_metadata_batch =
1938       db().GetAllSyncMetadata();
1939   ASSERT_THAT(empty_metadata_batch, testing::NotNull());
1940   EXPECT_EQ(empty_metadata_batch->TakeAllMetadata().size(), 0u);
1941 }
1942 
TEST_F(LoginDatabaseTest,WriteThenDeleteSyncMetadata)1943 TEST_F(LoginDatabaseTest, WriteThenDeleteSyncMetadata) {
1944   sync_pb::EntityMetadata metadata;
1945   const std::string kStorageKey = "1";
1946   sync_pb::ModelTypeState model_type_state;
1947 
1948   model_type_state.set_initial_sync_done(true);
1949 
1950   metadata.set_client_tag_hash("client_hash");
1951 
1952   // Write the data into the store.
1953   EXPECT_TRUE(
1954       db().UpdateSyncMetadata(syncer::PASSWORDS, kStorageKey, metadata));
1955   EXPECT_TRUE(db().UpdateModelTypeState(syncer::PASSWORDS, model_type_state));
1956   // Delete the data we just wrote.
1957   EXPECT_TRUE(db().ClearSyncMetadata(syncer::PASSWORDS, kStorageKey));
1958 
1959   std::unique_ptr<syncer::MetadataBatch> metadata_batch =
1960       db().GetAllSyncMetadata();
1961   ASSERT_THAT(metadata_batch, testing::NotNull());
1962 
1963   // It shouldn't be there any more.
1964   syncer::EntityMetadataMap metadata_records =
1965       metadata_batch->TakeAllMetadata();
1966   EXPECT_EQ(metadata_records.size(), 0u);
1967 
1968   // Now delete the model type state.
1969   EXPECT_TRUE(db().ClearModelTypeState(syncer::PASSWORDS));
1970   metadata_batch = db().GetAllSyncMetadata();
1971   ASSERT_THAT(metadata_batch, testing::NotNull());
1972 
1973   EXPECT_EQ(sync_pb::ModelTypeState().SerializeAsString(),
1974             metadata_batch->GetModelTypeState().SerializeAsString());
1975 }
1976 
1977 #if defined(OS_POSIX)
1978 // Only the current user has permission to read the database.
1979 //
1980 // Only POSIX because GetPosixFilePermissions() only exists on POSIX.
1981 // This tests that sql::Database::set_restrict_to_user() was called,
1982 // and that function is a noop on non-POSIX platforms in any case.
TEST_F(LoginDatabaseTest,FilePermissions)1983 TEST_F(LoginDatabaseTest, FilePermissions) {
1984   int mode = base::FILE_PERMISSION_MASK;
1985   EXPECT_TRUE(base::GetPosixFilePermissions(file_, &mode));
1986   EXPECT_EQ((mode & base::FILE_PERMISSION_USER_MASK), mode);
1987 }
1988 #endif  // defined(OS_POSIX)
1989 
1990 #if !defined(OS_IOS)
1991 // Test that LoginDatabase encrypts the password values that it stores.
TEST_F(LoginDatabaseTest,EncryptionEnabled)1992 TEST_F(LoginDatabaseTest, EncryptionEnabled) {
1993   PasswordForm password_form;
1994   GenerateExamplePasswordForm(&password_form);
1995   base::FilePath file = temp_dir_.GetPath().AppendASCII("TestUnencryptedDB");
1996   {
1997     LoginDatabase db(file, IsAccountStore(false));
1998     ASSERT_TRUE(db.Init());
1999     EXPECT_EQ(AddChangeForForm(password_form), db.AddLogin(password_form));
2000   }
2001   base::string16 decrypted_pw;
2002   ASSERT_TRUE(OSCrypt::DecryptString16(
2003       GetColumnValuesFromDatabase<std::string>(file, "password_value").at(0),
2004       &decrypted_pw));
2005   EXPECT_EQ(decrypted_pw, password_form.password_value);
2006 }
2007 #endif  // !defined(OS_IOS)
2008 
2009 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
2010 // Test that LoginDatabase does not encrypt values when encryption is disabled.
2011 // TODO(crbug.com/829857) This is supported only for Linux, while transitioning
2012 // into LoginDB with full encryption.
TEST_F(LoginDatabaseTest,EncryptionDisabled)2013 TEST_F(LoginDatabaseTest, EncryptionDisabled) {
2014   PasswordForm password_form;
2015   GenerateExamplePasswordForm(&password_form);
2016   base::FilePath file = temp_dir_.GetPath().AppendASCII("TestUnencryptedDB");
2017   {
2018     LoginDatabase db(file, IsAccountStore(false));
2019     db.disable_encryption();
2020     ASSERT_TRUE(db.Init());
2021     EXPECT_EQ(AddChangeForForm(password_form), db.AddLogin(password_form));
2022   }
2023   EXPECT_EQ(
2024       GetColumnValuesFromDatabase<std::string>(file, "password_value").at(0),
2025       base::UTF16ToUTF8(password_form.password_value));
2026 }
2027 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
2028 
2029 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
2030 // On Android and ChromeOS there is a mix of plain-text and obfuscated
2031 // passwords. Verify that they can both be accessed. Obfuscated passwords start
2032 // with "v10". Some password values also start with "v10". Test that both are
2033 // accessible (this doesn't work for any plain-text value).
TEST_F(LoginDatabaseTest,HandleObfuscationMix)2034 TEST_F(LoginDatabaseTest, HandleObfuscationMix) {
2035   const char k_obfuscated_pw[] = "v10pass1";
2036   const char k_plain_text_pw1[] = "v10pass2";
2037   const char k_plain_text_pw2[] = "v11pass3";
2038 
2039   base::FilePath file = temp_dir_.GetPath().AppendASCII("TestUnencryptedDB");
2040   {
2041     LoginDatabase db(file, IsAccountStore(false));
2042     ASSERT_TRUE(db.Init());
2043     // Add obfuscated (new) entries.
2044     PasswordForm password_form;
2045     GenerateExamplePasswordForm(&password_form);
2046     password_form.password_value = ASCIIToUTF16(k_obfuscated_pw);
2047     EXPECT_EQ(AddChangeForForm(password_form), db.AddLogin(password_form));
2048     // Add plain-text (old) entries.
2049     db.disable_encryption();
2050     GenerateExamplePasswordForm(&password_form);
2051     password_form.username_value = ASCIIToUTF16("other_username");
2052     password_form.password_value = ASCIIToUTF16(k_plain_text_pw1);
2053     EXPECT_EQ(AddChangeForForm(password_form), db.AddLogin(password_form));
2054     GenerateExamplePasswordForm(&password_form);
2055     password_form.username_value = ASCIIToUTF16("other_username2");
2056     password_form.password_value = ASCIIToUTF16(k_plain_text_pw2);
2057     EXPECT_EQ(AddChangeForForm(password_form), db.AddLogin(password_form));
2058   }
2059 
2060   std::vector<std::unique_ptr<PasswordForm>> forms;
2061   {
2062     LoginDatabase db(file, IsAccountStore(false));
2063     ASSERT_TRUE(db.Init());
2064     ASSERT_TRUE(db.GetAutofillableLogins(&forms));
2065   }
2066 
2067   // On disk, unobfuscated passwords are as-is, while obfuscated passwords have
2068   // been changed (obfuscated).
2069   EXPECT_THAT(GetColumnValuesFromDatabase<std::string>(file, "password_value"),
2070               UnorderedElementsAre(Ne(k_obfuscated_pw), k_plain_text_pw1,
2071                                    k_plain_text_pw2));
2072   // LoginDatabase serves the original values.
2073   ASSERT_THAT(forms, SizeIs(3));
2074   EXPECT_EQ(k_obfuscated_pw, UTF16ToASCII(forms[0]->password_value));
2075   EXPECT_EQ(k_plain_text_pw1, UTF16ToASCII(forms[1]->password_value));
2076   EXPECT_EQ(k_plain_text_pw2, UTF16ToASCII(forms[2]->password_value));
2077 }
2078 #endif  // defined(OS_ANDROID) || defined(OS_CHROMEOS)
2079 
2080 // If the database initialisation fails, the initialisation transaction should
2081 // roll back without crashing.
TEST(LoginDatabaseFailureTest,Init_NoCrashOnFailedRollback)2082 TEST(LoginDatabaseFailureTest, Init_NoCrashOnFailedRollback) {
2083   base::ScopedTempDir temp_dir;
2084   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
2085   base::FilePath database_path = temp_dir.GetPath().AppendASCII("test.db");
2086 
2087   // To cause an init failure, set the compatible version to be higher than the
2088   // current version (in reality, this could happen if, e.g., someone opened a
2089   // Canary-created profile with Chrome Stable.
2090   {
2091     sql::Database connection;
2092     sql::MetaTable meta_table;
2093     ASSERT_TRUE(connection.Open(database_path));
2094     ASSERT_TRUE(meta_table.Init(&connection, kCurrentVersionNumber + 1,
2095                                 kCurrentVersionNumber + 1));
2096   }
2097 
2098   // Now try to init the database with the file. The test succeeds if it does
2099   // not crash.
2100   LoginDatabase db(database_path, IsAccountStore(false));
2101   EXPECT_FALSE(db.Init());
2102 }
2103 
2104 // If the database version is from the future, it shouldn't be downgraded.
TEST(LoginDatabaseFutureLoginDatabase,ShouldNotDowngradeDatabaseVersion)2105 TEST(LoginDatabaseFutureLoginDatabase, ShouldNotDowngradeDatabaseVersion) {
2106   base::ScopedTempDir temp_dir;
2107   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
2108   base::FilePath database_path = temp_dir.GetPath().AppendASCII("test.db");
2109 
2110   const int kDBFutureVersion = kCurrentVersionNumber + 1000;
2111 
2112   {
2113     // Open a database with the current version.
2114     LoginDatabase db(database_path, IsAccountStore(false));
2115     EXPECT_TRUE(db.Init());
2116   }
2117   {
2118     // Overwrite the current version to be |kDBFutureVersion|
2119     sql::Database connection;
2120     sql::MetaTable meta_table;
2121     ASSERT_TRUE(connection.Open(database_path));
2122     // Set the DB version to be coming from the future.
2123     ASSERT_TRUE(meta_table.Init(&connection, kDBFutureVersion,
2124                                 kCompatibleVersionNumber));
2125     meta_table.SetVersionNumber(kDBFutureVersion);
2126   }
2127   {
2128     // Open the database again.
2129     LoginDatabase db(database_path, IsAccountStore(false));
2130     EXPECT_TRUE(db.Init());
2131   }
2132   {
2133     // The DB version should remain the same.
2134     sql::Database connection;
2135     sql::MetaTable meta_table;
2136     ASSERT_TRUE(connection.Open(database_path));
2137     ASSERT_TRUE(meta_table.Init(&connection, kDBFutureVersion,
2138                                 kCompatibleVersionNumber));
2139     EXPECT_EQ(kDBFutureVersion, meta_table.GetVersionNumber());
2140   }
2141 }
2142 
2143 // Test the migration from GetParam() version to kCurrentVersionNumber.
2144 class LoginDatabaseMigrationTest : public testing::TestWithParam<int> {
2145  protected:
SetUp()2146   void SetUp() override {
2147     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
2148     database_dump_location_ = database_dump_location_.AppendASCII("components")
2149                                   .AppendASCII("test")
2150                                   .AppendASCII("data")
2151                                   .AppendASCII("password_manager");
2152     database_path_ = temp_dir_.GetPath().AppendASCII("test.db");
2153     OSCryptMocker::SetUp();
2154   }
2155 
TearDown()2156   void TearDown() override { OSCryptMocker::TearDown(); }
2157 
2158   // Creates the database from |sql_file|.
CreateDatabase(base::StringPiece sql_file)2159   void CreateDatabase(base::StringPiece sql_file) {
2160     base::FilePath database_dump;
2161     ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &database_dump));
2162     database_dump =
2163         database_dump.Append(database_dump_location_).AppendASCII(sql_file);
2164     ASSERT_TRUE(
2165         sql::test::CreateDatabaseFromSQL(database_path_, database_dump));
2166   }
2167 
DestroyDatabase()2168   void DestroyDatabase() {
2169     if (!database_path_.empty())
2170       sql::Database::Delete(database_path_);
2171   }
2172 
2173   // Returns the database version for the test.
version() const2174   int version() const { return GetParam(); }
2175 
2176   // Actual test body.
2177   void MigrationToVCurrent(base::StringPiece sql_file);
2178 
2179   base::FilePath database_path_;
2180 
2181  private:
2182   base::FilePath database_dump_location_;
2183   base::ScopedTempDir temp_dir_;
2184   base::test::TaskEnvironment task_environment_;
2185 };
2186 
MigrationToVCurrent(base::StringPiece sql_file)2187 void LoginDatabaseMigrationTest::MigrationToVCurrent(
2188     base::StringPiece sql_file) {
2189   SCOPED_TRACE(testing::Message("Version file = ") << sql_file);
2190   CreateDatabase(sql_file);
2191   // Original date, in seconds since UTC epoch.
2192   std::vector<int64_t> date_created(
2193       GetColumnValuesFromDatabase<int64_t>(database_path_, "date_created"));
2194   if (version() == 10)  // Version 10 has a duplicate entry.
2195     ASSERT_EQ(4U, date_created.size());
2196   else
2197     ASSERT_EQ(3U, date_created.size());
2198   // Migration to version 8 performs changes dates to the new format.
2199   // So for versions less of equal to 8 create date should be in old
2200   // format before migration and in new format after.
2201   if (version() <= 8) {
2202     ASSERT_EQ(1402955745, date_created[0]);
2203     ASSERT_EQ(1402950000, date_created[1]);
2204     ASSERT_EQ(1402950000, date_created[2]);
2205   } else {
2206     ASSERT_EQ(13047429345000000, date_created[0]);
2207     ASSERT_EQ(13047423600000000, date_created[1]);
2208     ASSERT_EQ(13047423600000000, date_created[2]);
2209   }
2210 
2211   {
2212     // Assert that the database was successfully opened and updated
2213     // to current version.
2214     LoginDatabase db(database_path_, IsAccountStore(false));
2215     ASSERT_TRUE(db.Init());
2216 
2217     // Check that the contents was preserved.
2218     std::vector<std::unique_ptr<PasswordForm>> result;
2219     EXPECT_TRUE(db.GetAutofillableLogins(&result));
2220     EXPECT_THAT(result, UnorderedElementsAre(Pointee(IsGoogle1Account()),
2221                                              Pointee(IsGoogle2Account()),
2222                                              Pointee(IsBasicAuthAccount())));
2223 
2224     // Verifies that the final version can save all the appropriate fields.
2225     PasswordForm form;
2226     GenerateExamplePasswordForm(&form);
2227     // Add the same form twice to test the constraints in the database.
2228     EXPECT_EQ(AddChangeForForm(form), db.AddLogin(form));
2229     PasswordStoreChangeList list;
2230     list.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
2231     list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));
2232     EXPECT_EQ(list, db.AddLogin(form));
2233 
2234     result.clear();
2235     EXPECT_TRUE(db.GetLogins(PasswordStore::FormDigest(form), &result));
2236     ASSERT_EQ(1U, result.size());
2237     EXPECT_EQ(form, *result[0]);
2238     EXPECT_TRUE(db.RemoveLogin(form, /*changes=*/nullptr));
2239   }
2240   // New date, in microseconds since platform independent epoch.
2241   std::vector<int64_t> new_date_created(
2242       GetColumnValuesFromDatabase<int64_t>(database_path_, "date_created"));
2243   ASSERT_EQ(3U, new_date_created.size());
2244   if (version() <= 8) {
2245     // Check that the two dates match up.
2246     for (size_t i = 0; i < date_created.size(); ++i) {
2247       EXPECT_EQ(base::Time::FromInternalValue(new_date_created[i]),
2248                 base::Time::FromTimeT(date_created[i]));
2249     }
2250   } else {
2251     ASSERT_EQ(13047429345000000, new_date_created[0]);
2252     ASSERT_EQ(13047423600000000, new_date_created[1]);
2253     ASSERT_EQ(13047423600000000, new_date_created[2]);
2254   }
2255 
2256   if (version() >= 7 && version() <= 13) {
2257     // The "avatar_url" column first appeared in version 7. In version 14,
2258     // it was renamed to "icon_url". Migration from a version <= 13
2259     // to >= 14 should not break theses URLs.
2260     std::vector<std::string> urls(
2261         GetColumnValuesFromDatabase<std::string>(database_path_, "icon_url"));
2262 
2263     EXPECT_THAT(urls, UnorderedElementsAre("", "https://www.google.com/icon",
2264                                            "https://www.google.com/icon"));
2265   }
2266 
2267   {
2268     // On versions < 15 |kCompatibleVersionNumber| was set to 1, but
2269     // the migration should bring it to the correct value.
2270     sql::Database db;
2271     sql::MetaTable meta_table;
2272     ASSERT_TRUE(db.Open(database_path_));
2273     ASSERT_TRUE(
2274         meta_table.Init(&db, kCurrentVersionNumber, kCompatibleVersionNumber));
2275     EXPECT_EQ(password_manager::kCompatibleVersionNumber,
2276               meta_table.GetCompatibleVersionNumber());
2277   }
2278   DestroyDatabase();
2279 }
2280 
2281 // Tests the migration of the login database from version() to
2282 // kCurrentVersionNumber.
TEST_P(LoginDatabaseMigrationTest,MigrationToVCurrent)2283 TEST_P(LoginDatabaseMigrationTest, MigrationToVCurrent) {
2284   MigrationToVCurrent(base::StringPrintf("login_db_v%d.sql", version()));
2285 }
2286 
2287 class LoginDatabaseMigrationTestV9 : public LoginDatabaseMigrationTest {};
2288 
2289 // Tests migration from the alternative version #9, see crbug.com/423716.
TEST_P(LoginDatabaseMigrationTestV9,V9WithoutUseAdditionalAuthField)2290 TEST_P(LoginDatabaseMigrationTestV9, V9WithoutUseAdditionalAuthField) {
2291   ASSERT_EQ(9, version());
2292   MigrationToVCurrent("login_db_v9_without_use_additional_auth_field.sql");
2293 }
2294 
2295 class LoginDatabaseMigrationTestBroken : public LoginDatabaseMigrationTest {};
2296 
2297 // Test migrating certain databases with incorrect version.
2298 // http://crbug.com/295851
TEST_P(LoginDatabaseMigrationTestBroken,Broken)2299 TEST_P(LoginDatabaseMigrationTestBroken, Broken) {
2300   MigrationToVCurrent(base::StringPrintf("login_db_v%d_broken.sql", version()));
2301 }
2302 
2303 INSTANTIATE_TEST_SUITE_P(MigrationToVCurrent,
2304                          LoginDatabaseMigrationTest,
2305                          testing::Range(1, kCurrentVersionNumber + 1));
2306 INSTANTIATE_TEST_SUITE_P(MigrationToVCurrent,
2307                          LoginDatabaseMigrationTestV9,
2308                          testing::Values(9));
2309 INSTANTIATE_TEST_SUITE_P(MigrationToVCurrent,
2310                          LoginDatabaseMigrationTestBroken,
2311                          testing::Values(1, 2, 3, 24));
2312 
2313 class LoginDatabaseUndecryptableLoginsTest : public testing::Test {
2314  protected:
2315   LoginDatabaseUndecryptableLoginsTest() = default;
2316 
2317  public:
2318   LoginDatabaseUndecryptableLoginsTest(
2319       const LoginDatabaseUndecryptableLoginsTest&) = delete;
2320   LoginDatabaseUndecryptableLoginsTest& operator=(
2321       const LoginDatabaseUndecryptableLoginsTest&) = delete;
2322 
2323  protected:
SetUp()2324   void SetUp() override {
2325     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
2326     database_path_ = temp_dir_.GetPath().AppendASCII("test.db");
2327     OSCryptMocker::SetUp();
2328   }
2329 
TearDown()2330   void TearDown() override { OSCryptMocker::TearDown(); }
2331 
2332   // Generates login depending on |unique_string| and |origin| parameters and
2333   // adds it to the database. Changes encrypted password in the database if the
2334   // |should_be_corrupted| flag is active.
2335   PasswordForm AddDummyLogin(const std::string& unique_string,
2336                              const GURL& origin,
2337                              bool should_be_corrupted);
2338 
database_path() const2339   base::FilePath database_path() const { return database_path_; }
2340 
testing_local_state()2341   TestingPrefServiceSimple& testing_local_state() {
2342     return testing_local_state_;
2343   }
2344 
RunUntilIdle()2345   void RunUntilIdle() { task_environment_.RunUntilIdle(); }
2346 
2347  private:
2348   base::FilePath database_path_;
2349   base::ScopedTempDir temp_dir_;
2350   base::test::TaskEnvironment task_environment_;
2351   TestingPrefServiceSimple testing_local_state_;
2352 };
2353 
AddDummyLogin(const std::string & unique_string,const GURL & origin,bool should_be_corrupted)2354 PasswordForm LoginDatabaseUndecryptableLoginsTest::AddDummyLogin(
2355     const std::string& unique_string,
2356     const GURL& origin,
2357     bool should_be_corrupted) {
2358   // Create a dummy password form.
2359   const base::string16 unique_string16 = ASCIIToUTF16(unique_string);
2360   PasswordForm form;
2361   form.url = origin;
2362   form.username_element = unique_string16;
2363   form.username_value = unique_string16;
2364   form.password_element = unique_string16;
2365   form.password_value = unique_string16;
2366   form.signon_realm = origin.GetOrigin().spec();
2367 
2368   {
2369     LoginDatabase db(database_path(), IsAccountStore(false));
2370     EXPECT_TRUE(db.Init());
2371     EXPECT_EQ(db.AddLogin(form), AddChangeForForm(form));
2372   }
2373 
2374   if (should_be_corrupted) {
2375     sql::Database db;
2376     EXPECT_TRUE(db.Open(database_path()));
2377 
2378     // Change encrypted password in the database if the login should be
2379     // corrupted.
2380     std::string statement =
2381         "UPDATE logins SET password_value = password_value || 'trash' "
2382         "WHERE signon_realm = ? AND username_value = ?";
2383     sql::Statement s(db.GetCachedStatement(SQL_FROM_HERE, statement.c_str()));
2384     s.BindString(0, form.signon_realm);
2385     s.BindString(1, base::UTF16ToUTF8(form.username_value));
2386 
2387     EXPECT_TRUE(s.is_valid());
2388     EXPECT_TRUE(s.Run());
2389     EXPECT_EQ(db.GetLastChangeCount(), 1);
2390   }
2391 
2392   // When we retrieve the form from the store, |in_store| should be set.
2393   form.in_store = PasswordForm::Store::kProfileStore;
2394 
2395   return form;
2396 }
2397 
TEST_F(LoginDatabaseUndecryptableLoginsTest,DeleteUndecryptableLoginsTest)2398 TEST_F(LoginDatabaseUndecryptableLoginsTest, DeleteUndecryptableLoginsTest) {
2399   auto form1 = AddDummyLogin("foo1", GURL("https://foo1.com/"), false);
2400   auto form2 = AddDummyLogin("foo2", GURL("https://foo2.com/"), true);
2401   auto form3 = AddDummyLogin("foo3", GURL("https://foo3.com/"), false);
2402 
2403   LoginDatabase db(database_path(), IsAccountStore(false));
2404   base::HistogramTester histogram_tester;
2405   ASSERT_TRUE(db.Init());
2406 
2407 #if defined(OS_MAC)
2408   testing_local_state().registry()->RegisterTimePref(prefs::kPasswordRecovery,
2409                                                      base::Time());
2410   db.InitPasswordRecoveryUtil(std::make_unique<PasswordRecoveryUtilMac>(
2411       &testing_local_state(), base::ThreadTaskRunnerHandle::Get()));
2412 
2413   // Make sure that we can't get any logins when database is corrupted.
2414   std::vector<std::unique_ptr<PasswordForm>> result;
2415   EXPECT_FALSE(db.GetAutofillableLogins(&result));
2416   EXPECT_TRUE(result.empty());
2417 
2418   // Delete undecryptable logins and make sure we can get valid logins.
2419   EXPECT_EQ(DatabaseCleanupResult::kSuccess, db.DeleteUndecryptableLogins());
2420   EXPECT_TRUE(db.GetAutofillableLogins(&result));
2421   EXPECT_THAT(result, UnorderedElementsAre(Pointee(form1), Pointee(form3)));
2422 
2423   RunUntilIdle();
2424 
2425   // Make sure that password recovery pref is set.
2426   ASSERT_TRUE(testing_local_state().HasPrefPath(prefs::kPasswordRecovery));
2427 #else
2428   EXPECT_EQ(DatabaseCleanupResult::kSuccess, db.DeleteUndecryptableLogins());
2429 #endif
2430 
2431 // Check histograms.
2432 #if defined(OS_MAC)
2433   histogram_tester.ExpectUniqueSample("PasswordManager.CleanedUpPasswords", 1,
2434                                       1);
2435   histogram_tester.ExpectUniqueSample(
2436       "PasswordManager.DeleteUndecryptableLoginsReturnValue",
2437       metrics_util::DeleteCorruptedPasswordsResult::kSuccessPasswordsDeleted,
2438       1);
2439 #else
2440   EXPECT_TRUE(
2441       histogram_tester.GetAllSamples("PasswordManager.CleanedUpPasswords")
2442           .empty());
2443 #endif
2444 }
2445 
2446 #if defined(OS_MAC)
TEST_F(LoginDatabaseUndecryptableLoginsTest,PasswordRecoveryDisabledGetLogins)2447 TEST_F(LoginDatabaseUndecryptableLoginsTest,
2448        PasswordRecoveryDisabledGetLogins) {
2449   AddDummyLogin("foo1", GURL("https://foo1.com/"), false);
2450   AddDummyLogin("foo2", GURL("https://foo2.com/"), true);
2451 
2452   LoginDatabase db(database_path(), IsAccountStore(false));
2453   ASSERT_TRUE(db.Init());
2454 
2455   testing_local_state().registry()->RegisterTimePref(prefs::kPasswordRecovery,
2456                                                      base::Time());
2457   db.InitPasswordRecoveryUtil(std::make_unique<PasswordRecoveryUtilMac>(
2458       &testing_local_state(), base::ThreadTaskRunnerHandle::Get()));
2459 
2460   std::vector<std::unique_ptr<PasswordForm>> result;
2461   EXPECT_FALSE(db.GetAutofillableLogins(&result));
2462   EXPECT_TRUE(result.empty());
2463 
2464   RunUntilIdle();
2465   EXPECT_FALSE(testing_local_state().HasPrefPath(prefs::kPasswordRecovery));
2466 }
2467 
TEST_F(LoginDatabaseUndecryptableLoginsTest,KeychainLockedTest)2468 TEST_F(LoginDatabaseUndecryptableLoginsTest, KeychainLockedTest) {
2469   AddDummyLogin("foo1", GURL("https://foo1.com/"), false);
2470   AddDummyLogin("foo2", GURL("https://foo2.com/"), true);
2471 
2472   OSCryptMocker::SetBackendLocked(true);
2473   LoginDatabase db(database_path(), IsAccountStore(false));
2474   base::HistogramTester histogram_tester;
2475   ASSERT_TRUE(db.Init());
2476   EXPECT_EQ(DatabaseCleanupResult::kEncryptionUnavailable,
2477             db.DeleteUndecryptableLogins());
2478 
2479   EXPECT_TRUE(
2480       histogram_tester.GetAllSamples("PasswordManager.CleanedUpPasswords")
2481           .empty());
2482   histogram_tester.ExpectUniqueSample(
2483       "PasswordManager.DeleteUndecryptableLoginsReturnValue",
2484       metrics_util::DeleteCorruptedPasswordsResult::kEncryptionUnavailable, 1);
2485 }
2486 #endif  // defined(OS_MAC)
2487 
2488 // Test retrieving password forms by supplied password.
TEST_F(LoginDatabaseTest,GetLoginsByPassword)2489 TEST_F(LoginDatabaseTest, GetLoginsByPassword) {
2490   std::vector<std::unique_ptr<PasswordForm>> result;
2491   PrimaryKeyToFormMap key_to_form_map;
2492 
2493   const base::string16 duplicated_password =
2494       base::ASCIIToUTF16("duplicated_password");
2495 
2496   // Insert first logins.
2497   PasswordForm form1;
2498   GenerateExamplePasswordForm(&form1);
2499   form1.password_value = duplicated_password;
2500   PasswordStoreChangeList changes = db().AddLogin(form1);
2501   ASSERT_EQ(AddChangeForForm(form1), changes);
2502 
2503   // Check if there is exactly one form with this password.
2504   std::vector<std::unique_ptr<PasswordForm>> forms;
2505   EXPECT_TRUE(db().GetLoginsByPassword(duplicated_password, &forms));
2506   EXPECT_THAT(forms, UnorderedElementsAre(Pointee(form1)));
2507 
2508   // Insert another form with a different password for a different origin.
2509   PasswordForm form2;
2510   GenerateExamplePasswordForm(&form2);
2511   form2.url = GURL("https://myrandomsite.com/login.php");
2512   form2.signon_realm = form2.url.GetOrigin().spec();
2513   form2.password_value = base::ASCIIToUTF16("my-unique-random-password");
2514   changes = db().AddLogin(form2);
2515   ASSERT_EQ(AddChangeForForm(form2), changes);
2516 
2517   // Check if there is still exactly one form with the duplicated_password.
2518   EXPECT_TRUE(db().GetLoginsByPassword(duplicated_password, &forms));
2519   EXPECT_THAT(forms, UnorderedElementsAre(Pointee(form1)));
2520 
2521   // Insert another form with the target password for a different origin.
2522   PasswordForm form3;
2523   GenerateExamplePasswordForm(&form3);
2524   form3.url = GURL("https://myrandomsite1.com/login.php");
2525   form3.signon_realm = form3.url.GetOrigin().spec();
2526   form3.password_value = duplicated_password;
2527   changes = db().AddLogin(form3);
2528   ASSERT_EQ(AddChangeForForm(form3), changes);
2529 
2530   // Check if there are exactly two forms with the duplicated_password.
2531   EXPECT_TRUE(db().GetLoginsByPassword(duplicated_password, &forms));
2532   EXPECT_THAT(forms, UnorderedElementsAre(Pointee(form1), Pointee(form3)));
2533 }
2534 
2535 // Test encrypted passwords are present in add change lists.
TEST_F(LoginDatabaseTest,EncryptedPasswordAdd)2536 TEST_F(LoginDatabaseTest, EncryptedPasswordAdd) {
2537   PasswordForm form;
2538   form.url = GURL("http://0.com");
2539   form.signon_realm = "http://www.example.com/";
2540   form.action = GURL("http://www.example.com/action");
2541   form.password_element = base::ASCIIToUTF16("pwd");
2542   form.password_value = base::ASCIIToUTF16("example");
2543   password_manager::PasswordStoreChangeList changes = db().AddLogin(form);
2544   ASSERT_EQ(1u, changes.size());
2545   ASSERT_FALSE(changes[0].form().encrypted_password.empty());
2546 }
2547 
2548 // Test encrypted passwords are present in add change lists, when the password
2549 // is already in the DB.
TEST_F(LoginDatabaseTest,EncryptedPasswordAddWithReplaceSemantics)2550 TEST_F(LoginDatabaseTest, EncryptedPasswordAddWithReplaceSemantics) {
2551   PasswordForm form;
2552   form.url = GURL("http://0.com");
2553   form.signon_realm = "http://www.example.com/";
2554   form.action = GURL("http://www.example.com/action");
2555   form.password_element = base::ASCIIToUTF16("pwd");
2556   form.password_value = base::ASCIIToUTF16("example");
2557 
2558   ignore_result(db().AddLogin(form));
2559 
2560   form.password_value = base::ASCIIToUTF16("secret");
2561 
2562   password_manager::PasswordStoreChangeList changes = db().AddLogin(form);
2563   ASSERT_EQ(2u, changes.size());
2564   ASSERT_EQ(password_manager::PasswordStoreChange::Type::ADD,
2565             changes[1].type());
2566   ASSERT_FALSE(changes[1].form().encrypted_password.empty());
2567 }
2568 
2569 // Test encrypted passwords are present in update change lists.
TEST_F(LoginDatabaseTest,EncryptedPasswordUpdate)2570 TEST_F(LoginDatabaseTest, EncryptedPasswordUpdate) {
2571   PasswordForm form;
2572   form.url = GURL("http://0.com");
2573   form.signon_realm = "http://www.example.com/";
2574   form.action = GURL("http://www.example.com/action");
2575   form.password_element = base::ASCIIToUTF16("pwd");
2576   form.password_value = base::ASCIIToUTF16("example");
2577 
2578   ignore_result(db().AddLogin(form));
2579 
2580   form.password_value = base::ASCIIToUTF16("secret");
2581 
2582   password_manager::PasswordStoreChangeList changes = db().UpdateLogin(form);
2583   ASSERT_EQ(1u, changes.size());
2584   ASSERT_FALSE(changes[0].form().encrypted_password.empty());
2585 }
2586 
2587 // Test encrypted passwords are present when retrieving from DB.
TEST_F(LoginDatabaseTest,GetLoginsEncryptedPassword)2588 TEST_F(LoginDatabaseTest, GetLoginsEncryptedPassword) {
2589   PasswordForm form;
2590   form.url = GURL("http://0.com");
2591   form.signon_realm = "http://www.example.com/";
2592   form.action = GURL("http://www.example.com/action");
2593   form.password_element = base::ASCIIToUTF16("pwd");
2594   form.password_value = base::ASCIIToUTF16("example");
2595   password_manager::PasswordStoreChangeList changes = db().AddLogin(form);
2596   ASSERT_EQ(1u, changes.size());
2597   ASSERT_FALSE(changes[0].form().encrypted_password.empty());
2598 
2599   std::vector<std::unique_ptr<PasswordForm>> forms;
2600   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &forms));
2601 
2602   ASSERT_EQ(1U, forms.size());
2603   ASSERT_FALSE(forms[0]->encrypted_password.empty());
2604 }
2605 
2606 class LoginDatabaseForAccountStoreTest : public testing::Test {
2607  protected:
SetUp()2608   void SetUp() override {
2609     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
2610     file_ = temp_dir_.GetPath().AppendASCII("TestMetadataStoreMacDatabase");
2611     OSCryptMocker::SetUp();
2612 
2613     db_ = std::make_unique<LoginDatabase>(file_, IsAccountStore(true));
2614     ASSERT_TRUE(db_->Init());
2615   }
2616 
TearDown()2617   void TearDown() override { OSCryptMocker::TearDown(); }
2618 
db()2619   LoginDatabase& db() { return *db_; }
2620 
2621   base::ScopedTempDir temp_dir_;
2622   base::FilePath file_;
2623   std::unique_ptr<LoginDatabase> db_;
2624   base::test::TaskEnvironment task_environment_;
2625 };
2626 
TEST_F(LoginDatabaseForAccountStoreTest,AddLogins)2627 TEST_F(LoginDatabaseForAccountStoreTest, AddLogins) {
2628   PasswordForm form;
2629   GenerateExamplePasswordForm(&form);
2630 
2631   PasswordStoreChangeList changes = db().AddLogin(form);
2632   ASSERT_EQ(1U, changes.size());
2633   EXPECT_EQ(PasswordForm::Store::kAccountStore, changes[0].form().in_store);
2634 }
2635 
2636 }  // namespace password_manager
2637