diff options
18 files changed, 579 insertions, 101 deletions
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc index 196910c..9ea27e6 100644 --- a/components/autofill/core/browser/autofill_profile.cc +++ b/components/autofill/core/browser/autofill_profile.cc @@ -15,6 +15,7 @@ #include "base/i18n/case_conversion.h" #include "base/i18n/char_iterator.h" #include "base/logging.h" +#include "base/sha1.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversion_utils.h" #include "base/strings/utf_string_conversions.h" @@ -267,7 +268,8 @@ AutofillProfile::AutofillProfile(RecordType type, const std::string& server_id) record_type_(type), name_(1), email_(1), - phone_number_(1, PhoneNumber(this)) { + phone_number_(1, PhoneNumber(this)), + server_id_(server_id) { DCHECK(type == SERVER_PROFILE); } @@ -311,6 +313,8 @@ AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) { address_ = profile.address_; set_language_code(profile.language_code()); + server_id_ = profile.server_id(); + return *this; } @@ -824,6 +828,26 @@ void AutofillProfile::CreateInferredLabels( } } +void AutofillProfile::GenerateServerProfileIdentifier() { + DCHECK_EQ(SERVER_PROFILE, record_type()); + base::string16 contents = MultiString(*this, NAME_FIRST); + contents.append(MultiString(*this, NAME_MIDDLE)); + contents.append(MultiString(*this, NAME_LAST)); + contents.append(MultiString(*this, EMAIL_ADDRESS)); + contents.append(GetRawInfo(COMPANY_NAME)); + contents.append(GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)); + contents.append(GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)); + contents.append(GetRawInfo(ADDRESS_HOME_CITY)); + contents.append(GetRawInfo(ADDRESS_HOME_STATE)); + contents.append(GetRawInfo(ADDRESS_HOME_ZIP)); + contents.append(GetRawInfo(ADDRESS_HOME_SORTING_CODE)); + contents.append(GetRawInfo(ADDRESS_HOME_COUNTRY)); + contents.append(MultiString(*this, PHONE_HOME_WHOLE_NUMBER)); + std::string contents_utf8 = UTF16ToUTF8(contents); + contents_utf8.append(language_code()); + server_id_ = base::SHA1HashString(contents_utf8); +} + // static base::string16 AutofillProfile::CanonicalizeProfileString( const base::string16& str) { diff --git a/components/autofill/core/browser/autofill_profile.h b/components/autofill/core/browser/autofill_profile.h index 597ff041..5da60d5 100644 --- a/components/autofill/core/browser/autofill_profile.h +++ b/components/autofill/core/browser/autofill_profile.h @@ -42,7 +42,8 @@ class AutofillProfile : public AutofillDataModel { AutofillProfile(const std::string& guid, const std::string& origin); // Server profile constructor. The type must be SERVER_PROFILE (this serves - // to differentiate this constructor). + // to differentiate this constructor). |server_id| can be empty. If empty, + // callers should invoke GenerateServerProfileIdentifier after setting data. AutofillProfile(RecordType type, const std::string& server_id); // For use in STL containers. @@ -181,6 +182,11 @@ class AutofillProfile : public AutofillDataModel { // Nonempty only when type() == SERVER_PROFILE. const std::string& server_id() const { return server_id_; } + // Creates an identifier and saves it as |server_id_|. Only used for + // server credit cards. The server doesn't attach an identifier so Chrome + // creates its own. The ID is a hash of the data contained in the profile. + void GenerateServerProfileIdentifier(); + // Returns a standardized representation of the given string for comparison // purposes. The resulting string will be lower-cased with all punctuation // substituted by spaces. Whitespace will be converted to ASCII space, and @@ -257,7 +263,8 @@ class AutofillProfile : public AutofillDataModel { // The BCP 47 language code that can be used to format |address_| for display. std::string language_code_; - // ID assigned by the server. This will be set only for WALLET_PROFILEs. + // ID used for identifying this profile. Only set for SERVER_PROFILEs. This is + // a hash of the contents. std::string server_id_; }; diff --git a/components/autofill/core/browser/autofill_test_utils.cc b/components/autofill/core/browser/autofill_test_utils.cc index 8b94c99..922eff7 100644 --- a/components/autofill/core/browser/autofill_test_utils.cc +++ b/components/autofill/core/browser/autofill_test_utils.cc @@ -299,7 +299,7 @@ void SetServerCreditCards(AutofillTable* table, if (card.record_type() != CreditCard::FULL_SERVER_CARD) continue; - table->UnmaskServerCreditCard(card.server_id(), card.number()); + table->UnmaskServerCreditCard(card, card.number()); } } diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc index 0e10852..b7a0a46 100644 --- a/components/autofill/core/browser/personal_data_manager.cc +++ b/components/autofill/core/browser/personal_data_manager.cc @@ -517,16 +517,10 @@ void PersonalDataManager::RecordUseOf(const AutofillDataModel& data_model) { if (credit_card) { credit_card->RecordUse(); - if (credit_card->record_type() == CreditCard::LOCAL_CARD) { + if (credit_card->record_type() == CreditCard::LOCAL_CARD) database_->UpdateCreditCard(*credit_card); - } else if (credit_card->record_type() == CreditCard::FULL_SERVER_CARD) { - database_->UpdateUnmaskedCardUsageStats(*credit_card); - } else { - // It's possible to get a masked server card here if the user decides not - // to store a card while verifying it. We don't currently track usage - // of masked cards, so no-op. - return; - } + else + database_->UpdateServerCardUsageStats(*credit_card); Refresh(); return; @@ -535,7 +529,12 @@ void PersonalDataManager::RecordUseOf(const AutofillDataModel& data_model) { AutofillProfile* profile = GetProfileByGUID(data_model.guid()); if (profile) { profile->RecordUse(); - database_->UpdateAutofillProfile(*profile); + + if (profile->record_type() == AutofillProfile::LOCAL_PROFILE) + database_->UpdateAutofillProfile(*profile); + else if (profile->record_type() == AutofillProfile::SERVER_PROFILE) + database_->UpdateServerAddressUsageStats(*profile); + Refresh(); } } @@ -673,7 +672,7 @@ void PersonalDataManager::UpdateServerCreditCard( DCHECK_NE(existing_credit_card->record_type(), credit_card.record_type()); DCHECK_EQ(existing_credit_card->Label(), credit_card.Label()); if (existing_credit_card->record_type() == CreditCard::MASKED_SERVER_CARD) { - database_->UnmaskServerCreditCard(credit_card.server_id(), + database_->UnmaskServerCreditCard(credit_card, credit_card.number()); } else { database_->MaskServerCreditCard(credit_card.server_id()); diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc index 74f934d..ae63c86 100644 --- a/components/autofill/core/browser/personal_data_manager_unittest.cc +++ b/components/autofill/core/browser/personal_data_manager_unittest.cc @@ -3102,7 +3102,7 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCardUsageStats) { server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "b456")); test::SetCreditCardInfo(&server_cards.back(), "Bonnie Parker", - "2109" /* Mastercard */, "12", "2012"); + "4444" /* Mastercard */, "12", "2012"); server_cards.back().SetTypeForMaskedCard(kMasterCard); server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "c789")); @@ -3131,6 +3131,7 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCardUsageStats) { EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) .WillOnce(QuitMainMessageLoop()); base::MessageLoop::current()->Run(); + ASSERT_EQ(3U, personal_data_->GetCreditCards().size()); for (size_t i = 0; i < 3; ++i) EXPECT_EQ(0, server_cards[i].Compare(*personal_data_->GetCreditCards()[i])); @@ -3152,6 +3153,7 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCardUsageStats) { EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) .WillOnce(QuitMainMessageLoop()); base::MessageLoop::current()->Run(); + ASSERT_EQ(3U, personal_data_->GetCreditCards().size()); EXPECT_EQ(1U, personal_data_->GetCreditCards()[0]->use_count()); EXPECT_NE(base::Time(), personal_data_->GetCreditCards()[0]->use_date()); @@ -3163,6 +3165,31 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCardUsageStats) { EXPECT_NE(base::Time(), personal_data_->GetCreditCards()[2]->use_date()); // Time may or may not have elapsed between unmasking and RecordUseOf. EXPECT_LE(initial_use_date, personal_data_->GetCreditCards()[2]->use_date()); + + // Can record usage stats on masked cards. + server_cards[1].set_guid(personal_data_->GetCreditCards()[1]->guid()); + personal_data_->RecordUseOf(server_cards[1]); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .WillOnce(QuitMainMessageLoop()); + base::MessageLoop::current()->Run(); + ASSERT_EQ(3U, personal_data_->GetCreditCards().size()); + EXPECT_EQ(1U, personal_data_->GetCreditCards()[1]->use_count()); + EXPECT_NE(base::Time(), personal_data_->GetCreditCards()[1]->use_date()); + + // Upgrading to unmasked retains the usage stats (and increments them). + CreditCard* unmasked_card2 = &server_cards[1]; + unmasked_card2->set_record_type(CreditCard::FULL_SERVER_CARD); + unmasked_card2->SetNumber(ASCIIToUTF16("5555555555554444")); + personal_data_->UpdateServerCreditCard(*unmasked_card2); + + server_cards[1].set_guid(personal_data_->GetCreditCards()[1]->guid()); + personal_data_->RecordUseOf(server_cards[1]); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .WillOnce(QuitMainMessageLoop()); + base::MessageLoop::current()->Run(); + ASSERT_EQ(3U, personal_data_->GetCreditCards().size()); + EXPECT_EQ(2U, personal_data_->GetCreditCards()[1]->use_count()); + EXPECT_NE(base::Time(), personal_data_->GetCreditCards()[1]->use_date()); } TEST_F(PersonalDataManagerTest, ClearAllServerData) { diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc index 10ec246..3f5a4c2 100644 --- a/components/autofill/core/browser/webdata/autofill_table.cc +++ b/components/autofill/core/browser/webdata/autofill_table.cc @@ -437,7 +437,8 @@ bool AutofillTable::CreateTablesIfNecessary() { InitProfileNamesTable() && InitProfileEmailsTable() && InitProfilePhonesTable() && InitProfileTrashTable() && InitMaskedCreditCardsTable() && InitUnmaskedCreditCardsTable() && - InitServerAddressesTable()); + InitServerCardMetadataTable() && InitServerAddressesTable() && + InitServerAddressMetadataTable()); } bool AutofillTable::IsSyncable() { @@ -475,6 +476,9 @@ bool AutofillTable::MigrateToVersion(int version, case 64: *update_compatible_version = false; return MigrateToVersion64AddUnmaskDate(); + case 65: + *update_compatible_version = false; + return MigrateToVersion65AddServerMetadataTables(); } return true; } @@ -904,6 +908,8 @@ bool AutofillTable::GetServerProfiles(std::vector<AutofillProfile*>* profiles) { sql::Statement s(db_->GetUniqueStatement( "SELECT " "id," + "use_count," + "use_date," "recipient_name," "company_name," "street_address," @@ -916,12 +922,16 @@ bool AutofillTable::GetServerProfiles(std::vector<AutofillProfile*>* profiles) { "country_code," // ADDRESS_HOME_COUNTRY "phone_number," // PHONE_HOME_WHOLE_NUMBER "language_code " - "FROM server_addresses")); + "FROM server_addresses addresses " + "LEFT OUTER JOIN server_address_metadata USING (id)")); while (s.Step()) { int index = 0; scoped_ptr<AutofillProfile> profile(new AutofillProfile( AutofillProfile::SERVER_PROFILE, s.ColumnString(index++))); + profile->set_use_count(s.ColumnInt64(index++)); + profile->set_use_date( + base::Time::FromInternalValue(s.ColumnInt64(index++))); base::string16 recipient_name = s.ColumnString16(index++); profile->SetRawInfo(COMPANY_NAME, s.ColumnString16(index++)); @@ -1001,6 +1011,12 @@ void AutofillTable::SetServerProfiles( insert.Reset(true); } + // Delete metadata that's no longer relevant. + sql::Statement metadata_delete(db_->GetUniqueStatement( + "DELETE FROM server_address_metadata WHERE id NOT IN " + "(SELECT id FROM server_addresses)")); + metadata_delete.Run(); + transaction.Commit(); } @@ -1155,16 +1171,16 @@ bool AutofillTable::GetServerCreditCards( "card_number_encrypted, " // 0 "last_four," // 1 "masked.id," // 2 - "use_count," // 3 - "use_date," // 4 + "metadata.use_count," // 3 + "metadata.use_date," // 4 "type," // 5 "status," // 6 "name_on_card," // 7 "exp_month," // 8 "exp_year " // 9 "FROM masked_credit_cards masked " - "LEFT OUTER JOIN unmasked_credit_cards unmasked " - "ON masked.id = unmasked.id")); + "LEFT OUTER JOIN unmasked_credit_cards USING (id) " + "LEFT OUTER JOIN server_card_metadata metadata USING (id)")); while (s.Step()) { int index = 0; @@ -1182,19 +1198,16 @@ bool AutofillTable::GetServerCreditCards( CREDIT_CARD_NUMBER, record_type == CreditCard::MASKED_SERVER_CARD ? last_four : full_card_number); - int64 use_count = s.ColumnInt64(index++); - int64 use_date = s.ColumnInt64(index++); + card->set_use_count(s.ColumnInt64(index++)); + card->set_use_date(base::Time::FromInternalValue(s.ColumnInt64(index++))); + std::string card_type = s.ColumnString(index++); if (record_type == CreditCard::MASKED_SERVER_CARD) { // The type must be set after setting the number to override the // autodectected type. card->SetTypeForMaskedCard(card_type.c_str()); - DCHECK_EQ(0, use_count); - DCHECK_EQ(0, use_date); } else { DCHECK_EQ(CreditCard::GetCreditCardType(full_card_number), card_type); - card->set_use_count(use_count); - card->set_use_date(base::Time::FromInternalValue(use_date)); } card->SetServerStatus(ServerStatusStringToEnum(s.ColumnString(index++))); @@ -1218,31 +1231,6 @@ void AutofillTable::SetServerCreditCards( "DELETE FROM masked_credit_cards")); masked_delete.Run(); - // Delete all items in the unmasked table that aren't in the new set. - sql::Statement get_unmasked(db_->GetUniqueStatement( - "SELECT id FROM unmasked_credit_cards")); - while (get_unmasked.Step()) { - // We expect relatively few cards, just do brute-force. - std::string server_id = get_unmasked.ColumnString(0); - bool found_card = false; - for (const CreditCard& cur_card : credit_cards) { - if (cur_card.server_id() == server_id) { - found_card = true; - break; - } - } - if (!found_card) { - // This unmasked card in the DB isn't present in the input. The statement - // is compiled every time because it's much more likely that this is never - // executed than it runs more than once. - sql::Statement unmasked_delete(db_->GetUniqueStatement( - "DELETE FROM unmasked_credit_cards WHERE id = ?")); - unmasked_delete.BindString(0, server_id); - unmasked_delete.Run(); - DCHECK_EQ(1, db_->GetLastChangeCount()); - } - } - sql::Statement masked_insert(db_->GetUniqueStatement( "INSERT INTO masked_credit_cards(" "id," // 0 @@ -1270,36 +1258,46 @@ void AutofillTable::SetServerCreditCards( masked_insert.Reset(true); } + // Delete all items in the unmasked table that aren't in the new set. + sql::Statement unmasked_delete(db_->GetUniqueStatement( + "DELETE FROM unmasked_credit_cards WHERE id NOT IN " + "(SELECT id FROM masked_credit_cards)")); + unmasked_delete.Run(); + // Do the same for metadata. + sql::Statement metadata_delete(db_->GetUniqueStatement( + "DELETE FROM server_card_metadata WHERE id NOT IN " + "(SELECT id FROM masked_credit_cards)")); + metadata_delete.Run(); + transaction.Commit(); } -bool AutofillTable::UnmaskServerCreditCard(const std::string& id, +bool AutofillTable::UnmaskServerCreditCard(const CreditCard& masked, const base::string16& full_number) { // Make sure there aren't duplicates for this card. - MaskServerCreditCard(id); + MaskServerCreditCard(masked.server_id()); sql::Statement s(db_->GetUniqueStatement( "INSERT INTO unmasked_credit_cards(" "id," "card_number_encrypted," - "use_count," - "use_date," "unmask_date)" - "VALUES (?,?,?,?,?)")); - s.BindString(0, id); + "VALUES (?,?,?)")); + s.BindString(0, masked.server_id()); std::string encrypted_data; OSCrypt::EncryptString16(full_number, &encrypted_data); s.BindBlob(1, encrypted_data.data(), static_cast<int>(encrypted_data.length())); + s.BindInt64(2, base::Time::Now().ToInternalValue()); // unmask_date - // Unmasking counts as a usage, so set the stats accordingly. - base::Time now = base::Time::Now(); - s.BindInt64(2, 1); // use_count - s.BindInt64(3, now.ToInternalValue()); // use_date + s.Run(); - s.BindInt64(4, now.ToInternalValue()); // unmask_date + CreditCard unmasked = masked; + unmasked.set_record_type(CreditCard::FULL_SERVER_CARD); + unmasked.SetNumber(full_number); + unmasked.RecordUse(); + UpdateServerCardUsageStats(unmasked); - s.Run(); return db_->GetLastChangeCount() > 0; } @@ -1311,18 +1309,54 @@ bool AutofillTable::MaskServerCreditCard(const std::string& id) { return db_->GetLastChangeCount() > 0; } -bool AutofillTable::UpdateUnmaskedCardUsageStats( +bool AutofillTable::UpdateServerCardUsageStats( const CreditCard& credit_card) { - DCHECK_EQ(CreditCard::FULL_SERVER_CARD, credit_card.record_type()); + DCHECK_NE(CreditCard::LOCAL_CARD, credit_card.record_type()); + sql::Transaction transaction(db_); + if (!transaction.Begin()) + return false; + + sql::Statement remove(db_->GetUniqueStatement( + "DELETE FROM server_card_metadata WHERE id = ?")); + remove.BindString(0, credit_card.server_id()); + remove.Run(); sql::Statement s(db_->GetUniqueStatement( - "UPDATE unmasked_credit_cards " - "SET use_count=?, use_date=? " - "WHERE id=?")); + "INSERT INTO server_card_metadata(use_count, use_date, id)" + "VALUES (?,?,?)")); s.BindInt64(0, credit_card.use_count()); s.BindInt64(1, credit_card.use_date().ToInternalValue()); s.BindString(2, credit_card.server_id()); s.Run(); + + transaction.Commit(); + + return db_->GetLastChangeCount() > 0; +} + +bool AutofillTable::UpdateServerAddressUsageStats( + const AutofillProfile& profile) { + DCHECK_EQ(AutofillProfile::SERVER_PROFILE, profile.record_type()); + + sql::Transaction transaction(db_); + if (!transaction.Begin()) + return false; + + sql::Statement remove(db_->GetUniqueStatement( + "DELETE FROM server_address_metadata WHERE id = ?")); + remove.BindString(0, profile.server_id()); + remove.Run(); + + sql::Statement s(db_->GetUniqueStatement( + "INSERT INTO server_address_metadata(use_count, use_date, id)" + "VALUES (?,?,?)")); + s.BindInt64(0, profile.use_count()); + s.BindInt64(1, profile.use_date().ToInternalValue()); + s.BindString(2, profile.server_id()); + s.Run(); + + transaction.Commit(); + return db_->GetLastChangeCount() > 0; } @@ -1346,6 +1380,16 @@ bool AutofillTable::ClearAllServerData() { addresses.Run(); changed |= db_->GetLastChangeCount() > 0; + sql::Statement card_metadata(db_->GetUniqueStatement( + "DELETE FROM server_card_metadata")); + card_metadata.Run(); + changed |= db_->GetLastChangeCount() > 0; + + sql::Statement address_metadata(db_->GetUniqueStatement( + "DELETE FROM server_address_metadata")); + address_metadata.Run(); + changed |= db_->GetLastChangeCount() > 0; + transaction.Commit(); return changed; } @@ -1725,6 +1769,19 @@ bool AutofillTable::InitUnmaskedCreditCardsTable() { return true; } +bool AutofillTable::InitServerCardMetadataTable() { + if (!db_->DoesTableExist("server_card_metadata")) { + if (!db_->Execute("CREATE TABLE server_card_metadata (" + "id VARCHAR NOT NULL," + "use_count INTEGER NOT NULL DEFAULT 0, " + "use_date INTEGER NOT NULL DEFAULT 0)")) { + NOTREACHED(); + return false; + } + } + return true; +} + bool AutofillTable::InitServerAddressesTable() { if (!db_->DoesTableExist("server_addresses")) { // The space after language_code is necessary to match what sqlite does @@ -1750,6 +1807,19 @@ bool AutofillTable::InitServerAddressesTable() { return true; } +bool AutofillTable::InitServerAddressMetadataTable() { + if (!db_->DoesTableExist("server_address_metadata")) { + if (!db_->Execute("CREATE TABLE server_address_metadata (" + "id VARCHAR NOT NULL," + "use_count INTEGER NOT NULL DEFAULT 0, " + "use_date INTEGER NOT NULL DEFAULT 0)")) { + NOTREACHED(); + return false; + } + } + return true; +} + bool AutofillTable::MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields() { sql::Transaction transaction(db_); if (!transaction.Begin()) @@ -2054,4 +2124,122 @@ bool AutofillTable::MigrateToVersion64AddUnmaskDate() { return transaction.Commit(); } +bool AutofillTable::MigrateToVersion65AddServerMetadataTables() { + sql::Transaction transaction(db_); + if (!transaction.Begin()) + return false; + + if (!db_->DoesTableExist("server_card_metadata") && + !db_->Execute("CREATE TABLE server_card_metadata (" + "id VARCHAR NOT NULL," + "use_count INTEGER NOT NULL DEFAULT 0, " + "use_date INTEGER NOT NULL DEFAULT 0)")) { + return false; + } + + // This clobbers existing usage metadata, which is not synced and only + // applies to unmasked cards. Trying to migrate the usage metadata would be + // tricky as multiple devices for the same user get DB upgrades. + if (!db_->Execute("UPDATE unmasked_credit_cards " + "SET use_count=0, use_date=0")) { + return false; + } + + if (!db_->DoesTableExist("server_address_metadata") && + !db_->Execute("CREATE TABLE server_address_metadata (" + "id VARCHAR NOT NULL," + "use_count INTEGER NOT NULL DEFAULT 0, " + "use_date INTEGER NOT NULL DEFAULT 0)")) { + return false; + } + + // Get existing server addresses and generate IDs for them. + sql::Statement s(db_->GetUniqueStatement( + "SELECT " + "id," + "recipient_name," + "company_name," + "street_address," + "address_1," // ADDRESS_HOME_STATE + "address_2," // ADDRESS_HOME_CITY + "address_3," // ADDRESS_HOME_DEPENDENT_LOCALITY + "address_4," // Not supported in AutofillProfile yet. + "postal_code," // ADDRESS_HOME_ZIP + "sorting_code," // ADDRESS_HOME_SORTING_CODE + "country_code," // ADDRESS_HOME_COUNTRY + "phone_number," // PHONE_HOME_WHOLE_NUMBER + "language_code " + "FROM server_addresses addresses")); + std::vector<AutofillProfile> profiles; + while (s.Step()) { + int index = 0; + AutofillProfile profile( + AutofillProfile::SERVER_PROFILE, s.ColumnString(index++)); + + base::string16 recipient_name = s.ColumnString16(index++); + profile.SetRawInfo(COMPANY_NAME, s.ColumnString16(index++)); + profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, s.ColumnString16(index++)); + profile.SetRawInfo(ADDRESS_HOME_STATE, s.ColumnString16(index++)); + profile.SetRawInfo(ADDRESS_HOME_CITY, s.ColumnString16(index++)); + profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY, + s.ColumnString16(index++)); + index++; // Skip address_4 which we haven't added to AutofillProfile yet. + profile.SetRawInfo(ADDRESS_HOME_ZIP, s.ColumnString16(index++)); + profile.SetRawInfo(ADDRESS_HOME_SORTING_CODE, s.ColumnString16(index++)); + profile.SetRawInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(index++)); + base::string16 phone_number = s.ColumnString16(index++); + profile.set_language_code(s.ColumnString(index++)); + profile.SetInfo(AutofillType(NAME_FULL), recipient_name, + profile.language_code()); + profile.SetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), phone_number, + profile.language_code()); + profile.GenerateServerProfileIdentifier(); + profiles.push_back(profile); + } + + // Reinsert with the generated IDs. + sql::Statement delete_old(db_->GetUniqueStatement( + "DELETE FROM server_addresses")); + delete_old.Run(); + + sql::Statement insert(db_->GetUniqueStatement( + "INSERT INTO server_addresses(" + "id," + "recipient_name," + "company_name," + "street_address," + "address_1," // ADDRESS_HOME_STATE + "address_2," // ADDRESS_HOME_CITY + "address_3," // ADDRESS_HOME_DEPENDENT_LOCALITY + "address_4," // Not supported in AutofillProfile yet. + "postal_code," // ADDRESS_HOME_ZIP + "sorting_code," // ADDRESS_HOME_SORTING_CODE + "country_code," // ADDRESS_HOME_COUNTRY + "phone_number," // PHONE_HOME_WHOLE_NUMBER + "language_code) " + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)")); + for (const AutofillProfile& profile : profiles) { + int index = 0; + insert.BindString(index++, profile.server_id()); + insert.BindString16(index++, profile.GetRawInfo(NAME_FULL)); + insert.BindString16(index++, profile.GetRawInfo(COMPANY_NAME)); + insert.BindString16(index++, + profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)); + insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_STATE)); + insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_CITY)); + insert.BindString16(index++, + profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)); + index++; // SKip address_4 which we haven't added to AutofillProfile yet. + insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_ZIP)); + insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE)); + insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_COUNTRY)); + insert.BindString16(index++, profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)); + insert.BindString(index++, profile.language_code()); + insert.Run(); + insert.Reset(true); + } + + return transaction.Commit(); +} + } // namespace autofill diff --git a/components/autofill/core/browser/webdata/autofill_table.h b/components/autofill/core/browser/webdata/autofill_table.h index cd97658..9ed5c8c 100644 --- a/components/autofill/core/browser/webdata/autofill_table.h +++ b/components/autofill/core/browser/webdata/autofill_table.h @@ -163,13 +163,22 @@ struct FormFieldData; // masked_credit_cards table to get the rest of the data. // card_number_encrypted // Full card number, encrypted. -// use_count The number of times this card has been used to fill -// a form. Added in version 62. -// use_date The date this card was last used to fill a form, in -// internal time format (NOT time_t). Added in version 62. +// use_count DEPRECATED in version 65. See server_card_metadata. +// use_date DEPRECATED in version 65. See server_card_metadata. // unmask_date The date this card was unmasked in units of // Time::ToInternalValue. Added in version 64. // +// server_card_metadata +// Metadata (currently, usage data) about server credit +// cards. This will be synced. +// +// id The server ID, which matches an ID from the +// masked_credit_cards table. +// use_count The number of times this card has been used to fill +// a form. +// use_date The date this card was last used to fill a form, +// in internal t. +// // server_addresses This table contains Autofill address data synced from // the wallet server. It's basically the same as the // autofill_profiles table but locally immutable. @@ -198,6 +207,18 @@ struct FormFieldData; // "ja-latn" language code starts with the recipient name. // phone_number Phone number. This is a string and has no formatting // constraints. Added in version 64. +// +// server_address_metadata +// Metadata (currently, usage data) about server addresses. +// This will be synced. +// +// id The server ID, which matches an ID from the +// server_addresses table. +// use_count The number of times this address has been used to fill +// a form. +// use_date The date this address was last used to fill a form, +// in internal t. + class AutofillTable : public WebDatabaseTable { public: explicit AutofillTable(const std::string& app_locale); @@ -316,12 +337,12 @@ class AutofillTable : public WebDatabaseTable { // Cards synced from the server may be "masked" (only last 4 digits // available) or "unmasked" (everything is available). These functions set // that state. - bool UnmaskServerCreditCard(const std::string& id, + bool UnmaskServerCreditCard(const CreditCard& masked, const base::string16& full_number); bool MaskServerCreditCard(const std::string& id); - // Updates the use count and last use date for an unmasked server card. - bool UpdateUnmaskedCardUsageStats(const CreditCard& credit_card); + bool UpdateServerCardUsageStats(const CreditCard& credit_card); + bool UpdateServerAddressUsageStats(const AutofillProfile& profile); // Deletes all data from the server card and profile tables. Returns true if // any data was deleted, false if not (so false means "commit not needed" @@ -365,7 +386,10 @@ class AutofillTable : public WebDatabaseTable { // Clear all profiles. bool ClearAutofillProfiles(); - // Table migration functions. + // Table migration functions. NB: These do not and should not rely on other + // functions in this class. The implementation of a function such as + // GetCreditCard may change over time, but MigrateToVersionXX should never + // change. bool MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields(); bool MigrateToVersion55MergeAutofillDatesTable(); bool MigrateToVersion56AddProfileLanguageCodeForFormatting(); @@ -375,6 +399,7 @@ class AutofillTable : public WebDatabaseTable { bool MigrateToVersion62AddUsageStatsForUnmaskedCards(); bool MigrateToVersion63AddServerRecipientName(); bool MigrateToVersion64AddUnmaskDate(); + bool MigrateToVersion65AddServerMetadataTables(); // Max data length saved in the table; static const size_t kMaxDataLength; @@ -444,7 +469,9 @@ class AutofillTable : public WebDatabaseTable { bool InitProfileTrashTable(); bool InitMaskedCreditCardsTable(); bool InitUnmaskedCreditCardsTable(); + bool InitServerCardMetadataTable(); bool InitServerAddressesTable(); + bool InitServerAddressMetadataTable(); // The application locale. The locale is needed for the migration to version // 35. Since it must be read on the UI thread, it is set when the table is diff --git a/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/components/autofill/core/browser/webdata/autofill_table_unittest.cc index 061c63c..1f01515 100644 --- a/components/autofill/core/browser/webdata/autofill_table_unittest.cc +++ b/components/autofill/core/browser/webdata/autofill_table_unittest.cc @@ -1665,7 +1665,7 @@ TEST_F(AutofillTableTest, MaskUnmaskServerCards) { // Unmask the number. The full number should be available. base::string16 full_number(ASCIIToUTF16("4111111111111111")); - ASSERT_TRUE(table_->UnmaskServerCreditCard(inputs[0].server_id(), + ASSERT_TRUE(table_->UnmaskServerCreditCard(inputs[0], full_number)); std::vector<CreditCard*> outputs; @@ -1705,7 +1705,7 @@ TEST_F(AutofillTableTest, SetServerCardModify) { // Now unmask it. base::string16 full_number = ASCIIToUTF16("4111111111111111"); - table_->UnmaskServerCreditCard(masked_card.server_id(), full_number); + table_->UnmaskServerCreditCard(masked_card, full_number); // The card should now be unmasked. std::vector<CreditCard*> outputs; @@ -1764,6 +1764,63 @@ TEST_F(AutofillTableTest, SetServerCardModify) { outputs.clear(); } +TEST_F(AutofillTableTest, SetServerCardUpdateUsageStats) { + // Add a masked card. + CreditCard masked_card(CreditCard::MASKED_SERVER_CARD, "a123"); + masked_card.SetRawInfo(CREDIT_CARD_NAME, ASCIIToUTF16("Paul F. Tompkins")); + masked_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("1")); + masked_card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2020")); + masked_card.SetRawInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("1111")); + masked_card.SetTypeForMaskedCard(kVisaCard); + + std::vector<CreditCard> inputs; + inputs.push_back(masked_card); + test::SetServerCreditCards(table_.get(), inputs); + + ScopedVector<CreditCard> outputs; + table_->GetServerCreditCards(&outputs.get()); + ASSERT_EQ(1u, outputs.size()); + EXPECT_EQ(masked_card.server_id(), outputs[0]->server_id()); + EXPECT_EQ(0U, outputs[0]->use_count()); + EXPECT_EQ(base::Time(), outputs[0]->use_date()); + outputs.clear(); + + // Update the usage stats; make sure they're reflected in GetServerProfiles. + inputs.back().set_use_count(4U); + inputs.back().set_use_date(base::Time::Now()); + table_->UpdateServerCardUsageStats(inputs.back()); + table_->GetServerCreditCards(&outputs.get()); + ASSERT_EQ(1u, outputs.size()); + EXPECT_EQ(masked_card.server_id(), outputs[0]->server_id()); + EXPECT_EQ(4U, outputs[0]->use_count()); + EXPECT_NE(base::Time(), outputs[0]->use_date()); + outputs.clear(); + + // Setting the cards again shouldn't delete the usage stats. + table_->SetServerCreditCards(inputs); + table_->GetServerCreditCards(&outputs.get()); + ASSERT_EQ(1u, outputs.size()); + EXPECT_EQ(masked_card.server_id(), outputs[0]->server_id()); + EXPECT_EQ(4U, outputs[0]->use_count()); + EXPECT_NE(base::Time(), outputs[0]->use_date()); + outputs.clear(); + + // Set a card list where the card is missing --- this should clear metadata. + CreditCard masked_card2(CreditCard::MASKED_SERVER_CARD, "b456"); + inputs.back() = masked_card2; + table_->SetServerCreditCards(inputs); + + // Back to the original card list. + inputs.back() = masked_card; + table_->SetServerCreditCards(inputs); + table_->GetServerCreditCards(&outputs.get()); + ASSERT_EQ(1u, outputs.size()); + EXPECT_EQ(masked_card.server_id(), outputs[0]->server_id()); + EXPECT_EQ(0U, outputs[0]->use_count()); + EXPECT_EQ(base::Time(), outputs[0]->use_date()); + outputs.clear(); +} + TEST_F(AutofillTableTest, SetServerProfile) { AutofillProfile one(AutofillProfile::SERVER_PROFILE, "a123"); std::vector<AutofillProfile> inputs; @@ -1792,6 +1849,52 @@ TEST_F(AutofillTableTest, SetServerProfile) { outputs.clear(); } +TEST_F(AutofillTableTest, SetServerProfileUpdateUsageStats) { + AutofillProfile one(AutofillProfile::SERVER_PROFILE, "a123"); + std::vector<AutofillProfile> inputs; + inputs.push_back(one); + table_->SetServerProfiles(inputs); + + ScopedVector<AutofillProfile> outputs; + table_->GetServerProfiles(&outputs.get()); + ASSERT_EQ(1u, outputs.size()); + EXPECT_EQ(one.server_id(), outputs[0]->server_id()); + EXPECT_EQ(0U, outputs[0]->use_count()); + EXPECT_EQ(base::Time(), outputs[0]->use_date()); + outputs.clear(); + + // Update the usage stats; make sure they're reflected in GetServerProfiles. + inputs.back().set_use_count(4U); + inputs.back().set_use_date(base::Time::Now()); + table_->UpdateServerAddressUsageStats(inputs.back()); + table_->GetServerProfiles(&outputs.get()); + ASSERT_EQ(1u, outputs.size()); + EXPECT_EQ(one.server_id(), outputs[0]->server_id()); + EXPECT_EQ(4U, outputs[0]->use_count()); + EXPECT_NE(base::Time(), outputs[0]->use_date()); + outputs.clear(); + + // Setting the profiles again shouldn't delete the usage stats. + table_->SetServerProfiles(inputs); + table_->GetServerProfiles(&outputs.get()); + ASSERT_EQ(1u, outputs.size()); + EXPECT_EQ(one.server_id(), outputs[0]->server_id()); + EXPECT_EQ(4U, outputs[0]->use_count()); + EXPECT_NE(base::Time(), outputs[0]->use_date()); + outputs.clear(); + + // Set a null profile list --- this should clear metadata. + table_->SetServerProfiles(std::vector<AutofillProfile>()); + // Reset the old profile list and see the metadata is reset. + table_->SetServerProfiles(inputs); + table_->GetServerProfiles(&outputs.get()); + ASSERT_EQ(1u, outputs.size()); + EXPECT_EQ(one.server_id(), outputs[0]->server_id()); + EXPECT_EQ(0U, outputs[0]->use_count()); + EXPECT_EQ(base::Time(), outputs[0]->use_date()); + outputs.clear(); +} + // Tests that deleting time ranges re-masks server credit cards that were // unmasked in that time. // TODO(brettw) fix flakiness and re-enable: crbug.com/465882 @@ -1815,7 +1918,7 @@ TEST_F(AutofillTableTest, DISABLED_DeleteUnmaskedCard) { // Unmask it. base::string16 full_number = ASCIIToUTF16("4111111111111111"); - table_->UnmaskServerCreditCard(masked_card.server_id(), full_number); + table_->UnmaskServerCreditCard(masked_card, full_number); // Delete data in a range a year in the future. std::vector<std::string> profile_guids; @@ -1847,7 +1950,7 @@ TEST_F(AutofillTableTest, DISABLED_DeleteUnmaskedCard) { outputs.clear(); // Unmask again, the card should be back. - table_->UnmaskServerCreditCard(masked_card.server_id(), full_number); + table_->UnmaskServerCreditCard(masked_card, full_number); ASSERT_TRUE(table_->GetServerCreditCards(&outputs.get())); ASSERT_EQ(1u, outputs.size()); EXPECT_EQ(CreditCard::FULL_SERVER_CARD, outputs[0]->record_type()); diff --git a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc index e4e0d05..e49fda7 100644 --- a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc +++ b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc @@ -76,7 +76,7 @@ CreditCard CardFromSpecifics(const sync_pb::WalletMaskedCreditCard& card) { AutofillProfile ProfileFromSpecifics( const sync_pb::WalletPostalAddress& address) { - AutofillProfile profile(AutofillProfile::SERVER_PROFILE, address.id()); + AutofillProfile profile(AutofillProfile::SERVER_PROFILE, std::string()); // AutofillProfile stores multi-line addresses with newline separators. std::vector<std::string> street_address(address.street_address().begin(), @@ -109,6 +109,8 @@ AutofillProfile ProfileFromSpecifics( base::UTF8ToUTF16(address.phone_number()), profile.language_code()); + profile.GenerateServerProfileIdentifier(); + return profile; } diff --git a/components/autofill/core/browser/webdata/autofill_webdata.h b/components/autofill/core/browser/webdata/autofill_webdata.h index 2cf04ef2..e2c121e 100644 --- a/components/autofill/core/browser/webdata/autofill_webdata.h +++ b/components/autofill/core/browser/webdata/autofill_webdata.h @@ -103,12 +103,16 @@ class AutofillWebData { // Toggles the record for a server credit card between masked (only last 4 // digits) and full (all digits). - virtual void UnmaskServerCreditCard(const std::string& id, + virtual void UnmaskServerCreditCard(const CreditCard& credit_card, const base::string16& full_number) = 0; virtual void MaskServerCreditCard(const std::string& id) = 0; - // Updates the use count and last use date for an unmasked server card. - virtual void UpdateUnmaskedCardUsageStats(const CreditCard& credit_card) = 0; + // Updates the use count and last use date for a server card (masked or not). + virtual void UpdateServerCardUsageStats(const CreditCard& credit_card) = 0; + + // Updates the use count and last use date for a server address. + virtual void UpdateServerAddressUsageStats(const AutofillProfile& profile) + = 0; // Removes Autofill records from the database. virtual void RemoveAutofillDataModifiedBetween( diff --git a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc index 38bc3bc..2bdc505 100644 --- a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc +++ b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc @@ -336,12 +336,12 @@ scoped_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetServerCreditCards( } WebDatabase::State AutofillWebDataBackendImpl::UnmaskServerCreditCard( - const std::string& id, + const CreditCard& card, const base::string16& full_number, WebDatabase* db) { DCHECK(db_thread_->BelongsToCurrentThread()); if (AutofillTable::FromWebDatabase(db)->UnmaskServerCreditCard( - id, full_number)) + card, full_number)) return WebDatabase::COMMIT_NEEDED; return WebDatabase::COMMIT_NOT_NEEDED; } @@ -356,12 +356,23 @@ WebDatabase::State return WebDatabase::COMMIT_NOT_NEEDED; } -WebDatabase::State AutofillWebDataBackendImpl::UpdateUnmaskedCardUsageStats( +WebDatabase::State AutofillWebDataBackendImpl::UpdateServerCardUsageStats( const CreditCard& card, WebDatabase* db) { DCHECK(db_thread_->BelongsToCurrentThread()); - if (AutofillTable::FromWebDatabase(db)->UpdateUnmaskedCardUsageStats(card)) + if (AutofillTable::FromWebDatabase(db)->UpdateServerCardUsageStats(card)) + return WebDatabase::COMMIT_NEEDED; + return WebDatabase::COMMIT_NOT_NEEDED; +} + +WebDatabase::State AutofillWebDataBackendImpl::UpdateServerAddressUsageStats( + const AutofillProfile& profile, + WebDatabase* db) { + DCHECK(db_thread_->BelongsToCurrentThread()); + if (AutofillTable::FromWebDatabase(db)->UpdateServerAddressUsageStats( + profile)) { return WebDatabase::COMMIT_NEEDED; + } return WebDatabase::COMMIT_NOT_NEEDED; } diff --git a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h index 50f510a..18c54f7 100644 --- a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h +++ b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h @@ -137,16 +137,20 @@ class AutofillWebDataBackendImpl // Server credit cards can be masked (only last 4 digits stored) or unmasked // (all data stored). These toggle between the two states. - WebDatabase::State UnmaskServerCreditCard(const std::string& id, + WebDatabase::State UnmaskServerCreditCard(const CreditCard& card, const base::string16& full_number, WebDatabase* db); WebDatabase::State MaskServerCreditCard(const std::string& id, WebDatabase* db); - WebDatabase::State UpdateUnmaskedCardUsageStats( + WebDatabase::State UpdateServerCardUsageStats( const CreditCard& credit_card, WebDatabase* db); + WebDatabase::State UpdateServerAddressUsageStats( + const AutofillProfile& profile, + WebDatabase* db); + WebDatabase::State ClearAllServerData(WebDatabase* db); // Removes Autofill records from the database. Valid only for local diff --git a/components/autofill/core/browser/webdata/autofill_webdata_service.cc b/components/autofill/core/browser/webdata/autofill_webdata_service.cc index 82da109..8f3be4d 100644 --- a/components/autofill/core/browser/webdata/autofill_webdata_service.cc +++ b/components/autofill/core/browser/webdata/autofill_webdata_service.cc @@ -183,12 +183,12 @@ WebDataServiceBase::Handle AutofillWebDataService::GetServerCreditCards( } void AutofillWebDataService::UnmaskServerCreditCard( - const std::string& id, + const CreditCard& credit_card, const base::string16& full_number) { wdbs_->ScheduleDBTask( FROM_HERE, Bind(&AutofillWebDataBackendImpl::UnmaskServerCreditCard, - autofill_backend_, id, full_number)); + autofill_backend_, credit_card, full_number)); } void AutofillWebDataService::MaskServerCreditCard(const std::string& id) { @@ -205,14 +205,22 @@ void AutofillWebDataService::ClearAllServerData() { autofill_backend_)); } -void AutofillWebDataService::UpdateUnmaskedCardUsageStats( +void AutofillWebDataService::UpdateServerCardUsageStats( const CreditCard& credit_card) { wdbs_->ScheduleDBTask( FROM_HERE, - Bind(&AutofillWebDataBackendImpl::UpdateUnmaskedCardUsageStats, + Bind(&AutofillWebDataBackendImpl::UpdateServerCardUsageStats, autofill_backend_, credit_card)); } +void AutofillWebDataService::UpdateServerAddressUsageStats( + const AutofillProfile& profile) { + wdbs_->ScheduleDBTask( + FROM_HERE, + Bind(&AutofillWebDataBackendImpl::UpdateServerAddressUsageStats, + autofill_backend_, profile)); +} + void AutofillWebDataService::RemoveAutofillDataModifiedBetween( const Time& delete_begin, const Time& delete_end) { diff --git a/components/autofill/core/browser/webdata/autofill_webdata_service.h b/components/autofill/core/browser/webdata/autofill_webdata_service.h index acc23f3..221e49b 100644 --- a/components/autofill/core/browser/webdata/autofill_webdata_service.h +++ b/components/autofill/core/browser/webdata/autofill_webdata_service.h @@ -88,13 +88,14 @@ class AutofillWebDataService : public AutofillWebData, // Server cards. WebDataServiceBase::Handle GetServerCreditCards( WebDataServiceConsumer* consumer) override; - void UnmaskServerCreditCard(const std::string& id, + void UnmaskServerCreditCard(const CreditCard& card, const base::string16& full_number) override; void MaskServerCreditCard(const std::string& id) override; void ClearAllServerData(); - void UpdateUnmaskedCardUsageStats(const CreditCard& credit_card) override; + void UpdateServerCardUsageStats(const CreditCard& credit_card) override; + void UpdateServerAddressUsageStats(const AutofillProfile& profile) override; void RemoveAutofillDataModifiedBetween(const base::Time& delete_begin, const base::Time& delete_end) override; diff --git a/components/test/data/web_database/version_64.sql b/components/test/data/web_database/version_64.sql new file mode 100644 index 0000000..620f52a --- /dev/null +++ b/components/test/data/web_database/version_64.sql @@ -0,0 +1,26 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); +INSERT INTO "meta" VALUES('version','64'); +INSERT INTO "meta" VALUES('last_compatible_version','61'); +INSERT INTO "meta" VALUES('Builtin Keyword Version','82'); +CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); +CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, date_created INTEGER DEFAULT 0, date_last_used INTEGER DEFAULT 0, count INTEGER DEFAULT 1, PRIMARY KEY (name, value)); +CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0); +CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0); +CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR); +CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); +CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); +CREATE TABLE autofill_profiles_trash ( guid VARCHAR); +CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,type VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0); +CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, unmask_date INTEGER NOT NULL DEFAULT 0); +CREATE TABLE server_addresses (id VARCHAR,company_name VARCHAR,street_address VARCHAR,address_1 VARCHAR,address_2 VARCHAR,address_3 VARCHAR,address_4 VARCHAR,postal_code VARCHAR,sorting_code VARCHAR,country_code VARCHAR,language_code VARCHAR, recipient_name VARCHAR, phone_number VARCHAR); +CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR,search_terms_replacement_key VARCHAR,image_url VARCHAR,search_url_post_params VARCHAR,suggest_url_post_params VARCHAR,instant_url_post_params VARCHAR,image_url_post_params VARCHAR,new_tab_url VARCHAR); +INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?q={searchTerms}&{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:bookmarkBarPinned}{google:searchClient}{google:sourceId}{google:instantExtendedEnabledParameter}{google:omniboxStartMarginParameter}{google:contextualSearchVersion}ie={inputEncoding}',1,'',0,0,'UTF-8',1,'{google:baseSuggestURL}search?{google:searchFieldtrialParameter}client={google:suggestClient}&gs_ri={google:suggestRid}&xssi=t&q={searchTerms}&{google:inputType}{google:cursorPosition}{google:currentPageUrl}{google:pageClassification}{google:searchVersion}{google:sessionToken}{google:prefetchQuery}sugkey={google:suggestAPIKeyParameter}',1,0,'{google:baseURL}webhp?sourceid=chrome-instant&{google:RLZ}{google:forceInstantResults}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}{google:omniboxStartMarginParameter}ie={inputEncoding}',0,'B0AD0C88-0B0F-4D2E-9412-7D600832785D','["{google:baseURL}#q={searchTerms}","{google:baseURL}search#q={searchTerms}","{google:baseURL}webhp#q={searchTerms}","{google:baseURL}s#q={searchTerms}","{google:baseURL}s?q={searchTerms}"]','espv','{google:baseURL}searchbyimage/upload','','','','encoded_image={google:imageThumbnail},image_url={google:imageURL},sbisrc={google:imageSearchSource},original_width={google:imageOriginalWidth},original_height={google:imageOriginalHeight}','{google:baseURL}_/chrome/newtab?{google:RLZ}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}ie={inputEncoding}'); +INSERT INTO "keywords" VALUES(3,'Bing','bing.com','https://www.bing.com/s/a/bing_p.ico','https://www.bing.com/search?q={searchTerms}&PC=U316&FORM=CHROMN',1,'',0,0,'UTF-8',1,'https://www.bing.com/osjson.aspx?query={searchTerms}&language={language}&PC=U316',3,0,'',0,'D42E29D2-75F7-4D8E-8ECA-3886F2B9E737','[]','','','','','','','https://www.bing.com/chrome/newtab'); +INSERT INTO "keywords" VALUES(4,'Yahoo!','yahoo.com','https://search.yahoo.com/favicon.ico','https://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,'',0,0,'UTF-8',1,'https://search.yahoo.com/sugg/chrome?output=fxjson&appid=crmas&command={searchTerms}',2,0,'',0,'832F796B-6C66-4B24-BB24-37A52E831685','[]','','','','','','',''); +INSERT INTO "keywords" VALUES(5,'AOL','aol.com','http://search.aol.com/favicon.ico','http://search.aol.com/aol/search?q={searchTerms}',1,'',0,0,'UTF-8',1,'http://autocomplete.search.aol.com/autocomplete/get?output=json&it=&q={searchTerms}',35,0,'',0,'8AF217B0-8D8B-431F-A4AC-471AABB85B4E','[]','','','','','','',''); +INSERT INTO "keywords" VALUES(6,'Ask','ask.com','http://sp.ask.com/sh/i/a16/favicon/favicon.ico','http://www.ask.com/web?q={searchTerms}',1,'',0,0,'UTF-8',1,'http://ss.ask.com/query?q={searchTerms}&li=ff',4,0,'',0,'3F7F86C1-1CA7-4080-8DD1-990348B92F31','[]','','','','','','',''); +CREATE INDEX autofill_name ON autofill (name); +CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); +COMMIT; diff --git a/components/webdata/common/web_database.cc b/components/webdata/common/web_database.cc index 04ff538..f091a2a 100644 --- a/components/webdata/common/web_database.cc +++ b/components/webdata/common/web_database.cc @@ -14,7 +14,7 @@ // corresponding changes must happen in the unit tests, and new migration test // added. See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|. // static -const int WebDatabase::kCurrentVersionNumber = 64; +const int WebDatabase::kCurrentVersionNumber = 65; const int WebDatabase::kDeprecatedVersionNumber = 51; diff --git a/components/webdata/common/web_database_migration_unittest.cc b/components/webdata/common/web_database_migration_unittest.cc index 1f36aad..9919098 100644 --- a/components/webdata/common/web_database_migration_unittest.cc +++ b/components/webdata/common/web_database_migration_unittest.cc @@ -132,7 +132,7 @@ class WebDatabaseMigrationTest : public testing::Test { DISALLOW_COPY_AND_ASSIGN(WebDatabaseMigrationTest); }; -const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 64; +const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 65; void WebDatabaseMigrationTest::LoadDatabase( const base::FilePath::StringType& file) { @@ -934,3 +934,50 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion61ToCurrent) { "use_date")); } } + +// Tests addition of server metadata tables. +TEST_F(WebDatabaseMigrationTest, MigrateVersion64ToCurrent) { + ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_64.sql"))); + + // Verify pre-conditions. + { + sql::Connection connection; + ASSERT_TRUE(connection.Open(GetDatabasePath())); + ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); + + sql::MetaTable meta_table; + ASSERT_TRUE(meta_table.Init(&connection, 64, 64)); + + EXPECT_FALSE(connection.DoesTableExist("server_card_metadata")); + EXPECT_FALSE(connection.DoesTableExist("server_address_metadata")); + + // Add a server address --- make sure it gets an ID. + sql::Statement insert_profiles( + connection.GetUniqueStatement( + "INSERT INTO server_addresses(id, postal_code) " + "VALUES ('', 90210)")); + insert_profiles.Run(); + } + + DoMigration(); + + // Verify post-conditions. + { + sql::Connection connection; + ASSERT_TRUE(connection.Open(GetDatabasePath())); + ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); + + // Check version. + EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); + + EXPECT_TRUE(connection.DoesTableExist("server_card_metadata")); + EXPECT_TRUE(connection.DoesTableExist("server_address_metadata")); + + sql::Statement read_profiles( + connection.GetUniqueStatement( + "SELECT id, postal_code FROM server_addresses")); + ASSERT_TRUE(read_profiles.Step()); + EXPECT_FALSE(read_profiles.ColumnString(0).empty()); + EXPECT_EQ("90210", read_profiles.ColumnString(1)); + } +} diff --git a/sync/protocol/autofill_specifics.proto b/sync/protocol/autofill_specifics.proto index 85a868e..68547ae 100644 --- a/sync/protocol/autofill_specifics.proto +++ b/sync/protocol/autofill_specifics.proto @@ -116,7 +116,7 @@ message WalletMaskedCreditCard { // Different than an AutofillProfile because this represents some known address // on the server that is pulled down rather than synced between Chromes. message WalletPostalAddress { - // Server-generated unique ID string. This is opaque to the client. + // DEPRECATED optional string id = 1; optional string recipient_name = 12; |