| 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 <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/files/file_path.h" | 11 #include "base/files/file_path.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/metrics/histogram_macros.h" | 13 #include "base/metrics/histogram_macros.h" |
| 14 #include "base/metrics/sparse_histogram.h" |
| 14 #include "base/pickle.h" | 15 #include "base/pickle.h" |
| 15 #include "base/strings/string_util.h" | 16 #include "base/strings/string_util.h" |
| 16 #include "base/strings/stringprintf.h" | 17 #include "base/strings/stringprintf.h" |
| 17 #include "base/time/time.h" | 18 #include "base/time/time.h" |
| 18 #include "components/autofill/core/common/password_form.h" | 19 #include "components/autofill/core/common/password_form.h" |
| 19 #include "components/password_manager/core/browser/affiliation_utils.h" | 20 #include "components/password_manager/core/browser/affiliation_utils.h" |
| 20 #include "components/password_manager/core/browser/password_manager_client.h" | 21 #include "components/password_manager/core/browser/password_manager_client.h" |
| 21 #include "components/password_manager/core/browser/password_manager_metrics_util
.h" | 22 #include "components/password_manager/core/browser/password_manager_metrics_util
.h" |
| 22 #include "google_apis/gaia/gaia_auth_util.h" | 23 #include "google_apis/gaia/gaia_auth_util.h" |
| 23 #include "google_apis/gaia/gaia_urls.h" | 24 #include "google_apis/gaia/gaia_urls.h" |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 COLUMN_DATE_SYNCED, | 78 COLUMN_DATE_SYNCED, |
| 78 COLUMN_DISPLAY_NAME, | 79 COLUMN_DISPLAY_NAME, |
| 79 COLUMN_AVATAR_URL, | 80 COLUMN_AVATAR_URL, |
| 80 COLUMN_FEDERATION_URL, | 81 COLUMN_FEDERATION_URL, |
| 81 COLUMN_SKIP_ZERO_CLICK, | 82 COLUMN_SKIP_ZERO_CLICK, |
| 82 COLUMN_GENERATION_UPLOAD_STATUS, | 83 COLUMN_GENERATION_UPLOAD_STATUS, |
| 83 }; | 84 }; |
| 84 | 85 |
| 85 enum class HistogramSize { SMALL, LARGE }; | 86 enum class HistogramSize { SMALL, LARGE }; |
| 86 | 87 |
| 88 // An enum for UMA reporting. Add values to the end only. |
| 89 enum DatabaseInitError { |
| 90 INIT_OK, |
| 91 OPEN_FILE_ERROR, |
| 92 START_TRANSACTION_ERROR, |
| 93 META_TABLE_INIT_ERROR, |
| 94 INCOMPATIBLE_VERSION, |
| 95 INIT_LOGINS_ERROR, |
| 96 INIT_STATS_ERROR, |
| 97 MIGRATION_ERROR, |
| 98 COMMIT_TRANSACTION_ERROR, |
| 99 |
| 100 DATABASE_INIT_ERROR_COUNT, |
| 101 }; |
| 102 |
| 87 void BindAddStatement(const PasswordForm& form, | 103 void BindAddStatement(const PasswordForm& form, |
| 88 const std::string& encrypted_password, | 104 const std::string& encrypted_password, |
| 89 sql::Statement* s) { | 105 sql::Statement* s) { |
| 90 s->BindString(COLUMN_ORIGIN_URL, form.origin.spec()); | 106 s->BindString(COLUMN_ORIGIN_URL, form.origin.spec()); |
| 91 s->BindString(COLUMN_ACTION_URL, form.action.spec()); | 107 s->BindString(COLUMN_ACTION_URL, form.action.spec()); |
| 92 s->BindString16(COLUMN_USERNAME_ELEMENT, form.username_element); | 108 s->BindString16(COLUMN_USERNAME_ELEMENT, form.username_element); |
| 93 s->BindString16(COLUMN_USERNAME_VALUE, form.username_value); | 109 s->BindString16(COLUMN_USERNAME_VALUE, form.username_value); |
| 94 s->BindString16(COLUMN_PASSWORD_ELEMENT, form.password_element); | 110 s->BindString16(COLUMN_PASSWORD_ELEMENT, form.password_element); |
| 95 s->BindBlob(COLUMN_PASSWORD_VALUE, encrypted_password.data(), | 111 s->BindBlob(COLUMN_PASSWORD_VALUE, encrypted_password.data(), |
| 96 static_cast<int>(encrypted_password.length())); | 112 static_cast<int>(encrypted_password.length())); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 DLOG(ERROR) << "Constraint violation: form.origin is empty"; | 147 DLOG(ERROR) << "Constraint violation: form.origin is empty"; |
| 132 return false; | 148 return false; |
| 133 } | 149 } |
| 134 if (form.signon_realm.empty()) { | 150 if (form.signon_realm.empty()) { |
| 135 DLOG(ERROR) << "Constraint violation: form.signon_realm is empty"; | 151 DLOG(ERROR) << "Constraint violation: form.signon_realm is empty"; |
| 136 return false; | 152 return false; |
| 137 } | 153 } |
| 138 return true; | 154 return true; |
| 139 } | 155 } |
| 140 | 156 |
| 157 void LogDatabaseInitError(DatabaseInitError error) { |
| 158 UMA_HISTOGRAM_ENUMERATION("PasswordManager.LoginDatabaseInit", error, |
| 159 DATABASE_INIT_ERROR_COUNT); |
| 160 } |
| 161 |
| 141 // UMA_* macros assume that the name never changes. This is a helper function | 162 // UMA_* macros assume that the name never changes. This is a helper function |
| 142 // where this assumption doesn't hold. | 163 // where this assumption doesn't hold. |
| 143 void LogDynamicUMAStat(const std::string& name, | 164 void LogDynamicUMAStat(const std::string& name, |
| 144 int sample, | 165 int sample, |
| 145 int min, | 166 int min, |
| 146 int max, | 167 int max, |
| 147 int bucket_count) { | 168 int bucket_count) { |
| 148 base::HistogramBase* counter = base::Histogram::FactoryGet( | 169 base::HistogramBase* counter = base::Histogram::FactoryGet( |
| 149 name, min, max, bucket_count, | 170 name, min, max, bucket_count, |
| 150 base::HistogramBase::kUmaTargetedHistogramFlag); | 171 base::HistogramBase::kUmaTargetedHistogramFlag); |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 290 | 311 |
| 291 bool LoginDatabase::Init() { | 312 bool LoginDatabase::Init() { |
| 292 // Set pragmas for a small, private database (based on WebDatabase). | 313 // Set pragmas for a small, private database (based on WebDatabase). |
| 293 db_.set_page_size(2048); | 314 db_.set_page_size(2048); |
| 294 db_.set_cache_size(32); | 315 db_.set_cache_size(32); |
| 295 db_.set_exclusive_locking(); | 316 db_.set_exclusive_locking(); |
| 296 db_.set_restrict_to_user(); | 317 db_.set_restrict_to_user(); |
| 297 db_.set_histogram_tag("Passwords"); | 318 db_.set_histogram_tag("Passwords"); |
| 298 | 319 |
| 299 if (!db_.Open(db_path_)) { | 320 if (!db_.Open(db_path_)) { |
| 321 LogDatabaseInitError(OPEN_FILE_ERROR); |
| 300 LOG(ERROR) << "Unable to open the password store database."; | 322 LOG(ERROR) << "Unable to open the password store database."; |
| 301 return false; | 323 return false; |
| 302 } | 324 } |
| 303 | 325 |
| 304 sql::Transaction transaction(&db_); | 326 sql::Transaction transaction(&db_); |
| 305 if (!transaction.Begin()) { | 327 if (!transaction.Begin()) { |
| 328 LogDatabaseInitError(START_TRANSACTION_ERROR); |
| 306 LOG(ERROR) << "Unable to start a transaction."; | 329 LOG(ERROR) << "Unable to start a transaction."; |
| 307 db_.Close(); | 330 db_.Close(); |
| 308 return false; | 331 return false; |
| 309 } | 332 } |
| 310 | 333 |
| 311 // Check the database version. | 334 // Check the database version. |
| 312 if (!meta_table_.Init(&db_, kCurrentVersionNumber, | 335 if (!meta_table_.Init(&db_, kCurrentVersionNumber, |
| 313 kCompatibleVersionNumber)) { | 336 kCompatibleVersionNumber)) { |
| 337 LogDatabaseInitError(META_TABLE_INIT_ERROR); |
| 314 LOG(ERROR) << "Unable to create the meta table."; | 338 LOG(ERROR) << "Unable to create the meta table."; |
| 315 db_.Close(); | 339 db_.Close(); |
| 316 return false; | 340 return false; |
| 317 } | 341 } |
| 318 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) { | 342 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) { |
| 343 LogDatabaseInitError(INCOMPATIBLE_VERSION); |
| 319 LOG(ERROR) << "Password store database is too new, kCurrentVersionNumber=" | 344 LOG(ERROR) << "Password store database is too new, kCurrentVersionNumber=" |
| 320 << kCurrentVersionNumber << ", GetCompatibleVersionNumber=" | 345 << kCurrentVersionNumber << ", GetCompatibleVersionNumber=" |
| 321 << meta_table_.GetCompatibleVersionNumber(); | 346 << meta_table_.GetCompatibleVersionNumber(); |
| 322 db_.Close(); | 347 db_.Close(); |
| 323 return false; | 348 return false; |
| 324 } | 349 } |
| 325 | 350 |
| 326 // Initialize the tables. | 351 // Initialize the tables. |
| 327 if (!InitLoginsTable()) { | 352 if (!InitLoginsTable()) { |
| 353 LogDatabaseInitError(INIT_LOGINS_ERROR); |
| 328 LOG(ERROR) << "Unable to initialize the logins table."; | 354 LOG(ERROR) << "Unable to initialize the logins table."; |
| 329 db_.Close(); | 355 db_.Close(); |
| 330 return false; | 356 return false; |
| 331 } | 357 } |
| 332 | 358 |
| 333 if (!stats_table_.Init(&db_)) { | 359 if (!stats_table_.Init(&db_)) { |
| 360 LogDatabaseInitError(INIT_STATS_ERROR); |
| 334 LOG(ERROR) << "Unable to initialize the stats table."; | 361 LOG(ERROR) << "Unable to initialize the stats table."; |
| 335 db_.Close(); | 362 db_.Close(); |
| 336 return false; | 363 return false; |
| 337 } | 364 } |
| 338 | 365 |
| 339 // If the file on disk is an older database version, bring it up to date. | 366 // If the file on disk is an older database version, bring it up to date. |
| 340 if (!MigrateOldVersionsAsNeeded()) { | 367 if (!MigrateOldVersionsAsNeeded()) { |
| 368 LogDatabaseInitError(MIGRATION_ERROR); |
| 369 UMA_HISTOGRAM_SPARSE_SLOWLY("PasswordManager.LoginDatabaseFailedVersion", |
| 370 meta_table_.GetVersionNumber()); |
| 341 LOG(ERROR) << "Unable to migrate database from " | 371 LOG(ERROR) << "Unable to migrate database from " |
| 342 << meta_table_.GetVersionNumber() << " to " | 372 << meta_table_.GetVersionNumber() << " to " |
| 343 << kCurrentVersionNumber; | 373 << kCurrentVersionNumber; |
| 344 db_.Close(); | 374 db_.Close(); |
| 345 return false; | 375 return false; |
| 346 } | 376 } |
| 347 | 377 |
| 348 if (!transaction.Commit()) { | 378 if (!transaction.Commit()) { |
| 379 LogDatabaseInitError(COMMIT_TRANSACTION_ERROR); |
| 349 LOG(ERROR) << "Unable to commit a transaction."; | 380 LOG(ERROR) << "Unable to commit a transaction."; |
| 350 db_.Close(); | 381 db_.Close(); |
| 351 return false; | 382 return false; |
| 352 } | 383 } |
| 353 | 384 |
| 385 LogDatabaseInitError(INIT_OK); |
| 354 return true; | 386 return true; |
| 355 } | 387 } |
| 356 | 388 |
| 357 bool LoginDatabase::MigrateOldVersionsAsNeeded() { | 389 bool LoginDatabase::MigrateOldVersionsAsNeeded() { |
| 358 switch (meta_table_.GetVersionNumber()) { | 390 switch (meta_table_.GetVersionNumber()) { |
| 359 case 1: | 391 case 1: |
| 360 if (!db_.Execute("ALTER TABLE logins " | 392 if (!db_.Execute("ALTER TABLE logins " |
| 361 "ADD COLUMN password_type INTEGER") || | 393 "ADD COLUMN password_type INTEGER") || |
| 362 !db_.Execute("ALTER TABLE logins " | 394 !db_.Execute("ALTER TABLE logins " |
| 363 "ADD COLUMN possible_usernames BLOB")) { | 395 "ADD COLUMN possible_usernames BLOB")) { |
| (...skipping 750 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1114 UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering", | 1146 UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering", |
| 1115 psl_domain_match_metric, PSL_DOMAIN_MATCH_COUNT); | 1147 psl_domain_match_metric, PSL_DOMAIN_MATCH_COUNT); |
| 1116 } | 1148 } |
| 1117 | 1149 |
| 1118 if (!statement->Succeeded()) | 1150 if (!statement->Succeeded()) |
| 1119 return false; | 1151 return false; |
| 1120 return true; | 1152 return true; |
| 1121 } | 1153 } |
| 1122 | 1154 |
| 1123 } // namespace password_manager | 1155 } // namespace password_manager |
| OLD | NEW |