OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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.
| |
OLD | NEW |