Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / components / password_manager / core / browser / password_syncable_service.cc
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
225   for (syncer::SyncChangeList::const_iterator it = change_list.begin();
226        it != change_list.end();
227        ++it) {
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(),
231                           form.get());
232     switch (it->change_type()) {
233       case syncer::SyncChange::ACTION_ADD: {
234         new_sync_entries.push_back(form.release());
235         break;
236       }
237       case syncer::SyncChange::ACTION_UPDATE: {
238         updated_sync_entries.push_back(form.release());
239         break;
240       }
241
242       case syncer::SyncChange::ACTION_DELETE: {
243         deleted_entries.push_back(form.release());
244         break;
245       }
246       case syncer::SyncChange::ACTION_INVALID:
247         return sync_error_factory_->CreateAndUploadError(
248             FROM_HERE,
249             "Failed to process sync changes for passwords datatype.");
250     }
251   }
252   WriteToPasswordStore(new_sync_entries.get(),
253                        updated_sync_entries.get(),
254                        deleted_entries.get());
255   return syncer::SyncError();
256 }
257
258 void PasswordSyncableService::ActOnPasswordStoreChanges(
259     const PasswordStoreChangeList& local_changes) {
260   DCHECK(CalledOnValidThread());
261
262   if (!sync_processor_) {
263     if (!flare_.is_null()) {
264       flare_.Run(syncer::PASSWORDS);
265       flare_.Reset();
266     }
267     return;
268   }
269
270   // ActOnPasswordStoreChanges() can be called from ProcessSyncChanges(). Do
271   // nothing in this case.
272   if (is_processing_sync_changes_)
273     return;
274   syncer::SyncChangeList sync_changes;
275   for (PasswordStoreChangeList::const_iterator it = local_changes.begin();
276        it != local_changes.end();
277        ++it) {
278     sync_changes.push_back(
279         syncer::SyncChange(FROM_HERE,
280                            GetSyncChangeType(it->type()),
281                            SyncDataFromPassword(it->form())));
282   }
283   sync_processor_->ProcessSyncChanges(FROM_HERE, sync_changes);
284 }
285
286 void PasswordSyncableService::InjectStartSyncFlare(
287     const syncer::SyncableService::StartSyncFlare& flare) {
288   DCHECK(CalledOnValidThread());
289   flare_ = flare;
290 }
291
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);
303     return false;
304   }
305
306   if (!passwords_entry_map)
307     return true;
308
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));
314   }
315
316   return true;
317 }
318
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 =
325            new_entries.begin();
326        it != new_entries.end();
327        ++it) {
328     AppendChanges(password_store_->AddLoginImpl(**it), &changes);
329   }
330
331   for (std::vector<autofill::PasswordForm*>::const_iterator it =
332            updated_entries.begin();
333        it != updated_entries.end();
334        ++it) {
335     AppendChanges(password_store_->UpdateLoginImpl(**it), &changes);
336   }
337
338   for (std::vector<autofill::PasswordForm*>::const_iterator it =
339            deleted_entries.begin();
340        it != deleted_entries.end();
341        ++it) {
342     AppendChanges(password_store_->RemoveLoginImpl(**it), &changes);
343   }
344
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);
348 }
349
350 void PasswordSyncableService::NotifyPasswordStoreOfLoginChanges(
351     const PasswordStoreChangeList& changes) {
352   password_store_->NotifyLoginsChanged(changes);
353 }
354
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);
365
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());
375   } else {
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())) {
382       case IDENTICAL:
383         break;
384       case SYNC:
385         updated_sync_entries->push_back(new_password.release());
386         break;
387       case LOCAL:
388         updated_db_entries->push_back(
389             syncer::SyncChange(FROM_HERE,
390                                syncer::SyncChange::ACTION_UPDATE,
391                                SyncDataFromPassword(*new_password)));
392         break;
393     }
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);
398   }
399 }
400
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);
425
426   std::string tag = MakePasswordSyncTag(*password_specifics);
427   return syncer::SyncData::CreateLocalData(tag, tag, password_data);
428 }
429
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();
448   new_password->type =
449       static_cast<autofill::PasswordForm::Type>(password.type());
450   new_password->times_used = password.times_used();
451 }
452
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());
460 }
461
462 }  // namespace password_manager