web_database.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/webdata/web_database.h" 6 7#include <algorithm> 8#include <limits> 9#include <set> 10#include <string> 11 12#include "app/l10n_util.h" 13#include "app/sql/statement.h" 14#include "app/sql/transaction.h" 15#include "base/string_number_conversions.h" 16#include "base/string_split.h" 17#include "base/string_util.h" 18#include "base/tuple.h" 19#include "base/utf_string_conversions.h" 20#include "chrome/browser/autofill/autofill_profile.h" 21#include "chrome/browser/autofill/autofill_type.h" 22#include "chrome/browser/autofill/credit_card.h" 23#include "chrome/browser/diagnostics/sqlite_diagnostics.h" 24#include "chrome/browser/history/history_database.h" 25#include "chrome/browser/password_manager/encryptor.h" 26#include "chrome/browser/search_engines/template_url.h" 27#include "chrome/browser/webdata/autofill_change.h" 28#include "chrome/common/notification_service.h" 29#include "gfx/codec/png_codec.h" 30#include "third_party/skia/include/core/SkBitmap.h" 31#include "webkit/glue/form_field.h" 32#include "webkit/glue/password_form.h" 33 34// Encryptor is now in place for Windows and Mac. The Linux implementation 35// currently obfuscates only. Mac Encryptor implementation can block the 36// active thread while presenting UI to the user. See |encryptor_mac.mm| for 37// details. 38// For details on the Linux work see: 39// http://crbug.com/25404 40 41using webkit_glue::FormField; 42using webkit_glue::PasswordForm; 43 44//////////////////////////////////////////////////////////////////////////////// 45// 46// Schema 47// Note: The database stores time in seconds, UTC. 48// 49// keywords Most of the columns mirror that of a field in 50// TemplateURL. See TemplateURL for more details. 51// id 52// short_name 53// keyword 54// favicon_url 55// url 56// show_in_default_list 57// safe_for_autoreplace 58// originating_url 59// date_created This column was added after we allowed keywords. 60// Keywords created before we started tracking 61// creation date have a value of 0 for this. 62// usage_count 63// input_encodings Semicolon separated list of supported input 64// encodings, may be empty. 65// suggest_url 66// prepopulate_id See TemplateURL::prepopulate_id. 67// autogenerate_keyword 68// logo_id See TemplateURL::logo_id 69// created_by_policy See TemplateURL::created_by_policy. This was added 70// in version 26. 71// 72// logins 73// origin_url 74// action_url 75// username_element 76// username_value 77// password_element 78// password_value 79// submit_element 80// signon_realm The authority (scheme, host, port). 81// ssl_valid SSL status of page containing the form at first 82// impression. 83// preferred MRU bit. 84// date_created This column was added after logins support. "Legacy" 85// entries have a value of 0. 86// blacklisted_by_user Tracks whether or not the user opted to 'never 87// remember' 88// passwords for this site. 89// 90// autofill 91// name The name of the input as specified in the html. 92// value The literal contents of the text field. 93// value_lower The contents of the text field made lower_case. 94// pair_id An ID number unique to the row in the table. 95// count How many times the user has entered the string |value| 96// in a field of name |name|. 97// 98// autofill_dates This table associates a row to each separate time the 99// user submits a form containing a certain name/value 100// pair. The |pair_id| should match the |pair_id| field 101// in the appropriate row of the autofill table. 102// pair_id 103// date_created 104// 105// autofill_profiles This table contains AutoFill profile data added by the 106// user with the AutoFill dialog. Most of the columns are 107// standard entries in a contact information form. 108// 109// label The label of the profile. Presented to the user when 110// selecting profiles. 111// unique_id The unique ID of this profile. 112// first_name 113// middle_name 114// last_name 115// email 116// company_name 117// address_line_1 118// address_line_2 119// city 120// state 121// zipcode 122// country 123// phone 124// fax 125// 126// credit_cards This table contains credit card data added by the user 127// with the AutoFill dialog. Most of the columns are 128// standard entries in a credit card form. 129// 130// label The label of the credit card. Presented to the user 131// when selecting credit cards. 132// unique_id The unique ID of this credit card. 133// name_on_card 134// type 135// card_number Before version 23 stores credit card number, 23 and 136// after stores empty string. 137// expiration_month 138// expiration_year 139// verification_code Before version 23 stores the CVC/CVV/CVV2 card security 140// code. After that stores the empty string. 141// billing_address A foreign key into the autofill_profiles table. 142// shipping_address A foreign key into the autofill_profiles table. 143// For the following two fields encryption is used. Currently it uses 144// Encryptor, that does encryption on windows only. As on the other 145// systems this file is readable by owner only, it is good for now. 146// For potentially going over the wire other encryption is used, see 147// chrome/browser/sync/protocol/autofill_specifics.proto 148// card_number_encrypted Stores encrypted credit card number. 149// verification_code_encrypted The CVC/CVV/CVV2 card security code. 150// 151// web_app_icons 152// url URL of the web app. 153// width Width of the image. 154// height Height of the image. 155// image PNG encoded image data. 156// 157// web_apps 158// url URL of the web app. 159// has_all_images Do we have all the images? 160// 161//////////////////////////////////////////////////////////////////////////////// 162 163using base::Time; 164 165namespace { 166 167typedef std::vector<Tuple3<int64, string16, string16> > AutofillElementList; 168 169// Current version number. Note: when changing the current version number, 170// corresponding changes must happen in the unit tests, and new migration test 171// added. See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|. 172const int kCurrentVersionNumber = 27; 173const int kCompatibleVersionNumber = 27; 174const int kUrlIdPosition = 15; 175 176// Keys used in the meta table. 177const char* kDefaultSearchProviderKey = "Default Search Provider ID"; 178const char* kBuiltinKeywordVersion = "Builtin Keyword Version"; 179 180// The maximum length allowed for form data. 181const size_t kMaxDataLength = 1024; 182 183void BindURLToStatement(const TemplateURL& url, sql::Statement* s) { 184 s->BindString(0, WideToUTF8(url.short_name())); 185 s->BindString(1, WideToUTF8(url.keyword())); 186 GURL favicon_url = url.GetFavIconURL(); 187 if (!favicon_url.is_valid()) { 188 s->BindString(2, std::string()); 189 } else { 190 s->BindString(2, history::HistoryDatabase::GURLToDatabaseURL( 191 url.GetFavIconURL())); 192 } 193 if (url.url()) 194 s->BindString(3, url.url()->url()); 195 else 196 s->BindString(3, std::string()); 197 s->BindInt(4, url.safe_for_autoreplace() ? 1 : 0); 198 if (!url.originating_url().is_valid()) { 199 s->BindString(5, std::string()); 200 } else { 201 s->BindString(5, history::HistoryDatabase::GURLToDatabaseURL( 202 url.originating_url())); 203 } 204 s->BindInt64(6, url.date_created().ToTimeT()); 205 s->BindInt(7, url.usage_count()); 206 s->BindString(8, JoinString(url.input_encodings(), ';')); 207 s->BindInt(9, url.show_in_default_list() ? 1 : 0); 208 if (url.suggestions_url()) 209 s->BindString(10, url.suggestions_url()->url()); 210 else 211 s->BindString(10, std::string()); 212 s->BindInt(11, url.prepopulate_id()); 213 s->BindInt(12, url.autogenerate_keyword() ? 1 : 0); 214 s->BindInt(13, url.logo_id()); 215 s->BindBool(14, url.created_by_policy()); 216} 217 218void InitPasswordFormFromStatement(PasswordForm* form, sql::Statement* s) { 219 std::string tmp; 220 string16 decrypted_password; 221 tmp = s->ColumnString(0); 222 form->origin = GURL(tmp); 223 tmp = s->ColumnString(1); 224 form->action = GURL(tmp); 225 form->username_element = s->ColumnString16(2); 226 form->username_value = s->ColumnString16(3); 227 form->password_element = s->ColumnString16(4); 228 229 int encrypted_password_len = s->ColumnByteLength(5); 230 std::string encrypted_password; 231 if (encrypted_password_len) { 232 encrypted_password.resize(encrypted_password_len); 233 memcpy(&encrypted_password[0], s->ColumnBlob(5), encrypted_password_len); 234 Encryptor::DecryptString16(encrypted_password, &decrypted_password); 235 } 236 237 form->password_value = decrypted_password; 238 form->submit_element = s->ColumnString16(6); 239 tmp = s->ColumnString(7); 240 form->signon_realm = tmp; 241 form->ssl_valid = (s->ColumnInt(8) > 0); 242 form->preferred = (s->ColumnInt(9) > 0); 243 form->date_created = Time::FromTimeT(s->ColumnInt64(10)); 244 form->blacklisted_by_user = (s->ColumnInt(11) > 0); 245 int scheme_int = s->ColumnInt(12); 246 DCHECK((scheme_int >= 0) && (scheme_int <= PasswordForm::SCHEME_OTHER)); 247 form->scheme = static_cast<PasswordForm::Scheme>(scheme_int); 248} 249 250// TODO(jhawkins): This is a temporary stop-gap measure designed to prevent 251// a malicious site from DOS'ing the browser with extremely large profile 252// data. The correct solution is to parse this data asynchronously. 253// See http://crbug.com/49332. 254string16 LimitDataSize(const string16& data) { 255 if (data.size() > kMaxDataLength) 256 return data.substr(0, kMaxDataLength); 257 258 return data; 259} 260 261void BindAutoFillProfileToStatement(const AutoFillProfile& profile, 262 sql::Statement* s) { 263 s->BindString16(0, profile.Label()); 264 s->BindInt(1, profile.unique_id()); 265 266 string16 text = profile.GetFieldText(AutoFillType(NAME_FIRST)); 267 s->BindString16(2, LimitDataSize(text)); 268 text = profile.GetFieldText(AutoFillType(NAME_MIDDLE)); 269 s->BindString16(3, LimitDataSize(text)); 270 text = profile.GetFieldText(AutoFillType(NAME_LAST)); 271 s->BindString16(4, LimitDataSize(text)); 272 text = profile.GetFieldText(AutoFillType(EMAIL_ADDRESS)); 273 s->BindString16(5, LimitDataSize(text)); 274 text = profile.GetFieldText(AutoFillType(COMPANY_NAME)); 275 s->BindString16(6, LimitDataSize(text)); 276 text = profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE1)); 277 s->BindString16(7, LimitDataSize(text)); 278 text = profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE2)); 279 s->BindString16(8, LimitDataSize(text)); 280 text = profile.GetFieldText(AutoFillType(ADDRESS_HOME_CITY)); 281 s->BindString16(9, LimitDataSize(text)); 282 text = profile.GetFieldText(AutoFillType(ADDRESS_HOME_STATE)); 283 s->BindString16(10, LimitDataSize(text)); 284 text = profile.GetFieldText(AutoFillType(ADDRESS_HOME_ZIP)); 285 s->BindString16(11, LimitDataSize(text)); 286 text = profile.GetFieldText(AutoFillType(ADDRESS_HOME_COUNTRY)); 287 s->BindString16(12, LimitDataSize(text)); 288 text = profile.GetFieldText(AutoFillType(PHONE_HOME_WHOLE_NUMBER)); 289 s->BindString16(13, LimitDataSize(text)); 290 text = profile.GetFieldText(AutoFillType(PHONE_FAX_WHOLE_NUMBER)); 291 s->BindString16(14, LimitDataSize(text)); 292} 293 294AutoFillProfile* AutoFillProfileFromStatement(const sql::Statement& s) { 295 AutoFillProfile* profile = new AutoFillProfile( 296 s.ColumnString16(0), s.ColumnInt(1)); 297 profile->SetInfo(AutoFillType(NAME_FIRST), 298 s.ColumnString16(2)); 299 profile->SetInfo(AutoFillType(NAME_MIDDLE), 300 s.ColumnString16(3)); 301 profile->SetInfo(AutoFillType(NAME_LAST), 302 s.ColumnString16(4)); 303 profile->SetInfo(AutoFillType(EMAIL_ADDRESS), 304 s.ColumnString16(5)); 305 profile->SetInfo(AutoFillType(COMPANY_NAME), 306 s.ColumnString16(6)); 307 profile->SetInfo(AutoFillType(ADDRESS_HOME_LINE1), 308 s.ColumnString16(7)); 309 profile->SetInfo(AutoFillType(ADDRESS_HOME_LINE2), 310 s.ColumnString16(8)); 311 profile->SetInfo(AutoFillType(ADDRESS_HOME_CITY), 312 s.ColumnString16(9)); 313 profile->SetInfo(AutoFillType(ADDRESS_HOME_STATE), 314 s.ColumnString16(10)); 315 profile->SetInfo(AutoFillType(ADDRESS_HOME_ZIP), 316 s.ColumnString16(11)); 317 profile->SetInfo(AutoFillType(ADDRESS_HOME_COUNTRY), 318 s.ColumnString16(12)); 319 profile->SetInfo(AutoFillType(PHONE_HOME_WHOLE_NUMBER), 320 s.ColumnString16(13)); 321 profile->SetInfo(AutoFillType(PHONE_FAX_WHOLE_NUMBER), 322 s.ColumnString16(14)); 323 324 return profile; 325} 326 327void BindCreditCardToStatement(const CreditCard& credit_card, 328 sql::Statement* s) { 329 s->BindString16(0, credit_card.Label()); 330 s->BindInt(1, credit_card.unique_id()); 331 332 string16 text = credit_card.GetFieldText(AutoFillType(CREDIT_CARD_NAME)); 333 s->BindString16(2, LimitDataSize(text)); 334 text = credit_card.GetFieldText(AutoFillType(CREDIT_CARD_TYPE)); 335 s->BindString16(3, LimitDataSize(text)); 336 text.clear(); // No unencrypted cc info. 337 s->BindString16(4, LimitDataSize(text)); 338 text = credit_card.GetFieldText(AutoFillType(CREDIT_CARD_EXP_MONTH)); 339 s->BindString16(5, LimitDataSize(text)); 340 text = credit_card.GetFieldText(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR)); 341 s->BindString16(6, LimitDataSize(text)); 342 text.clear(); 343 s->BindString16(7, LimitDataSize(text)); 344 s->BindInt(8, credit_card.billing_address_id()); 345 // We don't store the shipping address anymore. 346 text.clear(); 347 s->BindString16(9, LimitDataSize(text)); 348 text = credit_card.GetFieldText(AutoFillType(CREDIT_CARD_NUMBER)); 349 std::string encrypted_data; 350 Encryptor::EncryptString16(text, &encrypted_data); 351 s->BindBlob(10, encrypted_data.data(), 352 static_cast<int>(encrypted_data.length())); 353 // We don't store the CVV anymore. 354 text.clear(); 355 s->BindBlob(11, text.data(), static_cast<int>(text.length())); 356} 357 358CreditCard* CreditCardFromStatement(const sql::Statement& s) { 359 CreditCard* credit_card = new CreditCard( 360 s.ColumnString16(0), s.ColumnInt(1)); 361 credit_card->SetInfo(AutoFillType(CREDIT_CARD_NAME), 362 s.ColumnString16(2)); 363 credit_card->SetInfo(AutoFillType(CREDIT_CARD_TYPE), 364 s.ColumnString16(3)); 365 string16 credit_card_number = s.ColumnString16(4); 366 // It could be non-empty prior to version 23. After that it encrypted in 367 // the column 10. 368 if (credit_card_number.empty()) { 369 int encrypted_cc_len = s.ColumnByteLength(10); 370 std::string encrypted_cc; 371 if (encrypted_cc_len) { 372 encrypted_cc.resize(encrypted_cc_len); 373 memcpy(&encrypted_cc[0], s.ColumnBlob(10), encrypted_cc_len); 374 Encryptor::DecryptString16(encrypted_cc, &credit_card_number); 375 } 376 } 377 credit_card->SetInfo(AutoFillType(CREDIT_CARD_NUMBER), credit_card_number); 378 credit_card->SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH), 379 s.ColumnString16(5)); 380 credit_card->SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), 381 s.ColumnString16(6)); 382 383 string16 credit_card_verification_code = s.ColumnString16(7); 384 // We don't store the CVV anymore. 385 credit_card->set_billing_address_id(s.ColumnInt(8)); 386 // We don't store the shipping address anymore. 387 // Column 10 is processed above. 388 // Column 11 is processed above. 389 390 return credit_card; 391} 392 393} // namespace 394 395WebDatabase::WebDatabase() { 396} 397 398WebDatabase::~WebDatabase() { 399} 400 401void WebDatabase::BeginTransaction() { 402 db_.BeginTransaction(); 403} 404 405void WebDatabase::CommitTransaction() { 406 db_.CommitTransaction(); 407} 408 409sql::InitStatus WebDatabase::Init(const FilePath& db_name) { 410 // When running in unit tests, there is already a NotificationService object. 411 // Since only one can exist at a time per thread, check first. 412 if (!NotificationService::current()) 413 notification_service_.reset(new NotificationService); 414 415 // Set the exceptional sqlite error handler. 416 db_.set_error_delegate(GetErrorHandlerForWebDb()); 417 418 // We don't store that much data in the tables so use a small page size. 419 // This provides a large benefit for empty tables (which is very likely with 420 // the tables we create). 421 db_.set_page_size(2048); 422 423 // We shouldn't have much data and what access we currently have is quite 424 // infrequent. So we go with a small cache size. 425 db_.set_cache_size(32); 426 427 // Run the database in exclusive mode. Nobody else should be accessing the 428 // database while we're running, and this will give somewhat improved perf. 429 db_.set_exclusive_locking(); 430 431 if (!db_.Open(db_name)) 432 return sql::INIT_FAILURE; 433 434 // Initialize various tables 435 sql::Transaction transaction(&db_); 436 if (!transaction.Begin()) 437 return sql::INIT_FAILURE; 438 439 // Version check. 440 if (!meta_table_.Init(&db_, kCurrentVersionNumber, kCompatibleVersionNumber)) 441 return sql::INIT_FAILURE; 442 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) { 443 LOG(WARNING) << "Web database is too new."; 444 return sql::INIT_TOO_NEW; 445 } 446 447 // Initialize the tables. 448 if (!InitKeywordsTable() || !InitLoginsTable() || !InitWebAppIconsTable() || 449 !InitWebAppsTable() || !InitAutofillTable() || 450 !InitAutofillDatesTable() || !InitAutoFillProfilesTable() || 451 !InitCreditCardsTable() || !InitTokenServiceTable()) { 452 LOG(WARNING) << "Unable to initialize the web database."; 453 return sql::INIT_FAILURE; 454 } 455 456 // If the file on disk is an older database version, bring it up to date. 457 MigrateOldVersionsAsNeeded(); 458 459 return transaction.Commit() ? sql::INIT_OK : sql::INIT_FAILURE; 460} 461 462bool WebDatabase::SetWebAppImage(const GURL& url, const SkBitmap& image) { 463 // Don't bother with a cached statement since this will be a relatively 464 // infrequent operation. 465 sql::Statement s(db_.GetUniqueStatement( 466 "INSERT OR REPLACE INTO web_app_icons " 467 "(url, width, height, image) VALUES (?, ?, ?, ?)")); 468 if (!s) 469 return false; 470 471 std::vector<unsigned char> image_data; 472 gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data); 473 474 s.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url)); 475 s.BindInt(1, image.width()); 476 s.BindInt(2, image.height()); 477 s.BindBlob(3, &image_data.front(), static_cast<int>(image_data.size())); 478 return s.Run(); 479} 480 481bool WebDatabase::GetWebAppImages(const GURL& url, 482 std::vector<SkBitmap>* images) { 483 sql::Statement s(db_.GetUniqueStatement( 484 "SELECT image FROM web_app_icons WHERE url=?")); 485 if (!s) { 486 NOTREACHED() << "Statement prepare failed"; 487 return false; 488 } 489 s.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url)); 490 while (s.Step()) { 491 SkBitmap image; 492 int col_bytes = s.ColumnByteLength(0); 493 if (col_bytes > 0) { 494 if (gfx::PNGCodec::Decode( 495 reinterpret_cast<const unsigned char*>(s.ColumnBlob(0)), 496 col_bytes, &image)) { 497 images->push_back(image); 498 } else { 499 // Should only have valid image data in the db. 500 NOTREACHED(); 501 } 502 } 503 } 504 return true; 505} 506 507bool WebDatabase::SetWebAppHasAllImages(const GURL& url, 508 bool has_all_images) { 509 sql::Statement s(db_.GetUniqueStatement( 510 "INSERT OR REPLACE INTO web_apps (url, has_all_images) VALUES (?, ?)")); 511 if (!s) { 512 NOTREACHED() << "Statement prepare failed"; 513 return false; 514 } 515 s.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url)); 516 s.BindInt(1, has_all_images ? 1 : 0); 517 return s.Run(); 518} 519 520bool WebDatabase::GetWebAppHasAllImages(const GURL& url) { 521 sql::Statement s(db_.GetUniqueStatement( 522 "SELECT has_all_images FROM web_apps WHERE url=?")); 523 if (!s) { 524 NOTREACHED() << "Statement prepare failed"; 525 return false; 526 } 527 s.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url)); 528 return (s.Step() && s.ColumnInt(0) == 1); 529} 530 531bool WebDatabase::RemoveWebApp(const GURL& url) { 532 sql::Statement delete_s(db_.GetUniqueStatement( 533 "DELETE FROM web_app_icons WHERE url = ?")); 534 if (!delete_s) { 535 NOTREACHED() << "Statement prepare failed"; 536 return false; 537 } 538 delete_s.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url)); 539 if (!delete_s.Run()) 540 return false; 541 542 sql::Statement delete_s2(db_.GetUniqueStatement( 543 "DELETE FROM web_apps WHERE url = ?")); 544 if (!delete_s2) { 545 NOTREACHED() << "Statement prepare failed"; 546 return false; 547 } 548 delete_s2.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url)); 549 return delete_s2.Run(); 550} 551 552bool WebDatabase::RemoveAllTokens() { 553 sql::Statement s(db_.GetUniqueStatement( 554 "DELETE FROM token_service")); 555 if (!s) { 556 NOTREACHED() << "Statement prepare failed"; 557 return false; 558 } 559 560 return s.Run(); 561} 562 563bool WebDatabase::SetTokenForService(const std::string& service, 564 const std::string& token) { 565 // Don't bother with a cached statement since this will be a relatively 566 // infrequent operation. 567 sql::Statement s(db_.GetUniqueStatement( 568 "INSERT OR REPLACE INTO token_service " 569 "(service, encrypted_token) VALUES (?, ?)")); 570 if (!s) { 571 NOTREACHED() << "Statement prepare failed"; 572 return false; 573 } 574 575 std::string encrypted_token; 576 577 bool encrypted = Encryptor::EncryptString(token, &encrypted_token); 578 if (!encrypted) { 579 return false; 580 } 581 582 s.BindString(0, service); 583 s.BindBlob(1, encrypted_token.data(), 584 static_cast<int>(encrypted_token.length())); 585 return s.Run(); 586} 587 588bool WebDatabase::GetAllTokens(std::map<std::string, std::string>* tokens) { 589 sql::Statement s(db_.GetUniqueStatement( 590 "SELECT service, encrypted_token FROM token_service")); 591 if (!s) { 592 NOTREACHED() << "Statement prepare failed"; 593 return false; 594 } 595 596 while (s.Step()) { 597 std::string encrypted_token; 598 std::string decrypted_token; 599 std::string service; 600 service = s.ColumnString(0); 601 bool entry_ok = !service.empty() && 602 s.ColumnBlobAsString(1, &encrypted_token); 603 if (entry_ok) { 604 Encryptor::DecryptString(encrypted_token, &decrypted_token); 605 (*tokens)[service] = decrypted_token; 606 } else { 607 NOTREACHED(); 608 return false; 609 } 610 } 611 return true; 612} 613 614bool WebDatabase::InitKeywordsTable() { 615 if (!db_.DoesTableExist("keywords")) { 616 if (!db_.Execute("CREATE TABLE keywords (" 617 "id INTEGER PRIMARY KEY," 618 "short_name VARCHAR NOT NULL," 619 "keyword VARCHAR NOT NULL," 620 "favicon_url VARCHAR NOT NULL," 621 "url VARCHAR NOT NULL," 622 "show_in_default_list INTEGER," 623 "safe_for_autoreplace INTEGER," 624 "originating_url VARCHAR," 625 "date_created INTEGER DEFAULT 0," 626 "usage_count INTEGER DEFAULT 0," 627 "input_encodings VARCHAR," 628 "suggest_url VARCHAR," 629 "prepopulate_id INTEGER DEFAULT 0," 630 "autogenerate_keyword INTEGER DEFAULT 0," 631 "logo_id INTEGER DEFAULT 0," 632 "created_by_policy INTEGER DEFAULT 0)")) { 633 NOTREACHED(); 634 return false; 635 } 636 } 637 return true; 638} 639 640bool WebDatabase::InitLoginsTable() { 641 if (!db_.DoesTableExist("logins")) { 642 if (!db_.Execute("CREATE TABLE logins (" 643 "origin_url VARCHAR NOT NULL, " 644 "action_url VARCHAR, " 645 "username_element VARCHAR, " 646 "username_value VARCHAR, " 647 "password_element VARCHAR, " 648 "password_value BLOB, " 649 "submit_element VARCHAR, " 650 "signon_realm VARCHAR NOT NULL," 651 "ssl_valid INTEGER NOT NULL," 652 "preferred INTEGER NOT NULL," 653 "date_created INTEGER NOT NULL," 654 "blacklisted_by_user INTEGER NOT NULL," 655 "scheme INTEGER NOT NULL," 656 "UNIQUE " 657 "(origin_url, username_element, " 658 "username_value, password_element, " 659 "submit_element, signon_realm))")) { 660 NOTREACHED(); 661 return false; 662 } 663 if (!db_.Execute("CREATE INDEX logins_signon ON logins (signon_realm)")) { 664 NOTREACHED(); 665 return false; 666 } 667 } 668 669#if defined(OS_WIN) 670 if (!db_.DoesTableExist("ie7_logins")) { 671 if (!db_.Execute("CREATE TABLE ie7_logins (" 672 "url_hash VARCHAR NOT NULL, " 673 "password_value BLOB, " 674 "date_created INTEGER NOT NULL," 675 "UNIQUE " 676 "(url_hash))")) { 677 NOTREACHED(); 678 return false; 679 } 680 if (!db_.Execute("CREATE INDEX ie7_logins_hash ON " 681 "ie7_logins (url_hash)")) { 682 NOTREACHED(); 683 return false; 684 } 685 } 686#endif 687 688 return true; 689} 690 691bool WebDatabase::InitAutofillTable() { 692 if (!db_.DoesTableExist("autofill")) { 693 if (!db_.Execute("CREATE TABLE autofill (" 694 "name VARCHAR, " 695 "value VARCHAR, " 696 "value_lower VARCHAR, " 697 "pair_id INTEGER PRIMARY KEY, " 698 "count INTEGER DEFAULT 1)")) { 699 NOTREACHED(); 700 return false; 701 } 702 if (!db_.Execute("CREATE INDEX autofill_name ON autofill (name)")) { 703 NOTREACHED(); 704 return false; 705 } 706 if (!db_.Execute("CREATE INDEX autofill_name_value_lower ON " 707 "autofill (name, value_lower)")) { 708 NOTREACHED(); 709 return false; 710 } 711 } 712 return true; 713} 714 715bool WebDatabase::InitAutofillDatesTable() { 716 if (!db_.DoesTableExist("autofill_dates")) { 717 if (!db_.Execute("CREATE TABLE autofill_dates ( " 718 "pair_id INTEGER DEFAULT 0, " 719 "date_created INTEGER DEFAULT 0)")) { 720 NOTREACHED(); 721 return false; 722 } 723 if (!db_.Execute("CREATE INDEX autofill_dates_pair_id ON " 724 "autofill_dates (pair_id)")) { 725 NOTREACHED(); 726 return false; 727 } 728 } 729 return true; 730} 731 732bool WebDatabase::InitAutoFillProfilesTable() { 733 if (!db_.DoesTableExist("autofill_profiles")) { 734 if (!db_.Execute("CREATE TABLE autofill_profiles ( " 735 "label VARCHAR, " 736 "unique_id INTEGER PRIMARY KEY, " 737 "first_name VARCHAR, " 738 "middle_name VARCHAR, " 739 "last_name VARCHAR, " 740 "email VARCHAR, " 741 "company_name VARCHAR, " 742 "address_line_1 VARCHAR, " 743 "address_line_2 VARCHAR, " 744 "city VARCHAR, " 745 "state VARCHAR, " 746 "zipcode VARCHAR, " 747 "country VARCHAR, " 748 "phone VARCHAR, " 749 "fax VARCHAR)")) { 750 NOTREACHED(); 751 return false; 752 } 753 if (!db_.Execute("CREATE INDEX autofill_profiles_label_index " 754 "ON autofill_profiles (label)")) { 755 NOTREACHED(); 756 return false; 757 } 758 } 759 return true; 760} 761 762bool WebDatabase::InitCreditCardsTable() { 763 if (!db_.DoesTableExist("credit_cards")) { 764 if (!db_.Execute("CREATE TABLE credit_cards ( " 765 "label VARCHAR, " 766 "unique_id INTEGER PRIMARY KEY, " 767 "name_on_card VARCHAR, " 768 "type VARCHAR, " 769 "card_number VARCHAR, " 770 "expiration_month INTEGER, " 771 "expiration_year INTEGER, " 772 "verification_code VARCHAR, " 773 "billing_address VARCHAR, " 774 "shipping_address VARCHAR, " 775 "card_number_encrypted BLOB, " 776 "verification_code_encrypted BLOB)")) { 777 NOTREACHED(); 778 return false; 779 } 780 if (!db_.Execute("CREATE INDEX credit_cards_label_index " 781 "ON credit_cards (label)")) { 782 NOTREACHED(); 783 return false; 784 } 785 } 786 return true; 787} 788 789bool WebDatabase::InitWebAppIconsTable() { 790 if (!db_.DoesTableExist("web_app_icons")) { 791 if (!db_.Execute("CREATE TABLE web_app_icons (" 792 "url LONGVARCHAR," 793 "width int," 794 "height int," 795 "image BLOB, UNIQUE (url, width, height))")) { 796 NOTREACHED(); 797 return false; 798 } 799 } 800 return true; 801} 802 803bool WebDatabase::InitWebAppsTable() { 804 if (!db_.DoesTableExist("web_apps")) { 805 if (!db_.Execute("CREATE TABLE web_apps (" 806 "url LONGVARCHAR UNIQUE," 807 "has_all_images INTEGER NOT NULL)")) { 808 NOTREACHED(); 809 return false; 810 } 811 if (!db_.Execute("CREATE INDEX web_apps_url_index ON web_apps (url)")) { 812 NOTREACHED(); 813 return false; 814 } 815 } 816 return true; 817} 818 819bool WebDatabase::InitTokenServiceTable() { 820 if (!db_.DoesTableExist("token_service")) { 821 if (!db_.Execute("CREATE TABLE token_service (" 822 "service VARCHAR PRIMARY KEY NOT NULL," 823 "encrypted_token BLOB)")) { 824 NOTREACHED(); 825 return false; 826 } 827 } 828 return true; 829} 830 831bool WebDatabase::AddKeyword(const TemplateURL& url) { 832 DCHECK(url.id()); 833 // Be sure to change kUrlIdPosition if you add columns 834 sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, 835 "INSERT INTO keywords " 836 "(short_name, keyword, favicon_url, url, safe_for_autoreplace, " 837 "originating_url, date_created, usage_count, input_encodings, " 838 "show_in_default_list, suggest_url, prepopulate_id, " 839 "autogenerate_keyword, logo_id, created_by_policy, id) VALUES " 840 "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)")); 841 if (!s) { 842 NOTREACHED() << "Statement prepare failed"; 843 return false; 844 } 845 BindURLToStatement(url, &s); 846 s.BindInt64(kUrlIdPosition, url.id()); 847 if (!s.Run()) { 848 NOTREACHED(); 849 return false; 850 } 851 return true; 852} 853 854bool WebDatabase::RemoveKeyword(TemplateURLID id) { 855 DCHECK(id); 856 sql::Statement s(db_.GetUniqueStatement("DELETE FROM keywords WHERE id = ?")); 857 if (!s) { 858 NOTREACHED() << "Statement prepare failed"; 859 return false; 860 } 861 s.BindInt64(0, id); 862 return s.Run(); 863} 864 865bool WebDatabase::GetKeywords(std::vector<TemplateURL*>* urls) { 866 sql::Statement s(db_.GetUniqueStatement( 867 "SELECT id, short_name, keyword, favicon_url, url, " 868 "safe_for_autoreplace, originating_url, date_created, " 869 "usage_count, input_encodings, show_in_default_list, " 870 "suggest_url, prepopulate_id, autogenerate_keyword, logo_id, " 871 "created_by_policy " 872 "FROM keywords ORDER BY id ASC")); 873 if (!s) { 874 NOTREACHED() << "Statement prepare failed"; 875 return false; 876 } 877 while (s.Step()) { 878 TemplateURL* template_url = new TemplateURL(); 879 template_url->set_id(s.ColumnInt64(0)); 880 881 std::string tmp; 882 tmp = s.ColumnString(1); 883 DCHECK(!tmp.empty()); 884 template_url->set_short_name(UTF8ToWide(tmp)); 885 886 tmp = s.ColumnString(2); 887 template_url->set_keyword(UTF8ToWide(tmp)); 888 889 tmp = s.ColumnString(3); 890 if (!tmp.empty()) 891 template_url->SetFavIconURL(GURL(tmp)); 892 893 tmp = s.ColumnString(4); 894 template_url->SetURL(tmp, 0, 0); 895 896 template_url->set_safe_for_autoreplace(s.ColumnInt(5) == 1); 897 898 tmp = s.ColumnString(6); 899 if (!tmp.empty()) 900 template_url->set_originating_url(GURL(tmp)); 901 902 template_url->set_date_created(Time::FromTimeT(s.ColumnInt64(7))); 903 904 template_url->set_usage_count(s.ColumnInt(8)); 905 906 std::vector<std::string> encodings; 907 SplitString(s.ColumnString(9), ';', &encodings); 908 template_url->set_input_encodings(encodings); 909 910 template_url->set_show_in_default_list(s.ColumnInt(10) == 1); 911 912 tmp = s.ColumnString(11); 913 template_url->SetSuggestionsURL(tmp, 0, 0); 914 915 template_url->set_prepopulate_id(s.ColumnInt(12)); 916 917 template_url->set_autogenerate_keyword(s.ColumnInt(13) == 1); 918 919 template_url->set_logo_id(s.ColumnInt(14)); 920 921 template_url->set_created_by_policy(s.ColumnBool(15)); 922 923 urls->push_back(template_url); 924 } 925 return s.Succeeded(); 926} 927 928bool WebDatabase::UpdateKeyword(const TemplateURL& url) { 929 DCHECK(url.id()); 930 // Be sure to change kUrlIdPosition if you add columns 931 sql::Statement s(db_.GetUniqueStatement( 932 "UPDATE keywords " 933 "SET short_name=?, keyword=?, favicon_url=?, url=?, " 934 "safe_for_autoreplace=?, originating_url=?, date_created=?, " 935 "usage_count=?, input_encodings=?, show_in_default_list=?, " 936 "suggest_url=?, prepopulate_id=?, autogenerate_keyword=?, " 937 "logo_id=?, created_by_policy=? WHERE id=?")); 938 if (!s) { 939 NOTREACHED() << "Statement prepare failed"; 940 return false; 941 } 942 BindURLToStatement(url, &s); 943 s.BindInt64(kUrlIdPosition, url.id()); 944 return s.Run(); 945} 946 947bool WebDatabase::SetDefaultSearchProviderID(int64 id) { 948 return meta_table_.SetValue(kDefaultSearchProviderKey, id); 949} 950 951int64 WebDatabase::GetDefaulSearchProviderID() { 952 int64 value = 0; 953 meta_table_.GetValue(kDefaultSearchProviderKey, &value); 954 return value; 955} 956 957bool WebDatabase::SetBuitinKeywordVersion(int version) { 958 return meta_table_.SetValue(kBuiltinKeywordVersion, version); 959} 960 961int WebDatabase::GetBuitinKeywordVersion() { 962 int version = 0; 963 meta_table_.GetValue(kBuiltinKeywordVersion, &version); 964 return version; 965} 966 967bool WebDatabase::AddLogin(const PasswordForm& form) { 968 sql::Statement s(db_.GetUniqueStatement( 969 "INSERT OR REPLACE INTO logins " 970 "(origin_url, action_url, username_element, username_value, " 971 " password_element, password_value, submit_element, " 972 " signon_realm, ssl_valid, preferred, date_created, " 973 " blacklisted_by_user, scheme) " 974 "VALUES " 975 "(?,?,?,?,?,?,?,?,?,?,?,?,?)")); 976 if (!s) { 977 NOTREACHED() << "Statement prepare failed"; 978 return false; 979 } 980 981 std::string encrypted_password; 982 s.BindString(0, form.origin.spec()); 983 s.BindString(1, form.action.spec()); 984 s.BindString16(2, form.username_element); 985 s.BindString16(3, form.username_value); 986 s.BindString16(4, form.password_element); 987 Encryptor::EncryptString16(form.password_value, &encrypted_password); 988 s.BindBlob(5, encrypted_password.data(), 989 static_cast<int>(encrypted_password.length())); 990 s.BindString16(6, form.submit_element); 991 s.BindString(7, form.signon_realm); 992 s.BindInt(8, form.ssl_valid); 993 s.BindInt(9, form.preferred); 994 s.BindInt64(10, form.date_created.ToTimeT()); 995 s.BindInt(11, form.blacklisted_by_user); 996 s.BindInt(12, form.scheme); 997 if (!s.Run()) { 998 NOTREACHED(); 999 return false; 1000 } 1001 return true; 1002} 1003 1004bool WebDatabase::UpdateLogin(const PasswordForm& form) { 1005 sql::Statement s(db_.GetUniqueStatement( 1006 "UPDATE logins SET " 1007 "action_url = ?, " 1008 "password_value = ?, " 1009 "ssl_valid = ?, " 1010 "preferred = ? " 1011 "WHERE origin_url = ? AND " 1012 "username_element = ? AND " 1013 "username_value = ? AND " 1014 "password_element = ? AND " 1015 "signon_realm = ?")); 1016 if (!s) { 1017 NOTREACHED() << "Statement prepare failed"; 1018 return false; 1019 } 1020 1021 s.BindString(0, form.action.spec()); 1022 std::string encrypted_password; 1023 Encryptor::EncryptString16(form.password_value, &encrypted_password); 1024 s.BindBlob(1, encrypted_password.data(), 1025 static_cast<int>(encrypted_password.length())); 1026 s.BindInt(2, form.ssl_valid); 1027 s.BindInt(3, form.preferred); 1028 s.BindString(4, form.origin.spec()); 1029 s.BindString16(5, form.username_element); 1030 s.BindString16(6, form.username_value); 1031 s.BindString16(7, form.password_element); 1032 s.BindString(8, form.signon_realm); 1033 1034 if (!s.Run()) { 1035 NOTREACHED(); 1036 return false; 1037 } 1038 return true; 1039} 1040 1041bool WebDatabase::RemoveLogin(const PasswordForm& form) { 1042 // Remove a login by UNIQUE-constrained fields. 1043 sql::Statement s(db_.GetUniqueStatement( 1044 "DELETE FROM logins WHERE " 1045 "origin_url = ? AND " 1046 "username_element = ? AND " 1047 "username_value = ? AND " 1048 "password_element = ? AND " 1049 "submit_element = ? AND " 1050 "signon_realm = ?")); 1051 if (!s) { 1052 NOTREACHED() << "Statement prepare failed"; 1053 return false; 1054 } 1055 s.BindString(0, form.origin.spec()); 1056 s.BindString16(1, form.username_element); 1057 s.BindString16(2, form.username_value); 1058 s.BindString16(3, form.password_element); 1059 s.BindString16(4, form.submit_element); 1060 s.BindString(5, form.signon_realm); 1061 1062 if (!s.Run()) { 1063 NOTREACHED(); 1064 return false; 1065 } 1066 return true; 1067} 1068 1069bool WebDatabase::RemoveLoginsCreatedBetween(base::Time delete_begin, 1070 base::Time delete_end) { 1071 sql::Statement s1(db_.GetUniqueStatement( 1072 "DELETE FROM logins WHERE " 1073 "date_created >= ? AND date_created < ?")); 1074 if (!s1) { 1075 NOTREACHED() << "Statement 1 prepare failed"; 1076 return false; 1077 } 1078 s1.BindInt64(0, delete_begin.ToTimeT()); 1079 s1.BindInt64(1, 1080 delete_end.is_null() ? 1081 std::numeric_limits<int64>::max() : 1082 delete_end.ToTimeT()); 1083 bool success = s1.Run(); 1084 1085#if defined(OS_WIN) 1086 sql::Statement s2(db_.GetUniqueStatement( 1087 "DELETE FROM ie7_logins WHERE date_created >= ? AND date_created < ?")); 1088 if (!s2) { 1089 NOTREACHED() << "Statement 2 prepare failed"; 1090 return false; 1091 } 1092 s2.BindInt64(0, delete_begin.ToTimeT()); 1093 s2.BindInt64(1, 1094 delete_end.is_null() ? 1095 std::numeric_limits<int64>::max() : 1096 delete_end.ToTimeT()); 1097 success = success && s2.Run(); 1098#endif 1099 1100 return success; 1101} 1102 1103bool WebDatabase::GetLogins(const PasswordForm& form, 1104 std::vector<PasswordForm*>* forms) { 1105 DCHECK(forms); 1106 sql::Statement s(db_.GetUniqueStatement( 1107 "SELECT origin_url, action_url, " 1108 "username_element, username_value, " 1109 "password_element, password_value, " 1110 "submit_element, signon_realm, " 1111 "ssl_valid, preferred, " 1112 "date_created, blacklisted_by_user, scheme FROM logins " 1113 "WHERE signon_realm == ?")); 1114 if (!s) { 1115 NOTREACHED() << "Statement prepare failed"; 1116 return false; 1117 } 1118 1119 s.BindString(0, form.signon_realm); 1120 1121 while (s.Step()) { 1122 PasswordForm* new_form = new PasswordForm(); 1123 InitPasswordFormFromStatement(new_form, &s); 1124 1125 forms->push_back(new_form); 1126 } 1127 return s.Succeeded(); 1128} 1129 1130bool WebDatabase::GetAllLogins(std::vector<PasswordForm*>* forms, 1131 bool include_blacklisted) { 1132 DCHECK(forms); 1133 std::string stmt = "SELECT origin_url, action_url, " 1134 "username_element, username_value, " 1135 "password_element, password_value, " 1136 "submit_element, signon_realm, ssl_valid, preferred, " 1137 "date_created, blacklisted_by_user, scheme FROM logins "; 1138 if (!include_blacklisted) 1139 stmt.append("WHERE blacklisted_by_user == 0 "); 1140 stmt.append("ORDER BY origin_url"); 1141 1142 sql::Statement s(db_.GetUniqueStatement(stmt.c_str())); 1143 if (!s) { 1144 NOTREACHED() << "Statement prepare failed"; 1145 return false; 1146 } 1147 1148 while (s.Step()) { 1149 PasswordForm* new_form = new PasswordForm(); 1150 InitPasswordFormFromStatement(new_form, &s); 1151 1152 forms->push_back(new_form); 1153 } 1154 return s.Succeeded(); 1155} 1156 1157bool WebDatabase::AddFormFieldValues(const std::vector<FormField>& elements, 1158 std::vector<AutofillChange>* changes) { 1159 return AddFormFieldValuesTime(elements, changes, Time::Now()); 1160} 1161 1162bool WebDatabase::AddFormFieldValuesTime(const std::vector<FormField>& elements, 1163 std::vector<AutofillChange>* changes, 1164 base::Time time) { 1165 // Only add one new entry for each unique element name. Use |seen_names| to 1166 // track this. Add up to |kMaximumUniqueNames| unique entries per form. 1167 const size_t kMaximumUniqueNames = 256; 1168 std::set<string16> seen_names; 1169 bool result = true; 1170 for (std::vector<FormField>::const_iterator 1171 itr = elements.begin(); 1172 itr != elements.end(); 1173 itr++) { 1174 if (seen_names.size() >= kMaximumUniqueNames) 1175 break; 1176 if (seen_names.find(itr->name()) != seen_names.end()) 1177 continue; 1178 result = result && AddFormFieldValueTime(*itr, changes, time); 1179 seen_names.insert(itr->name()); 1180 } 1181 return result; 1182} 1183 1184bool WebDatabase::ClearAutofillEmptyValueElements() { 1185 sql::Statement s(db_.GetUniqueStatement( 1186 "SELECT pair_id FROM autofill WHERE TRIM(value)= \"\"")); 1187 if (!s) { 1188 NOTREACHED() << "Statement prepare failed"; 1189 return false; 1190 } 1191 1192 std::set<int64> ids; 1193 while (s.Step()) 1194 ids.insert(s.ColumnInt64(0)); 1195 1196 bool success = true; 1197 for (std::set<int64>::const_iterator iter = ids.begin(); iter != ids.end(); 1198 ++iter) { 1199 if (!RemoveFormElementForID(*iter)) 1200 success = false; 1201 } 1202 1203 return success; 1204} 1205 1206bool WebDatabase::GetIDAndCountOfFormElement( 1207 const FormField& element, 1208 int64* pair_id, 1209 int* count) { 1210 sql::Statement s(db_.GetUniqueStatement( 1211 "SELECT pair_id, count FROM autofill " 1212 "WHERE name = ? AND value = ?")); 1213 if (!s) { 1214 NOTREACHED() << "Statement prepare failed"; 1215 return false; 1216 } 1217 1218 s.BindString16(0, element.name()); 1219 s.BindString16(1, element.value()); 1220 1221 *count = 0; 1222 1223 if (s.Step()) { 1224 *pair_id = s.ColumnInt64(0); 1225 *count = s.ColumnInt(1); 1226 } 1227 1228 return true; 1229} 1230 1231bool WebDatabase::GetCountOfFormElement(int64 pair_id, int* count) { 1232 sql::Statement s(db_.GetUniqueStatement( 1233 "SELECT count FROM autofill WHERE pair_id = ?")); 1234 if (!s) { 1235 NOTREACHED() << "Statement prepare failed"; 1236 return false; 1237 } 1238 1239 s.BindInt64(0, pair_id); 1240 1241 if (s.Step()) { 1242 *count = s.ColumnInt(0); 1243 return true; 1244 } 1245 return false; 1246} 1247 1248bool WebDatabase::GetAllAutofillEntries(std::vector<AutofillEntry>* entries) { 1249 DCHECK(entries); 1250 sql::Statement s(db_.GetUniqueStatement( 1251 "SELECT name, value, date_created FROM autofill a JOIN " 1252 "autofill_dates ad ON a.pair_id=ad.pair_id")); 1253 1254 if (!s) { 1255 NOTREACHED() << "Statement prepare failed"; 1256 return false; 1257 } 1258 1259 bool first_entry = true; 1260 AutofillKey* current_key_ptr = NULL; 1261 std::vector<base::Time>* timestamps_ptr = NULL; 1262 string16 name, value; 1263 base::Time time; 1264 while (s.Step()) { 1265 name = s.ColumnString16(0); 1266 value = s.ColumnString16(1); 1267 time = Time::FromTimeT(s.ColumnInt64(2)); 1268 1269 if (first_entry) { 1270 current_key_ptr = new AutofillKey(name, value); 1271 1272 timestamps_ptr = new std::vector<base::Time>; 1273 timestamps_ptr->push_back(time); 1274 1275 first_entry = false; 1276 } else { 1277 // we've encountered the next entry 1278 if (current_key_ptr->name().compare(name) != 0 || 1279 current_key_ptr->value().compare(value) != 0) { 1280 AutofillEntry entry(*current_key_ptr, *timestamps_ptr); 1281 entries->push_back(entry); 1282 1283 delete current_key_ptr; 1284 delete timestamps_ptr; 1285 1286 current_key_ptr = new AutofillKey(name, value); 1287 timestamps_ptr = new std::vector<base::Time>; 1288 } 1289 timestamps_ptr->push_back(time); 1290 } 1291 } 1292 // If there is at least one result returned, first_entry will be false. 1293 // For this case we need to do a final cleanup step. 1294 if (!first_entry) { 1295 AutofillEntry entry(*current_key_ptr, *timestamps_ptr); 1296 entries->push_back(entry); 1297 delete current_key_ptr; 1298 delete timestamps_ptr; 1299 } 1300 1301 return s.Succeeded(); 1302} 1303 1304bool WebDatabase::GetAutofillTimestamps(const string16& name, 1305 const string16& value, 1306 std::vector<base::Time>* timestamps) { 1307 DCHECK(timestamps); 1308 sql::Statement s(db_.GetUniqueStatement( 1309 "SELECT date_created FROM autofill a JOIN " 1310 "autofill_dates ad ON a.pair_id=ad.pair_id " 1311 "WHERE a.name = ? AND a.value = ?")); 1312 1313 if (!s) { 1314 NOTREACHED() << "Statement prepare failed"; 1315 return false; 1316 } 1317 1318 s.BindString16(0, name); 1319 s.BindString16(1, value); 1320 while (s.Step()) { 1321 timestamps->push_back(Time::FromTimeT(s.ColumnInt64(0))); 1322 } 1323 1324 return s.Succeeded(); 1325} 1326 1327bool WebDatabase::UpdateAutofillEntries( 1328 const std::vector<AutofillEntry>& entries) { 1329 if (!entries.size()) 1330 return true; 1331 1332 // Remove all existing entries. 1333 for (size_t i = 0; i < entries.size(); i++) { 1334 std::string sql = "SELECT pair_id FROM autofill " 1335 "WHERE name = ? AND value = ?"; 1336 sql::Statement s(db_.GetUniqueStatement(sql.c_str())); 1337 if (!s.is_valid()) { 1338 NOTREACHED() << "Statement prepare failed"; 1339 return false; 1340 } 1341 1342 s.BindString16(0, entries[i].key().name()); 1343 s.BindString16(1, entries[i].key().value()); 1344 if (s.Step()) { 1345 if (!RemoveFormElementForID(s.ColumnInt64(0))) 1346 return false; 1347 } 1348 } 1349 1350 // Insert all the supplied autofill entries. 1351 for (size_t i = 0; i < entries.size(); i++) { 1352 if (!InsertAutofillEntry(entries[i])) 1353 return false; 1354 } 1355 1356 return true; 1357} 1358 1359bool WebDatabase::InsertAutofillEntry(const AutofillEntry& entry) { 1360 std::string sql = "INSERT INTO autofill (name, value, value_lower, count) " 1361 "VALUES (?, ?, ?, ?)"; 1362 sql::Statement s(db_.GetUniqueStatement(sql.c_str())); 1363 if (!s.is_valid()) { 1364 NOTREACHED() << "Statement prepare failed"; 1365 return false; 1366 } 1367 1368 s.BindString16(0, entry.key().name()); 1369 s.BindString16(1, entry.key().value()); 1370 s.BindString16(2, l10n_util::ToLower(entry.key().value())); 1371 s.BindInt(3, entry.timestamps().size()); 1372 1373 if (!s.Run()) { 1374 NOTREACHED(); 1375 return false; 1376 } 1377 1378 int64 pair_id = db_.GetLastInsertRowId(); 1379 for (size_t i = 0; i < entry.timestamps().size(); i++) { 1380 if (!InsertPairIDAndDate(pair_id, entry.timestamps()[i])) 1381 return false; 1382 } 1383 1384 return true; 1385} 1386 1387bool WebDatabase::InsertFormElement(const FormField& element, 1388 int64* pair_id) { 1389 sql::Statement s(db_.GetUniqueStatement( 1390 "INSERT INTO autofill (name, value, value_lower) VALUES (?,?,?)")); 1391 if (!s) { 1392 NOTREACHED() << "Statement prepare failed"; 1393 return false; 1394 } 1395 1396 s.BindString16(0, element.name()); 1397 s.BindString16(1, element.value()); 1398 s.BindString16(2, l10n_util::ToLower(element.value())); 1399 1400 if (!s.Run()) { 1401 NOTREACHED(); 1402 return false; 1403 } 1404 1405 *pair_id = db_.GetLastInsertRowId(); 1406 return true; 1407} 1408 1409bool WebDatabase::InsertPairIDAndDate(int64 pair_id, 1410 base::Time date_created) { 1411 sql::Statement s(db_.GetUniqueStatement( 1412 "INSERT INTO autofill_dates " 1413 "(pair_id, date_created) VALUES (?, ?)")); 1414 if (!s) { 1415 NOTREACHED() << "Statement prepare failed"; 1416 return false; 1417 } 1418 1419 s.BindInt64(0, pair_id); 1420 s.BindInt64(1, date_created.ToTimeT()); 1421 1422 if (!s.Run()) { 1423 NOTREACHED(); 1424 return false; 1425 } 1426 1427 return true; 1428} 1429 1430bool WebDatabase::SetCountOfFormElement(int64 pair_id, int count) { 1431 sql::Statement s(db_.GetUniqueStatement( 1432 "UPDATE autofill SET count = ? WHERE pair_id = ?")); 1433 if (!s) { 1434 NOTREACHED() << "Statement prepare failed"; 1435 return false; 1436 } 1437 1438 s.BindInt(0, count); 1439 s.BindInt64(1, pair_id); 1440 if (!s.Run()) { 1441 NOTREACHED(); 1442 return false; 1443 } 1444 1445 return true; 1446} 1447 1448bool WebDatabase::AddFormFieldValue(const FormField& element, 1449 std::vector<AutofillChange>* changes) { 1450 return AddFormFieldValueTime(element, changes, base::Time::Now()); 1451} 1452 1453bool WebDatabase::AddFormFieldValueTime(const FormField& element, 1454 std::vector<AutofillChange>* changes, 1455 base::Time time) { 1456 int count = 0; 1457 int64 pair_id; 1458 1459 if (!GetIDAndCountOfFormElement(element, &pair_id, &count)) 1460 return false; 1461 1462 if (count == 0 && !InsertFormElement(element, &pair_id)) 1463 return false; 1464 1465 if (!SetCountOfFormElement(pair_id, count + 1)) 1466 return false; 1467 1468 if (!InsertPairIDAndDate(pair_id, time)) 1469 return false; 1470 1471 AutofillChange::Type change_type = 1472 count == 0 ? AutofillChange::ADD : AutofillChange::UPDATE; 1473 changes->push_back( 1474 AutofillChange(change_type, 1475 AutofillKey(element.name(), element.value()))); 1476 return true; 1477} 1478 1479bool WebDatabase::GetFormValuesForElementName(const string16& name, 1480 const string16& prefix, 1481 std::vector<string16>* values, 1482 int limit) { 1483 DCHECK(values); 1484 sql::Statement s; 1485 1486 if (prefix.empty()) { 1487 s.Assign(db_.GetUniqueStatement( 1488 "SELECT value FROM autofill " 1489 "WHERE name = ? " 1490 "ORDER BY count DESC " 1491 "LIMIT ?")); 1492 if (!s) { 1493 NOTREACHED() << "Statement prepare failed"; 1494 return false; 1495 } 1496 1497 s.BindString16(0, name); 1498 s.BindInt(1, limit); 1499 } else { 1500 string16 prefix_lower = l10n_util::ToLower(prefix); 1501 string16 next_prefix = prefix_lower; 1502 next_prefix[next_prefix.length() - 1]++; 1503 1504 s.Assign(db_.GetUniqueStatement( 1505 "SELECT value FROM autofill " 1506 "WHERE name = ? AND " 1507 "value_lower >= ? AND " 1508 "value_lower < ? " 1509 "ORDER BY count DESC " 1510 "LIMIT ?")); 1511 if (!s) { 1512 NOTREACHED() << "Statement prepare failed"; 1513 return false; 1514 } 1515 1516 s.BindString16(0, name); 1517 s.BindString16(1, prefix_lower); 1518 s.BindString16(2, next_prefix); 1519 s.BindInt(3, limit); 1520 } 1521 1522 values->clear(); 1523 while (s.Step()) 1524 values->push_back(s.ColumnString16(0)); 1525 return s.Succeeded(); 1526} 1527 1528bool WebDatabase::RemoveFormElementsAddedBetween( 1529 base::Time delete_begin, 1530 base::Time delete_end, 1531 std::vector<AutofillChange>* changes) { 1532 DCHECK(changes); 1533 // Query for the pair_id, name, and value of all form elements that 1534 // were used between the given times. 1535 sql::Statement s(db_.GetUniqueStatement( 1536 "SELECT DISTINCT a.pair_id, a.name, a.value " 1537 "FROM autofill_dates ad JOIN autofill a ON ad.pair_id = a.pair_id " 1538 "WHERE ad.date_created >= ? AND ad.date_created < ?")); 1539 if (!s) { 1540 NOTREACHED() << "Statement 1 prepare failed"; 1541 return false; 1542 } 1543 s.BindInt64(0, delete_begin.ToTimeT()); 1544 s.BindInt64(1, 1545 delete_end.is_null() ? 1546 std::numeric_limits<int64>::max() : 1547 delete_end.ToTimeT()); 1548 1549 AutofillElementList elements; 1550 while (s.Step()) { 1551 elements.push_back(MakeTuple(s.ColumnInt64(0), 1552 s.ColumnString16(1), 1553 s.ColumnString16(2))); 1554 } 1555 1556 if (!s.Succeeded()) { 1557 NOTREACHED(); 1558 return false; 1559 } 1560 1561 for (AutofillElementList::iterator itr = elements.begin(); 1562 itr != elements.end(); itr++) { 1563 int how_many = 0; 1564 if (!RemoveFormElementForTimeRange(itr->a, delete_begin, delete_end, 1565 &how_many)) { 1566 return false; 1567 } 1568 bool was_removed = false; 1569 if (!AddToCountOfFormElement(itr->a, -how_many, &was_removed)) 1570 return false; 1571 AutofillChange::Type change_type = 1572 was_removed ? AutofillChange::REMOVE : AutofillChange::UPDATE; 1573 changes->push_back(AutofillChange(change_type, 1574 AutofillKey(itr->b, itr->c))); 1575 } 1576 1577 return true; 1578} 1579 1580bool WebDatabase::RemoveFormElementForTimeRange(int64 pair_id, 1581 const Time delete_begin, 1582 const Time delete_end, 1583 int* how_many) { 1584 sql::Statement s(db_.GetUniqueStatement( 1585 "DELETE FROM autofill_dates WHERE pair_id = ? AND " 1586 "date_created >= ? AND date_created < ?")); 1587 if (!s) { 1588 NOTREACHED() << "Statement 1 prepare failed"; 1589 return false; 1590 } 1591 s.BindInt64(0, pair_id); 1592 s.BindInt64(1, delete_begin.is_null() ? 0 : delete_begin.ToTimeT()); 1593 s.BindInt64(2, delete_end.is_null() ? std::numeric_limits<int64>::max() : 1594 delete_end.ToTimeT()); 1595 1596 bool result = s.Run(); 1597 if (how_many) 1598 *how_many = db_.GetLastChangeCount(); 1599 1600 return result; 1601} 1602 1603bool WebDatabase::RemoveFormElement(const string16& name, 1604 const string16& value) { 1605 // Find the id for that pair. 1606 sql::Statement s(db_.GetUniqueStatement( 1607 "SELECT pair_id FROM autofill WHERE name = ? AND value= ?")); 1608 if (!s) { 1609 NOTREACHED() << "Statement 1 prepare failed"; 1610 return false; 1611 } 1612 s.BindString16(0, name); 1613 s.BindString16(1, value); 1614 1615 if (s.Step()) 1616 return RemoveFormElementForID(s.ColumnInt64(0)); 1617 return false; 1618} 1619 1620bool WebDatabase::AddAutoFillProfile(const AutoFillProfile& profile) { 1621 sql::Statement s(db_.GetUniqueStatement( 1622 "INSERT INTO autofill_profiles" 1623 "(label, unique_id, first_name, middle_name, last_name, email," 1624 " company_name, address_line_1, address_line_2, city, state, zipcode," 1625 " country, phone, fax)" 1626 "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)")); 1627 if (!s) { 1628 NOTREACHED() << "Statement prepare failed"; 1629 return false; 1630 } 1631 1632 BindAutoFillProfileToStatement(profile, &s); 1633 1634 if (!s.Run()) { 1635 NOTREACHED(); 1636 return false; 1637 } 1638 1639 return s.Succeeded(); 1640} 1641 1642bool WebDatabase::GetAutoFillProfileForLabel(const string16& label, 1643 AutoFillProfile** profile) { 1644 DCHECK(profile); 1645 sql::Statement s(db_.GetUniqueStatement( 1646 "SELECT * FROM autofill_profiles " 1647 "WHERE label = ?")); 1648 if (!s) { 1649 NOTREACHED() << "Statement prepare failed"; 1650 return false; 1651 } 1652 1653 s.BindString16(0, label); 1654 if (!s.Step()) 1655 return false; 1656 1657 *profile = AutoFillProfileFromStatement(s); 1658 1659 return s.Succeeded(); 1660} 1661 1662bool WebDatabase::GetAutoFillProfiles( 1663 std::vector<AutoFillProfile*>* profiles) { 1664 DCHECK(profiles); 1665 profiles->clear(); 1666 1667 sql::Statement s(db_.GetUniqueStatement("SELECT * FROM autofill_profiles")); 1668 if (!s) { 1669 NOTREACHED() << "Statement prepare failed"; 1670 return false; 1671 } 1672 1673 while (s.Step()) 1674 profiles->push_back(AutoFillProfileFromStatement(s)); 1675 1676 return s.Succeeded(); 1677} 1678 1679bool WebDatabase::UpdateAutoFillProfile(const AutoFillProfile& profile) { 1680 DCHECK(profile.unique_id()); 1681 sql::Statement s(db_.GetUniqueStatement( 1682 "UPDATE autofill_profiles " 1683 "SET label=?, unique_id=?, first_name=?, middle_name=?, last_name=?, " 1684 " email=?, company_name=?, address_line_1=?, address_line_2=?, " 1685 " city=?, state=?, zipcode=?, country=?, phone=?, fax=? " 1686 "WHERE unique_id=?")); 1687 if (!s) { 1688 NOTREACHED() << "Statement prepare failed"; 1689 return false; 1690 } 1691 1692 BindAutoFillProfileToStatement(profile, &s); 1693 s.BindInt(15, profile.unique_id()); 1694 bool result = s.Run(); 1695 DCHECK_GT(db_.GetLastChangeCount(), 0); 1696 return result; 1697} 1698 1699bool WebDatabase::RemoveAutoFillProfile(int profile_id) { 1700 DCHECK_NE(0, profile_id); 1701 sql::Statement s(db_.GetUniqueStatement( 1702 "DELETE FROM autofill_profiles WHERE unique_id = ?")); 1703 if (!s) { 1704 NOTREACHED() << "Statement prepare failed"; 1705 return false; 1706 } 1707 1708 s.BindInt(0, profile_id); 1709 return s.Run(); 1710} 1711 1712bool WebDatabase::GetAutoFillProfileForID(int profile_id, 1713 AutoFillProfile** profile) { 1714 sql::Statement s(db_.GetUniqueStatement( 1715 "SELECT * FROM autofill_profiles " 1716 "WHERE unique_id = ?")); 1717 if (!s) { 1718 NOTREACHED() << "Statement prepare failed"; 1719 return false; 1720 } 1721 1722 s.BindInt(0, profile_id); 1723 if (s.Step()) 1724 *profile = AutoFillProfileFromStatement(s); 1725 1726 return s.Succeeded(); 1727} 1728 1729bool WebDatabase::AddCreditCard(const CreditCard& credit_card) { 1730 sql::Statement s(db_.GetUniqueStatement( 1731 "INSERT INTO credit_cards" 1732 "(label, unique_id, name_on_card, type, card_number," 1733 " expiration_month, expiration_year, verification_code, billing_address," 1734 " shipping_address, card_number_encrypted, verification_code_encrypted)" 1735 "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)")); 1736 if (!s) { 1737 NOTREACHED() << "Statement prepare failed"; 1738 return false; 1739 } 1740 1741 BindCreditCardToStatement(credit_card, &s); 1742 1743 if (!s.Run()) { 1744 NOTREACHED(); 1745 return false; 1746 } 1747 1748 DCHECK_GT(db_.GetLastChangeCount(), 0); 1749 return s.Succeeded(); 1750} 1751 1752bool WebDatabase::GetCreditCardForLabel(const string16& label, 1753 CreditCard** credit_card) { 1754 DCHECK(credit_card); 1755 sql::Statement s(db_.GetUniqueStatement( 1756 "SELECT * FROM credit_cards " 1757 "WHERE label = ?")); 1758 if (!s) { 1759 NOTREACHED() << "Statement prepare failed"; 1760 return false; 1761 } 1762 1763 s.BindString16(0, label); 1764 if (!s.Step()) 1765 return false; 1766 1767 *credit_card = CreditCardFromStatement(s); 1768 1769 return s.Succeeded(); 1770} 1771 1772bool WebDatabase::GetCreditCardForID(int credit_card_id, 1773 CreditCard** credit_card) { 1774 sql::Statement s(db_.GetUniqueStatement( 1775 "SELECT * FROM credit_cards " 1776 "WHERE unique_id = ?")); 1777 if (!s) { 1778 NOTREACHED() << "Statement prepare failed"; 1779 return false; 1780 } 1781 1782 s.BindInt(0, credit_card_id); 1783 if (!s.Step()) 1784 return false; 1785 1786 *credit_card = CreditCardFromStatement(s); 1787 1788 return s.Succeeded(); 1789} 1790 1791bool WebDatabase::GetCreditCards( 1792 std::vector<CreditCard*>* credit_cards) { 1793 DCHECK(credit_cards); 1794 credit_cards->clear(); 1795 1796 sql::Statement s(db_.GetUniqueStatement("SELECT * FROM credit_cards")); 1797 if (!s) { 1798 NOTREACHED() << "Statement prepare failed"; 1799 return false; 1800 } 1801 1802 while (s.Step()) 1803 credit_cards->push_back(CreditCardFromStatement(s)); 1804 1805 return s.Succeeded(); 1806} 1807 1808bool WebDatabase::UpdateCreditCard(const CreditCard& credit_card) { 1809 DCHECK(credit_card.unique_id()); 1810 sql::Statement s(db_.GetUniqueStatement( 1811 "UPDATE credit_cards " 1812 "SET label=?, unique_id=?, name_on_card=?, type=?, card_number=?, " 1813 " expiration_month=?, expiration_year=?, verification_code=?, " 1814 " billing_address=?, shipping_address=?, card_number_encrypted=?, " 1815 " verification_code_encrypted=? " 1816 "WHERE unique_id=?")); 1817 if (!s) { 1818 NOTREACHED() << "Statement prepare failed"; 1819 return false; 1820 } 1821 1822 BindCreditCardToStatement(credit_card, &s); 1823 s.BindInt(12, credit_card.unique_id()); 1824 bool result = s.Run(); 1825 DCHECK_GT(db_.GetLastChangeCount(), 0); 1826 return result; 1827} 1828 1829bool WebDatabase::RemoveCreditCard(int credit_card_id) { 1830 DCHECK_NE(0, credit_card_id); 1831 sql::Statement s(db_.GetUniqueStatement( 1832 "DELETE FROM credit_cards WHERE unique_id = ?")); 1833 if (!s) { 1834 NOTREACHED() << "Statement prepare failed"; 1835 return false; 1836 } 1837 1838 s.BindInt(0, credit_card_id); 1839 return s.Run(); 1840} 1841 1842bool WebDatabase::AddToCountOfFormElement(int64 pair_id, 1843 int delta, 1844 bool* was_removed) { 1845 DCHECK(was_removed); 1846 int count = 0; 1847 *was_removed = false; 1848 1849 if (!GetCountOfFormElement(pair_id, &count)) 1850 return false; 1851 1852 if (count + delta == 0) { 1853 if (!RemoveFormElementForID(pair_id)) 1854 return false; 1855 *was_removed = true; 1856 } else { 1857 if (!SetCountOfFormElement(pair_id, count + delta)) 1858 return false; 1859 } 1860 return true; 1861} 1862 1863bool WebDatabase::RemoveFormElementForID(int64 pair_id) { 1864 sql::Statement s(db_.GetUniqueStatement( 1865 "DELETE FROM autofill WHERE pair_id = ?")); 1866 if (!s) { 1867 NOTREACHED() << "Statement prepare failed"; 1868 return false; 1869 } 1870 s.BindInt64(0, pair_id); 1871 if (s.Run()) { 1872 return RemoveFormElementForTimeRange(pair_id, base::Time(), base::Time(), 1873 NULL); 1874 } 1875 return false; 1876} 1877 1878void WebDatabase::MigrateOldVersionsAsNeeded(){ 1879 // Migrate if necessary. 1880 int current_version = meta_table_.GetVersionNumber(); 1881 switch (current_version) { 1882 // Versions 1 - 19 are unhandled. Version numbers greater than 1883 // kCurrentVersionNumber should have already been weeded out by the caller. 1884 default: 1885 // When the version is too old, we just try to continue anyway. There 1886 // should not be a released product that makes a database too old for us 1887 // to handle. 1888 LOG(WARNING) << "Web database version " << current_version << 1889 " is too old to handle."; 1890 return; 1891 1892 case 20: 1893 // Add the autogenerate_keyword column. 1894 if (!db_.Execute("ALTER TABLE keywords ADD COLUMN autogenerate_keyword " 1895 "INTEGER DEFAULT 0")) { 1896 NOTREACHED(); 1897 LOG(WARNING) << "Unable to update web database to version 21."; 1898 return; 1899 } 1900 meta_table_.SetVersionNumber(21); 1901 meta_table_.SetCompatibleVersionNumber( 1902 std::min(21, kCompatibleVersionNumber)); 1903 // FALL THROUGH 1904 1905 case 21: 1906 if (!ClearAutofillEmptyValueElements()) { 1907 NOTREACHED() << "Failed to clean-up autofill DB."; 1908 } 1909 meta_table_.SetVersionNumber(22); 1910 // No change in the compatibility version number. 1911 1912 // FALL THROUGH 1913 1914 case 22: 1915 // Add the card_number_encrypted column if credit card table was not 1916 // created in this build (otherwise the column already exists). 1917 // WARNING: Do not change the order of the execution of the SQL 1918 // statements in this case! Profile corruption and data migration 1919 // issues WILL OCCUR. (see http://crbug.com/10913) 1920 // 1921 // The problem is that if a user has a profile which was created before 1922 // r37036, when the credit_cards table was added, and then failed to 1923 // update this profile between the credit card addition and the addition 1924 // of the "encrypted" columns (44963), the next data migration will put 1925 // the user's profile in an incoherent state: The user will update from 1926 // a data profile set to be earlier than 22, and therefore pass through 1927 // this update case. But because the user did not have a credit_cards 1928 // table before starting Chrome, it will have just been initialized 1929 // above, and so already have these columns -- and thus this data 1930 // update step will have failed. 1931 // 1932 // The false assumption in this case is that at this step in the 1933 // migration, the user has a credit card table, and that this 1934 // table does not include encrypted columns! 1935 // Because this case does not roll back the complete set of SQL 1936 // transactions properly in case of failure (that is, it does not 1937 // roll back the table initialization done above), the incoherent 1938 // profile will now see itself as being at version 22 -- but include a 1939 // fully initialized credit_cards table. Every time Chrome runs, it 1940 // will try to update the web database and fail at this step, unless 1941 // we allow for the faulty assumption described above by checking for 1942 // the existence of the columns only AFTER we've executed the commands 1943 // to add them. 1944 if (!db_.Execute("ALTER TABLE credit_cards ADD COLUMN " 1945 "card_number_encrypted BLOB DEFAULT NULL")) { 1946 LOG(WARNING) << "Could not add card_number_encrypted to " 1947 "credit_cards table."; 1948 } 1949 if (!db_.Execute("ALTER TABLE credit_cards ADD COLUMN " 1950 "verification_code_encrypted BLOB DEFAULT NULL")) { 1951 LOG(WARNING) << "Could not add verification_code_encrypted to " 1952 "credit_cards table."; 1953 } 1954 if (!db_.Execute( 1955 "SELECT card_number_encrypted FROM credit_cards limit 1") || 1956 !db_.Execute( 1957 "SELECT verification_code_encrypted FROM credit_cards limit 1")) { 1958 NOTREACHED(); 1959 LOG(WARNING) << "Unable to update web database to version 23."; 1960 return; 1961 } 1962 meta_table_.SetVersionNumber(23); 1963 // FALL THROUGH 1964 1965 case 23: { 1966 // One-time cleanup for Chromium bug 38364. In the presence of 1967 // multi-byte UTF-8 characters, that bug could cause AutoFill strings 1968 // to grow larger and more corrupt with each save. The cleanup removes 1969 // any row with a string field larger than a reasonable size. The string 1970 // fields examined here are precisely the ones that were subject to 1971 // corruption by the original bug. 1972 const std::string autofill_is_too_big = 1973 "max(length(name), length(value)) > 500"; 1974 1975 const std::string credit_cards_is_too_big = 1976 "max(length(label), length(name_on_card), length(type), " 1977 " length(expiration_month), length(expiration_year), " 1978 " length(billing_address), length(shipping_address) " 1979 ") > 500"; 1980 1981 const std::string autofill_profiles_is_too_big = 1982 "max(length(label), length(first_name), " 1983 " length(middle_name), length(last_name), length(email), " 1984 " length(company_name), length(address_line_1), " 1985 " length(address_line_2), length(city), length(state), " 1986 " length(zipcode), length(country), length(phone), " 1987 " length(fax)) > 500"; 1988 1989 std::string query = "DELETE FROM autofill_dates WHERE pair_id IN (" 1990 "SELECT pair_id FROM autofill WHERE " + autofill_is_too_big + ")"; 1991 if (!db_.Execute(query.c_str())) { 1992 NOTREACHED(); 1993 LOG(WARNING) << "Unable to update web database to version 24."; 1994 return; 1995 } 1996 query = "DELETE FROM autofill WHERE " + autofill_is_too_big; 1997 if (!db_.Execute(query.c_str())) { 1998 NOTREACHED(); 1999 LOG(WARNING) << "Unable to update web database to version 24."; 2000 return; 2001 } 2002 query = "DELETE FROM credit_cards WHERE (" + credit_cards_is_too_big + 2003 ") OR label IN (SELECT label FROM autofill_profiles WHERE " + 2004 autofill_profiles_is_too_big + ")"; 2005 if (!db_.Execute(query.c_str())) { 2006 NOTREACHED(); 2007 LOG(WARNING) << "Unable to update web database to version 24."; 2008 return; 2009 } 2010 query = "DELETE FROM autofill_profiles WHERE " + 2011 autofill_profiles_is_too_big; 2012 if (!db_.Execute(query.c_str())) { 2013 NOTREACHED(); 2014 LOG(WARNING) << "Unable to update web database to version 24."; 2015 return; 2016 } 2017 2018 meta_table_.SetVersionNumber(24); 2019 2020 // FALL THROUGH 2021 } 2022 2023 case 24: 2024 // Add the logo_id column if keyword table was not created in this build. 2025 if (!db_.Execute("ALTER TABLE keywords ADD COLUMN logo_id " 2026 "INTEGER DEFAULT 0")) { 2027 NOTREACHED(); 2028 LOG(WARNING) << "Unable to update web database to version 25."; 2029 return; 2030 } 2031 meta_table_.SetVersionNumber(25); 2032 meta_table_.SetCompatibleVersionNumber( 2033 std::min(25, kCompatibleVersionNumber)); 2034 // FALL THROUGH 2035 2036 case 25: 2037 // Add the created_by_policy column. 2038 if (!db_.Execute("ALTER TABLE keywords ADD COLUMN created_by_policy " 2039 "INTEGER DEFAULT 0")) { 2040 NOTREACHED(); 2041 LOG(WARNING) << "Unable to update web database to version 26."; 2042 return; 2043 } 2044 2045 meta_table_.SetVersionNumber(26); 2046 meta_table_.SetCompatibleVersionNumber( 2047 std::min(26, kCompatibleVersionNumber)); 2048 // FALL THROUGH 2049 2050 case 26: { 2051 // Change the credit_cards.billing_address column from a string to an int. 2052 // The stored string is the label of an address, so we have to select the 2053 // unique ID of this address using the label as a foreign key into the 2054 // |autofill_profiles| table. 2055 std::string stmt = 2056 "SELECT credit_cards.unique_id, autofill_profiles.unique_id " 2057 "FROM autofill_profiles, credit_cards " 2058 "WHERE credit_cards.billing_address = autofill_profiles.label"; 2059 sql::Statement s(db_.GetUniqueStatement(stmt.c_str())); 2060 if (!s) { 2061 NOTREACHED() << "Statement prepare failed"; 2062 return; 2063 } 2064 2065 std::map<int, int> cc_billing_map; 2066 while (s.Step()) 2067 cc_billing_map[s.ColumnInt(0)] = s.ColumnInt(1); 2068 2069 // Windows already stores the IDs as strings in |billing_address|. Try to 2070 // convert those. 2071 if (cc_billing_map.empty()) { 2072 std::string stmt = 2073 "SELECT unique_id,billing_address FROM credit_cards"; 2074 sql::Statement s(db_.GetUniqueStatement(stmt.c_str())); 2075 if (!s) { 2076 NOTREACHED() << "Statement prepare failed"; 2077 return; 2078 } 2079 2080 while (s.Step()) { 2081 int id = 0; 2082 if (base::StringToInt(s.ColumnString(1), &id)) 2083 cc_billing_map[s.ColumnInt(0)] = id; 2084 } 2085 } 2086 2087 if (!db_.Execute("CREATE TABLE credit_cards_temp ( " 2088 "label VARCHAR, " 2089 "unique_id INTEGER PRIMARY KEY, " 2090 "name_on_card VARCHAR, " 2091 "type VARCHAR, " 2092 "card_number VARCHAR, " 2093 "expiration_month INTEGER, " 2094 "expiration_year INTEGER, " 2095 "verification_code VARCHAR, " 2096 "billing_address INTEGER, " 2097 "shipping_address VARCHAR, " 2098 "card_number_encrypted BLOB, " 2099 "verification_code_encrypted BLOB)")) { 2100 NOTREACHED(); 2101 LOG(WARNING) << "Unable to update web database to version 27."; 2102 return; 2103 } 2104 2105 if (!db_.Execute( 2106 "INSERT INTO credit_cards_temp " 2107 "SELECT label,unique_id,name_on_card,type,card_number," 2108 "expiration_month,expiration_year,verification_code,0," 2109 "shipping_address,card_number_encrypted,verification_code_encrypted " 2110 "FROM credit_cards")) { 2111 NOTREACHED(); 2112 LOG(WARNING) << "Unable to update web database to version 27."; 2113 return; 2114 } 2115 2116 if (!db_.Execute("DROP TABLE credit_cards")) { 2117 NOTREACHED(); 2118 LOG(WARNING) << "Unable to update web database to version 27."; 2119 return; 2120 } 2121 2122 if (!db_.Execute( 2123 "ALTER TABLE credit_cards_temp RENAME TO credit_cards")) { 2124 NOTREACHED(); 2125 LOG(WARNING) << "Unable to update web database to version 27."; 2126 return; 2127 } 2128 2129 meta_table_.SetVersionNumber(26); 2130 meta_table_.SetCompatibleVersionNumber( 2131 std::min(26, kCompatibleVersionNumber)); 2132 // FALL THROUGH 2133 2134 for (std::map<int, int>::const_iterator iter = cc_billing_map.begin(); 2135 iter != cc_billing_map.end(); ++iter) { 2136 sql::Statement s(db_.GetCachedStatement( 2137 SQL_FROM_HERE, 2138 "UPDATE credit_cards SET billing_address=? WHERE unique_id=?")); 2139 if (!s) { 2140 NOTREACHED() << "Statement prepare failed"; 2141 return; 2142 } 2143 2144 s.BindInt(0, (*iter).second); 2145 s.BindInt(1, (*iter).first); 2146 2147 if (!s.Run()) { 2148 NOTREACHED(); 2149 LOG(WARNING) << "Unable to update web database to version 27."; 2150 return; 2151 } 2152 } 2153 2154 meta_table_.SetVersionNumber(27); 2155 meta_table_.SetCompatibleVersionNumber( 2156 std::min(27, kCompatibleVersionNumber)); 2157 2158 // FALL THROUGH 2159 } 2160 2161 // Add successive versions here. Each should set the version number and 2162 // compatible version number as appropriate, then fall through to the next 2163 // case. 2164 2165 case kCurrentVersionNumber: 2166 // No migration needed. 2167 return; 2168 } 2169} 2170