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

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: Fix FillMatchingLogins + a typo Created 5 years, 9 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 653 matching lines...) Expand 10 before | Expand all | Expand 10 after
664 SQL_FROM_HERE, 664 SQL_FROM_HERE,
665 "DELETE FROM logins WHERE date_synced >= ? AND date_synced < ?")); 665 "DELETE FROM logins WHERE date_synced >= ? AND date_synced < ?"));
666 s.BindInt64(0, delete_begin.ToInternalValue()); 666 s.BindInt64(0, delete_begin.ToInternalValue());
667 s.BindInt64(1, 667 s.BindInt64(1,
668 delete_end.is_null() ? base::Time::Max().ToInternalValue() 668 delete_end.is_null() ? base::Time::Max().ToInternalValue()
669 : delete_end.ToInternalValue()); 669 : delete_end.ToInternalValue());
670 670
671 return s.Run(); 671 return s.Run();
672 } 672 }
673 673
674 // static
674 LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement( 675 LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement(
675 PasswordForm* form, 676 PasswordForm* form,
676 sql::Statement& s) const { 677 sql::Statement& s) {
677 std::string encrypted_password; 678 std::string encrypted_password;
678 s.ColumnBlobAsString(COLUMN_PASSWORD_VALUE, &encrypted_password); 679 s.ColumnBlobAsString(COLUMN_PASSWORD_VALUE, &encrypted_password);
679 base::string16 decrypted_password; 680 base::string16 decrypted_password;
680 EncryptionResult encryption_result = 681 EncryptionResult encryption_result =
681 DecryptedString(encrypted_password, &decrypted_password); 682 DecryptedString(encrypted_password, &decrypted_password);
682 if (encryption_result != ENCRYPTION_RESULT_SUCCESS) 683 if (encryption_result != ENCRYPTION_RESULT_SUCCESS)
683 return encryption_result; 684 return encryption_result;
684 685
685 std::string tmp = s.ColumnString(COLUMN_ORIGIN_URL); 686 std::string tmp = s.ColumnString(COLUMN_ORIGIN_URL);
686 form->origin = GURL(tmp); 687 form->origin = GURL(tmp);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
731 form->generation_upload_status = 732 form->generation_upload_status =
732 static_cast<PasswordForm::GenerationUploadStatus>( 733 static_cast<PasswordForm::GenerationUploadStatus>(
733 generation_upload_status_int); 734 generation_upload_status_int);
734 return ENCRYPTION_RESULT_SUCCESS; 735 return ENCRYPTION_RESULT_SUCCESS;
735 } 736 }
736 737
737 bool LoginDatabase::GetLogins( 738 bool LoginDatabase::GetLogins(
738 const PasswordForm& form, 739 const PasswordForm& form,
739 ScopedVector<autofill::PasswordForm>* forms) const { 740 ScopedVector<autofill::PasswordForm>* forms) const {
740 DCHECK(forms); 741 DCHECK(forms);
742 forms->clear();
741 // You *must* change LoginTableColumns if this query changes. 743 // You *must* change LoginTableColumns if this query changes.
742 const std::string sql_query = 744 const std::string sql_query =
743 "SELECT origin_url, action_url, " 745 "SELECT origin_url, action_url, "
744 "username_element, username_value, " 746 "username_element, username_value, "
745 "password_element, password_value, submit_element, " 747 "password_element, password_value, submit_element, "
746 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, " 748 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
747 "scheme, password_type, possible_usernames, times_used, form_data, " 749 "scheme, password_type, possible_usernames, times_used, form_data, "
748 "date_synced, display_name, avatar_url, " 750 "date_synced, display_name, avatar_url, "
749 "federation_url, skip_zero_click, generation_upload_status " 751 "federation_url, skip_zero_click, generation_upload_status "
750 "FROM logins WHERE signon_realm == ? "; 752 "FROM logins WHERE signon_realm == ? ";
751 sql::Statement s; 753 sql::Statement s;
752 const GURL signon_realm(form.signon_realm); 754 const GURL signon_realm(form.signon_realm);
753 std::string registered_domain = GetRegistryControlledDomain(signon_realm); 755 std::string registered_domain = GetRegistryControlledDomain(signon_realm);
754 PSLDomainMatchMetric psl_domain_match_metric = PSL_DOMAIN_MATCH_NONE;
755 const bool should_PSL_matching_apply = 756 const bool should_PSL_matching_apply =
756 form.scheme == PasswordForm::SCHEME_HTML && 757 form.scheme == PasswordForm::SCHEME_HTML &&
757 ShouldPSLDomainMatchingApply(registered_domain); 758 ShouldPSLDomainMatchingApply(registered_domain);
758 // PSL matching only applies to HTML forms. 759 // PSL matching only applies to HTML forms.
759 if (should_PSL_matching_apply) { 760 if (should_PSL_matching_apply) {
760 // We are extending the original SQL query with one that includes more 761 // We are extending the original SQL query with one that includes more
761 // possible matches based on public suffix domain matching. Using a regexp 762 // possible matches based on public suffix domain matching. Using a regexp
762 // here is just an optimization to not have to parse all the stored entries 763 // here is just an optimization to not have to parse all the stored entries
763 // in the |logins| table. The result (scheme, domain and port) is verified 764 // in the |logins| table. The result (scheme, domain and port) is verified
764 // further down using GURL. See the functions SchemeMatches, 765 // further down using GURL. See the functions SchemeMatches,
(...skipping 14 matching lines...) Expand all
779 const std::string port = signon_realm.port(); 780 const std::string port = signon_realm.port();
780 // For a signon realm such as http://foo.bar/, this regexp will match 781 // For a signon realm such as http://foo.bar/, this regexp will match
781 // domains on the form http://foo.bar/, http://www.foo.bar/, 782 // domains on the form http://foo.bar/, http://www.foo.bar/,
782 // http://www.mobile.foo.bar/. It will not match http://notfoo.bar/. 783 // http://www.mobile.foo.bar/. It will not match http://notfoo.bar/.
783 // The scheme and port has to be the same as the observed form. 784 // The scheme and port has to be the same as the observed form.
784 std::string regexp = "^(" + scheme + ":\\/\\/)([\\w-]+\\.)*" + 785 std::string regexp = "^(" + scheme + ":\\/\\/)([\\w-]+\\.)*" +
785 registered_domain + "(:" + port + ")?\\/$"; 786 registered_domain + "(:" + port + ")?\\/$";
786 s.BindString(0, form.signon_realm); 787 s.BindString(0, form.signon_realm);
787 s.BindString(1, regexp); 788 s.BindString(1, regexp);
788 } else { 789 } else {
789 psl_domain_match_metric = PSL_DOMAIN_MATCH_NOT_USED; 790 UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering",
791 PSL_DOMAIN_MATCH_NOT_USED,
792 PSL_DOMAIN_MATCH_COUNT);
790 s.Assign(db_.GetCachedStatement(SQL_FROM_HERE, sql_query.c_str())); 793 s.Assign(db_.GetCachedStatement(SQL_FROM_HERE, sql_query.c_str()));
791 s.BindString(0, form.signon_realm); 794 s.BindString(0, form.signon_realm);
792 } 795 }
793 796
794 while (s.Step()) { 797 return StatementToForms(&s, should_PSL_matching_apply ? &form : nullptr,
795 scoped_ptr<PasswordForm> new_form(new PasswordForm()); 798 forms);
796 EncryptionResult result = InitPasswordFormFromStatement(new_form.get(), s);
797 if (result == ENCRYPTION_RESULT_SERVICE_FAILURE)
798 return false;
799 if (result == ENCRYPTION_RESULT_ITEM_FAILURE)
800 continue;
801 DCHECK(result == ENCRYPTION_RESULT_SUCCESS);
802 if (should_PSL_matching_apply) {
803 if (!IsPublicSuffixDomainMatch(new_form->signon_realm,
804 form.signon_realm)) {
805 // The database returned results that should not match. Skipping result.
806 continue;
807 }
808 if (form.signon_realm != new_form->signon_realm) {
809 // Ignore non-HTML matches.
810 if (new_form->scheme != PasswordForm::SCHEME_HTML)
811 continue;
812
813 psl_domain_match_metric = PSL_DOMAIN_MATCH_FOUND;
814 // This is not a perfect match, so we need to create a new valid result.
815 // We do this by copying over origin, signon realm and action from the
816 // observed form and setting the original signon realm to what we found
817 // in the database. We use the fact that |original_signon_realm| is
818 // non-empty to communicate that this match was found using public
819 // suffix matching.
820 new_form->original_signon_realm = new_form->signon_realm;
821 new_form->origin = form.origin;
822 new_form->signon_realm = form.signon_realm;
823 new_form->action = form.action;
824 }
825 }
826 forms->push_back(new_form.release());
827 }
828 UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering",
829 psl_domain_match_metric,
830 PSL_DOMAIN_MATCH_COUNT);
831 return s.Succeeded();
832 } 799 }
833 800
834 bool LoginDatabase::GetLoginsCreatedBetween( 801 bool LoginDatabase::GetLoginsCreatedBetween(
835 const base::Time begin, 802 const base::Time begin,
836 const base::Time end, 803 const base::Time end,
837 ScopedVector<autofill::PasswordForm>* forms) const { 804 ScopedVector<autofill::PasswordForm>* forms) const {
838 DCHECK(forms); 805 DCHECK(forms);
806 forms->clear();
839 sql::Statement s(db_.GetCachedStatement( 807 sql::Statement s(db_.GetCachedStatement(
840 SQL_FROM_HERE, 808 SQL_FROM_HERE,
841 "SELECT origin_url, action_url, " 809 "SELECT origin_url, action_url, "
842 "username_element, username_value, " 810 "username_element, username_value, "
843 "password_element, password_value, submit_element, " 811 "password_element, password_value, submit_element, "
844 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, " 812 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
845 "scheme, password_type, possible_usernames, times_used, form_data, " 813 "scheme, password_type, possible_usernames, times_used, form_data, "
846 "date_synced, display_name, avatar_url, " 814 "date_synced, display_name, avatar_url, "
847 "federation_url, skip_zero_click, generation_upload_status FROM logins " 815 "federation_url, skip_zero_click, generation_upload_status FROM logins "
848 "WHERE date_created >= ? AND date_created < ?" 816 "WHERE date_created >= ? AND date_created < ?"
849 "ORDER BY origin_url")); 817 "ORDER BY origin_url"));
850 s.BindInt64(0, begin.ToInternalValue()); 818 s.BindInt64(0, begin.ToInternalValue());
851 s.BindInt64(1, end.is_null() ? std::numeric_limits<int64>::max() 819 s.BindInt64(1, end.is_null() ? std::numeric_limits<int64>::max()
852 : end.ToInternalValue()); 820 : end.ToInternalValue());
853 821
854 while (s.Step()) { 822 return StatementToForms(&s, nullptr, forms);
855 scoped_ptr<PasswordForm> new_form(new PasswordForm());
856 EncryptionResult result = InitPasswordFormFromStatement(new_form.get(), s);
857 if (result == ENCRYPTION_RESULT_SERVICE_FAILURE)
858 return false;
859 if (result == ENCRYPTION_RESULT_ITEM_FAILURE)
860 continue;
861 DCHECK(result == ENCRYPTION_RESULT_SUCCESS);
862 forms->push_back(new_form.release());
863 }
864 return s.Succeeded();
865 } 823 }
866 824
867 bool LoginDatabase::GetLoginsSyncedBetween( 825 bool LoginDatabase::GetLoginsSyncedBetween(
868 const base::Time begin, 826 const base::Time begin,
869 const base::Time end, 827 const base::Time end,
870 ScopedVector<autofill::PasswordForm>* forms) const { 828 ScopedVector<autofill::PasswordForm>* forms) const {
871 DCHECK(forms); 829 DCHECK(forms);
830 forms->clear();
872 sql::Statement s(db_.GetCachedStatement( 831 sql::Statement s(db_.GetCachedStatement(
873 SQL_FROM_HERE, 832 SQL_FROM_HERE,
874 "SELECT origin_url, action_url, username_element, username_value, " 833 "SELECT origin_url, action_url, username_element, username_value, "
875 "password_element, password_value, submit_element, signon_realm, " 834 "password_element, password_value, submit_element, signon_realm, "
876 "ssl_valid, preferred, date_created, blacklisted_by_user, " 835 "ssl_valid, preferred, date_created, blacklisted_by_user, "
877 "scheme, password_type, possible_usernames, times_used, form_data, " 836 "scheme, password_type, possible_usernames, times_used, form_data, "
878 "date_synced, display_name, avatar_url, " 837 "date_synced, display_name, avatar_url, "
879 "federation_url, skip_zero_click, generation_upload_status FROM logins " 838 "federation_url, skip_zero_click, generation_upload_status FROM logins "
880 "WHERE date_synced >= ? AND date_synced < ?" 839 "WHERE date_synced >= ? AND date_synced < ?"
881 "ORDER BY origin_url")); 840 "ORDER BY origin_url"));
882 s.BindInt64(0, begin.ToInternalValue()); 841 s.BindInt64(0, begin.ToInternalValue());
883 s.BindInt64(1, 842 s.BindInt64(1,
884 end.is_null() ? base::Time::Max().ToInternalValue() 843 end.is_null() ? base::Time::Max().ToInternalValue()
885 : end.ToInternalValue()); 844 : end.ToInternalValue());
886 845
887 while (s.Step()) { 846 return StatementToForms(&s, nullptr, forms);
888 scoped_ptr<PasswordForm> new_form(new PasswordForm());
889 EncryptionResult result = InitPasswordFormFromStatement(new_form.get(), s);
890 if (result == ENCRYPTION_RESULT_SERVICE_FAILURE)
891 return false;
892 if (result == ENCRYPTION_RESULT_ITEM_FAILURE)
893 continue;
894 DCHECK(result == ENCRYPTION_RESULT_SUCCESS);
895 forms->push_back(new_form.release());
896 }
897 return s.Succeeded();
898 } 847 }
899 848
900 bool LoginDatabase::GetAutofillableLogins( 849 bool LoginDatabase::GetAutofillableLogins(
901 ScopedVector<autofill::PasswordForm>* forms) const { 850 ScopedVector<autofill::PasswordForm>* forms) const {
902 return GetAllLoginsWithBlacklistSetting(false, forms); 851 return GetAllLoginsWithBlacklistSetting(false, forms);
903 } 852 }
904 853
905 bool LoginDatabase::GetBlacklistLogins( 854 bool LoginDatabase::GetBlacklistLogins(
906 ScopedVector<autofill::PasswordForm>* forms) const { 855 ScopedVector<autofill::PasswordForm>* forms) const {
907 return GetAllLoginsWithBlacklistSetting(true, forms); 856 return GetAllLoginsWithBlacklistSetting(true, forms);
908 } 857 }
909 858
910 bool LoginDatabase::GetAllLoginsWithBlacklistSetting( 859 bool LoginDatabase::GetAllLoginsWithBlacklistSetting(
911 bool blacklisted, 860 bool blacklisted,
912 ScopedVector<autofill::PasswordForm>* forms) const { 861 ScopedVector<autofill::PasswordForm>* forms) const {
913 DCHECK(forms); 862 DCHECK(forms);
863 forms->clear();
914 // You *must* change LoginTableColumns if this query changes. 864 // You *must* change LoginTableColumns if this query changes.
915 sql::Statement s(db_.GetCachedStatement( 865 sql::Statement s(db_.GetCachedStatement(
916 SQL_FROM_HERE, 866 SQL_FROM_HERE,
917 "SELECT origin_url, action_url, " 867 "SELECT origin_url, action_url, "
918 "username_element, username_value, " 868 "username_element, username_value, "
919 "password_element, password_value, submit_element, " 869 "password_element, password_value, submit_element, "
920 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, " 870 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
921 "scheme, password_type, possible_usernames, times_used, form_data, " 871 "scheme, password_type, possible_usernames, times_used, form_data, "
922 "date_synced, display_name, avatar_url, " 872 "date_synced, display_name, avatar_url, "
923 "federation_url, skip_zero_click, generation_upload_status FROM logins " 873 "federation_url, skip_zero_click, generation_upload_status FROM logins "
924 "WHERE blacklisted_by_user == ? ORDER BY origin_url")); 874 "WHERE blacklisted_by_user == ? ORDER BY origin_url"));
925 s.BindInt(0, blacklisted ? 1 : 0); 875 s.BindInt(0, blacklisted ? 1 : 0);
926 876
927 while (s.Step()) { 877 return StatementToForms(&s, nullptr, forms);
928 scoped_ptr<PasswordForm> new_form(new PasswordForm());
929 EncryptionResult result = InitPasswordFormFromStatement(new_form.get(), s);
930 if (result == ENCRYPTION_RESULT_SERVICE_FAILURE)
931 return false;
932 if (result == ENCRYPTION_RESULT_ITEM_FAILURE)
933 continue;
934 DCHECK(result == ENCRYPTION_RESULT_SUCCESS);
935 forms->push_back(new_form.release());
936 }
937 return s.Succeeded();
938 } 878 }
939 879
940 bool LoginDatabase::DeleteAndRecreateDatabaseFile() { 880 bool LoginDatabase::DeleteAndRecreateDatabaseFile() {
941 DCHECK(db_.is_open()); 881 DCHECK(db_.is_open());
942 meta_table_.Reset(); 882 meta_table_.Reset();
943 db_.Close(); 883 db_.Close();
944 sql::Connection::Delete(db_path_); 884 sql::Connection::Delete(db_path_);
945 return Init(); 885 return Init();
946 } 886 }
947 887
888 // static
889 bool LoginDatabase::StatementToForms(
890 sql::Statement* statement,
891 const autofill::PasswordForm* psl_match,
892 ScopedVector<autofill::PasswordForm>* forms) {
893 PSLDomainMatchMetric psl_domain_match_metric = PSL_DOMAIN_MATCH_NONE;
894 forms->clear();
895
896 // Swap |collected_forms| into |*forms| first on success, to avoid returning
897 // partial results on error.
898 ScopedVector<autofill::PasswordForm> collected_forms;
899
900 while (statement->Step()) {
901 scoped_ptr<PasswordForm> new_form(new PasswordForm());
902 EncryptionResult result =
903 InitPasswordFormFromStatement(new_form.get(), *statement);
904 if (result == ENCRYPTION_RESULT_SERVICE_FAILURE)
905 return false;
906 if (result == ENCRYPTION_RESULT_ITEM_FAILURE)
907 continue;
908 DCHECK(result == ENCRYPTION_RESULT_SUCCESS);
909 if (psl_match && psl_match->signon_realm != new_form->signon_realm) {
910 if (new_form->scheme != PasswordForm::SCHEME_HTML)
911 continue; // Ignore non-HTML matches.
912
913 if (!IsPublicSuffixDomainMatch(new_form->signon_realm,
914 psl_match->signon_realm)) {
915 continue;
916 }
917
918 psl_domain_match_metric = PSL_DOMAIN_MATCH_FOUND;
919 // This is not a perfect match, so we need to create a new valid result.
920 // We do this by copying over origin, signon realm and action from the
921 // observed form and setting the original signon realm to what we found
922 // in the database. We use the fact that |original_signon_realm| is
923 // non-empty to communicate that this match was found using public
924 // suffix matching.
925 new_form->original_signon_realm = new_form->signon_realm;
926 new_form->origin = psl_match->origin;
927 new_form->signon_realm = psl_match->signon_realm;
928 new_form->action = psl_match->action;
929 }
930 collected_forms.push_back(new_form.Pass());
931 }
932
933 if (psl_match) {
934 UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering",
935 psl_domain_match_metric, PSL_DOMAIN_MATCH_COUNT);
936 }
937
938 if (!statement->Succeeded())
939 return false;
940 forms->swap(collected_forms);
941 return true;
942 }
943
948 } // namespace password_manager 944 } // namespace password_manager
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698