Home | History | Annotate | Download | only in glue
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/sync/glue/autofill_profile_model_associator.h"
      6 
      7 #include "base/utf_string_conversions.h"
      8 #include "chrome/browser/sync/glue/autofill_profile_change_processor.h"
      9 #include "chrome/browser/sync/glue/do_optimistic_refresh_task.h"
     10 #include "chrome/browser/sync/profile_sync_service.h"
     11 #include "chrome/browser/webdata/web_database.h"
     12 #include "chrome/common/guid.h"
     13 
     14 using sync_api::ReadNode;
     15 namespace browser_sync {
     16 
     17 const char kAutofillProfileTag[] = "google_chrome_autofill_profiles";
     18 
     19 AutofillProfileModelAssociator::AutofillProfileModelAssociator(
     20     ProfileSyncService* sync_service,
     21     WebDatabase* web_database,
     22     PersonalDataManager* personal_data)
     23     : sync_service_(sync_service),
     24       web_database_(web_database),
     25       personal_data_(personal_data),
     26       autofill_node_id_(sync_api::kInvalidId),
     27       abort_association_pending_(false),
     28       number_of_profiles_created_(0) {
     29   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
     30   DCHECK(sync_service_);
     31   DCHECK(web_database_);
     32   DCHECK(personal_data_);
     33 }
     34 
     35 AutofillProfileModelAssociator::~AutofillProfileModelAssociator() {
     36   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
     37 }
     38 
     39 AutofillProfileModelAssociator::AutofillProfileModelAssociator()
     40     : sync_service_(NULL),
     41       web_database_(NULL),
     42       personal_data_(NULL),
     43       autofill_node_id_(0),
     44       abort_association_pending_(false),
     45       number_of_profiles_created_(0) {
     46 }
     47 
     48 bool AutofillProfileModelAssociator::TraverseAndAssociateChromeAutofillProfiles(
     49     sync_api::WriteTransaction* write_trans,
     50     const sync_api::ReadNode& autofill_root,
     51     const std::vector<AutofillProfile*>& all_profiles_from_db,
     52     std::set<std::string>* current_profiles,
     53     std::vector<AutofillProfile*>* updated_profiles,
     54     std::vector<AutofillProfile*>* new_profiles,
     55     std::vector<std::string>* profiles_to_delete) {
     56 
     57   if (VLOG_IS_ON(2)) {
     58     VLOG(2) << "[AUTOFILL MIGRATION]"
     59             << "Printing profiles from web db";
     60 
     61     for (std::vector<AutofillProfile*>::const_iterator ix =
     62         all_profiles_from_db.begin(); ix != all_profiles_from_db.end(); ++ix) {
     63       AutofillProfile* p = *ix;
     64       VLOG(2) << "[AUTOFILL MIGRATION]  "
     65               << p->GetInfo(NAME_FIRST)
     66               << p->GetInfo(NAME_LAST)
     67               << p->guid();
     68     }
     69   }
     70 
     71   VLOG(1) << "[AUTOFILL MIGRATION]"
     72           << "Looking for the above data in sync db..";
     73 
     74   // Alias the all_profiles_from_db so we fit in 80 characters
     75   const std::vector<AutofillProfile*>& profiles(all_profiles_from_db);
     76   for (std::vector<AutofillProfile*>::const_iterator ix = profiles.begin();
     77       ix != profiles.end();
     78       ++ix) {
     79     std::string guid((*ix)->guid());
     80     if (guid::IsValidGUID(guid) == false) {
     81       DCHECK(false) << "Guid in the web db is invalid " << guid;
     82       continue;
     83     }
     84 
     85     ReadNode node(write_trans);
     86     if (node.InitByClientTagLookup(syncable::AUTOFILL_PROFILE, guid) &&
     87         // The following check is to ensure the given sync node is not already
     88         // associated with another profile. That could happen if the user has
     89         // the same profile duplicated.
     90         current_profiles->find(guid) == current_profiles->end()) {
     91       VLOG(2) << "[AUTOFILL MIGRATION]"
     92               << " Found in sync db: "
     93               << (*ix)->GetInfo(NAME_FIRST)
     94               << (*ix)->GetInfo(NAME_LAST)
     95               << (*ix)->guid()
     96               << " so associating with node id " << node.GetId();
     97       const sync_pb::AutofillProfileSpecifics& autofill(
     98           node.GetAutofillProfileSpecifics());
     99       if (OverwriteProfileWithServerData(*ix, autofill)) {
    100         updated_profiles->push_back(*ix);
    101       }
    102       Associate(&guid, node.GetId());
    103       current_profiles->insert(guid);
    104     } else {
    105       MakeNewAutofillProfileSyncNodeIfNeeded(write_trans,
    106           autofill_root,
    107           (**ix),
    108           new_profiles,
    109           current_profiles,
    110           profiles_to_delete);
    111     }
    112   }
    113   return true;
    114 }
    115 
    116 bool AutofillProfileModelAssociator::GetSyncIdForTaggedNode(
    117     const std::string& tag,
    118     int64* sync_id) {
    119   sync_api::ReadTransaction trans(sync_service_->GetUserShare());
    120   sync_api::ReadNode sync_node(&trans);
    121   if (!sync_node.InitByTagLookup(tag.c_str()))
    122     return false;
    123   *sync_id = sync_node.GetId();
    124   return true;
    125 }
    126 
    127 bool AutofillProfileModelAssociator::LoadAutofillData(
    128     std::vector<AutofillProfile*>* profiles) {
    129   if (IsAbortPending())
    130     return false;
    131 
    132   if (!web_database_->GetAutofillTable()->GetAutofillProfiles(profiles))
    133     return false;
    134 
    135   return true;
    136 }
    137 
    138 bool AutofillProfileModelAssociator::AssociateModels() {
    139   VLOG(1) << "Associating Autofill Models";
    140   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    141   {
    142     base::AutoLock lock(abort_association_pending_lock_);
    143     abort_association_pending_ = false;
    144   }
    145 
    146   ScopedVector<AutofillProfile> profiles;
    147 
    148   if (!LoadAutofillData(&profiles.get())) {
    149     LOG(ERROR) << "Could not get the autofill data from WebDatabase.";
    150     return false;
    151   }
    152 
    153   VLOG(1) << "[AUTOFILL MIGRATION]"
    154           << " Now associating to the new autofill profile model associator"
    155           << " root node";
    156   DataBundle bundle;
    157   {
    158     // The write transaction lock is held inside this block.
    159     // We do all the web db operations outside this block.
    160     sync_api::WriteTransaction trans(sync_service_->GetUserShare());
    161 
    162     sync_api::ReadNode autofill_root(&trans);
    163     if (!autofill_root.InitByTagLookup(kAutofillProfileTag)) {
    164       LOG(ERROR) << "Server did not create the top-level autofill node. We "
    165                  << "might be running against an out-of-date server.";
    166       return false;
    167     }
    168 
    169     if (!TraverseAndAssociateChromeAutofillProfiles(&trans, autofill_root,
    170             profiles.get(), &bundle.current_profiles,
    171             &bundle.updated_profiles,
    172             &bundle.new_profiles,
    173             &bundle.profiles_to_delete) ||
    174         !TraverseAndAssociateAllSyncNodes(&trans, autofill_root, &bundle)) {
    175       return false;
    176     }
    177   }
    178 
    179   if (!SaveChangesToWebData(bundle)) {
    180     LOG(ERROR) << "Failed to update autofill entries.";
    181     return false;
    182   }
    183 
    184   if (sync_service_->GetAutofillMigrationState() !=
    185      syncable::MIGRATED) {
    186     syncable::AutofillMigrationDebugInfo debug_info;
    187     debug_info.autofill_profile_added_during_migration =
    188         number_of_profiles_created_;
    189     sync_service_->SetAutofillMigrationDebugInfo(
    190         syncable::AutofillMigrationDebugInfo::PROFILES_ADDED,
    191         debug_info);
    192     sync_service_->SetAutofillMigrationState(
    193         syncable::MIGRATED);
    194   }
    195 
    196   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
    197       new DoOptimisticRefreshForAutofill(personal_data_));
    198   return true;
    199 }
    200 
    201 bool AutofillProfileModelAssociator::DisassociateModels() {
    202   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    203   id_map_.clear();
    204   id_map_inverse_.clear();
    205   return true;
    206 }
    207 
    208 // Helper to compare the local value and cloud value of a field, merge into
    209 // the local value if they differ, and return whether the merge happened.
    210 bool AutofillProfileModelAssociator::MergeField(FormGroup* f,
    211     AutofillFieldType t,
    212     const std::string& specifics_field) {
    213   if (UTF16ToUTF8(f->GetInfo(t)) == specifics_field)
    214     return false;
    215   f->SetInfo(t, UTF8ToUTF16(specifics_field));
    216   return true;
    217 }
    218 bool AutofillProfileModelAssociator::SyncModelHasUserCreatedNodes(
    219     bool *has_nodes) {
    220   CHECK_NE(has_nodes, reinterpret_cast<bool*>(NULL));
    221   sync_api::ReadTransaction trans(sync_service_->GetUserShare());
    222 
    223   sync_api::ReadNode node(&trans);
    224 
    225   if (!node.InitByTagLookup(kAutofillProfileTag)) {
    226     LOG(ERROR) << "Sever did not create a top level node"
    227                << "Out of data server or autofill type not enabled";
    228     return false;
    229   }
    230 
    231   *has_nodes = sync_api::kInvalidId != node.GetFirstChildId();
    232   return true;
    233 }
    234 // static
    235 bool AutofillProfileModelAssociator::OverwriteProfileWithServerData(
    236     AutofillProfile* merge_into,
    237     const sync_pb::AutofillProfileSpecifics& specifics) {
    238   bool diff = false;
    239   AutofillProfile* p = merge_into;
    240   const sync_pb::AutofillProfileSpecifics& s(specifics);
    241   diff = MergeField(p, NAME_FIRST, s.name_first()) || diff;
    242   diff = MergeField(p, NAME_LAST, s.name_last()) || diff;
    243   diff = MergeField(p, NAME_MIDDLE, s.name_middle()) || diff;
    244   diff = MergeField(p, ADDRESS_HOME_LINE1, s.address_home_line1()) || diff;
    245   diff = MergeField(p, ADDRESS_HOME_LINE2, s.address_home_line2()) || diff;
    246   diff = MergeField(p, ADDRESS_HOME_CITY, s.address_home_city()) || diff;
    247   diff = MergeField(p, ADDRESS_HOME_STATE, s.address_home_state()) || diff;
    248   diff = MergeField(p, ADDRESS_HOME_COUNTRY, s.address_home_country()) || diff;
    249   diff = MergeField(p, ADDRESS_HOME_ZIP, s.address_home_zip()) || diff;
    250   diff = MergeField(p, EMAIL_ADDRESS, s.email_address()) || diff;
    251   diff = MergeField(p, COMPANY_NAME, s.company_name()) || diff;
    252   diff = MergeField(p, PHONE_FAX_WHOLE_NUMBER, s.phone_fax_whole_number())
    253       || diff;
    254   diff = MergeField(p, PHONE_HOME_WHOLE_NUMBER, s.phone_home_whole_number())
    255       || diff;
    256   return diff;
    257 }
    258 
    259 
    260 int64 AutofillProfileModelAssociator::FindSyncNodeWithProfile(
    261     sync_api::WriteTransaction* trans,
    262     const sync_api::BaseNode& autofill_root,
    263     const AutofillProfile& profile_from_db,
    264     std::set<std::string>* current_profiles) {
    265   int64 sync_child_id = autofill_root.GetFirstChildId();
    266   while (sync_child_id != sync_api::kInvalidId) {
    267     ReadNode read_node(trans);
    268     AutofillProfile p;
    269     if (!read_node.InitByIdLookup(sync_child_id)) {
    270       LOG(ERROR) << "unable to find the id given by getfirst child " <<
    271         sync_child_id;
    272       return sync_api::kInvalidId;
    273     }
    274     const sync_pb::AutofillProfileSpecifics& autofill_specifics(
    275         read_node.GetAutofillProfileSpecifics());
    276 
    277     // This find should be fast as the set uses tree.
    278     if (current_profiles->find(autofill_specifics.guid())
    279         == current_profiles->end()) {
    280       OverwriteProfileWithServerData(&p, autofill_specifics);
    281       if (p.Compare(profile_from_db) == 0) {
    282         return sync_child_id;
    283       }
    284     }
    285     sync_child_id = read_node.GetSuccessorId();
    286   }
    287 
    288   return sync_api::kInvalidId;
    289 }
    290 bool AutofillProfileModelAssociator::MakeNewAutofillProfileSyncNodeIfNeeded(
    291     sync_api::WriteTransaction* trans,
    292     const sync_api::BaseNode& autofill_root,
    293     const AutofillProfile& profile,
    294     std::vector<AutofillProfile*>* new_profiles,
    295     std::set<std::string>* current_profiles,
    296     std::vector<std::string>* profiles_to_delete) {
    297 
    298   int64 sync_node_id = FindSyncNodeWithProfile(trans,
    299       autofill_root,
    300       profile,
    301       current_profiles);
    302   if (sync_node_id != sync_api::kInvalidId) {
    303     // In case of duplicates throw away the local profile and apply the
    304     // server profile.(The only difference between the 2 profiles are the guids)
    305     profiles_to_delete->push_back(profile.guid());
    306     sync_api::ReadNode read_node(trans);
    307     if (!read_node.InitByIdLookup(sync_node_id)) {
    308       LOG(ERROR);
    309       return false;
    310     }
    311     const sync_pb::AutofillProfileSpecifics& autofill_specifics(
    312         read_node.GetAutofillProfileSpecifics());
    313     if (guid::IsValidGUID(autofill_specifics.guid()) == false) {
    314       NOTREACHED() << "Guid in the web db is invalid " <<
    315           autofill_specifics.guid();
    316       return false;
    317     }
    318     AutofillProfile* p = new AutofillProfile(autofill_specifics.guid());
    319     OverwriteProfileWithServerData(p, autofill_specifics);
    320     new_profiles->push_back(p);
    321     std::string guid = autofill_specifics.guid();
    322     Associate(&guid, sync_node_id);
    323     current_profiles->insert(autofill_specifics.guid());
    324     VLOG(2) << "[AUTOFILL MIGRATION]"
    325             << "Found in sync db but with a different guid: "
    326             << UTF16ToUTF8(profile.GetInfo(NAME_FIRST))
    327             << UTF16ToUTF8(profile.GetInfo(NAME_LAST))
    328             << "New guid " << autofill_specifics.guid() << " sync node id "
    329             << sync_node_id << " so associating. Profile to be deleted "
    330             << profile.guid();
    331   } else {
    332     sync_api::WriteNode node(trans);
    333 
    334     // The profile.guid() is expected to be a valid guid. The caller is expected
    335     // to pass in a valid profile object with a valid guid. Having to check in
    336     // 2 places(the caller and here) is not optimal.
    337     if (!node.InitUniqueByCreation(
    338              syncable::AUTOFILL_PROFILE, autofill_root, profile.guid())) {
    339       LOG(ERROR) << "Failed to create autofill sync node.";
    340       return false;
    341     }
    342     node.SetTitle(UTF8ToWide(profile.guid()));
    343     VLOG(2) << "[AUTOFILL MIGRATION]"
    344             << "NOT Found in sync db  "
    345             << UTF16ToUTF8(profile.GetInfo(NAME_FIRST))
    346             << UTF16ToUTF8(profile.GetInfo(NAME_LAST))
    347             << profile.guid()
    348             << " so creating a new sync node. Sync node id "
    349             << node.GetId();
    350     AutofillProfileChangeProcessor::WriteAutofillProfile(profile, &node);
    351     current_profiles->insert(profile.guid());
    352     std::string guid = profile.guid();
    353     Associate(&guid, node.GetId());
    354     number_of_profiles_created_++;
    355   }
    356   return true;
    357 }
    358 
    359 bool AutofillProfileModelAssociator::TraverseAndAssociateAllSyncNodes(
    360     sync_api::WriteTransaction* write_trans,
    361     const sync_api::ReadNode& autofill_root,
    362     DataBundle* bundle) {
    363   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    364   VLOG(1) << "[AUTOFILL MIGRATION] "
    365           << " Iterating over sync nodes of autofill profile root node";
    366 
    367   int64 sync_child_id = autofill_root.GetFirstChildId();
    368   while (sync_child_id != sync_api::kInvalidId) {
    369     ReadNode sync_child(write_trans);
    370     if (!sync_child.InitByIdLookup(sync_child_id)) {
    371       LOG(ERROR) << "Failed to fetch child node.";
    372       return false;
    373     }
    374     const sync_pb::AutofillProfileSpecifics& autofill(
    375         sync_child.GetAutofillProfileSpecifics());
    376 
    377     AddNativeProfileIfNeeded(autofill, bundle, sync_child);
    378 
    379     sync_child_id = sync_child.GetSuccessorId();
    380   }
    381   return true;
    382 }
    383 
    384 void AutofillProfileModelAssociator::AddNativeProfileIfNeeded(
    385     const sync_pb::AutofillProfileSpecifics& profile,
    386     DataBundle* bundle,
    387     const sync_api::ReadNode& node) {
    388   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    389 
    390   VLOG(2) << "[AUTOFILL MIGRATION] "
    391           << "Trying to lookup "
    392           << profile.name_first()
    393           << " "
    394           << profile.name_last()
    395           << "sync node id " << node.GetId()
    396           << " Guid " << profile.guid()
    397           << " in the web db";
    398 
    399   if (guid::IsValidGUID(profile.guid()) == false) {
    400     DCHECK(false) << "Guid in the sync db is invalid " << profile.guid();
    401     return;
    402   }
    403 
    404   if (bundle->current_profiles.find(profile.guid()) ==
    405       bundle->current_profiles.end()) {
    406     std::string guid(profile.guid());
    407     Associate(&guid, node.GetId());
    408     AutofillProfile* p = new AutofillProfile(profile.guid());
    409     OverwriteProfileWithServerData(p, profile);
    410     bundle->new_profiles.push_back(p);
    411     VLOG(2) << "[AUTOFILL MIGRATION] "
    412             << " Did not find one so creating it on web db";
    413   } else {
    414     VLOG(2) << "[AUTOFILL MIGRATION] "
    415             << " Found it on web db. Moving on ";
    416   }
    417 }
    418 
    419 bool AutofillProfileModelAssociator::SaveChangesToWebData(
    420     const DataBundle& bundle) {
    421   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    422 
    423   if (IsAbortPending())
    424     return false;
    425 
    426   for (size_t i = 0; i < bundle.new_profiles.size(); i++) {
    427     if (IsAbortPending())
    428       return false;
    429     if (!web_database_->GetAutofillTable()->AddAutofillProfile(
    430         *bundle.new_profiles[i]))
    431       return false;
    432   }
    433 
    434   for (size_t i = 0; i < bundle.updated_profiles.size(); i++) {
    435     if (IsAbortPending())
    436       return false;
    437     if (!web_database_->GetAutofillTable()->UpdateAutofillProfile(
    438         *bundle.updated_profiles[i]))
    439       return false;
    440   }
    441 
    442   for (size_t i = 0; i< bundle.profiles_to_delete.size(); ++i) {
    443     if (IsAbortPending())
    444       return false;
    445     if (!web_database_->GetAutofillTable()->RemoveAutofillProfile(
    446         bundle.profiles_to_delete[i]))
    447       return false;
    448   }
    449   return true;
    450 }
    451 
    452 bool AutofillProfileModelAssociator::InitSyncNodeFromChromeId(
    453     const std::string& node_id,
    454     sync_api::BaseNode* sync_node) {
    455   return false;
    456 }
    457 
    458 void AutofillProfileModelAssociator::Associate(
    459     const std::string* autofill,
    460     int64 sync_id) {
    461   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    462   DCHECK_NE(sync_api::kInvalidId, sync_id);
    463   DCHECK(id_map_.find(*autofill) == id_map_.end());
    464   DCHECK(id_map_inverse_.find(sync_id) == id_map_inverse_.end());
    465   id_map_[*autofill] = sync_id;
    466   id_map_inverse_[sync_id] = *autofill;
    467 }
    468 
    469 void AutofillProfileModelAssociator::Disassociate(int64 sync_id) {
    470   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    471   SyncIdToAutofillMap::iterator iter = id_map_inverse_.find(sync_id);
    472   if (iter == id_map_inverse_.end())
    473     return;
    474   CHECK(id_map_.erase(iter->second));
    475   id_map_inverse_.erase(iter);
    476 }
    477 
    478 int64 AutofillProfileModelAssociator::GetSyncIdFromChromeId(
    479     const std::string& autofill) {
    480   AutofillToSyncIdMap::const_iterator iter = id_map_.find(autofill);
    481   return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
    482 }
    483 
    484 void AutofillProfileModelAssociator::AbortAssociation() {
    485   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    486   base::AutoLock lock(abort_association_pending_lock_);
    487   abort_association_pending_ = true;
    488 }
    489 
    490 const std::string* AutofillProfileModelAssociator::GetChromeNodeFromSyncId(
    491     int64 sync_id) {
    492   SyncIdToAutofillMap::const_iterator iter = id_map_inverse_.find(sync_id);
    493   return iter == id_map_inverse_.end() ? NULL : &(iter->second);
    494 }
    495 
    496 bool AutofillProfileModelAssociator::IsAbortPending() {
    497   base::AutoLock lock(abort_association_pending_lock_);
    498   return abort_association_pending_;
    499 }
    500 
    501 AutofillProfileModelAssociator::DataBundle::DataBundle() {}
    502 
    503 AutofillProfileModelAssociator::DataBundle::~DataBundle() {
    504   STLDeleteElements(&new_profiles);
    505 }
    506 
    507 bool AutofillProfileModelAssociator::CryptoReadyIfNecessary() {
    508   // We only access the cryptographer while holding a transaction.
    509   sync_api::ReadTransaction trans(sync_service_->GetUserShare());
    510   syncable::ModelTypeSet encrypted_types;
    511   sync_service_->GetEncryptedDataTypes(&encrypted_types);
    512   return encrypted_types.count(syncable::AUTOFILL_PROFILE) == 0 ||
    513          sync_service_->IsCryptographerReady(&trans);
    514 }
    515 
    516 }  // namespace browser_sync
    517 
    518