Home | History | Annotate | Download | only in passwords
      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