diff options
Diffstat (limited to 'chromium/chrome/browser/signin/dice_signed_in_profile_creator.cc')
-rw-r--r-- | chromium/chrome/browser/signin/dice_signed_in_profile_creator.cc | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/chromium/chrome/browser/signin/dice_signed_in_profile_creator.cc b/chromium/chrome/browser/signin/dice_signed_in_profile_creator.cc new file mode 100644 index 00000000000..494a17b4695 --- /dev/null +++ b/chromium/chrome/browser/signin/dice_signed_in_profile_creator.cc @@ -0,0 +1,211 @@ +// 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/signin/dice_signed_in_profile_creator.h" + +#include <string> + +#include "base/check.h" +#include "base/location.h" +#include "base/memory/ptr_util.h" +#include "base/memory/raw_ptr.h" +#include "base/scoped_observation.h" +#include "base/threading/thread_task_runner_handle.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/profiles/profile_attributes_storage.h" +#include "chrome/browser/profiles/profile_avatar_icon_util.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/signin/identity_manager_factory.h" +#include "components/signin/public/identity_manager/accounts_mutator.h" +#include "components/signin/public/identity_manager/identity_manager.h" + +// Waits until the tokens are loaded and calls the callback. The callback is +// called immediately if the tokens are already loaded, and called with nullptr +// if the profile is destroyed before the tokens are loaded. +class TokensLoadedCallbackRunner : public signin::IdentityManager::Observer { + public: + ~TokensLoadedCallbackRunner() override = default; + TokensLoadedCallbackRunner(const TokensLoadedCallbackRunner&) = delete; + TokensLoadedCallbackRunner& operator=(const TokensLoadedCallbackRunner&) = + delete; + + // Runs the callback when the tokens are loaded. If tokens are already loaded + // the callback is called synchronously and this returns nullptr. + static std::unique_ptr<TokensLoadedCallbackRunner> RunWhenLoaded( + Profile* profile, + base::OnceCallback<void(Profile*)> callback); + + private: + TokensLoadedCallbackRunner(Profile* profile, + base::OnceCallback<void(Profile*)> callback); + + // signin::IdentityManager::Observer implementation: + void OnRefreshTokensLoaded() override { + scoped_identity_manager_observer_.Reset(); + std::move(callback_).Run(profile_.get()); + } + + void OnIdentityManagerShutdown(signin::IdentityManager* manager) override { + scoped_identity_manager_observer_.Reset(); + std::move(callback_).Run(nullptr); + } + + raw_ptr<Profile> profile_; + raw_ptr<signin::IdentityManager> identity_manager_; + base::ScopedObservation<signin::IdentityManager, + signin::IdentityManager::Observer> + scoped_identity_manager_observer_{this}; + base::OnceCallback<void(Profile*)> callback_; +}; + +// static +std::unique_ptr<TokensLoadedCallbackRunner> +TokensLoadedCallbackRunner::RunWhenLoaded( + Profile* profile, + base::OnceCallback<void(Profile*)> callback) { + if (IdentityManagerFactory::GetForProfile(profile) + ->AreRefreshTokensLoaded()) { + std::move(callback).Run(profile); + return nullptr; + } + + return base::WrapUnique( + new TokensLoadedCallbackRunner(profile, std::move(callback))); +} + +TokensLoadedCallbackRunner::TokensLoadedCallbackRunner( + Profile* profile, + base::OnceCallback<void(Profile*)> callback) + : profile_(profile), + identity_manager_(IdentityManagerFactory::GetForProfile(profile)), + callback_(std::move(callback)) { + DCHECK(profile_); + DCHECK(identity_manager_); + DCHECK(callback_); + DCHECK(!identity_manager_->AreRefreshTokensLoaded()); + scoped_identity_manager_observer_.Observe(identity_manager_.get()); +} + +DiceSignedInProfileCreator::DiceSignedInProfileCreator( + Profile* source_profile, + CoreAccountId account_id, + const std::u16string& local_profile_name, + absl::optional<size_t> icon_index, + bool use_guest_profile, + base::OnceCallback<void(Profile*)> callback) + : source_profile_(source_profile), + account_id_(account_id), + callback_(std::move(callback)) { + // Passing the sign-in token to an ephemeral Guest profile is part of the + // experiment to surface a Guest mode link in the DiceWebSigninIntercept + // and is only used to sign in to the web through account consistency and + // does NOT enable sync or any other browser level functionality. + // TODO(https://crbug.com/1225171): Revise the comment after Guest mode plans + // are finalized. + if (use_guest_profile) { + // TODO(https://crbug.com/1225171): Re-enabled if ephemeral based Guest mode + // is added. Remove the code otherwise. + NOTREACHED(); + + // Make sure the callback is not called synchronously. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(&ProfileManager::CreateProfileAsync, + base::Unretained(g_browser_process->profile_manager()), + ProfileManager::GetGuestProfilePath(), + base::BindRepeating( + &DiceSignedInProfileCreator::OnNewProfileCreated, + weak_pointer_factory_.GetWeakPtr()))); + } else { + ProfileAttributesStorage& storage = + g_browser_process->profile_manager()->GetProfileAttributesStorage(); + if (!icon_index.has_value()) + icon_index = storage.ChooseAvatarIconIndexForNewProfile(); + std::u16string name = local_profile_name.empty() + ? storage.ChooseNameForNewProfile(*icon_index) + : local_profile_name; + ProfileManager::CreateMultiProfileAsync( + name, *icon_index, /*is_hidden=*/false, + base::BindRepeating(&DiceSignedInProfileCreator::OnNewProfileCreated, + weak_pointer_factory_.GetWeakPtr())); + } +} + +DiceSignedInProfileCreator::DiceSignedInProfileCreator( + Profile* source_profile, + CoreAccountId account_id, + const base::FilePath& target_profile_path, + base::OnceCallback<void(Profile*)> callback) + : source_profile_(source_profile), + account_id_(account_id), + callback_(std::move(callback)) { + // Make sure the callback is not called synchronously. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce( + base::IgnoreResult(&ProfileManager::LoadProfileByPath), + base::Unretained(g_browser_process->profile_manager()), + target_profile_path, /*incognito=*/false, + base::BindOnce(&DiceSignedInProfileCreator::OnNewProfileInitialized, + weak_pointer_factory_.GetWeakPtr()))); +} + +DiceSignedInProfileCreator::~DiceSignedInProfileCreator() = default; + +void DiceSignedInProfileCreator::OnNewProfileCreated( + Profile* new_profile, + Profile::CreateStatus status) { + switch (status) { + case Profile::CREATE_STATUS_CREATED: + // Ignore this, wait for profile to be initialized. + return; + case Profile::CREATE_STATUS_INITIALIZED: + OnNewProfileInitialized(new_profile); + return; + case Profile::CREATE_STATUS_LOCAL_FAIL: + NOTREACHED() << "Error creating new profile"; + if (callback_) + std::move(callback_).Run(nullptr); + return; + } +} + +void DiceSignedInProfileCreator::OnNewProfileInitialized(Profile* new_profile) { + if (!new_profile) { + if (callback_) + std::move(callback_).Run(nullptr); + return; + } + + DCHECK(!tokens_loaded_callback_runner_); + // base::Unretained is fine because the runner is owned by this. + auto tokens_loaded_callback_runner = + TokensLoadedCallbackRunner::RunWhenLoaded( + new_profile, + base::BindOnce(&DiceSignedInProfileCreator::OnNewProfileTokensLoaded, + base::Unretained(this))); + // If the callback was called synchronously, |this| may have been deleted. + if (tokens_loaded_callback_runner) { + tokens_loaded_callback_runner_ = std::move(tokens_loaded_callback_runner); + } +} + +void DiceSignedInProfileCreator::OnNewProfileTokensLoaded( + Profile* new_profile) { + tokens_loaded_callback_runner_.reset(); + if (!new_profile) { + if (callback_) + std::move(callback_).Run(nullptr); + return; + } + + auto* accounts_mutator = + IdentityManagerFactory::GetForProfile(source_profile_) + ->GetAccountsMutator(); + auto* new_profile_accounts_mutator = + IdentityManagerFactory::GetForProfile(new_profile)->GetAccountsMutator(); + accounts_mutator->MoveAccount(new_profile_accounts_mutator, account_id_); + if (callback_) + std::move(callback_).Run(new_profile); +} |