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

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

Powered by Google App Engine
This is Rietveld 408576698