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

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

Powered by Google App Engine
This is Rietveld 408576698