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