Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(475)

Side by Side Diff: components/password_manager/core/browser/login_database.cc

Issue 2126713006: Refactor LoginDatabase migration (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix some tests Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/password_manager/core/browser/login_database.h" 5 #include "components/password_manager/core/browser/login_database.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 #include <algorithm> 9 #include <algorithm>
10 #include <limits> 10 #include <limits>
11 #include <map> 11 #include <map>
12 #include <utility> 12 #include <utility>
13 13
14 #include "base/bind.h" 14 #include "base/bind.h"
15 #include "base/files/file_path.h" 15 #include "base/files/file_path.h"
16 #include "base/logging.h" 16 #include "base/logging.h"
17 #include "base/macros.h" 17 #include "base/macros.h"
18 #include "base/metrics/histogram_macros.h" 18 #include "base/metrics/histogram_macros.h"
19 #include "base/metrics/sparse_histogram.h" 19 #include "base/metrics/sparse_histogram.h"
20 #include "base/numerics/safe_conversions.h"
20 #include "base/pickle.h" 21 #include "base/pickle.h"
21 #include "base/stl_util.h" 22 #include "base/stl_util.h"
22 #include "base/strings/string_util.h" 23 #include "base/strings/string_util.h"
23 #include "base/strings/stringprintf.h" 24 #include "base/strings/stringprintf.h"
24 #include "base/time/time.h" 25 #include "base/time/time.h"
25 #include "build/build_config.h" 26 #include "build/build_config.h"
26 #include "components/autofill/core/common/password_form.h" 27 #include "components/autofill/core/common/password_form.h"
27 #include "components/password_manager/core/browser/affiliation_utils.h" 28 #include "components/password_manager/core/browser/affiliation_utils.h"
28 #include "components/password_manager/core/browser/password_manager_client.h" 29 #include "components/password_manager/core/browser/password_manager_client.h"
29 #include "components/password_manager/core/browser/password_manager_metrics_util .h" 30 #include "components/password_manager/core/browser/password_manager_metrics_util .h"
31 #include "components/password_manager/core/browser/sql_table_builder.h"
30 #include "google_apis/gaia/gaia_auth_util.h" 32 #include "google_apis/gaia/gaia_auth_util.h"
31 #include "google_apis/gaia/gaia_urls.h" 33 #include "google_apis/gaia/gaia_urls.h"
32 #include "sql/connection.h" 34 #include "sql/connection.h"
33 #include "sql/statement.h" 35 #include "sql/statement.h"
34 #include "sql/transaction.h" 36 #include "sql/transaction.h"
35 #include "url/origin.h" 37 #include "url/origin.h"
36 #include "url/url_constants.h" 38 #include "url/url_constants.h"
37 39
38 using autofill::PasswordForm; 40 using autofill::PasswordForm;
39 41
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 COLUMN_PASSWORD_TYPE, 86 COLUMN_PASSWORD_TYPE,
85 COLUMN_POSSIBLE_USERNAMES, 87 COLUMN_POSSIBLE_USERNAMES,
86 COLUMN_TIMES_USED, 88 COLUMN_TIMES_USED,
87 COLUMN_FORM_DATA, 89 COLUMN_FORM_DATA,
88 COLUMN_DATE_SYNCED, 90 COLUMN_DATE_SYNCED,
89 COLUMN_DISPLAY_NAME, 91 COLUMN_DISPLAY_NAME,
90 COLUMN_ICON_URL, 92 COLUMN_ICON_URL,
91 COLUMN_FEDERATION_URL, 93 COLUMN_FEDERATION_URL,
92 COLUMN_SKIP_ZERO_CLICK, 94 COLUMN_SKIP_ZERO_CLICK,
93 COLUMN_GENERATION_UPLOAD_STATUS, 95 COLUMN_GENERATION_UPLOAD_STATUS,
96 COLUMN_NUM // Keep this last.
94 }; 97 };
95 98
96 enum class HistogramSize { SMALL, LARGE }; 99 enum class HistogramSize { SMALL, LARGE };
97 100
98 // An enum for UMA reporting. Add values to the end only. 101 // An enum for UMA reporting. Add values to the end only.
99 enum DatabaseInitError { 102 enum DatabaseInitError {
100 INIT_OK, 103 INIT_OK,
101 OPEN_FILE_ERROR, 104 OPEN_FILE_ERROR,
102 START_TRANSACTION_ERROR, 105 START_TRANSACTION_ERROR,
103 META_TABLE_INIT_ERROR, 106 META_TABLE_INIT_ERROR,
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
328 LogNumberOfAccountsReusingPassword( 331 LogNumberOfAccountsReusingPassword(
329 source_realm_kind + ".OnAnyRealmWithDifferentHost", 332 source_realm_kind + ".OnAnyRealmWithDifferentHost",
330 num_accounts_for_different_domain[SCHEME_HTTP] + 333 num_accounts_for_different_domain[SCHEME_HTTP] +
331 num_accounts_for_different_domain[SCHEME_HTTPS], 334 num_accounts_for_different_domain[SCHEME_HTTPS],
332 HistogramSize::LARGE); 335 HistogramSize::LARGE);
333 } 336 }
334 } 337 }
335 } 338 }
336 } 339 }
337 340
338 // Creates a table named |table_name| using our current schema. 341 // Teaches |builder| about the different DB schemes in different versions.
339 bool CreateNewTable(sql::Connection* db, 342 void InitializeBuilder(SQLTableBuilder* builder) {
340 const char* table_name, 343 // Versions 0 and 1, which are the same.
341 const char* extra_columns) { 344 builder->AddColumnToUniqueKey("origin_url", "VARCHAR NOT NULL");
342 std::string query = base::StringPrintf( 345 builder->AddColumn("action_url", "VARCHAR");
343 "CREATE TABLE %s (" 346 builder->AddColumnToUniqueKey("username_element", "VARCHAR");
344 "origin_url VARCHAR NOT NULL, " 347 builder->AddColumnToUniqueKey("username_value", "VARCHAR");
345 "action_url VARCHAR, " 348 builder->AddColumnToUniqueKey("password_element", "VARCHAR");
346 "username_element VARCHAR, " 349 builder->AddColumn("password_value", "BLOB");
347 "username_value VARCHAR, " 350 builder->AddColumn("submit_element", "VARCHAR");
348 "password_element VARCHAR, " 351 builder->AddColumnToUniqueKey("signon_realm", "VARCHAR NOT NULL");
349 "password_value BLOB, " 352 builder->AddColumn("ssl_valid", "INTEGER NOT NULL");
350 "submit_element VARCHAR, " 353 builder->AddColumn("preferred", "INTEGER NOT NULL");
351 "signon_realm VARCHAR NOT NULL," 354 builder->AddColumn("date_created", "INTEGER NOT NULL");
352 "ssl_valid INTEGER NOT NULL," 355 builder->AddColumn("blacklisted_by_user", "INTEGER NOT NULL");
353 "preferred INTEGER NOT NULL," 356 builder->AddColumn("scheme", "INTEGER NOT NULL");
354 "date_created INTEGER NOT NULL," 357 builder->SealVersion();
355 "blacklisted_by_user INTEGER NOT NULL," 358 unsigned version = builder->SealVersion();
356 "scheme INTEGER NOT NULL," 359 DCHECK_EQ(1u, version);
357 "password_type INTEGER," 360
358 "possible_usernames BLOB," 361 // Version 2.
359 "times_used INTEGER," 362 builder->AddColumn("password_type", "INTEGER");
360 "form_data BLOB," 363 builder->AddColumn("possible_usernames", "BLOB");
361 "date_synced INTEGER," 364 version = builder->SealVersion();
362 "display_name VARCHAR," 365 DCHECK_EQ(2u, version);
363 "icon_url VARCHAR," 366
364 "federation_url VARCHAR," 367 // Version 3.
365 "skip_zero_click INTEGER," 368 builder->AddColumn("times_used", "INTEGER");
366 "%s" 369 version = builder->SealVersion();
367 "UNIQUE (origin_url, username_element, username_value, " 370 DCHECK_EQ(3u, version);
368 "password_element, signon_realm))", 371
369 table_name, extra_columns); 372 // Version 4.
370 return db->Execute(query.c_str()); 373 builder->AddColumn("form_data", "BLOB");
374 version = builder->SealVersion();
375 DCHECK_EQ(4u, version);
376
377 // Version 5.
378 builder->AddColumn("use_additional_auth", "INTEGER");
379 version = builder->SealVersion();
380 DCHECK_EQ(5u, version);
381
382 // Version 6.
383 builder->AddColumn("date_synced", "INTEGER");
384 version = builder->SealVersion();
385 DCHECK_EQ(6u, version);
386
387 // Version 7.
388 builder->AddColumn("display_name", "VARCHAR");
389 builder->AddColumn("avatar_url", "VARCHAR");
390 builder->AddColumn("federation_url", "VARCHAR");
391 builder->AddColumn("is_zero_click", "INTEGER");
392 version = builder->SealVersion();
393 DCHECK_EQ(7u, version);
394
395 // Version 8.
396 builder->SealVersion();
397 // Version 9.
398 version = builder->SealVersion();
399 // Version 10.
400 builder->DropColumn("use_additional_auth");
401 version = builder->SealVersion();
402 DCHECK_EQ(10u, version);
403
404 // Version 11.
405 builder->RenameColumn("is_zero_click", "skip_zero_click");
406 version = builder->SealVersion();
407 DCHECK_EQ(11u, version);
408
409 // Version 12.
410 builder->AddColumn("generation_upload_status", "INTEGER");
411 version = builder->SealVersion();
412 DCHECK_EQ(12u, version);
413
414 // Version 13.
415 builder->SealVersion();
416 // Version 14.
417 builder->RenameColumn("avatar_url", "icon_url");
418 version = builder->SealVersion();
419 DCHECK_EQ(14u, version);
420
421 // Version 15.
422 builder->SealVersion();
423 // Version 16.
424 builder->SealVersion();
425 // Version 17.
426 version = builder->SealVersion();
427 DCHECK_EQ(17u, version);
428
429 DCHECK_EQ(static_cast<size_t>(COLUMN_NUM), builder->NumberOfColumns())
430 << "Adjust LoginTableColumns if you change column definitions here.";
371 } 431 }
372 432
373 bool CreateIndexOnSignonRealm(sql::Connection* db, const char* table_name) { 433 // Call this after having called InitializeBuilder, to migrate the database from
374 std::string query = base::StringPrintf( 434 // the current version to kCurrentVersionNumber.
375 "CREATE INDEX logins_signon ON %s (signon_realm)", table_name); 435 bool MigrateLogins(unsigned current_version,
376 return db->Execute(query.c_str()); 436 SQLTableBuilder* builder,
437 sql::Connection* db) {
438 if (!builder->MigrateFrom(current_version, db))
439 return false;
440
441 // Data changes, not covered by the schema migration above.
442 if (current_version <= 8) {
443 sql::Statement fix_time_format;
444 fix_time_format.Assign(db->GetCachedStatement(
445 SQL_FROM_HERE,
446 "UPDATE logins SET date_created = (date_created * ?) + ?"));
447 fix_time_format.BindInt64(0, base::Time::kMicrosecondsPerSecond);
448 fix_time_format.BindInt64(1, base::Time::kTimeTToMicrosecondsOffset);
449 if (!fix_time_format.Run())
450 return false;
451 }
452
453 if (current_version <= 16) {
454 sql::Statement reset_zero_click;
455 reset_zero_click.Assign(db->GetCachedStatement(
456 SQL_FROM_HERE, "UPDATE logins SET skip_zero_click = 1"));
457 if (!reset_zero_click.Run())
458 return false;
459 }
460
461 return true;
462 }
463
464 // Because of https://crbug.com/295851, some early version numbers might be
465 // wrong. This function detects that and fixes the version.
466 bool FixVersionIfNeeded(sql::Connection* db, int* current_version) {
467 if (*current_version == 1) {
468 int extra_columns = 0;
469 if (db->DoesColumnExist("logins", "password_type"))
470 ++extra_columns;
471 if (db->DoesColumnExist("logins", "possible_usernames"))
472 ++extra_columns;
473 if (extra_columns == 2) {
474 *current_version = 2;
475 } else if (extra_columns == 1) {
476 // If this is https://crbug.com/295851 then either both columns exist
477 // or none.
478 return false;
479 }
480 }
481 if (*current_version == 2) {
482 if (db->DoesColumnExist("logins", "times_used"))
483 *current_version = 3;
484 }
485 if (*current_version == 3) {
486 if (db->DoesColumnExist("logins", "form_data"))
487 *current_version = 4;
488 }
489 return true;
490 }
491
492 // Generates the string "(?,?,...,?)" with |count| repetitions of "?".
493 std::string GeneratePlaceholders(size_t count) {
494 std::string result(2 * count + 1, ',');
495 result.front() = '(';
496 result.back() = ')';
497 for (size_t i = 1; i < 2 * count + 1; i += 2) {
498 result[i] = '?';
499 }
500 return result;
377 } 501 }
378 502
379 } // namespace 503 } // namespace
380 504
381 LoginDatabase::LoginDatabase(const base::FilePath& db_path) 505 LoginDatabase::LoginDatabase(const base::FilePath& db_path)
382 : db_path_(db_path), clear_password_values_(false) { 506 : db_path_(db_path), clear_password_values_(false) {
383 } 507 }
384 508
385 LoginDatabase::~LoginDatabase() { 509 LoginDatabase::~LoginDatabase() {
386 } 510 }
(...skipping 30 matching lines...) Expand all
417 } 541 }
418 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) { 542 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
419 LogDatabaseInitError(INCOMPATIBLE_VERSION); 543 LogDatabaseInitError(INCOMPATIBLE_VERSION);
420 LOG(ERROR) << "Password store database is too new, kCurrentVersionNumber=" 544 LOG(ERROR) << "Password store database is too new, kCurrentVersionNumber="
421 << kCurrentVersionNumber << ", GetCompatibleVersionNumber=" 545 << kCurrentVersionNumber << ", GetCompatibleVersionNumber="
422 << meta_table_.GetCompatibleVersionNumber(); 546 << meta_table_.GetCompatibleVersionNumber();
423 db_.Close(); 547 db_.Close();
424 return false; 548 return false;
425 } 549 }
426 550
427 // Initialize the tables. 551 SQLTableBuilder builder;
428 if (!InitLoginsTable()) { 552 InitializeBuilder(&builder);
429 LogDatabaseInitError(INIT_LOGINS_ERROR); 553
430 LOG(ERROR) << "Unable to initialize the logins table."; 554 // Initialize the cached strings.
dvadym 2016/07/12 14:48:58 Nit: it looks like all next strings can be moved i
vabr (Chromium) 2016/07/13 09:12:13 Done.
431 db_.Close(); 555 std::string all_column_names = builder.ListAllNames();
432 return false; 556 std::string right_amount_of_placeholders =
557 GeneratePlaceholders(builder.NumberOfColumns());
558 std::string all_unique_key_column_names = builder.ListAllUniqueKeyNames();
559 std::string all_nonunique_key_column_names =
560 builder.ListAllNonuniqueKeyNames();
561
562 // This method may be called multiple times, if Chrome switches backends and
563 // LoginDatabase::DeleteAndRecreateDatabaseFile ends up being called. In those
564 // case do not recompute the SQL statements, because they would end up the
565 // same.
566 if (add_statement_.empty()) {
dvadym 2016/07/12 14:48:58 Nit: I'd prefer to extract initialization *stateme
vabr (Chromium) 2016/07/13 09:12:13 Done.
567 add_statement_ = "INSERT INTO logins (" + all_column_names + ") VALUES " +
568 right_amount_of_placeholders;
569 DCHECK(add_replace_statement_.empty());
570 add_replace_statement_ = "INSERT OR REPLACE INTO logins (" +
571 all_column_names + ") VALUES " +
572 right_amount_of_placeholders;
573 DCHECK(update_statement_.empty());
574 update_statement_ = "UPDATE OR REPLACE logins SET " +
575 all_nonunique_key_column_names + " WHERE " +
576 all_unique_key_column_names;
577 DCHECK(delete_statement_.empty());
578 delete_statement_ =
579 "DELETE FROM logins WHERE " + all_unique_key_column_names;
580 DCHECK(autosignin_statement_.empty());
581 autosignin_statement_ = "SELECT " + all_column_names +
582 " FROM logins "
583 "WHERE skip_zero_click = 0 ORDER BY origin_url";
584 DCHECK(get_statement_.empty());
585 get_statement_ = "SELECT " + all_column_names +
586 " FROM logins "
587 "WHERE signon_realm == ?";
588 std::string psl_statement = "OR signon_realm REGEXP ? ";
589 std::string federated_statement =
590 "OR (signon_realm LIKE ? AND password_type == 2) ";
591 DCHECK(get_statement_psl_.empty());
592 get_statement_psl_ = get_statement_ + psl_statement;
593 DCHECK(get_statement_federated_.empty());
594 get_statement_federated_ = get_statement_ + federated_statement;
595 DCHECK(get_statement_psl_federated_.empty());
596 get_statement_psl_federated_ =
597 get_statement_ + psl_statement + federated_statement;
598 DCHECK(created_statement_.empty());
599 created_statement_ =
600 "SELECT " + all_column_names +
601 " FROM logins WHERE date_created >= ? AND date_created < "
602 "? ORDER BY origin_url";
603 DCHECK(synced_statement_.empty());
604 synced_statement_ = "SELECT " + all_column_names +
605 " FROM logins WHERE date_synced >= ? AND date_synced < "
606 "? ORDER BY origin_url";
607 DCHECK(blacklisted_statement_.empty());
608 blacklisted_statement_ =
609 "SELECT " + all_column_names +
610 " FROM logins WHERE blacklisted_by_user == ? ORDER BY origin_url";
611 DCHECK(encrypted_statement_.empty());
612 encrypted_statement_ = "SELECT password_value FROM logins WHERE " +
613 all_unique_key_column_names;
433 } 614 }
615
616 if (!db_.DoesTableExist("logins")) {
617 if (!builder.CreateTable(&db_)) {
618 VLOG(0) << "Failed to create the 'logins' table";
619 db_.Close();
620 return false;
621 }
622 }
623
434 stats_table_.Init(&db_); 624 stats_table_.Init(&db_);
435 625
626 int current_version = meta_table_.GetVersionNumber();
627 bool migration_success = FixVersionIfNeeded(&db_, &current_version);
628 DCHECK_LE(current_version, kCurrentVersionNumber);
629
436 // If the file on disk is an older database version, bring it up to date. 630 // If the file on disk is an older database version, bring it up to date.
437 if (meta_table_.GetVersionNumber() < kCurrentVersionNumber && 631 if (migration_success && current_version < kCurrentVersionNumber) {
438 !MigrateOldVersionsAsNeeded()) { 632 migration_success = MigrateLogins(
633 base::checked_cast<unsigned>(current_version), &builder, &db_);
634 }
635 if (migration_success && current_version <= 15) {
636 migration_success = stats_table_.MigrateToVersion(16);
637 }
638 if (migration_success) {
639 meta_table_.SetCompatibleVersionNumber(kCompatibleVersionNumber);
640 meta_table_.SetVersionNumber(kCurrentVersionNumber);
641 } else {
439 LogDatabaseInitError(MIGRATION_ERROR); 642 LogDatabaseInitError(MIGRATION_ERROR);
440 UMA_HISTOGRAM_SPARSE_SLOWLY("PasswordManager.LoginDatabaseFailedVersion", 643 UMA_HISTOGRAM_SPARSE_SLOWLY("PasswordManager.LoginDatabaseFailedVersion",
441 meta_table_.GetVersionNumber()); 644 meta_table_.GetVersionNumber());
442 LOG(ERROR) << "Unable to migrate database from " 645 LOG(ERROR) << "Unable to migrate database from "
443 << meta_table_.GetVersionNumber() << " to " 646 << meta_table_.GetVersionNumber() << " to "
444 << kCurrentVersionNumber; 647 << kCurrentVersionNumber;
445 db_.Close(); 648 db_.Close();
446 return false; 649 return false;
447 } 650 }
448 651
449 if (!stats_table_.CreateTableIfNecessary()) { 652 if (!stats_table_.CreateTableIfNecessary()) {
450 LogDatabaseInitError(INIT_STATS_ERROR); 653 LogDatabaseInitError(INIT_STATS_ERROR);
451 LOG(ERROR) << "Unable to create the stats table."; 654 LOG(ERROR) << "Unable to create the stats table.";
452 db_.Close(); 655 db_.Close();
453 return false; 656 return false;
454 } 657 }
455 658
456 if (!transaction.Commit()) { 659 if (!transaction.Commit()) {
457 LogDatabaseInitError(COMMIT_TRANSACTION_ERROR); 660 LogDatabaseInitError(COMMIT_TRANSACTION_ERROR);
458 LOG(ERROR) << "Unable to commit a transaction."; 661 LOG(ERROR) << "Unable to commit a transaction.";
459 db_.Close(); 662 db_.Close();
460 return false; 663 return false;
461 } 664 }
462 665
463 LogDatabaseInitError(INIT_OK); 666 LogDatabaseInitError(INIT_OK);
464 return true; 667 return true;
465 } 668 }
466 669
467 bool LoginDatabase::MigrateOldVersionsAsNeeded() {
468 const int original_version = meta_table_.GetVersionNumber();
469 switch (original_version) {
470 case 1:
471 // Column could exist because of https://crbug.com/295851
472 if (!db_.DoesColumnExist("logins", "password_type") &&
473 !db_.Execute("ALTER TABLE logins "
474 "ADD COLUMN password_type INTEGER")) {
475 return false;
476 }
477 if (!db_.DoesColumnExist("logins", "possible_usernames") &&
478 !db_.Execute("ALTER TABLE logins "
479 "ADD COLUMN possible_usernames BLOB")) {
480 return false;
481 }
482 // Fall through.
483 case 2:
484 // Column could exist because of https://crbug.com/295851
485 if (!db_.DoesColumnExist("logins", "times_used") &&
486 !db_.Execute("ALTER TABLE logins ADD COLUMN times_used INTEGER")) {
487 return false;
488 }
489 // Fall through.
490 case 3:
491 // Column could exist because of https://crbug.com/295851
492 if (!db_.DoesColumnExist("logins", "form_data") &&
493 !db_.Execute("ALTER TABLE logins ADD COLUMN form_data BLOB")) {
494 return false;
495 }
496 // Fall through.
497 case 4:
498 if (!db_.Execute(
499 "ALTER TABLE logins ADD COLUMN use_additional_auth INTEGER")) {
500 return false;
501 }
502 // Fall through.
503 case 5:
504 if (!db_.Execute("ALTER TABLE logins ADD COLUMN date_synced INTEGER")) {
505 return false;
506 }
507 // Fall through.
508 case 6:
509 if (!db_.Execute("ALTER TABLE logins ADD COLUMN display_name VARCHAR") ||
510 !db_.Execute("ALTER TABLE logins ADD COLUMN avatar_url VARCHAR") ||
511 !db_.Execute("ALTER TABLE logins "
512 "ADD COLUMN federation_url VARCHAR") ||
513 !db_.Execute("ALTER TABLE logins ADD COLUMN is_zero_click INTEGER")) {
514 return false;
515 }
516 // Fall through.
517 case 7: {
518 // Keep version 8 around even though no changes are made. See
519 // crbug.com/423716 for context.
520 // Fall through.
521 }
522 case 8: {
523 sql::Statement s;
524 s.Assign(db_.GetCachedStatement(SQL_FROM_HERE,
525 "UPDATE logins SET "
526 "date_created = "
527 "(date_created * ?) + ?"));
528 s.BindInt64(0, base::Time::kMicrosecondsPerSecond);
529 s.BindInt64(1, base::Time::kTimeTToMicrosecondsOffset);
530 if (!s.Run())
531 return false;
532 // Fall through.
533 }
534 case 9: {
535 // Remove use_additional_auth column from database schema
536 // crbug.com/423716 for context.
537 std::string fields_to_copy =
538 "origin_url, action_url, username_element, username_value, "
539 "password_element, password_value, submit_element, "
540 "signon_realm, ssl_valid, preferred, date_created, "
541 "blacklisted_by_user, scheme, password_type, possible_usernames, "
542 "times_used, form_data, date_synced, display_name, avatar_url, "
543 "federation_url, is_zero_click";
544 auto copy_data_query =
545 [&fields_to_copy](const std::string& from, const std::string& to) {
546 return "INSERT INTO " + to + " SELECT " + fields_to_copy + " FROM " +
547 from;
548 };
549
550 if (!db_.Execute(("CREATE TEMPORARY TABLE logins_data(" + fields_to_copy +
551 ")").c_str()) ||
552 !db_.Execute(copy_data_query("logins", "logins_data").c_str()) ||
553 !db_.Execute("DROP TABLE logins") ||
554 !db_.Execute(
555 ("CREATE TABLE logins(" + fields_to_copy + ")").c_str()) ||
556 !db_.Execute(copy_data_query("logins_data", "logins").c_str()) ||
557 !db_.Execute("DROP TABLE logins_data") ||
558 !CreateIndexOnSignonRealm(&db_, "logins")) {
559 return false;
560 }
561 // Fall through.
562 }
563 case 10: {
564 // Rename is_zero_click -> skip_zero_click. Note that previous versions
565 // may have incorrectly used a 6-column key (origin_url, username_element,
566 // username_value, password_element, signon_realm, submit_element).
567 // In that case, this step also restores the correct 5-column key;
568 // that is, the above without "submit_element".
569 const char copy_query[] = "INSERT OR REPLACE INTO logins_new SELECT "
570 "origin_url, action_url, username_element, username_value, "
571 "password_element, password_value, submit_element, signon_realm, "
572 "ssl_valid, preferred, date_created, blacklisted_by_user, scheme, "
573 "password_type, possible_usernames, times_used, form_data, "
574 "date_synced, display_name, avatar_url, federation_url, is_zero_click"
575 " FROM logins";
576 if (!CreateNewTable(&db_, "logins_new", "") ||
577 !db_.Execute(copy_query) ||
578 !db_.Execute("DROP TABLE logins") ||
579 !db_.Execute("ALTER TABLE logins_new RENAME TO logins") ||
580 !CreateIndexOnSignonRealm(&db_, "logins")) {
581 return false;
582 }
583 // Fall through.
584 }
585 case 11:
586 if (!db_.Execute(
587 "ALTER TABLE logins ADD COLUMN "
588 "generation_upload_status INTEGER"))
589 return false;
590 // Fall through.
591 case 12:
592 // The stats table was added. Nothing to do really.
593 // Fall through.
594 case 13: {
595 // Rename avatar_url -> icon_url. Note that if the original version was
596 // at most 10, this renaming would have already happened in step 10,
597 // as |CreateNewTable| would create a table with the new column name.
598 if (original_version > 10) {
599 const char copy_query[] = "INSERT OR REPLACE INTO logins_new SELECT "
600 "origin_url, action_url, username_element, username_value, "
601 "password_element, password_value, submit_element, signon_realm, "
602 "ssl_valid, preferred, date_created, blacklisted_by_user, scheme, "
603 "password_type, possible_usernames, times_used, form_data, "
604 "date_synced, display_name, avatar_url, federation_url, "
605 "skip_zero_click, generation_upload_status FROM logins";
606 if (!CreateNewTable(
607 &db_, "logins_new", "generation_upload_status INTEGER,") ||
608 !db_.Execute(copy_query) ||
609 !db_.Execute("DROP TABLE logins") ||
610 !db_.Execute("ALTER TABLE logins_new RENAME TO logins") ||
611 !CreateIndexOnSignonRealm(&db_, "logins")) {
612 return false;
613 }
614 }
615 // Fall through.
616 }
617 case 14:
618 // No change of schema. Version 15 was introduced to force all databases
619 // through an otherwise no-op migration process that will, however, now
620 // correctly set the 'compatible version number'. Previously, it was
621 // always being set to (and forever left at) version 1.
622 meta_table_.SetCompatibleVersionNumber(kCompatibleVersionNumber);
623 case 15:
624 // Recreate the statistics.
625 if (!stats_table_.MigrateToVersion(16))
626 return false;
627 case 16: {
628 // No change in scheme: just disable auto sign-in by default in
629 // preparation to launch the credential management API.
630 if (!db_.Execute("UPDATE logins SET skip_zero_click = 1"))
631 return false;
632 // Fall through.
633 }
634
635 // -------------------------------------------------------------------------
636 // DO NOT FORGET to update |kCompatibleVersionNumber| if you add a migration
637 // step that is a breaking change. This is needed so that an older version
638 // of the browser can fail with a meaningful error when opening a newer
639 // database, as opposed to failing on the first database operation.
640 // -------------------------------------------------------------------------
641 case kCurrentVersionNumber:
642 // Already up to date.
643 meta_table_.SetVersionNumber(kCurrentVersionNumber);
644 return true;
645 default:
646 NOTREACHED();
647 return false;
648 }
649 }
650
651 bool LoginDatabase::InitLoginsTable() {
652 if (!db_.DoesTableExist("logins")) {
653 if (!CreateNewTable(&db_, "logins", "generation_upload_status INTEGER,")) {
654 NOTREACHED();
655 return false;
656 }
657 if (!CreateIndexOnSignonRealm(&db_, "logins")) {
658 NOTREACHED();
659 return false;
660 }
661 }
662 return true;
663 }
664
665 void LoginDatabase::ReportMetrics(const std::string& sync_username, 670 void LoginDatabase::ReportMetrics(const std::string& sync_username,
666 bool custom_passphrase_sync_enabled) { 671 bool custom_passphrase_sync_enabled) {
667 sql::Statement s(db_.GetCachedStatement( 672 sql::Statement s(db_.GetCachedStatement(
668 SQL_FROM_HERE, 673 SQL_FROM_HERE,
669 "SELECT signon_realm, password_type, blacklisted_by_user," 674 "SELECT signon_realm, password_type, blacklisted_by_user,"
670 "COUNT(username_value) FROM logins GROUP BY " 675 "COUNT(username_value) FROM logins GROUP BY "
671 "signon_realm, password_type, blacklisted_by_user")); 676 "signon_realm, password_type, blacklisted_by_user"));
672 677
673 if (!s.is_valid()) 678 if (!s.is_valid())
674 return; 679 return;
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
849 PasswordStoreChangeList LoginDatabase::AddLogin(const PasswordForm& form) { 854 PasswordStoreChangeList LoginDatabase::AddLogin(const PasswordForm& form) {
850 PasswordStoreChangeList list; 855 PasswordStoreChangeList list;
851 if (!DoesMatchConstraints(form)) 856 if (!DoesMatchConstraints(form))
852 return list; 857 return list;
853 std::string encrypted_password; 858 std::string encrypted_password;
854 if (EncryptedString( 859 if (EncryptedString(
855 clear_password_values_ ? base::string16() : form.password_value, 860 clear_password_values_ ? base::string16() : form.password_value,
856 &encrypted_password) != ENCRYPTION_RESULT_SUCCESS) 861 &encrypted_password) != ENCRYPTION_RESULT_SUCCESS)
857 return list; 862 return list;
858 863
859 // You *must* change LoginTableColumns if this query changes. 864 DCHECK(!add_statement_.empty());
860 sql::Statement s(db_.GetCachedStatement( 865 sql::Statement s(
861 SQL_FROM_HERE, 866 db_.GetCachedStatement(SQL_FROM_HERE, add_statement_.c_str()));
862 "INSERT INTO logins "
863 "(origin_url, action_url, username_element, username_value, "
864 " password_element, password_value, submit_element, "
865 " signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
866 " scheme, password_type, possible_usernames, times_used, form_data, "
867 " date_synced, display_name, icon_url,"
868 " federation_url, skip_zero_click, generation_upload_status) VALUES "
869 "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
870 BindAddStatement(form, encrypted_password, &s); 867 BindAddStatement(form, encrypted_password, &s);
871 db_.set_error_callback(base::Bind(&AddCallback)); 868 db_.set_error_callback(base::Bind(&AddCallback));
872 const bool success = s.Run(); 869 const bool success = s.Run();
873 db_.reset_error_callback(); 870 db_.reset_error_callback();
874 if (success) { 871 if (success) {
875 list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form)); 872 list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));
876 return list; 873 return list;
877 } 874 }
878 // Repeat the same statement but with REPLACE semantic. 875 // Repeat the same statement but with REPLACE semantic.
879 s.Assign(db_.GetCachedStatement( 876 DCHECK(!add_replace_statement_.empty());
880 SQL_FROM_HERE, 877 s.Assign(
881 "INSERT OR REPLACE INTO logins " 878 db_.GetCachedStatement(SQL_FROM_HERE, add_replace_statement_.c_str()));
882 "(origin_url, action_url, username_element, username_value, "
883 " password_element, password_value, submit_element, "
884 " signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
885 " scheme, password_type, possible_usernames, times_used, form_data, "
886 " date_synced, display_name, icon_url,"
887 " federation_url, skip_zero_click, generation_upload_status) VALUES "
888 "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
889 BindAddStatement(form, encrypted_password, &s); 879 BindAddStatement(form, encrypted_password, &s);
890 if (s.Run()) { 880 if (s.Run()) {
891 list.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form)); 881 list.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
892 list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form)); 882 list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));
893 } 883 }
894 return list; 884 return list;
895 } 885 }
896 886
897 PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form) { 887 PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form) {
898 std::string encrypted_password; 888 std::string encrypted_password;
899 if (EncryptedString( 889 if (EncryptedString(
900 clear_password_values_ ? base::string16() : form.password_value, 890 clear_password_values_ ? base::string16() : form.password_value,
901 &encrypted_password) != ENCRYPTION_RESULT_SUCCESS) 891 &encrypted_password) != ENCRYPTION_RESULT_SUCCESS)
902 return PasswordStoreChangeList(); 892 return PasswordStoreChangeList();
903 893
904 #if defined(OS_IOS) 894 #if defined(OS_IOS)
905 DeleteEncryptedPassword(form); 895 DeleteEncryptedPassword(form);
906 #endif 896 #endif
907 // Replacement is necessary to deal with updating imported credentials. See 897 // Replacement is necessary to deal with updating imported credentials. See
908 // crbug.com/349138 for details. 898 // crbug.com/349138 for details.
909 sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, 899 DCHECK(!update_statement_.empty());
910 "UPDATE OR REPLACE logins SET " 900 sql::Statement s(
911 "action_url = ?, " 901 db_.GetCachedStatement(SQL_FROM_HERE, update_statement_.c_str()));
912 "password_value = ?, "
913 "ssl_valid = ?, "
914 "preferred = ?, "
915 "possible_usernames = ?, "
916 "times_used = ?, "
917 "submit_element = ?, "
918 "date_synced = ?, "
919 "date_created = ?, "
920 "blacklisted_by_user = ?, "
921 "scheme = ?, "
922 "password_type = ?, "
923 "display_name = ?, "
924 "icon_url = ?, "
925 "federation_url = ?, "
926 "skip_zero_click = ?, "
927 "generation_upload_status = ? "
928 "WHERE origin_url = ? AND "
929 "username_element = ? AND "
930 "username_value = ? AND "
931 "password_element = ? AND "
932 "signon_realm = ?"));
933 s.BindString(0, form.action.spec()); 902 s.BindString(0, form.action.spec());
934 s.BindBlob(1, encrypted_password.data(), 903 s.BindBlob(1, encrypted_password.data(),
935 static_cast<int>(encrypted_password.length())); 904 static_cast<int>(encrypted_password.length()));
936 s.BindInt(2, form.ssl_valid); 905 s.BindString16(2, form.submit_element);
937 s.BindInt(3, form.preferred); 906 s.BindInt(3, form.ssl_valid);
907 s.BindInt(4, form.preferred);
908 s.BindInt64(5, form.date_created.ToInternalValue());
909 s.BindInt(6, form.blacklisted_by_user);
910 s.BindInt(7, form.scheme);
911 s.BindInt(8, form.type);
938 base::Pickle pickle = SerializeVector(form.other_possible_usernames); 912 base::Pickle pickle = SerializeVector(form.other_possible_usernames);
939 s.BindBlob(4, pickle.data(), pickle.size()); 913 s.BindBlob(9, pickle.data(), pickle.size());
940 s.BindInt(5, form.times_used); 914 s.BindInt(10, form.times_used);
941 s.BindString16(6, form.submit_element); 915 base::Pickle form_data_pickle;
942 s.BindInt64(7, form.date_synced.ToInternalValue()); 916 autofill::SerializeFormData(form.form_data, &form_data_pickle);
943 s.BindInt64(8, form.date_created.ToInternalValue()); 917 s.BindBlob(11, form_data_pickle.data(), form_data_pickle.size());
944 s.BindInt(9, form.blacklisted_by_user); 918 s.BindInt64(12, form.date_synced.ToInternalValue());
945 s.BindInt(10, form.scheme); 919 s.BindString16(13, form.display_name);
946 s.BindInt(11, form.type); 920 s.BindString(14, form.icon_url.spec());
947 s.BindString16(12, form.display_name);
948 s.BindString(13, form.icon_url.spec());
949 // An empty Origin serializes as "null" which would be strange to store here. 921 // An empty Origin serializes as "null" which would be strange to store here.
950 s.BindString(14, form.federation_origin.unique() 922 s.BindString(15, form.federation_origin.unique()
951 ? std::string() 923 ? std::string()
952 : form.federation_origin.Serialize()); 924 : form.federation_origin.Serialize());
953 s.BindInt(15, form.skip_zero_click); 925 s.BindInt(16, form.skip_zero_click);
954 s.BindInt(16, form.generation_upload_status); 926 s.BindInt(17, form.generation_upload_status);
955 927
956 // WHERE starts here. 928 // WHERE starts here.
957 s.BindString(17, form.origin.spec()); 929 s.BindString(18, form.origin.spec());
958 s.BindString16(18, form.username_element); 930 s.BindString16(19, form.username_element);
959 s.BindString16(19, form.username_value); 931 s.BindString16(20, form.username_value);
960 s.BindString16(20, form.password_element); 932 s.BindString16(21, form.password_element);
961 s.BindString(21, form.signon_realm); 933 s.BindString(22, form.signon_realm);
962 934
963 if (!s.Run()) 935 if (!s.Run())
964 return PasswordStoreChangeList(); 936 return PasswordStoreChangeList();
965 937
966 PasswordStoreChangeList list; 938 PasswordStoreChangeList list;
967 if (db_.GetLastChangeCount()) 939 if (db_.GetLastChangeCount())
968 list.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE, form)); 940 list.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE, form));
969 941
970 return list; 942 return list;
971 } 943 }
972 944
973 bool LoginDatabase::RemoveLogin(const PasswordForm& form) { 945 bool LoginDatabase::RemoveLogin(const PasswordForm& form) {
974 if (form.is_public_suffix_match) { 946 if (form.is_public_suffix_match) {
975 // TODO(dvadym): Discuss whether we should allow to remove PSL matched 947 // TODO(dvadym): Discuss whether we should allow to remove PSL matched
976 // credentials. 948 // credentials.
977 return false; 949 return false;
978 } 950 }
979 #if defined(OS_IOS) 951 #if defined(OS_IOS)
980 DeleteEncryptedPassword(form); 952 DeleteEncryptedPassword(form);
981 #endif 953 #endif
982 // Remove a login by UNIQUE-constrained fields. 954 // Remove a login by UNIQUE-constrained fields.
983 sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, 955 DCHECK(!delete_statement_.empty());
984 "DELETE FROM logins WHERE " 956 sql::Statement s(
985 "origin_url = ? AND " 957 db_.GetCachedStatement(SQL_FROM_HERE, delete_statement_.c_str()));
986 "username_element = ? AND "
987 "username_value = ? AND "
988 "password_element = ? AND "
989 "submit_element = ? AND "
990 "signon_realm = ? "));
991 s.BindString(0, form.origin.spec()); 958 s.BindString(0, form.origin.spec());
992 s.BindString16(1, form.username_element); 959 s.BindString16(1, form.username_element);
993 s.BindString16(2, form.username_value); 960 s.BindString16(2, form.username_value);
994 s.BindString16(3, form.password_element); 961 s.BindString16(3, form.password_element);
995 s.BindString16(4, form.submit_element); 962 s.BindString(4, form.signon_realm);
996 s.BindString(5, form.signon_realm);
997 963
998 return s.Run() && db_.GetLastChangeCount() > 0; 964 return s.Run() && db_.GetLastChangeCount() > 0;
999 } 965 }
1000 966
1001 bool LoginDatabase::RemoveLoginsCreatedBetween(base::Time delete_begin, 967 bool LoginDatabase::RemoveLoginsCreatedBetween(base::Time delete_begin,
1002 base::Time delete_end) { 968 base::Time delete_end) {
1003 #if defined(OS_IOS) 969 #if defined(OS_IOS)
1004 ScopedVector<autofill::PasswordForm> forms; 970 ScopedVector<autofill::PasswordForm> forms;
1005 if (GetLoginsCreatedBetween(delete_begin, delete_end, &forms)) { 971 if (GetLoginsCreatedBetween(delete_begin, delete_end, &forms)) {
1006 for (size_t i = 0; i < forms.size(); i++) { 972 for (size_t i = 0; i < forms.size(); i++) {
(...skipping 21 matching lines...) Expand all
1028 s.BindInt64(1, 994 s.BindInt64(1,
1029 delete_end.is_null() ? base::Time::Max().ToInternalValue() 995 delete_end.is_null() ? base::Time::Max().ToInternalValue()
1030 : delete_end.ToInternalValue()); 996 : delete_end.ToInternalValue());
1031 997
1032 return s.Run(); 998 return s.Run();
1033 } 999 }
1034 1000
1035 bool LoginDatabase::GetAutoSignInLogins( 1001 bool LoginDatabase::GetAutoSignInLogins(
1036 ScopedVector<autofill::PasswordForm>* forms) const { 1002 ScopedVector<autofill::PasswordForm>* forms) const {
1037 DCHECK(forms); 1003 DCHECK(forms);
1038 sql::Statement s(db_.GetCachedStatement( 1004 DCHECK(!autosignin_statement_.empty());
1039 SQL_FROM_HERE, 1005 sql::Statement s(
1040 "SELECT origin_url, action_url, username_element, username_value, " 1006 db_.GetCachedStatement(SQL_FROM_HERE, autosignin_statement_.c_str()));
1041 "password_element, password_value, submit_element, signon_realm, "
1042 "ssl_valid, preferred, date_created, blacklisted_by_user, "
1043 "scheme, password_type, possible_usernames, times_used, form_data, "
1044 "date_synced, display_name, icon_url, "
1045 "federation_url, skip_zero_click, generation_upload_status FROM logins "
1046 "WHERE skip_zero_click = 0 ORDER BY origin_url"));
1047 1007
1048 return StatementToForms(&s, nullptr, forms); 1008 return StatementToForms(&s, nullptr, forms);
1049 } 1009 }
1050 1010
1051 bool LoginDatabase::DisableAutoSignInForAllLogins() { 1011 bool LoginDatabase::DisableAutoSignInForAllLogins() {
1052 sql::Statement s(db_.GetCachedStatement( 1012 sql::Statement s(db_.GetCachedStatement(
1053 SQL_FROM_HERE, "UPDATE logins SET skip_zero_click = 1;")); 1013 SQL_FROM_HERE, "UPDATE logins SET skip_zero_click = 1;"));
1054 1014
1055 return s.Run(); 1015 return s.Run();
1056 } 1016 }
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
1126 form->generation_upload_status = 1086 form->generation_upload_status =
1127 static_cast<PasswordForm::GenerationUploadStatus>( 1087 static_cast<PasswordForm::GenerationUploadStatus>(
1128 generation_upload_status_int); 1088 generation_upload_status_int);
1129 return ENCRYPTION_RESULT_SUCCESS; 1089 return ENCRYPTION_RESULT_SUCCESS;
1130 } 1090 }
1131 1091
1132 bool LoginDatabase::GetLogins( 1092 bool LoginDatabase::GetLogins(
1133 const PasswordForm& form, 1093 const PasswordForm& form,
1134 ScopedVector<autofill::PasswordForm>* forms) const { 1094 ScopedVector<autofill::PasswordForm>* forms) const {
1135 DCHECK(forms); 1095 DCHECK(forms);
1136 // You *must* change LoginTableColumns if this query changes.
1137 std::string sql_query =
1138 "SELECT origin_url, action_url, "
1139 "username_element, username_value, "
1140 "password_element, password_value, submit_element, "
1141 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
1142 "scheme, password_type, possible_usernames, times_used, form_data, "
1143 "date_synced, display_name, icon_url, "
1144 "federation_url, skip_zero_click, generation_upload_status "
1145 "FROM logins WHERE signon_realm == ? ";
1146 const GURL signon_realm(form.signon_realm); 1096 const GURL signon_realm(form.signon_realm);
1147 std::string registered_domain = GetRegistryControlledDomain(signon_realm); 1097 std::string registered_domain = GetRegistryControlledDomain(signon_realm);
1148 const bool should_PSL_matching_apply = 1098 const bool should_PSL_matching_apply =
1149 form.scheme == PasswordForm::SCHEME_HTML && 1099 form.scheme == PasswordForm::SCHEME_HTML &&
1150 ShouldPSLDomainMatchingApply(registered_domain); 1100 ShouldPSLDomainMatchingApply(registered_domain);
1151 const bool should_federated_apply = form.scheme == PasswordForm::SCHEME_HTML; 1101 const bool should_federated_apply = form.scheme == PasswordForm::SCHEME_HTML;
1152 if (should_PSL_matching_apply) 1102 DCHECK(!get_statement_.empty());
1153 sql_query += "OR signon_realm REGEXP ? "; 1103 DCHECK(!get_statement_psl_.empty());
1154 if (should_federated_apply) 1104 DCHECK(!get_statement_federated_.empty());
1155 sql_query += "OR (signon_realm LIKE ? AND password_type == 2) "; 1105 DCHECK(!get_statement_psl_federated_.empty());
1106 const std::string* sql_query = &get_statement_;
1107 if (should_PSL_matching_apply && should_federated_apply)
1108 sql_query = &get_statement_psl_federated_;
1109 else if (should_PSL_matching_apply)
1110 sql_query = &get_statement_psl_;
1111 else if (should_federated_apply)
1112 sql_query = &get_statement_federated_;
1156 1113
1157 // TODO(nyquist) Consider usage of GetCachedStatement when 1114 // TODO(nyquist) Consider usage of GetCachedStatement when
1158 // http://crbug.com/248608 is fixed. 1115 // http://crbug.com/248608 is fixed.
1159 sql::Statement s(db_.GetUniqueStatement(sql_query.c_str())); 1116 sql::Statement s(db_.GetUniqueStatement(sql_query->c_str()));
1160 s.BindString(0, form.signon_realm); 1117 s.BindString(0, form.signon_realm);
1161 int placeholder = 1; 1118 int placeholder = 1;
1162 1119
1163 // PSL matching only applies to HTML forms. 1120 // PSL matching only applies to HTML forms.
1164 if (should_PSL_matching_apply) { 1121 if (should_PSL_matching_apply) {
1165 // We are extending the original SQL query with one that includes more 1122 // We are extending the original SQL query with one that includes more
1166 // possible matches based on public suffix domain matching. Using a regexp 1123 // possible matches based on public suffix domain matching. Using a regexp
1167 // here is just an optimization to not have to parse all the stored entries 1124 // here is just an optimization to not have to parse all the stored entries
1168 // in the |logins| table. The result (scheme, domain and port) is verified 1125 // in the |logins| table. The result (scheme, domain and port) is verified
1169 // further down using GURL. See the functions SchemeMatches, 1126 // further down using GURL. See the functions SchemeMatches,
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1201 return StatementToForms( 1158 return StatementToForms(
1202 &s, should_PSL_matching_apply || should_federated_apply ? &form : nullptr, 1159 &s, should_PSL_matching_apply || should_federated_apply ? &form : nullptr,
1203 forms); 1160 forms);
1204 } 1161 }
1205 1162
1206 bool LoginDatabase::GetLoginsCreatedBetween( 1163 bool LoginDatabase::GetLoginsCreatedBetween(
1207 const base::Time begin, 1164 const base::Time begin,
1208 const base::Time end, 1165 const base::Time end,
1209 ScopedVector<autofill::PasswordForm>* forms) const { 1166 ScopedVector<autofill::PasswordForm>* forms) const {
1210 DCHECK(forms); 1167 DCHECK(forms);
1211 sql::Statement s(db_.GetCachedStatement( 1168 DCHECK(!created_statement_.empty());
1212 SQL_FROM_HERE, 1169 sql::Statement s(
1213 "SELECT origin_url, action_url, " 1170 db_.GetCachedStatement(SQL_FROM_HERE, created_statement_.c_str()));
1214 "username_element, username_value, "
1215 "password_element, password_value, submit_element, "
1216 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
1217 "scheme, password_type, possible_usernames, times_used, form_data, "
1218 "date_synced, display_name, icon_url, "
1219 "federation_url, skip_zero_click, generation_upload_status FROM logins "
1220 "WHERE date_created >= ? AND date_created < ?"
1221 "ORDER BY origin_url"));
1222 s.BindInt64(0, begin.ToInternalValue()); 1171 s.BindInt64(0, begin.ToInternalValue());
1223 s.BindInt64(1, end.is_null() ? std::numeric_limits<int64_t>::max() 1172 s.BindInt64(1, end.is_null() ? std::numeric_limits<int64_t>::max()
1224 : end.ToInternalValue()); 1173 : end.ToInternalValue());
1225 1174
1226 return StatementToForms(&s, nullptr, forms); 1175 return StatementToForms(&s, nullptr, forms);
1227 } 1176 }
1228 1177
1229 bool LoginDatabase::GetLoginsSyncedBetween( 1178 bool LoginDatabase::GetLoginsSyncedBetween(
1230 const base::Time begin, 1179 const base::Time begin,
1231 const base::Time end, 1180 const base::Time end,
1232 ScopedVector<autofill::PasswordForm>* forms) const { 1181 ScopedVector<autofill::PasswordForm>* forms) const {
1233 DCHECK(forms); 1182 DCHECK(forms);
1234 sql::Statement s(db_.GetCachedStatement( 1183 DCHECK(!synced_statement_.empty());
1235 SQL_FROM_HERE, 1184 sql::Statement s(
1236 "SELECT origin_url, action_url, username_element, username_value, " 1185 db_.GetCachedStatement(SQL_FROM_HERE, synced_statement_.c_str()));
1237 "password_element, password_value, submit_element, signon_realm, "
1238 "ssl_valid, preferred, date_created, blacklisted_by_user, "
1239 "scheme, password_type, possible_usernames, times_used, form_data, "
1240 "date_synced, display_name, icon_url, "
1241 "federation_url, skip_zero_click, generation_upload_status FROM logins "
1242 "WHERE date_synced >= ? AND date_synced < ?"
1243 "ORDER BY origin_url"));
1244 s.BindInt64(0, begin.ToInternalValue()); 1186 s.BindInt64(0, begin.ToInternalValue());
1245 s.BindInt64(1, 1187 s.BindInt64(1,
1246 end.is_null() ? base::Time::Max().ToInternalValue() 1188 end.is_null() ? base::Time::Max().ToInternalValue()
1247 : end.ToInternalValue()); 1189 : end.ToInternalValue());
1248 1190
1249 return StatementToForms(&s, nullptr, forms); 1191 return StatementToForms(&s, nullptr, forms);
1250 } 1192 }
1251 1193
1252 bool LoginDatabase::GetAutofillableLogins( 1194 bool LoginDatabase::GetAutofillableLogins(
1253 ScopedVector<autofill::PasswordForm>* forms) const { 1195 ScopedVector<autofill::PasswordForm>* forms) const {
1254 return GetAllLoginsWithBlacklistSetting(false, forms); 1196 return GetAllLoginsWithBlacklistSetting(false, forms);
1255 } 1197 }
1256 1198
1257 bool LoginDatabase::GetBlacklistLogins( 1199 bool LoginDatabase::GetBlacklistLogins(
1258 ScopedVector<autofill::PasswordForm>* forms) const { 1200 ScopedVector<autofill::PasswordForm>* forms) const {
1259 return GetAllLoginsWithBlacklistSetting(true, forms); 1201 return GetAllLoginsWithBlacklistSetting(true, forms);
1260 } 1202 }
1261 1203
1262 bool LoginDatabase::GetAllLoginsWithBlacklistSetting( 1204 bool LoginDatabase::GetAllLoginsWithBlacklistSetting(
1263 bool blacklisted, 1205 bool blacklisted,
1264 ScopedVector<autofill::PasswordForm>* forms) const { 1206 ScopedVector<autofill::PasswordForm>* forms) const {
1265 DCHECK(forms); 1207 DCHECK(forms);
1266 // You *must* change LoginTableColumns if this query changes. 1208 DCHECK(!blacklisted_statement_.empty());
1267 sql::Statement s(db_.GetCachedStatement( 1209 sql::Statement s(
1268 SQL_FROM_HERE, 1210 db_.GetCachedStatement(SQL_FROM_HERE, blacklisted_statement_.c_str()));
1269 "SELECT origin_url, action_url, "
1270 "username_element, username_value, "
1271 "password_element, password_value, submit_element, "
1272 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
1273 "scheme, password_type, possible_usernames, times_used, form_data, "
1274 "date_synced, display_name, icon_url, "
1275 "federation_url, skip_zero_click, generation_upload_status FROM logins "
1276 "WHERE blacklisted_by_user == ? ORDER BY origin_url"));
1277 s.BindInt(0, blacklisted ? 1 : 0); 1211 s.BindInt(0, blacklisted ? 1 : 0);
1278 1212
1279 return StatementToForms(&s, nullptr, forms); 1213 return StatementToForms(&s, nullptr, forms);
1280 } 1214 }
1281 1215
1282 bool LoginDatabase::DeleteAndRecreateDatabaseFile() { 1216 bool LoginDatabase::DeleteAndRecreateDatabaseFile() {
1283 DCHECK(db_.is_open()); 1217 DCHECK(db_.is_open());
1284 meta_table_.Reset(); 1218 meta_table_.Reset();
1285 db_.Close(); 1219 db_.Close();
1286 sql::Connection::Delete(db_path_); 1220 sql::Connection::Delete(db_path_);
1287 return Init(); 1221 return Init();
1288 } 1222 }
1289 1223
1290 std::string LoginDatabase::GetEncryptedPassword( 1224 std::string LoginDatabase::GetEncryptedPassword(
1291 const autofill::PasswordForm& form) const { 1225 const autofill::PasswordForm& form) const {
1226 DCHECK(!encrypted_statement_.empty());
1292 sql::Statement s( 1227 sql::Statement s(
1293 db_.GetCachedStatement(SQL_FROM_HERE, 1228 db_.GetCachedStatement(SQL_FROM_HERE, encrypted_statement_.c_str()));
1294 "SELECT password_value FROM logins WHERE "
1295 "origin_url = ? AND "
1296 "username_element = ? AND "
1297 "username_value = ? AND "
1298 "password_element = ? AND "
1299 "submit_element = ? AND "
1300 "signon_realm = ? "));
1301 1229
1302 s.BindString(0, form.origin.spec()); 1230 s.BindString(0, form.origin.spec());
1303 s.BindString16(1, form.username_element); 1231 s.BindString16(1, form.username_element);
1304 s.BindString16(2, form.username_value); 1232 s.BindString16(2, form.username_value);
1305 s.BindString16(3, form.password_element); 1233 s.BindString16(3, form.password_element);
1306 s.BindString16(4, form.submit_element); 1234 s.BindString(4, form.signon_realm);
1307 s.BindString(5, form.signon_realm);
1308 1235
1309 std::string encrypted_password; 1236 std::string encrypted_password;
1310 if (s.Step()) { 1237 if (s.Step()) {
1311 s.ColumnBlobAsString(0, &encrypted_password); 1238 s.ColumnBlobAsString(0, &encrypted_password);
1312 } 1239 }
1313 return encrypted_password; 1240 return encrypted_password;
1314 } 1241 }
1315 1242
1316 // static 1243 // static
1317 bool LoginDatabase::StatementToForms( 1244 bool LoginDatabase::StatementToForms(
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1352 UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering", 1279 UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering",
1353 psl_domain_match_metric, PSL_DOMAIN_MATCH_COUNT); 1280 psl_domain_match_metric, PSL_DOMAIN_MATCH_COUNT);
1354 } 1281 }
1355 1282
1356 if (!statement->Succeeded()) 1283 if (!statement->Succeeded())
1357 return false; 1284 return false;
1358 return true; 1285 return true;
1359 } 1286 }
1360 1287
1361 } // namespace password_manager 1288 } // namespace password_manager
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698