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