blob: d17593308a6f882d948cb6d006855a418b990106 [file] [log] [blame]
// Copyright 2020 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/account_manager_core/chromeos/account_manager_mojo_service.h"
#include <algorithm>
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/callback_forward.h"
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/notreached.h"
#include "chromeos/crosapi/mojom/account_manager.mojom.h"
#include "components/account_manager_core/account.h"
#include "components/account_manager_core/account_addition_result.h"
#include "components/account_manager_core/account_manager_util.h"
#include "components/account_manager_core/chromeos/access_token_fetcher.h"
#include "components/account_manager_core/chromeos/account_manager.h"
#include "components/account_manager_core/chromeos/account_manager_ui.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace crosapi {
namespace {
void MarshalAccounts(
mojom::AccountManager::GetAccountsCallback callback,
const std::vector<account_manager::Account>& accounts_to_marshal) {
std::vector<mojom::AccountPtr> mojo_accounts;
for (const account_manager::Account& account : accounts_to_marshal) {
mojo_accounts.emplace_back(account_manager::ToMojoAccount(account));
}
std::move(callback).Run(std::move(mojo_accounts));
}
void ReportErrorStatusFromHasDummyGaiaToken(
base::OnceCallback<void(mojom::GoogleServiceAuthErrorPtr)> callback,
bool has_dummy_token) {
GoogleServiceAuthError error(GoogleServiceAuthError::AuthErrorNone());
if (has_dummy_token) {
error = GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
GoogleServiceAuthError::InvalidGaiaCredentialsReason::
CREDENTIALS_REJECTED_BY_CLIENT);
}
std::move(callback).Run(account_manager::ToMojoGoogleServiceAuthError(error));
}
#if DCHECK_IS_ON()
void VerifyThatAccountExists(
const account_manager::AccountKey& account_key,
const std::vector<account_manager::Account>& known_accounts) {
bool account_exists = false;
for (const account_manager::Account& known_account : known_accounts) {
if (known_account.key == account_key) {
account_exists = true;
break;
}
}
DCHECK(account_exists);
}
#endif // DCHECK_IS_ON()
} // namespace
AccountManagerMojoService::AccountManagerMojoService(
account_manager::AccountManager* account_manager)
: account_manager_(account_manager) {
DCHECK(account_manager_);
account_manager_->AddObserver(this);
}
AccountManagerMojoService::~AccountManagerMojoService() {
account_manager_->RemoveObserver(this);
}
void AccountManagerMojoService::BindReceiver(
mojo::PendingReceiver<mojom::AccountManager> receiver) {
receivers_.Add(this, std::move(receiver));
}
void AccountManagerMojoService::SetAccountManagerUI(
std::unique_ptr<account_manager::AccountManagerUI> account_manager_ui) {
account_manager_ui_ = std::move(account_manager_ui);
}
void AccountManagerMojoService::OnAccountAdditionFinishedForTesting(
const account_manager::AccountAdditionResult& result) {
OnAccountAdditionFinished(result);
}
void AccountManagerMojoService::IsInitialized(IsInitializedCallback callback) {
std::move(callback).Run(account_manager_->IsInitialized());
}
void AccountManagerMojoService::AddObserver(AddObserverCallback callback) {
mojo::Remote<mojom::AccountManagerObserver> remote;
auto receiver = remote.BindNewPipeAndPassReceiver();
observers_.Add(std::move(remote));
std::move(callback).Run(std::move(receiver));
}
void AccountManagerMojoService::GetAccounts(
mojom::AccountManager::GetAccountsCallback callback) {
account_manager_->GetAccounts(
base::BindOnce(&MarshalAccounts, std::move(callback)));
}
void AccountManagerMojoService::GetPersistentErrorForAccount(
mojom::AccountKeyPtr mojo_account_key,
mojom::AccountManager::GetPersistentErrorForAccountCallback callback) {
absl::optional<account_manager::AccountKey> maybe_account_key =
account_manager::FromMojoAccountKey(mojo_account_key);
DCHECK(maybe_account_key)
<< "Can't unmarshal account of type: " << mojo_account_key->account_type;
account_manager_->HasDummyGaiaToken(
maybe_account_key.value(),
base::BindOnce(&ReportErrorStatusFromHasDummyGaiaToken,
std::move(callback)));
}
void AccountManagerMojoService::ShowAddAccountDialog(
crosapi::mojom::AccountAdditionOptionsPtr options,
ShowAddAccountDialogCallback callback) {
DCHECK(account_manager_ui_);
if (account_manager_ui_->IsDialogShown()) {
std::move(callback).Run(ToMojoAccountAdditionResult(
account_manager::AccountAdditionResult::FromStatus(
account_manager::AccountAdditionResult::Status::
kAlreadyInProgress)));
return;
}
DCHECK(!account_addition_in_progress_);
account_addition_in_progress_ = true;
account_addition_callback_ = std::move(callback);
auto maybe_options = account_manager::FromMojoAccountAdditionOptions(options);
account_manager_ui_->ShowAddAccountDialog(
maybe_options.value_or(account_manager::AccountAdditionOptions{}),
base::BindOnce(&AccountManagerMojoService::OnAddAccountDialogClosed,
weak_ptr_factory_.GetWeakPtr()));
}
void AccountManagerMojoService::ShowReauthAccountDialog(
const std::string& email,
base::OnceClosure closure) {
DCHECK(account_manager_ui_);
if (account_manager_ui_->IsDialogShown())
return;
account_manager_ui_->ShowReauthAccountDialog(email, std::move(closure));
}
void AccountManagerMojoService::ShowManageAccountsSettings() {
account_manager_ui_->ShowManageAccountsSettings();
}
void AccountManagerMojoService::CreateAccessTokenFetcher(
mojom::AccountKeyPtr mojo_account_key,
const std::string& oauth_consumer_name,
CreateAccessTokenFetcherCallback callback) {
// TODO(https://crbug.com/1175741): Add metrics.
VLOG(1) << "Received a request for access token from: "
<< oauth_consumer_name;
mojo::PendingRemote<mojom::AccessTokenFetcher> pending_remote;
auto access_token_fetcher = std::make_unique<AccessTokenFetcher>(
account_manager_, std::move(mojo_account_key), oauth_consumer_name,
/*done_closure=*/
base::BindOnce(
&AccountManagerMojoService::DeletePendingAccessTokenFetchRequest,
weak_ptr_factory_.GetWeakPtr()),
/*receiver=*/pending_remote.InitWithNewPipeAndPassReceiver());
pending_access_token_requests_.emplace_back(std::move(access_token_fetcher));
std::move(callback).Run(std::move(pending_remote));
}
void AccountManagerMojoService::ReportAuthError(
mojom::AccountKeyPtr mojo_account_key,
mojom::GoogleServiceAuthErrorPtr error) {
absl::optional<account_manager::AccountKey> maybe_account_key =
account_manager::FromMojoAccountKey(mojo_account_key);
DCHECK(maybe_account_key)
<< "Can't unmarshal account of type: " << mojo_account_key->account_type;
#if DCHECK_IS_ON()
// Verify that `maybe_account_key` is known to Account Manager.
account_manager_->GetAccounts(
base::BindOnce(&VerifyThatAccountExists, maybe_account_key.value()));
#endif // DCHECK_IS_ON()
for (auto& observer : observers_)
observer->OnAuthErrorChanged(mojo_account_key.Clone(), error.Clone());
}
void AccountManagerMojoService::OnTokenUpserted(
const account_manager::Account& account) {
for (auto& observer : observers_)
observer->OnTokenUpserted(ToMojoAccount(account));
}
void AccountManagerMojoService::OnAccountRemoved(
const account_manager::Account& account) {
for (auto& observer : observers_)
observer->OnAccountRemoved(ToMojoAccount(account));
}
void AccountManagerMojoService::OnAccountAdditionFinished(
const account_manager::AccountAdditionResult& result) {
if (!account_addition_in_progress_)
return;
FinishAddAccount(result);
}
void AccountManagerMojoService::OnAddAccountDialogClosed() {
if (!account_addition_in_progress_)
return;
// Account addition is still in progress. It means that user didn't complete
// the account addition flow and closed the dialog.
FinishAddAccount(account_manager::AccountAdditionResult::FromStatus(
account_manager::AccountAdditionResult::Status::kCancelledByUser));
}
void AccountManagerMojoService::FinishAddAccount(
const account_manager::AccountAdditionResult& result) {
account_addition_in_progress_ = false;
DCHECK(!account_addition_callback_.is_null());
std::move(account_addition_callback_)
.Run(ToMojoAccountAdditionResult(result));
}
void AccountManagerMojoService::DeletePendingAccessTokenFetchRequest(
AccessTokenFetcher* request) {
pending_access_token_requests_.erase(
std::remove_if(
pending_access_token_requests_.begin(),
pending_access_token_requests_.end(),
[&request](const std::unique_ptr<AccessTokenFetcher>& pending_request)
-> bool { return pending_request.get() == request; }),
pending_access_token_requests_.end());
}
void AccountManagerMojoService::FlushMojoForTesting() {
observers_.FlushForTesting();
}
int AccountManagerMojoService::GetNumPendingAccessTokenRequests() const {
return pending_access_token_requests_.size();
}
} // namespace crosapi