• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
AreLocalAndSyncPasswordsEqual(const sync_pb::PasswordSpecificsData & password_specifics,const autofill::PasswordForm & password_form)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 
GetSyncChangeType(PasswordStoreChange::Type type)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|.
AppendPasswordFromSpecifics(const sync_pb::PasswordSpecificsData & specifics,base::Time sync_time,ScopedVector<autofill::PasswordForm> * 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 {
EntriesForChangeTypepassword_manager::PasswordSyncableService::SyncEntries90   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 
PasswordSyncableService(PasswordStoreSync * password_store)114 PasswordSyncableService::PasswordSyncableService(
115     PasswordStoreSync* password_store)
116     : password_store_(password_store),
117       is_processing_sync_changes_(false) {
118 }
119 
~PasswordSyncableService()120 PasswordSyncableService::~PasswordSyncableService() {}
121 
MergeDataAndStartSyncing(syncer::ModelType type,const syncer::SyncDataList & initial_sync_data,scoped_ptr<syncer::SyncChangeProcessor> sync_processor,scoped_ptr<syncer::SyncErrorFactory> sync_error_factory)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 
StopSyncing(syncer::ModelType type)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 
GetAllSyncData(syncer::ModelType type) const201 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 
ProcessSyncChanges(const tracked_objects::Location & from_here,const syncer::SyncChangeList & change_list)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 
ActOnPasswordStoreChanges(const PasswordStoreChangeList & local_changes)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 
InjectStartSyncFlare(const syncer::SyncableService::StartSyncFlare & flare)270 void PasswordSyncableService::InjectStartSyncFlare(
271     const syncer::SyncableService::StartSyncFlare& flare) {
272   DCHECK(CalledOnValidThread());
273   flare_ = flare;
274 }
275 
ReadFromPasswordStore(ScopedVector<autofill::PasswordForm> * password_entries,PasswordEntryMap * passwords_entry_map) const276 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 
WriteToPasswordStore(const SyncEntries & entries)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 
CreateOrUpdateEntry(const syncer::SyncData & data,PasswordEntryMap * unmatched_data_from_password_db,SyncEntries * sync_entries,syncer::SyncChangeList * updated_db_entries)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 
WriteEntriesToDatabase(DatabaseOperation operation,const PasswordForms & entries,PasswordStoreChangeList * all_changes)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 
SyncDataFromPassword(const autofill::PasswordForm & password_form)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 
PasswordFromSpecifics(const sync_pb::PasswordSpecificsData & password)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 
MakePasswordSyncTag(const sync_pb::PasswordSpecificsData & password)438 std::string MakePasswordSyncTag(
439     const sync_pb::PasswordSpecificsData& password) {
440   return MakePasswordSyncTag(PasswordFromSpecifics(password));
441 }
442 
MakePasswordSyncTag(const autofill::PasswordForm & password)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