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