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