1 // Copyright 2014 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 "components/password_manager/core/browser/password_syncable_service.h" 6 7 #include "base/auto_reset.h" 8 #include "base/location.h" 9 #include "base/memory/scoped_vector.h" 10 #include "base/metrics/histogram.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "components/autofill/core/common/password_form.h" 13 #include "components/password_manager/core/browser/password_store_sync.h" 14 #include "net/base/escape.h" 15 #include "sync/api/sync_error_factory.h" 16 17 namespace password_manager { 18 19 namespace { 20 21 // Describes the result of merging sync and local passwords. 22 enum MergeResult { 23 IDENTICAL, 24 SYNC, 25 LOCAL, 26 }; 27 28 // Merges the local and sync passwords and outputs the entry into 29 // |new_password_form|. Returns MergeResult value describing the content of 30 // |new_password_form|. 31 MergeResult MergeLocalAndSyncPasswords( 32 const sync_pb::PasswordSpecificsData& password_specifics, 33 const autofill::PasswordForm& password_form, 34 autofill::PasswordForm* new_password_form) { 35 DCHECK(new_password_form); 36 if (password_form.scheme == password_specifics.scheme() && 37 password_form.signon_realm == password_specifics.signon_realm() && 38 password_form.origin.spec() == password_specifics.origin() && 39 password_form.action.spec() == password_specifics.action() && 40 base::UTF16ToUTF8(password_form.username_element) == 41 password_specifics.username_element() && 42 base::UTF16ToUTF8(password_form.password_element) == 43 password_specifics.password_element() && 44 base::UTF16ToUTF8(password_form.username_value) == 45 password_specifics.username_value() && 46 base::UTF16ToUTF8(password_form.password_value) == 47 password_specifics.password_value() && 48 password_form.ssl_valid == password_specifics.ssl_valid() && 49 password_form.preferred == password_specifics.preferred() && 50 password_form.date_created.ToInternalValue() == 51 password_specifics.date_created() && 52 password_form.blacklisted_by_user == password_specifics.blacklisted() && 53 password_form.type == password_specifics.type() && 54 password_form.times_used == password_specifics.times_used()) { 55 return IDENTICAL; 56 } 57 58 // If the passwords differ, take the one that was created more recently. 59 if (base::Time::FromInternalValue(password_specifics.date_created()) < 60 password_form.date_created) { 61 *new_password_form = password_form; 62 return LOCAL; 63 } 64 65 PasswordFromSpecifics(password_specifics, new_password_form); 66 return SYNC; 67 } 68 69 std::string MakePasswordSyncTag(const std::string& origin_url, 70 const std::string& username_element, 71 const std::string& username_value, 72 const std::string& password_element, 73 const std::string& signon_realm) { 74 return net::EscapePath(origin_url) + "|" + 75 net::EscapePath(username_element) + "|" + 76 net::EscapePath(username_value) + "|" + 77 net::EscapePath(password_element) + "|" + 78 net::EscapePath(signon_realm); 79 } 80 81 std::string MakePasswordSyncTag(const autofill::PasswordForm& password) { 82 return MakePasswordSyncTag(password.origin.spec(), 83 base::UTF16ToUTF8(password.username_element), 84 base::UTF16ToUTF8(password.username_value), 85 base::UTF16ToUTF8(password.password_element), 86 password.signon_realm); 87 } 88 89 syncer::SyncChange::SyncChangeType GetSyncChangeType( 90 PasswordStoreChange::Type type) { 91 switch (type) { 92 case PasswordStoreChange::ADD: 93 return syncer::SyncChange::ACTION_ADD; 94 case PasswordStoreChange::UPDATE: 95 return syncer::SyncChange::ACTION_UPDATE; 96 case PasswordStoreChange::REMOVE: 97 return syncer::SyncChange::ACTION_DELETE; 98 } 99 NOTREACHED(); 100 return syncer::SyncChange::ACTION_INVALID; 101 } 102 103 void AppendChanges(const PasswordStoreChangeList& new_changes, 104 PasswordStoreChangeList* all_changes) { 105 all_changes->insert(all_changes->end(), 106 new_changes.begin(), 107 new_changes.end()); 108 } 109 110 } // namespace 111 112 PasswordSyncableService::PasswordSyncableService( 113 PasswordStoreSync* password_store) 114 : password_store_(password_store), 115 is_processing_sync_changes_(false) { 116 } 117 118 PasswordSyncableService::~PasswordSyncableService() {} 119 120 syncer::SyncMergeResult PasswordSyncableService::MergeDataAndStartSyncing( 121 syncer::ModelType type, 122 const syncer::SyncDataList& initial_sync_data, 123 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, 124 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { 125 DCHECK(CalledOnValidThread()); 126 DCHECK_EQ(syncer::PASSWORDS, type); 127 base::AutoReset<bool> processing_changes(&is_processing_sync_changes_, true); 128 syncer::SyncMergeResult merge_result(type); 129 sync_error_factory_ = sync_error_factory.Pass(); 130 sync_processor_ = sync_processor.Pass(); 131 132 // We add all the db entries as |new_local_entries| initially. During model 133 // association entries that match a sync entry will be removed and this list 134 // will only contain entries that are not in sync. 135 ScopedVector<autofill::PasswordForm> password_entries; 136 PasswordEntryMap new_local_entries; 137 if (!ReadFromPasswordStore(&password_entries, &new_local_entries)) { 138 DCHECK(sync_error_factory_); 139 merge_result.set_error(sync_error_factory_->CreateAndUploadError( 140 FROM_HERE, 141 "Failed to get passwords from store.")); 142 return merge_result; 143 } 144 145 merge_result.set_num_items_before_association(new_local_entries.size()); 146 147 // List that contains the entries that are known only to sync. 148 ScopedVector<autofill::PasswordForm> new_sync_entries; 149 150 // List that contains the entries that are known to both sync and db but 151 // have updates in sync. They need to be updated in the passwords db. 152 ScopedVector<autofill::PasswordForm> updated_sync_entries; 153 154 // Changes from password db that need to be propagated to sync. 155 syncer::SyncChangeList updated_db_entries; 156 for (syncer::SyncDataList::const_iterator sync_iter = 157 initial_sync_data.begin(); 158 sync_iter != initial_sync_data.end(); ++sync_iter) { 159 CreateOrUpdateEntry(*sync_iter, 160 &new_local_entries, 161 &new_sync_entries, 162 &updated_sync_entries, 163 &updated_db_entries); 164 } 165 166 WriteToPasswordStore(new_sync_entries.get(), 167 updated_sync_entries.get(), 168 PasswordForms()); 169 170 merge_result.set_num_items_after_association( 171 merge_result.num_items_before_association() + new_sync_entries.size()); 172 173 merge_result.set_num_items_added(new_sync_entries.size()); 174 175 merge_result.set_num_items_modified(updated_sync_entries.size()); 176 177 for (PasswordEntryMap::iterator it = new_local_entries.begin(); 178 it != new_local_entries.end(); 179 ++it) { 180 updated_db_entries.push_back( 181 syncer::SyncChange(FROM_HERE, 182 syncer::SyncChange::ACTION_ADD, 183 SyncDataFromPassword(*it->second))); 184 } 185 186 merge_result.set_error( 187 sync_processor_->ProcessSyncChanges(FROM_HERE, updated_db_entries)); 188 return merge_result; 189 } 190 191 void PasswordSyncableService::StopSyncing(syncer::ModelType type) { 192 DCHECK(CalledOnValidThread()); 193 DCHECK_EQ(syncer::PASSWORDS, type); 194 195 sync_processor_.reset(); 196 sync_error_factory_.reset(); 197 } 198 199 syncer::SyncDataList PasswordSyncableService::GetAllSyncData( 200 syncer::ModelType type) const { 201 DCHECK(CalledOnValidThread()); 202 DCHECK_EQ(syncer::PASSWORDS, type); 203 ScopedVector<autofill::PasswordForm> password_entries; 204 ReadFromPasswordStore(&password_entries, NULL); 205 206 syncer::SyncDataList sync_data; 207 for (PasswordForms::iterator it = password_entries.begin(); 208 it != password_entries.end(); ++it) { 209 sync_data.push_back(SyncDataFromPassword(**it)); 210 } 211 return sync_data; 212 } 213 214 syncer::SyncError PasswordSyncableService::ProcessSyncChanges( 215 const tracked_objects::Location& from_here, 216 const syncer::SyncChangeList& change_list) { 217 DCHECK(CalledOnValidThread()); 218 base::AutoReset<bool> processing_changes(&is_processing_sync_changes_, true); 219 // The |db_entries_map| and associated vectors are filled only in case of 220 // update change. 221 ScopedVector<autofill::PasswordForm> new_sync_entries; 222 ScopedVector<autofill::PasswordForm> updated_sync_entries; 223 ScopedVector<autofill::PasswordForm> deleted_entries; 224 base::Time time_now = base::Time::Now(); 225 226 for (syncer::SyncChangeList::const_iterator it = change_list.begin(); 227 it != change_list.end(); 228 ++it) { 229 const sync_pb::EntitySpecifics& specifics = it->sync_data().GetSpecifics(); 230 scoped_ptr<autofill::PasswordForm> form(new autofill::PasswordForm); 231 PasswordFromSpecifics(specifics.password().client_only_encrypted_data(), 232 form.get()); 233 switch (it->change_type()) { 234 case syncer::SyncChange::ACTION_ADD: { 235 form->date_synced = time_now; 236 new_sync_entries.push_back(form.release()); 237 break; 238 } 239 case syncer::SyncChange::ACTION_UPDATE: { 240 form->date_synced = time_now; 241 updated_sync_entries.push_back(form.release()); 242 break; 243 } 244 245 case syncer::SyncChange::ACTION_DELETE: { 246 deleted_entries.push_back(form.release()); 247 break; 248 } 249 case syncer::SyncChange::ACTION_INVALID: 250 return sync_error_factory_->CreateAndUploadError( 251 FROM_HERE, 252 "Failed to process sync changes for passwords datatype."); 253 } 254 } 255 WriteToPasswordStore(new_sync_entries.get(), 256 updated_sync_entries.get(), 257 deleted_entries.get()); 258 return syncer::SyncError(); 259 } 260 261 void PasswordSyncableService::ActOnPasswordStoreChanges( 262 const PasswordStoreChangeList& local_changes) { 263 DCHECK(CalledOnValidThread()); 264 265 if (!sync_processor_) { 266 if (!flare_.is_null()) { 267 flare_.Run(syncer::PASSWORDS); 268 flare_.Reset(); 269 } 270 return; 271 } 272 273 // ActOnPasswordStoreChanges() can be called from ProcessSyncChanges(). Do 274 // nothing in this case. 275 if (is_processing_sync_changes_) 276 return; 277 syncer::SyncChangeList sync_changes; 278 for (PasswordStoreChangeList::const_iterator it = local_changes.begin(); 279 it != local_changes.end(); 280 ++it) { 281 syncer::SyncData data = (it->type() == PasswordStoreChange::REMOVE ? 282 syncer::SyncData::CreateLocalDelete(MakePasswordSyncTag(it->form()), 283 syncer::PASSWORDS) : 284 SyncDataFromPassword(it->form())); 285 sync_changes.push_back( 286 syncer::SyncChange(FROM_HERE, GetSyncChangeType(it->type()), data)); 287 } 288 sync_processor_->ProcessSyncChanges(FROM_HERE, sync_changes); 289 } 290 291 void PasswordSyncableService::InjectStartSyncFlare( 292 const syncer::SyncableService::StartSyncFlare& flare) { 293 DCHECK(CalledOnValidThread()); 294 flare_ = flare; 295 } 296 297 bool PasswordSyncableService::ReadFromPasswordStore( 298 ScopedVector<autofill::PasswordForm>* password_entries, 299 PasswordEntryMap* passwords_entry_map) const { 300 DCHECK(password_entries); 301 if (!password_store_->FillAutofillableLogins(&password_entries->get()) || 302 !password_store_->FillBlacklistLogins(&password_entries->get())) { 303 // Password store often fails to load passwords. Track failures with UMA. 304 // (http://crbug.com/249000) 305 UMA_HISTOGRAM_ENUMERATION("Sync.LocalDataFailedToLoad", 306 ModelTypeToHistogramInt(syncer::PASSWORDS), 307 syncer::MODEL_TYPE_COUNT); 308 return false; 309 } 310 311 if (!passwords_entry_map) 312 return true; 313 314 for (PasswordForms::iterator it = password_entries->begin(); 315 it != password_entries->end(); ++it) { 316 autofill::PasswordForm* password_form = *it; 317 passwords_entry_map->insert( 318 std::make_pair(MakePasswordSyncTag(*password_form), password_form)); 319 } 320 321 return true; 322 } 323 324 void PasswordSyncableService::WriteToPasswordStore( 325 const PasswordForms& new_entries, 326 const PasswordForms& updated_entries, 327 const PasswordForms& deleted_entries) { 328 PasswordStoreChangeList changes; 329 for (std::vector<autofill::PasswordForm*>::const_iterator it = 330 new_entries.begin(); 331 it != new_entries.end(); 332 ++it) { 333 AppendChanges(password_store_->AddLoginImpl(**it), &changes); 334 } 335 336 for (std::vector<autofill::PasswordForm*>::const_iterator it = 337 updated_entries.begin(); 338 it != updated_entries.end(); 339 ++it) { 340 AppendChanges(password_store_->UpdateLoginImpl(**it), &changes); 341 } 342 343 for (std::vector<autofill::PasswordForm*>::const_iterator it = 344 deleted_entries.begin(); 345 it != deleted_entries.end(); 346 ++it) { 347 AppendChanges(password_store_->RemoveLoginImpl(**it), &changes); 348 } 349 350 // We have to notify password store observers of the change by hand since 351 // we use internal password store interfaces to make changes synchronously. 352 NotifyPasswordStoreOfLoginChanges(changes); 353 } 354 355 void PasswordSyncableService::NotifyPasswordStoreOfLoginChanges( 356 const PasswordStoreChangeList& changes) { 357 password_store_->NotifyLoginsChanged(changes); 358 } 359 360 void PasswordSyncableService::CreateOrUpdateEntry( 361 const syncer::SyncData& data, 362 PasswordEntryMap* umatched_data_from_password_db, 363 ScopedVector<autofill::PasswordForm>* new_sync_entries, 364 ScopedVector<autofill::PasswordForm>* updated_sync_entries, 365 syncer::SyncChangeList* updated_db_entries) { 366 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics(); 367 const sync_pb::PasswordSpecificsData& password_specifics( 368 specifics.password().client_only_encrypted_data()); 369 std::string tag = MakePasswordSyncTag(password_specifics); 370 371 // Check whether the data from sync is already in the password store. 372 PasswordEntryMap::iterator existing_local_entry_iter = 373 umatched_data_from_password_db->find(tag); 374 base::Time time_now = base::Time::Now(); 375 if (existing_local_entry_iter == umatched_data_from_password_db->end()) { 376 // The sync data is not in the password store, so we need to create it in 377 // the password store. Add the entry to the new_entries list. 378 scoped_ptr<autofill::PasswordForm> new_password(new autofill::PasswordForm); 379 new_password->date_synced = time_now; 380 PasswordFromSpecifics(password_specifics, new_password.get()); 381 new_sync_entries->push_back(new_password.release()); 382 } else { 383 // The entry is in password store. If the entries are not identical, then 384 // the entries need to be merged. 385 scoped_ptr<autofill::PasswordForm> new_password(new autofill::PasswordForm); 386 switch (MergeLocalAndSyncPasswords(password_specifics, 387 *existing_local_entry_iter->second, 388 new_password.get())) { 389 case IDENTICAL: 390 break; 391 case SYNC: 392 new_password->date_synced = time_now; 393 updated_sync_entries->push_back(new_password.release()); 394 break; 395 case LOCAL: 396 updated_db_entries->push_back( 397 syncer::SyncChange(FROM_HERE, 398 syncer::SyncChange::ACTION_UPDATE, 399 SyncDataFromPassword(*new_password))); 400 break; 401 } 402 // Remove the entry from the entry map to indicate a match has been found. 403 // Entries that remain in the map at the end of associating all sync entries 404 // will be treated as additions that need to be propagated to sync. 405 umatched_data_from_password_db->erase(existing_local_entry_iter); 406 } 407 } 408 409 syncer::SyncData SyncDataFromPassword( 410 const autofill::PasswordForm& password_form) { 411 sync_pb::EntitySpecifics password_data; 412 sync_pb::PasswordSpecificsData* password_specifics = 413 password_data.mutable_password()->mutable_client_only_encrypted_data(); 414 password_specifics->set_scheme(password_form.scheme); 415 password_specifics->set_signon_realm(password_form.signon_realm); 416 password_specifics->set_origin(password_form.origin.spec()); 417 password_specifics->set_action(password_form.action.spec()); 418 password_specifics->set_username_element( 419 base::UTF16ToUTF8(password_form.username_element)); 420 password_specifics->set_password_element( 421 base::UTF16ToUTF8(password_form.password_element)); 422 password_specifics->set_username_value( 423 base::UTF16ToUTF8(password_form.username_value)); 424 password_specifics->set_password_value( 425 base::UTF16ToUTF8(password_form.password_value)); 426 password_specifics->set_ssl_valid(password_form.ssl_valid); 427 password_specifics->set_preferred(password_form.preferred); 428 password_specifics->set_date_created( 429 password_form.date_created.ToInternalValue()); 430 password_specifics->set_blacklisted(password_form.blacklisted_by_user); 431 password_specifics->set_type(password_form.type); 432 password_specifics->set_times_used(password_form.times_used); 433 434 std::string tag = MakePasswordSyncTag(*password_specifics); 435 return syncer::SyncData::CreateLocalData(tag, tag, password_data); 436 } 437 438 void PasswordFromSpecifics(const sync_pb::PasswordSpecificsData& password, 439 autofill::PasswordForm* new_password) { 440 new_password->scheme = 441 static_cast<autofill::PasswordForm::Scheme>(password.scheme()); 442 new_password->signon_realm = password.signon_realm(); 443 new_password->origin = GURL(password.origin()); 444 new_password->action = GURL(password.action()); 445 new_password->username_element = 446 base::UTF8ToUTF16(password.username_element()); 447 new_password->password_element = 448 base::UTF8ToUTF16(password.password_element()); 449 new_password->username_value = base::UTF8ToUTF16(password.username_value()); 450 new_password->password_value = base::UTF8ToUTF16(password.password_value()); 451 new_password->ssl_valid = password.ssl_valid(); 452 new_password->preferred = password.preferred(); 453 new_password->date_created = 454 base::Time::FromInternalValue(password.date_created()); 455 new_password->blacklisted_by_user = password.blacklisted(); 456 new_password->type = 457 static_cast<autofill::PasswordForm::Type>(password.type()); 458 new_password->times_used = password.times_used(); 459 } 460 461 std::string MakePasswordSyncTag( 462 const sync_pb::PasswordSpecificsData& password) { 463 return MakePasswordSyncTag(password.origin(), 464 password.username_element(), 465 password.username_value(), 466 password.password_element(), 467 password.signon_realm()); 468 } 469 470 } // namespace password_manager 471