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 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/passwords/password_manager_presenter.h" 6 7#include "base/bind.h" 8#include "base/command_line.h" 9#include "base/metrics/user_metrics_action.h" 10#include "base/prefs/pref_service.h" 11#include "base/strings/utf_string_conversions.h" 12#include "base/time/time.h" 13#include "base/values.h" 14#include "chrome/browser/password_manager/password_manager_util.h" 15#include "chrome/browser/password_manager/password_store_factory.h" 16#include "chrome/browser/password_manager/sync_metrics.h" 17#include "chrome/browser/ui/passwords/password_ui_view.h" 18#include "chrome/common/chrome_switches.h" 19#include "chrome/common/url_constants.h" 20#include "components/autofill/core/common/password_form.h" 21#include "components/password_manager/core/common/password_manager_pref_names.h" 22#include "content/public/browser/user_metrics.h" 23#include "content/public/browser/web_contents.h" 24 25using password_manager::PasswordStore; 26 27PasswordManagerPresenter::PasswordManagerPresenter( 28 PasswordUIView* password_view) 29 : populater_(this), 30 exception_populater_(this), 31 password_view_(password_view) { 32 DCHECK(password_view_); 33 require_reauthentication_ = !CommandLine::ForCurrentProcess()->HasSwitch( 34 switches::kDisablePasswordManagerReauthentication); 35} 36 37PasswordManagerPresenter::~PasswordManagerPresenter() { 38 PasswordStore* store = GetPasswordStore(); 39 if (store) 40 store->RemoveObserver(this); 41} 42 43void PasswordManagerPresenter::Initialize() { 44 // Due to the way that handlers are (re)initialized under certain types of 45 // navigation, the presenter may already be initialized. (See bugs 88986 46 // and 86448). If this is the case, return immediately. This is a hack. 47 // TODO(mdm): remove this hack once it is no longer necessary. 48 if (!show_passwords_.GetPrefName().empty()) 49 return; 50 51 show_passwords_.Init( 52 password_manager::prefs::kPasswordManagerAllowShowPasswords, 53 password_view_->GetProfile()->GetPrefs(), 54 base::Bind(&PasswordManagerPresenter::UpdatePasswordLists, 55 base::Unretained(this))); 56 // TODO(jhawkins) We should not cache web_ui()->GetProfile().See 57 // crosbug.com/6304. 58 PasswordStore* store = GetPasswordStore(); 59 if (store) 60 store->AddObserver(this); 61} 62 63void PasswordManagerPresenter::OnLoginsChanged( 64 const password_manager::PasswordStoreChangeList& changes) { 65 // Entire list is updated for convenience. 66 UpdatePasswordLists(); 67} 68 69PasswordStore* PasswordManagerPresenter::GetPasswordStore() { 70 return PasswordStoreFactory::GetForProfile(password_view_->GetProfile(), 71 Profile::EXPLICIT_ACCESS).get(); 72} 73 74void PasswordManagerPresenter::UpdatePasswordLists() { 75 // Reset so that showing a password will require re-authentication. 76 last_authentication_time_ = base::TimeTicks(); 77 78 // Reset the current lists. 79 password_list_.clear(); 80 password_exception_list_.clear(); 81 82 populater_.Populate(); 83 exception_populater_.Populate(); 84} 85 86void PasswordManagerPresenter::RemoveSavedPassword(size_t index) { 87 if (index >= password_list_.size()) { 88 // |index| out of bounds might come from a compromised renderer, don't let 89 // it crash the browser. http://crbug.com/362054 90 NOTREACHED(); 91 return; 92 } 93 PasswordStore* store = GetPasswordStore(); 94 if (!store) 95 return; 96 store->RemoveLogin(*password_list_[index]); 97 content::RecordAction( 98 base::UserMetricsAction("PasswordManager_RemoveSavedPassword")); 99} 100 101void PasswordManagerPresenter::RemovePasswordException(size_t index) { 102 if (index >= password_exception_list_.size()) { 103 // |index| out of bounds might come from a compromised renderer, don't let 104 // it crash the browser. http://crbug.com/362054 105 NOTREACHED(); 106 return; 107 } 108 PasswordStore* store = GetPasswordStore(); 109 if (!store) 110 return; 111 store->RemoveLogin(*password_exception_list_[index]); 112 content::RecordAction( 113 base::UserMetricsAction("PasswordManager_RemovePasswordException")); 114} 115 116void PasswordManagerPresenter::RequestShowPassword(size_t index) { 117#if !defined(OS_ANDROID) // This is never called on Android. 118 if (index >= password_list_.size()) { 119 // |index| out of bounds might come from a compromised renderer, don't let 120 // it crash the browser. http://crbug.com/362054 121 NOTREACHED(); 122 return; 123 } 124 if (IsAuthenticationRequired()) { 125 if (password_manager_util::AuthenticateUser( 126 password_view_->GetNativeWindow())) 127 last_authentication_time_ = base::TimeTicks::Now(); 128 else 129 return; 130 } 131 132 if (password_manager_sync_metrics::IsSyncAccountCredential( 133 password_view_->GetProfile(), 134 base::UTF16ToUTF8(password_list_[index]->username_value), 135 password_list_[index]->signon_realm)) { 136 content::RecordAction( 137 base::UserMetricsAction("PasswordManager_SyncCredentialShown")); 138 } 139 140 // Call back the front end to reveal the password. 141 password_view_->ShowPassword(index, password_list_[index]->password_value); 142#endif 143} 144 145const autofill::PasswordForm* PasswordManagerPresenter::GetPassword( 146 size_t index) { 147 if (index >= password_list_.size()) { 148 // |index| out of bounds might come from a compromised renderer, don't let 149 // it crash the browser. http://crbug.com/362054 150 NOTREACHED(); 151 return NULL; 152 } 153 return password_list_[index]; 154} 155 156const autofill::PasswordForm* PasswordManagerPresenter::GetPasswordException( 157 size_t index) { 158 if (index >= password_exception_list_.size()) { 159 // |index| out of bounds might come from a compromised renderer, don't let 160 // it crash the browser. http://crbug.com/362054 161 NOTREACHED(); 162 return NULL; 163 } 164 return password_exception_list_[index]; 165} 166 167void PasswordManagerPresenter::SetPasswordList() { 168 // Due to the way that handlers are (re)initialized under certain types of 169 // navigation, the presenter may already be initialized. (See bugs 88986 170 // and 86448). If this is the case, return immediately. This is a hack. 171 // If this is the case, initialize on demand. This is a hack. 172 // TODO(mdm): remove this hack once it is no longer necessary. 173 if (show_passwords_.GetPrefName().empty()) 174 Initialize(); 175 176 bool show_passwords = *show_passwords_ && !require_reauthentication_; 177 password_view_->SetPasswordList(password_list_, show_passwords); 178} 179 180void PasswordManagerPresenter::SetPasswordExceptionList() { 181 password_view_->SetPasswordExceptionList(password_exception_list_); 182} 183 184bool PasswordManagerPresenter::IsAuthenticationRequired() { 185 base::TimeDelta delta = base::TimeDelta::FromSeconds(60); 186 return require_reauthentication_ && 187 (base::TimeTicks::Now() - last_authentication_time_) > delta; 188} 189 190PasswordManagerPresenter::ListPopulater::ListPopulater( 191 PasswordManagerPresenter* page) : page_(page) { 192} 193 194PasswordManagerPresenter::ListPopulater::~ListPopulater() { 195} 196 197PasswordManagerPresenter::PasswordListPopulater::PasswordListPopulater( 198 PasswordManagerPresenter* page) : ListPopulater(page) { 199} 200 201void PasswordManagerPresenter::PasswordListPopulater::Populate() { 202 PasswordStore* store = page_->GetPasswordStore(); 203 if (store != NULL) { 204 cancelable_task_tracker()->TryCancelAll(); 205 store->GetAutofillableLogins(this); 206 } else { 207 LOG(ERROR) << "No password store! Cannot display passwords."; 208 } 209} 210 211void PasswordManagerPresenter::PasswordListPopulater::OnGetPasswordStoreResults( 212 const std::vector<autofill::PasswordForm*>& results) { 213 page_->password_list_.clear(); 214 page_->password_list_.insert(page_->password_list_.end(), 215 results.begin(), results.end()); 216 page_->SetPasswordList(); 217} 218 219PasswordManagerPresenter::PasswordExceptionListPopulater:: 220 PasswordExceptionListPopulater(PasswordManagerPresenter* page) 221 : ListPopulater(page) { 222} 223 224void PasswordManagerPresenter::PasswordExceptionListPopulater::Populate() { 225 PasswordStore* store = page_->GetPasswordStore(); 226 if (store != NULL) { 227 cancelable_task_tracker()->TryCancelAll(); 228 store->GetBlacklistLogins(this); 229 } else { 230 LOG(ERROR) << "No password store! Cannot display exceptions."; 231 } 232} 233 234void PasswordManagerPresenter::PasswordExceptionListPopulater:: 235 OnGetPasswordStoreResults( 236 const std::vector<autofill::PasswordForm*>& results) { 237 page_->password_exception_list_.clear(); 238 page_->password_exception_list_.insert(page_->password_exception_list_.end(), 239 results.begin(), results.end()); 240 page_->SetPasswordExceptionList(); 241} 242