summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorestade <estade@chromium.org>2015-04-07 15:54:00 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-07 22:55:14 +0000
commit378d323b7aa68cddef9429901a7992c4b6346c85 (patch)
tree545d82ae892526b326c35f4ee3fb5af86fcbd6f1
parent0a76becb3c8bc0dce4a6b05a1c3b7a1c42053d1d (diff)
downloadchromium_src-378d323b7aa68cddef9429901a7992c4b6346c85.zip
chromium_src-378d323b7aa68cddef9429901a7992c4b6346c85.tar.gz
chromium_src-378d323b7aa68cddef9429901a7992c4b6346c85.tar.bz2
Create syncable metadata table for Wallet credit cards and addresses.
This is only used for usage statistics (without which we can't apply smart ordering to masked credit card suggestions, or sync usage stats between devices for unmasked cards). There was already code in place for IDs for addresses, which was essentially unused (ID was always empty). This generates an ID to help identify server addresses for the usage stat tracking. The tables are not actually synced yet (that's TODO). BUG=none Review URL: https://codereview.chromium.org/1042353003 Cr-Commit-Position: refs/heads/master@{#324142}
-rw-r--r--components/autofill/core/browser/autofill_profile.cc26
-rw-r--r--components/autofill/core/browser/autofill_profile.h11
-rw-r--r--components/autofill/core/browser/autofill_test_utils.cc2
-rw-r--r--components/autofill/core/browser/personal_data_manager.cc21
-rw-r--r--components/autofill/core/browser/personal_data_manager_unittest.cc29
-rw-r--r--components/autofill/core/browser/webdata/autofill_table.cc296
-rw-r--r--components/autofill/core/browser/webdata/autofill_table.h43
-rw-r--r--components/autofill/core/browser/webdata/autofill_table_unittest.cc111
-rw-r--r--components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc4
-rw-r--r--components/autofill/core/browser/webdata/autofill_webdata.h10
-rw-r--r--components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc19
-rw-r--r--components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h8
-rw-r--r--components/autofill/core/browser/webdata/autofill_webdata_service.cc16
-rw-r--r--components/autofill/core/browser/webdata/autofill_webdata_service.h5
-rw-r--r--components/test/data/web_database/version_64.sql26
-rw-r--r--components/webdata/common/web_database.cc2
-rw-r--r--components/webdata/common/web_database_migration_unittest.cc49
-rw-r--r--sync/protocol/autofill_specifics.proto2
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;