OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "components/password_manager/core/browser/password_syncable_service.h" | 5 #include "components/password_manager/core/browser/password_syncable_service.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <iterator> | 8 #include <iterator> |
9 #include <numeric> | |
9 #include <utility> | 10 #include <utility> |
10 | 11 |
11 #include "base/auto_reset.h" | 12 #include "base/auto_reset.h" |
12 #include "base/location.h" | 13 #include "base/location.h" |
13 #include "base/memory/ptr_util.h" | 14 #include "base/memory/ptr_util.h" |
14 #include "base/metrics/histogram_macros.h" | 15 #include "base/metrics/histogram_macros.h" |
16 #include "base/optional.h" | |
17 #include "base/strings/string_util.h" | |
15 #include "base/strings/utf_string_conversions.h" | 18 #include "base/strings/utf_string_conversions.h" |
19 #include "base/time/default_clock.h" | |
16 #include "components/autofill/core/common/password_form.h" | 20 #include "components/autofill/core/common/password_form.h" |
21 #include "components/password_manager/core/browser/android_affiliation/affiliati on_utils.h" | |
17 #include "components/password_manager/core/browser/password_manager_metrics_util .h" | 22 #include "components/password_manager/core/browser/password_manager_metrics_util .h" |
18 #include "components/password_manager/core/browser/password_store_sync.h" | 23 #include "components/password_manager/core/browser/password_store_sync.h" |
19 #include "components/sync/model/sync_error_factory.h" | 24 #include "components/sync/model/sync_error_factory.h" |
20 #include "net/base/escape.h" | 25 #include "net/base/escape.h" |
21 | 26 |
22 namespace password_manager { | 27 namespace password_manager { |
23 | 28 |
24 // Converts the |password| into a SyncData object. | 29 // Converts the |password| into a SyncData object. |
25 syncer::SyncData SyncDataFromPassword(const autofill::PasswordForm& password); | 30 syncer::SyncData SyncDataFromPassword(const autofill::PasswordForm& password); |
26 | 31 |
27 // Extracts the |PasswordForm| data from sync's protobuf format. | 32 // Extracts the |PasswordForm| data from sync's protobuf format. |
28 autofill::PasswordForm PasswordFromSpecifics( | 33 autofill::PasswordForm PasswordFromSpecifics( |
29 const sync_pb::PasswordSpecificsData& password); | 34 const sync_pb::PasswordSpecificsData& password); |
30 | 35 |
31 // Returns the unique tag that will serve as the sync identifier for the | 36 // Returns the unique tag that will serve as the sync identifier for the |
32 // |password| entry. | 37 // |password| entry. |
33 std::string MakePasswordSyncTag(const sync_pb::PasswordSpecificsData& password); | 38 std::string MakePasswordSyncTag(const sync_pb::PasswordSpecificsData& password); |
34 std::string MakePasswordSyncTag(const autofill::PasswordForm& password); | 39 std::string MakePasswordSyncTag(const autofill::PasswordForm& password); |
35 | 40 |
36 namespace { | 41 namespace { |
37 | 42 |
38 // Returns true iff |password_specifics| and |password_specifics| are equal | 43 // Returns true iff |password_specifics| and |password_specifics| are equal |
39 // memberwise. | 44 // in the fields which don't comprise the sync tag. |
40 bool AreLocalAndSyncPasswordsEqual( | 45 bool AreLocalAndSyncPasswordsNonSyncTagEqual( |
41 const sync_pb::PasswordSpecificsData& password_specifics, | 46 const sync_pb::PasswordSpecificsData& password_specifics, |
42 const autofill::PasswordForm& password_form) { | 47 const autofill::PasswordForm& password_form) { |
43 return (password_form.scheme == password_specifics.scheme() && | 48 return (password_form.scheme == password_specifics.scheme() && |
44 password_form.signon_realm == password_specifics.signon_realm() && | |
45 password_form.origin.spec() == password_specifics.origin() && | |
46 password_form.action.spec() == password_specifics.action() && | 49 password_form.action.spec() == password_specifics.action() && |
47 base::UTF16ToUTF8(password_form.username_element) == | |
48 password_specifics.username_element() && | |
49 base::UTF16ToUTF8(password_form.password_element) == | |
50 password_specifics.password_element() && | |
51 base::UTF16ToUTF8(password_form.username_value) == | |
52 password_specifics.username_value() && | |
53 base::UTF16ToUTF8(password_form.password_value) == | 50 base::UTF16ToUTF8(password_form.password_value) == |
54 password_specifics.password_value() && | 51 password_specifics.password_value() && |
55 password_form.preferred == password_specifics.preferred() && | 52 password_form.preferred == password_specifics.preferred() && |
56 password_form.date_created.ToInternalValue() == | 53 password_form.date_created.ToInternalValue() == |
57 password_specifics.date_created() && | 54 password_specifics.date_created() && |
58 password_form.blacklisted_by_user == | 55 password_form.blacklisted_by_user == |
59 password_specifics.blacklisted() && | 56 password_specifics.blacklisted() && |
60 password_form.type == password_specifics.type() && | 57 password_form.type == password_specifics.type() && |
61 password_form.times_used == password_specifics.times_used() && | 58 password_form.times_used == password_specifics.times_used() && |
62 base::UTF16ToUTF8(password_form.display_name) == | 59 base::UTF16ToUTF8(password_form.display_name) == |
63 password_specifics.display_name() && | 60 password_specifics.display_name() && |
64 password_form.icon_url.spec() == password_specifics.avatar_url() && | 61 password_form.icon_url.spec() == password_specifics.avatar_url() && |
65 url::Origin(GURL(password_specifics.federation_url())).Serialize() == | 62 url::Origin(GURL(password_specifics.federation_url())).Serialize() == |
66 password_form.federation_origin.Serialize()); | 63 password_form.federation_origin.Serialize()); |
67 } | 64 } |
68 | 65 |
66 // Returns true iff |password_specifics| and |password_specifics| are equal | |
67 // memberwise. | |
68 bool AreLocalAndSyncPasswordsEqual( | |
69 const sync_pb::PasswordSpecificsData& password_specifics, | |
70 const autofill::PasswordForm& password_form) { | |
71 return (password_form.signon_realm == password_specifics.signon_realm() && | |
72 password_form.origin.spec() == password_specifics.origin() && | |
73 base::UTF16ToUTF8(password_form.username_element) == | |
74 password_specifics.username_element() && | |
75 base::UTF16ToUTF8(password_form.password_element) == | |
76 password_specifics.password_element() && | |
77 base::UTF16ToUTF8(password_form.username_value) == | |
78 password_specifics.username_value() && | |
79 AreLocalAndSyncPasswordsNonSyncTagEqual(password_specifics, | |
80 password_form)); | |
81 } | |
82 | |
83 // Compares the fields which are not part of the sync tag. | |
84 bool AreNonSyncTagFieldsEqual(const sync_pb::PasswordSpecificsData& left, | |
85 const sync_pb::PasswordSpecificsData& right) { | |
86 return (left.scheme() == right.scheme() && left.action() == right.action() && | |
87 left.password_value() == right.password_value() && | |
88 left.preferred() == right.preferred() && | |
89 left.date_created() == right.date_created() && | |
90 left.blacklisted() == right.blacklisted() && | |
91 left.type() == right.type() && | |
92 left.times_used() == right.times_used() && | |
93 left.display_name() == right.display_name() && | |
94 left.avatar_url() == right.avatar_url() && | |
95 left.federation_url() == right.federation_url()); | |
96 } | |
97 | |
69 syncer::SyncChange::SyncChangeType GetSyncChangeType( | 98 syncer::SyncChange::SyncChangeType GetSyncChangeType( |
70 PasswordStoreChange::Type type) { | 99 PasswordStoreChange::Type type) { |
71 switch (type) { | 100 switch (type) { |
72 case PasswordStoreChange::ADD: | 101 case PasswordStoreChange::ADD: |
73 return syncer::SyncChange::ACTION_ADD; | 102 return syncer::SyncChange::ACTION_ADD; |
74 case PasswordStoreChange::UPDATE: | 103 case PasswordStoreChange::UPDATE: |
75 return syncer::SyncChange::ACTION_UPDATE; | 104 return syncer::SyncChange::ACTION_UPDATE; |
76 case PasswordStoreChange::REMOVE: | 105 case PasswordStoreChange::REMOVE: |
77 return syncer::SyncChange::ACTION_DELETE; | 106 return syncer::SyncChange::ACTION_DELETE; |
78 } | 107 } |
79 NOTREACHED(); | 108 NOTREACHED(); |
80 return syncer::SyncChange::ACTION_INVALID; | 109 return syncer::SyncChange::ACTION_INVALID; |
81 } | 110 } |
82 | 111 |
83 // Creates a PasswordForm from |specifics| and |sync_time|, appends it to | 112 // Creates a PasswordForm from |specifics| and |sync_time|, appends it to |
84 // |entries|. | 113 // |entries|. |
85 void AppendPasswordFromSpecifics( | 114 void AppendPasswordFromSpecifics( |
86 const sync_pb::PasswordSpecificsData& specifics, | 115 const sync_pb::PasswordSpecificsData& specifics, |
87 base::Time sync_time, | 116 base::Time sync_time, |
88 std::vector<std::unique_ptr<autofill::PasswordForm>>* entries) { | 117 std::vector<std::unique_ptr<autofill::PasswordForm>>* entries) { |
89 entries->push_back(base::MakeUnique<autofill::PasswordForm>( | 118 entries->push_back(base::MakeUnique<autofill::PasswordForm>( |
90 PasswordFromSpecifics(specifics))); | 119 PasswordFromSpecifics(specifics))); |
91 entries->back()->date_synced = sync_time; | 120 entries->back()->date_synced = sync_time; |
92 } | 121 } |
93 | 122 |
123 // Android autofill saves credential in a different format without trailing '/'. | |
124 std::string GetAndroidAutofillSignonRealm(std::string android_autofill_realm) { | |
engedy
2017/07/20 18:34:14
For extra readability in the code below, how about
vasilii
2017/07/20 19:50:18
Done.
| |
125 if (base::EndsWith(android_autofill_realm, "/", base::CompareCase::SENSITIVE)) | |
126 android_autofill_realm.erase(android_autofill_realm.size() - 1); | |
127 return android_autofill_realm; | |
128 } | |
129 | |
130 // The correct Android signon_realm should have a trailing '/'. | |
131 std::string GetCorrectAndroidSignonRealm(std::string android_realm) { | |
engedy
2017/07/20 18:34:14
Do we have complete confidence in [1] that we will
vasilii
2017/07/20 19:50:17
I didn't get the question. This particular functio
engedy
2017/07/20 20:12:14
Correct, no crashes, I was just wondering if havin
| |
132 if (!base::EndsWith(android_realm, "/", base::CompareCase::SENSITIVE)) | |
133 android_realm += '/'; | |
134 return android_realm; | |
135 } | |
136 | |
137 // Android autofill saves credential in a different format without trailing '/'. | |
engedy
2017/07/20 18:34:14
typo: credentials
vasilii
2017/07/20 19:50:18
Done.
| |
138 // Return a sync tag for the style used by Android Autofill in the GMS Core v12. | |
engedy
2017/07/20 18:34:14
typo: s/in the GMS/in GMS/
vasilii
2017/07/20 19:50:18
Done.
| |
139 std::string AndroidAutofillSyncTag( | |
140 const sync_pb::PasswordSpecificsData& password) { | |
141 // realm has the same value as the origin. | |
142 std::string origin = GetAndroidAutofillSignonRealm(password.origin()); | |
engedy
2017/07/20 18:34:14
Just to triple check:
-- Do you have some concre
vasilii
2017/07/20 19:50:17
- Yes, if you open the email thread then you can f
| |
143 std::string signon_realm = | |
144 GetAndroidAutofillSignonRealm(password.signon_realm()); | |
145 return (net::EscapePath(origin) + "|" + | |
146 net::EscapePath(password.username_element()) + "|" + | |
147 net::EscapePath(password.username_value()) + "|" + | |
148 net::EscapePath(password.password_element()) + "|" + | |
149 net::EscapePath(signon_realm)); | |
150 } | |
151 | |
152 // Return a sync tag for the correct format used by Android. | |
153 std::string AndroidCorrectSyncTag( | |
154 const sync_pb::PasswordSpecificsData& password) { | |
155 // realm has the same value as the origin. | |
156 std::string origin = GetCorrectAndroidSignonRealm(password.origin()); | |
157 std::string signon_realm = | |
158 GetCorrectAndroidSignonRealm(password.signon_realm()); | |
159 return (net::EscapePath(origin) + "|" + | |
160 net::EscapePath(password.username_element()) + "|" + | |
161 net::EscapePath(password.username_value()) + "|" + | |
162 net::EscapePath(password.password_element()) + "|" + | |
163 net::EscapePath(signon_realm)); | |
164 } | |
165 | |
166 void PasswordSpecificsFromPassword( | |
167 const autofill::PasswordForm& password_form, | |
168 sync_pb::PasswordSpecificsData* password_specifics) { | |
169 #define CopyField(field) password_specifics->set_##field(password_form.field) | |
170 #define CopyStringField(field) \ | |
171 password_specifics->set_##field(base::UTF16ToUTF8(password_form.field)) | |
172 CopyField(scheme); | |
173 CopyField(signon_realm); | |
174 password_specifics->set_origin(password_form.origin.spec()); | |
175 password_specifics->set_action(password_form.action.spec()); | |
176 CopyStringField(username_element); | |
177 CopyStringField(password_element); | |
178 CopyStringField(username_value); | |
179 CopyStringField(password_value); | |
180 CopyField(preferred); | |
181 password_specifics->set_date_created( | |
182 password_form.date_created.ToInternalValue()); | |
183 password_specifics->set_blacklisted(password_form.blacklisted_by_user); | |
184 CopyField(type); | |
185 CopyField(times_used); | |
186 CopyStringField(display_name); | |
187 password_specifics->set_avatar_url(password_form.icon_url.spec()); | |
188 password_specifics->set_federation_url( | |
189 password_form.federation_origin.unique() | |
190 ? std::string() | |
191 : password_form.federation_origin.Serialize()); | |
192 #undef CopyStringField | |
193 #undef CopyField | |
194 } | |
195 | |
196 struct AndroidMergeResult { | |
197 // New value for Android entry in the correct format. | |
198 base::Optional<syncer::SyncData> new_android_correct; | |
199 // New value for Android autofill entry. | |
200 base::Optional<syncer::SyncData> new_android_incorrect; | |
201 // New value for local entry in the correct format. | |
202 base::Optional<autofill::PasswordForm> new_local_correct; | |
203 // New value for local entry in the Android autofill format. | |
204 base::Optional<autofill::PasswordForm> new_local_incorrect; | |
205 }; | |
206 | |
207 // Perform deduplication of Android credentials saved in the wrong format. As | |
208 // the result all the four entries should be created and have the same value. | |
209 AndroidMergeResult Perform4WayMergeAndroidCredentials( | |
210 const sync_pb::PasswordSpecificsData* correct_android, | |
211 const sync_pb::PasswordSpecificsData* incorrect_android, | |
212 const autofill::PasswordForm* correct_local, | |
213 const autofill::PasswordForm* incorrect_local) { | |
214 AndroidMergeResult result; | |
215 | |
216 base::Optional<sync_pb::PasswordSpecificsData> local_correct_ps; | |
217 if (correct_local) { | |
218 local_correct_ps = sync_pb::PasswordSpecificsData(); | |
219 PasswordSpecificsFromPassword(*correct_local, &local_correct_ps.value()); | |
220 } | |
221 | |
222 base::Optional<sync_pb::PasswordSpecificsData> local_incorrect_ps; | |
223 if (incorrect_local) { | |
224 local_incorrect_ps = sync_pb::PasswordSpecificsData(); | |
225 PasswordSpecificsFromPassword(*incorrect_local, | |
226 &local_incorrect_ps.value()); | |
227 } | |
228 | |
229 const sync_pb::PasswordSpecificsData* all_data[4] = { | |
230 correct_android, incorrect_android, | |
231 local_correct_ps ? &local_correct_ps.value() : nullptr, | |
232 local_incorrect_ps ? &local_incorrect_ps.value() : nullptr}; | |
233 | |
234 // |newest_data| will point to the newest entry out of all 4. | |
235 const sync_pb::PasswordSpecificsData* newest_data = nullptr; | |
236 newest_data = | |
engedy
2017/07/20 18:34:14
nit: Isn't this actually longer than a good old ra
vasilii
2017/07/20 19:50:17
Done.
| |
237 std::accumulate(all_data, all_data + 4, newest_data, | |
238 [](const sync_pb::PasswordSpecificsData* newest, | |
239 const sync_pb::PasswordSpecificsData* current) { | |
240 if (newest && current) { | |
241 if (current->date_created() > newest->date_created()) | |
242 newest = current; | |
243 } else if (current) { | |
244 newest = current; | |
245 } | |
246 return newest; | |
247 }); | |
248 DCHECK(newest_data); | |
249 | |
250 const std::string correct_tag = AndroidCorrectSyncTag(*newest_data); | |
engedy
2017/07/20 18:34:14
For brevity, have you considered precalculating th
vasilii
2017/07/20 19:50:18
Done.
| |
251 const std::string incorrect_tag = AndroidAutofillSyncTag(*newest_data); | |
252 // Set the correct Sync entry if needed. | |
253 if (newest_data != correct_android && | |
254 (!correct_android || | |
255 !AreNonSyncTagFieldsEqual(*correct_android, *newest_data))) { | |
256 sync_pb::EntitySpecifics password_data; | |
257 sync_pb::PasswordSpecificsData* password_specifics = | |
258 password_data.mutable_password()->mutable_client_only_encrypted_data(); | |
engedy
2017/07/20 18:34:14
To double check: are you familiar with how non-enc
vasilii
2017/07/20 19:50:18
Right, not our business.
| |
259 *password_specifics = *newest_data; | |
260 password_specifics->set_origin( | |
261 GetCorrectAndroidSignonRealm(newest_data->origin())); | |
262 password_specifics->set_signon_realm( | |
263 GetCorrectAndroidSignonRealm(newest_data->signon_realm())); | |
264 result.new_android_correct = syncer::SyncData::CreateLocalData( | |
265 correct_tag, correct_tag, password_data); | |
266 } | |
267 // Set the Andoroid Autofill Sync entry if needed. | |
engedy
2017/07/20 18:34:14
optional nit: Consider blank lines between blocks.
vasilii
2017/07/20 19:50:18
Done.
| |
268 if (newest_data != incorrect_android && | |
269 (!incorrect_android || | |
270 !AreNonSyncTagFieldsEqual(*incorrect_android, *newest_data))) { | |
271 sync_pb::EntitySpecifics password_data; | |
272 sync_pb::PasswordSpecificsData* password_specifics = | |
273 password_data.mutable_password()->mutable_client_only_encrypted_data(); | |
274 *password_specifics = *newest_data; | |
275 password_specifics->set_origin( | |
276 GetAndroidAutofillSignonRealm(newest_data->origin())); | |
277 password_specifics->set_signon_realm( | |
278 GetAndroidAutofillSignonRealm(newest_data->signon_realm())); | |
279 result.new_android_incorrect = syncer::SyncData::CreateLocalData( | |
280 incorrect_tag, incorrect_tag, password_data); | |
281 } | |
282 // Set the correct local entry if needed. | |
283 if (!local_correct_ps || | |
284 (newest_data != &local_correct_ps.value() && | |
285 !AreNonSyncTagFieldsEqual(local_correct_ps.value(), *newest_data))) { | |
286 result.new_local_correct = PasswordFromSpecifics(*newest_data); | |
287 result.new_local_correct.value().origin = | |
288 GURL(GetCorrectAndroidSignonRealm(newest_data->origin())); | |
289 result.new_local_correct.value().signon_realm = | |
290 GetCorrectAndroidSignonRealm(newest_data->signon_realm()); | |
291 } | |
292 // Set the incorrect local entry if needed. | |
293 if (!local_incorrect_ps || | |
294 (newest_data != &local_incorrect_ps.value() && | |
295 !AreNonSyncTagFieldsEqual(local_incorrect_ps.value(), *newest_data))) { | |
296 result.new_local_incorrect = PasswordFromSpecifics(*newest_data); | |
297 result.new_local_incorrect.value().origin = | |
298 GURL(GetAndroidAutofillSignonRealm(newest_data->origin())); | |
299 result.new_local_incorrect.value().signon_realm = | |
300 GetAndroidAutofillSignonRealm(newest_data->signon_realm()); | |
301 } | |
302 return result; | |
303 } | |
304 | |
94 } // namespace | 305 } // namespace |
95 | 306 |
96 struct PasswordSyncableService::SyncEntries { | 307 struct PasswordSyncableService::SyncEntries { |
97 std::vector<std::unique_ptr<autofill::PasswordForm>>* EntriesForChangeType( | 308 std::vector<std::unique_ptr<autofill::PasswordForm>>* EntriesForChangeType( |
98 syncer::SyncChange::SyncChangeType type) { | 309 syncer::SyncChange::SyncChangeType type) { |
99 switch (type) { | 310 switch (type) { |
100 case syncer::SyncChange::ACTION_ADD: | 311 case syncer::SyncChange::ACTION_ADD: |
101 return &new_entries; | 312 return &new_entries; |
102 case syncer::SyncChange::ACTION_UPDATE: | 313 case syncer::SyncChange::ACTION_UPDATE: |
103 return &updated_entries; | 314 return &updated_entries; |
(...skipping 13 matching lines...) Expand all Loading... | |
117 // database but have updates in sync. They need to be updated in the local | 328 // database but have updates in sync. They need to be updated in the local |
118 // database. | 329 // database. |
119 std::vector<std::unique_ptr<autofill::PasswordForm>> updated_entries; | 330 std::vector<std::unique_ptr<autofill::PasswordForm>> updated_entries; |
120 | 331 |
121 // The list of entries to be deleted from the local database. | 332 // The list of entries to be deleted from the local database. |
122 std::vector<std::unique_ptr<autofill::PasswordForm>> deleted_entries; | 333 std::vector<std::unique_ptr<autofill::PasswordForm>> deleted_entries; |
123 }; | 334 }; |
124 | 335 |
125 PasswordSyncableService::PasswordSyncableService( | 336 PasswordSyncableService::PasswordSyncableService( |
126 PasswordStoreSync* password_store) | 337 PasswordStoreSync* password_store) |
127 : password_store_(password_store), is_processing_sync_changes_(false) { | 338 : password_store_(password_store), |
128 } | 339 clock_(new base::DefaultClock), |
340 is_processing_sync_changes_(false) {} | |
129 | 341 |
130 PasswordSyncableService::~PasswordSyncableService() { | 342 PasswordSyncableService::~PasswordSyncableService() { |
131 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 343 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
132 } | 344 } |
133 | 345 |
134 syncer::SyncMergeResult PasswordSyncableService::MergeDataAndStartSyncing( | 346 syncer::SyncMergeResult PasswordSyncableService::MergeDataAndStartSyncing( |
135 syncer::ModelType type, | 347 syncer::ModelType type, |
136 const syncer::SyncDataList& initial_sync_data, | 348 const syncer::SyncDataList& initial_sync_data, |
137 std::unique_ptr<syncer::SyncChangeProcessor> sync_processor, | 349 std::unique_ptr<syncer::SyncChangeProcessor> sync_processor, |
138 std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory) { | 350 std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory) { |
(...skipping 17 matching lines...) Expand all Loading... | |
156 if (password_entries.size() != new_local_entries.size()) { | 368 if (password_entries.size() != new_local_entries.size()) { |
157 merge_result.set_error(sync_error_factory->CreateAndUploadError( | 369 merge_result.set_error(sync_error_factory->CreateAndUploadError( |
158 FROM_HERE, | 370 FROM_HERE, |
159 "There are passwords with identical sync tags in the database.")); | 371 "There are passwords with identical sync tags in the database.")); |
160 metrics_util::LogPasswordSyncState( | 372 metrics_util::LogPasswordSyncState( |
161 metrics_util::NOT_SYNCING_DUPLICATE_TAGS); | 373 metrics_util::NOT_SYNCING_DUPLICATE_TAGS); |
162 return merge_result; | 374 return merge_result; |
163 } | 375 } |
164 merge_result.set_num_items_before_association(new_local_entries.size()); | 376 merge_result.set_num_items_before_association(new_local_entries.size()); |
165 | 377 |
378 // Changes from Sync to be applied locally. | |
166 SyncEntries sync_entries; | 379 SyncEntries sync_entries; |
167 // Changes from password db that need to be propagated to sync. | 380 // Changes from password db that need to be propagated to sync. |
168 syncer::SyncChangeList updated_db_entries; | 381 syncer::SyncChangeList updated_db_entries; |
169 for (syncer::SyncDataList::const_iterator sync_iter = | 382 MergeSyncDataWithLocalData(initial_sync_data, &new_local_entries, |
170 initial_sync_data.begin(); | 383 &sync_entries, &updated_db_entries); |
171 sync_iter != initial_sync_data.end(); ++sync_iter) { | |
172 CreateOrUpdateEntry(*sync_iter, | |
173 &new_local_entries, | |
174 &sync_entries, | |
175 &updated_db_entries); | |
176 } | |
177 | 384 |
178 for (PasswordEntryMap::iterator it = new_local_entries.begin(); | 385 for (PasswordEntryMap::iterator it = new_local_entries.begin(); |
179 it != new_local_entries.end(); ++it) { | 386 it != new_local_entries.end(); ++it) { |
180 updated_db_entries.push_back( | 387 updated_db_entries.push_back( |
181 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_ADD, | 388 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_ADD, |
182 SyncDataFromPassword(*it->second))); | 389 SyncDataFromPassword(*it->second))); |
183 } | 390 } |
184 | 391 |
185 WriteToPasswordStore(sync_entries); | 392 WriteToPasswordStore(sync_entries); |
186 merge_result.set_error( | 393 merge_result.set_error( |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
230 }); | 437 }); |
231 return sync_data; | 438 return sync_data; |
232 } | 439 } |
233 | 440 |
234 syncer::SyncError PasswordSyncableService::ProcessSyncChanges( | 441 syncer::SyncError PasswordSyncableService::ProcessSyncChanges( |
235 const tracked_objects::Location& from_here, | 442 const tracked_objects::Location& from_here, |
236 const syncer::SyncChangeList& change_list) { | 443 const syncer::SyncChangeList& change_list) { |
237 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 444 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
238 base::AutoReset<bool> processing_changes(&is_processing_sync_changes_, true); | 445 base::AutoReset<bool> processing_changes(&is_processing_sync_changes_, true); |
239 SyncEntries sync_entries; | 446 SyncEntries sync_entries; |
240 base::Time time_now = base::Time::Now(); | 447 base::Time time_now = clock_->Now(); |
241 | 448 |
242 for (syncer::SyncChangeList::const_iterator it = change_list.begin(); | 449 for (syncer::SyncChangeList::const_iterator it = change_list.begin(); |
243 it != change_list.end(); ++it) { | 450 it != change_list.end(); ++it) { |
244 const sync_pb::EntitySpecifics& specifics = it->sync_data().GetSpecifics(); | 451 const sync_pb::EntitySpecifics& specifics = it->sync_data().GetSpecifics(); |
245 std::vector<std::unique_ptr<autofill::PasswordForm>>* entries = | 452 std::vector<std::unique_ptr<autofill::PasswordForm>>* entries = |
246 sync_entries.EntriesForChangeType(it->change_type()); | 453 sync_entries.EntriesForChangeType(it->change_type()); |
247 if (!entries) { | 454 if (!entries) { |
248 return sync_error_factory_->CreateAndUploadError( | 455 return sync_error_factory_->CreateAndUploadError( |
249 FROM_HERE, "Failed to process sync changes for passwords datatype."); | 456 FROM_HERE, "Failed to process sync changes for passwords datatype."); |
250 } | 457 } |
251 AppendPasswordFromSpecifics( | 458 AppendPasswordFromSpecifics( |
252 specifics.password().client_only_encrypted_data(), time_now, entries); | 459 specifics.password().client_only_encrypted_data(), time_now, entries); |
460 if (IsValidAndroidFacetURI(entries->back()->signon_realm)) { | |
461 // Fix the Android Autofill credentials if needed. | |
462 entries->back()->signon_realm = | |
463 GetCorrectAndroidSignonRealm(entries->back()->signon_realm); | |
464 entries->back()->origin = | |
465 GURL(GetCorrectAndroidSignonRealm(entries->back()->origin.spec())); | |
466 } | |
253 } | 467 } |
254 | 468 |
255 WriteToPasswordStore(sync_entries); | 469 WriteToPasswordStore(sync_entries); |
256 return syncer::SyncError(); | 470 return syncer::SyncError(); |
257 } | 471 } |
258 | 472 |
259 void PasswordSyncableService::ActOnPasswordStoreChanges( | 473 void PasswordSyncableService::ActOnPasswordStoreChanges( |
260 const PasswordStoreChangeList& local_changes) { | 474 const PasswordStoreChangeList& local_changes) { |
261 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 475 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
262 | 476 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
332 WriteEntriesToDatabase(&PasswordStoreSync::UpdateLoginSync, | 546 WriteEntriesToDatabase(&PasswordStoreSync::UpdateLoginSync, |
333 entries.updated_entries, &changes); | 547 entries.updated_entries, &changes); |
334 WriteEntriesToDatabase(&PasswordStoreSync::RemoveLoginSync, | 548 WriteEntriesToDatabase(&PasswordStoreSync::RemoveLoginSync, |
335 entries.deleted_entries, &changes); | 549 entries.deleted_entries, &changes); |
336 | 550 |
337 // We have to notify password store observers of the change by hand since | 551 // We have to notify password store observers of the change by hand since |
338 // we use internal password store interfaces to make changes synchronously. | 552 // we use internal password store interfaces to make changes synchronously. |
339 password_store_->NotifyLoginsChanged(changes); | 553 password_store_->NotifyLoginsChanged(changes); |
340 } | 554 } |
341 | 555 |
342 // static | 556 void PasswordSyncableService::MergeSyncDataWithLocalData( |
343 void PasswordSyncableService::CreateOrUpdateEntry( | 557 const syncer::SyncDataList& sync_data, |
344 const syncer::SyncData& data, | |
345 PasswordEntryMap* unmatched_data_from_password_db, | 558 PasswordEntryMap* unmatched_data_from_password_db, |
346 SyncEntries* sync_entries, | 559 SyncEntries* sync_entries, |
347 syncer::SyncChangeList* updated_db_entries) { | 560 syncer::SyncChangeList* updated_db_entries) { |
348 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics(); | 561 std::map<std::string, const sync_pb::PasswordSpecificsData*> sync_data_map; |
349 const sync_pb::PasswordSpecificsData& password_specifics( | 562 for (const auto& data : sync_data) { |
350 specifics.password().client_only_encrypted_data()); | 563 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics(); |
564 const sync_pb::PasswordSpecificsData* password_specifics = | |
565 &specifics.password().client_only_encrypted_data(); | |
566 sync_data_map[MakePasswordSyncTag(*password_specifics)] = | |
engedy
2017/07/20 18:34:14
Should we add a DCHECK() that there was no such ke
vasilii
2017/07/20 19:50:18
Done.
| |
567 password_specifics; | |
568 } | |
569 | |
570 for (auto it = sync_data_map.begin(); it != sync_data_map.end();) { | |
571 if (IsValidAndroidFacetURI(it->second->signon_realm())) { | |
572 // Perform deduplication of Android credentials saved in the wrong format. | |
573 // An incorrect entry is copied in the correct format so Chrome can make | |
engedy
2017/07/20 18:34:14
phrasing nit: For each incorrect entry, a duplicat
vasilii
2017/07/20 19:50:17
Done.
| |
574 // use of it. The wrong sync entries are not deleted for now. | |
engedy
2017/07/20 18:34:14
phrasing nit: s/wrong/incorrect/
vasilii
2017/07/20 19:50:18
Done.
| |
575 std::string incorrect_tag = AndroidAutofillSyncTag(*it->second); | |
576 std::string correct_tag = AndroidCorrectSyncTag(*it->second); | |
577 auto it_android_incorrect = sync_data_map.find(incorrect_tag); | |
engedy
2017/07/20 18:34:14
For extra readability, have you considered s/andro
vasilii
2017/07/20 19:50:17
Done.
| |
578 auto it_android_correct = sync_data_map.find(correct_tag); | |
579 auto it_local_data_correct = | |
580 unmatched_data_from_password_db->find(correct_tag); | |
581 auto it_local_data_incorrect = | |
582 unmatched_data_from_password_db->find(incorrect_tag); | |
engedy
2017/07/20 18:34:14
Should we fall back to default handling if (it !=
vasilii
2017/07/20 19:50:18
Good point.
They claim that they use the same lib
| |
583 if (it_android_incorrect == sync_data_map.end() && | |
584 it_local_data_incorrect == unmatched_data_from_password_db->end()) { | |
585 // Wrong credential don't exist. Just do what Sync would normally do. | |
586 CreateOrUpdateEntry(*it->second, unmatched_data_from_password_db, | |
587 sync_entries, updated_db_entries); | |
588 ++it; | |
589 } else { | |
590 AndroidMergeResult result = Perform4WayMergeAndroidCredentials( | |
591 it_android_correct == sync_data_map.end() | |
592 ? nullptr | |
593 : it_android_correct->second, | |
594 it_android_incorrect == sync_data_map.end() | |
595 ? nullptr | |
596 : it_android_incorrect->second, | |
597 it_local_data_correct == unmatched_data_from_password_db->end() | |
598 ? nullptr | |
599 : it_local_data_correct->second, | |
600 it_local_data_incorrect == unmatched_data_from_password_db->end() | |
601 ? nullptr | |
602 : it_local_data_incorrect->second); | |
603 // Add or update the correct local entry. | |
604 if (result.new_local_correct) { | |
605 auto* local_changes = sync_entries->EntriesForChangeType( | |
606 it_local_data_correct == unmatched_data_from_password_db->end() | |
607 ? syncer::SyncChange::ACTION_ADD | |
608 : syncer::SyncChange::ACTION_UPDATE); | |
609 local_changes->push_back(base::MakeUnique<autofill::PasswordForm>( | |
610 result.new_local_correct.value())); | |
611 local_changes->back()->date_synced = clock_->Now(); | |
612 } | |
613 // Add or update the incorrect local entry. | |
614 if (result.new_local_incorrect) { | |
615 auto* local_changes = sync_entries->EntriesForChangeType( | |
616 it_local_data_incorrect == unmatched_data_from_password_db->end() | |
617 ? syncer::SyncChange::ACTION_ADD | |
618 : syncer::SyncChange::ACTION_UPDATE); | |
619 local_changes->push_back(base::MakeUnique<autofill::PasswordForm>( | |
620 result.new_local_incorrect.value())); | |
621 local_changes->back()->date_synced = clock_->Now(); | |
622 } | |
623 if (it_local_data_correct != unmatched_data_from_password_db->end()) | |
624 unmatched_data_from_password_db->erase(it_local_data_correct); | |
625 if (it_local_data_incorrect != unmatched_data_from_password_db->end()) | |
626 unmatched_data_from_password_db->erase(it_local_data_incorrect); | |
627 // Add or update the correct sync entry. | |
628 if (result.new_android_correct) { | |
629 updated_db_entries->push_back( | |
630 syncer::SyncChange(FROM_HERE, | |
631 it_android_correct == sync_data_map.end() | |
632 ? syncer::SyncChange::ACTION_ADD | |
633 : syncer::SyncChange::ACTION_UPDATE, | |
634 result.new_android_correct.value())); | |
635 } | |
636 // Add or update the Android Autofill sync entry. | |
637 if (result.new_android_incorrect) { | |
638 updated_db_entries->push_back( | |
639 syncer::SyncChange(FROM_HERE, | |
640 it_android_incorrect == sync_data_map.end() | |
641 ? syncer::SyncChange::ACTION_ADD | |
642 : syncer::SyncChange::ACTION_UPDATE, | |
643 result.new_android_incorrect.value())); | |
644 } | |
645 bool increment = true; | |
646 for (auto sync_data_it : {it_android_incorrect, it_android_correct}) { | |
647 if (sync_data_it != sync_data_map.end()) { | |
648 if (sync_data_it == it) { | |
649 it = sync_data_map.erase(it); | |
650 increment = false; | |
651 } else { | |
652 sync_data_map.erase(sync_data_it); | |
653 } | |
654 } | |
655 } | |
656 if (increment) | |
657 ++it; | |
658 } | |
659 } else { | |
660 // Not Android. | |
661 CreateOrUpdateEntry(*it->second, unmatched_data_from_password_db, | |
662 sync_entries, updated_db_entries); | |
663 ++it; | |
664 } | |
665 } | |
666 } | |
667 | |
668 void PasswordSyncableService::CreateOrUpdateEntry( | |
669 const sync_pb::PasswordSpecificsData& password_specifics, | |
670 PasswordEntryMap* unmatched_data_from_password_db, | |
671 SyncEntries* sync_entries, | |
672 syncer::SyncChangeList* updated_db_entries) { | |
351 std::string tag = MakePasswordSyncTag(password_specifics); | 673 std::string tag = MakePasswordSyncTag(password_specifics); |
352 | 674 |
353 // Check whether the data from sync is already in the password store. | 675 // Check whether the data from sync is already in the password store. |
354 PasswordEntryMap::iterator existing_local_entry_iter = | 676 PasswordEntryMap::iterator existing_local_entry_iter = |
355 unmatched_data_from_password_db->find(tag); | 677 unmatched_data_from_password_db->find(tag); |
356 base::Time time_now = base::Time::Now(); | 678 base::Time time_now = clock_->Now(); |
357 if (existing_local_entry_iter == unmatched_data_from_password_db->end()) { | 679 if (existing_local_entry_iter == unmatched_data_from_password_db->end()) { |
358 // The sync data is not in the password store, so we need to create it in | 680 // The sync data is not in the password store, so we need to create it in |
359 // the password store. Add the entry to the new_entries list. | 681 // the password store. Add the entry to the new_entries list. |
360 AppendPasswordFromSpecifics(password_specifics, time_now, | 682 AppendPasswordFromSpecifics(password_specifics, time_now, |
361 &sync_entries->new_entries); | 683 &sync_entries->new_entries); |
362 } else { | 684 } else { |
363 // The entry is in password store. If the entries are not identical, then | 685 // The entry is in password store. If the entries are not identical, then |
364 // the entries need to be merged. | 686 // the entries need to be merged. |
365 // If the passwords differ, take the one that was created more recently. | 687 // If the passwords differ, take the one that was created more recently. |
366 const autofill::PasswordForm& password_form = | 688 const autofill::PasswordForm& password_form = |
(...skipping 27 matching lines...) Expand all Loading... | |
394 new_changes.begin(), | 716 new_changes.begin(), |
395 new_changes.end()); | 717 new_changes.end()); |
396 } | 718 } |
397 } | 719 } |
398 | 720 |
399 syncer::SyncData SyncDataFromPassword( | 721 syncer::SyncData SyncDataFromPassword( |
400 const autofill::PasswordForm& password_form) { | 722 const autofill::PasswordForm& password_form) { |
401 sync_pb::EntitySpecifics password_data; | 723 sync_pb::EntitySpecifics password_data; |
402 sync_pb::PasswordSpecificsData* password_specifics = | 724 sync_pb::PasswordSpecificsData* password_specifics = |
403 password_data.mutable_password()->mutable_client_only_encrypted_data(); | 725 password_data.mutable_password()->mutable_client_only_encrypted_data(); |
404 #define CopyField(field) password_specifics->set_##field(password_form.field) | 726 PasswordSpecificsFromPassword(password_form, password_specifics); |
405 #define CopyStringField(field) \ | |
406 password_specifics->set_##field(base::UTF16ToUTF8(password_form.field)) | |
407 CopyField(scheme); | |
408 CopyField(signon_realm); | |
409 password_specifics->set_origin(password_form.origin.spec()); | |
410 password_specifics->set_action(password_form.action.spec()); | |
411 CopyStringField(username_element); | |
412 CopyStringField(password_element); | |
413 CopyStringField(username_value); | |
414 CopyStringField(password_value); | |
415 CopyField(preferred); | |
416 password_specifics->set_date_created( | |
417 password_form.date_created.ToInternalValue()); | |
418 password_specifics->set_blacklisted(password_form.blacklisted_by_user); | |
419 CopyField(type); | |
420 CopyField(times_used); | |
421 CopyStringField(display_name); | |
422 password_specifics->set_avatar_url(password_form.icon_url.spec()); | |
423 password_specifics->set_federation_url( | |
424 password_form.federation_origin.unique() | |
425 ? std::string() | |
426 : password_form.federation_origin.Serialize()); | |
427 #undef CopyStringField | |
428 #undef CopyField | |
429 | 727 |
430 std::string tag = MakePasswordSyncTag(*password_specifics); | 728 std::string tag = MakePasswordSyncTag(*password_specifics); |
431 return syncer::SyncData::CreateLocalData(tag, tag, password_data); | 729 return syncer::SyncData::CreateLocalData(tag, tag, password_data); |
432 } | 730 } |
433 | 731 |
434 autofill::PasswordForm PasswordFromSpecifics( | 732 autofill::PasswordForm PasswordFromSpecifics( |
435 const sync_pb::PasswordSpecificsData& password) { | 733 const sync_pb::PasswordSpecificsData& password) { |
436 autofill::PasswordForm new_password; | 734 autofill::PasswordForm new_password; |
437 new_password.scheme = | 735 new_password.scheme = |
438 static_cast<autofill::PasswordForm::Scheme>(password.scheme()); | 736 static_cast<autofill::PasswordForm::Scheme>(password.scheme()); |
(...skipping 26 matching lines...) Expand all Loading... | |
465 | 763 |
466 std::string MakePasswordSyncTag(const autofill::PasswordForm& password) { | 764 std::string MakePasswordSyncTag(const autofill::PasswordForm& password) { |
467 return (net::EscapePath(password.origin.spec()) + "|" + | 765 return (net::EscapePath(password.origin.spec()) + "|" + |
468 net::EscapePath(base::UTF16ToUTF8(password.username_element)) + "|" + | 766 net::EscapePath(base::UTF16ToUTF8(password.username_element)) + "|" + |
469 net::EscapePath(base::UTF16ToUTF8(password.username_value)) + "|" + | 767 net::EscapePath(base::UTF16ToUTF8(password.username_value)) + "|" + |
470 net::EscapePath(base::UTF16ToUTF8(password.password_element)) + "|" + | 768 net::EscapePath(base::UTF16ToUTF8(password.password_element)) + "|" + |
471 net::EscapePath(password.signon_realm)); | 769 net::EscapePath(password.signon_realm)); |
472 } | 770 } |
473 | 771 |
474 } // namespace password_manager | 772 } // namespace password_manager |
OLD | NEW |