Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/password_manager/password_syncable_service.h" | 5 #include "chrome/browser/password_manager/password_syncable_service.h" |
| 6 | 6 |
| 7 #include "base/location.h" | 7 #include "base/location.h" |
| 8 #include "base/memory/scoped_vector.h" | |
| 9 #include "base/metrics/histogram.h" | |
| 10 #include "base/stl_util.h" | |
| 8 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
| 9 #include "chrome/browser/password_manager/password_store.h" | 12 #include "chrome/browser/password_manager/password_store.h" |
| 10 #include "components/autofill/core/common/password_form.h" | 13 #include "components/autofill/core/common/password_form.h" |
| 11 #include "net/base/escape.h" | 14 #include "net/base/escape.h" |
| 12 #include "sync/api/sync_error_factory.h" | 15 #include "sync/api/sync_error_factory.h" |
| 13 | 16 |
| 14 namespace { | 17 namespace { |
| 15 | 18 |
| 16 // Converts the |PasswordSpecifics| obtained from sync to an | |
| 17 // object of type |PasswordForm|. | |
| 18 void ExtractPasswordFromSpecifics( | |
| 19 const sync_pb::PasswordSpecificsData& password, | |
| 20 autofill::PasswordForm* new_password) { | |
| 21 new_password->scheme = | |
| 22 static_cast<autofill::PasswordForm::Scheme>(password.scheme()); | |
| 23 new_password->signon_realm = password.signon_realm(); | |
| 24 new_password->origin = GURL(password.origin()); | |
| 25 new_password->action = GURL(password.action()); | |
| 26 new_password->username_element = | |
| 27 UTF8ToUTF16(password.username_element()); | |
| 28 new_password->password_element = | |
| 29 UTF8ToUTF16(password.password_element()); | |
| 30 new_password->username_value = | |
| 31 UTF8ToUTF16(password.username_value()); | |
| 32 new_password->password_value = | |
| 33 UTF8ToUTF16(password.password_value()); | |
| 34 new_password->ssl_valid = password.ssl_valid(); | |
| 35 new_password->preferred = password.preferred(); | |
| 36 new_password->date_created = | |
| 37 base::Time::FromInternalValue(password.date_created()); | |
| 38 new_password->blacklisted_by_user = | |
| 39 password.blacklisted(); | |
| 40 } | |
| 41 | |
| 42 // Merges the sync password (obtained from the password specifics) and | 19 // Merges the sync password (obtained from the password specifics) and |
| 43 // local password and stores the output in the |new_password_form| pointer. | 20 // local password and stores the output in the |new_password_form| pointer. |
| 44 bool MergeLocalAndSyncPasswords( | 21 bool MergeLocalAndSyncPasswords( |
| 45 const sync_pb::PasswordSpecificsData& password_specifics, | 22 const sync_pb::PasswordSpecificsData& password_specifics, |
| 46 const autofill::PasswordForm& password_form, | 23 const autofill::PasswordForm& password_form, |
| 47 autofill::PasswordForm* new_password_form) { | 24 autofill::PasswordForm* new_password_form) { |
| 48 if (password_specifics.scheme() == password_form.scheme && | 25 if (password_specifics.scheme() == password_form.scheme && |
| 49 password_form.signon_realm == password_specifics.signon_realm() && | 26 password_form.signon_realm == password_specifics.signon_realm() && |
| 50 password_form.origin.spec() == password_specifics.origin() && | 27 password_form.origin.spec() == password_specifics.origin() && |
| 51 password_form.action.spec() == password_specifics.action() && | 28 password_form.action.spec() == password_specifics.action() && |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 64 password_specifics.blacklisted() == | 41 password_specifics.blacklisted() == |
| 65 password_form.blacklisted_by_user) { | 42 password_form.blacklisted_by_user) { |
| 66 return false; | 43 return false; |
| 67 } | 44 } |
| 68 | 45 |
| 69 // If the passwords differ, take the one that was created more recently. | 46 // If the passwords differ, take the one that was created more recently. |
| 70 if (base::Time::FromInternalValue(password_specifics.date_created()) <= | 47 if (base::Time::FromInternalValue(password_specifics.date_created()) <= |
| 71 password_form.date_created) { | 48 password_form.date_created) { |
| 72 *new_password_form = password_form; | 49 *new_password_form = password_form; |
| 73 } else { | 50 } else { |
| 74 ExtractPasswordFromSpecifics(password_specifics, new_password_form); | 51 PasswordSyncableService::ExtractPasswordFromSpecifics( |
| 52 password_specifics, | |
| 53 new_password_form); | |
| 75 } | 54 } |
| 76 | 55 |
| 77 return true; | 56 return true; |
| 78 } | 57 } |
| 79 | 58 |
| 80 } // namespace | 59 } // namespace |
| 81 | 60 |
| 82 PasswordSyncableService::PasswordSyncableService( | 61 PasswordSyncableService::PasswordSyncableService( |
| 83 scoped_refptr<PasswordStore> password_store) | 62 scoped_refptr<PasswordStore> password_store) |
| 84 : password_store_(password_store) { | 63 : password_store_(password_store) { |
| 85 } | 64 } |
| 86 | 65 |
| 87 PasswordSyncableService::~PasswordSyncableService() {} | 66 PasswordSyncableService::~PasswordSyncableService() {} |
| 88 | 67 |
| 68 void PasswordSyncableService::CreateOrUpdateEntry( | |
| 69 const syncer::SyncData& data, | |
| 70 PasswordEntryMap* loaded_data, | |
| 71 ScopedVector<autofill::PasswordForm>* new_entries, | |
| 72 ScopedVector<autofill::PasswordForm>* updated_entries, | |
| 73 syncer::SyncChangeList* updated_db_entries) { | |
| 74 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics(); | |
| 75 const sync_pb::PasswordSpecificsData& password_specifics( | |
| 76 specifics.password().client_only_encrypted_data()); | |
| 77 | |
| 78 std::string tag = MakeTag(password_specifics); | |
| 79 | |
| 80 // Find if the data from sync is already in password store. | |
| 81 PasswordEntryMap::iterator it = loaded_data->find(tag); | |
| 82 | |
| 83 if (it == loaded_data->end()) { | |
| 84 // The sync data is not in password store, so we need to create it in | |
| 85 // password store. Add the entry to the new_entries list. | |
| 86 autofill::PasswordForm* new_password = new autofill::PasswordForm(); | |
| 87 ExtractPasswordFromSpecifics(password_specifics, new_password); | |
| 88 // The new_password pointer is owned by the caller. | |
| 89 new_entries->push_back(new_password); | |
| 90 } else { | |
| 91 // The entry is in password store. If the entries are not identical the | |
| 92 // entries need to be merged. | |
| 93 scoped_ptr<autofill::PasswordForm> new_password( | |
| 94 new autofill::PasswordForm()); | |
| 95 if (MergeLocalAndSyncPasswords(password_specifics, | |
| 96 **(it->second), | |
| 97 new_password.get())) { | |
| 98 updated_db_entries->push_back( | |
| 99 syncer::SyncChange(FROM_HERE, | |
| 100 syncer::SyncChange::ACTION_UPDATE, | |
| 101 CreateSyncData(*(new_password.get())))); | |
| 102 | |
| 103 updated_entries->push_back(new_password.release()); | |
| 104 } | |
| 105 // Remove the entry from the entry map to indicate a match has been found. | |
| 106 // Entries that remain in the map at the end of associating all sync entries | |
| 107 // will be treated as additions that needs to be propagated to sync. | |
| 108 loaded_data->erase(it); | |
| 109 } | |
| 110 } | |
| 111 | |
| 89 syncer::SyncMergeResult | 112 syncer::SyncMergeResult |
| 90 PasswordSyncableService::MergeDataAndStartSyncing( | 113 PasswordSyncableService::MergeDataAndStartSyncing( |
| 91 syncer::ModelType type, | 114 syncer::ModelType type, |
| 92 const syncer::SyncDataList& initial_sync_data, | 115 const syncer::SyncDataList& initial_sync_data, |
| 93 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, | 116 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, |
| 94 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { | 117 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { |
| 95 syncer::SyncMergeResult merge_result(type); | 118 syncer::SyncMergeResult merge_result(type); |
| 96 sync_error_factory_ = sync_error_factory.Pass(); | 119 sync_error_factory_ = sync_error_factory.Pass(); |
| 97 sync_processor_ = sync_processor.Pass(); | 120 sync_processor_ = sync_processor.Pass(); |
| 98 | 121 |
| 99 merge_result.set_error(sync_error_factory->CreateAndUploadError( | 122 ScopedVector<autofill::PasswordForm> password_entries; |
| 100 FROM_HERE, | 123 if (!password_store_->FillAutofillableLogins(&(password_entries.get())) || |
| 101 "Password Syncable Service Not Implemented.")); | 124 !password_store_->FillBlacklistLogins(&(password_entries.get()))) { |
| 125 // Password store often fails to load passwords. Track failures with UMA. | |
| 126 // (http://crbug.com/249000) | |
| 127 UMA_HISTOGRAM_ENUMERATION("Sync.LocalDataFailedToLoad", | |
| 128 ModelTypeToHistogramInt(syncer::PASSWORDS), | |
| 129 syncer::MODEL_TYPE_COUNT); | |
| 130 merge_result.set_error(sync_error_factory->CreateAndUploadError( | |
| 131 FROM_HERE, | |
| 132 "Failed to get passwords from store.")); | |
| 133 return merge_result;; | |
| 134 } | |
| 135 | |
| 136 PasswordEntryMap new_db_entries; | |
| 137 for (std::vector<autofill::PasswordForm*>::iterator | |
| 138 it = password_entries.begin(); | |
| 139 it != password_entries.end(); | |
| 140 ++it) { | |
| 141 // We add all the db entries as |new_db_entries| initially. While | |
| 142 // association entries with matching sync entries will be removed and this | |
| 143 // list will only contain entries that are not in sync. | |
| 144 new_db_entries[MakeTag(**it)] = it; | |
| 145 } | |
| 146 | |
| 147 // List that contains the entries that are known only to sync. | |
| 148 ScopedVector<autofill::PasswordForm> new_synced_entries; | |
|
Nicolas Zea
2013/10/25 20:20:13
nit: I think the name here would better represent
lipalani1
2013/10/29 20:16:36
May be I am missing something here:
The names refe
| |
| 149 | |
| 150 // List that contains the entries that are known to both sync and db but | |
| 151 // have to be updated in sync. | |
| 152 ScopedVector<autofill::PasswordForm> updated_sync_entries; | |
| 153 | |
| 154 // Changes from password db that needs to be propagated to sync. | |
| 155 syncer::SyncChangeList db_changes; | |
| 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_db_entries, | |
| 161 &new_synced_entries, | |
| 162 &updated_sync_entries, | |
| 163 &db_changes); | |
| 164 } | |
| 165 | |
| 166 WriteToPasswordStore(new_synced_entries.get(), | |
| 167 updated_sync_entries.get()); | |
| 168 | |
| 169 for (PasswordEntryMap::iterator it = new_db_entries.begin(); | |
| 170 it != new_db_entries.end(); | |
| 171 ++it) { | |
| 172 db_changes.push_back(syncer::SyncChange(FROM_HERE, | |
| 173 syncer::SyncChange::ACTION_ADD, | |
| 174 CreateSyncData(**(it->second)))); | |
| 175 } | |
| 176 | |
| 177 merge_result.set_error( | |
|
Nicolas Zea
2013/10/25 20:20:13
could you also fill calculate the other variables
lipalani1
2013/10/29 20:16:36
Done.
| |
| 178 sync_processor_->ProcessSyncChanges(FROM_HERE, db_changes)); | |
| 102 return merge_result; | 179 return merge_result; |
| 103 } | 180 } |
| 104 | 181 |
| 105 void PasswordSyncableService::StopSyncing(syncer::ModelType type) { | 182 void PasswordSyncableService::StopSyncing(syncer::ModelType type) { |
| 106 } | 183 } |
| 107 | 184 |
| 108 syncer::SyncDataList PasswordSyncableService::GetAllSyncData( | 185 syncer::SyncDataList PasswordSyncableService::GetAllSyncData( |
| 109 syncer::ModelType type) const { | 186 syncer::ModelType type) const { |
| 110 syncer::SyncDataList sync_data; | 187 syncer::SyncDataList sync_data; |
| 111 return sync_data; | 188 return sync_data; |
| 112 } | 189 } |
| 113 | 190 |
| 114 syncer::SyncError PasswordSyncableService::ProcessSyncChanges( | 191 syncer::SyncError PasswordSyncableService::ProcessSyncChanges( |
| 115 const tracked_objects::Location& from_here, | 192 const tracked_objects::Location& from_here, |
| 116 const syncer::SyncChangeList& change_list) { | 193 const syncer::SyncChangeList& change_list) { |
| 117 syncer::SyncError error(FROM_HERE, | 194 syncer::SyncError error(FROM_HERE, |
| 118 syncer::SyncError::UNRECOVERABLE_ERROR, | 195 syncer::SyncError::UNRECOVERABLE_ERROR, |
| 119 "Password Syncable Service Not Implemented.", | 196 "Password Syncable Service Not Implemented.", |
| 120 syncer::PASSWORDS); | 197 syncer::PASSWORDS); |
| 121 return error; | 198 return error; |
| 122 } | 199 } |
| 123 | 200 |
| 124 void PasswordSyncableService::WriteToPasswordStore( | 201 void PasswordSyncableService::WriteToPasswordStore( |
| 125 PasswordForms* new_entries, | 202 const PasswordForms& new_entries, |
| 126 PasswordForms* updated_entries) { | 203 const PasswordForms& updated_entries) { |
| 127 for (std::vector<autofill::PasswordForm*>::const_iterator it = | 204 for (std::vector<autofill::PasswordForm*>::const_iterator it = |
| 128 new_entries->begin(); | 205 new_entries.begin(); |
| 129 it != new_entries->end(); | 206 it != new_entries.end(); |
| 130 ++it) { | 207 ++it) { |
| 131 password_store_->AddLoginImpl(**it); | 208 password_store_->AddLoginImpl(**it); |
| 132 } | 209 } |
| 133 | 210 |
| 134 for (std::vector<autofill::PasswordForm*>::const_iterator it = | 211 for (std::vector<autofill::PasswordForm*>::const_iterator it = |
| 135 updated_entries->begin(); | 212 updated_entries.begin(); |
| 136 it != updated_entries->end(); | 213 it != updated_entries.end(); |
| 137 ++it) { | 214 ++it) { |
| 138 password_store_->UpdateLoginImpl(**it); | 215 password_store_->UpdateLoginImpl(**it); |
| 139 } | 216 } |
| 140 | 217 |
| 141 if (!new_entries->empty() || !updated_entries->empty()) { | 218 if (!new_entries.empty() || !updated_entries.empty()) { |
| 142 // We have to notify password store observers of the change by hand since | 219 // We have to notify password store observers of the change by hand since |
| 143 // we use internal password store interfaces to make changes synchronously. | 220 // we use internal password store interfaces to make changes synchronously. |
| 144 password_store_->PostNotifyLoginsChanged(); | 221 NotifyPasswordStore(); |
| 145 } | 222 } |
| 146 } | 223 } |
| 147 | 224 |
| 225 void PasswordSyncableService::NotifyPasswordStore() { | |
| 226 password_store_->PostNotifyLoginsChanged(); | |
| 227 } | |
| 228 | |
| 148 syncer::SyncData PasswordSyncableService::CreateSyncData( | 229 syncer::SyncData PasswordSyncableService::CreateSyncData( |
| 149 const autofill::PasswordForm& password_form) { | 230 const autofill::PasswordForm& password_form) { |
| 150 sync_pb::EntitySpecifics password_data; | 231 sync_pb::EntitySpecifics password_data; |
| 151 sync_pb::PasswordSpecificsData* password_specifics = | 232 sync_pb::PasswordSpecificsData* password_specifics = |
| 152 password_data.mutable_password()->mutable_client_only_encrypted_data(); | 233 password_data.mutable_password()->mutable_client_only_encrypted_data(); |
| 153 password_specifics->set_scheme(password_form.scheme); | 234 password_specifics->set_scheme(password_form.scheme); |
| 154 password_specifics->set_signon_realm(password_form.signon_realm); | 235 password_specifics->set_signon_realm(password_form.signon_realm); |
| 155 password_specifics->set_origin(password_form.origin.spec()); | 236 password_specifics->set_origin(password_form.origin.spec()); |
| 156 password_specifics->set_action(password_form.action.spec()); | 237 password_specifics->set_action(password_form.action.spec()); |
| 157 password_specifics->set_username_element( | 238 password_specifics->set_username_element( |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 199 // static | 280 // static |
| 200 std::string PasswordSyncableService::MakeTag( | 281 std::string PasswordSyncableService::MakeTag( |
| 201 const sync_pb::PasswordSpecificsData& password) { | 282 const sync_pb::PasswordSpecificsData& password) { |
| 202 return MakeTag(password.origin(), | 283 return MakeTag(password.origin(), |
| 203 password.username_element(), | 284 password.username_element(), |
| 204 password.username_value(), | 285 password.username_value(), |
| 205 password.password_element(), | 286 password.password_element(), |
| 206 password.signon_realm()); | 287 password.signon_realm()); |
| 207 } | 288 } |
| 208 | 289 |
| 290 // static | |
| 291 void PasswordSyncableService::ExtractPasswordFromSpecifics( | |
| 292 const sync_pb::PasswordSpecificsData& password, | |
| 293 autofill::PasswordForm* new_password) { | |
| 294 new_password->scheme = | |
| 295 static_cast<autofill::PasswordForm::Scheme>(password.scheme()); | |
| 296 new_password->signon_realm = password.signon_realm(); | |
| 297 new_password->origin = GURL(password.origin()); | |
| 298 new_password->action = GURL(password.action()); | |
| 299 new_password->username_element = | |
| 300 UTF8ToUTF16(password.username_element()); | |
| 301 new_password->password_element = | |
| 302 UTF8ToUTF16(password.password_element()); | |
| 303 new_password->username_value = | |
| 304 UTF8ToUTF16(password.username_value()); | |
| 305 new_password->password_value = | |
| 306 UTF8ToUTF16(password.password_value()); | |
| 307 new_password->ssl_valid = password.ssl_valid(); | |
| 308 new_password->preferred = password.preferred(); | |
| 309 new_password->date_created = | |
| 310 base::Time::FromInternalValue(password.date_created()); | |
| 311 new_password->blacklisted_by_user = | |
| 312 password.blacklisted(); | |
| 313 } | |
| 314 | |
| OLD | NEW |