password_manager_handler.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
1// Copyright (c) 2012 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/webui/options/password_manager_handler.h"
6
7#include "base/bind.h"
8#include "base/prefs/pref_service.h"
9#include "base/strings/string_number_conversions.h"
10#include "base/strings/utf_string_conversions.h"
11#include "base/values.h"
12#include "chrome/browser/chrome_notification_types.h"
13#include "chrome/browser/password_manager/password_store_factory.h"
14#include "chrome/browser/profiles/profile.h"
15#include "chrome/common/pref_names.h"
16#include "chrome/common/url_constants.h"
17#include "content/public/browser/notification_details.h"
18#include "content/public/browser/notification_source.h"
19#include "content/public/browser/web_ui.h"
20#include "content/public/common/password_form.h"
21#include "grit/chromium_strings.h"
22#include "grit/generated_resources.h"
23#include "net/base/net_util.h"
24#include "ui/base/l10n/l10n_util.h"
25
26namespace options {
27
28PasswordManagerHandler::PasswordManagerHandler()
29    : populater_(this),
30      exception_populater_(this) {
31}
32
33PasswordManagerHandler::~PasswordManagerHandler() {
34  PasswordStore* store = GetPasswordStore();
35  if (store)
36    store->RemoveObserver(this);
37}
38
39void PasswordManagerHandler::GetLocalizedValues(
40    DictionaryValue* localized_strings) {
41  DCHECK(localized_strings);
42
43  static const OptionsStringResource resources[] = {
44    { "savedPasswordsTitle",
45      IDS_PASSWORDS_SHOW_PASSWORDS_TAB_TITLE },
46    { "passwordExceptionsTitle",
47      IDS_PASSWORDS_EXCEPTIONS_TAB_TITLE },
48    { "passwordSearchPlaceholder",
49      IDS_PASSWORDS_PAGE_SEARCH_PASSWORDS },
50    { "passwordShowButton",
51      IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON },
52    { "passwordHideButton",
53      IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON },
54    { "passwordsNoPasswordsDescription",
55      IDS_PASSWORDS_PAGE_VIEW_NO_PASSWORDS_DESCRIPTION },
56    { "passwordsNoExceptionsDescription",
57      IDS_PASSWORDS_PAGE_VIEW_NO_EXCEPTIONS_DESCRIPTION },
58  };
59
60  RegisterStrings(localized_strings, resources, arraysize(resources));
61  RegisterTitle(localized_strings, "passwordsPage",
62                IDS_PASSWORDS_EXCEPTIONS_WINDOW_TITLE);
63
64  localized_strings->SetString("passwordManagerLearnMoreURL",
65                               chrome::kPasswordManagerLearnMoreURL);
66}
67
68void PasswordManagerHandler::InitializeHandler() {
69  // Due to the way that handlers are (re)initialized under certain types of
70  // navigation, we may already be initialized. (See bugs 88986 and 86448.)
71  // If this is the case, return immediately. This is a hack.
72  // TODO(mdm): remove this hack once it is no longer necessary.
73  if (!show_passwords_.GetPrefName().empty())
74    return;
75
76  show_passwords_.Init(prefs::kPasswordManagerAllowShowPasswords,
77                       Profile::FromWebUI(web_ui())->GetPrefs(),
78                       base::Bind(&PasswordManagerHandler::UpdatePasswordLists,
79                                  base::Unretained(this),
80                                  static_cast<base::ListValue*>(NULL)));
81  // We should not cache web_ui()->GetProfile(). See crosbug.com/6304.
82  PasswordStore* store = GetPasswordStore();
83  if (store)
84    store->AddObserver(this);
85}
86
87void PasswordManagerHandler::RegisterMessages() {
88  web_ui()->RegisterMessageCallback("updatePasswordLists",
89      base::Bind(&PasswordManagerHandler::UpdatePasswordLists,
90                 base::Unretained(this)));
91  web_ui()->RegisterMessageCallback("removeSavedPassword",
92      base::Bind(&PasswordManagerHandler::RemoveSavedPassword,
93                 base::Unretained(this)));
94  web_ui()->RegisterMessageCallback("removePasswordException",
95      base::Bind(&PasswordManagerHandler::RemovePasswordException,
96                 base::Unretained(this)));
97  web_ui()->RegisterMessageCallback("removeAllSavedPasswords",
98      base::Bind(&PasswordManagerHandler::RemoveAllSavedPasswords,
99                 base::Unretained(this)));
100  web_ui()->RegisterMessageCallback("removeAllPasswordExceptions",
101      base::Bind(&PasswordManagerHandler::RemoveAllPasswordExceptions,
102                 base::Unretained(this)));
103}
104
105void PasswordManagerHandler::OnLoginsChanged() {
106  UpdatePasswordLists(NULL);
107}
108
109PasswordStore* PasswordManagerHandler::GetPasswordStore() {
110  return PasswordStoreFactory::GetForProfile(Profile::FromWebUI(web_ui()),
111                                             Profile::EXPLICIT_ACCESS).get();
112}
113
114void PasswordManagerHandler::UpdatePasswordLists(const ListValue* args) {
115  // Reset the current lists.
116  password_list_.clear();
117  password_exception_list_.clear();
118
119  languages_ = Profile::FromWebUI(web_ui())->GetPrefs()->
120      GetString(prefs::kAcceptLanguages);
121  populater_.Populate();
122  exception_populater_.Populate();
123}
124
125void PasswordManagerHandler::RemoveSavedPassword(const ListValue* args) {
126  PasswordStore* store = GetPasswordStore();
127  if (!store)
128    return;
129  std::string string_value = UTF16ToUTF8(ExtractStringValue(args));
130  int index;
131  if (base::StringToInt(string_value, &index) && index >= 0 &&
132      static_cast<size_t>(index) < password_list_.size())
133    store->RemoveLogin(*password_list_[index]);
134}
135
136void PasswordManagerHandler::RemovePasswordException(
137    const ListValue* args) {
138  PasswordStore* store = GetPasswordStore();
139  if (!store)
140    return;
141  std::string string_value = UTF16ToUTF8(ExtractStringValue(args));
142  int index;
143  if (base::StringToInt(string_value, &index) && index >= 0 &&
144      static_cast<size_t>(index) < password_exception_list_.size())
145    store->RemoveLogin(*password_exception_list_[index]);
146}
147
148void PasswordManagerHandler::RemoveAllSavedPasswords(
149    const ListValue* args) {
150  // TODO(jhawkins): This will cause a list refresh for every password in the
151  // list. Add PasswordStore::RemoveAllLogins().
152  PasswordStore* store = GetPasswordStore();
153  if (!store)
154    return;
155  for (size_t i = 0; i < password_list_.size(); ++i)
156    store->RemoveLogin(*password_list_[i]);
157}
158
159void PasswordManagerHandler::RemoveAllPasswordExceptions(
160    const ListValue* args) {
161  PasswordStore* store = GetPasswordStore();
162  if (!store)
163    return;
164  for (size_t i = 0; i < password_exception_list_.size(); ++i)
165    store->RemoveLogin(*password_exception_list_[i]);
166}
167
168void PasswordManagerHandler::SetPasswordList() {
169  // Due to the way that handlers are (re)initialized under certain types of
170  // navigation, we may not be initialized yet. (See bugs 88986 and 86448.)
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    InitializeHandler();
175
176  ListValue entries;
177  bool show_passwords = *show_passwords_;
178  string16 empty;
179  for (size_t i = 0; i < password_list_.size(); ++i) {
180    ListValue* entry = new ListValue();
181    entry->Append(new StringValue(net::FormatUrl(password_list_[i]->origin,
182                                                 languages_)));
183    entry->Append(new StringValue(password_list_[i]->username_value));
184    entry->Append(new StringValue(
185        show_passwords ? password_list_[i]->password_value : empty));
186    entries.Append(entry);
187  }
188
189  web_ui()->CallJavascriptFunction("PasswordManager.setSavedPasswordsList",
190                                   entries);
191}
192
193void PasswordManagerHandler::SetPasswordExceptionList() {
194  ListValue entries;
195  for (size_t i = 0; i < password_exception_list_.size(); ++i) {
196    entries.Append(new StringValue(
197        net::FormatUrl(password_exception_list_[i]->origin, languages_)));
198  }
199
200  web_ui()->CallJavascriptFunction("PasswordManager.setPasswordExceptionsList",
201                                   entries);
202}
203
204PasswordManagerHandler::ListPopulater::ListPopulater(
205    PasswordManagerHandler* page)
206    : page_(page),
207      pending_login_query_(0) {
208}
209
210PasswordManagerHandler::ListPopulater::~ListPopulater() {
211}
212
213PasswordManagerHandler::PasswordListPopulater::PasswordListPopulater(
214    PasswordManagerHandler* page) : ListPopulater(page) {
215}
216
217void PasswordManagerHandler::PasswordListPopulater::Populate() {
218  PasswordStore* store = page_->GetPasswordStore();
219  if (store != NULL) {
220    if (pending_login_query_)
221      store->CancelRequest(pending_login_query_);
222
223    pending_login_query_ = store->GetAutofillableLogins(this);
224  } else {
225    LOG(ERROR) << "No password store! Cannot display passwords.";
226  }
227}
228
229void PasswordManagerHandler::PasswordListPopulater::
230    OnPasswordStoreRequestDone(
231        CancelableRequestProvider::Handle handle,
232        const std::vector<content::PasswordForm*>& result) {
233  DCHECK_EQ(pending_login_query_, handle);
234  pending_login_query_ = 0;
235  page_->password_list_.clear();
236  page_->password_list_.insert(page_->password_list_.end(),
237                               result.begin(), result.end());
238  page_->SetPasswordList();
239}
240
241void PasswordManagerHandler::PasswordListPopulater::OnGetPasswordStoreResults(
242    const std::vector<content::PasswordForm*>& results) {
243  // TODO(kaiwang): Implement when I refactor
244  // PasswordStore::GetAutofillableLogins and PasswordStore::GetBlacklistLogins.
245  NOTIMPLEMENTED();
246}
247
248PasswordManagerHandler::PasswordExceptionListPopulater::
249    PasswordExceptionListPopulater(PasswordManagerHandler* page)
250        : ListPopulater(page) {
251}
252
253void PasswordManagerHandler::PasswordExceptionListPopulater::Populate() {
254  PasswordStore* store = page_->GetPasswordStore();
255  if (store != NULL) {
256    if (pending_login_query_)
257      store->CancelRequest(pending_login_query_);
258
259    pending_login_query_ = store->GetBlacklistLogins(this);
260  } else {
261    LOG(ERROR) << "No password store! Cannot display exceptions.";
262  }
263}
264
265void PasswordManagerHandler::PasswordExceptionListPopulater::
266    OnPasswordStoreRequestDone(
267        CancelableRequestProvider::Handle handle,
268        const std::vector<content::PasswordForm*>& result) {
269  DCHECK_EQ(pending_login_query_, handle);
270  pending_login_query_ = 0;
271  page_->password_exception_list_.clear();
272  page_->password_exception_list_.insert(page_->password_exception_list_.end(),
273                                         result.begin(), result.end());
274  page_->SetPasswordExceptionList();
275}
276
277void PasswordManagerHandler::PasswordExceptionListPopulater::
278    OnGetPasswordStoreResults(
279        const std::vector<content::PasswordForm*>& results) {
280  // TODO(kaiwang): Implement when I refactor
281  // PasswordStore::GetAutofillableLogins and PasswordStore::GetBlacklistLogins.
282  NOTIMPLEMENTED();
283}
284
285}  // namespace options
286