OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |