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

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: 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/sha1.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"
34 38
39 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
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
41 using password_manager::PasswordStore; 46 using password_manager::PasswordStore;
42 47
48 namespace {
49
50 const int kAndroidAppSchemeAndDelimeterLength = 10; // Length of 'android://'.
vabr (Chromium) 2016/03/08 13:09:28 typo: delimeter -> delimiter
kolos1 2016/03/08 15:14:23 Done.
51
52 const char kSortKeyPartsSeparator = ' ';
53
54 // Reverse order of subdomains in hostname.
55 std::string SplitByDotAndReverse(const std::string& host) {
vabr (Chromium) 2016/03/08 13:09:28 To improve efficiency, consider passing a StringPi
kolos1 2016/03/08 15:14:24 Yes, it would be nice to replace std::string with
vabr (Chromium) 2016/03/08 16:04:44 This is not about changing the SplitString/JoinStr
kolos1 2016/03/09 09:56:39 Done.
56 std::vector<std::string> parts =
57 base::SplitString(host, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
58 std::reverse(parts.begin(), parts.end());
59 return base::JoinString(parts, ".");
60 }
61
62 // Helper function that returns the type of the entry (non-Android credentials,
63 // Android w/ affiliated web realm (i.e. clickable) or w/o web realm).
64 std::string GetEntryTypeCode(bool is_android_uri, bool is_clickable) {
65 if (!is_android_uri)
66 return "0";
67 if (is_clickable)
68 return "1";
69 return "2";
70 }
71
72 // Creates key for sorting password or password exception entries.
73 // The key is eTLD+1 followed by subdomains
74 // (e.g. secure.accounts.example.com => example.com.accounts.secure).
75 // If |username_and_password_in_key == true|, the key is appended with username
vabr (Chromium) 2016/03/08 13:09:28 nit: To avoid misunderstanding of what is appended
kolos1 2016/03/08 15:14:23 Done.
76 // and hashed password. The key is also appended with entry type code
77 // (non-Android, Android w/ or w/o affiliated web realm).
78 std::string CreateSortKey(const scoped_ptr<autofill::PasswordForm>& form,
vabr (Chromium) 2016/03/08 13:09:28 Please replace the const scoped_ptr with just a ra
kolos1 2016/03/08 15:14:23 Since we don't modify |form|, I redeclared it as c
vabr (Chromium) 2016/03/08 16:04:44 Acknowledged.
79 const std::string& languages,
80 bool username_and_password_in_key) {
81 bool is_android_uri = false;
82 bool is_clickable = false;
83 GURL link_url;
84 std::string origin = password_manager::GetShownOriginAndLinkUrl(
85 *form, languages, &is_android_uri, &link_url, &is_clickable);
86
87 if (!is_clickable) // e.g. android://com.example.r => r.example.com.
88 origin = SplitByDotAndReverse(
89 origin.substr(kAndroidAppSchemeAndDelimeterLength));
90
91 std::string site_name =
92 net::registry_controlled_domains::GetDomainAndRegistry(
93 origin, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
94 if (site_name.empty()) // e.g. localhost.
95 site_name = origin;
96 std::string key = site_name + SplitByDotAndReverse(origin.substr(
97 0, origin.length() - site_name.length()));
98
99 if (username_and_password_in_key)
vabr (Chromium) 2016/03/08 13:09:28 nit: Add { and }, this is not a one-liner.
kolos1 2016/03/08 15:14:23 Done.
100 key = key + kSortKeyPartsSeparator +
101 base::UTF16ToUTF8(form->username_value) + kSortKeyPartsSeparator +
102 base::SHA1HashString(base::UTF16ToUTF8(form->password_value));
vabr (Chromium) 2016/03/08 14:48:24 Why do we actually hash the passwords? The keys no
kolos1 2016/03/08 15:14:23 Lets somebody want to see one of passwords listed
vabr (Chromium) 2016/03/08 16:04:44 Oh, that's a interesting good point, especially th
kolos1 2016/03/09 09:56:39 I discussed this question with security team. They
103
104 // Since Android and non-Android entries shouldn't be merged into one entry,
105 // add the entry type code to the sort key.
106 key +=
107 kSortKeyPartsSeparator + GetEntryTypeCode(is_android_uri, is_clickable);
108 return key;
109 }
110
111 // Finds duplicates of |form| in |duplicates|, removes them from |store| and
112 // from |duplicates|.
113 void RemoveDuplicates(const scoped_ptr<autofill::PasswordForm>& form,
vabr (Chromium) 2016/03/08 13:09:28 Also here: raw pointer instead of a scoped_ptr.
kolos1 2016/03/08 15:14:23 Since we don't modify form, redeclared as const re
vabr (Chromium) 2016/03/08 16:04:44 Acknowledged.
114 const std::string& languages,
115 autofill::DuplicatesMap* duplicates,
116 PasswordStore* store,
117 bool username_and_password_in_key) {
118 std::string key =
119 CreateSortKey(form, languages, username_and_password_in_key);
120 std::pair<autofill::DuplicatesMap::iterator,
121 autofill::DuplicatesMap::iterator>
122 dups = duplicates->equal_range(key);
123 for (autofill::DuplicatesMap::iterator it = dups.first; it != dups.second;
vabr (Chromium) 2016/03/08 13:09:28 nit: Use range-based loop, it's shorter and easier
kolos1 2016/03/08 15:14:23 dups is a pair of iterators. I didn't find a way
vabr (Chromium) 2016/03/08 16:04:44 Ah right, I got confused by the STL naming. :) The
124 ++it)
125 store->RemoveLogin(*it->second);
126 duplicates->erase(key);
127 }
128
129 } // namespace
130
43 PasswordManagerPresenter::PasswordManagerPresenter( 131 PasswordManagerPresenter::PasswordManagerPresenter(
44 PasswordUIView* password_view) 132 PasswordUIView* password_view)
45 : populater_(this), 133 : populater_(this),
46 exception_populater_(this), 134 exception_populater_(this),
47 require_reauthentication_( 135 require_reauthentication_(
48 !base::CommandLine::ForCurrentProcess()->HasSwitch( 136 !base::CommandLine::ForCurrentProcess()->HasSwitch(
49 switches::kDisablePasswordManagerReauthentication)), 137 switches::kDisablePasswordManagerReauthentication)),
50 password_view_(password_view) { 138 password_view_(password_view) {
51 DCHECK(password_view_); 139 DCHECK(password_view_);
52 } 140 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 ServiceAccessType::EXPLICIT_ACCESS) 179 ServiceAccessType::EXPLICIT_ACCESS)
92 .get(); 180 .get();
93 } 181 }
94 182
95 void PasswordManagerPresenter::UpdatePasswordLists() { 183 void PasswordManagerPresenter::UpdatePasswordLists() {
96 // Reset so that showing a password will require re-authentication. 184 // Reset so that showing a password will require re-authentication.
97 last_authentication_time_ = base::TimeTicks(); 185 last_authentication_time_ = base::TimeTicks();
98 186
99 // Reset the current lists. 187 // Reset the current lists.
100 password_list_.clear(); 188 password_list_.clear();
189 password_duplicates_.clear();
101 password_exception_list_.clear(); 190 password_exception_list_.clear();
191 password_exception_duplicates_.clear();
102 192
103 populater_.Populate(); 193 populater_.Populate();
104 exception_populater_.Populate(); 194 exception_populater_.Populate();
105 } 195 }
106 196
107 void PasswordManagerPresenter::RemoveSavedPassword(size_t index) { 197 void PasswordManagerPresenter::RemoveSavedPassword(size_t index) {
108 if (index >= password_list_.size()) { 198 if (index >= password_list_.size()) {
109 // |index| out of bounds might come from a compromised renderer, don't let 199 // |index| out of bounds might come from a compromised renderer, don't let
110 // it crash the browser. http://crbug.com/362054 200 // it crash the browser. http://crbug.com/362054
111 NOTREACHED(); 201 NOTREACHED();
112 return; 202 return;
113 } 203 }
114 PasswordStore* store = GetPasswordStore(); 204 PasswordStore* store = GetPasswordStore();
115 if (!store) 205 if (!store)
116 return; 206 return;
207
208 RemoveDuplicates(password_list_[index], languages_, &password_duplicates_,
209 store, true);
117 store->RemoveLogin(*password_list_[index]); 210 store->RemoveLogin(*password_list_[index]);
118 content::RecordAction( 211 content::RecordAction(
119 base::UserMetricsAction("PasswordManager_RemoveSavedPassword")); 212 base::UserMetricsAction("PasswordManager_RemoveSavedPassword"));
120 } 213 }
121 214
122 void PasswordManagerPresenter::RemovePasswordException(size_t index) { 215 void PasswordManagerPresenter::RemovePasswordException(size_t index) {
123 if (index >= password_exception_list_.size()) { 216 if (index >= password_exception_list_.size()) {
124 // |index| out of bounds might come from a compromised renderer, don't let 217 // |index| out of bounds might come from a compromised renderer, don't let
125 // it crash the browser. http://crbug.com/362054 218 // it crash the browser. http://crbug.com/362054
126 NOTREACHED(); 219 NOTREACHED();
127 return; 220 return;
128 } 221 }
129 PasswordStore* store = GetPasswordStore(); 222 PasswordStore* store = GetPasswordStore();
130 if (!store) 223 if (!store)
131 return; 224 return;
225 RemoveDuplicates(password_exception_list_[index], languages_,
226 &password_exception_duplicates_, store, false);
132 store->RemoveLogin(*password_exception_list_[index]); 227 store->RemoveLogin(*password_exception_list_[index]);
133 content::RecordAction( 228 content::RecordAction(
134 base::UserMetricsAction("PasswordManager_RemovePasswordException")); 229 base::UserMetricsAction("PasswordManager_RemovePasswordException"));
135 } 230 }
136 231
137 void PasswordManagerPresenter::RequestShowPassword(size_t index) { 232 void PasswordManagerPresenter::RequestShowPassword(size_t index) {
138 #if !defined(OS_ANDROID) // This is never called on Android. 233 #if !defined(OS_ANDROID) // This is never called on Android.
139 if (index >= password_list_.size()) { 234 if (index >= password_list_.size()) {
140 // |index| out of bounds might come from a compromised renderer, don't let 235 // |index| out of bounds might come from a compromised renderer, don't let
141 // it crash the browser. http://crbug.com/362054 236 // it crash the browser. http://crbug.com/362054
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 Initialize(); 309 Initialize();
215 310
216 bool show_passwords = *show_passwords_ && !require_reauthentication_; 311 bool show_passwords = *show_passwords_ && !require_reauthentication_;
217 password_view_->SetPasswordList(password_list_, show_passwords); 312 password_view_->SetPasswordList(password_list_, show_passwords);
218 } 313 }
219 314
220 void PasswordManagerPresenter::SetPasswordExceptionList() { 315 void PasswordManagerPresenter::SetPasswordExceptionList() {
221 password_view_->SetPasswordExceptionList(password_exception_list_); 316 password_view_->SetPasswordExceptionList(password_exception_list_);
222 } 317 }
223 318
319 void PasswordManagerPresenter::SortEntriesAndHideDuplicates(
320 const std::string& languages,
321 std::vector<scoped_ptr<autofill::PasswordForm>>* list,
322 autofill::DuplicatesMap* duplicates_,
323 bool username_and_password_in_key) {
324 std::vector<std::pair<std::string, scoped_ptr<autofill::PasswordForm>>> pairs;
325 pairs.reserve(list->size());
326 for (auto& form : *list) {
327 pairs.push_back(std::make_pair(
328 CreateSortKey(form, languages, username_and_password_in_key),
329 std::move(form)));
330 }
331
332 std::sort(
333 pairs.begin(), pairs.end(),
334 [](const std::pair<std::string, scoped_ptr<autofill::PasswordForm>>& left,
335 const std::pair<std::string, scoped_ptr<autofill::PasswordForm>>&
336 right) { return left.first < right.first; });
337
338 list->clear();
339 duplicates_->clear();
340 std::string previous_key;
341 for (auto& pair : pairs) {
342 if (pair.first != previous_key) {
343 list->push_back(std::move(pair.second));
344 previous_key = pair.first;
345 } else {
346 duplicates_->insert(std::make_pair(previous_key, std::move(pair.second)));
347 }
348 }
349 }
350
224 PasswordManagerPresenter::ListPopulater::ListPopulater( 351 PasswordManagerPresenter::ListPopulater::ListPopulater(
225 PasswordManagerPresenter* page) : page_(page) { 352 PasswordManagerPresenter* page) : page_(page) {
226 } 353 }
227 354
228 PasswordManagerPresenter::ListPopulater::~ListPopulater() { 355 PasswordManagerPresenter::ListPopulater::~ListPopulater() {
229 } 356 }
230 357
231 PasswordManagerPresenter::PasswordListPopulater::PasswordListPopulater( 358 PasswordManagerPresenter::PasswordListPopulater::PasswordListPopulater(
232 PasswordManagerPresenter* page) : ListPopulater(page) { 359 PasswordManagerPresenter* page) : ListPopulater(page) {
233 } 360 }
234 361
235 void PasswordManagerPresenter::PasswordListPopulater::Populate() { 362 void PasswordManagerPresenter::PasswordListPopulater::Populate() {
236 PasswordStore* store = page_->GetPasswordStore(); 363 PasswordStore* store = page_->GetPasswordStore();
237 if (store != NULL) { 364 if (store != NULL) {
238 cancelable_task_tracker()->TryCancelAll(); 365 cancelable_task_tracker()->TryCancelAll();
239 store->GetAutofillableLoginsWithAffiliatedRealms(this); 366 store->GetAutofillableLoginsWithAffiliatedRealms(this);
240 } else { 367 } else {
241 LOG(ERROR) << "No password store! Cannot display passwords."; 368 LOG(ERROR) << "No password store! Cannot display passwords.";
242 } 369 }
243 } 370 }
244 371
245 void PasswordManagerPresenter::PasswordListPopulater::OnGetPasswordStoreResults( 372 void PasswordManagerPresenter::PasswordListPopulater::OnGetPasswordStoreResults(
246 ScopedVector<autofill::PasswordForm> results) { 373 ScopedVector<autofill::PasswordForm> results) {
247 page_->password_list_ = 374 page_->password_list_ =
248 password_manager_util::ConvertScopedVector(std::move(results)); 375 password_manager_util::ConvertScopedVector(std::move(results));
376 page_->SortEntriesAndHideDuplicates(page_->languages_, &page_->password_list_,
377 &page_->password_duplicates_,
378 true /* use username and password */);
249 page_->SetPasswordList(); 379 page_->SetPasswordList();
250 } 380 }
251 381
252 PasswordManagerPresenter::PasswordExceptionListPopulater:: 382 PasswordManagerPresenter::PasswordExceptionListPopulater::
253 PasswordExceptionListPopulater(PasswordManagerPresenter* page) 383 PasswordExceptionListPopulater(PasswordManagerPresenter* page)
254 : ListPopulater(page) { 384 : ListPopulater(page) {
255 } 385 }
256 386
257 void PasswordManagerPresenter::PasswordExceptionListPopulater::Populate() { 387 void PasswordManagerPresenter::PasswordExceptionListPopulater::Populate() {
258 PasswordStore* store = page_->GetPasswordStore(); 388 PasswordStore* store = page_->GetPasswordStore();
259 if (store != NULL) { 389 if (store != NULL) {
260 cancelable_task_tracker()->TryCancelAll(); 390 cancelable_task_tracker()->TryCancelAll();
261 store->GetBlacklistLogins(this); 391 store->GetBlacklistLogins(this);
262 } else { 392 } else {
263 LOG(ERROR) << "No password store! Cannot display exceptions."; 393 LOG(ERROR) << "No password store! Cannot display exceptions.";
264 } 394 }
265 } 395 }
266 396
267 void PasswordManagerPresenter::PasswordExceptionListPopulater:: 397 void PasswordManagerPresenter::PasswordExceptionListPopulater::
268 OnGetPasswordStoreResults(ScopedVector<autofill::PasswordForm> results) { 398 OnGetPasswordStoreResults(ScopedVector<autofill::PasswordForm> results) {
269 page_->password_exception_list_ = 399 page_->password_exception_list_ =
270 password_manager_util::ConvertScopedVector(std::move(results)); 400 password_manager_util::ConvertScopedVector(std::move(results));
401 page_->SortEntriesAndHideDuplicates(
402 page_->languages_, &page_->password_exception_list_,
403 &page_->password_exception_duplicates_,
404 false /* don't use username and password*/);
271 page_->SetPasswordExceptionList(); 405 page_->SetPasswordExceptionList();
272 } 406 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698