| Index: components/autofill/core/browser/webdata/autofill_table.cc
|
| diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc
|
| index 10ec2469b0d7c7be7de1a18252784540578b8bbc..3f5a4c21dbd5e776edb5a05cffa4266887fe0107 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
|
|
|