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