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 the best match for |base_form| from |keychain_forms|, or nullptr if | |
199 // there is no suitable match. | |
200 const PasswordForm* BestKeychainFormForForm( | |
201 const PasswordForm& base_form, | |
202 const std::vector<PasswordForm*>& keychain_forms) { | |
203 const PasswordForm* partial_match = nullptr; | |
204 for (const auto* keychain_form : keychain_forms) { | |
205 // TODO(stuartmorgan): We should really be scoring path matches and picking | |
206 // the best, rather than just checking exact-or-not (although in practice | |
207 // keychain items with paths probably came from us). | |
208 if (internal_keychain_helpers::FormsMatchForMerge( | |
209 base_form, *keychain_form, | |
210 internal_keychain_helpers::FUZZY_FORM_MATCH)) { | |
211 if (base_form.origin == keychain_form->origin) { | |
212 return keychain_form; | |
213 } else if (!partial_match) { | |
214 partial_match = keychain_form; | |
215 } | |
216 } | |
217 } | |
218 return partial_match; | |
219 } | |
220 | |
221 // Iterates over all elements in |forms|, passes the pointed to objects to | |
222 // |move_form|, and clears |forms| efficiently. | |
vasilii
2015/01/30 14:43:34
Expand the comment saying something about FormMove
vabr (Chromium)
2015/01/30 14:49:51
Done.
| |
223 template <typename FormMover> | |
224 inline void MoveAllFormsOut(ScopedVector<autofill::PasswordForm>* forms, | |
225 FormMover mover) { | |
226 for (autofill::PasswordForm* form_ptr : *forms) { | |
227 scoped_ptr<autofill::PasswordForm> form(form_ptr); | |
228 mover(form.Pass()); | |
vasilii
2015/01/30 14:43:34
mover(scoped_ptr<autofill::PasswordForm>(form_ptr)
vabr (Chromium)
2015/01/30 14:49:51
Done.
vasilii
2015/01/30 15:29:08
Just copy-paste my comment :-)
vabr (Chromium)
2015/01/30 16:47:51
Hopefully done this time. :)
| |
229 } | |
230 // We moved the ownership of every form out of |forms|. For performance | |
231 // reasons, we can just weak_clear it, instead of nullptr-ing the respective | |
232 // elements and letting the vector's destructor to go through the list once | |
233 // more. This was tested on a banchmark, and seemed to make a difference on | |
vasilii
2015/01/30 14:43:34
bEnchmark
vabr (Chromium)
2015/01/30 14:49:51
Done.
| |
234 // Mac. | |
235 forms->weak_clear(); | |
236 } | |
237 | |
198 } // namespace | 238 } // namespace |
199 | 239 |
200 #pragma mark - | 240 #pragma mark - |
201 | 241 |
202 // TODO(stuartmorgan): Convert most of this to private helpers in | 242 // TODO(stuartmorgan): Convert most of this to private helpers in |
203 // MacKeychainPasswordFormAdapter once it has sufficient higher-level public | 243 // MacKeychainPasswordFormAdapter once it has sufficient higher-level public |
204 // methods to provide test coverage. | 244 // methods to provide test coverage. |
205 namespace internal_keychain_helpers { | 245 namespace internal_keychain_helpers { |
206 | 246 |
207 // Returns a URL built from the given components. To create a URL without a | 247 // 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 } | 435 } |
396 bool equal_realm = form_a.signon_realm == form_b.signon_realm; | 436 bool equal_realm = form_a.signon_realm == form_b.signon_realm; |
397 if (strictness == FUZZY_FORM_MATCH) { | 437 if (strictness == FUZZY_FORM_MATCH) { |
398 equal_realm |= (!form_a.original_signon_realm.empty()) && | 438 equal_realm |= (!form_a.original_signon_realm.empty()) && |
399 form_a.original_signon_realm == form_b.signon_realm; | 439 form_a.original_signon_realm == form_b.signon_realm; |
400 } | 440 } |
401 return form_a.scheme == form_b.scheme && equal_realm && | 441 return form_a.scheme == form_b.scheme && equal_realm && |
402 form_a.username_value == form_b.username_value; | 442 form_a.username_value == form_b.username_value; |
403 } | 443 } |
404 | 444 |
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|. | 445 // Moves entries from |forms| that are blacklist entries into |blacklist|. |
428 void ExtractBlacklistForms(ScopedVector<autofill::PasswordForm>* forms, | 446 void ExtractBlacklistForms(ScopedVector<autofill::PasswordForm>* forms, |
429 ScopedVector<autofill::PasswordForm>* blacklist) { | 447 ScopedVector<autofill::PasswordForm>* blacklist) { |
430 blacklist->reserve(blacklist->size() + forms->size()); | 448 blacklist->reserve(blacklist->size() + forms->size()); |
431 ScopedVector<autofill::PasswordForm> non_blacklist; | 449 ScopedVector<autofill::PasswordForm> non_blacklist; |
432 for (auto& form : *forms) { | 450 // Move forms in either |non_blacklist| or |blacklist|, depending on whether |
451 // they are blacklisted by the user. | |
452 MoveAllFormsOut(forms, [&non_blacklist, blacklist]( | |
453 scoped_ptr<autofill::PasswordForm> form) { | |
433 if (form->blacklisted_by_user) | 454 if (form->blacklisted_by_user) |
434 blacklist->push_back(form); | 455 blacklist->push_back(form.release()); |
435 else | 456 else |
436 non_blacklist.push_back(form); | 457 non_blacklist.push_back(form.release()); |
437 form = nullptr; | 458 }); |
438 } | |
439 forms->swap(non_blacklist); | 459 forms->swap(non_blacklist); |
440 } | 460 } |
441 | 461 |
442 // Takes |keychain_forms| and |database_forms| and moves the following 2 types | 462 // Takes |keychain_forms| and |database_forms| and moves the following 2 types |
443 // of forms to |merged_forms|: (1) blacklisted |database_forms|, (2) | 463 // of forms to |merged_forms|: (1) blacklisted |database_forms|, (2) |
444 // |database_forms| which have a corresponding entry in |keychain_forms|. The | 464 // |database_forms| which have a corresponding entry in |keychain_forms|. The |
445 // database forms of type (2) have their password value updated from the | 465 // database forms of type (2) have their password value updated from the |
446 // corresponding keychain form, and all the keychain forms corresponding to some | 466 // corresponding keychain form, and all the keychain forms corresponding to some |
447 // database form are removed from |keychain_forms| and deleted. | 467 // database form are removed from |keychain_forms| and deleted. |
448 void MergePasswordForms(ScopedVector<autofill::PasswordForm>* keychain_forms, | 468 void MergePasswordForms(ScopedVector<autofill::PasswordForm>* keychain_forms, |
449 ScopedVector<autofill::PasswordForm>* database_forms, | 469 ScopedVector<autofill::PasswordForm>* database_forms, |
450 ScopedVector<autofill::PasswordForm>* merged_forms) { | 470 ScopedVector<autofill::PasswordForm>* merged_forms) { |
451 // Pull out the database blacklist items, since they are used as-is rather | 471 // Pull out the database blacklist items, since they are used as-is rather |
452 // than being merged with keychain forms. | 472 // than being merged with keychain forms. |
453 ExtractBlacklistForms(database_forms, merged_forms); | 473 ExtractBlacklistForms(database_forms, merged_forms); |
454 | 474 |
455 // Merge the normal entries. | 475 // Merge the normal entries. |
456 ScopedVector<autofill::PasswordForm> unused_database_forms; | 476 ScopedVector<autofill::PasswordForm> unused_database_forms; |
457 unused_database_forms.reserve(database_forms->size()); | 477 unused_database_forms.reserve(database_forms->size()); |
458 std::set<autofill::PasswordForm*> used_keychain_forms; | 478 std::set<const autofill::PasswordForm*> used_keychain_forms; |
459 for (auto& db_form : *database_forms) { | 479 // Move all database forms to either |merged_forms| or |
460 PasswordForm* best_match = | 480 // |unused_database_forms|, based on whether they have a match in the keychain |
461 BestKeychainFormForForm(*db_form, &keychain_forms->get()); | 481 // forms or not. If there is a match, add its password to the DB form and |
482 // mark the keychain form as used. | |
483 MoveAllFormsOut(database_forms, [keychain_forms, &used_keychain_forms, | |
484 merged_forms, &unused_database_forms]( | |
485 scoped_ptr<autofill::PasswordForm> form) { | |
486 const PasswordForm* best_match = | |
487 BestKeychainFormForForm(*form, keychain_forms->get()); | |
462 if (best_match) { | 488 if (best_match) { |
463 used_keychain_forms.insert(best_match); | 489 used_keychain_forms.insert(best_match); |
464 db_form->password_value = best_match->password_value; | 490 form->password_value = best_match->password_value; |
465 merged_forms->push_back(db_form); | 491 merged_forms->push_back(form.release()); |
466 } else { | 492 } else { |
467 unused_database_forms.push_back(db_form); | 493 unused_database_forms.push_back(form.release()); |
468 } | 494 } |
469 db_form = nullptr; | 495 }); |
470 } | |
471 database_forms->swap(unused_database_forms); | 496 database_forms->swap(unused_database_forms); |
472 | 497 |
473 // Clear out all the Keychain entries we used. | 498 // Clear out all the Keychain entries we used. |
474 ScopedVector<autofill::PasswordForm> unused_keychain_forms; | 499 ScopedVector<autofill::PasswordForm> unused_keychain_forms; |
475 unused_keychain_forms.reserve(keychain_forms->size()); | 500 unused_keychain_forms.reserve(keychain_forms->size()); |
476 for (auto& keychain_form : *keychain_forms) { | 501 for (auto& keychain_form : *keychain_forms) { |
477 if (!ContainsKey(used_keychain_forms, keychain_form)) { | 502 if (!ContainsKey(used_keychain_forms, keychain_form)) { |
478 unused_keychain_forms.push_back(keychain_form); | 503 unused_keychain_forms.push_back(keychain_form); |
479 keychain_form = nullptr; | 504 keychain_form = nullptr; |
480 } | 505 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
515 std::vector<SecKeychainItemRef> keychain_items; | 540 std::vector<SecKeychainItemRef> keychain_items; |
516 std::vector<ItemFormPair> item_form_pairs = | 541 std::vector<ItemFormPair> item_form_pairs = |
517 ExtractAllKeychainItemAttributesIntoPasswordForms(&keychain_items, | 542 ExtractAllKeychainItemAttributesIntoPasswordForms(&keychain_items, |
518 keychain); | 543 keychain); |
519 | 544 |
520 // Next, compare the attributes of the PasswordForms in |database_forms| | 545 // Next, compare the attributes of the PasswordForms in |database_forms| |
521 // against those in |item_form_pairs|, and extract password data for each | 546 // against those in |item_form_pairs|, and extract password data for each |
522 // matching PasswordForm using its corresponding SecKeychainItemRef. | 547 // matching PasswordForm using its corresponding SecKeychainItemRef. |
523 ScopedVector<autofill::PasswordForm> unused_db_forms; | 548 ScopedVector<autofill::PasswordForm> unused_db_forms; |
524 unused_db_forms.reserve(database_forms->size()); | 549 unused_db_forms.reserve(database_forms->size()); |
525 for (auto& db_form : *database_forms) { | 550 // Move database forms with a password stored in |keychain| to |passwords|, |
551 // including the password. The rest is moved to |unused_db_forms|. | |
552 MoveAllFormsOut(database_forms, | |
553 [&keychain, &item_form_pairs, passwords, &unused_db_forms]( | |
554 scoped_ptr<autofill::PasswordForm> form) { | |
526 ScopedVector<autofill::PasswordForm> keychain_matches = | 555 ScopedVector<autofill::PasswordForm> keychain_matches = |
527 ExtractPasswordsMergeableWithForm(keychain, item_form_pairs, *db_form); | 556 ExtractPasswordsMergeableWithForm(keychain, item_form_pairs, *form); |
528 | 557 |
529 ScopedVector<autofill::PasswordForm> db_form_container; | 558 ScopedVector<autofill::PasswordForm> db_form_container; |
530 db_form_container.push_back(db_form); | 559 db_form_container.push_back(form.release()); |
531 db_form = nullptr; | |
532 MergePasswordForms(&keychain_matches, &db_form_container, passwords); | 560 MergePasswordForms(&keychain_matches, &db_form_container, passwords); |
533 unused_db_forms.insert(unused_db_forms.end(), db_form_container.begin(), | 561 AppendSecondToFirst(&unused_db_forms, &db_form_container); |
534 db_form_container.end()); | 562 }); |
535 db_form_container.weak_clear(); | |
536 } | |
537 database_forms->swap(unused_db_forms); | 563 database_forms->swap(unused_db_forms); |
538 | 564 |
539 STLDeleteContainerPairSecondPointers(item_form_pairs.begin(), | 565 STLDeleteContainerPairSecondPointers(item_form_pairs.begin(), |
540 item_form_pairs.end()); | 566 item_form_pairs.end()); |
541 for (SecKeychainItemRef item : keychain_items) { | 567 for (SecKeychainItemRef item : keychain_items) { |
542 keychain.Free(item); | 568 keychain.Free(item); |
543 } | 569 } |
544 } | 570 } |
545 | 571 |
546 // TODO(stuartmorgan): signon_realm for proxies is not yet supported. | 572 // TODO(stuartmorgan): signon_realm for proxies is not yet supported. |
(...skipping 28 matching lines...) Expand all Loading... | |
575 bool FormIsValidAndMatchesOtherForm(const PasswordForm& query_form, | 601 bool FormIsValidAndMatchesOtherForm(const PasswordForm& query_form, |
576 const PasswordForm& other_form) { | 602 const PasswordForm& other_form) { |
577 std::string server; | 603 std::string server; |
578 std::string security_domain; | 604 std::string security_domain; |
579 UInt32 port; | 605 UInt32 port; |
580 bool is_secure; | 606 bool is_secure; |
581 if (!ExtractSignonRealmComponents(query_form.signon_realm, &server, &port, | 607 if (!ExtractSignonRealmComponents(query_form.signon_realm, &server, &port, |
582 &is_secure, &security_domain)) { | 608 &is_secure, &security_domain)) { |
583 return false; | 609 return false; |
584 } | 610 } |
585 return internal_keychain_helpers::FormsMatchForMerge( | 611 return FormsMatchForMerge(query_form, other_form, STRICT_FORM_MATCH); |
586 query_form, other_form, STRICT_FORM_MATCH); | |
587 } | 612 } |
588 | 613 |
589 ScopedVector<autofill::PasswordForm> ExtractPasswordsMergeableWithForm( | 614 ScopedVector<autofill::PasswordForm> ExtractPasswordsMergeableWithForm( |
590 const AppleKeychain& keychain, | 615 const AppleKeychain& keychain, |
591 const std::vector<ItemFormPair>& item_form_pairs, | 616 const std::vector<ItemFormPair>& item_form_pairs, |
592 const PasswordForm& query_form) { | 617 const PasswordForm& query_form) { |
593 ScopedVector<autofill::PasswordForm> matches; | 618 ScopedVector<autofill::PasswordForm> matches; |
594 for (std::vector<ItemFormPair>::const_iterator i = item_form_pairs.begin(); | 619 for (std::vector<ItemFormPair>::const_iterator i = item_form_pairs.begin(); |
595 i != item_form_pairs.end(); ++i) { | 620 i != item_form_pairs.end(); ++i) { |
596 if (FormIsValidAndMatchesOtherForm(query_form, *(i->second))) { | 621 if (FormIsValidAndMatchesOtherForm(query_form, *(i->second))) { |
597 // Create a new object, since the caller is responsible for deleting the | 622 // Create a new object, since the caller is responsible for deleting the |
598 // returned forms. | 623 // returned forms. |
599 scoped_ptr<PasswordForm> form_with_password(new PasswordForm()); | 624 scoped_ptr<PasswordForm> form_with_password(new PasswordForm()); |
600 internal_keychain_helpers::FillPasswordFormFromKeychainItem( | 625 FillPasswordFormFromKeychainItem( |
601 keychain, *(i->first), form_with_password.get(), | 626 keychain, *(i->first), form_with_password.get(), |
602 true); // Load password attributes and data. | 627 true); // Load password attributes and data. |
603 // Do not include blacklisted items found in the keychain. | 628 // Do not include blacklisted items found in the keychain. |
604 if (!form_with_password->blacklisted_by_user) | 629 if (!form_with_password->blacklisted_by_user) |
605 matches.push_back(form_with_password.release()); | 630 matches.push_back(form_with_password.release()); |
606 } | 631 } |
607 } | 632 } |
608 return matches.Pass(); | 633 return matches.Pass(); |
609 } | 634 } |
610 | 635 |
(...skipping 434 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1045 | 1070 |
1046 ScopedVector<autofill::PasswordForm> matched_forms; | 1071 ScopedVector<autofill::PasswordForm> matched_forms; |
1047 internal_keychain_helpers::MergePasswordForms( | 1072 internal_keychain_helpers::MergePasswordForms( |
1048 &keychain_forms, &database_forms, &matched_forms); | 1073 &keychain_forms, &database_forms, &matched_forms); |
1049 | 1074 |
1050 // Strip any blacklist entries out of the unused Keychain array, then take | 1075 // Strip any blacklist entries out of the unused Keychain array, then take |
1051 // all the entries that are left (which we can use as imported passwords). | 1076 // all the entries that are left (which we can use as imported passwords). |
1052 ScopedVector<PasswordForm> keychain_blacklist_forms; | 1077 ScopedVector<PasswordForm> keychain_blacklist_forms; |
1053 internal_keychain_helpers::ExtractBlacklistForms(&keychain_forms, | 1078 internal_keychain_helpers::ExtractBlacklistForms(&keychain_forms, |
1054 &keychain_blacklist_forms); | 1079 &keychain_blacklist_forms); |
1055 matched_forms.insert(matched_forms.end(), | 1080 AppendSecondToFirst(&matched_forms, &keychain_forms); |
1056 keychain_forms.begin(), | |
1057 keychain_forms.end()); | |
1058 keychain_forms.weak_clear(); | |
1059 | 1081 |
1060 if (!database_forms.empty()) { | 1082 if (!database_forms.empty()) { |
1061 RemoveDatabaseForms(database_forms.get()); | 1083 RemoveDatabaseForms(database_forms.get()); |
1062 NotifyLoginsChanged(FormsToRemoveChangeList(database_forms.get())); | 1084 NotifyLoginsChanged(FormsToRemoveChangeList(database_forms.get())); |
1063 } | 1085 } |
1064 | 1086 |
1065 callback_runner.Run(matched_forms.Pass()); | 1087 callback_runner.Run(matched_forms.Pass()); |
1066 } | 1088 } |
1067 | 1089 |
1068 void PasswordStoreMac::GetBlacklistLoginsImpl(GetLoginsRequest* request) { | 1090 void PasswordStoreMac::GetBlacklistLoginsImpl(GetLoginsRequest* request) { |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1162 | 1184 |
1163 // Filter forms with corresponding Keychain entry out of |database_forms|. | 1185 // Filter forms with corresponding Keychain entry out of |database_forms|. |
1164 ScopedVector<PasswordForm> forms_with_keychain_entry; | 1186 ScopedVector<PasswordForm> forms_with_keychain_entry; |
1165 internal_keychain_helpers::GetPasswordsForForms(*keychain_, &database_forms, | 1187 internal_keychain_helpers::GetPasswordsForForms(*keychain_, &database_forms, |
1166 &forms_with_keychain_entry); | 1188 &forms_with_keychain_entry); |
1167 | 1189 |
1168 // Clean up any orphaned database entries. | 1190 // Clean up any orphaned database entries. |
1169 RemoveDatabaseForms(database_forms.get()); | 1191 RemoveDatabaseForms(database_forms.get()); |
1170 | 1192 |
1171 // Move the orphaned DB forms to the output parameter. | 1193 // Move the orphaned DB forms to the output parameter. |
1172 orphaned_forms->insert(orphaned_forms->end(), database_forms.begin(), | 1194 AppendSecondToFirst(orphaned_forms, &database_forms); |
1173 database_forms.end()); | |
1174 database_forms.weak_clear(); | |
1175 } | 1195 } |
OLD | NEW |