blob: ddb7e31e5042d0cf844b05c294fd09164885c2df [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_API_H_
#define CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_API_H_
#include <optional>
#include <string>
#include <utility>
#include "base/callback_list.h"
#include "base/containers/flat_set.h"
#include "base/feature_list.h"
#include "base/functional/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "build/build_config.h"
#include "build/buildflag.h"
#include "chrome/browser/extensions/api/identity/identity_get_accounts_function.h"
#include "chrome/browser/extensions/api/identity/identity_get_profile_user_info_function.h"
#include "chrome/browser/extensions/api/identity/identity_mint_queue.h"
#include "chrome/browser/extensions/api/identity/identity_token_cache.h"
#include "components/signin/public/base/signin_buildflags.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/event_router.h"
#include "google_apis/gaia/gaia_id.h"
#if BUILDFLAG(IS_ANDROID)
#include "chrome/browser/extensions/api/identity/identity_unimplemented_functions_android.h"
#else
#include "chrome/browser/extensions/api/identity/identity_clear_all_cached_auth_tokens_function.h"
#include "chrome/browser/extensions/api/identity/identity_get_auth_token_function.h"
#include "chrome/browser/extensions/api/identity/identity_launch_web_auth_flow_function.h"
#include "chrome/browser/extensions/api/identity/identity_remove_cached_auth_token_function.h"
#endif
namespace content {
class BrowserContext;
}
class Profile;
namespace extensions {
class IdentityAPI : public BrowserContextKeyedAPI,
public signin::IdentityManager::Observer {
public:
explicit IdentityAPI(content::BrowserContext* context);
~IdentityAPI() override;
// Request serialization queue for getAuthToken.
IdentityMintRequestQueue* mint_queue();
IdentityTokenCache* token_cache();
// GAIA id cache.
void SetGaiaIdForExtension(const std::string& extension_id,
const GaiaId& gaia_id);
// Returns |std::nullopt| if no GAIA id is saved for `extension_id`.
// Otherwise, returns GAIA id previously saved via SetGaiaIdForExtension().
std::optional<GaiaId> GetGaiaIdForExtension(const std::string& extension_id);
void EraseGaiaIdForExtension(const std::string& extension_id);
// If refresh tokens have been loaded, erases GAIA ids of accounts that are no
// longer signed in to Chrome for all extensions.
void EraseStaleGaiaIdsForAllExtensions();
// BrowserContextKeyedAPI:
void Shutdown() override;
static BrowserContextKeyedAPIFactory<IdentityAPI>* GetFactoryInstance();
base::CallbackListSubscription RegisterOnShutdownCallback(
base::OnceClosure cb);
// Callback that is used in testing contexts to test the implementation of
// the chrome.identity.onSignInChanged event. Note that the passed-in Event is
// valid only for the duration of the callback.
using OnSignInChangedCallback = base::RepeatingCallback<void(Event*)>;
void set_on_signin_changed_callback_for_testing(
const OnSignInChangedCallback& callback) {
on_signin_changed_callback_for_testing_ = callback;
}
// Whether the chrome.identity API should use all accounts or the primary
// account only.
bool AreExtensionsRestrictedToPrimaryAccount();
// Returns accounts that extension have access to.
// This returns empty if Chrome is not signed in. Otherwise, returns all
// accounts in the `identity_manager_`.
std::vector<CoreAccountInfo> GetAccountsWithRefreshTokensForExtensions();
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
// Shows the Chrome sign in dialog for extensions if:
// - The dialog is not already showing
// - The user is signed in on the web but not to Chrome
// `on_complete` is guaranteed to be called.
void MaybeShowChromeSigninDialog(
const std::u16string& extension_name_for_display,
base::OnceClosure on_complete);
// Callback to be called when the tests triggers showing UI.
// Should be used in unittests.
void SetSkipUIForTesting(
base::OnceCallback<void(base::OnceClosure)> callback) {
skip_ui_for_testing_callback_ = std::move(callback);
}
#endif
private:
friend class BrowserContextKeyedAPIFactory<IdentityAPI>;
friend class IdentityAPITest;
// BrowserContextKeyedAPI:
static const char* service_name() { return "IdentityAPI"; }
static const bool kServiceIsNULLWhileTesting = true;
// This constructor allows to mock keyed services in tests.
IdentityAPI(Profile* profile,
signin::IdentityManager* identity_manager,
ExtensionPrefs* extension_prefs,
EventRouter* event_router);
// Returns true if extensions have access to Chrome accounts.
// Access requires Chrome to be signed in.
bool HasAccessToChromeAccounts() const;
// signin::IdentityManager::Observer:
void OnPrimaryAccountChanged(
const signin::PrimaryAccountChangeEvent& event_details) override;
void OnRefreshTokensLoaded() override;
void OnRefreshTokenUpdatedForAccount(
const CoreAccountInfo& account_info) override;
// NOTE: This class must listen for this callback rather than
// OnRefreshTokenRemovedForAccount() to obtain the Gaia ID of the removed
// account.
void OnExtendedAccountInfoRemoved(const AccountInfo& info) override;
// Fires the chrome.identity.onSignInChanged event.
void FireOnAccountSignInChanged(const GaiaId& gaia_id, bool is_signed_in);
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
void OnChromeSigninDialogDestroyed();
void HandleSkipUIForTesting(base::OnceClosure on_complete);
#endif
const raw_ptr<Profile> profile_;
const raw_ptr<signin::IdentityManager> identity_manager_;
const raw_ptr<ExtensionPrefs> extension_prefs_;
const raw_ptr<EventRouter> event_router_;
IdentityMintRequestQueue mint_queue_;
IdentityTokenCache token_cache_;
// Contains Gaia Id of accounts known to extensions.
base::flat_set<GaiaId> accounts_known_to_extensions_;
OnSignInChangedCallback on_signin_changed_callback_for_testing_;
base::OnceCallbackList<void()> on_shutdown_callback_list_;
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
bool is_chrome_signin_dialog_open_ = false;
std::vector<base::OnceClosure> on_chrome_signin_dialog_completed_;
// Should only be set in unittests.
base::OnceCallback<void(base::OnceClosure)> skip_ui_for_testing_callback_;
base::WeakPtrFactory<IdentityAPI> weak_ptr_factory_{this};
#endif
};
template <>
void BrowserContextKeyedAPIFactory<IdentityAPI>::DeclareFactoryDependencies();
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_API_H_