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 <utility> | 9 #include <utility> |
10 | 10 |
11 #include "base/auto_reset.h" | 11 #include "base/auto_reset.h" |
12 #include "base/location.h" | 12 #include "base/location.h" |
13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
14 #include "base/metrics/histogram_macros.h" | 14 #include "base/metrics/histogram_macros.h" |
| 15 #include "base/optional.h" |
| 16 #include "base/strings/string_util.h" |
15 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
| 18 #include "base/time/default_clock.h" |
16 #include "components/autofill/core/common/password_form.h" | 19 #include "components/autofill/core/common/password_form.h" |
| 20 #include "components/password_manager/core/browser/android_affiliation/affiliati
on_utils.h" |
17 #include "components/password_manager/core/browser/password_manager_metrics_util
.h" | 21 #include "components/password_manager/core/browser/password_manager_metrics_util
.h" |
18 #include "components/password_manager/core/browser/password_store_sync.h" | 22 #include "components/password_manager/core/browser/password_store_sync.h" |
19 #include "components/sync/model/sync_error_factory.h" | 23 #include "components/sync/model/sync_error_factory.h" |
20 #include "net/base/escape.h" | 24 #include "net/base/escape.h" |
21 | 25 |
22 namespace password_manager { | 26 namespace password_manager { |
23 | 27 |
24 // Converts the |password| into a SyncData object. | 28 // Converts the |password| into a SyncData object. |
25 syncer::SyncData SyncDataFromPassword(const autofill::PasswordForm& password); | 29 syncer::SyncData SyncDataFromPassword(const autofill::PasswordForm& password); |
26 | 30 |
27 // Extracts the |PasswordForm| data from sync's protobuf format. | 31 // Extracts the |PasswordForm| data from sync's protobuf format. |
28 autofill::PasswordForm PasswordFromSpecifics( | 32 autofill::PasswordForm PasswordFromSpecifics( |
29 const sync_pb::PasswordSpecificsData& password); | 33 const sync_pb::PasswordSpecificsData& password); |
30 | 34 |
31 // Returns the unique tag that will serve as the sync identifier for the | 35 // Returns the unique tag that will serve as the sync identifier for the |
32 // |password| entry. | 36 // |password| entry. |
33 std::string MakePasswordSyncTag(const sync_pb::PasswordSpecificsData& password); | 37 std::string MakePasswordSyncTag(const sync_pb::PasswordSpecificsData& password); |
34 std::string MakePasswordSyncTag(const autofill::PasswordForm& password); | 38 std::string MakePasswordSyncTag(const autofill::PasswordForm& password); |
35 | 39 |
36 namespace { | 40 namespace { |
37 | 41 |
38 // Returns true iff |password_specifics| and |password_specifics| are equal | 42 // Returns true iff |password_specifics| and |password_specifics| are equal |
39 // memberwise. | 43 // in the fields which don't comprise the sync tag. |
40 bool AreLocalAndSyncPasswordsEqual( | 44 bool AreLocalAndSyncPasswordsNonSyncTagEqual( |
41 const sync_pb::PasswordSpecificsData& password_specifics, | 45 const sync_pb::PasswordSpecificsData& password_specifics, |
42 const autofill::PasswordForm& password_form) { | 46 const autofill::PasswordForm& password_form) { |
43 return (password_form.scheme == password_specifics.scheme() && | 47 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() && | 48 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) == | 49 base::UTF16ToUTF8(password_form.password_value) == |
54 password_specifics.password_value() && | 50 password_specifics.password_value() && |
55 password_form.preferred == password_specifics.preferred() && | 51 password_form.preferred == password_specifics.preferred() && |
56 password_form.date_created.ToInternalValue() == | 52 password_form.date_created.ToInternalValue() == |
57 password_specifics.date_created() && | 53 password_specifics.date_created() && |
58 password_form.blacklisted_by_user == | 54 password_form.blacklisted_by_user == |
59 password_specifics.blacklisted() && | 55 password_specifics.blacklisted() && |
60 password_form.type == password_specifics.type() && | 56 password_form.type == password_specifics.type() && |
61 password_form.times_used == password_specifics.times_used() && | 57 password_form.times_used == password_specifics.times_used() && |
62 base::UTF16ToUTF8(password_form.display_name) == | 58 base::UTF16ToUTF8(password_form.display_name) == |
63 password_specifics.display_name() && | 59 password_specifics.display_name() && |
64 password_form.icon_url.spec() == password_specifics.avatar_url() && | 60 password_form.icon_url.spec() == password_specifics.avatar_url() && |
65 url::Origin(GURL(password_specifics.federation_url())).Serialize() == | 61 url::Origin(GURL(password_specifics.federation_url())).Serialize() == |
66 password_form.federation_origin.Serialize()); | 62 password_form.federation_origin.Serialize()); |
67 } | 63 } |
68 | 64 |
| 65 // Returns true iff |password_specifics| and |password_specifics| are equal |
| 66 // memberwise. |
| 67 bool AreLocalAndSyncPasswordsEqual( |
| 68 const sync_pb::PasswordSpecificsData& password_specifics, |
| 69 const autofill::PasswordForm& password_form) { |
| 70 return (password_form.signon_realm == password_specifics.signon_realm() && |
| 71 password_form.origin.spec() == password_specifics.origin() && |
| 72 base::UTF16ToUTF8(password_form.username_element) == |
| 73 password_specifics.username_element() && |
| 74 base::UTF16ToUTF8(password_form.password_element) == |
| 75 password_specifics.password_element() && |
| 76 base::UTF16ToUTF8(password_form.username_value) == |
| 77 password_specifics.username_value() && |
| 78 AreLocalAndSyncPasswordsNonSyncTagEqual(password_specifics, |
| 79 password_form)); |
| 80 } |
| 81 |
| 82 // Compares the fields which are not part of the sync tag. |
| 83 bool AreNonSyncTagFieldsEqual(const sync_pb::PasswordSpecificsData& left, |
| 84 const sync_pb::PasswordSpecificsData& right) { |
| 85 return (left.scheme() == right.scheme() && left.action() == right.action() && |
| 86 left.password_value() == right.password_value() && |
| 87 left.preferred() == right.preferred() && |
| 88 left.date_created() == right.date_created() && |
| 89 left.blacklisted() == right.blacklisted() && |
| 90 left.type() == right.type() && |
| 91 left.times_used() == right.times_used() && |
| 92 left.display_name() == right.display_name() && |
| 93 left.avatar_url() == right.avatar_url() && |
| 94 left.federation_url() == right.federation_url()); |
| 95 } |
| 96 |
69 syncer::SyncChange::SyncChangeType GetSyncChangeType( | 97 syncer::SyncChange::SyncChangeType GetSyncChangeType( |
70 PasswordStoreChange::Type type) { | 98 PasswordStoreChange::Type type) { |
71 switch (type) { | 99 switch (type) { |
72 case PasswordStoreChange::ADD: | 100 case PasswordStoreChange::ADD: |
73 return syncer::SyncChange::ACTION_ADD; | 101 return syncer::SyncChange::ACTION_ADD; |
74 case PasswordStoreChange::UPDATE: | 102 case PasswordStoreChange::UPDATE: |
75 return syncer::SyncChange::ACTION_UPDATE; | 103 return syncer::SyncChange::ACTION_UPDATE; |
76 case PasswordStoreChange::REMOVE: | 104 case PasswordStoreChange::REMOVE: |
77 return syncer::SyncChange::ACTION_DELETE; | 105 return syncer::SyncChange::ACTION_DELETE; |
78 } | 106 } |
79 NOTREACHED(); | 107 NOTREACHED(); |
80 return syncer::SyncChange::ACTION_INVALID; | 108 return syncer::SyncChange::ACTION_INVALID; |
81 } | 109 } |
82 | 110 |
83 // Creates a PasswordForm from |specifics| and |sync_time|, appends it to | 111 // Creates a PasswordForm from |specifics| and |sync_time|, appends it to |
84 // |entries|. | 112 // |entries|. |
85 void AppendPasswordFromSpecifics( | 113 void AppendPasswordFromSpecifics( |
86 const sync_pb::PasswordSpecificsData& specifics, | 114 const sync_pb::PasswordSpecificsData& specifics, |
87 base::Time sync_time, | 115 base::Time sync_time, |
88 std::vector<std::unique_ptr<autofill::PasswordForm>>* entries) { | 116 std::vector<std::unique_ptr<autofill::PasswordForm>>* entries) { |
89 entries->push_back(base::MakeUnique<autofill::PasswordForm>( | 117 entries->push_back(base::MakeUnique<autofill::PasswordForm>( |
90 PasswordFromSpecifics(specifics))); | 118 PasswordFromSpecifics(specifics))); |
91 entries->back()->date_synced = sync_time; | 119 entries->back()->date_synced = sync_time; |
92 } | 120 } |
93 | 121 |
| 122 // Android autofill saves credential in a different format without trailing '/'. |
| 123 std::string GetIncorrectAndroidSignonRealm(std::string android_autofill_realm) { |
| 124 if (base::EndsWith(android_autofill_realm, "/", base::CompareCase::SENSITIVE)) |
| 125 android_autofill_realm.erase(android_autofill_realm.size() - 1); |
| 126 return android_autofill_realm; |
| 127 } |
| 128 |
| 129 // The correct Android signon_realm should have a trailing '/'. |
| 130 std::string GetCorrectAndroidSignonRealm(std::string android_realm) { |
| 131 if (!base::EndsWith(android_realm, "/", base::CompareCase::SENSITIVE)) |
| 132 android_realm += '/'; |
| 133 return android_realm; |
| 134 } |
| 135 |
| 136 // Android autofill saves credentials in a different format without trailing |
| 137 // '/'. Return a sync tag for the style used by Android Autofill in GMS Core |
| 138 // v12. |
| 139 std::string AndroidAutofillSyncTag( |
| 140 const sync_pb::PasswordSpecificsData& password) { |
| 141 // realm has the same value as the origin. |
| 142 std::string origin = GetIncorrectAndroidSignonRealm(password.origin()); |
| 143 std::string signon_realm = |
| 144 GetIncorrectAndroidSignonRealm(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 for (int i = 0; i < 4; ++i) { |
| 237 if (newest_data && all_data[i]) { |
| 238 if (all_data[i]->date_created() > newest_data->date_created()) |
| 239 newest_data = all_data[i]; |
| 240 } else if (all_data[i]) { |
| 241 newest_data = all_data[i]; |
| 242 } |
| 243 } |
| 244 DCHECK(newest_data); |
| 245 |
| 246 const std::string correct_tag = AndroidCorrectSyncTag(*newest_data); |
| 247 const std::string incorrect_tag = AndroidAutofillSyncTag(*newest_data); |
| 248 const std::string correct_signon_realm = |
| 249 GetCorrectAndroidSignonRealm(newest_data->signon_realm()); |
| 250 const std::string incorrect_signon_realm = |
| 251 GetIncorrectAndroidSignonRealm(newest_data->signon_realm()); |
| 252 const std::string correct_origin = |
| 253 GetCorrectAndroidSignonRealm(newest_data->origin()); |
| 254 const std::string incorrect_origin = |
| 255 GetIncorrectAndroidSignonRealm(newest_data->origin()); |
| 256 DCHECK_EQ(GURL(incorrect_origin).spec(), incorrect_origin); |
| 257 |
| 258 // Set the correct Sync entry if needed. |
| 259 if (newest_data != correct_android && |
| 260 (!correct_android || |
| 261 !AreNonSyncTagFieldsEqual(*correct_android, *newest_data))) { |
| 262 sync_pb::EntitySpecifics password_data; |
| 263 sync_pb::PasswordSpecificsData* password_specifics = |
| 264 password_data.mutable_password()->mutable_client_only_encrypted_data(); |
| 265 *password_specifics = *newest_data; |
| 266 password_specifics->set_origin(correct_origin); |
| 267 password_specifics->set_signon_realm(correct_signon_realm); |
| 268 result.new_android_correct = syncer::SyncData::CreateLocalData( |
| 269 correct_tag, correct_tag, password_data); |
| 270 } |
| 271 |
| 272 // Set the Andoroid Autofill Sync entry if needed. |
| 273 if (newest_data != incorrect_android && |
| 274 (!incorrect_android || |
| 275 !AreNonSyncTagFieldsEqual(*incorrect_android, *newest_data))) { |
| 276 sync_pb::EntitySpecifics password_data; |
| 277 sync_pb::PasswordSpecificsData* password_specifics = |
| 278 password_data.mutable_password()->mutable_client_only_encrypted_data(); |
| 279 *password_specifics = *newest_data; |
| 280 password_specifics->set_origin(incorrect_origin); |
| 281 password_specifics->set_signon_realm(incorrect_signon_realm); |
| 282 result.new_android_incorrect = syncer::SyncData::CreateLocalData( |
| 283 incorrect_tag, incorrect_tag, password_data); |
| 284 } |
| 285 |
| 286 // Set the correct local entry if needed. |
| 287 if (!local_correct_ps || |
| 288 (newest_data != &local_correct_ps.value() && |
| 289 !AreNonSyncTagFieldsEqual(local_correct_ps.value(), *newest_data))) { |
| 290 result.new_local_correct = PasswordFromSpecifics(*newest_data); |
| 291 result.new_local_correct.value().origin = GURL(correct_origin); |
| 292 result.new_local_correct.value().signon_realm = correct_signon_realm; |
| 293 } |
| 294 |
| 295 // Set the incorrect local entry if needed. |
| 296 if (!local_incorrect_ps || |
| 297 (newest_data != &local_incorrect_ps.value() && |
| 298 !AreNonSyncTagFieldsEqual(local_incorrect_ps.value(), *newest_data))) { |
| 299 result.new_local_incorrect = PasswordFromSpecifics(*newest_data); |
| 300 result.new_local_incorrect.value().origin = GURL(incorrect_origin); |
| 301 result.new_local_incorrect.value().signon_realm = incorrect_signon_realm; |
| 302 } |
| 303 return result; |
| 304 } |
| 305 |
94 } // namespace | 306 } // namespace |
95 | 307 |
96 struct PasswordSyncableService::SyncEntries { | 308 struct PasswordSyncableService::SyncEntries { |
97 std::vector<std::unique_ptr<autofill::PasswordForm>>* EntriesForChangeType( | 309 std::vector<std::unique_ptr<autofill::PasswordForm>>* EntriesForChangeType( |
98 syncer::SyncChange::SyncChangeType type) { | 310 syncer::SyncChange::SyncChangeType type) { |
99 switch (type) { | 311 switch (type) { |
100 case syncer::SyncChange::ACTION_ADD: | 312 case syncer::SyncChange::ACTION_ADD: |
101 return &new_entries; | 313 return &new_entries; |
102 case syncer::SyncChange::ACTION_UPDATE: | 314 case syncer::SyncChange::ACTION_UPDATE: |
103 return &updated_entries; | 315 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 | 329 // database but have updates in sync. They need to be updated in the local |
118 // database. | 330 // database. |
119 std::vector<std::unique_ptr<autofill::PasswordForm>> updated_entries; | 331 std::vector<std::unique_ptr<autofill::PasswordForm>> updated_entries; |
120 | 332 |
121 // The list of entries to be deleted from the local database. | 333 // The list of entries to be deleted from the local database. |
122 std::vector<std::unique_ptr<autofill::PasswordForm>> deleted_entries; | 334 std::vector<std::unique_ptr<autofill::PasswordForm>> deleted_entries; |
123 }; | 335 }; |
124 | 336 |
125 PasswordSyncableService::PasswordSyncableService( | 337 PasswordSyncableService::PasswordSyncableService( |
126 PasswordStoreSync* password_store) | 338 PasswordStoreSync* password_store) |
127 : password_store_(password_store), is_processing_sync_changes_(false) { | 339 : password_store_(password_store), |
128 } | 340 clock_(new base::DefaultClock), |
| 341 is_processing_sync_changes_(false) {} |
129 | 342 |
130 PasswordSyncableService::~PasswordSyncableService() { | 343 PasswordSyncableService::~PasswordSyncableService() { |
131 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 344 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
132 } | 345 } |
133 | 346 |
134 syncer::SyncMergeResult PasswordSyncableService::MergeDataAndStartSyncing( | 347 syncer::SyncMergeResult PasswordSyncableService::MergeDataAndStartSyncing( |
135 syncer::ModelType type, | 348 syncer::ModelType type, |
136 const syncer::SyncDataList& initial_sync_data, | 349 const syncer::SyncDataList& initial_sync_data, |
137 std::unique_ptr<syncer::SyncChangeProcessor> sync_processor, | 350 std::unique_ptr<syncer::SyncChangeProcessor> sync_processor, |
138 std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory) { | 351 std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory) { |
(...skipping 17 matching lines...) Expand all Loading... |
156 if (password_entries.size() != new_local_entries.size()) { | 369 if (password_entries.size() != new_local_entries.size()) { |
157 merge_result.set_error(sync_error_factory->CreateAndUploadError( | 370 merge_result.set_error(sync_error_factory->CreateAndUploadError( |
158 FROM_HERE, | 371 FROM_HERE, |
159 "There are passwords with identical sync tags in the database.")); | 372 "There are passwords with identical sync tags in the database.")); |
160 metrics_util::LogPasswordSyncState( | 373 metrics_util::LogPasswordSyncState( |
161 metrics_util::NOT_SYNCING_DUPLICATE_TAGS); | 374 metrics_util::NOT_SYNCING_DUPLICATE_TAGS); |
162 return merge_result; | 375 return merge_result; |
163 } | 376 } |
164 merge_result.set_num_items_before_association(new_local_entries.size()); | 377 merge_result.set_num_items_before_association(new_local_entries.size()); |
165 | 378 |
| 379 // Changes from Sync to be applied locally. |
166 SyncEntries sync_entries; | 380 SyncEntries sync_entries; |
167 // Changes from password db that need to be propagated to sync. | 381 // Changes from password db that need to be propagated to sync. |
168 syncer::SyncChangeList updated_db_entries; | 382 syncer::SyncChangeList updated_db_entries; |
169 for (syncer::SyncDataList::const_iterator sync_iter = | 383 MergeSyncDataWithLocalData(initial_sync_data, &new_local_entries, |
170 initial_sync_data.begin(); | 384 &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 | 385 |
178 for (PasswordEntryMap::iterator it = new_local_entries.begin(); | 386 for (PasswordEntryMap::iterator it = new_local_entries.begin(); |
179 it != new_local_entries.end(); ++it) { | 387 it != new_local_entries.end(); ++it) { |
180 updated_db_entries.push_back( | 388 updated_db_entries.push_back( |
181 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_ADD, | 389 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_ADD, |
182 SyncDataFromPassword(*it->second))); | 390 SyncDataFromPassword(*it->second))); |
183 } | 391 } |
184 | 392 |
185 WriteToPasswordStore(sync_entries); | 393 WriteToPasswordStore(sync_entries); |
186 merge_result.set_error( | 394 merge_result.set_error( |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 }); | 438 }); |
231 return sync_data; | 439 return sync_data; |
232 } | 440 } |
233 | 441 |
234 syncer::SyncError PasswordSyncableService::ProcessSyncChanges( | 442 syncer::SyncError PasswordSyncableService::ProcessSyncChanges( |
235 const tracked_objects::Location& from_here, | 443 const tracked_objects::Location& from_here, |
236 const syncer::SyncChangeList& change_list) { | 444 const syncer::SyncChangeList& change_list) { |
237 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 445 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
238 base::AutoReset<bool> processing_changes(&is_processing_sync_changes_, true); | 446 base::AutoReset<bool> processing_changes(&is_processing_sync_changes_, true); |
239 SyncEntries sync_entries; | 447 SyncEntries sync_entries; |
240 base::Time time_now = base::Time::Now(); | 448 base::Time time_now = clock_->Now(); |
241 | 449 |
242 for (syncer::SyncChangeList::const_iterator it = change_list.begin(); | 450 for (syncer::SyncChangeList::const_iterator it = change_list.begin(); |
243 it != change_list.end(); ++it) { | 451 it != change_list.end(); ++it) { |
244 const sync_pb::EntitySpecifics& specifics = it->sync_data().GetSpecifics(); | 452 const sync_pb::EntitySpecifics& specifics = it->sync_data().GetSpecifics(); |
245 std::vector<std::unique_ptr<autofill::PasswordForm>>* entries = | 453 std::vector<std::unique_ptr<autofill::PasswordForm>>* entries = |
246 sync_entries.EntriesForChangeType(it->change_type()); | 454 sync_entries.EntriesForChangeType(it->change_type()); |
247 if (!entries) { | 455 if (!entries) { |
248 return sync_error_factory_->CreateAndUploadError( | 456 return sync_error_factory_->CreateAndUploadError( |
249 FROM_HERE, "Failed to process sync changes for passwords datatype."); | 457 FROM_HERE, "Failed to process sync changes for passwords datatype."); |
250 } | 458 } |
251 AppendPasswordFromSpecifics( | 459 AppendPasswordFromSpecifics( |
252 specifics.password().client_only_encrypted_data(), time_now, entries); | 460 specifics.password().client_only_encrypted_data(), time_now, entries); |
| 461 if (IsValidAndroidFacetURI(entries->back()->signon_realm)) { |
| 462 // Fix the Android Autofill credentials if needed. |
| 463 entries->back()->signon_realm = |
| 464 GetCorrectAndroidSignonRealm(entries->back()->signon_realm); |
| 465 entries->back()->origin = |
| 466 GURL(GetCorrectAndroidSignonRealm(entries->back()->origin.spec())); |
| 467 } |
253 } | 468 } |
254 | 469 |
255 WriteToPasswordStore(sync_entries); | 470 WriteToPasswordStore(sync_entries); |
256 return syncer::SyncError(); | 471 return syncer::SyncError(); |
257 } | 472 } |
258 | 473 |
259 void PasswordSyncableService::ActOnPasswordStoreChanges( | 474 void PasswordSyncableService::ActOnPasswordStoreChanges( |
260 const PasswordStoreChangeList& local_changes) { | 475 const PasswordStoreChangeList& local_changes) { |
261 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 476 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
262 | 477 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 WriteEntriesToDatabase(&PasswordStoreSync::UpdateLoginSync, | 547 WriteEntriesToDatabase(&PasswordStoreSync::UpdateLoginSync, |
333 entries.updated_entries, &changes); | 548 entries.updated_entries, &changes); |
334 WriteEntriesToDatabase(&PasswordStoreSync::RemoveLoginSync, | 549 WriteEntriesToDatabase(&PasswordStoreSync::RemoveLoginSync, |
335 entries.deleted_entries, &changes); | 550 entries.deleted_entries, &changes); |
336 | 551 |
337 // We have to notify password store observers of the change by hand since | 552 // We have to notify password store observers of the change by hand since |
338 // we use internal password store interfaces to make changes synchronously. | 553 // we use internal password store interfaces to make changes synchronously. |
339 password_store_->NotifyLoginsChanged(changes); | 554 password_store_->NotifyLoginsChanged(changes); |
340 } | 555 } |
341 | 556 |
342 // static | 557 void PasswordSyncableService::MergeSyncDataWithLocalData( |
343 void PasswordSyncableService::CreateOrUpdateEntry( | 558 const syncer::SyncDataList& sync_data, |
344 const syncer::SyncData& data, | |
345 PasswordEntryMap* unmatched_data_from_password_db, | 559 PasswordEntryMap* unmatched_data_from_password_db, |
346 SyncEntries* sync_entries, | 560 SyncEntries* sync_entries, |
347 syncer::SyncChangeList* updated_db_entries) { | 561 syncer::SyncChangeList* updated_db_entries) { |
348 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics(); | 562 std::map<std::string, const sync_pb::PasswordSpecificsData*> sync_data_map; |
349 const sync_pb::PasswordSpecificsData& password_specifics( | 563 for (const auto& data : sync_data) { |
350 specifics.password().client_only_encrypted_data()); | 564 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics(); |
| 565 const sync_pb::PasswordSpecificsData* password_specifics = |
| 566 &specifics.password().client_only_encrypted_data(); |
| 567 sync_data_map[MakePasswordSyncTag(*password_specifics)] = |
| 568 password_specifics; |
| 569 } |
| 570 DCHECK_EQ(sync_data_map.size(), sync_data.size()); |
| 571 |
| 572 for (auto it = sync_data_map.begin(); it != sync_data_map.end();) { |
| 573 if (IsValidAndroidFacetURI(it->second->signon_realm())) { |
| 574 // Perform deduplication of Android credentials saved in the wrong format. |
| 575 // For each incorrect entry, a duplicate of it is created in the correct |
| 576 // format, so Chrome can make use of it. The incorrect sync entries are |
| 577 // not deleted for now. |
| 578 std::string incorrect_tag = AndroidAutofillSyncTag(*it->second); |
| 579 std::string correct_tag = AndroidCorrectSyncTag(*it->second); |
| 580 auto it_sync_incorrect = sync_data_map.find(incorrect_tag); |
| 581 auto it_sync_correct = sync_data_map.find(correct_tag); |
| 582 auto it_local_data_correct = |
| 583 unmatched_data_from_password_db->find(correct_tag); |
| 584 auto it_local_data_incorrect = |
| 585 unmatched_data_from_password_db->find(incorrect_tag); |
| 586 if ((it != it_sync_incorrect && it != it_sync_correct) || |
| 587 (it_sync_incorrect == sync_data_map.end() && |
| 588 it_local_data_incorrect == unmatched_data_from_password_db->end())) { |
| 589 // The current credential is in an unexpected format or incorrect |
| 590 // credential don't exist. Just do what Sync would normally do. |
| 591 CreateOrUpdateEntry(*it->second, unmatched_data_from_password_db, |
| 592 sync_entries, updated_db_entries); |
| 593 ++it; |
| 594 } else { |
| 595 AndroidMergeResult result = Perform4WayMergeAndroidCredentials( |
| 596 it_sync_correct == sync_data_map.end() ? nullptr |
| 597 : it_sync_correct->second, |
| 598 it_sync_incorrect == sync_data_map.end() |
| 599 ? nullptr |
| 600 : it_sync_incorrect->second, |
| 601 it_local_data_correct == unmatched_data_from_password_db->end() |
| 602 ? nullptr |
| 603 : it_local_data_correct->second, |
| 604 it_local_data_incorrect == unmatched_data_from_password_db->end() |
| 605 ? nullptr |
| 606 : it_local_data_incorrect->second); |
| 607 // Add or update the correct local entry. |
| 608 if (result.new_local_correct) { |
| 609 auto* local_changes = sync_entries->EntriesForChangeType( |
| 610 it_local_data_correct == unmatched_data_from_password_db->end() |
| 611 ? syncer::SyncChange::ACTION_ADD |
| 612 : syncer::SyncChange::ACTION_UPDATE); |
| 613 local_changes->push_back(base::MakeUnique<autofill::PasswordForm>( |
| 614 result.new_local_correct.value())); |
| 615 local_changes->back()->date_synced = clock_->Now(); |
| 616 } |
| 617 // Add or update the incorrect local entry. |
| 618 if (result.new_local_incorrect) { |
| 619 auto* local_changes = sync_entries->EntriesForChangeType( |
| 620 it_local_data_incorrect == unmatched_data_from_password_db->end() |
| 621 ? syncer::SyncChange::ACTION_ADD |
| 622 : syncer::SyncChange::ACTION_UPDATE); |
| 623 local_changes->push_back(base::MakeUnique<autofill::PasswordForm>( |
| 624 result.new_local_incorrect.value())); |
| 625 local_changes->back()->date_synced = clock_->Now(); |
| 626 } |
| 627 if (it_local_data_correct != unmatched_data_from_password_db->end()) |
| 628 unmatched_data_from_password_db->erase(it_local_data_correct); |
| 629 if (it_local_data_incorrect != unmatched_data_from_password_db->end()) |
| 630 unmatched_data_from_password_db->erase(it_local_data_incorrect); |
| 631 // Add or update the correct sync entry. |
| 632 if (result.new_android_correct) { |
| 633 updated_db_entries->push_back( |
| 634 syncer::SyncChange(FROM_HERE, |
| 635 it_sync_correct == sync_data_map.end() |
| 636 ? syncer::SyncChange::ACTION_ADD |
| 637 : syncer::SyncChange::ACTION_UPDATE, |
| 638 result.new_android_correct.value())); |
| 639 } |
| 640 // Add or update the Android Autofill sync entry. |
| 641 if (result.new_android_incorrect) { |
| 642 updated_db_entries->push_back( |
| 643 syncer::SyncChange(FROM_HERE, |
| 644 it_sync_incorrect == sync_data_map.end() |
| 645 ? syncer::SyncChange::ACTION_ADD |
| 646 : syncer::SyncChange::ACTION_UPDATE, |
| 647 result.new_android_incorrect.value())); |
| 648 } |
| 649 bool increment = true; |
| 650 for (auto sync_data_it : {it_sync_incorrect, it_sync_correct}) { |
| 651 if (sync_data_it != sync_data_map.end()) { |
| 652 if (sync_data_it == it) { |
| 653 it = sync_data_map.erase(it); |
| 654 increment = false; |
| 655 } else { |
| 656 sync_data_map.erase(sync_data_it); |
| 657 } |
| 658 } |
| 659 } |
| 660 if (increment) |
| 661 ++it; |
| 662 } |
| 663 } else { |
| 664 // Not Android. |
| 665 CreateOrUpdateEntry(*it->second, unmatched_data_from_password_db, |
| 666 sync_entries, updated_db_entries); |
| 667 ++it; |
| 668 } |
| 669 } |
| 670 } |
| 671 |
| 672 void PasswordSyncableService::CreateOrUpdateEntry( |
| 673 const sync_pb::PasswordSpecificsData& password_specifics, |
| 674 PasswordEntryMap* unmatched_data_from_password_db, |
| 675 SyncEntries* sync_entries, |
| 676 syncer::SyncChangeList* updated_db_entries) { |
351 std::string tag = MakePasswordSyncTag(password_specifics); | 677 std::string tag = MakePasswordSyncTag(password_specifics); |
352 | 678 |
353 // Check whether the data from sync is already in the password store. | 679 // Check whether the data from sync is already in the password store. |
354 PasswordEntryMap::iterator existing_local_entry_iter = | 680 PasswordEntryMap::iterator existing_local_entry_iter = |
355 unmatched_data_from_password_db->find(tag); | 681 unmatched_data_from_password_db->find(tag); |
356 base::Time time_now = base::Time::Now(); | 682 base::Time time_now = clock_->Now(); |
357 if (existing_local_entry_iter == unmatched_data_from_password_db->end()) { | 683 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 | 684 // 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. | 685 // the password store. Add the entry to the new_entries list. |
360 AppendPasswordFromSpecifics(password_specifics, time_now, | 686 AppendPasswordFromSpecifics(password_specifics, time_now, |
361 &sync_entries->new_entries); | 687 &sync_entries->new_entries); |
362 } else { | 688 } else { |
363 // The entry is in password store. If the entries are not identical, then | 689 // The entry is in password store. If the entries are not identical, then |
364 // the entries need to be merged. | 690 // the entries need to be merged. |
365 // If the passwords differ, take the one that was created more recently. | 691 // If the passwords differ, take the one that was created more recently. |
366 const autofill::PasswordForm& password_form = | 692 const autofill::PasswordForm& password_form = |
(...skipping 27 matching lines...) Expand all Loading... |
394 new_changes.begin(), | 720 new_changes.begin(), |
395 new_changes.end()); | 721 new_changes.end()); |
396 } | 722 } |
397 } | 723 } |
398 | 724 |
399 syncer::SyncData SyncDataFromPassword( | 725 syncer::SyncData SyncDataFromPassword( |
400 const autofill::PasswordForm& password_form) { | 726 const autofill::PasswordForm& password_form) { |
401 sync_pb::EntitySpecifics password_data; | 727 sync_pb::EntitySpecifics password_data; |
402 sync_pb::PasswordSpecificsData* password_specifics = | 728 sync_pb::PasswordSpecificsData* password_specifics = |
403 password_data.mutable_password()->mutable_client_only_encrypted_data(); | 729 password_data.mutable_password()->mutable_client_only_encrypted_data(); |
404 #define CopyField(field) password_specifics->set_##field(password_form.field) | 730 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 | 731 |
430 std::string tag = MakePasswordSyncTag(*password_specifics); | 732 std::string tag = MakePasswordSyncTag(*password_specifics); |
431 return syncer::SyncData::CreateLocalData(tag, tag, password_data); | 733 return syncer::SyncData::CreateLocalData(tag, tag, password_data); |
432 } | 734 } |
433 | 735 |
434 autofill::PasswordForm PasswordFromSpecifics( | 736 autofill::PasswordForm PasswordFromSpecifics( |
435 const sync_pb::PasswordSpecificsData& password) { | 737 const sync_pb::PasswordSpecificsData& password) { |
436 autofill::PasswordForm new_password; | 738 autofill::PasswordForm new_password; |
437 new_password.scheme = | 739 new_password.scheme = |
438 static_cast<autofill::PasswordForm::Scheme>(password.scheme()); | 740 static_cast<autofill::PasswordForm::Scheme>(password.scheme()); |
(...skipping 26 matching lines...) Expand all Loading... |
465 | 767 |
466 std::string MakePasswordSyncTag(const autofill::PasswordForm& password) { | 768 std::string MakePasswordSyncTag(const autofill::PasswordForm& password) { |
467 return (net::EscapePath(password.origin.spec()) + "|" + | 769 return (net::EscapePath(password.origin.spec()) + "|" + |
468 net::EscapePath(base::UTF16ToUTF8(password.username_element)) + "|" + | 770 net::EscapePath(base::UTF16ToUTF8(password.username_element)) + "|" + |
469 net::EscapePath(base::UTF16ToUTF8(password.username_value)) + "|" + | 771 net::EscapePath(base::UTF16ToUTF8(password.username_value)) + "|" + |
470 net::EscapePath(base::UTF16ToUTF8(password.password_element)) + "|" + | 772 net::EscapePath(base::UTF16ToUTF8(password.password_element)) + "|" + |
471 net::EscapePath(password.signon_realm)); | 773 net::EscapePath(password.signon_realm)); |
472 } | 774 } |
473 | 775 |
474 } // namespace password_manager | 776 } // namespace password_manager |
OLD | NEW |