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