Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / ui / webui / options / create_profile_handler.cc
bloba2ac78789ee5f99d335d1ef846e7e75d4ec7ec75
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/webui/options/create_profile_handler.h"
7 #include "base/bind.h"
8 #include "base/files/file_path.h"
9 #include "base/metrics/histogram.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/string_util.h"
12 #include "base/value_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/profiles/profile_manager.h"
16 #include "chrome/browser/profiles/profile_metrics.h"
17 #include "chrome/browser/profiles/profiles_state.h"
18 #include "chrome/browser/sync/profile_sync_service.h"
19 #include "chrome/browser/sync/profile_sync_service_factory.h"
20 #include "chrome/browser/ui/webui/options/options_handlers_helper.h"
21 #include "chrome/common/pref_names.h"
22 #include "chrome/grit/generated_resources.h"
23 #include "content/public/browser/web_ui.h"
24 #include "ui/base/l10n/l10n_util.h"
26 #if defined(ENABLE_SUPERVISED_USERS)
27 #include "chrome/browser/supervised_user/legacy/supervised_user_registration_utility.h"
28 #include "chrome/browser/supervised_user/legacy/supervised_user_sync_service.h"
29 #include "chrome/browser/supervised_user/legacy/supervised_user_sync_service_factory.h"
30 #include "chrome/browser/supervised_user/supervised_user_service.h"
31 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
32 #endif
34 namespace options {
36 CreateProfileHandler::CreateProfileHandler()
37 : profile_creation_type_(NO_CREATION_IN_PROGRESS),
38 weak_ptr_factory_(this) {
41 CreateProfileHandler::~CreateProfileHandler() {
42 #if defined(ENABLE_SUPERVISED_USERS)
43 // Cancellation is only supported for supervised users.
44 CancelProfileRegistration(false);
45 #endif
48 void CreateProfileHandler::GetLocalizedValues(
49 base::DictionaryValue* localized_strings) {
52 void CreateProfileHandler::RegisterMessages() {
53 #if defined(ENABLE_SUPERVISED_USERS)
54 // Cancellation is only supported for supervised users.
55 web_ui()->RegisterMessageCallback(
56 "cancelCreateProfile",
57 base::Bind(&CreateProfileHandler::HandleCancelProfileCreation,
58 base::Unretained(this)));
59 #endif
60 web_ui()->RegisterMessageCallback(
61 "createProfile",
62 base::Bind(&CreateProfileHandler::CreateProfile,
63 base::Unretained(this)));
66 void CreateProfileHandler::CreateProfile(const base::ListValue* args) {
67 #if defined(ENABLE_SUPERVISED_USERS)
68 // This handler could have been called for a supervised user, for example
69 // because the user fiddled with the web inspector. Silently return.
70 if (Profile::FromWebUI(web_ui())->IsSupervised())
71 return;
72 #endif
74 if (!profiles::IsMultipleProfilesEnabled())
75 return;
77 // We can have only one in progress profile creation
78 // at any given moment, if new ones are initiated just
79 // ignore them until we are done with the old one.
80 if (profile_creation_type_ != NO_CREATION_IN_PROGRESS)
81 return;
83 profile_creation_type_ = NON_SUPERVISED_PROFILE_CREATION;
85 DCHECK(profile_path_being_created_.empty());
86 profile_creation_start_time_ = base::TimeTicks::Now();
88 base::string16 name;
89 base::string16 icon;
90 bool create_shortcut = false;
91 if (args->GetString(0, &name) && args->GetString(1, &icon)) {
92 base::TrimWhitespace(name, base::TRIM_ALL, &name);
93 CHECK(!name.empty());
94 args->GetBoolean(2, &create_shortcut);
96 std::string supervised_user_id;
97 #if defined(ENABLE_SUPERVISED_USERS)
98 if (!ProcessSupervisedCreateProfileArgs(args, &supervised_user_id))
99 return;
100 #endif
102 ProfileMetrics::LogProfileAddNewUser(ProfileMetrics::ADD_NEW_USER_DIALOG);
104 profile_path_being_created_ = ProfileManager::CreateMultiProfileAsync(
105 name, icon,
106 base::Bind(&CreateProfileHandler::OnProfileCreated,
107 weak_ptr_factory_.GetWeakPtr(),
108 create_shortcut,
109 helper::GetDesktopType(web_ui()),
110 supervised_user_id),
111 supervised_user_id);
114 void CreateProfileHandler::OnProfileCreated(
115 bool create_shortcut,
116 chrome::HostDesktopType desktop_type,
117 const std::string& supervised_user_id,
118 Profile* profile,
119 Profile::CreateStatus status) {
120 if (status != Profile::CREATE_STATUS_CREATED)
121 RecordProfileCreationMetrics(status);
123 switch (status) {
124 case Profile::CREATE_STATUS_LOCAL_FAIL: {
125 ShowProfileCreationError(profile, GetProfileCreationErrorMessageLocal());
126 break;
128 case Profile::CREATE_STATUS_CREATED: {
129 // Do nothing for an intermediate status.
130 break;
132 case Profile::CREATE_STATUS_INITIALIZED: {
133 HandleProfileCreationSuccess(create_shortcut, desktop_type,
134 supervised_user_id, profile);
135 break;
137 // User-initiated cancellation is handled in CancelProfileRegistration and
138 // does not call this callback.
139 case Profile::CREATE_STATUS_CANCELED:
140 // Supervised user registration errors are handled in
141 // OnSupervisedUserRegistered().
142 case Profile::CREATE_STATUS_REMOTE_FAIL:
143 case Profile::MAX_CREATE_STATUS: {
144 NOTREACHED();
145 break;
150 void CreateProfileHandler::HandleProfileCreationSuccess(
151 bool create_shortcut,
152 chrome::HostDesktopType desktop_type,
153 const std::string& supervised_user_id,
154 Profile* profile) {
155 switch (profile_creation_type_) {
156 case NON_SUPERVISED_PROFILE_CREATION: {
157 DCHECK(supervised_user_id.empty());
158 CreateShortcutAndShowSuccess(create_shortcut, desktop_type, profile);
159 break;
161 #if defined(ENABLE_SUPERVISED_USERS)
162 case SUPERVISED_PROFILE_CREATION:
163 case SUPERVISED_PROFILE_IMPORT:
164 RegisterSupervisedUser(create_shortcut, desktop_type,
165 supervised_user_id, profile);
166 break;
167 #endif
168 case NO_CREATION_IN_PROGRESS:
169 NOTREACHED();
170 break;
174 void CreateProfileHandler::CreateShortcutAndShowSuccess(
175 bool create_shortcut,
176 chrome::HostDesktopType desktop_type,
177 Profile* profile) {
178 if (create_shortcut) {
179 ProfileShortcutManager* shortcut_manager =
180 g_browser_process->profile_manager()->profile_shortcut_manager();
182 if (shortcut_manager)
183 shortcut_manager->CreateProfileShortcut(profile->GetPath());
186 DCHECK_EQ(profile_path_being_created_.value(), profile->GetPath().value());
187 profile_path_being_created_.clear();
188 DCHECK_NE(NO_CREATION_IN_PROGRESS, profile_creation_type_);
189 base::DictionaryValue dict;
190 dict.SetString("name",
191 profile->GetPrefs()->GetString(prefs::kProfileName));
192 dict.Set("filePath", base::CreateFilePathValue(profile->GetPath()));
193 #if defined(ENABLE_SUPERVISED_USERS)
194 bool is_supervised =
195 profile_creation_type_ == SUPERVISED_PROFILE_CREATION ||
196 profile_creation_type_ == SUPERVISED_PROFILE_IMPORT;
197 dict.SetBoolean("isSupervised", is_supervised);
198 #endif
199 web_ui()->CallJavascriptFunction(
200 GetJavascriptMethodName(PROFILE_CREATION_SUCCESS), dict);
202 // If the new profile is a supervised user, instead of opening a new window
203 // right away, a confirmation overlay will be shown by JS from the creation
204 // dialog. If we are importing an existing supervised profile or creating a
205 // new non-supervised user profile we don't show any confirmation, so open
206 // the new window now.
207 bool should_open_new_window = true;
208 #if defined(ENABLE_SUPERVISED_USERS)
209 if (profile_creation_type_ == SUPERVISED_PROFILE_CREATION)
210 should_open_new_window = false;
211 #endif
213 if (should_open_new_window) {
214 // Opening the new window must be the last action, after all callbacks
215 // have been run, to give them a chance to initialize the profile.
216 helper::OpenNewWindowForProfile(desktop_type,
217 profile,
218 Profile::CREATE_STATUS_INITIALIZED);
220 profile_creation_type_ = NO_CREATION_IN_PROGRESS;
223 void CreateProfileHandler::ShowProfileCreationError(
224 Profile* profile,
225 const base::string16& error) {
226 DCHECK_NE(NO_CREATION_IN_PROGRESS, profile_creation_type_);
227 profile_creation_type_ = NO_CREATION_IN_PROGRESS;
228 profile_path_being_created_.clear();
229 web_ui()->CallJavascriptFunction(
230 GetJavascriptMethodName(PROFILE_CREATION_ERROR),
231 base::StringValue(error));
232 // The ProfileManager calls us back with a NULL profile in some cases.
233 if (profile)
234 helper::DeleteProfileAtPath(profile->GetPath(), web_ui());
237 void CreateProfileHandler::RecordProfileCreationMetrics(
238 Profile::CreateStatus status) {
239 UMA_HISTOGRAM_ENUMERATION("Profile.CreateResult",
240 status,
241 Profile::MAX_CREATE_STATUS);
242 UMA_HISTOGRAM_MEDIUM_TIMES(
243 "Profile.CreateTimeNoTimeout",
244 base::TimeTicks::Now() - profile_creation_start_time_);
247 base::string16 CreateProfileHandler::GetProfileCreationErrorMessageLocal()
248 const {
249 int message_id = IDS_PROFILES_CREATE_LOCAL_ERROR;
250 #if defined(ENABLE_SUPERVISED_USERS)
251 // Local errors can occur during supervised profile import.
252 if (profile_creation_type_ == SUPERVISED_PROFILE_IMPORT)
253 message_id = IDS_LEGACY_SUPERVISED_USER_IMPORT_LOCAL_ERROR;
254 #endif
255 return l10n_util::GetStringUTF16(message_id);
258 #if defined(ENABLE_SUPERVISED_USERS)
259 base::string16 CreateProfileHandler::GetProfileCreationErrorMessageRemote()
260 const {
261 return l10n_util::GetStringUTF16(
262 profile_creation_type_ == SUPERVISED_PROFILE_IMPORT ?
263 IDS_LEGACY_SUPERVISED_USER_IMPORT_REMOTE_ERROR :
264 IDS_PROFILES_CREATE_REMOTE_ERROR);
267 base::string16 CreateProfileHandler::GetProfileCreationErrorMessageSignin()
268 const {
269 return l10n_util::GetStringUTF16(
270 profile_creation_type_ == SUPERVISED_PROFILE_IMPORT ?
271 IDS_LEGACY_SUPERVISED_USER_IMPORT_SIGN_IN_ERROR :
272 IDS_PROFILES_CREATE_SIGN_IN_ERROR);
274 #endif
276 std::string CreateProfileHandler::GetJavascriptMethodName(
277 ProfileCreationStatus status) const {
278 switch (profile_creation_type_) {
279 #if defined(ENABLE_SUPERVISED_USERS)
280 case SUPERVISED_PROFILE_IMPORT:
281 switch (status) {
282 case PROFILE_CREATION_SUCCESS:
283 return "BrowserOptions.showSupervisedUserImportSuccess";
284 case PROFILE_CREATION_ERROR:
285 return "BrowserOptions.showSupervisedUserImportError";
287 break;
288 #endif
289 default:
290 switch (status) {
291 case PROFILE_CREATION_SUCCESS:
292 return "BrowserOptions.showCreateProfileSuccess";
293 case PROFILE_CREATION_ERROR:
294 return "BrowserOptions.showCreateProfileError";
296 break;
299 NOTREACHED();
300 return std::string();
303 #if defined(ENABLE_SUPERVISED_USERS)
304 bool CreateProfileHandler::ProcessSupervisedCreateProfileArgs(
305 const base::ListValue* args, std::string* supervised_user_id) {
306 bool supervised_user = false;
307 if (args->GetSize() >= 5) {
308 bool success = args->GetBoolean(3, &supervised_user);
309 DCHECK(success);
311 success = args->GetString(4, supervised_user_id);
312 DCHECK(success);
315 if (supervised_user) {
316 if (!IsValidExistingSupervisedUserId(*supervised_user_id))
317 return false;
319 profile_creation_type_ = SUPERVISED_PROFILE_IMPORT;
320 if (supervised_user_id->empty()) {
321 profile_creation_type_ = SUPERVISED_PROFILE_CREATION;
322 *supervised_user_id =
323 SupervisedUserRegistrationUtility::GenerateNewSupervisedUserId();
325 // If sync is not yet fully initialized, the creation may take extra time,
326 // so show a message. Import doesn't wait for an acknowledgment, so it
327 // won't have the same potential delay.
328 ProfileSyncService* sync_service =
329 ProfileSyncServiceFactory::GetInstance()->GetForProfile(
330 Profile::FromWebUI(web_ui()));
331 ProfileSyncService::SyncStatusSummary status =
332 sync_service->QuerySyncStatusSummary();
333 if (status == ProfileSyncService::DATATYPES_NOT_INITIALIZED) {
334 ShowProfileCreationWarning(l10n_util::GetStringUTF16(
335 IDS_PROFILES_CREATE_SUPERVISED_JUST_SIGNED_IN));
339 return true;
342 void CreateProfileHandler::HandleCancelProfileCreation(
343 const base::ListValue* args) {
344 CancelProfileRegistration(true);
347 // Non-supervised user creation cannot be canceled. (Creating a non-supervised
348 // profile shouldn't take significant time, and it can easily be deleted
349 // afterward.)
350 void CreateProfileHandler::CancelProfileRegistration(bool user_initiated) {
351 if (profile_path_being_created_.empty())
352 return;
354 ProfileManager* manager = g_browser_process->profile_manager();
355 Profile* new_profile = manager->GetProfileByPath(profile_path_being_created_);
356 if (!new_profile || !new_profile->IsSupervised())
357 return;
359 DCHECK(supervised_user_registration_utility_.get());
360 supervised_user_registration_utility_.reset();
362 if (user_initiated) {
363 UMA_HISTOGRAM_MEDIUM_TIMES(
364 "Profile.CreateTimeCanceledNoTimeout",
365 base::TimeTicks::Now() - profile_creation_start_time_);
366 RecordProfileCreationMetrics(Profile::CREATE_STATUS_CANCELED);
369 DCHECK_NE(NO_CREATION_IN_PROGRESS, profile_creation_type_);
370 profile_creation_type_ = NO_CREATION_IN_PROGRESS;
372 // Cancelling registration means the callback passed into
373 // RegisterAndInitSync() won't be called, so the cleanup must be done here.
374 profile_path_being_created_.clear();
375 helper::DeleteProfileAtPath(new_profile->GetPath(), web_ui());
378 void CreateProfileHandler::RegisterSupervisedUser(
379 bool create_shortcut,
380 chrome::HostDesktopType desktop_type,
381 const std::string& supervised_user_id,
382 Profile* new_profile) {
383 DCHECK_EQ(profile_path_being_created_.value(),
384 new_profile->GetPath().value());
386 SupervisedUserService* supervised_user_service =
387 SupervisedUserServiceFactory::GetForProfile(new_profile);
389 // Register the supervised user using the profile of the custodian.
390 supervised_user_registration_utility_ =
391 SupervisedUserRegistrationUtility::Create(Profile::FromWebUI(web_ui()));
392 supervised_user_service->RegisterAndInitSync(
393 supervised_user_registration_utility_.get(),
394 Profile::FromWebUI(web_ui()),
395 supervised_user_id,
396 base::Bind(&CreateProfileHandler::OnSupervisedUserRegistered,
397 weak_ptr_factory_.GetWeakPtr(),
398 create_shortcut,
399 desktop_type,
400 new_profile));
403 void CreateProfileHandler::OnSupervisedUserRegistered(
404 bool create_shortcut,
405 chrome::HostDesktopType desktop_type,
406 Profile* profile,
407 const GoogleServiceAuthError& error) {
408 GoogleServiceAuthError::State state = error.state();
409 RecordSupervisedProfileCreationMetrics(state);
410 if (state == GoogleServiceAuthError::NONE) {
411 CreateShortcutAndShowSuccess(create_shortcut, desktop_type, profile);
412 return;
415 base::string16 error_msg;
416 if (state == GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS ||
417 state == GoogleServiceAuthError::USER_NOT_SIGNED_UP ||
418 state == GoogleServiceAuthError::ACCOUNT_DELETED ||
419 state == GoogleServiceAuthError::ACCOUNT_DISABLED) {
420 error_msg = GetProfileCreationErrorMessageSignin();
421 } else {
422 error_msg = GetProfileCreationErrorMessageRemote();
424 ShowProfileCreationError(profile, error_msg);
427 void CreateProfileHandler::ShowProfileCreationWarning(
428 const base::string16& warning) {
429 DCHECK_EQ(SUPERVISED_PROFILE_CREATION, profile_creation_type_);
430 web_ui()->CallJavascriptFunction("BrowserOptions.showCreateProfileWarning",
431 base::StringValue(warning));
434 void CreateProfileHandler::RecordSupervisedProfileCreationMetrics(
435 GoogleServiceAuthError::State error_state) {
436 if (profile_creation_type_ == SUPERVISED_PROFILE_CREATION) {
437 UMA_HISTOGRAM_ENUMERATION("Profile.SupervisedProfileCreateError",
438 error_state,
439 GoogleServiceAuthError::NUM_STATES);
440 UMA_HISTOGRAM_MEDIUM_TIMES(
441 "Profile.SupervisedProfileTotalCreateTime",
442 base::TimeTicks::Now() - profile_creation_start_time_);
443 } else {
444 DCHECK_EQ(SUPERVISED_PROFILE_IMPORT, profile_creation_type_);
445 UMA_HISTOGRAM_ENUMERATION("Profile.SupervisedProfileImportError",
446 error_state,
447 GoogleServiceAuthError::NUM_STATES);
448 UMA_HISTOGRAM_MEDIUM_TIMES(
449 "Profile.SupervisedProfileTotalImportTime",
450 base::TimeTicks::Now() - profile_creation_start_time_);
454 bool CreateProfileHandler::IsValidExistingSupervisedUserId(
455 const std::string& existing_supervised_user_id) const {
456 if (existing_supervised_user_id.empty())
457 return true;
459 Profile* profile = Profile::FromWebUI(web_ui());
460 const base::DictionaryValue* dict =
461 SupervisedUserSyncServiceFactory::GetForProfile(profile)->
462 GetSupervisedUsers();
463 if (!dict->HasKey(existing_supervised_user_id))
464 return false;
466 // Check if this supervised user already exists on this machine.
467 const ProfileInfoCache& cache =
468 g_browser_process->profile_manager()->GetProfileInfoCache();
469 for (size_t i = 0; i < cache.GetNumberOfProfiles(); ++i) {
470 if (existing_supervised_user_id ==
471 cache.GetSupervisedUserIdOfProfileAtIndex(i))
472 return false;
474 return true;
476 #endif
478 } // namespace options