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" | 8 #include "base/memory/scoped_vector.h" |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 108 syncer::ModelType type, | 108 syncer::ModelType type, |
| 109 const syncer::SyncDataList& initial_sync_data, | 109 const syncer::SyncDataList& initial_sync_data, |
| 110 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, | 110 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, |
| 111 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { | 111 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { |
| 112 DCHECK_EQ(syncer::PASSWORDS, type); | 112 DCHECK_EQ(syncer::PASSWORDS, type); |
| 113 syncer::SyncMergeResult merge_result(type); | 113 syncer::SyncMergeResult merge_result(type); |
| 114 sync_error_factory_ = sync_error_factory.Pass(); | 114 sync_error_factory_ = sync_error_factory.Pass(); |
| 115 sync_processor_ = sync_processor.Pass(); | 115 sync_processor_ = sync_processor.Pass(); |
| 116 | 116 |
| 117 ScopedVector<autofill::PasswordForm> password_entries; | 117 ScopedVector<autofill::PasswordForm> password_entries; |
| 118 if (!password_store_->FillAutofillableLogins(&password_entries.get())) { | 118 PasswordEntryMap new_local_entries; |
| 119 // Password store often fails to load passwords. Track failures with UMA. | 119 if (!ReadFromPasswordStore(&password_entries, &new_local_entries)) { |
| 120 // (http://crbug.com/249000) | 120 DCHECK(sync_error_factory_); |
| 121 UMA_HISTOGRAM_ENUMERATION("Sync.LocalDataFailedToLoad", | |
| 122 syncer::PASSWORDS, | |
| 123 syncer::MODEL_TYPE_COUNT); | |
| 124 merge_result.set_error(sync_error_factory_->CreateAndUploadError( | 121 merge_result.set_error(sync_error_factory_->CreateAndUploadError( |
| 125 FROM_HERE, | 122 FROM_HERE, |
| 126 "Failed to get passwords from store.")); | 123 "Failed to get passwords from store.")); |
| 127 return merge_result; | 124 return merge_result; |
| 128 } | 125 } |
| 129 | 126 |
| 130 PasswordEntryMap new_local_entries; | |
| 131 for (PasswordForms::iterator it = password_entries.begin(); | |
| 132 it != password_entries.end(); ++it) { | |
| 133 autofill::PasswordForm* password_form = *it; | |
| 134 // We add all the db entries as |new_local_entries| initially. During | |
| 135 // model association entries that match a sync entry will be | |
| 136 // removed and this list will only contain entries that are not in sync. | |
|
Ilya Sherman
2014/02/07 22:56:35
This was a useful comment, IMO. It would be nice
vasilii
2014/02/10 19:06:50
Done.
| |
| 137 new_local_entries.insert( | |
| 138 std::make_pair(MakePasswordSyncTag(*password_form), password_form)); | |
| 139 } | |
| 140 | |
| 141 merge_result.set_num_items_before_association(new_local_entries.size()); | 127 merge_result.set_num_items_before_association(new_local_entries.size()); |
| 142 | 128 |
| 143 // List that contains the entries that are known only to sync. | 129 // List that contains the entries that are known only to sync. |
| 144 ScopedVector<autofill::PasswordForm> new_sync_entries; | 130 ScopedVector<autofill::PasswordForm> new_sync_entries; |
| 145 | 131 |
| 146 // List that contains the entries that are known to both sync and db but | 132 // List that contains the entries that are known to both sync and db but |
| 147 // have updates in sync. They need to be updated in the passwords db. | 133 // have updates in sync. They need to be updated in the passwords db. |
| 148 ScopedVector<autofill::PasswordForm> updated_sync_entries; | 134 ScopedVector<autofill::PasswordForm> updated_sync_entries; |
| 149 | 135 |
| 150 // Changes from password db that need to be propagated to sync. | 136 // Changes from password db that need to be propagated to sync. |
| 151 syncer::SyncChangeList updated_db_entries; | 137 syncer::SyncChangeList updated_db_entries; |
| 152 for (syncer::SyncDataList::const_iterator sync_iter = | 138 for (syncer::SyncDataList::const_iterator sync_iter = |
| 153 initial_sync_data.begin(); | 139 initial_sync_data.begin(); |
| 154 sync_iter != initial_sync_data.end(); ++sync_iter) { | 140 sync_iter != initial_sync_data.end(); ++sync_iter) { |
| 155 CreateOrUpdateEntry(*sync_iter, | 141 CreateOrUpdateEntry(*sync_iter, |
| 156 &new_local_entries, | 142 &new_local_entries, |
| 157 &new_sync_entries, | 143 &new_sync_entries, |
| 158 &updated_sync_entries, | 144 &updated_sync_entries, |
| 159 &updated_db_entries); | 145 &updated_db_entries); |
| 160 } | 146 } |
| 161 | 147 |
| 162 WriteToPasswordStore(new_sync_entries.get(), | 148 WriteToPasswordStore(new_sync_entries.get(), |
| 163 updated_sync_entries.get()); | 149 updated_sync_entries.get(), |
| 150 PasswordForms()); | |
| 164 | 151 |
| 165 merge_result.set_num_items_after_association( | 152 merge_result.set_num_items_after_association( |
| 166 merge_result.num_items_before_association() + new_sync_entries.size()); | 153 merge_result.num_items_before_association() + new_sync_entries.size()); |
| 167 | 154 |
| 168 merge_result.set_num_items_added(new_sync_entries.size()); | 155 merge_result.set_num_items_added(new_sync_entries.size()); |
| 169 | 156 |
| 170 merge_result.set_num_items_modified(updated_sync_entries.size()); | 157 merge_result.set_num_items_modified(updated_sync_entries.size()); |
| 171 | 158 |
| 172 for (PasswordEntryMap::iterator it = new_local_entries.begin(); | 159 for (PasswordEntryMap::iterator it = new_local_entries.begin(); |
| 173 it != new_local_entries.end(); | 160 it != new_local_entries.end(); |
| 174 ++it) { | 161 ++it) { |
| 175 updated_db_entries.push_back( | 162 updated_db_entries.push_back( |
| 176 syncer::SyncChange(FROM_HERE, | 163 syncer::SyncChange(FROM_HERE, |
| 177 syncer::SyncChange::ACTION_ADD, | 164 syncer::SyncChange::ACTION_ADD, |
| 178 SyncDataFromPassword(*it->second))); | 165 SyncDataFromPassword(*it->second))); |
| 179 } | 166 } |
| 180 | 167 |
| 181 merge_result.set_error( | 168 merge_result.set_error( |
| 182 sync_processor_->ProcessSyncChanges(FROM_HERE, updated_db_entries)); | 169 sync_processor_->ProcessSyncChanges(FROM_HERE, updated_db_entries)); |
| 183 return merge_result; | 170 return merge_result; |
| 184 } | 171 } |
| 185 | 172 |
| 186 void PasswordSyncableService::StopSyncing(syncer::ModelType type) { | 173 void PasswordSyncableService::StopSyncing(syncer::ModelType type) { |
| 187 sync_processor_.reset(); | 174 sync_processor_.reset(); |
| 188 sync_error_factory_.reset(); | 175 sync_error_factory_.reset(); |
| 189 } | 176 } |
| 190 | 177 |
| 191 syncer::SyncDataList PasswordSyncableService::GetAllSyncData( | 178 syncer::SyncDataList PasswordSyncableService::GetAllSyncData( |
| 192 syncer::ModelType type) const { | 179 syncer::ModelType type) const { |
| 180 DCHECK_EQ(syncer::PASSWORDS, type); | |
| 181 ScopedVector<autofill::PasswordForm> password_entries; | |
| 182 ReadFromPasswordStore(&password_entries, NULL); | |
| 183 | |
| 193 syncer::SyncDataList sync_data; | 184 syncer::SyncDataList sync_data; |
| 185 for (PasswordForms::iterator i = password_entries.begin(); | |
|
Ilya Sherman
2014/02/07 22:56:35
nit: i -> it
vasilii
2014/02/10 19:06:50
Done.
| |
| 186 i != password_entries.end(); ++i) { | |
| 187 sync_data.push_back(SyncDataFromPassword(**i)); | |
| 188 } | |
| 194 return sync_data; | 189 return sync_data; |
| 195 } | 190 } |
| 196 | 191 |
| 197 syncer::SyncError PasswordSyncableService::ProcessSyncChanges( | 192 syncer::SyncError PasswordSyncableService::ProcessSyncChanges( |
| 198 const tracked_objects::Location& from_here, | 193 const tracked_objects::Location& from_here, |
| 199 const syncer::SyncChangeList& change_list) { | 194 const syncer::SyncChangeList& change_list) { |
| 200 syncer::SyncError error(FROM_HERE, | 195 // The |db_entries_map| and associated vectors are filled only in case of |
| 201 syncer::SyncError::UNRECOVERABLE_ERROR, | 196 // add/update change. |
| 202 "Password Syncable Service Not Implemented.", | 197 PasswordEntryMap db_entries_map; |
| 203 syncer::PASSWORDS); | 198 ScopedVector<autofill::PasswordForm> password_db_entries; |
| 204 return error; | 199 ScopedVector<autofill::PasswordForm> new_sync_entries; |
| 200 ScopedVector<autofill::PasswordForm> updated_sync_entries; | |
| 201 ScopedVector<autofill::PasswordForm> deleted_entries; | |
| 202 bool has_read_passwords = false; | |
| 203 | |
| 204 for (syncer::SyncChangeList::const_iterator it = change_list.begin(); | |
| 205 it != change_list.end(); | |
| 206 ++it) { | |
| 207 switch (it->change_type()) { | |
| 208 case syncer::SyncChange::ACTION_ADD: | |
| 209 case syncer::SyncChange::ACTION_UPDATE: { | |
| 210 if (!has_read_passwords) { | |
| 211 if (ReadFromPasswordStore(&password_db_entries, | |
|
Nicolas Zea
2014/02/07 21:16:47
It seems expensive to read all passwords from the
Ilya Sherman
2014/02/07 22:56:35
FWIW, my vote is against caching unless we really
vasilii
2014/02/10 19:06:50
This implementation isn't slower than the existing
| |
| 212 &db_entries_map)) { | |
| 213 has_read_passwords = true; | |
| 214 } else { | |
| 215 return sync_error_factory_->CreateAndUploadError( | |
| 216 FROM_HERE, | |
| 217 "Failed to get passwords from store."); | |
| 218 } | |
| 219 } | |
| 220 syncer::SyncChangeList sync_changes; | |
| 221 | |
| 222 // This item from sync will be compared to the data in passwords db and | |
| 223 // |new_sync_entries| or |updated_sync_entries| will be updated based on | |
| 224 // whether this sync item is an addition or update. | |
|
Ilya Sherman
2014/02/07 22:56:35
Hmm, why is this needed? That is, why is it not s
vasilii
2014/02/10 19:06:50
It's safe. I just reuse the existing method.
| |
| 225 CreateOrUpdateEntry(it->sync_data(), | |
| 226 &db_entries_map, | |
| 227 &new_sync_entries, | |
| 228 &updated_sync_entries, | |
| 229 &sync_changes); | |
| 230 break; | |
| 231 } | |
|
Ilya Sherman
2014/02/07 22:56:35
nit: Leave a blank line between cases, IMO.
vasilii
2014/02/10 19:06:50
Done.
| |
| 232 case syncer::SyncChange::ACTION_DELETE: { | |
| 233 const sync_pb::EntitySpecifics& specifics = | |
| 234 it->sync_data().GetSpecifics(); | |
| 235 const sync_pb::PasswordSpecificsData& password_specifics( | |
| 236 specifics.password().client_only_encrypted_data()); | |
| 237 autofill::PasswordForm* new_password = new autofill::PasswordForm; | |
|
Ilya Sherman
2014/02/07 22:56:35
nit: I prefer to immediately wrap all |new|s in sc
vasilii
2014/02/10 19:06:50
Done.
| |
| 238 PasswordFromSpecifics(password_specifics, new_password); | |
| 239 deleted_entries.push_back(new_password); | |
| 240 break; | |
| 241 } | |
| 242 default: { | |
|
Ilya Sherman
2014/02/07 22:56:35
nit: Rather than a default case, please have an ex
vasilii
2014/02/10 19:06:50
Done.
| |
| 243 return sync_error_factory_->CreateAndUploadError( | |
| 244 FROM_HERE, | |
| 245 "Failed to process sync changes for passwords datatype."); | |
| 246 } | |
|
Ilya Sherman
2014/02/07 22:56:35
nit: No need for curly braces.
vasilii
2014/02/10 19:06:50
Done.
| |
| 247 } | |
| 248 } | |
| 249 WriteToPasswordStore(new_sync_entries.get(), | |
| 250 updated_sync_entries.get(), | |
| 251 deleted_entries.get()); | |
| 252 return syncer::SyncError(); | |
| 205 } | 253 } |
| 206 | 254 |
| 207 void PasswordSyncableService::ActOnPasswordStoreChanges( | 255 void PasswordSyncableService::ActOnPasswordStoreChanges( |
| 208 const PasswordStoreChangeList& local_changes) { | 256 const PasswordStoreChangeList& local_changes) { |
| 209 if (!sync_processor_) | 257 if (!sync_processor_) |
| 210 return; | 258 return; |
| 211 syncer::SyncChangeList sync_changes; | 259 syncer::SyncChangeList sync_changes; |
| 212 for (PasswordStoreChangeList::const_iterator it = local_changes.begin(); | 260 for (PasswordStoreChangeList::const_iterator it = local_changes.begin(); |
| 213 it != local_changes.end(); | 261 it != local_changes.end(); |
| 214 ++it) { | 262 ++it) { |
| 215 sync_changes.push_back( | 263 sync_changes.push_back( |
| 216 syncer::SyncChange(FROM_HERE, | 264 syncer::SyncChange(FROM_HERE, |
| 217 GetSyncChangeType(it->type()), | 265 GetSyncChangeType(it->type()), |
| 218 SyncDataFromPassword(it->form()))); | 266 SyncDataFromPassword(it->form()))); |
| 219 } | 267 } |
| 220 sync_processor_->ProcessSyncChanges(FROM_HERE, sync_changes); | 268 sync_processor_->ProcessSyncChanges(FROM_HERE, sync_changes); |
| 221 } | 269 } |
| 222 | 270 |
| 271 bool PasswordSyncableService::ReadFromPasswordStore( | |
| 272 ScopedVector<autofill::PasswordForm>* password_entries, | |
| 273 PasswordEntryMap* passwords_entry_map) const { | |
| 274 DCHECK(password_entries); | |
|
Ilya Sherman
2014/02/07 22:56:35
nit: No need for this, IMO, since you dereference
vasilii
2014/02/10 19:06:50
For better log readability?
| |
| 275 if (!password_store_->FillAutofillableLogins(&password_entries->get()) || | |
| 276 !password_store_->FillBlacklistLogins(&password_entries->get())) { | |
|
Ilya Sherman
2014/02/07 22:56:35
Have you added test coverage for blacklisted login
vasilii
2014/02/10 19:06:50
I modified PasswordSyncableServiceTest.ProcessSync
Ilya Sherman
2014/02/11 07:59:45
Lovely, thanks :)
| |
| 277 // Password store often fails to load passwords. Track failures with UMA. | |
| 278 // (http://crbug.com/249000) | |
| 279 UMA_HISTOGRAM_ENUMERATION("Sync.LocalDataFailedToLoad", | |
| 280 ModelTypeToHistogramInt(syncer::PASSWORDS), | |
| 281 syncer::MODEL_TYPE_COUNT); | |
| 282 return false; | |
| 283 } | |
| 284 | |
| 285 if (!passwords_entry_map) | |
| 286 return true; | |
| 287 | |
| 288 for (PasswordForms::iterator it = password_entries->begin(); | |
| 289 it != password_entries->end(); ++it) { | |
| 290 autofill::PasswordForm* password_form = *it; | |
| 291 passwords_entry_map->insert( | |
| 292 std::make_pair(MakePasswordSyncTag(*password_form), password_form)); | |
| 293 } | |
| 294 | |
| 295 return true; | |
| 296 } | |
| 297 | |
| 223 void PasswordSyncableService::WriteToPasswordStore( | 298 void PasswordSyncableService::WriteToPasswordStore( |
| 224 const PasswordForms& new_entries, | 299 const PasswordForms& new_entries, |
| 225 const PasswordForms& updated_entries) { | 300 const PasswordForms& updated_entries, |
| 301 const PasswordForms& deleted_entries) { | |
| 226 PasswordStoreChangeList changes; | 302 PasswordStoreChangeList changes; |
| 227 for (std::vector<autofill::PasswordForm*>::const_iterator it = | 303 for (std::vector<autofill::PasswordForm*>::const_iterator it = |
| 228 new_entries.begin(); | 304 new_entries.begin(); |
| 229 it != new_entries.end(); | 305 it != new_entries.end(); |
| 230 ++it) { | 306 ++it) { |
| 231 AppendChanges(password_store_->AddLoginImpl(**it), &changes); | 307 AppendChanges(password_store_->AddLoginImpl(**it), &changes); |
| 232 } | 308 } |
| 233 | 309 |
| 234 for (std::vector<autofill::PasswordForm*>::const_iterator it = | 310 for (std::vector<autofill::PasswordForm*>::const_iterator it = |
| 235 updated_entries.begin(); | 311 updated_entries.begin(); |
| 236 it != updated_entries.end(); | 312 it != updated_entries.end(); |
| 237 ++it) { | 313 ++it) { |
| 238 AppendChanges(password_store_->UpdateLoginImpl(**it), &changes); | 314 AppendChanges(password_store_->UpdateLoginImpl(**it), &changes); |
| 239 } | 315 } |
| 240 | 316 |
| 317 for (std::vector<autofill::PasswordForm*>::const_iterator it = | |
| 318 deleted_entries.begin(); | |
| 319 it != deleted_entries.end(); | |
| 320 ++it) { | |
| 321 AppendChanges(password_store_->RemoveLoginImpl(**it), &changes); | |
| 322 } | |
| 323 | |
| 241 // We have to notify password store observers of the change by hand since | 324 // We have to notify password store observers of the change by hand since |
| 242 // we use internal password store interfaces to make changes synchronously. | 325 // we use internal password store interfaces to make changes synchronously. |
| 243 NotifyPasswordStoreOfLoginChanges(changes); | 326 NotifyPasswordStoreOfLoginChanges(changes); |
| 244 } | 327 } |
| 245 | 328 |
| 246 void PasswordSyncableService::NotifyPasswordStoreOfLoginChanges( | 329 void PasswordSyncableService::NotifyPasswordStoreOfLoginChanges( |
| 247 const PasswordStoreChangeList& changes) { | 330 const PasswordStoreChangeList& changes) { |
| 248 password_store_->NotifyLoginsChanged(changes); | 331 password_store_->NotifyLoginsChanged(changes); |
| 249 } | 332 } |
| 250 | 333 |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 340 } | 423 } |
| 341 | 424 |
| 342 std::string MakePasswordSyncTag( | 425 std::string MakePasswordSyncTag( |
| 343 const sync_pb::PasswordSpecificsData& password) { | 426 const sync_pb::PasswordSpecificsData& password) { |
| 344 return MakePasswordSyncTag(password.origin(), | 427 return MakePasswordSyncTag(password.origin(), |
| 345 password.username_element(), | 428 password.username_element(), |
| 346 password.username_value(), | 429 password.username_value(), |
| 347 password.password_element(), | 430 password.password_element(), |
| 348 password.signon_realm()); | 431 password.signon_realm()); |
| 349 } | 432 } |
| OLD | NEW |