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

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, 2 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 <set> 7 #include <set>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/location.h" 10 #include "base/location.h"
11 #include "base/memory/scoped_ptr.h" 11 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/scoped_vector.h" 12 #include "base/memory/scoped_vector.h"
13 #include "base/metrics/histogram.h" 13 #include "base/metrics/histogram.h"
14 #include "base/stl_util.h" 14 #include "base/stl_util.h"
15 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/password_manager/password_store.h" 16 #include "chrome/browser/password_manager/password_store.h"
17 #include "components/autofill/core/common/password_form.h" 17 #include "components/autofill/core/common/password_form.h"
18 #include "net/base/escape.h" 18 #include "net/base/escape.h"
19 #include "sync/api/sync_error.h" 19 #include "sync/api/sync_error.h"
20 #include "sync/api/sync_error_factory.h" 20 #include "sync/api/sync_error_factory.h"
21 21
22 namespace { 22 namespace {
23
24 void ExtractPasswordFromSpecifics(
25 const sync_pb::PasswordSpecificsData& password,
26 autofill::PasswordForm* new_password) {
27 new_password->scheme =
28 static_cast<autofill::PasswordForm::Scheme>(password.scheme());
29 new_password->signon_realm = password.signon_realm();
30 new_password->origin = GURL(password.origin());
31 new_password->action = GURL(password.action());
32 new_password->username_element =
33 UTF8ToUTF16(password.username_element());
34 new_password->password_element =
35 UTF8ToUTF16(password.password_element());
36 new_password->username_value =
37 UTF8ToUTF16(password.username_value());
38 new_password->password_value =
39 UTF8ToUTF16(password.password_value());
40 new_password->ssl_valid = password.ssl_valid();
41 new_password->preferred = password.preferred();
42 new_password->date_created =
43 base::Time::FromInternalValue(password.date_created());
44 new_password->blacklisted_by_user =
45 password.blacklisted();
46 }
47
48 bool MergeLocalAndSyncPasswords( 23 bool MergeLocalAndSyncPasswords(
49 const sync_pb::PasswordSpecificsData& password, 24 const sync_pb::PasswordSpecificsData& password,
50 const autofill::PasswordForm& password_form, 25 const autofill::PasswordForm& password_form,
51 autofill::PasswordForm* new_password) { 26 autofill::PasswordForm* new_password) {
52 DCHECK(new_password); 27 DCHECK(new_password);
53 28
54 if (password.scheme() == password_form.scheme && 29 if (password.scheme() == password_form.scheme &&
55 password_form.signon_realm == password.signon_realm() && 30 password_form.signon_realm == password.signon_realm() &&
56 password_form.origin.spec() == password.origin() && 31 password_form.origin.spec() == password.origin() &&
57 password_form.action.spec() == password.action() && 32 password_form.action.spec() == password.action() &&
(...skipping 10 matching lines...) Expand all
68 password.date_created() == password_form.date_created.ToInternalValue() && 43 password.date_created() == password_form.date_created.ToInternalValue() &&
69 password.blacklisted() == password_form.blacklisted_by_user) { 44 password.blacklisted() == password_form.blacklisted_by_user) {
70 return false; 45 return false;
71 } 46 }
72 47
73 // If the passwords differ, we take the one that was created more recently. 48 // If the passwords differ, we take the one that was created more recently.
74 if (base::Time::FromInternalValue(password.date_created()) <= 49 if (base::Time::FromInternalValue(password.date_created()) <=
75 password_form.date_created) { 50 password_form.date_created) {
76 *new_password = password_form; 51 *new_password = password_form;
77 } else { 52 } else {
78 ExtractPasswordFromSpecifics(password, new_password); 53 PasswordSyncableService::ExtractPasswordFromSpecifics(
54 password,
55 new_password);
79 } 56 }
80 57
81 return true; 58 return true;
82 } 59 }
83 60
84 } // namespace 61 } // namespace
85 62
86 PasswordSyncableService::PasswordSyncableService( 63 PasswordSyncableService::PasswordSyncableService(
87 PasswordStore* password_store) : password_store_(password_store) { 64 PasswordStore* password_store) : password_store_(password_store) {
88 } 65 }
89 66
90 PasswordSyncableService::~PasswordSyncableService() {} 67 PasswordSyncableService::~PasswordSyncableService() {}
91 68
69 void PasswordSyncableService::CreateOrUpdateEntry(
70 const syncer::SyncData& data,
71 PasswordEntryMap* loaded_data,
72 std::vector<autofill::PasswordForm*>* new_entries,
Nicolas Zea 2013/10/15 22:04:10 pass ScopedVectors instead?
lipalani1 2013/10/18 23:33:03 Done.
73 std::vector<autofill::PasswordForm*>* udpated_entries) {
Nicolas Zea 2013/10/15 22:04:10 udpated -> updated
lipalani1 2013/10/18 23:33:03 Done.
74 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics();
75 const sync_pb::PasswordSpecificsData& password_specifics(
76 specifics.password().client_only_encrypted_data());
77
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);
82
83 if (it == loaded_data->end()) {
84 // The sync data is not in password store, so we need to create it in
85 // passowrd store. Add the entry to the new_entries list.
Nicolas Zea 2013/10/15 22:04:10 passowrd -> password
lipalani1 2013/10/18 23:33:03 Done.
86 autofill::PasswordForm* new_password = new autofill::PasswordForm();
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.second),
97 new_password.get())) {
Nicolas Zea 2013/10/15 22:04:10 fix indent
lipalani1 2013/10/18 23:33:03 Done.
98 delete *(it->second.second);
99 *(it->second.second) = new_password.release();
100 it->second.first = syncer::SyncChange::ACTION_UPDATE;
101
102 // Make a copy for updated list.
103 autofill::PasswordForm* updated_password = new autofill::PasswordForm();
104 *updated_password = **(it->second.second);
105 udpated_entries->push_back(updated_password);
106 } else {
107 // The entries are identical. Remove it from the |loaded_data| list to
108 // prevent it from being treated as an unassociated entry.
109 loaded_data->erase(it);
110 }
111 }
112 }
113
92 syncer::SyncMergeResult 114 syncer::SyncMergeResult
93 PasswordSyncableService::MergeDataAndStartSyncing( 115 PasswordSyncableService::MergeDataAndStartSyncing(
94 syncer::ModelType type, 116 syncer::ModelType type,
95 const syncer::SyncDataList& initial_sync_data, 117 const syncer::SyncDataList& initial_sync_data,
96 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, 118 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
97 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { 119 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
98 syncer::SyncMergeResult merge_result(type); 120 syncer::SyncMergeResult merge_result(type);
99 sync_error_factory_ = sync_error_factory.Pass(); 121 sync_error_factory_ = sync_error_factory.Pass();
100 sync_processor_ = sync_processor.Pass(); 122 sync_processor_ = sync_processor.Pass();
101 merge_result.set_error(sync_error_factory->CreateAndUploadError( 123
102 FROM_HERE, 124 ScopedVector<autofill::PasswordForm> password_entries;
103 "Password Syncable Service Not Implemented.")); 125 if (!password_store_->FillAutofillableLogins(&(password_entries.get())) ||
126 !password_store_->FillBlacklistLogins(&(password_entries.get()))) {
127 STLDeleteElements(&password_entries);
128
129 // Password store often fails to load passwords. Track failures with UMA.
130 // (http://crbug.com/249000)
131 UMA_HISTOGRAM_ENUMERATION("Sync.LocalDataFailedToLoad",
132 ModelTypeToHistogramInt(syncer::PASSWORDS),
133 syncer::MODEL_TYPE_COUNT);
134 merge_result.set_error(sync_error_factory->CreateAndUploadError(
135 FROM_HERE,
136 "Failed to get passwords from store."));
137 return merge_result;;
138 }
139
140 PasswordEntryMap new_db_entries;
Nicolas Zea 2013/10/15 22:04:10 I think it's cleaner to track the entries separate
lipalani1 2013/10/18 23:33:03 Possible I am missing something here: delete *(it-
Nicolas Zea 2013/10/21 23:55:14 I'm not really suggesting to have two lists for tr
141 for (std::vector<autofill::PasswordForm*>::iterator
142 it = password_entries.begin();
Nicolas Zea 2013/10/15 22:04:10 indent four more spaces
lipalani1 2013/10/18 23:33:03 Done.
143 it != password_entries.end();
144 ++it) {
145 // We add all the db entries as |new_db_entries| initially. While
146 // association entries with matching sync entries will be removed and this
147 // list will only contain entries that are not in sync.
148 new_db_entries[MakeTag(**it)] =
149 std::make_pair(syncer::SyncChange::ACTION_ADD, it);
150 }
151
152 // List that contains the entries that are known only to sync.
153 ScopedVector<autofill::PasswordForm> new_synced_entries;
154
155 // List that contains the entries that are known to both sync and db but
156 // have to be updated in sync.
157 ScopedVector<autofill::PasswordForm> updated_sync_entries;
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_synced_entries.get()),
164 &(updated_sync_entries.get()));
165 }
166
167 WriteToPasswordStore(&(new_synced_entries.get()),
168 &(updated_sync_entries.get()));
169
170 syncer::SyncChangeList new_changes;
171 for (PasswordEntryMap::iterator it = new_db_entries.begin();
172 it != new_db_entries.end();
173 ++it) {
174 new_changes.push_back(syncer::SyncChange(FROM_HERE,
175 it->second.first,
176 CreateSyncData(**(it->second.second))));
177 }
178
179 merge_result.set_error(
180 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes));
104 return merge_result; 181 return merge_result;
105 } 182 }
106 183
107 void PasswordSyncableService::StopSyncing(syncer::ModelType type) { 184 void PasswordSyncableService::StopSyncing(syncer::ModelType type) {
108 } 185 }
109 186
110 syncer::SyncDataList PasswordSyncableService::GetAllSyncData( 187 syncer::SyncDataList PasswordSyncableService::GetAllSyncData(
111 syncer::ModelType type) const { 188 syncer::ModelType type) const {
112 syncer::SyncDataList sync_data; 189 syncer::SyncDataList sync_data;
113 return sync_data; 190 return sync_data;
(...skipping 24 matching lines...) Expand all
138 updated_entries->begin(); 215 updated_entries->begin();
139 it != updated_entries->end(); 216 it != updated_entries->end();
140 ++it) { 217 ++it) {
141 password_store_->UpdateLoginImpl(**it); 218 password_store_->UpdateLoginImpl(**it);
142 } 219 }
143 220
144 if (new_entries->size() > 0 || 221 if (new_entries->size() > 0 ||
145 updated_entries->size() > 0) { 222 updated_entries->size() > 0) {
146 // We have to notify password store observers of the change by hand since 223 // We have to notify password store observers of the change by hand since
147 // we use internal password store interfaces to make changes synchronously. 224 // we use internal password store interfaces to make changes synchronously.
148 password_store_->PostNotifyLoginsChanged(); 225 NotifyPasswordStore();
149 } 226 }
150 return true; 227 return true;
151 } 228 }
152 229
230 void PasswordSyncableService::NotifyPasswordStore() {
231 password_store_->PostNotifyLoginsChanged();
232 }
233
153 syncer::SyncData PasswordSyncableService::CreateSyncData( 234 syncer::SyncData PasswordSyncableService::CreateSyncData(
154 const autofill::PasswordForm& password_form) { 235 const autofill::PasswordForm& password_form) {
155 sync_pb::EntitySpecifics password_data; 236 sync_pb::EntitySpecifics password_data;
156 sync_pb::PasswordSpecificsData* password_specifics = 237 sync_pb::PasswordSpecificsData* password_specifics =
157 password_data.mutable_password()->mutable_client_only_encrypted_data(); 238 password_data.mutable_password()->mutable_client_only_encrypted_data();
158 password_specifics->set_scheme(password_form.scheme); 239 password_specifics->set_scheme(password_form.scheme);
159 password_specifics->set_signon_realm(password_form.signon_realm); 240 password_specifics->set_signon_realm(password_form.signon_realm);
160 password_specifics->set_origin(password_form.origin.spec()); 241 password_specifics->set_origin(password_form.origin.spec());
161 password_specifics->set_action(password_form.action.spec()); 242 password_specifics->set_action(password_form.action.spec());
162 password_specifics->set_username_element( 243 password_specifics->set_username_element(
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 // static 285 // static
205 std::string PasswordSyncableService::MakeTag( 286 std::string PasswordSyncableService::MakeTag(
206 const sync_pb::PasswordSpecificsData& password) { 287 const sync_pb::PasswordSpecificsData& password) {
207 return MakeTag(password.origin(), 288 return MakeTag(password.origin(),
208 password.username_element(), 289 password.username_element(),
209 password.username_value(), 290 password.username_value(),
210 password.password_element(), 291 password.password_element(),
211 password.signon_realm()); 292 password.signon_realm());
212 } 293 }
213 294
295 // static
296 void PasswordSyncableService::ExtractPasswordFromSpecifics(
297 const sync_pb::PasswordSpecificsData& password,
298 autofill::PasswordForm* new_password) {
299 new_password->scheme =
300 static_cast<autofill::PasswordForm::Scheme>(password.scheme());
301 new_password->signon_realm = password.signon_realm();
302 new_password->origin = GURL(password.origin());
303 new_password->action = GURL(password.action());
304 new_password->username_element =
305 UTF8ToUTF16(password.username_element());
306 new_password->password_element =
307 UTF8ToUTF16(password.password_element());
308 new_password->username_value =
309 UTF8ToUTF16(password.username_value());
310 new_password->password_value =
311 UTF8ToUTF16(password.password_value());
312 new_password->ssl_valid = password.ssl_valid();
313 new_password->preferred = password.preferred();
314 new_password->date_created =
315 base::Time::FromInternalValue(password.date_created());
316 new_password->blacklisted_by_user =
317 password.blacklisted();
318 }
319
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698