Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: chrome/browser/password_manager/password_syncable_service.cc

Issue 131003006: Password sync refactoring: implemented |MergeDataAndStartSyncing| and unit_tests (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: win compilation Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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"
8 #include "base/strings/utf_string_conversions.h" 10 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/password_manager/password_store.h" 11 #include "chrome/browser/password_manager/password_store.h"
10 #include "components/autofill/core/common/password_form.h" 12 #include "components/autofill/core/common/password_form.h"
11 #include "net/base/escape.h" 13 #include "net/base/escape.h"
12 #include "sync/api/sync_error_factory.h" 14 #include "sync/api/sync_error_factory.h"
13 15
14 namespace { 16 namespace {
15 17
18 // Merges the local and sync passwords and outputs the entry into
19 // |new_password_form|. Returns true if the local and the sync passwords differ.
20 // Returns false if they are identical.
21 bool MergeLocalAndSyncPasswords(
22 const sync_pb::PasswordSpecificsData& password_specifics,
23 const autofill::PasswordForm& password_form,
24 autofill::PasswordForm* new_password_form) {
25 DCHECK(new_password_form);
26 if (password_form.scheme == password_specifics.scheme() &&
27 password_form.signon_realm == password_specifics.signon_realm() &&
28 password_form.origin.spec() == password_specifics.origin() &&
29 password_form.action.spec() == password_specifics.action() &&
30 base::UTF16ToUTF8(password_form.username_element) ==
31 password_specifics.username_element() &&
32 base::UTF16ToUTF8(password_form.password_element) ==
33 password_specifics.password_element() &&
34 base::UTF16ToUTF8(password_form.username_value) ==
35 password_specifics.username_value() &&
36 base::UTF16ToUTF8(password_form.password_value) ==
37 password_specifics.password_value() &&
38 password_form.ssl_valid == password_specifics.ssl_valid() &&
39 password_form.preferred == password_specifics.preferred() &&
40 password_form.date_created.ToInternalValue() ==
41 password_specifics.date_created() &&
42 password_form.blacklisted_by_user == password_specifics.blacklisted()) {
43 return false;
44 }
45
46 // If the passwords differ, take the one that was created more recently.
47 if (base::Time::FromInternalValue(password_specifics.date_created()) <=
48 password_form.date_created) {
49 *new_password_form = password_form;
50 } else {
51 PasswordFromSpecifics(password_specifics, new_password_form);
52 }
53
54 return true;
55 }
56
57 std::string MakePasswordSyncTag(const std::string& origin_url,
58 const std::string& username_element,
59 const std::string& username_value,
60 const std::string& password_element,
61 const std::string& signon_realm) {
62 return net::EscapePath(origin_url) + "|" +
63 net::EscapePath(username_element) + "|" +
64 net::EscapePath(username_value) + "|" +
65 net::EscapePath(password_element) + "|" +
66 net::EscapePath(signon_realm);
67 }
68
69 std::string MakePasswordSyncTag(const autofill::PasswordForm& password) {
70 return MakePasswordSyncTag(password.origin.spec(),
71 base::UTF16ToUTF8(password.username_element),
72 base::UTF16ToUTF8(password.username_value),
73 base::UTF16ToUTF8(password.password_element),
74 password.signon_realm);
75 }
76
16 syncer::SyncChange::SyncChangeType GetSyncChangeType( 77 syncer::SyncChange::SyncChangeType GetSyncChangeType(
17 PasswordStoreChange::Type type) { 78 PasswordStoreChange::Type type) {
18 switch (type) { 79 switch (type) {
19 case PasswordStoreChange::ADD: 80 case PasswordStoreChange::ADD:
20 return syncer::SyncChange::ACTION_ADD; 81 return syncer::SyncChange::ACTION_ADD;
21 case PasswordStoreChange::UPDATE: 82 case PasswordStoreChange::UPDATE:
22 return syncer::SyncChange::ACTION_UPDATE; 83 return syncer::SyncChange::ACTION_UPDATE;
23 case PasswordStoreChange::REMOVE: 84 case PasswordStoreChange::REMOVE:
24 return syncer::SyncChange::ACTION_DELETE; 85 return syncer::SyncChange::ACTION_DELETE;
25 } 86 }
26 NOTREACHED(); 87 NOTREACHED();
27 return syncer::SyncChange::ACTION_INVALID; 88 return syncer::SyncChange::ACTION_INVALID;
28 } 89 }
29 90
30 } // namespace 91 } // namespace
31 92
32 PasswordSyncableService::PasswordSyncableService( 93 PasswordSyncableService::PasswordSyncableService(
33 scoped_refptr<PasswordStore> password_store) 94 scoped_refptr<PasswordStore> password_store)
34 : password_store_(password_store) { 95 : password_store_(password_store) {
35 } 96 }
36 97
37 PasswordSyncableService::~PasswordSyncableService() {} 98 PasswordSyncableService::~PasswordSyncableService() {}
38 99
39 syncer::SyncMergeResult 100 syncer::SyncMergeResult PasswordSyncableService::MergeDataAndStartSyncing(
40 PasswordSyncableService::MergeDataAndStartSyncing(
41 syncer::ModelType type, 101 syncer::ModelType type,
42 const syncer::SyncDataList& initial_sync_data, 102 const syncer::SyncDataList& initial_sync_data,
43 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, 103 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
44 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { 104 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
105 DCHECK_EQ(syncer::PASSWORDS, type);
45 syncer::SyncMergeResult merge_result(type); 106 syncer::SyncMergeResult merge_result(type);
46 sync_error_factory_ = sync_error_factory.Pass(); 107 sync_error_factory_ = sync_error_factory.Pass();
47 sync_processor_ = sync_processor.Pass(); 108 sync_processor_ = sync_processor.Pass();
48 109
49 merge_result.set_error(sync_error_factory->CreateAndUploadError( 110 ScopedVector<autofill::PasswordForm> password_entries;
50 FROM_HERE, 111 if (!password_store_->FillAutofillableLogins(&password_entries.get())) {
51 "Password Syncable Service Not Implemented.")); 112 // Password store often fails to load passwords. Track failures with UMA.
113 // (http://crbug.com/249000)
114 UMA_HISTOGRAM_ENUMERATION("Sync.LocalDataFailedToLoad",
115 syncer::PASSWORDS,
116 syncer::MODEL_TYPE_COUNT);
117 merge_result.set_error(sync_error_factory_->CreateAndUploadError(
118 FROM_HERE,
119 "Failed to get passwords from store."));
120 return merge_result;
121 }
122
123 PasswordEntryMap new_local_entries;
124 for (PasswordForms::iterator it = password_entries.begin();
125 it != password_entries.end(); ++it) {
126 autofill::PasswordForm* password_form = *it;
127 // We add all the db entries as |new_local_entries| initially. During
128 // model association entries that match a sync entry will be
129 // removed and this list will only contain entries that are not in sync.
130 new_local_entries.insert(
131 std::make_pair(MakePasswordSyncTag(*password_form), password_form));
132 }
133
134 merge_result.set_num_items_before_association(new_local_entries.size());
135
136 // List that contains the entries that are known only to sync.
137 ScopedVector<autofill::PasswordForm> new_sync_entries;
138
139 // List that contains the entries that are known to both sync and db but
140 // have updates in sync. They need to be updated in the passwords db.
141 ScopedVector<autofill::PasswordForm> updated_sync_entries;
142
143 // Changes from password db that need to be propagated to sync.
144 syncer::SyncChangeList updated_db_entries;
145 for (syncer::SyncDataList::const_iterator sync_iter =
146 initial_sync_data.begin();
147 sync_iter != initial_sync_data.end(); ++sync_iter) {
148 CreateOrUpdateEntry(*sync_iter,
149 &new_local_entries,
150 &new_sync_entries,
151 &updated_sync_entries,
152 &updated_db_entries);
153 }
154
155 WriteToPasswordStore(new_sync_entries.get(),
156 updated_sync_entries.get());
157
158 merge_result.set_num_items_after_association(
159 merge_result.num_items_before_association() + new_sync_entries.size());
160
161 merge_result.set_num_items_added(new_sync_entries.size());
162
163 merge_result.set_num_items_modified(updated_sync_entries.size());
164
165 for (PasswordEntryMap::iterator it = new_local_entries.begin();
166 it != new_local_entries.end();
167 ++it) {
168 updated_db_entries.push_back(
169 syncer::SyncChange(FROM_HERE,
170 syncer::SyncChange::ACTION_ADD,
171 SyncDataFromPassword(*it->second)));
172 }
173
174 merge_result.set_error(
175 sync_processor_->ProcessSyncChanges(FROM_HERE, updated_db_entries));
52 return merge_result; 176 return merge_result;
53 } 177 }
54 178
55 void PasswordSyncableService::StopSyncing(syncer::ModelType type) { 179 void PasswordSyncableService::StopSyncing(syncer::ModelType type) {
56 sync_processor_.reset(); 180 sync_processor_.reset();
57 sync_error_factory_.reset(); 181 sync_error_factory_.reset();
58 } 182 }
59 183
60 syncer::SyncDataList PasswordSyncableService::GetAllSyncData( 184 syncer::SyncDataList PasswordSyncableService::GetAllSyncData(
61 syncer::ModelType type) const { 185 syncer::ModelType type) const {
(...skipping 12 matching lines...) Expand all
74 } 198 }
75 199
76 void PasswordSyncableService::ActOnPasswordStoreChanges( 200 void PasswordSyncableService::ActOnPasswordStoreChanges(
77 const PasswordStoreChangeList& local_changes) { 201 const PasswordStoreChangeList& local_changes) {
78 if (!sync_processor_) 202 if (!sync_processor_)
79 return; 203 return;
80 syncer::SyncChangeList sync_changes; 204 syncer::SyncChangeList sync_changes;
81 for (PasswordStoreChangeList::const_iterator it = local_changes.begin(); 205 for (PasswordStoreChangeList::const_iterator it = local_changes.begin();
82 it != local_changes.end(); 206 it != local_changes.end();
83 ++it) { 207 ++it) {
84 sync_changes.push_back(syncer::SyncChange(FROM_HERE, 208 sync_changes.push_back(
85 GetSyncChangeType(it->type()), 209 syncer::SyncChange(FROM_HERE,
86 CreateSyncData(it->form()))); 210 GetSyncChangeType(it->type()),
211 SyncDataFromPassword(it->form())));
87 } 212 }
88 sync_processor_->ProcessSyncChanges(FROM_HERE, sync_changes); 213 sync_processor_->ProcessSyncChanges(FROM_HERE, sync_changes);
89 } 214 }
90 215
91 // static
92 std::string PasswordSyncableService::MakeTag(
93 const std::string& origin_url,
94 const std::string& username_element,
95 const std::string& username_value,
96 const std::string& password_element,
97 const std::string& signon_realm) {
98 return net::EscapePath(origin_url) + "|" +
99 net::EscapePath(username_element) + "|" +
100 net::EscapePath(username_value) + "|" +
101 net::EscapePath(password_element) + "|" +
102 net::EscapePath(signon_realm);
103 }
104
105 // static
106 std::string PasswordSyncableService::MakeTag(
107 const autofill::PasswordForm& password) {
108 return MakeTag(password.origin.spec(),
109 base::UTF16ToUTF8(password.username_element),
110 base::UTF16ToUTF8(password.username_value),
111 base::UTF16ToUTF8(password.password_element),
112 password.signon_realm);
113 }
114
115 // static
116 std::string PasswordSyncableService::MakeTag(
117 const sync_pb::PasswordSpecificsData& password) {
118 return MakeTag(password.origin(),
119 password.username_element(),
120 password.username_value(),
121 password.password_element(),
122 password.signon_realm());
123 }
124
125 void PasswordSyncableService::WriteToPasswordStore( 216 void PasswordSyncableService::WriteToPasswordStore(
126 PasswordForms* new_entries, 217 const PasswordForms& new_entries,
127 PasswordForms* updated_entries) { 218 const PasswordForms& updated_entries) {
128 for (std::vector<autofill::PasswordForm*>::const_iterator it = 219 for (std::vector<autofill::PasswordForm*>::const_iterator it =
129 new_entries->begin(); 220 new_entries.begin();
130 it != new_entries->end(); 221 it != new_entries.end();
131 ++it) { 222 ++it) {
132 password_store_->AddLoginImpl(**it); 223 password_store_->AddLoginImpl(**it);
133 } 224 }
134 225
135 for (std::vector<autofill::PasswordForm*>::const_iterator it = 226 for (std::vector<autofill::PasswordForm*>::const_iterator it =
136 updated_entries->begin(); 227 updated_entries.begin();
137 it != updated_entries->end(); 228 it != updated_entries.end();
138 ++it) { 229 ++it) {
139 password_store_->UpdateLoginImpl(**it); 230 password_store_->UpdateLoginImpl(**it);
140 } 231 }
141 232
142 if (!new_entries->empty() || !updated_entries->empty()) { 233 if (!new_entries.empty() || !updated_entries.empty()) {
143 // We have to notify password store observers of the change by hand since 234 // We have to notify password store observers of the change by hand since
144 // we use internal password store interfaces to make changes synchronously. 235 // we use internal password store interfaces to make changes synchronously.
145 password_store_->PostNotifyLoginsChanged(); 236 NotifyPasswordStoreOfLoginChanges();
146 } 237 }
147 } 238 }
148 239
149 syncer::SyncData PasswordSyncableService::CreateSyncData( 240 void PasswordSyncableService::NotifyPasswordStoreOfLoginChanges() {
241 password_store_->PostNotifyLoginsChanged();
242 }
243
244 void PasswordSyncableService::CreateOrUpdateEntry(
245 const syncer::SyncData& data,
246 PasswordEntryMap* umatched_data_from_password_db,
247 ScopedVector<autofill::PasswordForm>* new_sync_entries,
248 ScopedVector<autofill::PasswordForm>* updated_sync_entries,
249 syncer::SyncChangeList* updated_db_entries) {
250 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics();
251 const sync_pb::PasswordSpecificsData& password_specifics(
252 specifics.password().client_only_encrypted_data());
253 std::string tag = MakePasswordSyncTag(password_specifics);
254
255 // Check whether the data from sync is already in the password store.
256 PasswordEntryMap::iterator existing_local_entry_iter =
257 umatched_data_from_password_db->find(tag);
258 if (existing_local_entry_iter == umatched_data_from_password_db->end()) {
259 // The sync data is not in the password store, so we need to create it in
260 // the password store. Add the entry to the new_entries list.
261 scoped_ptr<autofill::PasswordForm> new_password(new autofill::PasswordForm);
262 PasswordFromSpecifics(password_specifics, new_password.get());
263 new_sync_entries->push_back(new_password.release());
264 } else {
265 // The entry is in password store. If the entries are not identical, then
266 // the entries need to be merged.
267 scoped_ptr<autofill::PasswordForm> new_password(new autofill::PasswordForm);
268 if (MergeLocalAndSyncPasswords(password_specifics,
269 *existing_local_entry_iter->second,
270 new_password.get())) {
271 // Rather than checking which database -- sync or local -- needs updating,
272 // simply push an update to both. This will end up being a noop for the
273 // database that didn't need an update.
274 updated_db_entries->push_back(
275 syncer::SyncChange(FROM_HERE,
276 syncer::SyncChange::ACTION_UPDATE,
277 SyncDataFromPassword(*new_password)));
278
279 updated_sync_entries->push_back(new_password.release());
280 }
281 // Remove the entry from the entry map to indicate a match has been found.
282 // Entries that remain in the map at the end of associating all sync entries
283 // will be treated as additions that need to be propagated to sync.
284 umatched_data_from_password_db->erase(existing_local_entry_iter);
285 }
286 }
287
288 syncer::SyncData SyncDataFromPassword(
150 const autofill::PasswordForm& password_form) { 289 const autofill::PasswordForm& password_form) {
151 sync_pb::EntitySpecifics password_data; 290 sync_pb::EntitySpecifics password_data;
152 sync_pb::PasswordSpecificsData* password_specifics = 291 sync_pb::PasswordSpecificsData* password_specifics =
153 password_data.mutable_password()->mutable_client_only_encrypted_data(); 292 password_data.mutable_password()->mutable_client_only_encrypted_data();
154 password_specifics->set_scheme(password_form.scheme); 293 password_specifics->set_scheme(password_form.scheme);
155 password_specifics->set_signon_realm(password_form.signon_realm); 294 password_specifics->set_signon_realm(password_form.signon_realm);
156 password_specifics->set_origin(password_form.origin.spec()); 295 password_specifics->set_origin(password_form.origin.spec());
157 password_specifics->set_action(password_form.action.spec()); 296 password_specifics->set_action(password_form.action.spec());
158 password_specifics->set_username_element( 297 password_specifics->set_username_element(
159 base::UTF16ToUTF8(password_form.username_element)); 298 base::UTF16ToUTF8(password_form.username_element));
160 password_specifics->set_password_element( 299 password_specifics->set_password_element(
161 base::UTF16ToUTF8(password_form.password_element)); 300 base::UTF16ToUTF8(password_form.password_element));
162 password_specifics->set_username_value( 301 password_specifics->set_username_value(
163 base::UTF16ToUTF8(password_form.username_value)); 302 base::UTF16ToUTF8(password_form.username_value));
164 password_specifics->set_password_value( 303 password_specifics->set_password_value(
165 base::UTF16ToUTF8(password_form.password_value)); 304 base::UTF16ToUTF8(password_form.password_value));
166 password_specifics->set_ssl_valid(password_form.ssl_valid); 305 password_specifics->set_ssl_valid(password_form.ssl_valid);
167 password_specifics->set_preferred(password_form.preferred); 306 password_specifics->set_preferred(password_form.preferred);
168 password_specifics->set_date_created( 307 password_specifics->set_date_created(
169 password_form.date_created.ToInternalValue()); 308 password_form.date_created.ToInternalValue());
170 password_specifics->set_blacklisted(password_form.blacklisted_by_user); 309 password_specifics->set_blacklisted(password_form.blacklisted_by_user);
171 310
172 std::string tag = MakeTag(*password_specifics); 311 std::string tag = MakePasswordSyncTag(*password_specifics);
173 return syncer::SyncData::CreateLocalData(tag, tag, password_data); 312 return syncer::SyncData::CreateLocalData(tag, tag, password_data);
174 } 313 }
314
315 void PasswordFromSpecifics(const sync_pb::PasswordSpecificsData& password,
316 autofill::PasswordForm* new_password) {
317 new_password->scheme =
318 static_cast<autofill::PasswordForm::Scheme>(password.scheme());
319 new_password->signon_realm = password.signon_realm();
320 new_password->origin = GURL(password.origin());
321 new_password->action = GURL(password.action());
322 new_password->username_element =
323 base::UTF8ToUTF16(password.username_element());
324 new_password->password_element =
325 base::UTF8ToUTF16(password.password_element());
326 new_password->username_value = base::UTF8ToUTF16(password.username_value());
327 new_password->password_value = base::UTF8ToUTF16(password.password_value());
328 new_password->ssl_valid = password.ssl_valid();
329 new_password->preferred = password.preferred();
330 new_password->date_created =
331 base::Time::FromInternalValue(password.date_created());
332 new_password->blacklisted_by_user = password.blacklisted();
333 }
334
335 std::string MakePasswordSyncTag(
336 const sync_pb::PasswordSpecificsData& password) {
337 return MakePasswordSyncTag(password.origin(),
338 password.username_element(),
339 password.username_value(),
340 password.password_element(),
341 password.signon_realm());
342 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698