blob: 7252db00a5eb8a88b47e63fa7d61c5203e335fb4 [file] [log] [blame]
// Copyright 2016 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 "components/password_manager/core/browser/form_saver_impl.h"
#include <memory>
#include <vector>
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "components/password_manager/core/browser/password_store.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/gaia_urls.h"
#include "url/gurl.h"
#include "url/origin.h"
using autofill::FormData;
using autofill::FormFieldData;
using autofill::PasswordForm;
namespace password_manager {
namespace {
// Remove all information from |form| that is not required for signature
// calculation.
void SanitizeFormData(FormData* form) {
form->main_frame_origin = url::Origin();
for (FormFieldData& field : form->fields) {
field.label.clear();
field.value.clear();
field.autocomplete_attribute.clear();
field.option_values.clear();
field.option_contents.clear();
field.placeholder.clear();
field.css_classes.clear();
field.id_attribute.clear();
field.name_attribute.clear();
}
}
} // namespace
FormSaverImpl::FormSaverImpl(PasswordStore* store) : store_(store) {
DCHECK(store);
}
FormSaverImpl::~FormSaverImpl() = default;
void FormSaverImpl::PermanentlyBlacklist(PasswordForm* observed) {
observed->preferred = false;
observed->blacklisted_by_user = true;
observed->username_value.clear();
observed->password_value.clear();
observed->other_possible_usernames.clear();
observed->date_created = base::Time::Now();
store_->AddLogin(*observed);
}
void FormSaverImpl::Save(
const PasswordForm& pending,
const std::map<base::string16, const PasswordForm*>& best_matches) {
SaveImpl(pending, true, best_matches, nullptr, nullptr);
}
void FormSaverImpl::Update(
const PasswordForm& pending,
const std::map<base::string16, const PasswordForm*>& best_matches,
const std::vector<PasswordForm>* credentials_to_update,
const PasswordForm* old_primary_key) {
SaveImpl(pending, false, best_matches, credentials_to_update,
old_primary_key);
}
void FormSaverImpl::PresaveGeneratedPassword(const PasswordForm& generated) {
auto form = std::make_unique<PasswordForm>(generated);
SanitizeFormData(&form->form_data);
if (presaved_)
store_->UpdateLoginWithPrimaryKey(*form, *presaved_);
else
store_->AddLogin(*form);
presaved_ = std::move(form);
}
void FormSaverImpl::RemovePresavedPassword() {
if (!presaved_)
return;
store_->RemoveLogin(*presaved_);
presaved_ = nullptr;
}
std::unique_ptr<FormSaver> FormSaverImpl::Clone() {
auto result = std::make_unique<FormSaverImpl>(store_);
if (presaved_)
result->presaved_ = std::make_unique<PasswordForm>(*presaved_);
return result;
}
void FormSaverImpl::SaveImpl(
const PasswordForm& pending,
bool is_new_login,
const std::map<base::string16, const PasswordForm*>& best_matches,
const std::vector<PasswordForm>* credentials_to_update,
const PasswordForm* old_primary_key) {
DCHECK(pending.preferred);
DCHECK(!pending.blacklisted_by_user);
UpdatePreferredLoginState(pending.username_value, best_matches);
PasswordForm sanitized_pending(pending);
SanitizeFormData(&sanitized_pending.form_data);
if (presaved_) {
store_->UpdateLoginWithPrimaryKey(sanitized_pending, *presaved_);
presaved_ = nullptr;
} else if (is_new_login) {
store_->AddLogin(sanitized_pending);
if (!sanitized_pending.username_value.empty())
DeleteEmptyUsernameCredentials(sanitized_pending, best_matches);
} else {
if (old_primary_key)
store_->UpdateLoginWithPrimaryKey(sanitized_pending, *old_primary_key);
else
store_->UpdateLogin(sanitized_pending);
}
if (credentials_to_update) {
for (const PasswordForm& credential : *credentials_to_update) {
store_->UpdateLogin(credential);
}
}
}
void FormSaverImpl::UpdatePreferredLoginState(
const base::string16& preferred_username,
const std::map<base::string16, const PasswordForm*>& best_matches) {
for (const auto& key_value_pair : best_matches) {
const PasswordForm& form = *key_value_pair.second;
if (form.preferred && !form.is_public_suffix_match &&
form.username_value != preferred_username) {
// This wasn't the selected login but it used to be preferred.
PasswordForm update(form);
SanitizeFormData(&update.form_data);
update.preferred = false;
store_->UpdateLogin(update);
}
}
}
void FormSaverImpl::DeleteEmptyUsernameCredentials(
const PasswordForm& pending,
const std::map<base::string16, const PasswordForm*>& best_matches) {
DCHECK(!pending.username_value.empty());
for (const auto& match : best_matches) {
const PasswordForm* form = match.second;
if (!form->is_public_suffix_match && form->username_value.empty() &&
form->password_value == pending.password_value) {
store_->RemoveLogin(*form);
}
}
}
} // namespace password_manager