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

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 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"
Ilya Sherman 2013/12/05 07:01:54 nit: Redundant with the header's include.
9 #include "base/metrics/histogram.h"
Ilya Sherman 2013/12/05 07:01:54 nit: unused.
10 #include "base/stl_util.h"
Ilya Sherman 2013/12/05 07:01:54 nit: unused?
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/12/05 07:01:54 nit: Please arrange the code in the implementation
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* umatched_data_from_password_db,
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());
71 std::string tag = MakeTag(password_specifics);
72
73 // Check whether the data from sync is already in password store.
Ilya Sherman 2013/12/05 07:01:54 nit: "in password store" -> "in the password store
74 PasswordEntryMap::iterator umatched_data_from_password_db_iter =
Ilya Sherman 2013/12/05 07:01:54 nit: Perhaps name this something more like "existi
75 umatched_data_from_password_db->find(tag);
76 if (umatched_data_from_password_db_iter ==
77 umatched_data_from_password_db->end()) {
Ilya Sherman 2013/12/05 07:01:54 nit: Please indent this line four more spaces.
78 // The sync data is not in the password store, so we need to create it in
79 // the password store. Add the entry to the new_entries list.
80 scoped_ptr<autofill::PasswordForm> new_password(
81 new autofill::PasswordForm());
82 ExtractPasswordFromSpecifics(password_specifics, new_password.get());
83 new_entries->push_back(new_password.release());
84 } else {
85 // The entry is in password store. If the entries are not identical, then
86 // the entries need to be merged.
87 scoped_ptr<autofill::PasswordForm> new_password(
88 new autofill::PasswordForm());
89 if (MergeLocalAndSyncPasswords(password_specifics,
90 *(umatched_data_from_password_db_iter->second),
91 new_password.get())) {
92 // It is possible that both the sync database and the passwords
93 // database need to be updated to reflect the merged data. Rather
94 // than checking we simply update both.
Ilya Sherman 2013/12/05 07:01:54 Is it actually possible that both need to be updat
95 updated_db_entries->push_back(
96 syncer::SyncChange(FROM_HERE,
97 syncer::SyncChange::ACTION_UPDATE,
98 CreateSyncData(*(new_password.get()))));
99
100 updated_entries->push_back(new_password.release());
101 }
102 // Remove the entry from the entry map to indicate a match has been found.
103 // Entries that remain in the map at the end of associating all sync entries
104 // will be treated as additions that need to be propagated to sync.
105 umatched_data_from_password_db->erase(umatched_data_from_password_db_iter);
106 }
107 }
108
21 syncer::SyncMergeResult 109 syncer::SyncMergeResult
22 PasswordSyncableService::MergeDataAndStartSyncing( 110 PasswordSyncableService::MergeDataAndStartSyncing(
23 syncer::ModelType type, 111 syncer::ModelType type,
24 const syncer::SyncDataList& initial_sync_data, 112 const syncer::SyncDataList& initial_sync_data,
25 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, 113 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
26 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { 114 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
27 syncer::SyncMergeResult merge_result(type); 115 syncer::SyncMergeResult merge_result(type);
28 sync_error_factory_ = sync_error_factory.Pass(); 116 sync_error_factory_ = sync_error_factory.Pass();
29 sync_processor_ = sync_processor.Pass(); 117 sync_processor_ = sync_processor.Pass();
30 118
31 merge_result.set_error(sync_error_factory->CreateAndUploadError( 119 ScopedVector<autofill::PasswordForm> password_entries;
32 FROM_HERE, 120 if (!password_store_->FillAutofillableLogins(&(password_entries.get()))) {
33 "Password Syncable Service Not Implemented.")); 121 // Password store often fails to load passwords. Track failures with UMA.
122 // (http://crbug.com/249000)
123 syncer::SyncError::LogDataLoadFailure(syncer::PASSWORDS);
124 merge_result.set_error(sync_error_factory->CreateAndUploadError(
125 FROM_HERE,
126 "Failed to get passwords from store."));
127 return merge_result;
128 }
129
130 PasswordEntryMap new_local_entries;
131 for (PasswordForms::iterator it = password_entries.begin();
132 it != password_entries.end();
133 ++it) {
134 autofill::PasswordForm* password_form = *it;
135 // We add all the db entries as |new_local_entries| initially. During
136 // model association entries that match a sync entry will be
137 // removed and this list will only contain entries that are not in sync.
138 new_local_entries[MakeTag(*password_form)] = password_form;
139 }
140
141 merge_result.set_num_items_before_association(new_local_entries.size());
142
143 // List that contains the entries that are known only to sync.
144 ScopedVector<autofill::PasswordForm> new_sync_entries;
145
146 // 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.
148 ScopedVector<autofill::PasswordForm> updated_sync_entries;
149
150 // Changes from password db that needs to be propagated to sync.
Ilya Sherman 2013/12/05 07:01:54 nit: "needs" -> "need"
151 syncer::SyncChangeList db_changes;
152 for (syncer::SyncDataList::const_iterator sync_iter =
153 initial_sync_data.begin();
154 sync_iter != initial_sync_data.end(); ++sync_iter) {
155 CreateOrUpdateEntry(*sync_iter,
156 &new_local_entries,
157 &new_sync_entries,
158 &updated_sync_entries,
159 &db_changes);
160 }
161
162 WriteToPasswordStore(new_sync_entries.get(),
163 updated_sync_entries.get());
164
165 merge_result.set_num_items_after_association(
166 merge_result.num_items_before_association() + new_sync_entries.size());
167
168 merge_result.set_num_items_added(new_sync_entries.size());
169
170 merge_result.set_num_items_modified(updated_sync_entries.size());
171
172 for (PasswordEntryMap::iterator it = new_local_entries.begin();
173 it != new_local_entries.end();
174 ++it) {
175 db_changes.push_back(syncer::SyncChange(FROM_HERE,
176 syncer::SyncChange::ACTION_ADD,
177 CreateSyncData(*(it->second))));
Ilya Sherman 2013/12/05 07:01:54 nit: Please align all three arguments to syncer::S
178 }
179
180 merge_result.set_error(
181 sync_processor_->ProcessSyncChanges(FROM_HERE, db_changes));
34 return merge_result; 182 return merge_result;
35 } 183 }
36 184
37 void PasswordSyncableService::StopSyncing(syncer::ModelType type) { 185 void PasswordSyncableService::StopSyncing(syncer::ModelType type) {
38 } 186 }
39 187
40 syncer::SyncDataList PasswordSyncableService::GetAllSyncData( 188 syncer::SyncDataList PasswordSyncableService::GetAllSyncData(
41 syncer::ModelType type) const { 189 syncer::ModelType type) const {
42 syncer::SyncDataList sync_data; 190 syncer::SyncDataList sync_data;
43 return sync_data; 191 return sync_data;
44 } 192 }
45 193
46 syncer::SyncError PasswordSyncableService::ProcessSyncChanges( 194 syncer::SyncError PasswordSyncableService::ProcessSyncChanges(
47 const tracked_objects::Location& from_here, 195 const tracked_objects::Location& from_here,
48 const syncer::SyncChangeList& change_list) { 196 const syncer::SyncChangeList& change_list) {
49 syncer::SyncError error(FROM_HERE, 197 syncer::SyncError error(FROM_HERE,
50 syncer::SyncError::UNRECOVERABLE_ERROR, 198 syncer::SyncError::UNRECOVERABLE_ERROR,
51 "Password Syncable Service Not Implemented.", 199 "Password Syncable Service Not Implemented.",
52 syncer::PASSWORDS); 200 syncer::PASSWORDS);
53 return error; 201 return error;
54 } 202 }
55 203
56 void PasswordSyncableService::WriteToPasswordStore( 204 void PasswordSyncableService::WriteToPasswordStore(
57 PasswordForms* new_entries, 205 const PasswordForms& new_entries,
58 PasswordForms* updated_entries) { 206 const PasswordForms& updated_entries) {
59 for (std::vector<autofill::PasswordForm*>::const_iterator it = 207 for (std::vector<autofill::PasswordForm*>::const_iterator it =
60 new_entries->begin(); 208 new_entries.begin();
61 it != new_entries->end(); 209 it != new_entries.end();
62 ++it) { 210 ++it) {
63 password_store_->AddLoginImpl(**it); 211 password_store_->AddLoginImpl(**it);
64 } 212 }
65 213
66 for (std::vector<autofill::PasswordForm*>::const_iterator it = 214 for (std::vector<autofill::PasswordForm*>::const_iterator it =
67 updated_entries->begin(); 215 updated_entries.begin();
68 it != updated_entries->end(); 216 it != updated_entries.end();
69 ++it) { 217 ++it) {
70 password_store_->UpdateLoginImpl(**it); 218 password_store_->UpdateLoginImpl(**it);
71 } 219 }
72 220
73 if (!new_entries->empty() || !updated_entries->empty()) { 221 if (!new_entries.empty() || !updated_entries.empty()) {
74 // We have to notify password store observers of the change by hand since 222 // We have to notify password store observers of the change by hand since
75 // we use internal password store interfaces to make changes synchronously. 223 // we use internal password store interfaces to make changes synchronously.
76 password_store_->PostNotifyLoginsChanged(); 224 NotifyPasswordStoreOfLoginChanges();
77 } 225 }
78 } 226 }
79 227
228 void PasswordSyncableService::NotifyPasswordStoreOfLoginChanges() {
229 password_store_->PostNotifyLoginsChanged();
230 }
231
80 syncer::SyncData PasswordSyncableService::CreateSyncData( 232 syncer::SyncData PasswordSyncableService::CreateSyncData(
81 const autofill::PasswordForm& password_form) { 233 const autofill::PasswordForm& password_form) {
82 sync_pb::EntitySpecifics password_data; 234 sync_pb::EntitySpecifics password_data;
83 sync_pb::PasswordSpecificsData* password_specifics = 235 sync_pb::PasswordSpecificsData* password_specifics =
84 password_data.mutable_password()->mutable_client_only_encrypted_data(); 236 password_data.mutable_password()->mutable_client_only_encrypted_data();
85 password_specifics->set_scheme(password_form.scheme); 237 password_specifics->set_scheme(password_form.scheme);
86 password_specifics->set_signon_realm(password_form.signon_realm); 238 password_specifics->set_signon_realm(password_form.signon_realm);
87 password_specifics->set_origin(password_form.origin.spec()); 239 password_specifics->set_origin(password_form.origin.spec());
88 password_specifics->set_action(password_form.action.spec()); 240 password_specifics->set_action(password_form.action.spec());
89 password_specifics->set_username_element( 241 password_specifics->set_username_element(
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 // static 283 // static
132 std::string PasswordSyncableService::MakeTag( 284 std::string PasswordSyncableService::MakeTag(
133 const sync_pb::PasswordSpecificsData& password) { 285 const sync_pb::PasswordSpecificsData& password) {
134 return MakeTag(password.origin(), 286 return MakeTag(password.origin(),
135 password.username_element(), 287 password.username_element(),
136 password.username_value(), 288 password.username_value(),
137 password.password_element(), 289 password.password_element(),
138 password.signon_realm()); 290 password.signon_realm());
139 } 291 }
140 292
293 // static
294 void PasswordSyncableService::ExtractPasswordFromSpecifics(
295 const sync_pb::PasswordSpecificsData& password,
296 autofill::PasswordForm* new_password) {
297 new_password->scheme =
298 static_cast<autofill::PasswordForm::Scheme>(password.scheme());
299 new_password->signon_realm = password.signon_realm();
300 new_password->origin = GURL(password.origin());
301 new_password->action = GURL(password.action());
302 new_password->username_element =
303 UTF8ToUTF16(password.username_element());
304 new_password->password_element =
305 UTF8ToUTF16(password.password_element());
306 new_password->username_value =
307 UTF8ToUTF16(password.username_value());
308 new_password->password_value =
309 UTF8ToUTF16(password.password_value());
310 new_password->ssl_valid = password.ssl_valid();
311 new_password->preferred = password.preferred();
312 new_password->date_created =
313 base::Time::FromInternalValue(password.date_created());
314 new_password->blacklisted_by_user =
315 password.blacklisted();
316 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698