// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/webdata/autofill_table.h" #include #include #include #include #include #include #include "base/guid.h" #include "base/i18n/case_conversion.h" #include "base/logging.h" #include "base/string_number_conversions.h" #include "base/time.h" #include "base/tuple.h" #include "chrome/browser/autofill/autofill_country.h" #include "chrome/browser/autofill/autofill_profile.h" #include "chrome/browser/autofill/autofill_type.h" #include "chrome/browser/autofill/credit_card.h" #include "chrome/browser/autofill/personal_data_manager.h" #include "chrome/browser/password_manager/encryptor.h" #include "chrome/browser/webdata/autofill_change.h" #include "chrome/browser/webdata/autofill_entry.h" #include "chrome/common/form_field_data.h" #include "sql/statement.h" #include "ui/base/l10n/l10n_util.h" using base::Time; namespace { typedef std::vector > AutofillElementList; // TODO(dhollowa): Find a common place for this. It is duplicated in // personal_data_manager.cc. template T* address_of(T& v) { return &v; } string16 LimitDataSize(const string16& data) { if (data.size() > AutofillTable::kMaxDataLength) return data.substr(0, AutofillTable::kMaxDataLength); return data; } void BindAutofillProfileToStatement(const AutofillProfile& profile, sql::Statement* s) { DCHECK(base::IsValidGUID(profile.guid())); s->BindString(0, profile.guid()); string16 text = profile.GetRawInfo(COMPANY_NAME); s->BindString16(1, LimitDataSize(text)); text = profile.GetRawInfo(ADDRESS_HOME_LINE1); s->BindString16(2, LimitDataSize(text)); text = profile.GetRawInfo(ADDRESS_HOME_LINE2); s->BindString16(3, LimitDataSize(text)); text = profile.GetRawInfo(ADDRESS_HOME_CITY); s->BindString16(4, LimitDataSize(text)); text = profile.GetRawInfo(ADDRESS_HOME_STATE); s->BindString16(5, LimitDataSize(text)); text = profile.GetRawInfo(ADDRESS_HOME_ZIP); s->BindString16(6, LimitDataSize(text)); text = profile.GetRawInfo(ADDRESS_HOME_COUNTRY); s->BindString16(7, LimitDataSize(text)); std::string country_code = profile.CountryCode(); s->BindString(8, country_code); s->BindInt64(9, Time::Now().ToTimeT()); } AutofillProfile* AutofillProfileFromStatement(const sql::Statement& s) { AutofillProfile* profile = new AutofillProfile; profile->set_guid(s.ColumnString(0)); DCHECK(base::IsValidGUID(profile->guid())); profile->SetRawInfo(COMPANY_NAME, s.ColumnString16(1)); profile->SetRawInfo(ADDRESS_HOME_LINE1, s.ColumnString16(2)); profile->SetRawInfo(ADDRESS_HOME_LINE2, s.ColumnString16(3)); profile->SetRawInfo(ADDRESS_HOME_CITY, s.ColumnString16(4)); profile->SetRawInfo(ADDRESS_HOME_STATE, s.ColumnString16(5)); profile->SetRawInfo(ADDRESS_HOME_ZIP, s.ColumnString16(6)); // Intentionally skip column 7, which stores the localized country name. profile->SetCountryCode(s.ColumnString(8)); // Intentionally skip column 9, which stores the profile's modification date. return profile; } void BindCreditCardToStatement(const CreditCard& credit_card, sql::Statement* s) { DCHECK(base::IsValidGUID(credit_card.guid())); s->BindString(0, credit_card.guid()); string16 text = credit_card.GetRawInfo(CREDIT_CARD_NAME); s->BindString16(1, LimitDataSize(text)); text = credit_card.GetRawInfo(CREDIT_CARD_EXP_MONTH); s->BindString16(2, LimitDataSize(text)); text = credit_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR); s->BindString16(3, LimitDataSize(text)); text = credit_card.GetRawInfo(CREDIT_CARD_NUMBER); std::string encrypted_data; Encryptor::EncryptString16(text, &encrypted_data); s->BindBlob(4, encrypted_data.data(), static_cast(encrypted_data.length())); s->BindInt64(5, Time::Now().ToTimeT()); } CreditCard* CreditCardFromStatement(const sql::Statement& s) { CreditCard* credit_card = new CreditCard; credit_card->set_guid(s.ColumnString(0)); DCHECK(base::IsValidGUID(credit_card->guid())); credit_card->SetRawInfo(CREDIT_CARD_NAME, s.ColumnString16(1)); credit_card->SetRawInfo(CREDIT_CARD_EXP_MONTH, s.ColumnString16(2)); credit_card->SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, s.ColumnString16(3)); int encrypted_number_len = s.ColumnByteLength(4); string16 credit_card_number; if (encrypted_number_len) { std::string encrypted_number; encrypted_number.resize(encrypted_number_len); memcpy(&encrypted_number[0], s.ColumnBlob(4), encrypted_number_len); Encryptor::DecryptString16(encrypted_number, &credit_card_number); } credit_card->SetRawInfo(CREDIT_CARD_NUMBER, credit_card_number); // Intentionally skip column 5, which stores the modification date. return credit_card; } bool AddAutofillProfileNamesToProfile(sql::Connection* db, AutofillProfile* profile) { sql::Statement s(db->GetUniqueStatement( "SELECT guid, first_name, middle_name, last_name " "FROM autofill_profile_names " "WHERE guid=?")); s.BindString(0, profile->guid()); if (!s.is_valid()) return false; std::vector first_names; std::vector middle_names; std::vector last_names; while (s.Step()) { DCHECK_EQ(profile->guid(), s.ColumnString(0)); first_names.push_back(s.ColumnString16(1)); middle_names.push_back(s.ColumnString16(2)); last_names.push_back(s.ColumnString16(3)); } if (!s.Succeeded()) return false; profile->SetRawMultiInfo(NAME_FIRST, first_names); profile->SetRawMultiInfo(NAME_MIDDLE, middle_names); profile->SetRawMultiInfo(NAME_LAST, last_names); return true; } bool AddAutofillProfileEmailsToProfile(sql::Connection* db, AutofillProfile* profile) { sql::Statement s(db->GetUniqueStatement( "SELECT guid, email " "FROM autofill_profile_emails " "WHERE guid=?")); s.BindString(0, profile->guid()); if (!s.is_valid()) return false; std::vector emails; while (s.Step()) { DCHECK_EQ(profile->guid(), s.ColumnString(0)); emails.push_back(s.ColumnString16(1)); } if (!s.Succeeded()) return false; profile->SetRawMultiInfo(EMAIL_ADDRESS, emails); return true; } bool AddAutofillProfilePhonesToProfile(sql::Connection* db, AutofillProfile* profile) { sql::Statement s(db->GetUniqueStatement( "SELECT guid, type, number " "FROM autofill_profile_phones " "WHERE guid=? AND type=?")); // Value used to be either [(0, phone), (1, fax)] but fax has been removed. s.BindString(0, profile->guid()); s.BindInt(1, 0); if (!s.is_valid()) return false; std::vector numbers; while (s.Step()) { DCHECK_EQ(profile->guid(), s.ColumnString(0)); numbers.push_back(s.ColumnString16(2)); } if (!s.Succeeded()) return false; profile->SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, numbers); return true; } bool AddAutofillProfileNames(const AutofillProfile& profile, sql::Connection* db) { std::vector first_names; profile.GetRawMultiInfo(NAME_FIRST, &first_names); std::vector middle_names; profile.GetRawMultiInfo(NAME_MIDDLE, &middle_names); std::vector last_names; profile.GetRawMultiInfo(NAME_LAST, &last_names); DCHECK_EQ(first_names.size(), middle_names.size()); DCHECK_EQ(middle_names.size(), last_names.size()); for (size_t i = 0; i < first_names.size(); ++i) { // Add the new name. sql::Statement s(db->GetUniqueStatement( "INSERT INTO autofill_profile_names" " (guid, first_name, middle_name, last_name) " "VALUES (?,?,?,?)")); s.BindString(0, profile.guid()); s.BindString16(1, first_names[i]); s.BindString16(2, middle_names[i]); s.BindString16(3, last_names[i]); if (!s.Run()) return false; } return true; } bool AddAutofillProfileEmails(const AutofillProfile& profile, sql::Connection* db) { std::vector emails; profile.GetRawMultiInfo(EMAIL_ADDRESS, &emails); for (size_t i = 0; i < emails.size(); ++i) { // Add the new email. sql::Statement s(db->GetUniqueStatement( "INSERT INTO autofill_profile_emails" " (guid, email) " "VALUES (?,?)")); s.BindString(0, profile.guid()); s.BindString16(1, emails[i]); if (!s.Run()) return false; } return true; } bool AddAutofillProfilePhones(const AutofillProfile& profile, sql::Connection* db) { std::vector numbers; profile.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &numbers); for (size_t i = 0; i < numbers.size(); ++i) { // Add the new number. sql::Statement s(db->GetUniqueStatement( "INSERT INTO autofill_profile_phones" " (guid, type, number) " "VALUES (?,?,?)")); s.BindString(0, profile.guid()); // Value used to be either [(0, phone), (1, fax)] but fax has been removed. s.BindInt(1, 0); s.BindString16(2, numbers[i]); if (!s.Run()) return false; } return true; } bool AddAutofillProfilePieces(const AutofillProfile& profile, sql::Connection* db) { if (!AddAutofillProfileNames(profile, db)) return false; if (!AddAutofillProfileEmails(profile, db)) return false; if (!AddAutofillProfilePhones(profile, db)) return false; return true; } bool RemoveAutofillProfilePieces(const std::string& guid, sql::Connection* db) { sql::Statement s1(db->GetUniqueStatement( "DELETE FROM autofill_profile_names WHERE guid = ?")); s1.BindString(0, guid); if (!s1.Run()) return false; sql::Statement s2(db->GetUniqueStatement( "DELETE FROM autofill_profile_emails WHERE guid = ?")); s2.BindString(0, guid); if (!s2.Run()) return false; sql::Statement s3(db->GetUniqueStatement( "DELETE FROM autofill_profile_phones WHERE guid = ?")); s3.BindString(0, guid); return s3.Run(); } } // namespace // The maximum length allowed for form data. const size_t AutofillTable::kMaxDataLength = 1024; AutofillTable::AutofillTable(sql::Connection* db, sql::MetaTable* meta_table) : WebDatabaseTable(db, meta_table) { } AutofillTable::~AutofillTable() { } bool AutofillTable::Init() { return (InitMainTable() && InitCreditCardsTable() && InitDatesTable() && InitProfilesTable() && InitProfileNamesTable() && InitProfileEmailsTable() && InitProfilePhonesTable() && InitProfileTrashTable()); } bool AutofillTable::IsSyncable() { return true; } bool AutofillTable::AddFormFieldValues( const std::vector& elements, std::vector* changes) { return AddFormFieldValuesTime(elements, changes, Time::Now()); } bool AutofillTable::AddFormFieldValue(const FormFieldData& element, std::vector* changes) { return AddFormFieldValueTime(element, changes, Time::Now()); } bool AutofillTable::GetFormValuesForElementName(const string16& name, const string16& prefix, std::vector* values, int limit) { DCHECK(values); sql::Statement s; if (prefix.empty()) { s.Assign(db_->GetUniqueStatement( "SELECT value FROM autofill " "WHERE name = ? " "ORDER BY count DESC " "LIMIT ?")); s.BindString16(0, name); s.BindInt(1, limit); } else { string16 prefix_lower = base::i18n::ToLower(prefix); string16 next_prefix = prefix_lower; next_prefix[next_prefix.length() - 1]++; s.Assign(db_->GetUniqueStatement( "SELECT value FROM autofill " "WHERE name = ? AND " "value_lower >= ? AND " "value_lower < ? " "ORDER BY count DESC " "LIMIT ?")); s.BindString16(0, name); s.BindString16(1, prefix_lower); s.BindString16(2, next_prefix); s.BindInt(3, limit); } values->clear(); while (s.Step()) values->push_back(s.ColumnString16(0)); return s.Succeeded(); } bool AutofillTable::RemoveFormElementsAddedBetween( const Time& delete_begin, const Time& delete_end, std::vector* changes) { DCHECK(changes); // Query for the pair_id, name, and value of all form elements that // were used between the given times. sql::Statement s(db_->GetUniqueStatement( "SELECT DISTINCT a.pair_id, a.name, a.value " "FROM autofill_dates ad JOIN autofill a ON ad.pair_id = a.pair_id " "WHERE ad.date_created >= ? AND ad.date_created < ?")); s.BindInt64(0, delete_begin.ToTimeT()); s.BindInt64(1, (delete_end.is_null() || delete_end == base::Time::Max()) ? std::numeric_limits::max() : delete_end.ToTimeT()); AutofillElementList elements; while (s.Step()) { elements.push_back(MakeTuple(s.ColumnInt64(0), s.ColumnString16(1), s.ColumnString16(2))); } if (!s.Succeeded()) return false; for (AutofillElementList::iterator itr = elements.begin(); itr != elements.end(); ++itr) { int how_many = 0; if (!RemoveFormElementForTimeRange(itr->a, delete_begin, delete_end, &how_many)) { return false; } // We store at most 2 time stamps. If we remove both of them we should // delete the corresponding data. If we delete only one it could still be // the last timestamp for the data, so check how many timestamps do remain. bool should_remove = (CountTimestampsData(itr->a) == 0); if (should_remove) { if (!RemoveFormElementForID(itr->a)) return false; } else { if (!AddToCountOfFormElement(itr->a, -how_many)) return false; } AutofillChange::Type change_type = should_remove ? AutofillChange::REMOVE : AutofillChange::UPDATE; changes->push_back(AutofillChange(change_type, AutofillKey(itr->b, itr->c))); } return true; } bool AutofillTable::RemoveExpiredFormElements( std::vector* changes) { DCHECK(changes); base::Time delete_end = AutofillEntry::ExpirationTime(); // Query for the pair_id, name, and value of all form elements that // were last used before the |delete_end|. sql::Statement select_for_delete(db_->GetUniqueStatement( "SELECT DISTINCT pair_id, name, value " "FROM autofill WHERE pair_id NOT IN " "(SELECT DISTINCT pair_id " "FROM autofill_dates WHERE date_created >= ?)")); select_for_delete.BindInt64(0, delete_end.ToTimeT()); AutofillElementList entries_to_delete; while (select_for_delete.Step()) { entries_to_delete.push_back(MakeTuple(select_for_delete.ColumnInt64(0), select_for_delete.ColumnString16(1), select_for_delete.ColumnString16(2))); } if (!select_for_delete.Succeeded()) return false; sql::Statement delete_data_statement(db_->GetUniqueStatement( "DELETE FROM autofill WHERE pair_id NOT IN (" "SELECT pair_id FROM autofill_dates WHERE date_created >= ?)")); delete_data_statement.BindInt64(0, delete_end.ToTimeT()); if (!delete_data_statement.Run()) return false; sql::Statement delete_times_statement(db_->GetUniqueStatement( "DELETE FROM autofill_dates WHERE pair_id NOT IN (" "SELECT pair_id FROM autofill_dates WHERE date_created >= ?)")); delete_times_statement.BindInt64(0, delete_end.ToTimeT()); if (!delete_times_statement.Run()) return false; // Cull remaining entries' timestamps. std::vector entries; if (!GetAllAutofillEntries(&entries)) return false; sql::Statement cull_date_entry(db_->GetUniqueStatement( "DELETE FROM autofill_dates " "WHERE pair_id == (SELECT pair_id FROM autofill " "WHERE name = ? and value = ?)" "AND date_created != ? AND date_created != ?")); for (size_t i = 0; i < entries.size(); ++i) { cull_date_entry.BindString16(0, entries[i].key().name()); cull_date_entry.BindString16(1, entries[i].key().value()); cull_date_entry.BindInt64(2, entries[i].timestamps().empty() ? 0 : entries[i].timestamps().front().ToTimeT()); cull_date_entry.BindInt64(3, entries[i].timestamps().empty() ? 0 : entries[i].timestamps().back().ToTimeT()); if (!cull_date_entry.Run()) return false; cull_date_entry.Reset(true); } changes->clear(); changes->reserve(entries_to_delete.size()); for (AutofillElementList::iterator it = entries_to_delete.begin(); it != entries_to_delete.end(); ++it) { changes->push_back(AutofillChange( AutofillChange::REMOVE, AutofillKey(it->b, it->c))); } return true; } bool AutofillTable::RemoveFormElementForTimeRange(int64 pair_id, const Time& delete_begin, const Time& delete_end, int* how_many) { sql::Statement s(db_->GetUniqueStatement( "DELETE FROM autofill_dates WHERE pair_id = ? AND " "date_created >= ? AND date_created < ?")); s.BindInt64(0, pair_id); s.BindInt64(1, delete_begin.is_null() ? 0 : delete_begin.ToTimeT()); s.BindInt64(2, delete_end.is_null() ? std::numeric_limits::max() : delete_end.ToTimeT()); bool result = s.Run(); if (how_many) *how_many = db_->GetLastChangeCount(); return result; } int AutofillTable::CountTimestampsData(int64 pair_id) { sql::Statement s(db_->GetUniqueStatement( "SELECT COUNT(*) FROM autofill_dates WHERE pair_id = ?")); s.BindInt64(0, pair_id); if (!s.Step()) { NOTREACHED(); return 0; } else { return s.ColumnInt(0); } } bool AutofillTable::AddToCountOfFormElement(int64 pair_id, int delta) { int count = 0; if (!GetCountOfFormElement(pair_id, &count)) return false; if (count + delta == 0) { // Should remove the element earlier in the code. NOTREACHED(); return false; } else { if (!SetCountOfFormElement(pair_id, count + delta)) return false; } return true; } bool AutofillTable::GetIDAndCountOfFormElement( const FormFieldData& element, int64* pair_id, int* count) { DCHECK(pair_id); DCHECK(count); sql::Statement s(db_->GetUniqueStatement( "SELECT pair_id, count FROM autofill " "WHERE name = ? AND value = ?")); s.BindString16(0, element.name); s.BindString16(1, element.value); if (!s.is_valid()) return false; *pair_id = 0; *count = 0; if (s.Step()) { *pair_id = s.ColumnInt64(0); *count = s.ColumnInt(1); } return true; } bool AutofillTable::GetCountOfFormElement(int64 pair_id, int* count) { DCHECK(count); sql::Statement s(db_->GetUniqueStatement( "SELECT count FROM autofill WHERE pair_id = ?")); s.BindInt64(0, pair_id); if (s.Step()) { *count = s.ColumnInt(0); return true; } return false; } bool AutofillTable::SetCountOfFormElement(int64 pair_id, int count) { sql::Statement s(db_->GetUniqueStatement( "UPDATE autofill SET count = ? WHERE pair_id = ?")); s.BindInt(0, count); s.BindInt64(1, pair_id); return s.Run(); } bool AutofillTable::InsertFormElement(const FormFieldData& element, int64* pair_id) { DCHECK(pair_id); sql::Statement s(db_->GetUniqueStatement( "INSERT INTO autofill (name, value, value_lower) VALUES (?,?,?)")); s.BindString16(0, element.name); s.BindString16(1, element.value); s.BindString16(2, base::i18n::ToLower(element.value)); if (!s.Run()) return false; *pair_id = db_->GetLastInsertRowId(); return true; } bool AutofillTable::InsertPairIDAndDate(int64 pair_id, const Time& date_created) { sql::Statement s(db_->GetUniqueStatement( "INSERT INTO autofill_dates " "(pair_id, date_created) VALUES (?, ?)")); s.BindInt64(0, pair_id); s.BindInt64(1, date_created.ToTimeT()); return s.Run(); } bool AutofillTable::DeleteLastAccess(int64 pair_id) { // Inner SELECT selects the newest |date_created| for a given |pair_id|. // DELETE deletes only that entry. sql::Statement s(db_->GetUniqueStatement( "DELETE FROM autofill_dates WHERE pair_id = ? and date_created IN " "(SELECT date_created FROM autofill_dates WHERE pair_id = ? " "ORDER BY date_created DESC LIMIT 1)")); s.BindInt64(0, pair_id); s.BindInt64(1, pair_id); return s.Run(); } bool AutofillTable::AddFormFieldValuesTime( const std::vector& elements, std::vector* changes, Time time) { // Only add one new entry for each unique element name. Use |seen_names| to // track this. Add up to |kMaximumUniqueNames| unique entries per form. const size_t kMaximumUniqueNames = 256; std::set seen_names; bool result = true; for (std::vector::const_iterator itr = elements.begin(); itr != elements.end(); ++itr) { if (seen_names.size() >= kMaximumUniqueNames) break; if (seen_names.find(itr->name) != seen_names.end()) continue; result = result && AddFormFieldValueTime(*itr, changes, time); seen_names.insert(itr->name); } return result; } bool AutofillTable::ClearAutofillEmptyValueElements() { sql::Statement s(db_->GetUniqueStatement( "SELECT pair_id FROM autofill WHERE TRIM(value)= \"\"")); if (!s.is_valid()) return false; std::set ids; while (s.Step()) ids.insert(s.ColumnInt64(0)); if (!s.Succeeded()) return false; bool success = true; for (std::set::const_iterator iter = ids.begin(); iter != ids.end(); ++iter) { if (!RemoveFormElementForID(*iter)) success = false; } return success; } bool AutofillTable::GetAllAutofillEntries(std::vector* entries) { DCHECK(entries); sql::Statement s(db_->GetUniqueStatement( "SELECT name, value, date_created FROM autofill a JOIN " "autofill_dates ad ON a.pair_id=ad.pair_id")); bool first_entry = true; AutofillKey* current_key_ptr = NULL; std::vector