| // Copyright 2016 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/ui/webui/signin/signin_create_profile_handler.h" |
| |
| #include <stddef.h> |
| #include <string> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/files/file_path.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/task_runner_util.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "base/value_conversions.h" |
| #include "base/values.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/profiles/profile_attributes_entry.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/profiles/profile_metrics.h" |
| #include "chrome/browser/profiles/profiles_state.h" |
| #include "chrome/browser/signin/signin_error_controller_factory.h" |
| #include "chrome/browser/signin/signin_manager_factory.h" |
| #include "chrome/browser/signin/signin_util.h" |
| #include "chrome/browser/sync/profile_sync_service_factory.h" |
| #include "chrome/browser/ui/browser_finder.h" |
| #include "chrome/browser/ui/user_manager.h" |
| #include "chrome/browser/ui/webui/profile_helper.h" |
| #include "chrome/browser/ui/webui/signin/signin_utils.h" |
| #include "chrome/common/buildflags.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/common/url_constants.h" |
| #include "chrome/grit/chromium_strings.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "components/browser_sync/profile_sync_service.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/signin/core/browser/signin_error_controller.h" |
| #include "components/strings/grit/components_strings.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/browser/web_ui.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| #if BUILDFLAG(ENABLE_SUPERVISED_USERS) |
| #include "chrome/browser/supervised_user/legacy/supervised_user_registration_utility.h" |
| #include "chrome/browser/supervised_user/legacy/supervised_user_sync_service.h" |
| #include "chrome/browser/supervised_user/legacy/supervised_user_sync_service_factory.h" |
| #include "chrome/browser/supervised_user/supervised_user_service.h" |
| #include "chrome/browser/supervised_user/supervised_user_service_factory.h" |
| #endif |
| |
| SigninCreateProfileHandler::SigninCreateProfileHandler() |
| : profile_creation_type_(NO_CREATION_IN_PROGRESS), |
| weak_ptr_factory_(this) { |
| g_browser_process->profile_manager()-> |
| GetProfileAttributesStorage().AddObserver(this); |
| } |
| |
| SigninCreateProfileHandler::~SigninCreateProfileHandler() { |
| #if BUILDFLAG(ENABLE_SUPERVISED_USERS) |
| // Cancellation is only supported for supervised users. |
| CancelProfileRegistration(false); |
| #endif |
| g_browser_process->profile_manager()-> |
| GetProfileAttributesStorage().RemoveObserver(this); |
| } |
| |
| void SigninCreateProfileHandler::GetLocalizedValues( |
| base::DictionaryValue* localized_strings) { |
| localized_strings->SetString( |
| "createDesktopShortcutLabel", |
| l10n_util::GetStringUTF16( |
| IDS_PROFILES_CREATE_DESKTOP_SHORTCUT_LABEL)); |
| localized_strings->SetString( |
| "manageProfilesSupervisedSignedInLabel", |
| l10n_util::GetStringUTF16( |
| IDS_PROFILES_CREATE_SUPERVISED_MULTI_SIGNED_IN_LABEL)); |
| localized_strings->SetString( |
| "noSignedInUserMessage", |
| l10n_util::GetStringUTF16( |
| IDS_PROFILES_CREATE_SUPERVISED_NO_SIGNED_IN_USER_TEXT)); |
| localized_strings->SetString("createProfileConfirm", |
| l10n_util::GetStringUTF16(IDS_ADD)); |
| localized_strings->SetString("learnMore", |
| l10n_util::GetStringUTF16(IDS_LEARN_MORE)); |
| localized_strings->SetString( |
| "selectAnAccount", |
| l10n_util::GetStringUTF16( |
| IDS_PROFILES_CREATE_SUPERVISED_SENTINEL_MENU_ITEM_TEXT)); |
| localized_strings->SetString( |
| "createProfileTitle", |
| l10n_util::GetStringUTF16(IDS_PROFILES_CREATE_TITLE)); |
| localized_strings->SetString( |
| "supervisedUserLearnMoreTitle", |
| l10n_util::GetStringUTF16(IDS_LEGACY_SUPERVISED_USER_LEARN_MORE_TITLE)); |
| localized_strings->SetString( |
| "supervisedUserLearnMoreDone", |
| l10n_util::GetStringUTF16( |
| IDS_LEGACY_SUPERVISED_USER_LEARN_MORE_DONE_BUTTON)); |
| localized_strings->SetString( |
| "supervisedUserLearnMoreText", |
| l10n_util::GetStringFUTF16( |
| IDS_SUPERVISED_USER_LEARN_MORE_TEXT, |
| base::ASCIIToUTF16( |
| chrome::kLegacySupervisedUserManagementURL), |
| base::ASCIIToUTF16( |
| chrome::kLegacySupervisedUserManagementDisplayURL))); |
| localized_strings->SetString( |
| "importExistingSupervisedUserLink", |
| l10n_util::GetStringUTF16( |
| IDS_IMPORT_EXISTING_LEGACY_SUPERVISED_USER_TITLE)); |
| localized_strings->SetString( |
| "manageProfilesExistingSupervisedUser", |
| l10n_util::GetStringUTF16( |
| IDS_PROFILES_CREATE_LEGACY_SUPERVISED_USER_ERROR_EXISTS_REMOTELY)); |
| localized_strings->SetString( |
| "managedProfilesExistingLocalSupervisedUser", |
| l10n_util::GetStringUTF16( |
| IDS_PROFILES_CREATE_LEGACY_SUPERVISED_USER_ERROR_EXISTS_LOCALLY)); |
| localized_strings->SetString( |
| "custodianAccountNotSelectedError", |
| l10n_util::GetStringUTF16( |
| IDS_PROFILES_CREATE_NO_CUSTODIAN_ACCOUNT_ERROR)); |
| localized_strings->SetString( |
| "supervisedUserCreatedTitle", |
| l10n_util::GetStringUTF16(IDS_LEGACY_SUPERVISED_USER_CREATED_TITLE)); |
| // The first two substitution parameters remain to be filled by the page JS. |
| localized_strings->SetString( |
| "supervisedUserCreatedText", |
| l10n_util::GetStringFUTF16( |
| IDS_SUPERVISED_USER_CREATED_TEXT, |
| base::ASCIIToUTF16("$1"), |
| base::ASCIIToUTF16("$2"), |
| base::ASCIIToUTF16(chrome::kLegacySupervisedUserManagementURL), |
| base::ASCIIToUTF16( |
| chrome::kLegacySupervisedUserManagementDisplayURL))); |
| localized_strings->SetString( |
| "exitAndChildlockLabel", |
| l10n_util::GetStringUTF16( |
| IDS_PROFILES_PROFILE_SIGNOUT_BUTTON)); |
| localized_strings->SetString( |
| "supervisedUserCreatedDone", |
| l10n_util::GetStringUTF16( |
| IDS_LEGACY_SUPERVISED_USER_CREATED_DONE_BUTTON)); |
| localized_strings->SetString( |
| "supervisedUserCreatedSwitch", |
| l10n_util::GetStringUTF16( |
| IDS_LEGACY_SUPERVISED_USER_CREATED_SWITCH_BUTTON)); |
| } |
| |
| void SigninCreateProfileHandler::RegisterMessages() { |
| #if BUILDFLAG(ENABLE_SUPERVISED_USERS) |
| // Cancellation is only supported for supervised users. |
| web_ui()->RegisterMessageCallback( |
| "cancelCreateProfile", |
| base::BindRepeating( |
| &SigninCreateProfileHandler::HandleCancelProfileCreation, |
| base::Unretained(this))); |
| |
| web_ui()->RegisterMessageCallback( |
| "switchToProfile", |
| base::BindRepeating(&SigninCreateProfileHandler::SwitchToProfile, |
| base::Unretained(this))); |
| #endif |
| web_ui()->RegisterMessageCallback( |
| "createProfile", |
| base::BindRepeating(&SigninCreateProfileHandler::CreateProfile, |
| base::Unretained(this))); |
| |
| web_ui()->RegisterMessageCallback( |
| "requestDefaultProfileIcons", |
| base::BindRepeating( |
| &SigninCreateProfileHandler::RequestDefaultProfileIcons, |
| base::Unretained(this))); |
| |
| web_ui()->RegisterMessageCallback( |
| "requestSignedInProfiles", |
| base::BindRepeating(&SigninCreateProfileHandler::RequestSignedInProfiles, |
| base::Unretained(this))); |
| } |
| |
| void SigninCreateProfileHandler::RequestDefaultProfileIcons( |
| const base::ListValue* args) { |
| web_ui()->CallJavascriptFunctionUnsafe( |
| "cr.webUIListenerCallback", base::Value("profile-icons-received"), |
| *profiles::GetDefaultProfileAvatarIconsAndLabels()); |
| |
| SendNewProfileDefaults(); |
| } |
| |
| void SigninCreateProfileHandler::SendNewProfileDefaults() { |
| ProfileAttributesStorage& storage = |
| g_browser_process->profile_manager()->GetProfileAttributesStorage(); |
| base::DictionaryValue profile_info; |
| profile_info.SetString("name", storage.ChooseNameForNewProfile(0)); |
| |
| web_ui()->CallJavascriptFunctionUnsafe( |
| "cr.webUIListenerCallback", base::Value("profile-defaults-received"), |
| profile_info); |
| } |
| |
| void SigninCreateProfileHandler::RequestSignedInProfiles( |
| const base::ListValue* args) { |
| base::ListValue user_info_list; |
| std::vector<ProfileAttributesEntry*> entries = |
| g_browser_process->profile_manager()-> |
| GetProfileAttributesStorage().GetAllProfilesAttributesSortedByName(); |
| for (ProfileAttributesEntry* entry : entries) { |
| base::string16 username = entry->GetUserName(); |
| if (username.empty()) |
| continue; |
| base::string16 profile_path = entry->GetPath().AsUTF16Unsafe(); |
| std::unique_ptr<base::DictionaryValue> user_info( |
| new base::DictionaryValue()); |
| user_info->SetString("username", username); |
| user_info->SetString("profilePath", profile_path); |
| |
| user_info_list.Append(std::move(user_info)); |
| } |
| web_ui()->CallJavascriptFunctionUnsafe("cr.webUIListenerCallback", |
| base::Value("signedin-users-received"), |
| user_info_list); |
| } |
| |
| void SigninCreateProfileHandler::OnProfileAuthInfoChanged( |
| const base::FilePath& profile_path) { |
| RequestSignedInProfiles(nullptr); |
| } |
| |
| void SigninCreateProfileHandler::CreateProfile(const base::ListValue* args) { |
| if (!profiles::IsMultipleProfilesEnabled()) |
| return; |
| |
| // We can have only one in progress profile creation |
| // at any given moment, if new ones are initiated just |
| // ignore them until we are done with the old one. |
| if (profile_creation_type_ != NO_CREATION_IN_PROGRESS) |
| return; |
| |
| profile_creation_type_ = NON_SUPERVISED_PROFILE_CREATION; |
| |
| DCHECK(profile_path_being_created_.empty()); |
| profile_creation_start_time_ = base::TimeTicks::Now(); |
| |
| base::string16 name; |
| std::string icon_url; |
| bool create_shortcut = false; |
| if (args->GetString(0, &name) && args->GetString(1, &icon_url)) { |
| DCHECK(base::IsStringASCII(icon_url)); |
| base::TrimWhitespace(name, base::TRIM_ALL, &name); |
| CHECK(!name.empty()); |
| #ifndef NDEBUG |
| size_t icon_index; |
| DCHECK(profiles::IsDefaultAvatarIconUrl(icon_url, &icon_index)); |
| #endif |
| args->GetBoolean(2, &create_shortcut); |
| } |
| #if BUILDFLAG(ENABLE_SUPERVISED_USERS) |
| std::string supervised_user_id; |
| base::FilePath custodian_profile_path; |
| if (GetSupervisedCreateProfileArgs(args, &supervised_user_id, |
| &custodian_profile_path)) { |
| // Load custodian profile. |
| g_browser_process->profile_manager()->CreateProfileAsync( |
| custodian_profile_path, |
| base::Bind(&SigninCreateProfileHandler::LoadCustodianProfileCallback, |
| weak_ptr_factory_.GetWeakPtr(), name, icon_url, |
| create_shortcut, supervised_user_id), |
| base::string16(), std::string(), std::string()); |
| } else { |
| DoCreateProfile(name, icon_url, create_shortcut, std::string(), nullptr); |
| } |
| #else |
| DoCreateProfile(name, icon_url, create_shortcut, std::string(), nullptr); |
| #endif |
| } |
| |
| void SigninCreateProfileHandler::DoCreateProfile( |
| const base::string16& name, |
| const std::string& icon_url, |
| bool create_shortcut, |
| const std::string& supervised_user_id, |
| Profile* custodian_profile) { |
| ProfileMetrics::LogProfileAddNewUser(ProfileMetrics::ADD_NEW_USER_DIALOG); |
| |
| profile_path_being_created_ = ProfileManager::CreateMultiProfileAsync( |
| name, icon_url, |
| base::Bind(&SigninCreateProfileHandler::OnProfileCreated, |
| weak_ptr_factory_.GetWeakPtr(), create_shortcut, |
| supervised_user_id, custodian_profile), |
| supervised_user_id); |
| } |
| |
| void SigninCreateProfileHandler::OnProfileCreated( |
| bool create_shortcut, |
| const std::string& supervised_user_id, |
| Profile* custodian_profile, |
| Profile* profile, |
| Profile::CreateStatus status) { |
| if (status != Profile::CREATE_STATUS_CREATED) |
| RecordProfileCreationMetrics(status); |
| |
| switch (status) { |
| case Profile::CREATE_STATUS_LOCAL_FAIL: { |
| ShowProfileCreationError(profile, GetProfileCreationErrorMessageLocal()); |
| break; |
| } |
| case Profile::CREATE_STATUS_CREATED: { |
| // Do nothing for an intermediate status. |
| break; |
| } |
| case Profile::CREATE_STATUS_INITIALIZED: { |
| HandleProfileCreationSuccess(create_shortcut, supervised_user_id, |
| custodian_profile, profile); |
| break; |
| } |
| // User-initiated cancellation is handled in CancelProfileRegistration and |
| // does not call this callback. |
| case Profile::CREATE_STATUS_CANCELED: |
| // Supervised user registration errors are handled in |
| // OnSupervisedUserRegistered(). |
| case Profile::CREATE_STATUS_REMOTE_FAIL: |
| case Profile::MAX_CREATE_STATUS: { |
| NOTREACHED(); |
| break; |
| } |
| } |
| } |
| |
| void SigninCreateProfileHandler::HandleProfileCreationSuccess( |
| bool create_shortcut, |
| const std::string& supervised_user_id, |
| Profile* custodian_profile, |
| Profile* profile) { |
| switch (profile_creation_type_) { |
| case NON_SUPERVISED_PROFILE_CREATION: { |
| DCHECK(supervised_user_id.empty()); |
| CreateShortcutAndShowSuccess(create_shortcut, nullptr, profile); |
| break; |
| } |
| #if BUILDFLAG(ENABLE_SUPERVISED_USERS) |
| case SUPERVISED_PROFILE_CREATION: |
| case SUPERVISED_PROFILE_IMPORT: |
| RegisterSupervisedUser(create_shortcut, supervised_user_id, |
| custodian_profile, profile); |
| break; |
| #endif |
| case NO_CREATION_IN_PROGRESS: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| void SigninCreateProfileHandler::CreateShortcutAndShowSuccess( |
| bool create_shortcut, |
| Profile* custodian_profile, |
| Profile* profile) { |
| if (create_shortcut) { |
| DCHECK(ProfileShortcutManager::IsFeatureEnabled()); |
| ProfileShortcutManager* shortcut_manager = |
| g_browser_process->profile_manager()->profile_shortcut_manager(); |
| DCHECK(shortcut_manager); |
| if (shortcut_manager) |
| shortcut_manager->CreateProfileShortcut(profile->GetPath()); |
| } |
| |
| DCHECK_EQ(profile_path_being_created_.value(), profile->GetPath().value()); |
| profile_path_being_created_.clear(); |
| DCHECK_NE(NO_CREATION_IN_PROGRESS, profile_creation_type_); |
| base::DictionaryValue dict; |
| dict.SetString("name", profile->GetPrefs()->GetString(prefs::kProfileName)); |
| dict.Set("filePath", base::CreateFilePathValue(profile->GetPath())); |
| |
| bool is_force_signin_enabled = signin_util::IsForceSigninEnabled(); |
| bool open_new_window = !is_force_signin_enabled; |
| |
| #if BUILDFLAG(ENABLE_SUPERVISED_USERS) |
| // If the new profile is a supervised user, instead of opening a new window |
| // right away, a confirmation page will be shown by JS from the creation |
| // dialog. If we are importing an existing supervised profile or creating a |
| // new non-supervised user profile we don't show any confirmation, so open |
| // the new window now. |
| |
| open_new_window = |
| open_new_window && profile_creation_type_ != SUPERVISED_PROFILE_CREATION; |
| |
| dict.SetBoolean("showConfirmation", |
| profile_creation_type_ == SUPERVISED_PROFILE_CREATION); |
| |
| bool is_supervised = profile_creation_type_ == SUPERVISED_PROFILE_CREATION || |
| profile_creation_type_ == SUPERVISED_PROFILE_IMPORT; |
| dict.SetBoolean("isSupervised", is_supervised); |
| |
| if (is_supervised) { |
| DCHECK(custodian_profile); |
| if (custodian_profile) { |
| std::string custodian_username = custodian_profile->GetProfileUserName(); |
| dict.SetString("custodianUsername", custodian_username); |
| } |
| } |
| #endif |
| |
| web_ui()->CallJavascriptFunctionUnsafe( |
| "cr.webUIListenerCallback", |
| GetWebUIListenerName(PROFILE_CREATION_SUCCESS), dict); |
| |
| if (open_new_window) { |
| // Opening the new window must be the last action, after all callbacks |
| // have been run, to give them a chance to initialize the profile. |
| OpenNewWindowForProfile(profile, Profile::CREATE_STATUS_INITIALIZED); |
| } else if (is_force_signin_enabled) { |
| OpenSigninDialogForProfile(profile); |
| } |
| profile_creation_type_ = NO_CREATION_IN_PROGRESS; |
| } |
| |
| void SigninCreateProfileHandler::OpenNewWindowForProfile( |
| Profile* profile, |
| Profile::CreateStatus status) { |
| profiles::OpenBrowserWindowForProfile( |
| base::Bind(&SigninCreateProfileHandler::OnBrowserReadyCallback, |
| weak_ptr_factory_.GetWeakPtr()), |
| false, // Don't create a window if one already exists. |
| true, // Create a first run window. |
| profile, |
| status); |
| } |
| |
| void SigninCreateProfileHandler::OpenSigninDialogForProfile(Profile* profile) { |
| UserManagerProfileDialog::ShowSigninDialog( |
| web_ui()->GetWebContents()->GetBrowserContext(), profile->GetPath(), |
| signin_util::IsForceSigninEnabled() |
| ? signin_metrics::Reason::REASON_FORCED_SIGNIN_PRIMARY_ACCOUNT |
| : signin_metrics::Reason::REASON_SIGNIN_PRIMARY_ACCOUNT); |
| } |
| |
| void SigninCreateProfileHandler::ShowProfileCreationError( |
| Profile* profile, |
| const base::string16& error) { |
| DCHECK_NE(NO_CREATION_IN_PROGRESS, profile_creation_type_); |
| web_ui()->CallJavascriptFunctionUnsafe( |
| "cr.webUIListenerCallback", GetWebUIListenerName(PROFILE_CREATION_ERROR), |
| base::Value(error)); |
| // The ProfileManager calls us back with a NULL profile in some cases. |
| if (profile) { |
| webui::DeleteProfileAtPath(profile->GetPath(), |
| ProfileMetrics::DELETE_PROFILE_SETTINGS); |
| } |
| profile_creation_type_ = NO_CREATION_IN_PROGRESS; |
| profile_path_being_created_.clear(); |
| } |
| |
| void SigninCreateProfileHandler::RecordProfileCreationMetrics( |
| Profile::CreateStatus status) { |
| UMA_HISTOGRAM_ENUMERATION("Profile.CreateResult", status, |
| Profile::MAX_CREATE_STATUS); |
| UMA_HISTOGRAM_MEDIUM_TIMES( |
| "Profile.CreateTimeNoTimeout", |
| base::TimeTicks::Now() - profile_creation_start_time_); |
| } |
| |
| base::string16 SigninCreateProfileHandler::GetProfileCreationErrorMessageLocal() |
| const { |
| int message_id = IDS_PROFILES_CREATE_LOCAL_ERROR; |
| #if BUILDFLAG(ENABLE_SUPERVISED_USERS) |
| // Local errors can occur during supervised profile import. |
| if (profile_creation_type_ == SUPERVISED_PROFILE_IMPORT) |
| message_id = IDS_LEGACY_SUPERVISED_USER_IMPORT_LOCAL_ERROR; |
| #endif |
| return l10n_util::GetStringUTF16(message_id); |
| } |
| |
| void SigninCreateProfileHandler::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| DCHECK_EQ(chrome::NOTIFICATION_BROWSER_WINDOW_READY, type); |
| |
| // Only respond to one Browser Window Ready event. |
| registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY, |
| content::NotificationService::AllSources()); |
| UserManager::Hide(); |
| } |
| |
| void SigninCreateProfileHandler::OnBrowserReadyCallback( |
| Profile* profile, |
| Profile::CreateStatus profile_create_status) { |
| Browser* browser = chrome::FindAnyBrowser(profile, false); |
| // Closing the User Manager before the window is created can flakily cause |
| // Chrome to close. |
| if (browser && browser->window()) { |
| UserManager::Hide(); |
| } else { |
| registrar_.Add(this, |
| chrome::NOTIFICATION_BROWSER_WINDOW_READY, |
| content::NotificationService::AllSources()); |
| } |
| } |
| |
| base::Value SigninCreateProfileHandler::GetWebUIListenerName( |
| ProfileCreationStatus status) const { |
| switch (status) { |
| case PROFILE_CREATION_SUCCESS: |
| return base::Value("create-profile-success"); |
| case PROFILE_CREATION_ERROR: |
| return base::Value("create-profile-error"); |
| } |
| NOTREACHED(); |
| return base::Value(std::string()); |
| } |
| |
| #if BUILDFLAG(ENABLE_SUPERVISED_USERS) |
| base::string16 SigninCreateProfileHandler::GetProfileCreateErrorMessageRemote() |
| const { |
| return l10n_util::GetStringUTF16( |
| profile_creation_type_ == SUPERVISED_PROFILE_IMPORT |
| ? IDS_LEGACY_SUPERVISED_USER_IMPORT_REMOTE_ERROR |
| : IDS_PROFILES_CREATE_REMOTE_ERROR); |
| } |
| |
| base::string16 SigninCreateProfileHandler::GetProfileCreateErrorMessageSignin() |
| const { |
| return l10n_util::GetStringUTF16( |
| profile_creation_type_ == SUPERVISED_PROFILE_IMPORT |
| ? IDS_LEGACY_SUPERVISED_USER_IMPORT_SIGN_IN_ERROR |
| : IDS_PROFILES_CREATE_SIGN_IN_ERROR); |
| } |
| |
| bool SigninCreateProfileHandler::GetSupervisedCreateProfileArgs( |
| const base::ListValue* args, |
| std::string* supervised_user_id, |
| base::FilePath* custodian_profile_path) { |
| bool supervised_user = false; |
| bool success = args->GetBoolean(3, &supervised_user); |
| DCHECK(success); |
| |
| if (!supervised_user) |
| return false; |
| |
| success = args->GetString(4, supervised_user_id); |
| DCHECK(success); |
| const base::Value* path_value; |
| success = args->Get(5, &path_value); |
| DCHECK(success); |
| success = base::GetValueAsFilePath(*path_value, custodian_profile_path); |
| DCHECK(success); |
| |
| return !custodian_profile_path->empty(); |
| } |
| |
| void SigninCreateProfileHandler::LoadCustodianProfileCallback( |
| const base::string16& name, |
| const std::string& icon_url, |
| bool create_shortcut, |
| const std::string& supervised_user_id, |
| Profile* custodian_profile, |
| Profile::CreateStatus status) { |
| // This method gets called once before with Profile::CREATE_STATUS_CREATED. |
| switch (status) { |
| case Profile::CREATE_STATUS_LOCAL_FAIL: { |
| ShowProfileCreationError(nullptr, GetProfileCreationErrorMessageLocal()); |
| break; |
| } |
| case Profile::CREATE_STATUS_CREATED: { |
| // Ignore the intermediate status. |
| break; |
| } |
| case Profile::CREATE_STATUS_INITIALIZED: { |
| // We are only interested in Profile::CREATE_STATUS_INITIALIZED when |
| // everything is ready. |
| if (!IsAccountConnected(custodian_profile) || |
| HasAuthError(custodian_profile)) { |
| ShowProfileCreationError(nullptr, l10n_util::GetStringFUTF16( |
| IDS_PROFILES_CREATE_CUSTODIAN_ACCOUNT_DETAILS_OUT_OF_DATE_ERROR, |
| base::ASCIIToUTF16(custodian_profile->GetProfileUserName()))); |
| return; |
| } |
| |
| PrefService* prefs = custodian_profile->GetPrefs(); |
| if (!prefs->GetBoolean(prefs::kSupervisedUserCreationAllowed)) { |
| ShowProfileCreationError( |
| nullptr, |
| l10n_util::GetStringUTF16( |
| IDS_PROFILES_CREATE_SUPERVISED_NOT_ALLOWED_BY_POLICY)); |
| return; |
| } |
| |
| if (!supervised_user_id.empty()) { |
| profile_creation_type_ = SUPERVISED_PROFILE_IMPORT; |
| |
| // Load all supervised users managed by this user in order to |
| // check if this supervised user already exists on this device. |
| SupervisedUserSyncService* supervised_user_sync_service = |
| SupervisedUserSyncServiceFactory::GetForProfile(custodian_profile); |
| if (supervised_user_sync_service) { |
| supervised_user_sync_service->GetSupervisedUsersAsync(base::Bind( |
| &SigninCreateProfileHandler::DoCreateProfileIfPossible, |
| weak_ptr_factory_.GetWeakPtr(), name, icon_url, create_shortcut, |
| supervised_user_id, custodian_profile)); |
| } else { |
| ShowProfileCreationError(nullptr, |
| GetProfileCreateErrorMessageRemote()); |
| } |
| } else { |
| profile_creation_type_ = SUPERVISED_PROFILE_CREATION; |
| std::string new_supervised_user_id = |
| SupervisedUserRegistrationUtility::GenerateNewSupervisedUserId(); |
| |
| // If sync is not yet fully initialized, the creation may take extra |
| // time, so show a message. Import doesn't wait for an acknowledgment, |
| // so it won't have the same potential delay. |
| browser_sync::ProfileSyncService* sync_service = |
| ProfileSyncServiceFactory::GetInstance()->GetForProfile( |
| custodian_profile); |
| browser_sync::ProfileSyncService::SyncStatusSummary status = |
| sync_service->QuerySyncStatusSummary(); |
| if (status == |
| browser_sync::ProfileSyncService::DATATYPES_NOT_INITIALIZED) { |
| ShowProfileCreationWarning(l10n_util::GetStringUTF16( |
| IDS_PROFILES_CREATE_SUPERVISED_JUST_SIGNED_IN)); |
| } |
| |
| DoCreateProfile(name, icon_url, create_shortcut, new_supervised_user_id, |
| custodian_profile); |
| } |
| break; |
| } |
| case Profile::CREATE_STATUS_CANCELED: |
| case Profile::CREATE_STATUS_REMOTE_FAIL: |
| case Profile::MAX_CREATE_STATUS: { |
| NOTREACHED(); |
| break; |
| } |
| } |
| } |
| |
| bool SigninCreateProfileHandler::IsAccountConnected(Profile* profile) |
| const { |
| SigninManagerBase* signin_manager = |
| SigninManagerFactory::GetForProfile(profile); |
| return signin_manager && signin_manager->IsAuthenticated(); |
| } |
| |
| bool SigninCreateProfileHandler::HasAuthError(Profile* profile) |
| const { |
| SigninErrorController* error_controller = |
| SigninErrorControllerFactory::GetForProfile(profile); |
| if (!error_controller) |
| return true; |
| |
| GoogleServiceAuthError::State state = error_controller->auth_error().state(); |
| return state != GoogleServiceAuthError::NONE; |
| } |
| |
| void SigninCreateProfileHandler::DoCreateProfileIfPossible( |
| const base::string16& name, |
| const std::string& icon_url, |
| bool create_shortcut, |
| const std::string& supervised_user_id, |
| Profile* custodian_profile, |
| const base::DictionaryValue* dict) { |
| DCHECK(dict); |
| if (!dict->HasKey(supervised_user_id)) |
| return; |
| |
| // Check if this supervised user already exists on this machine. |
| std::vector<ProfileAttributesEntry*> entries = |
| g_browser_process->profile_manager()-> |
| GetProfileAttributesStorage().GetAllProfilesAttributes(); |
| for (ProfileAttributesEntry* entry : entries) { |
| if (supervised_user_id == entry->GetSupervisedUserId()) { |
| ShowProfileCreationError(nullptr, GetProfileCreationErrorMessageLocal()); |
| return; |
| } |
| } |
| |
| DoCreateProfile(name, icon_url, create_shortcut, supervised_user_id, |
| custodian_profile); |
| } |
| |
| void SigninCreateProfileHandler::HandleCancelProfileCreation( |
| const base::ListValue* args) { |
| CancelProfileRegistration(true); |
| } |
| |
| // Non-supervised user creation cannot be canceled. (Creating a non-supervised |
| // profile shouldn't take significant time, and it can easily be deleted |
| // afterward.) |
| void SigninCreateProfileHandler::CancelProfileRegistration( |
| bool user_initiated) { |
| if (profile_path_being_created_.empty()) |
| return; |
| |
| ProfileManager* manager = g_browser_process->profile_manager(); |
| Profile* new_profile = manager->GetProfileByPath(profile_path_being_created_); |
| if (!new_profile || !new_profile->IsSupervised()) |
| return; |
| |
| DCHECK(supervised_user_registration_utility_.get()); |
| supervised_user_registration_utility_.reset(); |
| |
| if (user_initiated) { |
| UMA_HISTOGRAM_MEDIUM_TIMES( |
| "Profile.CreateTimeCanceledNoTimeout", |
| base::TimeTicks::Now() - profile_creation_start_time_); |
| RecordProfileCreationMetrics(Profile::CREATE_STATUS_CANCELED); |
| } |
| |
| DCHECK_NE(NO_CREATION_IN_PROGRESS, profile_creation_type_); |
| profile_creation_type_ = NO_CREATION_IN_PROGRESS; |
| |
| // Canceling registration means the callback passed into |
| // RegisterAndInitSync() won't be called, so the cleanup must be done here. |
| profile_path_being_created_.clear(); |
| webui::DeleteProfileAtPath(new_profile->GetPath(), |
| ProfileMetrics::DELETE_PROFILE_SETTINGS); |
| } |
| |
| void SigninCreateProfileHandler::RegisterSupervisedUser( |
| bool create_shortcut, |
| const std::string& supervised_user_id, |
| Profile* custodian_profile, |
| Profile* new_profile) { |
| DCHECK_EQ(profile_path_being_created_.value(), |
| new_profile->GetPath().value()); |
| |
| SupervisedUserService* supervised_user_service = |
| SupervisedUserServiceFactory::GetForProfile(new_profile); |
| |
| // Register the supervised user using the profile of the custodian. |
| supervised_user_registration_utility_ = |
| SupervisedUserRegistrationUtility::Create(custodian_profile); |
| if (supervised_user_service) { |
| supervised_user_service->RegisterAndInitSync( |
| supervised_user_registration_utility_.get(), custodian_profile, |
| supervised_user_id, |
| base::BindOnce(&SigninCreateProfileHandler::OnSupervisedUserRegistered, |
| weak_ptr_factory_.GetWeakPtr(), create_shortcut, |
| custodian_profile, new_profile)); |
| } |
| } |
| |
| void SigninCreateProfileHandler::OnSupervisedUserRegistered( |
| bool create_shortcut, |
| Profile* custodian_profile, |
| Profile* profile, |
| const GoogleServiceAuthError& error) { |
| GoogleServiceAuthError::State state = error.state(); |
| RecordSupervisedProfileCreationMetrics(state); |
| if (state == GoogleServiceAuthError::NONE) { |
| CreateShortcutAndShowSuccess(create_shortcut, custodian_profile, profile); |
| return; |
| } |
| |
| base::string16 error_msg; |
| if (state == GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS || |
| state == GoogleServiceAuthError::USER_NOT_SIGNED_UP || |
| state == GoogleServiceAuthError::ACCOUNT_DELETED || |
| state == GoogleServiceAuthError::ACCOUNT_DISABLED) { |
| error_msg = GetProfileCreateErrorMessageSignin(); |
| } else { |
| error_msg = GetProfileCreateErrorMessageRemote(); |
| } |
| ShowProfileCreationError(profile, error_msg); |
| } |
| |
| void SigninCreateProfileHandler::ShowProfileCreationWarning( |
| const base::string16& warning) { |
| DCHECK_EQ(SUPERVISED_PROFILE_CREATION, profile_creation_type_); |
| web_ui()->CallJavascriptFunctionUnsafe("cr.webUIListenerCallback", |
| base::Value("create-profile-warning"), |
| base::Value(warning)); |
| } |
| |
| void SigninCreateProfileHandler::RecordSupervisedProfileCreationMetrics( |
| GoogleServiceAuthError::State error_state) { |
| if (profile_creation_type_ == SUPERVISED_PROFILE_CREATION) { |
| UMA_HISTOGRAM_ENUMERATION("Profile.SupervisedProfileCreateError", |
| error_state, GoogleServiceAuthError::NUM_STATES); |
| UMA_HISTOGRAM_MEDIUM_TIMES( |
| "Profile.SupervisedProfileTotalCreateTime", |
| base::TimeTicks::Now() - profile_creation_start_time_); |
| } else { |
| DCHECK_EQ(SUPERVISED_PROFILE_IMPORT, profile_creation_type_); |
| UMA_HISTOGRAM_ENUMERATION("Profile.SupervisedProfileImportError", |
| error_state, GoogleServiceAuthError::NUM_STATES); |
| UMA_HISTOGRAM_MEDIUM_TIMES( |
| "Profile.SupervisedProfileTotalImportTime", |
| base::TimeTicks::Now() - profile_creation_start_time_); |
| } |
| } |
| |
| void SigninCreateProfileHandler::SwitchToProfile( |
| const base::ListValue* args) { |
| DCHECK(args); |
| const base::Value* file_path_value; |
| if (!args->Get(0, &file_path_value)) |
| return; |
| |
| base::FilePath profile_file_path; |
| if (!base::GetValueAsFilePath(*file_path_value, &profile_file_path)) |
| return; |
| |
| Profile* profile = g_browser_process->profile_manager()-> |
| GetProfileByPath(profile_file_path); |
| DCHECK(profile); |
| |
| profiles::OpenBrowserWindowForProfile( |
| base::Bind(&SigninCreateProfileHandler::OnBrowserReadyCallback, |
| weak_ptr_factory_.GetWeakPtr()), |
| false, // Don't create a window if one already exists. |
| true, // Create a first run window. |
| profile, |
| Profile::CREATE_STATUS_INITIALIZED); |
| } |
| #endif |