blob: 2a51be060e021bdfa40c7f7366948e5f126c0a27 [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 "chrome/browser/media/kaleidoscope/kaleidoscope_identity_manager_impl.h"
#include "base/callback.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/media/kaleidoscope/kaleidoscope_prefs.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/common/channel_info.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/base/signin_metrics.h"
#include "components/signin/public/identity_manager/access_token_info.h"
#include "components/signin/public/identity_manager/consent_level.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/signin/public/identity_manager/primary_account_access_token_fetcher.h"
#include "components/version_info/version_info.h"
#include "content/public/browser/web_ui.h"
#include "google_apis/google_api_keys.h"
namespace {
constexpr char kChromeMediaRecommendationsOAuth2Scope[] =
"https://www.googleapis.com/auth/chrome-media-recommendations";
} // namespace
KaleidoscopeIdentityManagerImpl::KaleidoscopeIdentityManagerImpl(
mojo::PendingReceiver<media::mojom::KaleidoscopeIdentityManager> receiver,
content::WebUI* web_ui)
: KaleidoscopeIdentityManagerImpl(std::move(receiver),
Profile::FromWebUI(web_ui)) {
DCHECK(web_ui);
web_ui_ = web_ui;
}
KaleidoscopeIdentityManagerImpl::KaleidoscopeIdentityManagerImpl(
mojo::PendingReceiver<media::mojom::KaleidoscopeIdentityManager> receiver,
Profile* profile)
: credentials_(media::mojom::Credentials::New()),
profile_(profile),
receiver_(this, std::move(receiver)) {
DCHECK(profile);
// If this is Google Chrome then we should use the official API key.
if (google_apis::IsGoogleChromeAPIKeyUsed()) {
bool is_stable_channel =
chrome::GetChannel() == version_info::Channel::STABLE;
credentials_->api_key = is_stable_channel
? google_apis::GetAPIKey()
: google_apis::GetNonStableAPIKey();
}
identity_manager_ = IdentityManagerFactory::GetForProfile(profile);
identity_manager_->AddObserver(this);
}
KaleidoscopeIdentityManagerImpl::~KaleidoscopeIdentityManagerImpl() {
identity_manager_->RemoveObserver(this);
}
void KaleidoscopeIdentityManagerImpl::GetCredentials(
GetCredentialsCallback cb) {
// If the profile is incognito then disable Kaleidoscope.
if (profile_->IsOffTheRecord()) {
std::move(cb).Run(nullptr,
media::mojom::CredentialsResult::kFailedIncognito);
return;
}
// If the profile is a child then disable Kaleidoscope.
if (profile_->IsSupervised() || profile_->IsChild()) {
std::move(cb).Run(nullptr, media::mojom::CredentialsResult::kFailedChild);
return;
}
// If the administrator has disabled Kaleidoscope then stop.
auto* prefs = profile_->GetPrefs();
if (!prefs->GetBoolean(kaleidoscope::prefs::kKaleidoscopePolicyEnabled)) {
std::move(cb).Run(nullptr,
media::mojom::CredentialsResult::kDisabledByPolicy);
return;
}
// If the user is not signed in, return the credentials without an access
// token. Sync consent is not required to use Kaleidoscope.
if (!identity_manager_->HasPrimaryAccount(
signin::ConsentLevel::kNotRequired)) {
std::move(cb).Run(credentials_.Clone(),
media::mojom::CredentialsResult::kSuccess);
return;
}
pending_callbacks_.push_back(std::move(cb));
// Get an OAuth token for the backend API. This token will be limited to just
// our backend scope. Destroying |token_fetcher_| will cancel the fetch so
// unretained is safe here.
signin::ScopeSet scopes = {kChromeMediaRecommendationsOAuth2Scope};
token_fetcher_ = std::make_unique<signin::PrimaryAccountAccessTokenFetcher>(
"kaleidoscope_service", identity_manager_, scopes,
base::BindOnce(&KaleidoscopeIdentityManagerImpl::OnAccessTokenAvailable,
base::Unretained(this)),
signin::PrimaryAccountAccessTokenFetcher::Mode::kImmediate,
signin::ConsentLevel::kNotRequired);
}
void KaleidoscopeIdentityManagerImpl::OnAccessTokenAvailable(
GoogleServiceAuthError error,
signin::AccessTokenInfo access_token_info) {
DCHECK(token_fetcher_);
token_fetcher_.reset();
if (error.state() == GoogleServiceAuthError::State::NONE) {
credentials_->access_token = access_token_info.token;
credentials_->expiry_time = access_token_info.expiration_time;
}
for (auto& callback : pending_callbacks_) {
std::move(callback).Run(credentials_.Clone(),
media::mojom::CredentialsResult::kSuccess);
}
pending_callbacks_.clear();
}
void KaleidoscopeIdentityManagerImpl::SignIn() {
#if BUILDFLAG(IS_CHROMEOS_ASH)
NOTREACHED() << "SignIn() shouldn't be called on Chrome OS.";
#else
// The identity manager may not be created in a context where it has access
// to the UI. The client should not request a sign-in in that case.
DCHECK(web_ui_);
content::WebContents* web_contents = web_ui_->GetWebContents();
DCHECK(web_contents);
Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
DCHECK(browser);
chrome::ShowBrowserSignin(
browser, signin_metrics::AccessPoint::ACCESS_POINT_KALEIDOSCOPE,
signin::ConsentLevel::kNotRequired);
signin_metrics::RecordSigninImpressionUserActionForAccessPoint(
signin_metrics::AccessPoint::ACCESS_POINT_KALEIDOSCOPE);
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
void KaleidoscopeIdentityManagerImpl::AddObserver(
mojo::PendingRemote<media::mojom::KaleidoscopeIdentityObserver> observer) {
identity_observers_.Add(std::move(observer));
}
void KaleidoscopeIdentityManagerImpl::OnRefreshTokenUpdatedForAccount(
const CoreAccountInfo& account_info) {
for (auto& observer : identity_observers_)
observer->OnSignedIn();
}
void KaleidoscopeIdentityManagerImpl::OnRefreshTokenRemovedForAccount(
const CoreAccountId& account_id) {
for (auto& observer : identity_observers_)
observer->OnSignedOut();
}