blob: 46a5089494815ccb1c0ee593fdfb3ddc350ed002 [file] [log] [blame]
// Copyright 2019 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/autofill_assistant/browser/website_login_fetcher_impl.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "components/password_manager/core/browser/form_fetcher_impl.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
namespace autofill_assistant {
// Represents a pending form fetcher request which will notify the
// |WebsiteLoginFetcherImpl| when finished.
class WebsiteLoginFetcherImpl::PendingRequest
: public password_manager::FormFetcher::Consumer {
public:
PendingRequest(
const password_manager::PasswordStore::FormDigest& form_digest,
const password_manager::PasswordManagerClient* client,
base::OnceCallback<void(const PendingRequest*)> notify_finished_callback)
: form_fetcher_(
std::make_unique<password_manager::FormFetcherImpl>(form_digest,
client,
true)),
notify_finished_callback_(std::move(notify_finished_callback)),
weak_ptr_factory_(this) {}
~PendingRequest() override = default;
void Start() {
// Note: Currently, |FormFetcherImpl| has the default state NOT_WAITING.
// This has the unfortunate side effect that new consumers are immediately
// notified with an empty result. As a workaround to avoid this first
// notification, we register as consumer *after* we call |Fetch|.
form_fetcher_->Fetch();
form_fetcher_->AddConsumer(this);
}
protected:
// From password_manager::FormFetcher::Consumer:
// This implementation should be called by subclasses when they are finished.
void OnFetchCompleted() override {
// This needs to be done asynchronously, because it will lead to the
// destruction of |this|, which needs to happen *after* this call has
// returned.
base::PostTask(FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(&PendingRequest::NotifyFinished,
weak_ptr_factory_.GetWeakPtr()));
}
std::unique_ptr<password_manager::FormFetcher> form_fetcher_;
private:
void NotifyFinished() { std::move(notify_finished_callback_).Run(this); }
base::OnceCallback<void(const PendingRequest*)> notify_finished_callback_;
base::WeakPtrFactory<PendingRequest> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(PendingRequest);
};
// A pending request to fetch all logins that match the specified |form_digest|.
class WebsiteLoginFetcherImpl::PendingFetchLoginsRequest
: public WebsiteLoginFetcherImpl::PendingRequest {
public:
PendingFetchLoginsRequest(
const password_manager::PasswordStore::FormDigest& form_digest,
const password_manager::PasswordManagerClient* client,
base::OnceCallback<void(std::vector<Login>)> callback,
base::OnceCallback<void(const PendingRequest*)> notify_finished_callback)
: PendingRequest(form_digest,
client,
std::move(notify_finished_callback)),
callback_(std::move(callback)) {}
protected:
// From PendingRequest:
void OnFetchCompleted() override {
std::vector<Login> logins;
for (const auto& match : form_fetcher_->GetBestMatches()) {
logins.emplace_back(match.second->origin,
base::UTF16ToUTF8(match.second->username_value));
}
std::move(callback_).Run(logins);
PendingRequest::OnFetchCompleted();
}
private:
base::OnceCallback<void(std::vector<Login>)> callback_;
};
// A pending request to fetch the password for the specified |login|.
class WebsiteLoginFetcherImpl::PendingFetchPasswordRequest
: public WebsiteLoginFetcherImpl::PendingRequest {
public:
PendingFetchPasswordRequest(
const password_manager::PasswordStore::FormDigest& form_digest,
const password_manager::PasswordManagerClient* client,
const Login& login,
base::OnceCallback<void(bool, std::string)> callback,
base::OnceCallback<void(const PendingRequest*)> notify_finished_callback)
: PendingRequest(form_digest,
client,
std::move(notify_finished_callback)),
login_(login),
callback_(std::move(callback)) {}
protected:
// From PendingRequest:
void OnFetchCompleted() override {
std::vector<const autofill::PasswordForm*> matches =
form_fetcher_->GetNonFederatedMatches();
for (const auto* match : matches) {
if (base::UTF16ToUTF8(match->username_value) == login_.username) {
std::move(callback_).Run(true,
base::UTF16ToUTF8(match->password_value));
PendingRequest::OnFetchCompleted();
return;
}
}
std::move(callback_).Run(false, std::string());
PendingRequest::OnFetchCompleted();
}
private:
Login login_;
base::OnceCallback<void(bool, std::string)> callback_;
};
WebsiteLoginFetcherImpl::WebsiteLoginFetcherImpl(
const password_manager::PasswordManagerClient* client)
: client_(client), weak_ptr_factory_(this) {}
WebsiteLoginFetcherImpl::~WebsiteLoginFetcherImpl() = default;
void WebsiteLoginFetcherImpl::GetLoginsForUrl(
const GURL& url,
base::OnceCallback<void(std::vector<Login>)> callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
password_manager::PasswordStore::FormDigest digest(
autofill::PasswordForm::Scheme::kHtml, url.GetOrigin().spec(), GURL());
pending_requests_.emplace_back(std::make_unique<PendingFetchLoginsRequest>(
digest, client_, std::move(callback),
base::BindOnce(&WebsiteLoginFetcherImpl::OnRequestFinished,
weak_ptr_factory_.GetWeakPtr())));
pending_requests_.back()->Start();
}
void WebsiteLoginFetcherImpl::GetPasswordForLogin(
const Login& login,
base::OnceCallback<void(bool, std::string)> callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
password_manager::PasswordStore::FormDigest digest(
autofill::PasswordForm::Scheme::kHtml, login.origin.spec(), GURL());
pending_requests_.emplace_back(std::make_unique<PendingFetchPasswordRequest>(
digest, client_, login, std::move(callback),
base::BindOnce(&WebsiteLoginFetcherImpl::OnRequestFinished,
weak_ptr_factory_.GetWeakPtr())));
pending_requests_.back()->Start();
}
void WebsiteLoginFetcherImpl::OnRequestFinished(const PendingRequest* request) {
base::EraseIf(pending_requests_, [request](const auto& candidate_request) {
return candidate_request.get() == request;
});
}
} // namespace autofill_assistant