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