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

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

Issue 27233003: [Sync] Implementation of model association for passwords using sync API (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: For review Created 7 years, 1 month 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"
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
17 bool PasswordSyncableService::MergeLocalAndSyncPasswords(
18 const sync_pb::PasswordSpecificsData& password_specifics,
19 const autofill::PasswordForm& password_form,
20 autofill::PasswordForm* new_password_form) {
21 if (password_specifics.scheme() == password_form.scheme &&
22 password_form.signon_realm == password_specifics.signon_realm() &&
23 password_form.origin.spec() == password_specifics.origin() &&
24 password_form.action.spec() == password_specifics.action() &&
25 UTF16ToUTF8(password_form.username_element) ==
26 password_specifics.username_element() &&
27 UTF16ToUTF8(password_form.password_element) ==
28 password_specifics.password_element() &&
29 UTF16ToUTF8(password_form.username_value) ==
30 password_specifics.username_value() &&
31 UTF16ToUTF8(password_form.password_value) ==
32 password_specifics.password_value() &&
33 password_specifics.ssl_valid() == password_form.ssl_valid &&
34 password_specifics.preferred() == password_form.preferred &&
35 password_specifics.date_created() ==
36 password_form.date_created.ToInternalValue() &&
37 password_specifics.blacklisted() ==
38 password_form.blacklisted_by_user) {
39 return false;
40 }
41
42 // If the passwords differ, take the one that was created more recently.
43 if (base::Time::FromInternalValue(password_specifics.date_created()) <=
44 password_form.date_created) {
45 *new_password_form = password_form;
46 } else {
47 PasswordSyncableService::ExtractPasswordFromSpecifics(
48 password_specifics,
49 new_password_form);
50 }
51
52 return true;
53 }
Ilya Sherman 2013/11/19 22:49:04 Can this method be tucked into an anonymous namesp
lipalani1 2013/11/26 23:31:35 it calls into other private methods inside the cla
54
14 PasswordSyncableService::PasswordSyncableService( 55 PasswordSyncableService::PasswordSyncableService(
15 scoped_refptr<PasswordStore> password_store) 56 scoped_refptr<PasswordStore> password_store)
16 : password_store_(password_store) { 57 : password_store_(password_store) {
17 } 58 }
18 59
19 PasswordSyncableService::~PasswordSyncableService() {} 60 PasswordSyncableService::~PasswordSyncableService() {}
20 61
62 void PasswordSyncableService::CreateOrUpdateEntry(
63 const syncer::SyncData& data,
64 PasswordEntryMap* loaded_data,
65 ScopedVector<autofill::PasswordForm>* new_entries,
66 ScopedVector<autofill::PasswordForm>* updated_entries,
67 syncer::SyncChangeList* updated_db_entries) {
68 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics();
69 const sync_pb::PasswordSpecificsData& password_specifics(
70 specifics.password().client_only_encrypted_data());
Ilya Sherman 2013/11/19 22:49:04 Could you explain to me what |client_only_encrypte
lipalani1 2013/11/26 23:31:35 This is the way things are stored in sync internal
Ilya Sherman 2013/12/05 07:01:54 Ok. That is a pretty confusing name for the field
71 std::string tag = MakeTag(password_specifics);
72
73 // Find if the data from sync is already in password store.
Ilya Sherman 2013/11/19 22:49:04 nit: "Find if" -> "Check whether" or "Test whether
lipalani1 2013/11/26 23:31:35 Done.
74 PasswordEntryMap::iterator loaded_data_index = loaded_data->find(tag);
Ilya Sherman 2013/11/19 22:49:04 nit: "index" -> "iter"
lipalani1 2013/11/26 23:31:35 Done.
75 if (loaded_data_index == loaded_data->end()) {
76 // The sync data is not in the password store, so we need to create it in
77 // the password store. Add the entry to the new_entries list.
78 scoped_ptr<autofill::PasswordForm> new_password(
79 new autofill::PasswordForm());
80 ExtractPasswordFromSpecifics(password_specifics, new_password.get());
81 new_entries->push_back(new_password.release());
82 } else {
83 // The entry is in password store. If the entries are not identical the
Ilya Sherman 2013/11/19 22:49:04 nit: "are not identical the entries" -> "are not i
lipalani1 2013/11/26 23:31:35 Done.
84 // entries need to be merged.
85 scoped_ptr<autofill::PasswordForm> new_password(
86 new autofill::PasswordForm());
87 if (MergeLocalAndSyncPasswords(password_specifics,
88 *(loaded_data_index->second),
89 new_password.get())) {
Ilya Sherman 2013/11/19 22:49:04 Please add a comment within this if-stmt along the
lipalani1 2013/11/26 23:31:35 Done.
90 updated_db_entries->push_back(
91 syncer::SyncChange(FROM_HERE,
92 syncer::SyncChange::ACTION_UPDATE,
93 CreateSyncData(*(new_password.get()))));
94
95 updated_entries->push_back(new_password.release());
96 }
97 // Remove the entry from the entry map to indicate a match has been found.
98 // Entries that remain in the map at the end of associating all sync entries
99 // will be treated as additions that needs to be propagated to sync.
100 loaded_data->erase(loaded_data_index);
Ilya Sherman 2013/11/19 22:49:04 The comment in the header strongly implies that en
lipalani1 2013/11/26 23:31:35 Done.
101 }
102 }
103
21 syncer::SyncMergeResult 104 syncer::SyncMergeResult
22 PasswordSyncableService::MergeDataAndStartSyncing( 105 PasswordSyncableService::MergeDataAndStartSyncing(
23 syncer::ModelType type, 106 syncer::ModelType type,
24 const syncer::SyncDataList& initial_sync_data, 107 const syncer::SyncDataList& initial_sync_data,
25 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, 108 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
26 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { 109 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
27 syncer::SyncMergeResult merge_result(type); 110 syncer::SyncMergeResult merge_result(type);
28 sync_error_factory_ = sync_error_factory.Pass(); 111 sync_error_factory_ = sync_error_factory.Pass();
29 sync_processor_ = sync_processor.Pass(); 112 sync_processor_ = sync_processor.Pass();
30 113
31 merge_result.set_error(sync_error_factory->CreateAndUploadError( 114 ScopedVector<autofill::PasswordForm> password_entries;
32 FROM_HERE, 115 if (!password_store_->FillAutofillableLogins(&(password_entries.get())) ||
33 "Password Syncable Service Not Implemented.")); 116 !password_store_->FillBlacklistLogins(&(password_entries.get()))) {
117 // Password store often fails to load passwords. Track failures with UMA.
118 // (http://crbug.com/249000)
119 syncer::SyncError::LogDataLoadFailure(syncer::PASSWORDS);
120 merge_result.set_error(sync_error_factory->CreateAndUploadError(
121 FROM_HERE,
122 "Failed to get passwords from store."));
123 return merge_result;
124 }
125
126 PasswordEntryMap new_local_entries;
127 for (PasswordForms::iterator it = password_entries.begin();
128 it != password_entries.end();
129 ++it) {
130 autofill::PasswordForm* password_form = *it;
131 // We add all the db entries as |new_local_entries| initially. While model
132 // association entries that match a sync entry will be removed and this
Ilya Sherman 2013/11/19 22:49:04 nit: "While model association entries" -> "During
lipalani1 2013/11/26 23:31:35 Done.
133 // list will only contain entries that are not in sync.
134 new_local_entries[MakeTag(*password_form)] = password_form;
135 }
136
137 merge_result.set_num_items_before_association(new_local_entries.size());
138
139 // List that contains the entries that are known only to sync.
Ilya Sherman 2013/11/19 22:49:04 nit: Needing comments like these generally implies
lipalani1 2013/11/26 23:31:35 These names will make sense when looking at it as
140 ScopedVector<autofill::PasswordForm> new_sync_entries;
141
142 // List that contains the entries that are known to both sync and db but
143 // have updates in sync. They need to be updated in the passwords db.
144 ScopedVector<autofill::PasswordForm> updated_sync_entries;
145
146 // Changes from password db that needs to be propagated to sync.
Ilya Sherman 2013/11/19 22:49:04 nit: "needs" -> "need"
lipalani1 2013/11/26 23:31:35 Done.
147 syncer::SyncChangeList db_changes;
Ilya Sherman 2013/11/19 22:49:04 Optional nit: I'd suggest leaving a blank line aft
lipalani1 2013/11/26 23:31:35 Done.
148 for (syncer::SyncDataList::const_iterator sync_iter =
149 initial_sync_data.begin();
150 sync_iter != initial_sync_data.end(); ++sync_iter) {
151 CreateOrUpdateEntry(*sync_iter,
152 &new_local_entries,
153 &new_sync_entries,
154 &updated_sync_entries,
155 &db_changes);
156 }
157
158 WriteToPasswordStore(new_sync_entries.get(),
159 updated_sync_entries.get());
Ilya Sherman 2013/11/19 22:49:04 Does this line compile? It looks like you're pass
lipalani1 2013/11/26 23:31:35 Done.
160
161 merge_result.set_num_items_after_association(
162 merge_result.num_items_before_association() + new_sync_entries.size());
163
164 merge_result.set_num_items_added(new_sync_entries.size());
165
166 merge_result.set_num_items_modified(updated_sync_entries.size());
167
168 for (PasswordEntryMap::iterator it = new_local_entries.begin();
169 it != new_local_entries.end();
170 ++it) {
171 db_changes.push_back(syncer::SyncChange(FROM_HERE,
172 syncer::SyncChange::ACTION_ADD,
173 CreateSyncData(*(it->second))));
174 }
175
176 merge_result.set_error(
177 sync_processor_->ProcessSyncChanges(FROM_HERE, db_changes));
34 return merge_result; 178 return merge_result;
35 } 179 }
36 180
37 void PasswordSyncableService::StopSyncing(syncer::ModelType type) { 181 void PasswordSyncableService::StopSyncing(syncer::ModelType type) {
38 } 182 }
39 183
40 syncer::SyncDataList PasswordSyncableService::GetAllSyncData( 184 syncer::SyncDataList PasswordSyncableService::GetAllSyncData(
41 syncer::ModelType type) const { 185 syncer::ModelType type) const {
42 syncer::SyncDataList sync_data; 186 syncer::SyncDataList sync_data;
43 return sync_data; 187 return sync_data;
44 } 188 }
45 189
46 syncer::SyncError PasswordSyncableService::ProcessSyncChanges( 190 syncer::SyncError PasswordSyncableService::ProcessSyncChanges(
47 const tracked_objects::Location& from_here, 191 const tracked_objects::Location& from_here,
48 const syncer::SyncChangeList& change_list) { 192 const syncer::SyncChangeList& change_list) {
49 syncer::SyncError error(FROM_HERE, 193 syncer::SyncError error(FROM_HERE,
50 syncer::SyncError::UNRECOVERABLE_ERROR, 194 syncer::SyncError::UNRECOVERABLE_ERROR,
51 "Password Syncable Service Not Implemented.", 195 "Password Syncable Service Not Implemented.",
52 syncer::PASSWORDS); 196 syncer::PASSWORDS);
53 return error; 197 return error;
54 } 198 }
55 199
56 void PasswordSyncableService::WriteToPasswordStore( 200 void PasswordSyncableService::WriteToPasswordStore(
57 PasswordForms* new_entries, 201 const PasswordForms& new_entries,
58 PasswordForms* updated_entries) { 202 const PasswordForms& updated_entries) {
59 for (std::vector<autofill::PasswordForm*>::const_iterator it = 203 for (std::vector<autofill::PasswordForm*>::const_iterator it =
60 new_entries->begin(); 204 new_entries.begin();
61 it != new_entries->end(); 205 it != new_entries.end();
62 ++it) { 206 ++it) {
63 password_store_->AddLoginImpl(**it); 207 password_store_->AddLoginImpl(**it);
64 } 208 }
65 209
66 for (std::vector<autofill::PasswordForm*>::const_iterator it = 210 for (std::vector<autofill::PasswordForm*>::const_iterator it =
67 updated_entries->begin(); 211 updated_entries.begin();
68 it != updated_entries->end(); 212 it != updated_entries.end();
69 ++it) { 213 ++it) {
70 password_store_->UpdateLoginImpl(**it); 214 password_store_->UpdateLoginImpl(**it);
71 } 215 }
72 216
73 if (!new_entries->empty() || !updated_entries->empty()) { 217 if (!new_entries.empty() || !updated_entries.empty()) {
74 // We have to notify password store observers of the change by hand since 218 // We have to notify password store observers of the change by hand since
75 // we use internal password store interfaces to make changes synchronously. 219 // we use internal password store interfaces to make changes synchronously.
76 password_store_->PostNotifyLoginsChanged(); 220 NotifyPasswordStoreOfLoginChanges();
77 } 221 }
78 } 222 }
79 223
224 void PasswordSyncableService::NotifyPasswordStoreOfLoginChanges() {
225 password_store_->PostNotifyLoginsChanged();
226 }
227
80 syncer::SyncData PasswordSyncableService::CreateSyncData( 228 syncer::SyncData PasswordSyncableService::CreateSyncData(
81 const autofill::PasswordForm& password_form) { 229 const autofill::PasswordForm& password_form) {
82 sync_pb::EntitySpecifics password_data; 230 sync_pb::EntitySpecifics password_data;
83 sync_pb::PasswordSpecificsData* password_specifics = 231 sync_pb::PasswordSpecificsData* password_specifics =
84 password_data.mutable_password()->mutable_client_only_encrypted_data(); 232 password_data.mutable_password()->mutable_client_only_encrypted_data();
85 password_specifics->set_scheme(password_form.scheme); 233 password_specifics->set_scheme(password_form.scheme);
86 password_specifics->set_signon_realm(password_form.signon_realm); 234 password_specifics->set_signon_realm(password_form.signon_realm);
87 password_specifics->set_origin(password_form.origin.spec()); 235 password_specifics->set_origin(password_form.origin.spec());
88 password_specifics->set_action(password_form.action.spec()); 236 password_specifics->set_action(password_form.action.spec());
89 password_specifics->set_username_element( 237 password_specifics->set_username_element(
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 // static 279 // static
132 std::string PasswordSyncableService::MakeTag( 280 std::string PasswordSyncableService::MakeTag(
133 const sync_pb::PasswordSpecificsData& password) { 281 const sync_pb::PasswordSpecificsData& password) {
134 return MakeTag(password.origin(), 282 return MakeTag(password.origin(),
135 password.username_element(), 283 password.username_element(),
136 password.username_value(), 284 password.username_value(),
137 password.password_element(), 285 password.password_element(),
138 password.signon_realm()); 286 password.signon_realm());
139 } 287 }
140 288
289 // static
290 void PasswordSyncableService::ExtractPasswordFromSpecifics(
291 const sync_pb::PasswordSpecificsData& password,
292 autofill::PasswordForm* new_password) {
293 new_password->scheme =
294 static_cast<autofill::PasswordForm::Scheme>(password.scheme());
295 new_password->signon_realm = password.signon_realm();
296 new_password->origin = GURL(password.origin());
297 new_password->action = GURL(password.action());
298 new_password->username_element =
299 UTF8ToUTF16(password.username_element());
300 new_password->password_element =
301 UTF8ToUTF16(password.password_element());
302 new_password->username_value =
303 UTF8ToUTF16(password.username_value());
304 new_password->password_value =
305 UTF8ToUTF16(password.password_value());
306 new_password->ssl_valid = password.ssl_valid();
307 new_password->preferred = password.preferred();
308 new_password->date_created =
309 base::Time::FromInternalValue(password.date_created());
310 new_password->blacklisted_by_user =
311 password.blacklisted();
312 }
Ilya Sherman 2013/11/19 22:49:04 Can this be tucked into the anonymous namespace, r
lipalani1 2013/11/26 23:31:35 Are used in test cases. On 2013/11/19 22:49:04, Il
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698