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

Side by Side Diff: chrome/browser/ui/passwords/password_manager_presenter.cc

Issue 1589483002: [Password Manager] Implements entries sorting and duplicates omitting on chrome://settings/passwords (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Mistype in a comment Created 4 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 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "chrome/browser/ui/passwords/password_manager_presenter.h" 5 #include "chrome/browser/ui/passwords/password_manager_presenter.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
11 #include "base/metrics/user_metrics_action.h" 11 #include "base/metrics/user_metrics_action.h"
12 #include "base/strings/string_piece.h"
13 #include "base/strings/string_split.h"
14 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/time.h" 16 #include "base/time/time.h"
14 #include "base/values.h" 17 #include "base/values.h"
15 #include "build/build_config.h" 18 #include "build/build_config.h"
16 #include "chrome/browser/password_manager/password_store_factory.h" 19 #include "chrome/browser/password_manager/password_store_factory.h"
17 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/signin/signin_manager_factory.h" 21 #include "chrome/browser/signin/signin_manager_factory.h"
19 #include "chrome/browser/sync/profile_sync_service_factory.h" 22 #include "chrome/browser/sync/profile_sync_service_factory.h"
20 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h" 23 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
21 #include "chrome/browser/ui/passwords/password_ui_view.h" 24 #include "chrome/browser/ui/passwords/password_ui_view.h"
22 #include "chrome/common/chrome_switches.h" 25 #include "chrome/common/chrome_switches.h"
23 #include "chrome/common/pref_names.h" 26 #include "chrome/common/pref_names.h"
24 #include "chrome/common/url_constants.h" 27 #include "chrome/common/url_constants.h"
25 #include "components/autofill/core/common/password_form.h" 28 #include "components/autofill/core/common/password_form.h"
26 #include "components/browser_sync/browser/profile_sync_service.h" 29 #include "components/browser_sync/browser/profile_sync_service.h"
27 #include "components/password_manager/core/browser/affiliation_utils.h" 30 #include "components/password_manager/core/browser/affiliation_utils.h"
28 #include "components/password_manager/core/browser/password_manager_util.h" 31 #include "components/password_manager/core/browser/password_manager_util.h"
32 #include "components/password_manager/core/browser/password_ui_utils.h"
29 #include "components/password_manager/core/common/password_manager_pref_names.h" 33 #include "components/password_manager/core/common/password_manager_pref_names.h"
30 #include "components/password_manager/sync/browser/password_sync_util.h" 34 #include "components/password_manager/sync/browser/password_sync_util.h"
31 #include "components/prefs/pref_service.h" 35 #include "components/prefs/pref_service.h"
32 #include "content/public/browser/user_metrics.h" 36 #include "content/public/browser/user_metrics.h"
33 #include "content/public/browser/web_contents.h" 37 #include "content/public/browser/web_contents.h"
38 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
34 39
35 #if defined(OS_WIN) 40 #if defined(OS_WIN)
36 #include "chrome/browser/password_manager/password_manager_util_win.h" 41 #include "chrome/browser/password_manager/password_manager_util_win.h"
37 #elif defined(OS_MACOSX) 42 #elif defined(OS_MACOSX)
38 #include "chrome/browser/password_manager/password_manager_util_mac.h" 43 #include "chrome/browser/password_manager/password_manager_util_mac.h"
39 #endif 44 #endif
40 45
46 using base::StringPiece;
41 using password_manager::PasswordStore; 47 using password_manager::PasswordStore;
42 48
49 namespace {
50
51 const int kAndroidAppSchemeAndDelimiterLength = 10; // Length of 'android://'.
52
53 const char kSortKeyPartsSeparator = ' ';
54
55 // Reverse order of subdomains in hostname.
56 std::string SplitByDotAndReverse(StringPiece host) {
57 std::vector<std::string> parts =
58 base::SplitString(host, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
59 std::reverse(parts.begin(), parts.end());
60 return base::JoinString(parts, ".");
61 }
62
63 // Helper function that returns the type of the entry (non-Android credentials,
64 // Android w/ affiliated web realm (i.e. clickable) or w/o web realm).
65 std::string GetEntryTypeCode(bool is_android_uri, bool is_clickable) {
66 if (!is_android_uri)
67 return "0";
68 if (is_clickable)
69 return "1";
70 return "2";
71 }
72
73 // Creates key for sorting password or password exception entries.
74 // The key is eTLD+1 followed by subdomains
75 // (e.g. secure.accounts.example.com => example.com.accounts.secure).
76 // If |username_and_password_in_key == true|, username and password is appended
77 // to the key. The entry type code (non-Android, Android w/ or w/o affiliated
78 // web realm) is also appended to the key.
79 std::string CreateSortKey(const autofill::PasswordForm& form,
80 const std::string& languages,
81 bool username_and_password_in_key) {
82 bool is_android_uri = false;
83 bool is_clickable = false;
84 GURL link_url;
85 std::string origin = password_manager::GetShownOriginAndLinkUrl(
86 form, languages, &is_android_uri, &link_url, &is_clickable);
87
88 if (!is_clickable) { // e.g. android://com.example.r => r.example.com.
89 origin = SplitByDotAndReverse(
90 StringPiece(&origin[kAndroidAppSchemeAndDelimiterLength],
91 origin.length() - kAndroidAppSchemeAndDelimiterLength));
92 }
93
94 std::string site_name =
95 net::registry_controlled_domains::GetDomainAndRegistry(
96 origin, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
97 if (site_name.empty()) // e.g. localhost.
98 site_name = origin;
99 std::string key =
100 site_name + SplitByDotAndReverse(StringPiece(
101 &origin[0], origin.length() - site_name.length()));
102
103 if (username_and_password_in_key) {
104 key = key + kSortKeyPartsSeparator +
105 base::UTF16ToUTF8(form.username_value) + kSortKeyPartsSeparator +
106 base::UTF16ToUTF8(form.password_value);
107 }
108
109 // Since Android and non-Android entries shouldn't be merged into one entry,
110 // add the entry type code to the sort key.
111 key +=
112 kSortKeyPartsSeparator + GetEntryTypeCode(is_android_uri, is_clickable);
113 return key;
114 }
115
116 // Finds duplicates of |form| in |duplicates|, removes them from |store| and
117 // from |duplicates|.
118 void RemoveDuplicates(const autofill::PasswordForm& form,
119 const std::string& languages,
120 DuplicatesMap* duplicates,
121 PasswordStore* store,
122 bool username_and_password_in_key) {
123 std::string key =
124 CreateSortKey(form, languages, username_and_password_in_key);
125 std::pair<DuplicatesMap::iterator, DuplicatesMap::iterator> dups =
126 duplicates->equal_range(key);
127 for (DuplicatesMap::iterator it = dups.first; it != dups.second; ++it)
128 store->RemoveLogin(*it->second);
129 duplicates->erase(key);
130 }
131
132 } // namespace
133
43 PasswordManagerPresenter::PasswordManagerPresenter( 134 PasswordManagerPresenter::PasswordManagerPresenter(
44 PasswordUIView* password_view) 135 PasswordUIView* password_view)
45 : populater_(this), 136 : populater_(this),
46 exception_populater_(this), 137 exception_populater_(this),
47 require_reauthentication_( 138 require_reauthentication_(
48 !base::CommandLine::ForCurrentProcess()->HasSwitch( 139 !base::CommandLine::ForCurrentProcess()->HasSwitch(
49 switches::kDisablePasswordManagerReauthentication)), 140 switches::kDisablePasswordManagerReauthentication)),
50 password_view_(password_view) { 141 password_view_(password_view) {
51 DCHECK(password_view_); 142 DCHECK(password_view_);
52 } 143 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 ServiceAccessType::EXPLICIT_ACCESS) 182 ServiceAccessType::EXPLICIT_ACCESS)
92 .get(); 183 .get();
93 } 184 }
94 185
95 void PasswordManagerPresenter::UpdatePasswordLists() { 186 void PasswordManagerPresenter::UpdatePasswordLists() {
96 // Reset so that showing a password will require re-authentication. 187 // Reset so that showing a password will require re-authentication.
97 last_authentication_time_ = base::TimeTicks(); 188 last_authentication_time_ = base::TimeTicks();
98 189
99 // Reset the current lists. 190 // Reset the current lists.
100 password_list_.clear(); 191 password_list_.clear();
192 password_duplicates_.clear();
101 password_exception_list_.clear(); 193 password_exception_list_.clear();
194 password_exception_duplicates_.clear();
102 195
103 populater_.Populate(); 196 populater_.Populate();
104 exception_populater_.Populate(); 197 exception_populater_.Populate();
105 } 198 }
106 199
107 void PasswordManagerPresenter::RemoveSavedPassword(size_t index) { 200 void PasswordManagerPresenter::RemoveSavedPassword(size_t index) {
108 if (index >= password_list_.size()) { 201 if (index >= password_list_.size()) {
109 // |index| out of bounds might come from a compromised renderer, don't let 202 // |index| out of bounds might come from a compromised renderer, don't let
110 // it crash the browser. http://crbug.com/362054 203 // it crash the browser. http://crbug.com/362054
111 NOTREACHED(); 204 NOTREACHED();
112 return; 205 return;
113 } 206 }
114 PasswordStore* store = GetPasswordStore(); 207 PasswordStore* store = GetPasswordStore();
115 if (!store) 208 if (!store)
116 return; 209 return;
210
211 RemoveDuplicates(*password_list_[index], languages_, &password_duplicates_,
212 store, true);
117 store->RemoveLogin(*password_list_[index]); 213 store->RemoveLogin(*password_list_[index]);
118 content::RecordAction( 214 content::RecordAction(
119 base::UserMetricsAction("PasswordManager_RemoveSavedPassword")); 215 base::UserMetricsAction("PasswordManager_RemoveSavedPassword"));
120 } 216 }
121 217
122 void PasswordManagerPresenter::RemovePasswordException(size_t index) { 218 void PasswordManagerPresenter::RemovePasswordException(size_t index) {
123 if (index >= password_exception_list_.size()) { 219 if (index >= password_exception_list_.size()) {
124 // |index| out of bounds might come from a compromised renderer, don't let 220 // |index| out of bounds might come from a compromised renderer, don't let
125 // it crash the browser. http://crbug.com/362054 221 // it crash the browser. http://crbug.com/362054
126 NOTREACHED(); 222 NOTREACHED();
127 return; 223 return;
128 } 224 }
129 PasswordStore* store = GetPasswordStore(); 225 PasswordStore* store = GetPasswordStore();
130 if (!store) 226 if (!store)
131 return; 227 return;
228 RemoveDuplicates(*password_exception_list_[index], languages_,
229 &password_exception_duplicates_, store, false);
132 store->RemoveLogin(*password_exception_list_[index]); 230 store->RemoveLogin(*password_exception_list_[index]);
133 content::RecordAction( 231 content::RecordAction(
134 base::UserMetricsAction("PasswordManager_RemovePasswordException")); 232 base::UserMetricsAction("PasswordManager_RemovePasswordException"));
135 } 233 }
136 234
137 void PasswordManagerPresenter::RequestShowPassword(size_t index) { 235 void PasswordManagerPresenter::RequestShowPassword(size_t index) {
138 #if !defined(OS_ANDROID) // This is never called on Android. 236 #if !defined(OS_ANDROID) // This is never called on Android.
139 if (index >= password_list_.size()) { 237 if (index >= password_list_.size()) {
140 // |index| out of bounds might come from a compromised renderer, don't let 238 // |index| out of bounds might come from a compromised renderer, don't let
141 // it crash the browser. http://crbug.com/362054 239 // it crash the browser. http://crbug.com/362054
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 Initialize(); 312 Initialize();
215 313
216 bool show_passwords = *show_passwords_ && !require_reauthentication_; 314 bool show_passwords = *show_passwords_ && !require_reauthentication_;
217 password_view_->SetPasswordList(password_list_, show_passwords); 315 password_view_->SetPasswordList(password_list_, show_passwords);
218 } 316 }
219 317
220 void PasswordManagerPresenter::SetPasswordExceptionList() { 318 void PasswordManagerPresenter::SetPasswordExceptionList() {
221 password_view_->SetPasswordExceptionList(password_exception_list_); 319 password_view_->SetPasswordExceptionList(password_exception_list_);
222 } 320 }
223 321
322 void PasswordManagerPresenter::SortEntriesAndHideDuplicates(
323 const std::string& languages,
324 std::vector<scoped_ptr<autofill::PasswordForm>>* list,
325 DuplicatesMap* duplicates,
326 bool username_and_password_in_key) {
327 std::vector<std::pair<std::string, scoped_ptr<autofill::PasswordForm>>> pairs;
328 pairs.reserve(list->size());
329 for (auto& form : *list) {
330 pairs.push_back(std::make_pair(
331 CreateSortKey(*form, languages, username_and_password_in_key),
332 std::move(form)));
333 }
334
335 std::sort(
336 pairs.begin(), pairs.end(),
337 [](const std::pair<std::string, scoped_ptr<autofill::PasswordForm>>& left,
338 const std::pair<std::string, scoped_ptr<autofill::PasswordForm>>&
339 right) { return left.first < right.first; });
340
341 list->clear();
342 duplicates->clear();
343 std::string previous_key;
344 for (auto& pair : pairs) {
345 if (pair.first != previous_key) {
346 list->push_back(std::move(pair.second));
347 previous_key = pair.first;
348 } else {
349 duplicates->insert(std::make_pair(previous_key, std::move(pair.second)));
350 }
351 }
352 }
353
224 PasswordManagerPresenter::ListPopulater::ListPopulater( 354 PasswordManagerPresenter::ListPopulater::ListPopulater(
225 PasswordManagerPresenter* page) : page_(page) { 355 PasswordManagerPresenter* page) : page_(page) {
226 } 356 }
227 357
228 PasswordManagerPresenter::ListPopulater::~ListPopulater() { 358 PasswordManagerPresenter::ListPopulater::~ListPopulater() {
229 } 359 }
230 360
231 PasswordManagerPresenter::PasswordListPopulater::PasswordListPopulater( 361 PasswordManagerPresenter::PasswordListPopulater::PasswordListPopulater(
232 PasswordManagerPresenter* page) : ListPopulater(page) { 362 PasswordManagerPresenter* page) : ListPopulater(page) {
233 } 363 }
234 364
235 void PasswordManagerPresenter::PasswordListPopulater::Populate() { 365 void PasswordManagerPresenter::PasswordListPopulater::Populate() {
236 PasswordStore* store = page_->GetPasswordStore(); 366 PasswordStore* store = page_->GetPasswordStore();
237 if (store != NULL) { 367 if (store != NULL) {
238 cancelable_task_tracker()->TryCancelAll(); 368 cancelable_task_tracker()->TryCancelAll();
239 store->GetAutofillableLoginsWithAffiliatedRealms(this); 369 store->GetAutofillableLoginsWithAffiliatedRealms(this);
240 } else { 370 } else {
241 LOG(ERROR) << "No password store! Cannot display passwords."; 371 LOG(ERROR) << "No password store! Cannot display passwords.";
242 } 372 }
243 } 373 }
244 374
245 void PasswordManagerPresenter::PasswordListPopulater::OnGetPasswordStoreResults( 375 void PasswordManagerPresenter::PasswordListPopulater::OnGetPasswordStoreResults(
246 ScopedVector<autofill::PasswordForm> results) { 376 ScopedVector<autofill::PasswordForm> results) {
247 page_->password_list_ = 377 page_->password_list_ =
248 password_manager_util::ConvertScopedVector(std::move(results)); 378 password_manager_util::ConvertScopedVector(std::move(results));
379 page_->SortEntriesAndHideDuplicates(page_->languages_, &page_->password_list_,
380 &page_->password_duplicates_,
381 true /* use username and password */);
249 page_->SetPasswordList(); 382 page_->SetPasswordList();
250 } 383 }
251 384
252 PasswordManagerPresenter::PasswordExceptionListPopulater:: 385 PasswordManagerPresenter::PasswordExceptionListPopulater::
253 PasswordExceptionListPopulater(PasswordManagerPresenter* page) 386 PasswordExceptionListPopulater(PasswordManagerPresenter* page)
254 : ListPopulater(page) { 387 : ListPopulater(page) {
255 } 388 }
256 389
257 void PasswordManagerPresenter::PasswordExceptionListPopulater::Populate() { 390 void PasswordManagerPresenter::PasswordExceptionListPopulater::Populate() {
258 PasswordStore* store = page_->GetPasswordStore(); 391 PasswordStore* store = page_->GetPasswordStore();
259 if (store != NULL) { 392 if (store != NULL) {
260 cancelable_task_tracker()->TryCancelAll(); 393 cancelable_task_tracker()->TryCancelAll();
261 store->GetBlacklistLogins(this); 394 store->GetBlacklistLogins(this);
262 } else { 395 } else {
263 LOG(ERROR) << "No password store! Cannot display exceptions."; 396 LOG(ERROR) << "No password store! Cannot display exceptions.";
264 } 397 }
265 } 398 }
266 399
267 void PasswordManagerPresenter::PasswordExceptionListPopulater:: 400 void PasswordManagerPresenter::PasswordExceptionListPopulater::
268 OnGetPasswordStoreResults(ScopedVector<autofill::PasswordForm> results) { 401 OnGetPasswordStoreResults(ScopedVector<autofill::PasswordForm> results) {
269 page_->password_exception_list_ = 402 page_->password_exception_list_ =
270 password_manager_util::ConvertScopedVector(std::move(results)); 403 password_manager_util::ConvertScopedVector(std::move(results));
404 page_->SortEntriesAndHideDuplicates(
405 page_->languages_, &page_->password_exception_list_,
406 &page_->password_exception_duplicates_,
407 false /* don't use username and password*/);
271 page_->SetPasswordExceptionList(); 408 page_->SetPasswordExceptionList();
272 } 409 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698