Chromium Code Reviews| 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 |