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

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: 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
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.
Ilya Sherman 2013/11/05 08:39:21 nit: Please document the semantics of the return v
lipalani1 2013/11/19 00:46:54 Done. it is in the header file.
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() &&
52 UTF16ToUTF8(password_form.username_element) == 29 UTF16ToUTF8(password_form.username_element) ==
53 password_specifics.username_element() && 30 password_specifics.username_element() &&
(...skipping 10 matching lines...) Expand all
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
Ilya Sherman 2013/11/05 08:39:21 Optional nit: Omit this newline IMO
lipalani1 2013/11/19 00:46:54 Done.
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);
Ilya Sherman 2013/11/05 08:39:21 nit: Can you find a more descriptive name for this
lipalani1 2013/11/19 00:46:54 Done.
82
Ilya Sherman 2013/11/05 08:39:21 Optional nit: Omit this newline IMO.
lipalani1 2013/11/19 00:46:54 Done.
83 if (it == loaded_data->end()) {
84 // The sync data is not in password store, so we need to create it in
Ilya Sherman 2013/11/05 08:39:21 nit: "in password store" -> "in the password store
lipalani1 2013/11/19 00:46:54 Done.
85 // password store. Add the entry to the new_entries list.
86 autofill::PasswordForm* new_password = new autofill::PasswordForm();
Ilya Sherman 2013/11/05 08:39:21 Please store this in a scoped_ptr, and document ow
lipalani1 2013/11/19 00:46:54 Done.
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());
Ilya Sherman 2013/11/05 08:39:21 Hmm, if I'm reading this code correctly, it looks
lipalani1 2013/11/19 00:46:54 In this case the entries are merged. there could b
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);
Ilya Sherman 2013/11/05 08:39:21 Please define a wrapper function for this histogra
lipalani1 2013/11/19 00:46:54 Done.
130 merge_result.set_error(sync_error_factory->CreateAndUploadError(
131 FROM_HERE,
132 "Failed to get passwords from store."));
133 return merge_result;;
Ilya Sherman 2013/11/05 08:39:21 nit: Duplicate semicolon.
lipalani1 2013/11/19 00:46:54 Done.
134 }
135
136 PasswordEntryMap new_db_entries;
Ilya Sherman 2013/11/05 08:39:21 nit: "db" -> "database" or "local"
lipalani1 2013/11/19 00:46:54 Done.
137 for (std::vector<autofill::PasswordForm*>::iterator
Ilya Sherman 2013/11/05 08:39:21 nit: Since you do have a typedef for this type, wh
lipalani1 2013/11/19 00:46:54 Done.
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.
Ilya Sherman 2013/11/05 08:39:21 nit: This second sentence is worded a little bit s
lipalani1 2013/11/19 00:46:54 Done.
144 new_db_entries[MakeTag(**it)] = *it;
Ilya Sherman 2013/11/05 08:39:21 nit: This line might be easier to read if the prev
lipalani1 2013/11/19 00:46:54 Done.
145 }
146
147 merge_result.set_num_items_before_association(new_db_entries.size());
148
149 // List that contains the entries that are known only to sync.
150 ScopedVector<autofill::PasswordForm> new_sync_entries;
151
152 // List that contains the entries that are known to both sync and db but
153 // have to be updated in sync.
Ilya Sherman 2013/11/05 08:39:21 Are these entries that need to be updated in Sync,
lipalani1 2013/11/19 00:46:54 Done.
154 ScopedVector<autofill::PasswordForm> updated_sync_entries;
Ilya Sherman 2013/11/05 08:39:21 Thanks, the comments for both this variable and th
lipalani1 2013/11/19 00:46:54 Done.
155
156 // Changes from password db that needs to be propagated to sync.
157 syncer::SyncChangeList db_changes;
158 for (syncer::SyncDataList::const_iterator sync_iter =
159 initial_sync_data.begin();
160 sync_iter != initial_sync_data.end(); ++sync_iter) {
161 CreateOrUpdateEntry(*sync_iter,
162 &new_db_entries,
163 &new_sync_entries,
164 &updated_sync_entries,
165 &db_changes);
166 }
167
168 WriteToPasswordStore(new_sync_entries.get(),
169 updated_sync_entries.get());
170
171 merge_result.set_num_items_after_association(
172 merge_result.num_items_before_association() + new_sync_entries.size());
173
174 merge_result.set_num_items_added(new_sync_entries.size());
Ilya Sherman 2013/11/05 08:39:21 Out of curiosity, why does the Sync API require cl
lipalani1 2013/11/19 00:46:54 these stats will get uploaded to the server. Havin
175
176 merge_result.set_num_items_modified(updated_sync_entries.size());
177
178 for (PasswordEntryMap::iterator it = new_db_entries.begin();
179 it != new_db_entries.end();
180 ++it) {
181 db_changes.push_back(syncer::SyncChange(FROM_HERE,
182 syncer::SyncChange::ACTION_ADD,
183 CreateSyncData(*(it->second))));
184 }
185
186 merge_result.set_error(
187 sync_processor_->ProcessSyncChanges(FROM_HERE, db_changes));
102 return merge_result; 188 return merge_result;
103 } 189 }
104 190
105 void PasswordSyncableService::StopSyncing(syncer::ModelType type) { 191 void PasswordSyncableService::StopSyncing(syncer::ModelType type) {
106 } 192 }
107 193
108 syncer::SyncDataList PasswordSyncableService::GetAllSyncData( 194 syncer::SyncDataList PasswordSyncableService::GetAllSyncData(
109 syncer::ModelType type) const { 195 syncer::ModelType type) const {
110 syncer::SyncDataList sync_data; 196 syncer::SyncDataList sync_data;
111 return sync_data; 197 return sync_data;
112 } 198 }
113 199
114 syncer::SyncError PasswordSyncableService::ProcessSyncChanges( 200 syncer::SyncError PasswordSyncableService::ProcessSyncChanges(
115 const tracked_objects::Location& from_here, 201 const tracked_objects::Location& from_here,
116 const syncer::SyncChangeList& change_list) { 202 const syncer::SyncChangeList& change_list) {
117 syncer::SyncError error(FROM_HERE, 203 syncer::SyncError error(FROM_HERE,
118 syncer::SyncError::UNRECOVERABLE_ERROR, 204 syncer::SyncError::UNRECOVERABLE_ERROR,
119 "Password Syncable Service Not Implemented.", 205 "Password Syncable Service Not Implemented.",
120 syncer::PASSWORDS); 206 syncer::PASSWORDS);
121 return error; 207 return error;
122 } 208 }
123 209
124 void PasswordSyncableService::WriteToPasswordStore( 210 void PasswordSyncableService::WriteToPasswordStore(
125 PasswordForms* new_entries, 211 const PasswordForms& new_entries,
126 PasswordForms* updated_entries) { 212 const PasswordForms& updated_entries) {
127 for (std::vector<autofill::PasswordForm*>::const_iterator it = 213 for (std::vector<autofill::PasswordForm*>::const_iterator it =
128 new_entries->begin(); 214 new_entries.begin();
129 it != new_entries->end(); 215 it != new_entries.end();
130 ++it) { 216 ++it) {
131 password_store_->AddLoginImpl(**it); 217 password_store_->AddLoginImpl(**it);
132 } 218 }
133 219
134 for (std::vector<autofill::PasswordForm*>::const_iterator it = 220 for (std::vector<autofill::PasswordForm*>::const_iterator it =
135 updated_entries->begin(); 221 updated_entries.begin();
136 it != updated_entries->end(); 222 it != updated_entries.end();
137 ++it) { 223 ++it) {
138 password_store_->UpdateLoginImpl(**it); 224 password_store_->UpdateLoginImpl(**it);
139 } 225 }
140 226
141 if (!new_entries->empty() || !updated_entries->empty()) { 227 if (!new_entries.empty() || !updated_entries.empty()) {
142 // We have to notify password store observers of the change by hand since 228 // We have to notify password store observers of the change by hand since
143 // we use internal password store interfaces to make changes synchronously. 229 // we use internal password store interfaces to make changes synchronously.
144 password_store_->PostNotifyLoginsChanged(); 230 NotifyPasswordStore();
145 } 231 }
146 } 232 }
147 233
234 void PasswordSyncableService::NotifyPasswordStore() {
235 password_store_->PostNotifyLoginsChanged();
236 }
237
148 syncer::SyncData PasswordSyncableService::CreateSyncData( 238 syncer::SyncData PasswordSyncableService::CreateSyncData(
149 const autofill::PasswordForm& password_form) { 239 const autofill::PasswordForm& password_form) {
150 sync_pb::EntitySpecifics password_data; 240 sync_pb::EntitySpecifics password_data;
151 sync_pb::PasswordSpecificsData* password_specifics = 241 sync_pb::PasswordSpecificsData* password_specifics =
152 password_data.mutable_password()->mutable_client_only_encrypted_data(); 242 password_data.mutable_password()->mutable_client_only_encrypted_data();
153 password_specifics->set_scheme(password_form.scheme); 243 password_specifics->set_scheme(password_form.scheme);
154 password_specifics->set_signon_realm(password_form.signon_realm); 244 password_specifics->set_signon_realm(password_form.signon_realm);
155 password_specifics->set_origin(password_form.origin.spec()); 245 password_specifics->set_origin(password_form.origin.spec());
156 password_specifics->set_action(password_form.action.spec()); 246 password_specifics->set_action(password_form.action.spec());
157 password_specifics->set_username_element( 247 password_specifics->set_username_element(
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 // static 289 // static
200 std::string PasswordSyncableService::MakeTag( 290 std::string PasswordSyncableService::MakeTag(
201 const sync_pb::PasswordSpecificsData& password) { 291 const sync_pb::PasswordSpecificsData& password) {
202 return MakeTag(password.origin(), 292 return MakeTag(password.origin(),
203 password.username_element(), 293 password.username_element(),
204 password.username_value(), 294 password.username_value(),
205 password.password_element(), 295 password.password_element(),
206 password.signon_realm()); 296 password.signon_realm());
207 } 297 }
208 298
299 // static
300 void PasswordSyncableService::ExtractPasswordFromSpecifics(
301 const sync_pb::PasswordSpecificsData& password,
302 autofill::PasswordForm* new_password) {
303 new_password->scheme =
304 static_cast<autofill::PasswordForm::Scheme>(password.scheme());
305 new_password->signon_realm = password.signon_realm();
306 new_password->origin = GURL(password.origin());
307 new_password->action = GURL(password.action());
308 new_password->username_element =
309 UTF8ToUTF16(password.username_element());
310 new_password->password_element =
311 UTF8ToUTF16(password.password_element());
312 new_password->username_value =
313 UTF8ToUTF16(password.username_value());
314 new_password->password_value =
315 UTF8ToUTF16(password.password_value());
316 new_password->ssl_valid = password.ssl_valid();
317 new_password->preferred = password.preferred();
318 new_password->date_created =
319 base::Time::FromInternalValue(password.date_created());
320 new_password->blacklisted_by_user =
321 password.blacklisted();
322 }
323
Ilya Sherman 2013/11/05 08:39:21 nit: Spurious newline.
lipalani1 2013/11/19 00:46:54 Done.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698