Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(142)

Side by Side Diff: components/password_manager/core/browser/login_database.cc

Issue 906973007: PasswordStore: Clean up expectations about rewriting vectors of forms (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/login_database.h" 5 #include "components/password_manager/core/browser/login_database.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits> 8 #include <limits>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 639 matching lines...) Expand 10 before | Expand all | Expand 10 after
650 SQL_FROM_HERE, 650 SQL_FROM_HERE,
651 "DELETE FROM logins WHERE date_synced >= ? AND date_synced < ?")); 651 "DELETE FROM logins WHERE date_synced >= ? AND date_synced < ?"));
652 s.BindInt64(0, delete_begin.ToInternalValue()); 652 s.BindInt64(0, delete_begin.ToInternalValue());
653 s.BindInt64(1, 653 s.BindInt64(1,
654 delete_end.is_null() ? base::Time::Max().ToInternalValue() 654 delete_end.is_null() ? base::Time::Max().ToInternalValue()
655 : delete_end.ToInternalValue()); 655 : delete_end.ToInternalValue());
656 656
657 return s.Run(); 657 return s.Run();
658 } 658 }
659 659
660 // static
660 LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement( 661 LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement(
661 PasswordForm* form, 662 PasswordForm* form,
662 sql::Statement& s) const { 663 sql::Statement& s) {
663 std::string encrypted_password; 664 std::string encrypted_password;
664 s.ColumnBlobAsString(COLUMN_PASSWORD_VALUE, &encrypted_password); 665 s.ColumnBlobAsString(COLUMN_PASSWORD_VALUE, &encrypted_password);
665 base::string16 decrypted_password; 666 base::string16 decrypted_password;
666 EncryptionResult encryption_result = 667 EncryptionResult encryption_result =
667 DecryptedString(encrypted_password, &decrypted_password); 668 DecryptedString(encrypted_password, &decrypted_password);
668 if (encryption_result != ENCRYPTION_RESULT_SUCCESS) 669 if (encryption_result != ENCRYPTION_RESULT_SUCCESS)
669 return encryption_result; 670 return encryption_result;
670 671
671 std::string tmp = s.ColumnString(COLUMN_ORIGIN_URL); 672 std::string tmp = s.ColumnString(COLUMN_ORIGIN_URL);
672 form->origin = GURL(tmp); 673 form->origin = GURL(tmp);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
710 form->avatar_url = GURL(s.ColumnString(COLUMN_AVATAR_URL)); 711 form->avatar_url = GURL(s.ColumnString(COLUMN_AVATAR_URL));
711 form->federation_url = GURL(s.ColumnString(COLUMN_FEDERATION_URL)); 712 form->federation_url = GURL(s.ColumnString(COLUMN_FEDERATION_URL));
712 form->skip_zero_click = (s.ColumnInt(COLUMN_SKIP_ZERO_CLICK) > 0); 713 form->skip_zero_click = (s.ColumnInt(COLUMN_SKIP_ZERO_CLICK) > 0);
713 return ENCRYPTION_RESULT_SUCCESS; 714 return ENCRYPTION_RESULT_SUCCESS;
714 } 715 }
715 716
716 bool LoginDatabase::GetLogins( 717 bool LoginDatabase::GetLogins(
717 const PasswordForm& form, 718 const PasswordForm& form,
718 ScopedVector<autofill::PasswordForm>* forms) const { 719 ScopedVector<autofill::PasswordForm>* forms) const {
719 DCHECK(forms); 720 DCHECK(forms);
721 forms->clear();
720 // You *must* change LoginTableColumns if this query changes. 722 // You *must* change LoginTableColumns if this query changes.
721 const std::string sql_query = 723 const std::string sql_query =
722 "SELECT origin_url, action_url, " 724 "SELECT origin_url, action_url, "
723 "username_element, username_value, " 725 "username_element, username_value, "
724 "password_element, password_value, submit_element, " 726 "password_element, password_value, submit_element, "
725 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, " 727 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
726 "scheme, password_type, possible_usernames, times_used, form_data, " 728 "scheme, password_type, possible_usernames, times_used, form_data, "
727 "date_synced, display_name, avatar_url, " 729 "date_synced, display_name, avatar_url, "
728 "federation_url, skip_zero_click " 730 "federation_url, skip_zero_click "
729 "FROM logins WHERE signon_realm == ? "; 731 "FROM logins WHERE signon_realm == ? ";
730 sql::Statement s; 732 sql::Statement s;
731 const GURL signon_realm(form.signon_realm); 733 const GURL signon_realm(form.signon_realm);
732 std::string registered_domain = GetRegistryControlledDomain(signon_realm); 734 std::string registered_domain = GetRegistryControlledDomain(signon_realm);
733 PSLDomainMatchMetric psl_domain_match_metric = PSL_DOMAIN_MATCH_NONE;
734 const bool should_PSL_matching_apply = 735 const bool should_PSL_matching_apply =
735 form.scheme == PasswordForm::SCHEME_HTML && 736 form.scheme == PasswordForm::SCHEME_HTML &&
736 ShouldPSLDomainMatchingApply(registered_domain); 737 ShouldPSLDomainMatchingApply(registered_domain);
737 // PSL matching only applies to HTML forms. 738 // PSL matching only applies to HTML forms.
738 if (should_PSL_matching_apply) { 739 if (should_PSL_matching_apply) {
739 // We are extending the original SQL query with one that includes more 740 // We are extending the original SQL query with one that includes more
740 // possible matches based on public suffix domain matching. Using a regexp 741 // possible matches based on public suffix domain matching. Using a regexp
741 // here is just an optimization to not have to parse all the stored entries 742 // here is just an optimization to not have to parse all the stored entries
742 // in the |logins| table. The result (scheme, domain and port) is verified 743 // in the |logins| table. The result (scheme, domain and port) is verified
743 // further down using GURL. See the functions SchemeMatches, 744 // further down using GURL. See the functions SchemeMatches,
(...skipping 14 matching lines...) Expand all
758 const std::string port = signon_realm.port(); 759 const std::string port = signon_realm.port();
759 // For a signon realm such as http://foo.bar/, this regexp will match 760 // For a signon realm such as http://foo.bar/, this regexp will match
760 // domains on the form http://foo.bar/, http://www.foo.bar/, 761 // domains on the form http://foo.bar/, http://www.foo.bar/,
761 // http://www.mobile.foo.bar/. It will not match http://notfoo.bar/. 762 // http://www.mobile.foo.bar/. It will not match http://notfoo.bar/.
762 // The scheme and port has to be the same as the observed form. 763 // The scheme and port has to be the same as the observed form.
763 std::string regexp = "^(" + scheme + ":\\/\\/)([\\w-]+\\.)*" + 764 std::string regexp = "^(" + scheme + ":\\/\\/)([\\w-]+\\.)*" +
764 registered_domain + "(:" + port + ")?\\/$"; 765 registered_domain + "(:" + port + ")?\\/$";
765 s.BindString(0, form.signon_realm); 766 s.BindString(0, form.signon_realm);
766 s.BindString(1, regexp); 767 s.BindString(1, regexp);
767 } else { 768 } else {
768 psl_domain_match_metric = PSL_DOMAIN_MATCH_NOT_USED; 769 UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering",
770 PSL_DOMAIN_MATCH_NOT_USED,
771 PSL_DOMAIN_MATCH_COUNT);
769 s.Assign(db_.GetCachedStatement(SQL_FROM_HERE, sql_query.c_str())); 772 s.Assign(db_.GetCachedStatement(SQL_FROM_HERE, sql_query.c_str()));
770 s.BindString(0, form.signon_realm); 773 s.BindString(0, form.signon_realm);
771 } 774 }
772 775
773 while (s.Step()) { 776 return StatementToForms(&s, should_PSL_matching_apply ? &form : nullptr,
774 scoped_ptr<PasswordForm> new_form(new PasswordForm()); 777 forms);
775 EncryptionResult result = InitPasswordFormFromStatement(new_form.get(), s);
776 if (result == ENCRYPTION_RESULT_SERVICE_FAILURE)
777 return false;
778 if (result == ENCRYPTION_RESULT_ITEM_FAILURE)
779 continue;
780 DCHECK(result == ENCRYPTION_RESULT_SUCCESS);
781 if (should_PSL_matching_apply) {
782 if (!IsPublicSuffixDomainMatch(new_form->signon_realm,
783 form.signon_realm)) {
784 // The database returned results that should not match. Skipping result.
785 continue;
786 }
787 if (form.signon_realm != new_form->signon_realm) {
788 // Ignore non-HTML matches.
789 if (new_form->scheme != PasswordForm::SCHEME_HTML)
790 continue;
791
792 psl_domain_match_metric = PSL_DOMAIN_MATCH_FOUND;
793 // This is not a perfect match, so we need to create a new valid result.
794 // We do this by copying over origin, signon realm and action from the
795 // observed form and setting the original signon realm to what we found
796 // in the database. We use the fact that |original_signon_realm| is
797 // non-empty to communicate that this match was found using public
798 // suffix matching.
799 new_form->original_signon_realm = new_form->signon_realm;
800 new_form->origin = form.origin;
801 new_form->signon_realm = form.signon_realm;
802 new_form->action = form.action;
803 }
804 }
805 forms->push_back(new_form.release());
806 }
807 UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering",
808 psl_domain_match_metric,
809 PSL_DOMAIN_MATCH_COUNT);
810 return s.Succeeded();
811 } 778 }
812 779
813 bool LoginDatabase::GetLoginsCreatedBetween( 780 bool LoginDatabase::GetLoginsCreatedBetween(
814 const base::Time begin, 781 const base::Time begin,
815 const base::Time end, 782 const base::Time end,
816 ScopedVector<autofill::PasswordForm>* forms) const { 783 ScopedVector<autofill::PasswordForm>* forms) const {
817 DCHECK(forms); 784 DCHECK(forms);
785 forms->clear();
818 sql::Statement s(db_.GetCachedStatement( 786 sql::Statement s(db_.GetCachedStatement(
819 SQL_FROM_HERE, 787 SQL_FROM_HERE,
820 "SELECT origin_url, action_url, " 788 "SELECT origin_url, action_url, "
821 "username_element, username_value, " 789 "username_element, username_value, "
822 "password_element, password_value, submit_element, " 790 "password_element, password_value, submit_element, "
823 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, " 791 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
824 "scheme, password_type, possible_usernames, times_used, form_data, " 792 "scheme, password_type, possible_usernames, times_used, form_data, "
825 "date_synced, display_name, avatar_url, " 793 "date_synced, display_name, avatar_url, "
826 "federation_url, skip_zero_click FROM logins " 794 "federation_url, skip_zero_click FROM logins "
827 "WHERE date_created >= ? AND date_created < ?" 795 "WHERE date_created >= ? AND date_created < ?"
828 "ORDER BY origin_url")); 796 "ORDER BY origin_url"));
829 s.BindInt64(0, begin.ToInternalValue()); 797 s.BindInt64(0, begin.ToInternalValue());
830 s.BindInt64(1, end.is_null() ? std::numeric_limits<int64>::max() 798 s.BindInt64(1, end.is_null() ? std::numeric_limits<int64>::max()
831 : end.ToInternalValue()); 799 : end.ToInternalValue());
832 800
833 while (s.Step()) { 801 return StatementToForms(&s, nullptr, forms);
834 scoped_ptr<PasswordForm> new_form(new PasswordForm());
835 EncryptionResult result = InitPasswordFormFromStatement(new_form.get(), s);
836 if (result == ENCRYPTION_RESULT_SERVICE_FAILURE)
837 return false;
838 if (result == ENCRYPTION_RESULT_ITEM_FAILURE)
839 continue;
840 DCHECK(result == ENCRYPTION_RESULT_SUCCESS);
841 forms->push_back(new_form.release());
842 }
843 return s.Succeeded();
844 } 802 }
845 803
846 bool LoginDatabase::GetLoginsSyncedBetween( 804 bool LoginDatabase::GetLoginsSyncedBetween(
847 const base::Time begin, 805 const base::Time begin,
848 const base::Time end, 806 const base::Time end,
849 ScopedVector<autofill::PasswordForm>* forms) const { 807 ScopedVector<autofill::PasswordForm>* forms) const {
850 DCHECK(forms); 808 DCHECK(forms);
809 forms->clear();
851 sql::Statement s(db_.GetCachedStatement( 810 sql::Statement s(db_.GetCachedStatement(
852 SQL_FROM_HERE, 811 SQL_FROM_HERE,
853 "SELECT origin_url, action_url, username_element, username_value, " 812 "SELECT origin_url, action_url, username_element, username_value, "
854 "password_element, password_value, submit_element, signon_realm, " 813 "password_element, password_value, submit_element, signon_realm, "
855 "ssl_valid, preferred, date_created, blacklisted_by_user, " 814 "ssl_valid, preferred, date_created, blacklisted_by_user, "
856 "scheme, password_type, possible_usernames, times_used, form_data, " 815 "scheme, password_type, possible_usernames, times_used, form_data, "
857 "date_synced, display_name, avatar_url, " 816 "date_synced, display_name, avatar_url, "
858 "federation_url, skip_zero_click FROM logins " 817 "federation_url, skip_zero_click FROM logins "
859 "WHERE date_synced >= ? AND date_synced < ?" 818 "WHERE date_synced >= ? AND date_synced < ?"
860 "ORDER BY origin_url")); 819 "ORDER BY origin_url"));
861 s.BindInt64(0, begin.ToInternalValue()); 820 s.BindInt64(0, begin.ToInternalValue());
862 s.BindInt64(1, 821 s.BindInt64(1,
863 end.is_null() ? base::Time::Max().ToInternalValue() 822 end.is_null() ? base::Time::Max().ToInternalValue()
864 : end.ToInternalValue()); 823 : end.ToInternalValue());
865 824
866 while (s.Step()) { 825 return StatementToForms(&s, nullptr, forms);
867 scoped_ptr<PasswordForm> new_form(new PasswordForm());
868 EncryptionResult result = InitPasswordFormFromStatement(new_form.get(), s);
869 if (result == ENCRYPTION_RESULT_SERVICE_FAILURE)
870 return false;
871 if (result == ENCRYPTION_RESULT_ITEM_FAILURE)
872 continue;
873 DCHECK(result == ENCRYPTION_RESULT_SUCCESS);
874 forms->push_back(new_form.release());
875 }
876 return s.Succeeded();
877 } 826 }
878 827
879 bool LoginDatabase::GetAutofillableLogins( 828 bool LoginDatabase::GetAutofillableLogins(
880 ScopedVector<autofill::PasswordForm>* forms) const { 829 ScopedVector<autofill::PasswordForm>* forms) const {
881 return GetAllLoginsWithBlacklistSetting(false, forms); 830 return GetAllLoginsWithBlacklistSetting(false, forms);
882 } 831 }
883 832
884 bool LoginDatabase::GetBlacklistLogins( 833 bool LoginDatabase::GetBlacklistLogins(
885 ScopedVector<autofill::PasswordForm>* forms) const { 834 ScopedVector<autofill::PasswordForm>* forms) const {
886 return GetAllLoginsWithBlacklistSetting(true, forms); 835 return GetAllLoginsWithBlacklistSetting(true, forms);
887 } 836 }
888 837
889 bool LoginDatabase::GetAllLoginsWithBlacklistSetting( 838 bool LoginDatabase::GetAllLoginsWithBlacklistSetting(
890 bool blacklisted, 839 bool blacklisted,
891 ScopedVector<autofill::PasswordForm>* forms) const { 840 ScopedVector<autofill::PasswordForm>* forms) const {
892 DCHECK(forms); 841 DCHECK(forms);
842 forms->clear();
893 // You *must* change LoginTableColumns if this query changes. 843 // You *must* change LoginTableColumns if this query changes.
894 sql::Statement s(db_.GetCachedStatement( 844 sql::Statement s(db_.GetCachedStatement(
895 SQL_FROM_HERE, 845 SQL_FROM_HERE,
896 "SELECT origin_url, action_url, " 846 "SELECT origin_url, action_url, "
897 "username_element, username_value, " 847 "username_element, username_value, "
898 "password_element, password_value, submit_element, " 848 "password_element, password_value, submit_element, "
899 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, " 849 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
900 "scheme, password_type, possible_usernames, times_used, form_data, " 850 "scheme, password_type, possible_usernames, times_used, form_data, "
901 "date_synced, display_name, avatar_url, " 851 "date_synced, display_name, avatar_url, "
902 "federation_url, skip_zero_click FROM logins " 852 "federation_url, skip_zero_click FROM logins "
903 "WHERE blacklisted_by_user == ? ORDER BY origin_url")); 853 "WHERE blacklisted_by_user == ? ORDER BY origin_url"));
904 s.BindInt(0, blacklisted ? 1 : 0); 854 s.BindInt(0, blacklisted ? 1 : 0);
905 855
906 while (s.Step()) { 856 return StatementToForms(&s, nullptr, forms);
907 scoped_ptr<PasswordForm> new_form(new PasswordForm());
908 EncryptionResult result = InitPasswordFormFromStatement(new_form.get(), s);
909 if (result == ENCRYPTION_RESULT_SERVICE_FAILURE)
910 return false;
911 if (result == ENCRYPTION_RESULT_ITEM_FAILURE)
912 continue;
913 DCHECK(result == ENCRYPTION_RESULT_SUCCESS);
914 forms->push_back(new_form.release());
915 }
916 return s.Succeeded();
917 } 857 }
918 858
919 bool LoginDatabase::DeleteAndRecreateDatabaseFile() { 859 bool LoginDatabase::DeleteAndRecreateDatabaseFile() {
920 DCHECK(db_.is_open()); 860 DCHECK(db_.is_open());
921 meta_table_.Reset(); 861 meta_table_.Reset();
922 db_.Close(); 862 db_.Close();
923 sql::Connection::Delete(db_path_); 863 sql::Connection::Delete(db_path_);
924 return Init(); 864 return Init();
925 } 865 }
926 866
867 // static
868 bool LoginDatabase::StatementToForms(
869 sql::Statement* statement,
870 const autofill::PasswordForm* psl_match,
871 ScopedVector<autofill::PasswordForm>* forms) {
872 PSLDomainMatchMetric psl_domain_match_metric = PSL_DOMAIN_MATCH_NONE;
873
874 // Swap |collected_forms| into |*forms| first on success, to avoid returning
875 // partial results on error.
876 ScopedVector<autofill::PasswordForm> collected_forms;
877
878 while (statement->Step()) {
879 scoped_ptr<PasswordForm> new_form(new PasswordForm());
880 EncryptionResult result =
881 InitPasswordFormFromStatement(new_form.get(), *statement);
882 if (result == ENCRYPTION_RESULT_SERVICE_FAILURE)
883 return false;
884 if (result == ENCRYPTION_RESULT_ITEM_FAILURE)
885 continue;
886 DCHECK(result == ENCRYPTION_RESULT_SUCCESS);
887 if (psl_match && psl_match->signon_realm != new_form->signon_realm) {
888 if (new_form->scheme != PasswordForm::SCHEME_HTML)
889 continue; // Ignore non-HTML matches.
890
891 if (!IsPublicSuffixDomainMatch(new_form->signon_realm,
892 psl_match->signon_realm)) {
893 continue;
894 }
895
896 psl_domain_match_metric = PSL_DOMAIN_MATCH_FOUND;
897 // This is not a perfect match, so we need to create a new valid result.
898 // We do this by copying over origin, signon realm and action from the
899 // observed form and setting the original signon realm to what we found
900 // in the database. We use the fact that |original_signon_realm| is
901 // non-empty to communicate that this match was found using public
902 // suffix matching.
903 new_form->original_signon_realm = new_form->signon_realm;
904 new_form->origin = psl_match->origin;
905 new_form->signon_realm = psl_match->signon_realm;
906 new_form->action = psl_match->action;
907 }
908 collected_forms.push_back(new_form.Pass());
909 }
910
911 if (psl_match) {
912 UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering",
913 psl_domain_match_metric, PSL_DOMAIN_MATCH_COUNT);
914 }
915
916 if (!statement->Succeeded())
917 return false;
918 forms->swap(collected_forms);
919 return true;
920 }
921
927 } // namespace password_manager 922 } // namespace password_manager
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698