• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AutofillProfileModelAssociator(ProfileSyncService * sync_service,WebDatabase * web_database,PersonalDataManager * personal_data)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 
~AutofillProfileModelAssociator()35 AutofillProfileModelAssociator::~AutofillProfileModelAssociator() {
36   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
37 }
38 
AutofillProfileModelAssociator()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 
TraverseAndAssociateChromeAutofillProfiles(sync_api::WriteTransaction * write_trans,const sync_api::ReadNode & autofill_root,const std::vector<AutofillProfile * > & all_profiles_from_db,std::set<std::string> * current_profiles,std::vector<AutofillProfile * > * updated_profiles,std::vector<AutofillProfile * > * new_profiles,std::vector<std::string> * profiles_to_delete)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 
GetSyncIdForTaggedNode(const std::string & tag,int64 * sync_id)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 
LoadAutofillData(std::vector<AutofillProfile * > * profiles)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 
AssociateModels()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 
DisassociateModels()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.
MergeField(FormGroup * f,AutofillFieldType t,const std::string & specifics_field)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 }
SyncModelHasUserCreatedNodes(bool * has_nodes)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
OverwriteProfileWithServerData(AutofillProfile * merge_into,const sync_pb::AutofillProfileSpecifics & specifics)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 
FindSyncNodeWithProfile(sync_api::WriteTransaction * trans,const sync_api::BaseNode & autofill_root,const AutofillProfile & profile_from_db,std::set<std::string> * current_profiles)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 }
MakeNewAutofillProfileSyncNodeIfNeeded(sync_api::WriteTransaction * trans,const sync_api::BaseNode & autofill_root,const AutofillProfile & profile,std::vector<AutofillProfile * > * new_profiles,std::set<std::string> * current_profiles,std::vector<std::string> * profiles_to_delete)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 
TraverseAndAssociateAllSyncNodes(sync_api::WriteTransaction * write_trans,const sync_api::ReadNode & autofill_root,DataBundle * bundle)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 
AddNativeProfileIfNeeded(const sync_pb::AutofillProfileSpecifics & profile,DataBundle * bundle,const sync_api::ReadNode & node)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 
SaveChangesToWebData(const DataBundle & bundle)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 
InitSyncNodeFromChromeId(const std::string & node_id,sync_api::BaseNode * sync_node)452 bool AutofillProfileModelAssociator::InitSyncNodeFromChromeId(
453     const std::string& node_id,
454     sync_api::BaseNode* sync_node) {
455   return false;
456 }
457 
Associate(const std::string * autofill,int64 sync_id)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 
Disassociate(int64 sync_id)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 
GetSyncIdFromChromeId(const std::string & autofill)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 
AbortAssociation()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 
GetChromeNodeFromSyncId(int64 sync_id)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 
IsAbortPending()496 bool AutofillProfileModelAssociator::IsAbortPending() {
497   base::AutoLock lock(abort_association_pending_lock_);
498   return abort_association_pending_;
499 }
500 
DataBundle()501 AutofillProfileModelAssociator::DataBundle::DataBundle() {}
502 
~DataBundle()503 AutofillProfileModelAssociator::DataBundle::~DataBundle() {
504   STLDeleteElements(&new_profiles);
505 }
506 
CryptoReadyIfNecessary()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