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 "base/logging.h"
6#include "components/autofill/core/browser/autofill_driver.h"
7#include "components/autofill/core/browser/popup_item_ids.h"
8#include "components/autofill/core/common/autofill_data_validation.h"
9#include "components/password_manager/core/browser/password_autofill_manager.h"
10#include "components/password_manager/core/browser/password_manager_client.h"
11#include "components/password_manager/core/browser/password_manager_driver.h"
12
13namespace password_manager {
14
15////////////////////////////////////////////////////////////////////////////////
16// PasswordAutofillManager, public:
17
18PasswordAutofillManager::PasswordAutofillManager(
19    PasswordManagerClient* password_manager_client,
20    autofill::AutofillClient* autofill_client)
21    : password_manager_client_(password_manager_client),
22      autofill_client_(autofill_client),
23      weak_ptr_factory_(this) {
24}
25
26PasswordAutofillManager::~PasswordAutofillManager() {
27}
28
29bool PasswordAutofillManager::FillSuggestion(
30    const autofill::FormFieldData& field,
31    const base::string16& username) {
32  autofill::PasswordFormFillData fill_data;
33  base::string16 password;
34  if (FindLoginInfo(field, &fill_data) &&
35      GetPasswordForUsername(username, fill_data, &password)) {
36    PasswordManagerDriver* driver = password_manager_client_->GetDriver();
37    driver->FillSuggestion(username, password);
38    return true;
39  }
40  return false;
41}
42
43bool PasswordAutofillManager::PreviewSuggestion(
44    const autofill::FormFieldData& field,
45    const base::string16& username) {
46  autofill::PasswordFormFillData fill_data;
47  base::string16 password;
48  if (FindLoginInfo(field, &fill_data) &&
49      GetPasswordForUsername(username, fill_data, &password)) {
50    PasswordManagerDriver* driver = password_manager_client_->GetDriver();
51    driver->PreviewSuggestion(username, password);
52    return true;
53  }
54  return false;
55}
56
57void PasswordAutofillManager::OnAddPasswordFormMapping(
58    const autofill::FormFieldData& field,
59    const autofill::PasswordFormFillData& fill_data) {
60  if (!autofill::IsValidFormFieldData(field) ||
61      !autofill::IsValidPasswordFormFillData(fill_data))
62    return;
63
64  login_to_password_info_[field] = fill_data;
65}
66
67void PasswordAutofillManager::OnShowPasswordSuggestions(
68    const autofill::FormFieldData& field,
69    const gfx::RectF& bounds,
70    const std::vector<base::string16>& suggestions,
71    const std::vector<base::string16>& realms) {
72  if (!autofill::IsValidString16Vector(suggestions) ||
73      !autofill::IsValidString16Vector(realms) ||
74      suggestions.size() != realms.size())
75    return;
76
77  form_field_ = field;
78
79  if (suggestions.empty()) {
80    autofill_client_->HideAutofillPopup();
81    return;
82  }
83
84  std::vector<base::string16> empty(suggestions.size());
85  std::vector<int> password_ids(suggestions.size(),
86                                autofill::POPUP_ITEM_ID_PASSWORD_ENTRY);
87  autofill_client_->ShowAutofillPopup(bounds,
88                                      field.text_direction,
89                                      suggestions,
90                                      realms,
91                                      empty,
92                                      password_ids,
93                                      weak_ptr_factory_.GetWeakPtr());
94}
95
96void PasswordAutofillManager::Reset() {
97  login_to_password_info_.clear();
98}
99
100bool PasswordAutofillManager::FillSuggestionForTest(
101    const autofill::FormFieldData& field,
102    const base::string16& username) {
103  return FillSuggestion(field, username);
104}
105
106bool PasswordAutofillManager::PreviewSuggestionForTest(
107    const autofill::FormFieldData& field,
108    const base::string16& username) {
109  return PreviewSuggestion(field, username);
110}
111
112void PasswordAutofillManager::OnPopupShown() {
113}
114
115void PasswordAutofillManager::OnPopupHidden() {
116}
117
118void PasswordAutofillManager::DidSelectSuggestion(const base::string16& value,
119                                                  int identifier) {
120  ClearPreviewedForm();
121  bool success = PreviewSuggestion(form_field_, value);
122  DCHECK(success);
123}
124
125void PasswordAutofillManager::DidAcceptSuggestion(const base::string16& value,
126                                                  int identifier) {
127  bool success = FillSuggestion(form_field_, value);
128  DCHECK(success);
129  autofill_client_->HideAutofillPopup();
130}
131
132void PasswordAutofillManager::RemoveSuggestion(const base::string16& value,
133                                               int identifier) {
134  NOTREACHED();
135}
136
137void PasswordAutofillManager::ClearPreviewedForm() {
138  PasswordManagerDriver* driver = password_manager_client_->GetDriver();
139  driver->ClearPreviewedForm();
140}
141
142////////////////////////////////////////////////////////////////////////////////
143// PasswordAutofillManager, private:
144
145bool PasswordAutofillManager::GetPasswordForUsername(
146    const base::string16& current_username,
147    const autofill::PasswordFormFillData& fill_data,
148    base::string16* password) {
149  // TODO(dubroy): When password access requires some kind of authentication
150  // (e.g. Keychain access on Mac OS), use |password_manager_client_| here to
151  // fetch the actual password. See crbug.com/178358 for more context.
152
153  // Look for any suitable matches to current field text.
154  if (fill_data.basic_data.fields[0].value == current_username) {
155    *password = fill_data.basic_data.fields[1].value;
156    return true;
157  }
158
159  // Scan additional logins for a match.
160  for (autofill::PasswordFormFillData::LoginCollection::const_iterator iter =
161           fill_data.additional_logins.begin();
162       iter != fill_data.additional_logins.end();
163       ++iter) {
164    if (iter->first == current_username) {
165      *password = iter->second.password;
166      return true;
167    }
168  }
169
170  for (autofill::PasswordFormFillData::UsernamesCollection::const_iterator
171           usernames_iter = fill_data.other_possible_usernames.begin();
172       usernames_iter != fill_data.other_possible_usernames.end();
173       ++usernames_iter) {
174    for (size_t i = 0; i < usernames_iter->second.size(); ++i) {
175      if (usernames_iter->second[i] == current_username) {
176        *password = usernames_iter->first.password;
177        return true;
178      }
179    }
180  }
181
182  return false;
183}
184
185bool PasswordAutofillManager::FindLoginInfo(
186    const autofill::FormFieldData& field,
187    autofill::PasswordFormFillData* found_password) {
188  LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(field);
189  if (iter == login_to_password_info_.end())
190    return false;
191
192  *found_password = iter->second;
193  return true;
194}
195
196}  //  namespace password_manager
197