OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_store_mac.h" | 5 #include "chrome/browser/password_manager/password_store_mac.h" |
6 #include "chrome/browser/password_manager/password_store_mac_internal.h" | 6 #include "chrome/browser/password_manager/password_store_mac_internal.h" |
7 | 7 |
8 #include <CoreServices/CoreServices.h> | 8 #include <CoreServices/CoreServices.h> |
9 #include <set> | 9 #include <set> |
10 #include <string> | 10 #include <string> |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
188 return changes; | 188 return changes; |
189 } | 189 } |
190 | 190 |
191 // Moves the content of |second| to the end of |first|. | 191 // Moves the content of |second| to the end of |first|. |
192 void AppendSecondToFirst(ScopedVector<autofill::PasswordForm>* first, | 192 void AppendSecondToFirst(ScopedVector<autofill::PasswordForm>* first, |
193 ScopedVector<autofill::PasswordForm>* second) { | 193 ScopedVector<autofill::PasswordForm>* second) { |
194 first->insert(first->end(), second->begin(), second->end()); | 194 first->insert(first->end(), second->begin(), second->end()); |
195 second->weak_clear(); | 195 second->weak_clear(); |
196 } | 196 } |
197 | 197 |
198 // Returns an the best match for |base_form| from |keychain_forms|, or NULL if | |
199 // there is no suitable match. | |
200 PasswordForm* BestKeychainFormForForm( | |
vabr (Chromium)
2015/01/29 15:41:11
This is a plain move out of the internal_keychain_
vasilii
2015/01/29 16:41:12
Acknowledged.
| |
201 const PasswordForm& base_form, | |
202 const std::vector<PasswordForm*>* keychain_forms) { | |
vasilii
2015/01/29 16:41:13
const std::vector<PasswordForm*>&
vabr (Chromium)
2015/01/30 12:57:09
Done.
(Originally I did not intend to modify this
| |
203 PasswordForm* partial_match = NULL; | |
204 for (std::vector<PasswordForm*>::const_iterator i = keychain_forms->begin(); | |
205 i != keychain_forms->end(); ++i) { | |
206 // TODO(stuartmorgan): We should really be scoring path matches and picking | |
207 // the best, rather than just checking exact-or-not (although in practice | |
208 // keychain items with paths probably came from us). | |
209 if (internal_keychain_helpers::FormsMatchForMerge( | |
210 base_form, *(*i), internal_keychain_helpers::FUZZY_FORM_MATCH)) { | |
vasilii
2015/01/29 16:41:13
**i
vabr (Chromium)
2015/01/30 12:57:09
Done.
| |
211 if (base_form.origin == (*i)->origin) { | |
212 return *i; | |
213 } else if (!partial_match) { | |
214 partial_match = *i; | |
215 } | |
216 } | |
217 } | |
218 return partial_match; | |
219 } | |
220 | |
221 typedef base::Callback<void(scoped_ptr<autofill::PasswordForm>)> | |
222 TakeFormCallback; | |
vasilii
2015/01/29 16:41:13
The typedef should go to the beginning of the file
vabr (Chromium)
2015/01/30 12:57:09
Agreed, but I'll remove the typedef anyway.
| |
223 | |
224 // Stores |form| in either |non_blacklist| or |blacklist|, depending on whether | |
225 // |form| is blacklisted by the user. | |
226 void ExtractBlacklistFormsCallback( | |
vabr (Chromium)
2015/01/29 15:41:11
The three callbacks correspond to the three places
| |
227 ScopedVector<autofill::PasswordForm>* non_blacklist, | |
228 ScopedVector<autofill::PasswordForm>* blacklist, | |
229 scoped_ptr<autofill::PasswordForm> form) { | |
230 if (form->blacklisted_by_user) | |
231 blacklist->push_back(form.release()); | |
232 else | |
233 non_blacklist->push_back(form.release()); | |
234 } | |
235 | |
236 // If |db_form|, coming from the login DB, has a match in |keychain_forms|, the | |
237 // password of the match is copied into |db_form|, which is moved to | |
238 // |merged_forms|. The used keychain form is also marked in | |
239 // |used_keychain_forms|. Otherwise, |db_form| is moved to | |
240 // |unused_database_forms|. | |
241 void MergePasswordFormsCallback( | |
242 const std::vector<autofill::PasswordForm*>* keychain_forms, | |
vasilii
2015/01/29 16:41:13
const std::vector<autofill::PasswordForm*>&
vabr (Chromium)
2015/01/30 12:57:09
Done.
| |
243 std::set<autofill::PasswordForm*>* used_keychain_forms, | |
244 ScopedVector<autofill::PasswordForm>* unused_database_forms, | |
245 ScopedVector<autofill::PasswordForm>* merged_forms, | |
246 scoped_ptr<autofill::PasswordForm> db_form) { | |
247 PasswordForm* best_match = BestKeychainFormForForm(*db_form, keychain_forms); | |
248 if (best_match) { | |
249 used_keychain_forms->insert(best_match); | |
250 db_form->password_value = best_match->password_value; | |
251 merged_forms->push_back(db_form.release()); | |
252 } else { | |
253 unused_database_forms->push_back(db_form.release()); | |
254 } | |
255 } | |
256 | |
257 // If there is a password stored in |keychain| for |db_form|, adds it to | |
258 // |db_form| and moves |db_form| to |passwords|. Otherwise moves |db_form| to | |
259 // |unused_db_forms|. | |
260 void GetPasswordsForFormsCallback( | |
261 const AppleKeychain* keychain, | |
262 const std::vector<internal_keychain_helpers::ItemFormPair>& item_form_pairs, | |
263 ScopedVector<autofill::PasswordForm>* passwords, | |
264 ScopedVector<autofill::PasswordForm>* unused_db_forms, | |
265 scoped_ptr<autofill::PasswordForm> db_form) { | |
266 ScopedVector<autofill::PasswordForm> keychain_matches = | |
267 internal_keychain_helpers::ExtractPasswordsMergeableWithForm( | |
268 *keychain, item_form_pairs, *db_form); | |
269 | |
270 ScopedVector<autofill::PasswordForm> db_form_container; | |
271 db_form_container.push_back(db_form.release()); | |
272 internal_keychain_helpers::MergePasswordForms(&keychain_matches, | |
273 &db_form_container, passwords); | |
274 unused_db_forms->insert(unused_db_forms->end(), db_form_container.begin(), | |
vasilii
2015/01/29 16:41:13
Do you want to reuse AppendSecondToFirst?
vabr (Chromium)
2015/01/30 12:57:09
Indeed! Thanks, it felt like I forgot something.
| |
275 db_form_container.end()); | |
276 db_form_container.weak_clear(); | |
277 } | |
278 | |
279 // Iterates over all elements in |forms|, passes the pointed to objects to | |
280 // |move_form|, and clears |forms| efficiently. | |
281 void MoveAllFormsOut(ScopedVector<autofill::PasswordForm>* forms, | |
vabr (Chromium)
2015/01/29 15:41:11
This is the only function which gets to use weak_e
| |
282 TakeFormCallback move_form) { | |
283 for (auto* form_ptr : *forms) { | |
vasilii
2015/01/29 16:41:13
autofill::PasswordForm*
vabr (Chromium)
2015/01/30 12:57:09
Done.
| |
284 scoped_ptr<autofill::PasswordForm> form(form_ptr); | |
285 move_form.Run(form.Pass()); | |
286 } | |
287 // We moved the ownership of every form out of |forms|. For performance | |
288 // reasons, we can just weak_clear it, instead of nullptr-ing the respective | |
289 // elements and letting the vector's destructor to go through the list once | |
290 // more. This was tested on a banchmark, and seemed to make a difference on | |
291 // Mac. | |
292 forms->weak_clear(); | |
293 } | |
294 | |
198 } // namespace | 295 } // namespace |
199 | 296 |
200 #pragma mark - | 297 #pragma mark - |
201 | 298 |
202 // TODO(stuartmorgan): Convert most of this to private helpers in | 299 // TODO(stuartmorgan): Convert most of this to private helpers in |
203 // MacKeychainPasswordFormAdapter once it has sufficient higher-level public | 300 // MacKeychainPasswordFormAdapter once it has sufficient higher-level public |
204 // methods to provide test coverage. | 301 // methods to provide test coverage. |
205 namespace internal_keychain_helpers { | 302 namespace internal_keychain_helpers { |
206 | 303 |
207 // Returns a URL built from the given components. To create a URL without a | 304 // Returns a URL built from the given components. To create a URL without a |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
395 } | 492 } |
396 bool equal_realm = form_a.signon_realm == form_b.signon_realm; | 493 bool equal_realm = form_a.signon_realm == form_b.signon_realm; |
397 if (strictness == FUZZY_FORM_MATCH) { | 494 if (strictness == FUZZY_FORM_MATCH) { |
398 equal_realm |= (!form_a.original_signon_realm.empty()) && | 495 equal_realm |= (!form_a.original_signon_realm.empty()) && |
399 form_a.original_signon_realm == form_b.signon_realm; | 496 form_a.original_signon_realm == form_b.signon_realm; |
400 } | 497 } |
401 return form_a.scheme == form_b.scheme && equal_realm && | 498 return form_a.scheme == form_b.scheme && equal_realm && |
402 form_a.username_value == form_b.username_value; | 499 form_a.username_value == form_b.username_value; |
403 } | 500 } |
404 | 501 |
405 // Returns an the best match for |base_form| from |keychain_forms|, or NULL if | |
406 // there is no suitable match. | |
407 PasswordForm* BestKeychainFormForForm( | |
408 const PasswordForm& base_form, | |
409 const std::vector<PasswordForm*>* keychain_forms) { | |
410 PasswordForm* partial_match = NULL; | |
411 for (std::vector<PasswordForm*>::const_iterator i = keychain_forms->begin(); | |
412 i != keychain_forms->end(); ++i) { | |
413 // TODO(stuartmorgan): We should really be scoring path matches and picking | |
414 // the best, rather than just checking exact-or-not (although in practice | |
415 // keychain items with paths probably came from us). | |
416 if (FormsMatchForMerge(base_form, *(*i), FUZZY_FORM_MATCH)) { | |
417 if (base_form.origin == (*i)->origin) { | |
418 return *i; | |
419 } else if (!partial_match) { | |
420 partial_match = *i; | |
421 } | |
422 } | |
423 } | |
424 return partial_match; | |
425 } | |
426 | |
427 // Moves entries from |forms| that are blacklist entries into |blacklist|. | 502 // Moves entries from |forms| that are blacklist entries into |blacklist|. |
428 void ExtractBlacklistForms(ScopedVector<autofill::PasswordForm>* forms, | 503 void ExtractBlacklistForms(ScopedVector<autofill::PasswordForm>* forms, |
429 ScopedVector<autofill::PasswordForm>* blacklist) { | 504 ScopedVector<autofill::PasswordForm>* blacklist) { |
430 blacklist->reserve(blacklist->size() + forms->size()); | 505 blacklist->reserve(blacklist->size() + forms->size()); |
431 ScopedVector<autofill::PasswordForm> non_blacklist; | 506 ScopedVector<autofill::PasswordForm> non_blacklist; |
432 for (auto& form : *forms) { | 507 // Move forms in either |non_blacklist| or |blacklist|, depending on whether |
433 if (form->blacklisted_by_user) | 508 // they are blacklisted by the user. |
434 blacklist->push_back(form); | 509 MoveAllFormsOut(forms, base::Bind(&ExtractBlacklistFormsCallback, |
435 else | 510 &non_blacklist, blacklist)); |
436 non_blacklist.push_back(form); | |
437 form = nullptr; | |
438 } | |
439 forms->swap(non_blacklist); | 511 forms->swap(non_blacklist); |
440 } | 512 } |
441 | 513 |
442 // Takes |keychain_forms| and |database_forms| and moves the following 2 types | 514 // Takes |keychain_forms| and |database_forms| and moves the following 2 types |
443 // of forms to |merged_forms|: (1) blacklisted |database_forms|, (2) | 515 // of forms to |merged_forms|: (1) blacklisted |database_forms|, (2) |
444 // |database_forms| which have a corresponding entry in |keychain_forms|. The | 516 // |database_forms| which have a corresponding entry in |keychain_forms|. The |
445 // database forms of type (2) have their password value updated from the | 517 // database forms of type (2) have their password value updated from the |
446 // corresponding keychain form, and all the keychain forms corresponding to some | 518 // corresponding keychain form, and all the keychain forms corresponding to some |
447 // database form are removed from |keychain_forms| and deleted. | 519 // database form are removed from |keychain_forms| and deleted. |
448 void MergePasswordForms(ScopedVector<autofill::PasswordForm>* keychain_forms, | 520 void MergePasswordForms(ScopedVector<autofill::PasswordForm>* keychain_forms, |
449 ScopedVector<autofill::PasswordForm>* database_forms, | 521 ScopedVector<autofill::PasswordForm>* database_forms, |
450 ScopedVector<autofill::PasswordForm>* merged_forms) { | 522 ScopedVector<autofill::PasswordForm>* merged_forms) { |
451 // Pull out the database blacklist items, since they are used as-is rather | 523 // Pull out the database blacklist items, since they are used as-is rather |
452 // than being merged with keychain forms. | 524 // than being merged with keychain forms. |
453 ExtractBlacklistForms(database_forms, merged_forms); | 525 ExtractBlacklistForms(database_forms, merged_forms); |
454 | 526 |
455 // Merge the normal entries. | 527 // Merge the normal entries. |
456 ScopedVector<autofill::PasswordForm> unused_database_forms; | 528 ScopedVector<autofill::PasswordForm> unused_database_forms; |
457 unused_database_forms.reserve(database_forms->size()); | 529 unused_database_forms.reserve(database_forms->size()); |
458 std::set<autofill::PasswordForm*> used_keychain_forms; | 530 std::set<autofill::PasswordForm*> used_keychain_forms; |
459 for (auto& db_form : *database_forms) { | 531 // Move all database forms to either |merged_forms| or |
460 PasswordForm* best_match = | 532 // |unused_database_forms|, based on whether they have a match in the keychain |
461 BestKeychainFormForForm(*db_form, &keychain_forms->get()); | 533 // forms or not. If there is a match, add its password to the DB form and |
462 if (best_match) { | 534 // mark the keychain form as used. |
463 used_keychain_forms.insert(best_match); | 535 MoveAllFormsOut( |
464 db_form->password_value = best_match->password_value; | 536 database_forms, |
465 merged_forms->push_back(db_form); | 537 base::Bind(&MergePasswordFormsCallback, &keychain_forms->get(), |
466 } else { | 538 &used_keychain_forms, &unused_database_forms, merged_forms)); |
467 unused_database_forms.push_back(db_form); | |
468 } | |
469 db_form = nullptr; | |
470 } | |
471 database_forms->swap(unused_database_forms); | 539 database_forms->swap(unused_database_forms); |
472 | 540 |
473 // Clear out all the Keychain entries we used. | 541 // Clear out all the Keychain entries we used. |
474 ScopedVector<autofill::PasswordForm> unused_keychain_forms; | 542 ScopedVector<autofill::PasswordForm> unused_keychain_forms; |
475 unused_keychain_forms.reserve(keychain_forms->size()); | 543 unused_keychain_forms.reserve(keychain_forms->size()); |
476 for (auto& keychain_form : *keychain_forms) { | 544 for (auto& keychain_form : *keychain_forms) { |
477 if (!ContainsKey(used_keychain_forms, keychain_form)) { | 545 if (!ContainsKey(used_keychain_forms, keychain_form)) { |
478 unused_keychain_forms.push_back(keychain_form); | 546 unused_keychain_forms.push_back(keychain_form); |
479 keychain_form = nullptr; | 547 keychain_form = nullptr; |
480 } | 548 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
515 std::vector<SecKeychainItemRef> keychain_items; | 583 std::vector<SecKeychainItemRef> keychain_items; |
516 std::vector<ItemFormPair> item_form_pairs = | 584 std::vector<ItemFormPair> item_form_pairs = |
517 ExtractAllKeychainItemAttributesIntoPasswordForms(&keychain_items, | 585 ExtractAllKeychainItemAttributesIntoPasswordForms(&keychain_items, |
518 keychain); | 586 keychain); |
519 | 587 |
520 // Next, compare the attributes of the PasswordForms in |database_forms| | 588 // Next, compare the attributes of the PasswordForms in |database_forms| |
521 // against those in |item_form_pairs|, and extract password data for each | 589 // against those in |item_form_pairs|, and extract password data for each |
522 // matching PasswordForm using its corresponding SecKeychainItemRef. | 590 // matching PasswordForm using its corresponding SecKeychainItemRef. |
523 ScopedVector<autofill::PasswordForm> unused_db_forms; | 591 ScopedVector<autofill::PasswordForm> unused_db_forms; |
524 unused_db_forms.reserve(database_forms->size()); | 592 unused_db_forms.reserve(database_forms->size()); |
525 for (auto& db_form : *database_forms) { | 593 // Move database forms with a password stored in |keychain| to |passwords|, |
526 ScopedVector<autofill::PasswordForm> keychain_matches = | 594 // including the password. The rest is moved to |unused_db_forms|. |
527 ExtractPasswordsMergeableWithForm(keychain, item_form_pairs, *db_form); | 595 MoveAllFormsOut(database_forms, |
528 | 596 base::Bind(&GetPasswordsForFormsCallback, &keychain, |
529 ScopedVector<autofill::PasswordForm> db_form_container; | 597 item_form_pairs, passwords, &unused_db_forms)); |
530 db_form_container.push_back(db_form); | |
531 db_form = nullptr; | |
532 MergePasswordForms(&keychain_matches, &db_form_container, passwords); | |
533 unused_db_forms.insert(unused_db_forms.end(), db_form_container.begin(), | |
534 db_form_container.end()); | |
535 db_form_container.weak_clear(); | |
536 } | |
537 database_forms->swap(unused_db_forms); | 598 database_forms->swap(unused_db_forms); |
538 | 599 |
539 STLDeleteContainerPairSecondPointers(item_form_pairs.begin(), | 600 STLDeleteContainerPairSecondPointers(item_form_pairs.begin(), |
540 item_form_pairs.end()); | 601 item_form_pairs.end()); |
541 for (SecKeychainItemRef item : keychain_items) { | 602 for (SecKeychainItemRef item : keychain_items) { |
542 keychain.Free(item); | 603 keychain.Free(item); |
543 } | 604 } |
544 } | 605 } |
545 | 606 |
546 // TODO(stuartmorgan): signon_realm for proxies is not yet supported. | 607 // TODO(stuartmorgan): signon_realm for proxies is not yet supported. |
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1166 &forms_with_keychain_entry); | 1227 &forms_with_keychain_entry); |
1167 | 1228 |
1168 // Clean up any orphaned database entries. | 1229 // Clean up any orphaned database entries. |
1169 RemoveDatabaseForms(database_forms.get()); | 1230 RemoveDatabaseForms(database_forms.get()); |
1170 | 1231 |
1171 // Move the orphaned DB forms to the output parameter. | 1232 // Move the orphaned DB forms to the output parameter. |
1172 orphaned_forms->insert(orphaned_forms->end(), database_forms.begin(), | 1233 orphaned_forms->insert(orphaned_forms->end(), database_forms.begin(), |
1173 database_forms.end()); | 1234 database_forms.end()); |
1174 database_forms.weak_clear(); | 1235 database_forms.weak_clear(); |
1175 } | 1236 } |
OLD | NEW |