| // Copyright (c) 2013 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/signin_ui_util.h" |
| |
| #include "base/bind_helpers.h" |
| #include "base/callback.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/sys_string_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/signin/account_tracker_service_factory.h" |
| #include "chrome/browser/signin/gaia_cookie_manager_service_factory.h" |
| #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" |
| #include "chrome/browser/signin/signin_error_controller_factory.h" |
| #include "chrome/browser/signin/signin_global_error.h" |
| #include "chrome/browser/signin/signin_global_error_factory.h" |
| #include "chrome/browser/signin/signin_manager_factory.h" |
| #include "chrome/browser/sync/profile_sync_service_factory.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_navigator.h" |
| #include "chrome/browser/ui/browser_navigator_params.h" |
| #include "chrome/browser/ui/chrome_pages.h" |
| #include "chrome/common/pref_names.h" |
| #include "components/browser_sync/profile_sync_service.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/signin/core/browser/account_consistency_method.h" |
| #include "components/signin/core/browser/account_tracker_service.h" |
| #include "components/signin/core/browser/gaia_cookie_manager_service.h" |
| #include "components/signin/core/browser/profile_oauth2_token_service.h" |
| #include "components/signin/core/browser/signin_manager.h" |
| #include "components/user_manager/user_manager.h" |
| #include "third_party/re2/src/re2/re2.h" |
| #include "ui/gfx/font_list.h" |
| #include "ui/gfx/text_elider.h" |
| |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) |
| #include "chrome/browser/signin/account_consistency_mode_manager.h" |
| #include "chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h" |
| #endif |
| |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) |
| namespace { |
| void CreateDiceTurnSyncOnHelper( |
| Profile* profile, |
| Browser* browser, |
| signin_metrics::AccessPoint signin_access_point, |
| signin_metrics::PromoAction signin_promo_action, |
| signin_metrics::Reason signin_reason, |
| const std::string& account_id, |
| DiceTurnSyncOnHelper::SigninAbortedMode signin_aborted_mode) { |
| // DiceTurnSyncOnHelper is suicidal (it will delete itself once it finishes |
| // enabling sync). |
| new DiceTurnSyncOnHelper(profile, browser, signin_access_point, |
| signin_promo_action, signin_reason, account_id, |
| signin_aborted_mode); |
| } |
| } // namespace |
| #endif // BUILDFLAG(ENABLE_DICE_SUPPORT) |
| |
| namespace signin_ui_util { |
| |
| base::string16 GetAuthenticatedUsername(const SigninManagerBase* signin) { |
| std::string user_display_name; |
| |
| if (signin->IsAuthenticated()) { |
| user_display_name = signin->GetAuthenticatedAccountInfo().email; |
| |
| #if defined(OS_CHROMEOS) |
| if (user_manager::UserManager::IsInitialized()) { |
| // On CrOS user email is sanitized and then passed to the signin manager. |
| // Original email (containing dots) is stored as "display email". |
| user_display_name = user_manager::UserManager::Get()->GetUserDisplayEmail( |
| AccountId::FromUserEmail(user_display_name)); |
| } |
| #endif // defined(OS_CHROMEOS) |
| } |
| |
| return base::UTF8ToUTF16(user_display_name); |
| } |
| |
| void InitializePrefsForProfile(Profile* profile) { |
| if (profile->IsNewProfile()) { |
| // Suppresses the upgrade tutorial for a new profile. |
| profile->GetPrefs()->SetInteger(prefs::kProfileAvatarTutorialShown, |
| kUpgradeWelcomeTutorialShowMax + 1); |
| } |
| } |
| |
| void ShowSigninErrorLearnMorePage(Profile* profile) { |
| static const char kSigninErrorLearnMoreUrl[] = |
| "https://support.google.com/chrome/answer/1181420?"; |
| NavigateParams params(profile, GURL(kSigninErrorLearnMoreUrl), |
| ui::PAGE_TRANSITION_LINK); |
| params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB; |
| Navigate(¶ms); |
| } |
| |
| void EnableSyncFromPromo(Browser* browser, |
| const AccountInfo& account, |
| signin_metrics::AccessPoint access_point, |
| bool is_default_promo_account) { |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) |
| internal::EnableSyncFromPromo(browser, account, access_point, |
| is_default_promo_account, |
| base::BindOnce(&CreateDiceTurnSyncOnHelper)); |
| #else |
| internal::EnableSyncFromPromo(browser, account, access_point, |
| is_default_promo_account, base::DoNothing()); |
| #endif |
| } |
| |
| namespace internal { |
| void EnableSyncFromPromo( |
| Browser* browser, |
| const AccountInfo& account, |
| signin_metrics::AccessPoint access_point, |
| bool is_default_promo_account, |
| base::OnceCallback< |
| void(Profile* profile, |
| Browser* browser, |
| signin_metrics::AccessPoint signin_access_point, |
| signin_metrics::PromoAction signin_promo_action, |
| signin_metrics::Reason signin_reason, |
| const std::string& account_id, |
| DiceTurnSyncOnHelper::SigninAbortedMode signin_aborted_mode)> |
| create_dice_turn_sync_on_helper_callback) { |
| DCHECK(browser); |
| DCHECK_NE(signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN, access_point); |
| Profile* profile = browser->profile(); |
| DCHECK(!profile->IsOffTheRecord()); |
| |
| #if defined(OS_CHROMEOS) |
| // It looks like on ChromeOS there are tests that expect that the Chrome |
| // sign-in tab is presented even thought the user is signed in to Chrome |
| // (e.g. BookmarkBubbleSignInDelegateTest.*). However signing in to Chrome in |
| // a regular profile is not supported on ChromeOS as the primary account is |
| // set when the profile is created. |
| // |
| // TODO(msarda): Investigate whether this flow needs to be supported on |
| // ChromeOS and remove it if not. |
| DCHECK(account.IsEmpty()); |
| chrome::ShowBrowserSignin(browser, access_point); |
| return; |
| #endif |
| |
| if (SigninManagerFactory::GetForProfile(profile)->IsAuthenticated()) { |
| DVLOG(1) << "There is already a primary account."; |
| return; |
| } |
| |
| if (account.IsEmpty()) { |
| chrome::ShowBrowserSignin(browser, access_point); |
| return; |
| } |
| |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) |
| DCHECK(!account.account_id.empty()); |
| DCHECK(!account.email.empty()); |
| DCHECK(AccountConsistencyModeManager::IsDiceEnabledForProfile(profile)); |
| |
| signin_metrics::PromoAction promo_action = |
| is_default_promo_account |
| ? signin_metrics::PromoAction::PROMO_ACTION_WITH_DEFAULT |
| : signin_metrics::PromoAction::PROMO_ACTION_NOT_DEFAULT; |
| |
| ProfileOAuth2TokenService* token_service = |
| ProfileOAuth2TokenServiceFactory::GetForProfile(profile); |
| bool needs_reauth_before_enable_sync = |
| !token_service->RefreshTokenIsAvailable(account.account_id) || |
| token_service->RefreshTokenHasError(account.account_id); |
| if (needs_reauth_before_enable_sync) { |
| browser->signin_view_controller()->ShowDiceSigninTab( |
| profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN, browser, access_point, |
| promo_action, account.email); |
| return; |
| } |
| |
| signin_metrics::LogSigninAccessPointStarted(access_point, promo_action); |
| signin_metrics::RecordSigninUserActionForAccessPoint(access_point, |
| promo_action); |
| std::move(create_dice_turn_sync_on_helper_callback) |
| .Run(profile, browser, access_point, promo_action, |
| signin_metrics::Reason::REASON_SIGNIN_PRIMARY_ACCOUNT, |
| account.account_id, |
| DiceTurnSyncOnHelper::SigninAbortedMode::KEEP_ACCOUNT); |
| #else |
| NOTREACHED(); |
| #endif // BUILDFLAG(ENABLE_DICE_SUPPORT) |
| } |
| } // namespace internal |
| |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) |
| |
| std::string GetDisplayEmail(Profile* profile, const std::string& account_id) { |
| AccountTrackerService* account_tracker = |
| AccountTrackerServiceFactory::GetForProfile(profile); |
| std::string email = account_tracker->GetAccountInfo(account_id).email; |
| if (email.empty()) { |
| DCHECK_EQ(AccountTrackerService::MIGRATION_NOT_STARTED, |
| account_tracker->GetMigrationState()); |
| return account_id; |
| } |
| return email; |
| } |
| |
| std::vector<AccountInfo> GetAccountsForDicePromos(Profile* profile) { |
| // Fetch account ids for accounts that have a token. |
| ProfileOAuth2TokenService* token_service = |
| ProfileOAuth2TokenServiceFactory::GetForProfile(profile); |
| std::vector<std::string> account_ids = token_service->GetAccounts(); |
| |
| // Compute the default account. |
| SigninManager* signin_manager = SigninManagerFactory::GetForProfile(profile); |
| std::string default_account_id; |
| if (signin_manager->IsAuthenticated()) { |
| default_account_id = signin_manager->GetAuthenticatedAccountId(); |
| } else { |
| // Fetch accounts in the Gaia cookies. |
| GaiaCookieManagerService* cookie_manager_service = |
| GaiaCookieManagerServiceFactory::GetForProfile(profile); |
| std::vector<gaia::ListedAccount> cookie_accounts; |
| bool cookie_accounts_valid = cookie_manager_service->ListAccounts( |
| &cookie_accounts, nullptr, "ProfileChooserView"); |
| UMA_HISTOGRAM_BOOLEAN("Profile.DiceUI.GaiaAccountsStale", |
| !cookie_accounts_valid); |
| if (cookie_accounts_valid && !cookie_accounts.empty()) |
| default_account_id = cookie_accounts[0].id; |
| } |
| |
| // Fetch account information for each id and make sure that the first account |
| // in the list matches the first account in the Gaia cookies (if available). |
| AccountTrackerService* account_tracker_service = |
| AccountTrackerServiceFactory::GetForProfile(profile); |
| std::vector<AccountInfo> accounts; |
| for (const std::string& account_id : account_ids) { |
| DCHECK(!account_id.empty()); |
| AccountInfo account_info = |
| account_tracker_service->GetAccountInfo(account_id); |
| if (account_info.IsEmpty() || |
| !signin_manager->IsAllowedUsername(account_info.email)) { |
| continue; |
| } |
| if (account_id == default_account_id) |
| accounts.insert(accounts.begin(), account_info); |
| else |
| accounts.push_back(account_info); |
| } |
| return accounts; |
| } |
| |
| #endif // BUILDFLAG(ENABLE_DICE_SUPPORT) |
| |
| std::string GetAllowedDomain(std::string signin_pattern) { |
| std::vector<std::string> splitted_signin_pattern = base::SplitString( |
| signin_pattern, "@", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); |
| |
| // There are more than one '@'s in the pattern. |
| if (splitted_signin_pattern.size() != 2) |
| return std::string(); |
| |
| std::string domain = splitted_signin_pattern[1]; |
| |
| // Trims tailing '$' if existed. |
| if (domain.size() > 0 && domain.back() == '$') |
| domain.pop_back(); |
| |
| // Trims tailing '\E' if existed. |
| if (domain.size() > 1 && |
| base::EndsWith(domain, "\\E", base::CompareCase::SENSITIVE)) |
| domain.erase(domain.size() - 2); |
| |
| // Check if there is any special character in the domain. Note that |
| // jsmith@[192.168.2.1] is not supported. |
| if (!re2::RE2::FullMatch(domain, "[a-zA-Z0-9\\-.]+")) |
| return std::string(); |
| |
| return domain; |
| } |
| |
| } // namespace signin_ui_util |