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 |
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_, ¤t_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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |