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_model_associator.h" 6 7 #include <functional> 8 #include <vector> 9 10 #include "base/string_number_conversions.h" 11 #include "base/task.h" 12 #include "base/time.h" 13 #include "base/utf_string_conversions.h" 14 #include "chrome/browser/autofill/autofill_profile.h" 15 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/sync/engine/syncapi.h" 17 #include "chrome/browser/sync/glue/autofill_change_processor.h" 18 #include "chrome/browser/sync/glue/autofill_profile_model_associator.h" 19 #include "chrome/browser/sync/glue/do_optimistic_refresh_task.h" 20 #include "chrome/browser/sync/profile_sync_service.h" 21 #include "chrome/browser/sync/protocol/autofill_specifics.pb.h" 22 #include "chrome/browser/webdata/web_database.h" 23 #include "chrome/common/guid.h" 24 #include "content/browser/browser_thread.h" 25 #include "net/base/escape.h" 26 27 using base::TimeTicks; 28 29 namespace browser_sync { 30 31 const char kAutofillTag[] = "google_chrome_autofill"; 32 const char kAutofillEntryNamespaceTag[] = "autofill_entry|"; 33 34 struct AutofillModelAssociator::DataBundle { 35 std::set<AutofillKey> current_entries; 36 std::vector<AutofillEntry> new_entries; 37 std::set<string16> current_profiles; 38 std::vector<AutofillProfile*> updated_profiles; 39 std::vector<AutofillProfile*> new_profiles; // We own these pointers. 40 ~DataBundle() { STLDeleteElements(&new_profiles); } 41 }; 42 43 AutofillModelAssociator::AutofillModelAssociator( 44 ProfileSyncService* sync_service, 45 WebDatabase* web_database, 46 PersonalDataManager* personal_data) 47 : sync_service_(sync_service), 48 web_database_(web_database), 49 personal_data_(personal_data), 50 autofill_node_id_(sync_api::kInvalidId), 51 abort_association_pending_(false), 52 number_of_entries_created_(0) { 53 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 54 DCHECK(sync_service_); 55 DCHECK(web_database_); 56 DCHECK(personal_data_); 57 } 58 59 AutofillModelAssociator::~AutofillModelAssociator() { 60 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 61 } 62 63 bool AutofillModelAssociator::TraverseAndAssociateChromeAutofillEntries( 64 sync_api::WriteTransaction* write_trans, 65 const sync_api::ReadNode& autofill_root, 66 const std::vector<AutofillEntry>& all_entries_from_db, 67 std::set<AutofillKey>* current_entries, 68 std::vector<AutofillEntry>* new_entries) { 69 70 const std::vector<AutofillEntry>& entries = all_entries_from_db; 71 for (std::vector<AutofillEntry>::const_iterator ix = entries.begin(); 72 ix != entries.end(); ++ix) { 73 std::string tag = KeyToTag(ix->key().name(), ix->key().value()); 74 if (id_map_.find(tag) != id_map_.end()) { 75 // It seems that name/value pairs are not unique in the web database. 76 // As a result, we have to filter out duplicates here. This is probably 77 // a bug in the database. 78 continue; 79 } 80 81 sync_api::ReadNode node(write_trans); 82 if (node.InitByClientTagLookup(syncable::AUTOFILL, tag)) { 83 const sync_pb::AutofillSpecifics& autofill(node.GetAutofillSpecifics()); 84 DCHECK_EQ(tag, KeyToTag(UTF8ToUTF16(autofill.name()), 85 UTF8ToUTF16(autofill.value()))); 86 87 std::vector<base::Time> timestamps; 88 if (MergeTimestamps(autofill, ix->timestamps(), ×tamps)) { 89 AutofillEntry new_entry(ix->key(), timestamps); 90 new_entries->push_back(new_entry); 91 92 sync_api::WriteNode write_node(write_trans); 93 if (!write_node.InitByClientTagLookup(syncable::AUTOFILL, tag)) { 94 LOG(ERROR) << "Failed to write autofill sync node."; 95 return false; 96 } 97 AutofillChangeProcessor::WriteAutofillEntry(new_entry, &write_node); 98 } 99 100 Associate(&tag, node.GetId()); 101 } else { 102 sync_api::WriteNode node(write_trans); 103 if (!node.InitUniqueByCreation(syncable::AUTOFILL, 104 autofill_root, tag)) { 105 LOG(ERROR) << "Failed to create autofill sync node."; 106 return false; 107 } 108 node.SetTitle(UTF8ToWide(tag)); 109 AutofillChangeProcessor::WriteAutofillEntry(*ix, &node); 110 Associate(&tag, node.GetId()); 111 number_of_entries_created_++; 112 } 113 114 current_entries->insert(ix->key()); 115 } 116 return true; 117 } 118 119 bool AutofillModelAssociator::LoadAutofillData( 120 std::vector<AutofillEntry>* entries, 121 std::vector<AutofillProfile*>* profiles) { 122 if (IsAbortPending()) 123 return false; 124 if (!web_database_->GetAutofillTable()->GetAllAutofillEntries(entries)) 125 return false; 126 127 if (IsAbortPending()) 128 return false; 129 if (!web_database_->GetAutofillTable()->GetAutofillProfiles(profiles)) 130 return false; 131 132 return true; 133 } 134 135 bool AutofillModelAssociator::AssociateModels() { 136 VLOG(1) << "Associating Autofill Models"; 137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 138 { 139 base::AutoLock lock(abort_association_pending_lock_); 140 abort_association_pending_ = false; 141 } 142 143 // TODO(zork): Attempt to load the model association from storage. 144 std::vector<AutofillEntry> entries; 145 ScopedVector<AutofillProfile> profiles; 146 147 if (!LoadAutofillData(&entries, &profiles.get())) { 148 LOG(ERROR) << "Could not get the autofill data from WebDatabase."; 149 return false; 150 } 151 152 DataBundle bundle; 153 { 154 sync_api::WriteTransaction trans(sync_service_->GetUserShare()); 155 156 sync_api::ReadNode autofill_root(&trans); 157 if (!autofill_root.InitByTagLookup(kAutofillTag)) { 158 LOG(ERROR) << "Server did not create the top-level autofill node. We " 159 << "might be running against an out-of-date server."; 160 return false; 161 } 162 163 if (!TraverseAndAssociateChromeAutofillEntries(&trans, autofill_root, 164 entries, &bundle.current_entries, &bundle.new_entries)) { 165 return false; 166 } 167 168 if (!TraverseAndAssociateAllSyncNodes( 169 &trans, 170 autofill_root, 171 &bundle, 172 profiles.get())) { 173 return false; 174 } 175 } 176 177 // Since we're on the DB thread, we don't have to worry about updating 178 // the autofill database after closing the write transaction, since 179 // this is the only thread that writes to the database. We also don't have 180 // to worry about the sync model getting out of sync, because changes are 181 // propagated to the ChangeProcessor on this thread. 182 if (!SaveChangesToWebData(bundle)) { 183 LOG(ERROR) << "Failed to update autofill entries."; 184 return false; 185 } 186 187 if (sync_service_->GetAutofillMigrationState() != 188 syncable::MIGRATED) { 189 syncable::AutofillMigrationDebugInfo debug_info; 190 debug_info.autofill_entries_added_during_migration = 191 number_of_entries_created_; 192 sync_service_->SetAutofillMigrationDebugInfo( 193 syncable::AutofillMigrationDebugInfo::ENTRIES_ADDED, 194 debug_info); 195 } 196 197 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 198 new DoOptimisticRefreshForAutofill(personal_data_)); 199 return true; 200 } 201 202 bool AutofillModelAssociator::SaveChangesToWebData(const DataBundle& bundle) { 203 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 204 205 if (IsAbortPending()) 206 return false; 207 208 if (bundle.new_entries.size() && 209 !web_database_->GetAutofillTable()->UpdateAutofillEntries( 210 bundle.new_entries)) { 211 return false; 212 } 213 214 for (size_t i = 0; i < bundle.new_profiles.size(); i++) { 215 if (IsAbortPending()) 216 return false; 217 if (!web_database_->GetAutofillTable()->AddAutofillProfile( 218 *bundle.new_profiles[i])) 219 return false; 220 } 221 222 for (size_t i = 0; i < bundle.updated_profiles.size(); i++) { 223 if (IsAbortPending()) 224 return false; 225 if (!web_database_->GetAutofillTable()->UpdateAutofillProfile( 226 *bundle.updated_profiles[i])) 227 return false; 228 } 229 return true; 230 } 231 232 bool AutofillModelAssociator::TraverseAndAssociateAllSyncNodes( 233 sync_api::WriteTransaction* write_trans, 234 const sync_api::ReadNode& autofill_root, 235 DataBundle* bundle, 236 const std::vector<AutofillProfile*>& all_profiles_from_db) { 237 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 238 239 bool autofill_profile_not_migrated = HasNotMigratedYet(write_trans); 240 241 if (VLOG_IS_ON(2) && autofill_profile_not_migrated) { 242 VLOG(2) << "[AUTOFILL MIGRATION]" 243 << "Printing profiles from web db"; 244 245 for (std::vector<AutofillProfile*>::const_iterator ix = 246 all_profiles_from_db.begin(); ix != all_profiles_from_db.end(); ++ix) { 247 AutofillProfile* p = *ix; 248 VLOG(2) << "[AUTOFILL MIGRATION] " 249 << p->GetInfo(NAME_FIRST) 250 << p->GetInfo(NAME_LAST); 251 } 252 } 253 254 if (autofill_profile_not_migrated) { 255 VLOG(1) << "[AUTOFILL MIGRATION]" 256 << "Iterating over sync db"; 257 } 258 259 int64 sync_child_id = autofill_root.GetFirstChildId(); 260 while (sync_child_id != sync_api::kInvalidId) { 261 sync_api::ReadNode sync_child(write_trans); 262 if (!sync_child.InitByIdLookup(sync_child_id)) { 263 LOG(ERROR) << "Failed to fetch child node."; 264 return false; 265 } 266 const sync_pb::AutofillSpecifics& autofill( 267 sync_child.GetAutofillSpecifics()); 268 269 if (autofill.has_value()) { 270 AddNativeEntryIfNeeded(autofill, bundle, sync_child); 271 } else if (autofill.has_profile()) { 272 // Ignore autofill profiles if we are not upgrading. 273 if (autofill_profile_not_migrated) { 274 VLOG(2) << "[AUTOFILL MIGRATION] Looking for " 275 << autofill.profile().name_first() 276 << autofill.profile().name_last(); 277 AddNativeProfileIfNeeded( 278 autofill.profile(), 279 bundle, 280 sync_child, 281 all_profiles_from_db); 282 } 283 } else { 284 NOTREACHED() << "AutofillSpecifics has no autofill data!"; 285 } 286 287 sync_child_id = sync_child.GetSuccessorId(); 288 } 289 return true; 290 } 291 292 // Define the functor to be used as the predicate in find_if call. 293 struct CompareProfiles 294 : public std::binary_function<AutofillProfile*, AutofillProfile*, bool> { 295 bool operator() (AutofillProfile* p1, AutofillProfile* p2) const { 296 if (p1->Compare(*p2) == 0) 297 return true; 298 else 299 return false; 300 } 301 }; 302 303 AutofillProfile* AutofillModelAssociator::FindCorrespondingNodeFromWebDB( 304 const sync_pb::AutofillProfileSpecifics& profile, 305 const std::vector<AutofillProfile*>& all_profiles_from_db) { 306 static std::string guid(guid::GenerateGUID()); 307 AutofillProfile p; 308 p.set_guid(guid); 309 if (!FillProfileWithServerData(&p, profile)) { 310 // Not a big deal. We encountered an error. Just say this profile does not 311 // exist. 312 LOG(ERROR) << " Profile could not be associated"; 313 return NULL; 314 } 315 316 // Now instantiate the functor and call find_if. 317 std::vector<AutofillProfile*>::const_iterator ix = 318 std::find_if(all_profiles_from_db.begin(), 319 all_profiles_from_db.end(), 320 std::bind2nd(CompareProfiles(), &p)); 321 322 return (ix == all_profiles_from_db.end()) ? NULL : *ix; 323 } 324 325 void AutofillModelAssociator::AddNativeEntryIfNeeded( 326 const sync_pb::AutofillSpecifics& autofill, DataBundle* bundle, 327 const sync_api::ReadNode& node) { 328 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 329 AutofillKey key(UTF8ToUTF16(autofill.name()), UTF8ToUTF16(autofill.value())); 330 331 if (bundle->current_entries.find(key) == bundle->current_entries.end()) { 332 std::vector<base::Time> timestamps; 333 int timestamps_count = autofill.usage_timestamp_size(); 334 for (int c = 0; c < timestamps_count; ++c) { 335 timestamps.push_back(base::Time::FromInternalValue( 336 autofill.usage_timestamp(c))); 337 } 338 std::string tag(KeyToTag(key.name(), key.value())); 339 Associate(&tag, node.GetId()); 340 bundle->new_entries.push_back(AutofillEntry(key, timestamps)); 341 } 342 } 343 344 void AutofillModelAssociator::AddNativeProfileIfNeeded( 345 const sync_pb::AutofillProfileSpecifics& profile, 346 DataBundle* bundle, 347 const sync_api::ReadNode& node, 348 const std::vector<AutofillProfile*>& all_profiles_from_db) { 349 350 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 351 352 AutofillProfile* profile_in_web_db = FindCorrespondingNodeFromWebDB( 353 profile, all_profiles_from_db); 354 355 if (profile_in_web_db != NULL) { 356 VLOG(1) << "[AUTOFILL MIGRATION]" 357 << "Node found in web db. So associating"; 358 int64 sync_id = node.GetId(); 359 std::string guid = profile_in_web_db->guid(); 360 Associate(&guid, sync_id); 361 return; 362 } else { // Create a new node. 363 VLOG(1) << "[AUTOFILL MIGRATION]" 364 << "Node not found in web db so creating and associating"; 365 std::string guid = guid::GenerateGUID(); 366 if (guid::IsValidGUID(guid) == false) { 367 DCHECK(false) << "Guid generated is invalid " << guid; 368 return; 369 } 370 Associate(&guid, node.GetId()); 371 AutofillProfile* p = new AutofillProfile(guid); 372 FillProfileWithServerData(p, profile); 373 bundle->new_profiles.push_back(p); 374 } 375 } 376 377 bool AutofillModelAssociator::DisassociateModels() { 378 id_map_.clear(); 379 id_map_inverse_.clear(); 380 return true; 381 } 382 383 bool AutofillModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) { 384 DCHECK(has_nodes); 385 *has_nodes = false; 386 int64 autofill_sync_id; 387 if (!GetSyncIdForTaggedNode(kAutofillTag, &autofill_sync_id)) { 388 LOG(ERROR) << "Server did not create the top-level autofill node. We " 389 << "might be running against an out-of-date server."; 390 return false; 391 } 392 sync_api::ReadTransaction trans(sync_service_->GetUserShare()); 393 394 sync_api::ReadNode autofill_node(&trans); 395 if (!autofill_node.InitByIdLookup(autofill_sync_id)) { 396 LOG(ERROR) << "Server did not create the top-level autofill node. We " 397 << "might be running against an out-of-date server."; 398 return false; 399 } 400 401 // The sync model has user created nodes if the autofill folder has any 402 // children. 403 *has_nodes = sync_api::kInvalidId != autofill_node.GetFirstChildId(); 404 return true; 405 } 406 407 void AutofillModelAssociator::AbortAssociation() { 408 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 409 base::AutoLock lock(abort_association_pending_lock_); 410 abort_association_pending_ = true; 411 } 412 413 const std::string* 414 AutofillModelAssociator::GetChromeNodeFromSyncId(int64 sync_id) { 415 SyncIdToAutofillMap::const_iterator iter = id_map_inverse_.find(sync_id); 416 return iter == id_map_inverse_.end() ? NULL : &(iter->second); 417 } 418 419 bool AutofillModelAssociator::InitSyncNodeFromChromeId( 420 const std::string& node_id, 421 sync_api::BaseNode* sync_node) { 422 return false; 423 } 424 425 int64 AutofillModelAssociator::GetSyncIdFromChromeId( 426 const std::string& autofill) { 427 AutofillToSyncIdMap::const_iterator iter = id_map_.find(autofill); 428 return iter == id_map_.end() ? sync_api::kInvalidId : iter->second; 429 } 430 431 void AutofillModelAssociator::Associate( 432 const std::string* autofill, int64 sync_id) { 433 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 434 DCHECK_NE(sync_api::kInvalidId, sync_id); 435 DCHECK(id_map_.find(*autofill) == id_map_.end()); 436 DCHECK(id_map_inverse_.find(sync_id) == id_map_inverse_.end()); 437 id_map_[*autofill] = sync_id; 438 id_map_inverse_[sync_id] = *autofill; 439 } 440 441 void AutofillModelAssociator::Disassociate(int64 sync_id) { 442 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 443 SyncIdToAutofillMap::iterator iter = id_map_inverse_.find(sync_id); 444 if (iter == id_map_inverse_.end()) 445 return; 446 CHECK(id_map_.erase(iter->second)); 447 id_map_inverse_.erase(iter); 448 } 449 450 bool AutofillModelAssociator::GetSyncIdForTaggedNode(const std::string& tag, 451 int64* sync_id) { 452 sync_api::ReadTransaction trans(sync_service_->GetUserShare()); 453 sync_api::ReadNode sync_node(&trans); 454 if (!sync_node.InitByTagLookup(tag.c_str())) 455 return false; 456 *sync_id = sync_node.GetId(); 457 return true; 458 } 459 460 bool AutofillModelAssociator::IsAbortPending() { 461 base::AutoLock lock(abort_association_pending_lock_); 462 return abort_association_pending_; 463 } 464 465 // static 466 std::string AutofillModelAssociator::KeyToTag(const string16& name, 467 const string16& value) { 468 std::string ns(kAutofillEntryNamespaceTag); 469 return ns + EscapePath(UTF16ToUTF8(name)) + "|" + 470 EscapePath(UTF16ToUTF8(value)); 471 } 472 473 // static 474 bool AutofillModelAssociator::MergeTimestamps( 475 const sync_pb::AutofillSpecifics& autofill, 476 const std::vector<base::Time>& timestamps, 477 std::vector<base::Time>* new_timestamps) { 478 DCHECK(new_timestamps); 479 std::set<base::Time> timestamp_union(timestamps.begin(), 480 timestamps.end()); 481 482 size_t timestamps_count = autofill.usage_timestamp_size(); 483 484 bool different = timestamps.size() != timestamps_count; 485 for (size_t c = 0; c < timestamps_count; ++c) { 486 if (timestamp_union.insert(base::Time::FromInternalValue( 487 autofill.usage_timestamp(c))).second) { 488 different = true; 489 } 490 } 491 492 if (different) { 493 new_timestamps->insert(new_timestamps->begin(), 494 timestamp_union.begin(), 495 timestamp_union.end()); 496 } 497 return different; 498 } 499 500 // Helper to compare the local value and cloud value of a field, merge into 501 // the local value if they differ, and return whether the merge happened. 502 bool MergeField(FormGroup* f, AutofillFieldType t, 503 const std::string& specifics_field) { 504 if (UTF16ToUTF8(f->GetInfo(t)) == specifics_field) 505 return false; 506 f->SetInfo(t, UTF8ToUTF16(specifics_field)); 507 return true; 508 } 509 510 // static 511 bool AutofillModelAssociator::FillProfileWithServerData( 512 AutofillProfile* merge_into, 513 const sync_pb::AutofillProfileSpecifics& specifics) { 514 bool diff = false; 515 AutofillProfile* p = merge_into; 516 const sync_pb::AutofillProfileSpecifics& s(specifics); 517 diff = MergeField(p, NAME_FIRST, s.name_first()) || diff; 518 diff = MergeField(p, NAME_LAST, s.name_last()) || diff; 519 diff = MergeField(p, NAME_MIDDLE, s.name_middle()) || diff; 520 diff = MergeField(p, ADDRESS_HOME_LINE1, s.address_home_line1()) || diff; 521 diff = MergeField(p, ADDRESS_HOME_LINE2, s.address_home_line2()) || diff; 522 diff = MergeField(p, ADDRESS_HOME_CITY, s.address_home_city()) || diff; 523 diff = MergeField(p, ADDRESS_HOME_STATE, s.address_home_state()) || diff; 524 diff = MergeField(p, ADDRESS_HOME_COUNTRY, s.address_home_country()) || diff; 525 diff = MergeField(p, ADDRESS_HOME_ZIP, s.address_home_zip()) || diff; 526 diff = MergeField(p, EMAIL_ADDRESS, s.email_address()) || diff; 527 diff = MergeField(p, COMPANY_NAME, s.company_name()) || diff; 528 diff = MergeField(p, PHONE_FAX_WHOLE_NUMBER, s.phone_fax_whole_number()) 529 || diff; 530 diff = MergeField(p, PHONE_HOME_WHOLE_NUMBER, s.phone_home_whole_number()) 531 || diff; 532 return diff; 533 } 534 535 bool AutofillModelAssociator::HasNotMigratedYet( 536 const sync_api::BaseTransaction* trans) { 537 538 // Now read the current value from the directory. 539 syncable::AutofillMigrationState autofill_migration_state = 540 sync_service_->GetAutofillMigrationState(); 541 542 DCHECK_NE(autofill_migration_state, syncable::NOT_DETERMINED); 543 544 if (autofill_migration_state== syncable::NOT_DETERMINED) { 545 VLOG(1) << "Autofill migration state is not determined inside " 546 << " model associator"; 547 } 548 549 if (autofill_migration_state == syncable::NOT_MIGRATED) { 550 return true; 551 } 552 553 if (autofill_migration_state == syncable::INSUFFICIENT_INFO_TO_DETERMINE) { 554 VLOG(1) << "[AUTOFILL MIGRATION]" 555 << "current autofill migration state is insufficient info to" 556 << "determine."; 557 sync_api::ReadNode autofill_profile_root_node(trans); 558 if (!autofill_profile_root_node.InitByTagLookup( 559 browser_sync::kAutofillProfileTag) || 560 autofill_profile_root_node.GetFirstChildId()== 561 static_cast<int64>(0)) { 562 sync_service_->SetAutofillMigrationState( 563 syncable::NOT_MIGRATED); 564 565 VLOG(1) << "[AUTOFILL MIGRATION]" 566 << "Current autofill migration state is NOT Migrated because" 567 << "legacy autofill root node is present whereas new " 568 << "Autofill profile root node is absent."; 569 return true; 570 } 571 572 sync_service_->SetAutofillMigrationState(syncable::MIGRATED); 573 574 VLOG(1) << "[AUTOFILL MIGRATION]" 575 << "Current autofill migration state is migrated."; 576 } 577 578 return false; 579 } 580 581 bool AutofillModelAssociator::CryptoReadyIfNecessary() { 582 // We only access the cryptographer while holding a transaction. 583 sync_api::ReadTransaction trans(sync_service_->GetUserShare()); 584 syncable::ModelTypeSet encrypted_types; 585 sync_service_->GetEncryptedDataTypes(&encrypted_types); 586 return encrypted_types.count(syncable::AUTOFILL) == 0 || 587 sync_service_->IsCryptographerReady(&trans); 588 } 589 590 } // namespace browser_sync 591