Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "components/password_manager/core/browser/hsts_deleter.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <iterator> | |
| 9 #include <tuple> | |
| 10 | |
| 11 #include "base/logging.h" | |
| 12 #include "components/autofill/core/common/password_form.h" | |
| 13 #include "components/password_manager/core/browser/password_manager_client.h" | |
| 14 #include "components/password_manager/core/browser/password_store.h" | |
| 15 #include "components/password_manager/core/browser/statistics_table.h" | |
| 16 #include "url/url_constants.h" | |
| 17 | |
| 18 using autofill::PasswordForm; | |
| 19 | |
| 20 namespace password_manager { | |
| 21 | |
| 22 HstsDeleter::HstsDeleter(const PasswordManagerClient* client, | |
| 23 PasswordStore* password_store) | |
| 24 : client_(client), password_store_(password_store) { | |
| 25 DCHECK(client_); | |
| 26 DCHECK(password_store_); | |
| 27 } | |
| 28 | |
| 29 void HstsDeleter::OnGetPasswordStoreResults( | |
| 30 std::vector<std::unique_ptr<PasswordForm>> results) { | |
| 31 // Non HTTP or HTTPS credentials are ignored. | |
| 32 results.erase(std::remove_if(std::begin(results), std::end(results), | |
| 33 [](const std::unique_ptr<PasswordForm>& form) { | |
| 34 return !form->origin.SchemeIsHTTPOrHTTPS(); | |
| 35 }), | |
| 36 std::end(results)); | |
| 37 | |
| 38 // Move HTTPS forms to the end of the container, | |
| 39 auto begin_https = | |
| 40 std::partition(std::begin(results), std::end(results), | |
| 41 [](const std::unique_ptr<PasswordForm>& form) { | |
| 42 return form->origin.SchemeIs(url::kHttpScheme); | |
| 43 }); | |
| 44 | |
| 45 // Move blacklisted HTTP forms to the end of the HTTP form segment. | |
| 46 auto begin_blacklisted_http = | |
| 47 std::partition(std::begin(results), begin_https, | |
| 48 [](const std::unique_ptr<PasswordForm>& form) { | |
| 49 return !form->blacklisted_by_user; | |
| 50 }); | |
| 51 | |
| 52 // Remove blacklisted HTTP forms from the password store when HSTS is active | |
| 53 // for the given host. | |
| 54 std::for_each(begin_blacklisted_http, begin_https, | |
| 55 [this](const std::unique_ptr<PasswordForm>& blacklisted_form) { | |
| 56 if (client_->IsHSTSActiveForOrigin(blacklisted_form->origin)) | |
|
vasilii
2017/02/06 16:43:24
Does HSTS request for HTTP also work?
jdoerrie
2017/02/07 13:15:00
Yes, it does. For HSTS queries only the host matte
| |
| 57 password_store_->RemoveLogin(*blacklisted_form); | |
| 58 }); | |
|
vasilii
2017/02/06 16:43:24
Why can't you process and remove the blacklisted f
jdoerrie
2017/02/07 13:15:00
I could have done that, but then I also need to ch
| |
| 59 | |
| 60 // Return early if there are no non-blacklisted HTTP forms. | |
| 61 if (std::begin(results) == begin_blacklisted_http) | |
| 62 return; | |
| 63 | |
| 64 // Ignore non HSTS forms. We are explicitly not calling |results.erase| so | |
| 65 // that we don't invalidate |begin_https| in case there are no HSTS forms. | |
|
vasilii
2017/02/06 16:43:24
erase() doesn't ivalidate the iterators before |fi
jdoerrie
2017/02/07 13:15:00
As discussed offline this actually does leed to in
| |
| 66 auto end_hsts = | |
| 67 std::remove_if(begin_https, std::end(results), | |
| 68 [this](const std::unique_ptr<PasswordForm>& form) { | |
| 69 return !client_->IsHSTSActiveForOrigin(form->origin); | |
| 70 }); | |
| 71 | |
| 72 // Sort HSTS forms according to custom comparison function. Consider two forms | |
| 73 // equivalent if they have the same host, as well as the same username and | |
| 74 // password. | |
| 75 const auto form_cmp = [](const std::unique_ptr<PasswordForm>& lhs, | |
| 76 const std::unique_ptr<PasswordForm>& rhs) { | |
| 77 return std::forward_as_tuple(lhs->origin.host_piece(), lhs->username_value, | |
| 78 lhs->password_value) < | |
| 79 std::forward_as_tuple(rhs->origin.host_piece(), rhs->username_value, | |
| 80 rhs->password_value); | |
| 81 }; | |
| 82 | |
| 83 std::sort(begin_https, end_hsts, form_cmp); | |
| 84 | |
| 85 // Iterate through HTTP forms and remove them from the password store if there | |
| 86 // exists an equivalent HSTS form. | |
| 87 std::for_each(std::begin(results), begin_blacklisted_http, | |
| 88 [&, this](const std::unique_ptr<PasswordForm>& form) { | |
| 89 if (std::binary_search(begin_https, end_hsts, form, form_cmp)) | |
| 90 password_store_->RemoveLogin(*form); | |
| 91 }); | |
| 92 } | |
| 93 | |
| 94 void HstsDeleter::OnGetSiteStatistics(std::vector<InteractionsStats> stats) { | |
| 95 for (const auto& stat : stats) { | |
| 96 if (stat.origin_domain.SchemeIs(url::kHttpScheme) && | |
| 97 client_->IsHSTSActiveForOrigin(stat.origin_domain)) { | |
|
vasilii
2017/02/06 16:43:24
How can HSTS be active for an HTTP origin?
jdoerrie
2017/02/07 13:15:00
See above (scheme is ignored, only host matters).
| |
| 98 password_store_->RemoveSiteStats(stat.origin_domain); | |
| 99 } | |
| 100 } | |
| 101 } | |
| 102 | |
| 103 } // namespace password_manager | |
| OLD | NEW |