Home | History | Annotate | Download | only in browser
      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