OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 InitializeStatementStrings(builder); |
430 LOG(ERROR) << "Unable to initialize the logins table."; | 554 |
431 db_.Close(); | 555 if (!db_.DoesTableExist("logins")) { |
432 return false; | 556 if (!builder.CreateTable(&db_)) { |
| 557 VLOG(0) << "Failed to create the 'logins' table"; |
| 558 db_.Close(); |
| 559 return false; |
| 560 } |
433 } | 561 } |
| 562 |
434 stats_table_.Init(&db_); | 563 stats_table_.Init(&db_); |
435 | 564 |
| 565 int current_version = meta_table_.GetVersionNumber(); |
| 566 bool migration_success = FixVersionIfNeeded(&db_, ¤t_version); |
| 567 DCHECK_LE(current_version, kCurrentVersionNumber); |
| 568 |
436 // If the file on disk is an older database version, bring it up to date. | 569 // If the file on disk is an older database version, bring it up to date. |
437 if (meta_table_.GetVersionNumber() < kCurrentVersionNumber && | 570 if (migration_success && current_version < kCurrentVersionNumber) { |
438 !MigrateOldVersionsAsNeeded()) { | 571 migration_success = MigrateLogins( |
| 572 base::checked_cast<unsigned>(current_version), &builder, &db_); |
| 573 } |
| 574 if (migration_success && current_version <= 15) { |
| 575 migration_success = stats_table_.MigrateToVersion(16); |
| 576 } |
| 577 if (migration_success) { |
| 578 meta_table_.SetCompatibleVersionNumber(kCompatibleVersionNumber); |
| 579 meta_table_.SetVersionNumber(kCurrentVersionNumber); |
| 580 } else { |
439 LogDatabaseInitError(MIGRATION_ERROR); | 581 LogDatabaseInitError(MIGRATION_ERROR); |
440 UMA_HISTOGRAM_SPARSE_SLOWLY("PasswordManager.LoginDatabaseFailedVersion", | 582 UMA_HISTOGRAM_SPARSE_SLOWLY("PasswordManager.LoginDatabaseFailedVersion", |
441 meta_table_.GetVersionNumber()); | 583 meta_table_.GetVersionNumber()); |
442 LOG(ERROR) << "Unable to migrate database from " | 584 LOG(ERROR) << "Unable to migrate database from " |
443 << meta_table_.GetVersionNumber() << " to " | 585 << meta_table_.GetVersionNumber() << " to " |
444 << kCurrentVersionNumber; | 586 << kCurrentVersionNumber; |
445 db_.Close(); | 587 db_.Close(); |
446 return false; | 588 return false; |
447 } | 589 } |
448 | 590 |
449 if (!stats_table_.CreateTableIfNecessary()) { | 591 if (!stats_table_.CreateTableIfNecessary()) { |
450 LogDatabaseInitError(INIT_STATS_ERROR); | 592 LogDatabaseInitError(INIT_STATS_ERROR); |
451 LOG(ERROR) << "Unable to create the stats table."; | 593 LOG(ERROR) << "Unable to create the stats table."; |
452 db_.Close(); | 594 db_.Close(); |
453 return false; | 595 return false; |
454 } | 596 } |
455 | 597 |
456 if (!transaction.Commit()) { | 598 if (!transaction.Commit()) { |
457 LogDatabaseInitError(COMMIT_TRANSACTION_ERROR); | 599 LogDatabaseInitError(COMMIT_TRANSACTION_ERROR); |
458 LOG(ERROR) << "Unable to commit a transaction."; | 600 LOG(ERROR) << "Unable to commit a transaction."; |
459 db_.Close(); | 601 db_.Close(); |
460 return false; | 602 return false; |
461 } | 603 } |
462 | 604 |
463 LogDatabaseInitError(INIT_OK); | 605 LogDatabaseInitError(INIT_OK); |
464 return true; | 606 return true; |
465 } | 607 } |
466 | 608 |
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, | 609 void LoginDatabase::ReportMetrics(const std::string& sync_username, |
666 bool custom_passphrase_sync_enabled) { | 610 bool custom_passphrase_sync_enabled) { |
667 sql::Statement s(db_.GetCachedStatement( | 611 sql::Statement s(db_.GetCachedStatement( |
668 SQL_FROM_HERE, | 612 SQL_FROM_HERE, |
669 "SELECT signon_realm, password_type, blacklisted_by_user," | 613 "SELECT signon_realm, password_type, blacklisted_by_user," |
670 "COUNT(username_value) FROM logins GROUP BY " | 614 "COUNT(username_value) FROM logins GROUP BY " |
671 "signon_realm, password_type, blacklisted_by_user")); | 615 "signon_realm, password_type, blacklisted_by_user")); |
672 | 616 |
673 if (!s.is_valid()) | 617 if (!s.is_valid()) |
674 return; | 618 return; |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
849 PasswordStoreChangeList LoginDatabase::AddLogin(const PasswordForm& form) { | 793 PasswordStoreChangeList LoginDatabase::AddLogin(const PasswordForm& form) { |
850 PasswordStoreChangeList list; | 794 PasswordStoreChangeList list; |
851 if (!DoesMatchConstraints(form)) | 795 if (!DoesMatchConstraints(form)) |
852 return list; | 796 return list; |
853 std::string encrypted_password; | 797 std::string encrypted_password; |
854 if (EncryptedString( | 798 if (EncryptedString( |
855 clear_password_values_ ? base::string16() : form.password_value, | 799 clear_password_values_ ? base::string16() : form.password_value, |
856 &encrypted_password) != ENCRYPTION_RESULT_SUCCESS) | 800 &encrypted_password) != ENCRYPTION_RESULT_SUCCESS) |
857 return list; | 801 return list; |
858 | 802 |
859 // You *must* change LoginTableColumns if this query changes. | 803 DCHECK(!add_statement_.empty()); |
860 sql::Statement s(db_.GetCachedStatement( | 804 sql::Statement s( |
861 SQL_FROM_HERE, | 805 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); | 806 BindAddStatement(form, encrypted_password, &s); |
871 db_.set_error_callback(base::Bind(&AddCallback)); | 807 db_.set_error_callback(base::Bind(&AddCallback)); |
872 const bool success = s.Run(); | 808 const bool success = s.Run(); |
873 db_.reset_error_callback(); | 809 db_.reset_error_callback(); |
874 if (success) { | 810 if (success) { |
875 list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form)); | 811 list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form)); |
876 return list; | 812 return list; |
877 } | 813 } |
878 // Repeat the same statement but with REPLACE semantic. | 814 // Repeat the same statement but with REPLACE semantic. |
879 s.Assign(db_.GetCachedStatement( | 815 DCHECK(!add_replace_statement_.empty()); |
880 SQL_FROM_HERE, | 816 s.Assign( |
881 "INSERT OR REPLACE INTO logins " | 817 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); | 818 BindAddStatement(form, encrypted_password, &s); |
890 if (s.Run()) { | 819 if (s.Run()) { |
891 list.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form)); | 820 list.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form)); |
892 list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form)); | 821 list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form)); |
893 } | 822 } |
894 return list; | 823 return list; |
895 } | 824 } |
896 | 825 |
897 PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form) { | 826 PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form) { |
898 std::string encrypted_password; | 827 std::string encrypted_password; |
899 if (EncryptedString( | 828 if (EncryptedString( |
900 clear_password_values_ ? base::string16() : form.password_value, | 829 clear_password_values_ ? base::string16() : form.password_value, |
901 &encrypted_password) != ENCRYPTION_RESULT_SUCCESS) | 830 &encrypted_password) != ENCRYPTION_RESULT_SUCCESS) |
902 return PasswordStoreChangeList(); | 831 return PasswordStoreChangeList(); |
903 | 832 |
904 #if defined(OS_IOS) | 833 #if defined(OS_IOS) |
905 DeleteEncryptedPassword(form); | 834 DeleteEncryptedPassword(form); |
906 #endif | 835 #endif |
907 // Replacement is necessary to deal with updating imported credentials. See | 836 // Replacement is necessary to deal with updating imported credentials. See |
908 // crbug.com/349138 for details. | 837 // crbug.com/349138 for details. |
909 sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, | 838 DCHECK(!update_statement_.empty()); |
910 "UPDATE OR REPLACE logins SET " | 839 sql::Statement s( |
911 "action_url = ?, " | 840 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()); | 841 s.BindString(0, form.action.spec()); |
934 s.BindBlob(1, encrypted_password.data(), | 842 s.BindBlob(1, encrypted_password.data(), |
935 static_cast<int>(encrypted_password.length())); | 843 static_cast<int>(encrypted_password.length())); |
936 s.BindInt(2, form.ssl_valid); | 844 s.BindString16(2, form.submit_element); |
937 s.BindInt(3, form.preferred); | 845 s.BindInt(3, form.ssl_valid); |
| 846 s.BindInt(4, form.preferred); |
| 847 s.BindInt64(5, form.date_created.ToInternalValue()); |
| 848 s.BindInt(6, form.blacklisted_by_user); |
| 849 s.BindInt(7, form.scheme); |
| 850 s.BindInt(8, form.type); |
938 base::Pickle pickle = SerializeVector(form.other_possible_usernames); | 851 base::Pickle pickle = SerializeVector(form.other_possible_usernames); |
939 s.BindBlob(4, pickle.data(), pickle.size()); | 852 s.BindBlob(9, pickle.data(), pickle.size()); |
940 s.BindInt(5, form.times_used); | 853 s.BindInt(10, form.times_used); |
941 s.BindString16(6, form.submit_element); | 854 base::Pickle form_data_pickle; |
942 s.BindInt64(7, form.date_synced.ToInternalValue()); | 855 autofill::SerializeFormData(form.form_data, &form_data_pickle); |
943 s.BindInt64(8, form.date_created.ToInternalValue()); | 856 s.BindBlob(11, form_data_pickle.data(), form_data_pickle.size()); |
944 s.BindInt(9, form.blacklisted_by_user); | 857 s.BindInt64(12, form.date_synced.ToInternalValue()); |
945 s.BindInt(10, form.scheme); | 858 s.BindString16(13, form.display_name); |
946 s.BindInt(11, form.type); | 859 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. | 860 // An empty Origin serializes as "null" which would be strange to store here. |
950 s.BindString(14, form.federation_origin.unique() | 861 s.BindString(15, form.federation_origin.unique() |
951 ? std::string() | 862 ? std::string() |
952 : form.federation_origin.Serialize()); | 863 : form.federation_origin.Serialize()); |
953 s.BindInt(15, form.skip_zero_click); | 864 s.BindInt(16, form.skip_zero_click); |
954 s.BindInt(16, form.generation_upload_status); | 865 s.BindInt(17, form.generation_upload_status); |
955 | 866 |
956 // WHERE starts here. | 867 // WHERE starts here. |
957 s.BindString(17, form.origin.spec()); | 868 s.BindString(18, form.origin.spec()); |
958 s.BindString16(18, form.username_element); | 869 s.BindString16(19, form.username_element); |
959 s.BindString16(19, form.username_value); | 870 s.BindString16(20, form.username_value); |
960 s.BindString16(20, form.password_element); | 871 s.BindString16(21, form.password_element); |
961 s.BindString(21, form.signon_realm); | 872 s.BindString(22, form.signon_realm); |
962 | 873 |
963 if (!s.Run()) | 874 if (!s.Run()) |
964 return PasswordStoreChangeList(); | 875 return PasswordStoreChangeList(); |
965 | 876 |
966 PasswordStoreChangeList list; | 877 PasswordStoreChangeList list; |
967 if (db_.GetLastChangeCount()) | 878 if (db_.GetLastChangeCount()) |
968 list.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE, form)); | 879 list.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE, form)); |
969 | 880 |
970 return list; | 881 return list; |
971 } | 882 } |
972 | 883 |
973 bool LoginDatabase::RemoveLogin(const PasswordForm& form) { | 884 bool LoginDatabase::RemoveLogin(const PasswordForm& form) { |
974 if (form.is_public_suffix_match) { | 885 if (form.is_public_suffix_match) { |
975 // TODO(dvadym): Discuss whether we should allow to remove PSL matched | 886 // TODO(dvadym): Discuss whether we should allow to remove PSL matched |
976 // credentials. | 887 // credentials. |
977 return false; | 888 return false; |
978 } | 889 } |
979 #if defined(OS_IOS) | 890 #if defined(OS_IOS) |
980 DeleteEncryptedPassword(form); | 891 DeleteEncryptedPassword(form); |
981 #endif | 892 #endif |
982 // Remove a login by UNIQUE-constrained fields. | 893 // Remove a login by UNIQUE-constrained fields. |
983 sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, | 894 DCHECK(!delete_statement_.empty()); |
984 "DELETE FROM logins WHERE " | 895 sql::Statement s( |
985 "origin_url = ? AND " | 896 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()); | 897 s.BindString(0, form.origin.spec()); |
992 s.BindString16(1, form.username_element); | 898 s.BindString16(1, form.username_element); |
993 s.BindString16(2, form.username_value); | 899 s.BindString16(2, form.username_value); |
994 s.BindString16(3, form.password_element); | 900 s.BindString16(3, form.password_element); |
995 s.BindString16(4, form.submit_element); | 901 s.BindString(4, form.signon_realm); |
996 s.BindString(5, form.signon_realm); | |
997 | 902 |
998 return s.Run() && db_.GetLastChangeCount() > 0; | 903 return s.Run() && db_.GetLastChangeCount() > 0; |
999 } | 904 } |
1000 | 905 |
1001 bool LoginDatabase::RemoveLoginsCreatedBetween(base::Time delete_begin, | 906 bool LoginDatabase::RemoveLoginsCreatedBetween(base::Time delete_begin, |
1002 base::Time delete_end) { | 907 base::Time delete_end) { |
1003 #if defined(OS_IOS) | 908 #if defined(OS_IOS) |
1004 ScopedVector<autofill::PasswordForm> forms; | 909 ScopedVector<autofill::PasswordForm> forms; |
1005 if (GetLoginsCreatedBetween(delete_begin, delete_end, &forms)) { | 910 if (GetLoginsCreatedBetween(delete_begin, delete_end, &forms)) { |
1006 for (size_t i = 0; i < forms.size(); i++) { | 911 for (size_t i = 0; i < forms.size(); i++) { |
(...skipping 21 matching lines...) Expand all Loading... |
1028 s.BindInt64(1, | 933 s.BindInt64(1, |
1029 delete_end.is_null() ? base::Time::Max().ToInternalValue() | 934 delete_end.is_null() ? base::Time::Max().ToInternalValue() |
1030 : delete_end.ToInternalValue()); | 935 : delete_end.ToInternalValue()); |
1031 | 936 |
1032 return s.Run(); | 937 return s.Run(); |
1033 } | 938 } |
1034 | 939 |
1035 bool LoginDatabase::GetAutoSignInLogins( | 940 bool LoginDatabase::GetAutoSignInLogins( |
1036 ScopedVector<autofill::PasswordForm>* forms) const { | 941 ScopedVector<autofill::PasswordForm>* forms) const { |
1037 DCHECK(forms); | 942 DCHECK(forms); |
1038 sql::Statement s(db_.GetCachedStatement( | 943 DCHECK(!autosignin_statement_.empty()); |
1039 SQL_FROM_HERE, | 944 sql::Statement s( |
1040 "SELECT origin_url, action_url, username_element, username_value, " | 945 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 | 946 |
1048 return StatementToForms(&s, nullptr, forms); | 947 return StatementToForms(&s, nullptr, forms); |
1049 } | 948 } |
1050 | 949 |
1051 bool LoginDatabase::DisableAutoSignInForOrigin(const GURL& origin) { | 950 bool LoginDatabase::DisableAutoSignInForOrigin(const GURL& origin) { |
1052 sql::Statement s(db_.GetCachedStatement( | 951 sql::Statement s(db_.GetCachedStatement( |
1053 SQL_FROM_HERE, | 952 SQL_FROM_HERE, |
1054 "UPDATE logins SET skip_zero_click = 1 WHERE origin_url = ?;")); | 953 "UPDATE logins SET skip_zero_click = 1 WHERE origin_url = ?;")); |
1055 s.BindString(0, origin.spec()); | 954 s.BindString(0, origin.spec()); |
1056 | 955 |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1128 form->generation_upload_status = | 1027 form->generation_upload_status = |
1129 static_cast<PasswordForm::GenerationUploadStatus>( | 1028 static_cast<PasswordForm::GenerationUploadStatus>( |
1130 generation_upload_status_int); | 1029 generation_upload_status_int); |
1131 return ENCRYPTION_RESULT_SUCCESS; | 1030 return ENCRYPTION_RESULT_SUCCESS; |
1132 } | 1031 } |
1133 | 1032 |
1134 bool LoginDatabase::GetLogins( | 1033 bool LoginDatabase::GetLogins( |
1135 const PasswordForm& form, | 1034 const PasswordForm& form, |
1136 ScopedVector<autofill::PasswordForm>* forms) const { | 1035 ScopedVector<autofill::PasswordForm>* forms) const { |
1137 DCHECK(forms); | 1036 DCHECK(forms); |
1138 // You *must* change LoginTableColumns if this query changes. | |
1139 std::string sql_query = | |
1140 "SELECT origin_url, action_url, " | |
1141 "username_element, username_value, " | |
1142 "password_element, password_value, submit_element, " | |
1143 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, " | |
1144 "scheme, password_type, possible_usernames, times_used, form_data, " | |
1145 "date_synced, display_name, icon_url, " | |
1146 "federation_url, skip_zero_click, generation_upload_status " | |
1147 "FROM logins WHERE signon_realm == ? "; | |
1148 const GURL signon_realm(form.signon_realm); | 1037 const GURL signon_realm(form.signon_realm); |
1149 std::string registered_domain = GetRegistryControlledDomain(signon_realm); | 1038 std::string registered_domain = GetRegistryControlledDomain(signon_realm); |
1150 const bool should_PSL_matching_apply = | 1039 const bool should_PSL_matching_apply = |
1151 form.scheme == PasswordForm::SCHEME_HTML && | 1040 form.scheme == PasswordForm::SCHEME_HTML && |
1152 ShouldPSLDomainMatchingApply(registered_domain); | 1041 ShouldPSLDomainMatchingApply(registered_domain); |
1153 const bool should_federated_apply = form.scheme == PasswordForm::SCHEME_HTML; | 1042 const bool should_federated_apply = form.scheme == PasswordForm::SCHEME_HTML; |
1154 if (should_PSL_matching_apply) | 1043 DCHECK(!get_statement_.empty()); |
1155 sql_query += "OR signon_realm REGEXP ? "; | 1044 DCHECK(!get_statement_psl_.empty()); |
1156 if (should_federated_apply) | 1045 DCHECK(!get_statement_federated_.empty()); |
1157 sql_query += "OR (signon_realm LIKE ? AND password_type == 2) "; | 1046 DCHECK(!get_statement_psl_federated_.empty()); |
| 1047 const std::string* sql_query = &get_statement_; |
| 1048 if (should_PSL_matching_apply && should_federated_apply) |
| 1049 sql_query = &get_statement_psl_federated_; |
| 1050 else if (should_PSL_matching_apply) |
| 1051 sql_query = &get_statement_psl_; |
| 1052 else if (should_federated_apply) |
| 1053 sql_query = &get_statement_federated_; |
1158 | 1054 |
1159 // TODO(nyquist) Consider usage of GetCachedStatement when | 1055 // TODO(nyquist) Consider usage of GetCachedStatement when |
1160 // http://crbug.com/248608 is fixed. | 1056 // http://crbug.com/248608 is fixed. |
1161 sql::Statement s(db_.GetUniqueStatement(sql_query.c_str())); | 1057 sql::Statement s(db_.GetUniqueStatement(sql_query->c_str())); |
1162 s.BindString(0, form.signon_realm); | 1058 s.BindString(0, form.signon_realm); |
1163 int placeholder = 1; | 1059 int placeholder = 1; |
1164 | 1060 |
1165 // PSL matching only applies to HTML forms. | 1061 // PSL matching only applies to HTML forms. |
1166 if (should_PSL_matching_apply) { | 1062 if (should_PSL_matching_apply) { |
1167 // We are extending the original SQL query with one that includes more | 1063 // We are extending the original SQL query with one that includes more |
1168 // possible matches based on public suffix domain matching. Using a regexp | 1064 // possible matches based on public suffix domain matching. Using a regexp |
1169 // here is just an optimization to not have to parse all the stored entries | 1065 // here is just an optimization to not have to parse all the stored entries |
1170 // in the |logins| table. The result (scheme, domain and port) is verified | 1066 // in the |logins| table. The result (scheme, domain and port) is verified |
1171 // further down using GURL. See the functions SchemeMatches, | 1067 // further down using GURL. See the functions SchemeMatches, |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1203 return StatementToForms( | 1099 return StatementToForms( |
1204 &s, should_PSL_matching_apply || should_federated_apply ? &form : nullptr, | 1100 &s, should_PSL_matching_apply || should_federated_apply ? &form : nullptr, |
1205 forms); | 1101 forms); |
1206 } | 1102 } |
1207 | 1103 |
1208 bool LoginDatabase::GetLoginsCreatedBetween( | 1104 bool LoginDatabase::GetLoginsCreatedBetween( |
1209 const base::Time begin, | 1105 const base::Time begin, |
1210 const base::Time end, | 1106 const base::Time end, |
1211 ScopedVector<autofill::PasswordForm>* forms) const { | 1107 ScopedVector<autofill::PasswordForm>* forms) const { |
1212 DCHECK(forms); | 1108 DCHECK(forms); |
1213 sql::Statement s(db_.GetCachedStatement( | 1109 DCHECK(!created_statement_.empty()); |
1214 SQL_FROM_HERE, | 1110 sql::Statement s( |
1215 "SELECT origin_url, action_url, " | 1111 db_.GetCachedStatement(SQL_FROM_HERE, created_statement_.c_str())); |
1216 "username_element, username_value, " | |
1217 "password_element, password_value, submit_element, " | |
1218 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, " | |
1219 "scheme, password_type, possible_usernames, times_used, form_data, " | |
1220 "date_synced, display_name, icon_url, " | |
1221 "federation_url, skip_zero_click, generation_upload_status FROM logins " | |
1222 "WHERE date_created >= ? AND date_created < ?" | |
1223 "ORDER BY origin_url")); | |
1224 s.BindInt64(0, begin.ToInternalValue()); | 1112 s.BindInt64(0, begin.ToInternalValue()); |
1225 s.BindInt64(1, end.is_null() ? std::numeric_limits<int64_t>::max() | 1113 s.BindInt64(1, end.is_null() ? std::numeric_limits<int64_t>::max() |
1226 : end.ToInternalValue()); | 1114 : end.ToInternalValue()); |
1227 | 1115 |
1228 return StatementToForms(&s, nullptr, forms); | 1116 return StatementToForms(&s, nullptr, forms); |
1229 } | 1117 } |
1230 | 1118 |
1231 bool LoginDatabase::GetLoginsSyncedBetween( | 1119 bool LoginDatabase::GetLoginsSyncedBetween( |
1232 const base::Time begin, | 1120 const base::Time begin, |
1233 const base::Time end, | 1121 const base::Time end, |
1234 ScopedVector<autofill::PasswordForm>* forms) const { | 1122 ScopedVector<autofill::PasswordForm>* forms) const { |
1235 DCHECK(forms); | 1123 DCHECK(forms); |
1236 sql::Statement s(db_.GetCachedStatement( | 1124 DCHECK(!synced_statement_.empty()); |
1237 SQL_FROM_HERE, | 1125 sql::Statement s( |
1238 "SELECT origin_url, action_url, username_element, username_value, " | 1126 db_.GetCachedStatement(SQL_FROM_HERE, synced_statement_.c_str())); |
1239 "password_element, password_value, submit_element, signon_realm, " | |
1240 "ssl_valid, preferred, date_created, blacklisted_by_user, " | |
1241 "scheme, password_type, possible_usernames, times_used, form_data, " | |
1242 "date_synced, display_name, icon_url, " | |
1243 "federation_url, skip_zero_click, generation_upload_status FROM logins " | |
1244 "WHERE date_synced >= ? AND date_synced < ?" | |
1245 "ORDER BY origin_url")); | |
1246 s.BindInt64(0, begin.ToInternalValue()); | 1127 s.BindInt64(0, begin.ToInternalValue()); |
1247 s.BindInt64(1, | 1128 s.BindInt64(1, |
1248 end.is_null() ? base::Time::Max().ToInternalValue() | 1129 end.is_null() ? base::Time::Max().ToInternalValue() |
1249 : end.ToInternalValue()); | 1130 : end.ToInternalValue()); |
1250 | 1131 |
1251 return StatementToForms(&s, nullptr, forms); | 1132 return StatementToForms(&s, nullptr, forms); |
1252 } | 1133 } |
1253 | 1134 |
1254 bool LoginDatabase::GetAutofillableLogins( | 1135 bool LoginDatabase::GetAutofillableLogins( |
1255 ScopedVector<autofill::PasswordForm>* forms) const { | 1136 ScopedVector<autofill::PasswordForm>* forms) const { |
1256 return GetAllLoginsWithBlacklistSetting(false, forms); | 1137 return GetAllLoginsWithBlacklistSetting(false, forms); |
1257 } | 1138 } |
1258 | 1139 |
1259 bool LoginDatabase::GetBlacklistLogins( | 1140 bool LoginDatabase::GetBlacklistLogins( |
1260 ScopedVector<autofill::PasswordForm>* forms) const { | 1141 ScopedVector<autofill::PasswordForm>* forms) const { |
1261 return GetAllLoginsWithBlacklistSetting(true, forms); | 1142 return GetAllLoginsWithBlacklistSetting(true, forms); |
1262 } | 1143 } |
1263 | 1144 |
1264 bool LoginDatabase::GetAllLoginsWithBlacklistSetting( | 1145 bool LoginDatabase::GetAllLoginsWithBlacklistSetting( |
1265 bool blacklisted, | 1146 bool blacklisted, |
1266 ScopedVector<autofill::PasswordForm>* forms) const { | 1147 ScopedVector<autofill::PasswordForm>* forms) const { |
1267 DCHECK(forms); | 1148 DCHECK(forms); |
1268 // You *must* change LoginTableColumns if this query changes. | 1149 DCHECK(!blacklisted_statement_.empty()); |
1269 sql::Statement s(db_.GetCachedStatement( | 1150 sql::Statement s( |
1270 SQL_FROM_HERE, | 1151 db_.GetCachedStatement(SQL_FROM_HERE, blacklisted_statement_.c_str())); |
1271 "SELECT origin_url, action_url, " | |
1272 "username_element, username_value, " | |
1273 "password_element, password_value, submit_element, " | |
1274 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, " | |
1275 "scheme, password_type, possible_usernames, times_used, form_data, " | |
1276 "date_synced, display_name, icon_url, " | |
1277 "federation_url, skip_zero_click, generation_upload_status FROM logins " | |
1278 "WHERE blacklisted_by_user == ? ORDER BY origin_url")); | |
1279 s.BindInt(0, blacklisted ? 1 : 0); | 1152 s.BindInt(0, blacklisted ? 1 : 0); |
1280 | 1153 |
1281 return StatementToForms(&s, nullptr, forms); | 1154 return StatementToForms(&s, nullptr, forms); |
1282 } | 1155 } |
1283 | 1156 |
1284 bool LoginDatabase::DeleteAndRecreateDatabaseFile() { | 1157 bool LoginDatabase::DeleteAndRecreateDatabaseFile() { |
1285 DCHECK(db_.is_open()); | 1158 DCHECK(db_.is_open()); |
1286 meta_table_.Reset(); | 1159 meta_table_.Reset(); |
1287 db_.Close(); | 1160 db_.Close(); |
1288 sql::Connection::Delete(db_path_); | 1161 sql::Connection::Delete(db_path_); |
1289 return Init(); | 1162 return Init(); |
1290 } | 1163 } |
1291 | 1164 |
1292 std::string LoginDatabase::GetEncryptedPassword( | 1165 std::string LoginDatabase::GetEncryptedPassword( |
1293 const autofill::PasswordForm& form) const { | 1166 const autofill::PasswordForm& form) const { |
| 1167 DCHECK(!encrypted_statement_.empty()); |
1294 sql::Statement s( | 1168 sql::Statement s( |
1295 db_.GetCachedStatement(SQL_FROM_HERE, | 1169 db_.GetCachedStatement(SQL_FROM_HERE, encrypted_statement_.c_str())); |
1296 "SELECT password_value FROM logins WHERE " | |
1297 "origin_url = ? AND " | |
1298 "username_element = ? AND " | |
1299 "username_value = ? AND " | |
1300 "password_element = ? AND " | |
1301 "submit_element = ? AND " | |
1302 "signon_realm = ? ")); | |
1303 | 1170 |
1304 s.BindString(0, form.origin.spec()); | 1171 s.BindString(0, form.origin.spec()); |
1305 s.BindString16(1, form.username_element); | 1172 s.BindString16(1, form.username_element); |
1306 s.BindString16(2, form.username_value); | 1173 s.BindString16(2, form.username_value); |
1307 s.BindString16(3, form.password_element); | 1174 s.BindString16(3, form.password_element); |
1308 s.BindString16(4, form.submit_element); | 1175 s.BindString(4, form.signon_realm); |
1309 s.BindString(5, form.signon_realm); | |
1310 | 1176 |
1311 std::string encrypted_password; | 1177 std::string encrypted_password; |
1312 if (s.Step()) { | 1178 if (s.Step()) { |
1313 s.ColumnBlobAsString(0, &encrypted_password); | 1179 s.ColumnBlobAsString(0, &encrypted_password); |
1314 } | 1180 } |
1315 return encrypted_password; | 1181 return encrypted_password; |
1316 } | 1182 } |
1317 | 1183 |
1318 // static | 1184 // static |
1319 bool LoginDatabase::StatementToForms( | 1185 bool LoginDatabase::StatementToForms( |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1353 if (matched_form) { | 1219 if (matched_form) { |
1354 UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering", | 1220 UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering", |
1355 psl_domain_match_metric, PSL_DOMAIN_MATCH_COUNT); | 1221 psl_domain_match_metric, PSL_DOMAIN_MATCH_COUNT); |
1356 } | 1222 } |
1357 | 1223 |
1358 if (!statement->Succeeded()) | 1224 if (!statement->Succeeded()) |
1359 return false; | 1225 return false; |
1360 return true; | 1226 return true; |
1361 } | 1227 } |
1362 | 1228 |
| 1229 void LoginDatabase::InitializeStatementStrings(const SQLTableBuilder& builder) { |
| 1230 // This method may be called multiple times, if Chrome switches backends and |
| 1231 // LoginDatabase::DeleteAndRecreateDatabaseFile ends up being called. In those |
| 1232 // case do not recompute the SQL statements, because they would end up the |
| 1233 // same. |
| 1234 if (!add_statement_.empty()) |
| 1235 return; |
| 1236 |
| 1237 // Initialize the cached strings. |
| 1238 std::string all_column_names = builder.ListAllColumnNames(); |
| 1239 std::string right_amount_of_placeholders = |
| 1240 GeneratePlaceholders(builder.NumberOfColumns()); |
| 1241 std::string all_unique_key_column_names = builder.ListAllUniqueKeyNames(); |
| 1242 std::string all_nonunique_key_column_names = |
| 1243 builder.ListAllNonuniqueKeyNames(); |
| 1244 |
| 1245 add_statement_ = "INSERT INTO logins (" + all_column_names + ") VALUES " + |
| 1246 right_amount_of_placeholders; |
| 1247 DCHECK(add_replace_statement_.empty()); |
| 1248 add_replace_statement_ = "INSERT OR REPLACE INTO logins (" + |
| 1249 all_column_names + ") VALUES " + |
| 1250 right_amount_of_placeholders; |
| 1251 DCHECK(update_statement_.empty()); |
| 1252 update_statement_ = "UPDATE OR REPLACE logins SET " + |
| 1253 all_nonunique_key_column_names + " WHERE " + |
| 1254 all_unique_key_column_names; |
| 1255 DCHECK(delete_statement_.empty()); |
| 1256 delete_statement_ = "DELETE FROM logins WHERE " + all_unique_key_column_names; |
| 1257 DCHECK(autosignin_statement_.empty()); |
| 1258 autosignin_statement_ = "SELECT " + all_column_names + |
| 1259 " FROM logins " |
| 1260 "WHERE skip_zero_click = 0 ORDER BY origin_url"; |
| 1261 DCHECK(get_statement_.empty()); |
| 1262 get_statement_ = "SELECT " + all_column_names + |
| 1263 " FROM logins " |
| 1264 "WHERE signon_realm == ?"; |
| 1265 std::string psl_statement = "OR signon_realm REGEXP ? "; |
| 1266 std::string federated_statement = |
| 1267 "OR (signon_realm LIKE ? AND password_type == 2) "; |
| 1268 DCHECK(get_statement_psl_.empty()); |
| 1269 get_statement_psl_ = get_statement_ + psl_statement; |
| 1270 DCHECK(get_statement_federated_.empty()); |
| 1271 get_statement_federated_ = get_statement_ + federated_statement; |
| 1272 DCHECK(get_statement_psl_federated_.empty()); |
| 1273 get_statement_psl_federated_ = |
| 1274 get_statement_ + psl_statement + federated_statement; |
| 1275 DCHECK(created_statement_.empty()); |
| 1276 created_statement_ = |
| 1277 "SELECT " + all_column_names + |
| 1278 " FROM logins WHERE date_created >= ? AND date_created < " |
| 1279 "? ORDER BY origin_url"; |
| 1280 DCHECK(synced_statement_.empty()); |
| 1281 synced_statement_ = "SELECT " + all_column_names + |
| 1282 " FROM logins WHERE date_synced >= ? AND date_synced < " |
| 1283 "? ORDER BY origin_url"; |
| 1284 DCHECK(blacklisted_statement_.empty()); |
| 1285 blacklisted_statement_ = |
| 1286 "SELECT " + all_column_names + |
| 1287 " FROM logins WHERE blacklisted_by_user == ? ORDER BY origin_url"; |
| 1288 DCHECK(encrypted_statement_.empty()); |
| 1289 encrypted_statement_ = |
| 1290 "SELECT password_value FROM logins WHERE " + all_unique_key_column_names; |
| 1291 } |
| 1292 |
1363 } // namespace password_manager | 1293 } // namespace password_manager |
OLD | NEW |