blob: c14d6e9781efcc68c63b5d65ed2b573dfe37d6c9 [file] [log] [blame]
// Copyright 2018 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/password_requirements_service.h"
#include "base/bind.h"
#include "base/logging.h"
#include "components/autofill/core/browser/password_requirements_spec_printer.h"
namespace {
constexpr size_t kCacheSizeForDomainKeyedSpecs = 200;
constexpr size_t kCacheSizeForSignatureKeyedSpecs = 500;
} // namespace
namespace password_manager {
PasswordRequirementsService::PasswordRequirementsService(
std::unique_ptr<autofill::PasswordRequirementsSpecFetcher> fetcher)
: specs_for_domains_(kCacheSizeForDomainKeyedSpecs),
specs_for_signatures_(kCacheSizeForSignatureKeyedSpecs),
fetcher_(std::move(fetcher)) {}
PasswordRequirementsService::~PasswordRequirementsService() = default;
autofill::PasswordRequirementsSpec PasswordRequirementsService::GetSpec(
const GURL& main_frame_domain,
autofill::FormSignature form_signature,
autofill::FieldSignature field_signature) {
autofill::PasswordRequirementsSpec result;
auto iter_by_signature = specs_for_signatures_.Get(
std::make_pair(form_signature, field_signature));
bool found_item_by_signature =
iter_by_signature != specs_for_signatures_.end();
if (found_item_by_signature) {
result = iter_by_signature->second;
}
auto iter_by_domain = specs_for_domains_.Get(main_frame_domain);
if (iter_by_domain != specs_for_domains_.end()) {
const autofill::PasswordRequirementsSpec& spec = iter_by_domain->second;
if (!found_item_by_signature) {
// If nothing was found by signature, |spec| can be adopted.
result = spec;
} else if (spec.has_priority() && (!result.has_priority() ||
spec.priority() > result.priority())) {
// If something was found by signature, override with |spec| only in case
// the priority of |spec| exceeds the priority of the data found by
// signature.
result = spec;
}
}
VLOG(1) << "PasswordRequirementsService::GetSpec(" << main_frame_domain
<< ", " << form_signature << ", " << field_signature
<< ") = " << result;
return result;
}
void PasswordRequirementsService::PrefetchSpec(const GURL& main_frame_domain) {
VLOG(1) << "PasswordRequirementsService::PrefetchSpec(" << main_frame_domain
<< ")";
if (!fetcher_) {
VLOG(1) << "PasswordRequirementsService::PrefetchSpec has no fetcher";
return;
}
// No need to fetch the same data multiple times.
if (specs_for_domains_.Get(main_frame_domain) != specs_for_domains_.end()) {
VLOG(1) << "PasswordRequirementsService::PrefetchSpec has an entry already";
return;
}
// Using base::Unretained(this) is safe here because the
// PasswordRequirementsService owns fetcher_. If |this| is deleted, so is
// the |fetcher_|, and no callback can happen.
fetcher_->Fetch(
main_frame_domain,
base::BindOnce(&PasswordRequirementsService::OnFetchedRequirements,
base::Unretained(this), main_frame_domain));
}
void PasswordRequirementsService::OnFetchedRequirements(
const GURL& main_frame_domain,
const autofill::PasswordRequirementsSpec& spec) {
VLOG(1) << "PasswordRequirementsService::OnFetchedRequirements("
<< main_frame_domain << ", " << spec << ")";
specs_for_domains_.Put(main_frame_domain, spec);
}
void PasswordRequirementsService::AddSpec(
autofill::FormSignature form_signature,
autofill::FieldSignature field_signature,
const autofill::PasswordRequirementsSpec& spec) {
VLOG(1) << "PasswordRequirementsService::AddSpec(" << form_signature << ", "
<< field_signature << ", " << spec << ")";
specs_for_signatures_.Put(std::make_pair(form_signature, field_signature),
spec);
}
void PasswordRequirementsService::ClearDataForTestingImpl() {
specs_for_domains_.Clear();
specs_for_signatures_.Clear();
}
} // namespace password_manager