blob: 33649b86676a31a67d73d5466eb43c0e97c09939 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/passwords/manage_passwords_state.h"
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
#include "components/password_manager/core/browser/password_form_manager.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/common/credential_manager_types.h"
using password_manager::PasswordFormManager;
using autofill::PasswordFormMap;
namespace {
// Returns a vector containing the values of a map.
template <typename Map>
std::vector<typename Map::mapped_type> MapToVector(const Map& map) {
std::vector<typename Map::mapped_type> ret;
ret.reserve(map.size());
for (const auto& form_pair : map)
ret.push_back(form_pair.second);
return ret;
}
// Takes a ScopedPtrMap. Returns a vector of non-owned pointers to the elements
// inside the scoped_ptrs.
template <typename Map>
std::vector<const typename Map::mapped_type::element_type*>
ScopedPtrMapToVector(const Map& map) {
std::vector<const typename Map::mapped_type::element_type*> ret;
ret.reserve(map.size());
for (const auto& form_pair : map)
ret.push_back(form_pair.second);
return ret;
}
ScopedVector<const autofill::PasswordForm> DeepCopyMapToVector(
const PasswordFormMap& password_form_map) {
ScopedVector<const autofill::PasswordForm> ret;
ret.reserve(password_form_map.size());
for (const auto& form_pair : password_form_map)
ret.push_back(new autofill::PasswordForm(*form_pair.second));
return ret.Pass();
}
ScopedVector<const autofill::PasswordForm> ConstifyVector(
ScopedVector<autofill::PasswordForm>* forms) {
ScopedVector<const autofill::PasswordForm> ret;
ret.assign(forms->begin(), forms->end());
forms->weak_clear();
return ret.Pass();
}
// Updates one form in |forms| that has the same unique key as |updated_form|.
// Returns true if the form was found and updated.
bool UpdateFormInVector(const autofill::PasswordForm& updated_form,
ScopedVector<const autofill::PasswordForm>* forms) {
ScopedVector<const autofill::PasswordForm>::iterator it = std::find_if(
forms->begin(), forms->end(),
[&updated_form](const autofill::PasswordForm* form) {
return ArePasswordFormUniqueKeyEqual(*form, updated_form);
});
if (it != forms->end()) {
delete *it;
*it = new autofill::PasswordForm(updated_form);
return true;
}
return false;
}
// Removes a form from |forms| that has the same unique key as |form_to_delete|.
template <class Vector>
void RemoveFormFromVector(const autofill::PasswordForm& form_to_delete,
Vector* forms) {
typename Vector::iterator it = std::find_if(
forms->begin(), forms->end(),
[&form_to_delete](const autofill::PasswordForm* form) {
return ArePasswordFormUniqueKeyEqual(*form, form_to_delete);
});
if (it != forms->end())
forms->erase(it);
}
} // namespace
ManagePasswordsState::ManagePasswordsState()
: state_(password_manager::ui::INACTIVE_STATE),
client_(nullptr) {
}
ManagePasswordsState::~ManagePasswordsState() {}
void ManagePasswordsState::OnPendingPassword(
scoped_ptr<password_manager::PasswordFormManager> form_manager) {
ClearData();
form_manager_ = form_manager.Pass();
current_forms_weak_ = ScopedPtrMapToVector(form_manager_->best_matches());
origin_ = form_manager_->pending_credentials().origin;
SetState(password_manager::ui::PENDING_PASSWORD_STATE);
}
void ManagePasswordsState::OnUpdatePassword(
scoped_ptr<password_manager::PasswordFormManager> form_manager) {
ClearData();
form_manager_ = form_manager.Pass();
current_forms_weak_ = ScopedPtrMapToVector(form_manager_->best_matches());
origin_ = form_manager_->pending_credentials().origin;
SetState(password_manager::ui::PENDING_PASSWORD_UPDATE_STATE);
}
void ManagePasswordsState::OnRequestCredentials(
ScopedVector<autofill::PasswordForm> local_credentials,
ScopedVector<autofill::PasswordForm> federated_credentials,
const GURL& origin) {
ClearData();
local_credentials_forms_ = ConstifyVector(&local_credentials);
federated_credentials_forms_ = ConstifyVector(&federated_credentials);
origin_ = origin;
SetState(password_manager::ui::CREDENTIAL_REQUEST_STATE);
}
void ManagePasswordsState::OnAutoSignin(
ScopedVector<autofill::PasswordForm> local_forms) {
DCHECK(!local_forms.empty());
ClearData();
local_credentials_forms_ = ConstifyVector(&local_forms);
origin_ = local_credentials_forms_[0]->origin;
SetState(password_manager::ui::AUTO_SIGNIN_STATE);
}
void ManagePasswordsState::OnAutomaticPasswordSave(
scoped_ptr<PasswordFormManager> form_manager) {
ClearData();
form_manager_ = form_manager.Pass();
autofill::ConstPasswordFormMap current_forms;
current_forms.insert(form_manager_->best_matches().begin(),
form_manager_->best_matches().end());
current_forms[form_manager_->pending_credentials().username_value] =
&form_manager_->pending_credentials();
current_forms_weak_ = MapToVector(current_forms);
origin_ = form_manager_->pending_credentials().origin;
SetState(password_manager::ui::CONFIRMATION_STATE);
}
void ManagePasswordsState::OnPasswordAutofilled(
const PasswordFormMap& password_form_map) {
// TODO(vabr): Revert back to DCHECK once http://crbug.com/486931 is fixed.
CHECK(!password_form_map.empty());
ClearData();
if (password_form_map.begin()->second->is_public_suffix_match) {
// Don't show the UI for PSL matched passwords. They are not stored for this
// page and cannot be deleted.
origin_ = GURL();
SetState(password_manager::ui::INACTIVE_STATE);
} else {
local_credentials_forms_ = DeepCopyMapToVector(password_form_map);
origin_ = local_credentials_forms_.front()->origin;
SetState(password_manager::ui::MANAGE_STATE);
}
}
void ManagePasswordsState::OnInactive() {
ClearData();
origin_ = GURL();
SetState(password_manager::ui::INACTIVE_STATE);
}
void ManagePasswordsState::TransitionToState(
password_manager::ui::State state) {
DCHECK_NE(password_manager::ui::INACTIVE_STATE, state_);
DCHECK_EQ(password_manager::ui::MANAGE_STATE, state);
if (state_ == password_manager::ui::CREDENTIAL_REQUEST_STATE) {
if (!credentials_callback_.is_null()) {
credentials_callback_.Run(password_manager::CredentialInfo());
credentials_callback_.Reset();
}
federated_credentials_forms_.clear();
}
SetState(state);
}
void ManagePasswordsState::ProcessLoginsChanged(
const password_manager::PasswordStoreChangeList& changes) {
if (state() == password_manager::ui::INACTIVE_STATE)
return;
for (const password_manager::PasswordStoreChange& change : changes) {
const autofill::PasswordForm& changed_form = change.form();
if (changed_form.blacklisted_by_user)
continue;
if (change.type() == password_manager::PasswordStoreChange::REMOVE) {
DeleteForm(changed_form);
} else {
if (change.type() == password_manager::PasswordStoreChange::UPDATE)
UpdateForm(changed_form);
else
AddForm(changed_form);
}
}
}
void ManagePasswordsState::ClearData() {
form_manager_.reset();
current_forms_weak_.clear();
local_credentials_forms_.clear();
federated_credentials_forms_.clear();
credentials_callback_.Reset();
}
void ManagePasswordsState::AddForm(const autofill::PasswordForm& form) {
if (form.origin != origin_)
return;
if (UpdateForm(form))
return;
if (form_manager_) {
local_credentials_forms_.push_back(new autofill::PasswordForm(form));
current_forms_weak_.push_back(local_credentials_forms_.back());
} else {
local_credentials_forms_.push_back(new autofill::PasswordForm(form));
}
}
bool ManagePasswordsState::UpdateForm(const autofill::PasswordForm& form) {
if (form_manager_) {
// |current_forms_weak_| contains the list of current passwords.
std::vector<const autofill::PasswordForm*>::iterator it = std::find_if(
current_forms_weak_.begin(), current_forms_weak_.end(),
[&form](const autofill::PasswordForm* current_form) {
return ArePasswordFormUniqueKeyEqual(form, *current_form);
});
if (it != current_forms_weak_.end()) {
RemoveFormFromVector(form, &local_credentials_forms_);
local_credentials_forms_.push_back(new autofill::PasswordForm(form));
*it = local_credentials_forms_.back();
return true;
}
} else {
// |current_forms_weak_| isn't used.
bool updated_locals = UpdateFormInVector(form, &local_credentials_forms_);
return (UpdateFormInVector(form, &federated_credentials_forms_) ||
updated_locals);
}
return false;
}
void ManagePasswordsState::DeleteForm(const autofill::PasswordForm& form) {
RemoveFormFromVector(form, &current_forms_weak_);
RemoveFormFromVector(form, &local_credentials_forms_);
RemoveFormFromVector(form, &federated_credentials_forms_);
}
void ManagePasswordsState::SetState(password_manager::ui::State state) {
DCHECK(client_);
if (client_->IsLoggingActive()) {
password_manager::BrowserSavePasswordProgressLogger logger(client_);
logger.LogNumber(
autofill::SavePasswordProgressLogger::STRING_NEW_UI_STATE,
state);
}
state_ = state;
}