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.
5 #include "components/password_manager/core/browser/password_syncable_service.h"
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"
17 namespace password_manager {
21 // Describes the result of merging sync and local passwords.
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()) {
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;
65 PasswordFromSpecifics(password_specifics, new_password_form);
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);
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);
89 syncer::SyncChange::SyncChangeType GetSyncChangeType(
90 PasswordStoreChange::Type 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;
100 return syncer::SyncChange::ACTION_INVALID;
103 void AppendChanges(const PasswordStoreChangeList& new_changes,
104 PasswordStoreChangeList* all_changes) {
105 all_changes->insert(all_changes->end(),
112 PasswordSyncableService::PasswordSyncableService(
113 PasswordStoreSync* password_store)
114 : password_store_(password_store),
115 is_processing_sync_changes_(false) {
118 PasswordSyncableService::~PasswordSyncableService() {}
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();
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(
141 "Failed to get passwords from store."));
145 merge_result.set_num_items_before_association(new_local_entries.size());
147 // List that contains the entries that are known only to sync.
148 ScopedVector<autofill::PasswordForm> new_sync_entries;
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;
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,
162 &updated_sync_entries,
163 &updated_db_entries);
166 WriteToPasswordStore(new_sync_entries.get(),
167 updated_sync_entries.get(),
170 merge_result.set_num_items_after_association(
171 merge_result.num_items_before_association() + new_sync_entries.size());
173 merge_result.set_num_items_added(new_sync_entries.size());
175 merge_result.set_num_items_modified(updated_sync_entries.size());
177 for (PasswordEntryMap::iterator it = new_local_entries.begin();
178 it != new_local_entries.end();
180 updated_db_entries.push_back(
181 syncer::SyncChange(FROM_HERE,
182 syncer::SyncChange::ACTION_ADD,
183 SyncDataFromPassword(*it->second)));
186 merge_result.set_error(
187 sync_processor_->ProcessSyncChanges(FROM_HERE, updated_db_entries));
191 void PasswordSyncableService::StopSyncing(syncer::ModelType type) {
192 DCHECK(CalledOnValidThread());
193 DCHECK_EQ(syncer::PASSWORDS, type);
195 sync_processor_.reset();
196 sync_error_factory_.reset();
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);
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));
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
221 ScopedVector<autofill::PasswordForm> new_sync_entries;
222 ScopedVector<autofill::PasswordForm> updated_sync_entries;
223 ScopedVector<autofill::PasswordForm> deleted_entries;
225 for (syncer::SyncChangeList::const_iterator it = change_list.begin();
226 it != change_list.end();
228 const sync_pb::EntitySpecifics& specifics = it->sync_data().GetSpecifics();
229 scoped_ptr<autofill::PasswordForm> form(new autofill::PasswordForm);
230 PasswordFromSpecifics(specifics.password().client_only_encrypted_data(),
232 switch (it->change_type()) {
233 case syncer::SyncChange::ACTION_ADD: {
234 new_sync_entries.push_back(form.release());
237 case syncer::SyncChange::ACTION_UPDATE: {
238 updated_sync_entries.push_back(form.release());
242 case syncer::SyncChange::ACTION_DELETE: {
243 deleted_entries.push_back(form.release());
246 case syncer::SyncChange::ACTION_INVALID:
247 return sync_error_factory_->CreateAndUploadError(
249 "Failed to process sync changes for passwords datatype.");
252 WriteToPasswordStore(new_sync_entries.get(),
253 updated_sync_entries.get(),
254 deleted_entries.get());
255 return syncer::SyncError();
258 void PasswordSyncableService::ActOnPasswordStoreChanges(
259 const PasswordStoreChangeList& local_changes) {
260 DCHECK(CalledOnValidThread());
262 if (!sync_processor_) {
263 if (!flare_.is_null()) {
264 flare_.Run(syncer::PASSWORDS);
270 // ActOnPasswordStoreChanges() can be called from ProcessSyncChanges(). Do
271 // nothing in this case.
272 if (is_processing_sync_changes_)
274 syncer::SyncChangeList sync_changes;
275 for (PasswordStoreChangeList::const_iterator it = local_changes.begin();
276 it != local_changes.end();
278 sync_changes.push_back(
279 syncer::SyncChange(FROM_HERE,
280 GetSyncChangeType(it->type()),
281 SyncDataFromPassword(it->form())));
283 sync_processor_->ProcessSyncChanges(FROM_HERE, sync_changes);
286 void PasswordSyncableService::InjectStartSyncFlare(
287 const syncer::SyncableService::StartSyncFlare& flare) {
288 DCHECK(CalledOnValidThread());
292 bool PasswordSyncableService::ReadFromPasswordStore(
293 ScopedVector<autofill::PasswordForm>* password_entries,
294 PasswordEntryMap* passwords_entry_map) const {
295 DCHECK(password_entries);
296 if (!password_store_->FillAutofillableLogins(&password_entries->get()) ||
297 !password_store_->FillBlacklistLogins(&password_entries->get())) {
298 // Password store often fails to load passwords. Track failures with UMA.
299 // (http://crbug.com/249000)
300 UMA_HISTOGRAM_ENUMERATION("Sync.LocalDataFailedToLoad",
301 ModelTypeToHistogramInt(syncer::PASSWORDS),
302 syncer::MODEL_TYPE_COUNT);
306 if (!passwords_entry_map)
309 for (PasswordForms::iterator it = password_entries->begin();
310 it != password_entries->end(); ++it) {
311 autofill::PasswordForm* password_form = *it;
312 passwords_entry_map->insert(
313 std::make_pair(MakePasswordSyncTag(*password_form), password_form));
319 void PasswordSyncableService::WriteToPasswordStore(
320 const PasswordForms& new_entries,
321 const PasswordForms& updated_entries,
322 const PasswordForms& deleted_entries) {
323 PasswordStoreChangeList changes;
324 for (std::vector<autofill::PasswordForm*>::const_iterator it =
326 it != new_entries.end();
328 AppendChanges(password_store_->AddLoginImpl(**it), &changes);
331 for (std::vector<autofill::PasswordForm*>::const_iterator it =
332 updated_entries.begin();
333 it != updated_entries.end();
335 AppendChanges(password_store_->UpdateLoginImpl(**it), &changes);
338 for (std::vector<autofill::PasswordForm*>::const_iterator it =
339 deleted_entries.begin();
340 it != deleted_entries.end();
342 AppendChanges(password_store_->RemoveLoginImpl(**it), &changes);
345 // We have to notify password store observers of the change by hand since
346 // we use internal password store interfaces to make changes synchronously.
347 NotifyPasswordStoreOfLoginChanges(changes);
350 void PasswordSyncableService::NotifyPasswordStoreOfLoginChanges(
351 const PasswordStoreChangeList& changes) {
352 password_store_->NotifyLoginsChanged(changes);
355 void PasswordSyncableService::CreateOrUpdateEntry(
356 const syncer::SyncData& data,
357 PasswordEntryMap* umatched_data_from_password_db,
358 ScopedVector<autofill::PasswordForm>* new_sync_entries,
359 ScopedVector<autofill::PasswordForm>* updated_sync_entries,
360 syncer::SyncChangeList* updated_db_entries) {
361 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics();
362 const sync_pb::PasswordSpecificsData& password_specifics(
363 specifics.password().client_only_encrypted_data());
364 std::string tag = MakePasswordSyncTag(password_specifics);
366 // Check whether the data from sync is already in the password store.
367 PasswordEntryMap::iterator existing_local_entry_iter =
368 umatched_data_from_password_db->find(tag);
369 if (existing_local_entry_iter == umatched_data_from_password_db->end()) {
370 // The sync data is not in the password store, so we need to create it in
371 // the password store. Add the entry to the new_entries list.
372 scoped_ptr<autofill::PasswordForm> new_password(new autofill::PasswordForm);
373 PasswordFromSpecifics(password_specifics, new_password.get());
374 new_sync_entries->push_back(new_password.release());
376 // The entry is in password store. If the entries are not identical, then
377 // the entries need to be merged.
378 scoped_ptr<autofill::PasswordForm> new_password(new autofill::PasswordForm);
379 switch (MergeLocalAndSyncPasswords(password_specifics,
380 *existing_local_entry_iter->second,
381 new_password.get())) {
385 updated_sync_entries->push_back(new_password.release());
388 updated_db_entries->push_back(
389 syncer::SyncChange(FROM_HERE,
390 syncer::SyncChange::ACTION_UPDATE,
391 SyncDataFromPassword(*new_password)));
394 // Remove the entry from the entry map to indicate a match has been found.
395 // Entries that remain in the map at the end of associating all sync entries
396 // will be treated as additions that need to be propagated to sync.
397 umatched_data_from_password_db->erase(existing_local_entry_iter);
401 syncer::SyncData SyncDataFromPassword(
402 const autofill::PasswordForm& password_form) {
403 sync_pb::EntitySpecifics password_data;
404 sync_pb::PasswordSpecificsData* password_specifics =
405 password_data.mutable_password()->mutable_client_only_encrypted_data();
406 password_specifics->set_scheme(password_form.scheme);
407 password_specifics->set_signon_realm(password_form.signon_realm);
408 password_specifics->set_origin(password_form.origin.spec());
409 password_specifics->set_action(password_form.action.spec());
410 password_specifics->set_username_element(
411 base::UTF16ToUTF8(password_form.username_element));
412 password_specifics->set_password_element(
413 base::UTF16ToUTF8(password_form.password_element));
414 password_specifics->set_username_value(
415 base::UTF16ToUTF8(password_form.username_value));
416 password_specifics->set_password_value(
417 base::UTF16ToUTF8(password_form.password_value));
418 password_specifics->set_ssl_valid(password_form.ssl_valid);
419 password_specifics->set_preferred(password_form.preferred);
420 password_specifics->set_date_created(
421 password_form.date_created.ToInternalValue());
422 password_specifics->set_blacklisted(password_form.blacklisted_by_user);
423 password_specifics->set_type(password_form.type);
424 password_specifics->set_times_used(password_form.times_used);
426 std::string tag = MakePasswordSyncTag(*password_specifics);
427 return syncer::SyncData::CreateLocalData(tag, tag, password_data);
430 void PasswordFromSpecifics(const sync_pb::PasswordSpecificsData& password,
431 autofill::PasswordForm* new_password) {
432 new_password->scheme =
433 static_cast<autofill::PasswordForm::Scheme>(password.scheme());
434 new_password->signon_realm = password.signon_realm();
435 new_password->origin = GURL(password.origin());
436 new_password->action = GURL(password.action());
437 new_password->username_element =
438 base::UTF8ToUTF16(password.username_element());
439 new_password->password_element =
440 base::UTF8ToUTF16(password.password_element());
441 new_password->username_value = base::UTF8ToUTF16(password.username_value());
442 new_password->password_value = base::UTF8ToUTF16(password.password_value());
443 new_password->ssl_valid = password.ssl_valid();
444 new_password->preferred = password.preferred();
445 new_password->date_created =
446 base::Time::FromInternalValue(password.date_created());
447 new_password->blacklisted_by_user = password.blacklisted();
449 static_cast<autofill::PasswordForm::Type>(password.type());
450 new_password->times_used = password.times_used();
453 std::string MakePasswordSyncTag(
454 const sync_pb::PasswordSpecificsData& password) {
455 return MakePasswordSyncTag(password.origin(),
456 password.username_element(),
457 password.username_value(),
458 password.password_element(),
459 password.signon_realm());
462 } // namespace password_manager