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.
4
5 #include "chrome/browser/ui/webui/options/create_profile_handler.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/files/file_path.h"
10 #include "base/metrics/histogram.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/value_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/managed_mode/managed_user_registration_utility.h"
16 #include "chrome/browser/managed_mode/managed_user_service.h"
17 #include "chrome/browser/managed_mode/managed_user_service_factory.h"
18 #include "chrome/browser/managed_mode/managed_user_sync_service.h"
19 #include "chrome/browser/managed_mode/managed_user_sync_service_factory.h"
20 #include "chrome/browser/profiles/profile_manager.h"
21 #include "chrome/browser/profiles/profile_metrics.h"
22 #include "chrome/browser/profiles/profiles_state.h"
23 #include "chrome/browser/sync/profile_sync_service.h"
24 #include "chrome/browser/sync/profile_sync_service_factory.h"
25 #include "chrome/browser/ui/webui/options/options_handlers_helper.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/pref_names.h"
28 #include "grit/generated_resources.h"
29 #include "ui/base/l10n/l10n_util.h"
30
31 namespace options {
32
CreateProfileHandler()33 CreateProfileHandler::CreateProfileHandler()
34 : profile_creation_type_(NO_CREATION_IN_PROGRESS),
35 weak_ptr_factory_(this) {
36 }
37
~CreateProfileHandler()38 CreateProfileHandler::~CreateProfileHandler() {
39 CancelProfileRegistration(false);
40 }
41
GetLocalizedValues(base::DictionaryValue * localized_strings)42 void CreateProfileHandler::GetLocalizedValues(
43 base::DictionaryValue* localized_strings) {
44 }
45
RegisterMessages()46 void CreateProfileHandler::RegisterMessages() {
47 web_ui()->RegisterMessageCallback(
48 "cancelCreateProfile",
49 base::Bind(&CreateProfileHandler::HandleCancelProfileCreation,
50 base::Unretained(this)));
51 web_ui()->RegisterMessageCallback(
52 "createProfile",
53 base::Bind(&CreateProfileHandler::CreateProfile,
54 base::Unretained(this)));
55 }
56
CreateProfile(const ListValue * args)57 void CreateProfileHandler::CreateProfile(const ListValue* args) {
58 // This handler could have been called in managed mode, for example because
59 // the user fiddled with the web inspector. Silently return in this case.
60 Profile* current_profile = Profile::FromWebUI(web_ui());
61 if (current_profile->IsManaged())
62 return;
63
64 if (!profiles::IsMultipleProfilesEnabled())
65 return;
66
67 // We can have only one in progress profile creation
68 // at any given moment, if new ones are initiated just
69 // ignore them until we are done with the old one.
70 if (profile_creation_type_ != NO_CREATION_IN_PROGRESS)
71 return;
72
73 profile_creation_type_ = NON_SUPERVISED_PROFILE_CREATION;
74
75 DCHECK(profile_path_being_created_.empty());
76 profile_creation_start_time_ = base::TimeTicks::Now();
77
78 base::string16 name;
79 base::string16 icon;
80 std::string managed_user_id;
81 bool create_shortcut = false;
82 bool managed_user = false;
83 if (args->GetString(0, &name) && args->GetString(1, &icon)) {
84 if (args->GetBoolean(2, &create_shortcut)) {
85 bool success = args->GetBoolean(3, &managed_user);
86 DCHECK(success);
87 success = args->GetString(4, &managed_user_id);
88 DCHECK(success);
89 }
90 }
91
92 if (managed_user) {
93 if (!IsValidExistingManagedUserId(managed_user_id))
94 return;
95
96 profile_creation_type_ = SUPERVISED_PROFILE_IMPORT;
97 if (managed_user_id.empty()) {
98 profile_creation_type_ = SUPERVISED_PROFILE_CREATION;
99 managed_user_id =
100 ManagedUserRegistrationUtility::GenerateNewManagedUserId();
101
102 // If sync is not yet fully initialized, the creation may take extra time,
103 // so show a message. Import doesn't wait for an acknowledgement, so it
104 // won't have the same potential delay.
105 ProfileSyncService* sync_service =
106 ProfileSyncServiceFactory::GetInstance()->GetForProfile(
107 current_profile);
108 ProfileSyncService::SyncStatusSummary status =
109 sync_service->QuerySyncStatusSummary();
110 if (status == ProfileSyncService::DATATYPES_NOT_INITIALIZED) {
111 ShowProfileCreationWarning(l10n_util::GetStringUTF16(
112 IDS_PROFILES_CREATE_MANAGED_JUST_SIGNED_IN));
113 }
114 }
115 }
116
117 ProfileMetrics::LogProfileAddNewUser(ProfileMetrics::ADD_NEW_USER_DIALOG);
118
119 profile_path_being_created_ = ProfileManager::CreateMultiProfileAsync(
120 name, icon,
121 base::Bind(&CreateProfileHandler::OnProfileCreated,
122 weak_ptr_factory_.GetWeakPtr(),
123 create_shortcut,
124 helper::GetDesktopType(web_ui()),
125 managed_user_id),
126 managed_user_id);
127 }
128
OnProfileCreated(bool create_shortcut,chrome::HostDesktopType desktop_type,const std::string & managed_user_id,Profile * profile,Profile::CreateStatus status)129 void CreateProfileHandler::OnProfileCreated(
130 bool create_shortcut,
131 chrome::HostDesktopType desktop_type,
132 const std::string& managed_user_id,
133 Profile* profile,
134 Profile::CreateStatus status) {
135 if (status != Profile::CREATE_STATUS_CREATED)
136 RecordProfileCreationMetrics(status);
137
138 switch (status) {
139 case Profile::CREATE_STATUS_LOCAL_FAIL: {
140 ShowProfileCreationError(profile,
141 GetProfileCreationErrorMessage(LOCAL_ERROR));
142 break;
143 }
144 case Profile::CREATE_STATUS_CREATED: {
145 // Do nothing for an intermediate status.
146 break;
147 }
148 case Profile::CREATE_STATUS_INITIALIZED: {
149 HandleProfileCreationSuccess(create_shortcut, desktop_type,
150 managed_user_id, profile);
151 break;
152 }
153 // User-initiated cancellation is handled in CancelProfileRegistration and
154 // does not call this callback.
155 case Profile::CREATE_STATUS_CANCELED:
156 // Managed user registration errors are handled in
157 // OnManagedUserRegistered().
158 case Profile::CREATE_STATUS_REMOTE_FAIL:
159 case Profile::MAX_CREATE_STATUS: {
160 NOTREACHED();
161 break;
162 }
163 }
164 }
165
HandleProfileCreationSuccess(bool create_shortcut,chrome::HostDesktopType desktop_type,const std::string & managed_user_id,Profile * profile)166 void CreateProfileHandler::HandleProfileCreationSuccess(
167 bool create_shortcut,
168 chrome::HostDesktopType desktop_type,
169 const std::string& managed_user_id,
170 Profile* profile) {
171 switch (profile_creation_type_) {
172 case NON_SUPERVISED_PROFILE_CREATION: {
173 DCHECK(managed_user_id.empty());
174 CreateShortcutAndShowSuccess(create_shortcut, desktop_type, profile);
175 break;
176 }
177 case SUPERVISED_PROFILE_CREATION:
178 case SUPERVISED_PROFILE_IMPORT:
179 RegisterManagedUser(create_shortcut, desktop_type,
180 managed_user_id, profile);
181 break;
182 case NO_CREATION_IN_PROGRESS:
183 NOTREACHED();
184 break;
185 }
186 }
187
RegisterManagedUser(bool create_shortcut,chrome::HostDesktopType desktop_type,const std::string & managed_user_id,Profile * new_profile)188 void CreateProfileHandler::RegisterManagedUser(
189 bool create_shortcut,
190 chrome::HostDesktopType desktop_type,
191 const std::string& managed_user_id,
192 Profile* new_profile) {
193 DCHECK_EQ(profile_path_being_created_.value(),
194 new_profile->GetPath().value());
195
196 ManagedUserService* managed_user_service =
197 ManagedUserServiceFactory::GetForProfile(new_profile);
198
199 // Register the managed user using the profile of the custodian.
200 managed_user_registration_utility_ =
201 ManagedUserRegistrationUtility::Create(Profile::FromWebUI(web_ui()));
202 managed_user_service->RegisterAndInitSync(
203 managed_user_registration_utility_.get(),
204 Profile::FromWebUI(web_ui()),
205 managed_user_id,
206 base::Bind(&CreateProfileHandler::OnManagedUserRegistered,
207 weak_ptr_factory_.GetWeakPtr(),
208 create_shortcut,
209 desktop_type,
210 new_profile));
211 }
212
OnManagedUserRegistered(bool create_shortcut,chrome::HostDesktopType desktop_type,Profile * profile,const GoogleServiceAuthError & error)213 void CreateProfileHandler::OnManagedUserRegistered(
214 bool create_shortcut,
215 chrome::HostDesktopType desktop_type,
216 Profile* profile,
217 const GoogleServiceAuthError& error) {
218 GoogleServiceAuthError::State state = error.state();
219 RecordSupervisedProfileCreationMetrics(state);
220 if (state == GoogleServiceAuthError::NONE) {
221 CreateShortcutAndShowSuccess(create_shortcut, desktop_type, profile);
222 return;
223 }
224
225 base::string16 error_msg;
226 if (state == GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS ||
227 state == GoogleServiceAuthError::USER_NOT_SIGNED_UP ||
228 state == GoogleServiceAuthError::ACCOUNT_DELETED ||
229 state == GoogleServiceAuthError::ACCOUNT_DISABLED) {
230 error_msg = GetProfileCreationErrorMessage(SIGNIN_ERROR);
231 } else {
232 error_msg = GetProfileCreationErrorMessage(REMOTE_ERROR);
233 }
234 ShowProfileCreationError(profile, error_msg);
235 }
236
CreateShortcutAndShowSuccess(bool create_shortcut,chrome::HostDesktopType desktop_type,Profile * profile)237 void CreateProfileHandler::CreateShortcutAndShowSuccess(
238 bool create_shortcut,
239 chrome::HostDesktopType desktop_type,
240 Profile* profile) {
241 if (create_shortcut) {
242 ProfileShortcutManager* shortcut_manager =
243 g_browser_process->profile_manager()->profile_shortcut_manager();
244
245 if (shortcut_manager)
246 shortcut_manager->CreateProfileShortcut(profile->GetPath());
247 }
248
249 DCHECK_EQ(profile_path_being_created_.value(), profile->GetPath().value());
250 profile_path_being_created_.clear();
251 DCHECK_NE(NO_CREATION_IN_PROGRESS, profile_creation_type_);
252 DictionaryValue dict;
253 dict.SetString("name",
254 profile->GetPrefs()->GetString(prefs::kProfileName));
255 dict.Set("filePath", base::CreateFilePathValue(profile->GetPath()));
256 bool is_managed =
257 profile_creation_type_ == SUPERVISED_PROFILE_CREATION ||
258 profile_creation_type_ == SUPERVISED_PROFILE_IMPORT;
259 dict.SetBoolean("isManaged", is_managed);
260 web_ui()->CallJavascriptFunction(
261 GetJavascriptMethodName(PROFILE_CREATION_SUCCESS), dict);
262
263 // If the new profile is a supervised user, instead of opening a new window
264 // right away, a confirmation overlay will be shown by JS from the creation
265 // dialog. If we are importing an existing supervised profile or creating a
266 // new non-supervised user profile we don't show any confirmation, so open
267 // the new window now.
268 if (profile_creation_type_ != SUPERVISED_PROFILE_CREATION) {
269 // Opening the new window must be the last action, after all callbacks
270 // have been run, to give them a chance to initialize the profile.
271 helper::OpenNewWindowForProfile(desktop_type,
272 profile,
273 Profile::CREATE_STATUS_INITIALIZED);
274 }
275 profile_creation_type_ = NO_CREATION_IN_PROGRESS;
276 }
277
ShowProfileCreationError(Profile * profile,const base::string16 & error)278 void CreateProfileHandler::ShowProfileCreationError(
279 Profile* profile,
280 const base::string16& error) {
281 DCHECK_NE(NO_CREATION_IN_PROGRESS, profile_creation_type_);
282 profile_creation_type_ = NO_CREATION_IN_PROGRESS;
283 profile_path_being_created_.clear();
284 web_ui()->CallJavascriptFunction(
285 GetJavascriptMethodName(PROFILE_CREATION_ERROR),
286 base::StringValue(error));
287 helper::DeleteProfileAtPath(profile->GetPath(), web_ui());
288 }
289
ShowProfileCreationWarning(const base::string16 & warning)290 void CreateProfileHandler::ShowProfileCreationWarning(
291 const base::string16& warning) {
292 DCHECK_EQ(SUPERVISED_PROFILE_CREATION, profile_creation_type_);
293 web_ui()->CallJavascriptFunction("BrowserOptions.showCreateProfileWarning",
294 base::StringValue(warning));
295 }
296
HandleCancelProfileCreation(const ListValue * args)297 void CreateProfileHandler::HandleCancelProfileCreation(const ListValue* args) {
298 CancelProfileRegistration(true);
299 }
300
CancelProfileRegistration(bool user_initiated)301 void CreateProfileHandler::CancelProfileRegistration(bool user_initiated) {
302 if (profile_path_being_created_.empty())
303 return;
304
305 ProfileManager* manager = g_browser_process->profile_manager();
306 Profile* new_profile = manager->GetProfileByPath(profile_path_being_created_);
307 if (!new_profile)
308 return;
309
310 // Non-managed user creation cannot be canceled. (Creating a non-managed
311 // profile shouldn't take significant time, and it can easily be deleted
312 // afterward.)
313 if (!new_profile->IsManaged())
314 return;
315
316 if (user_initiated) {
317 UMA_HISTOGRAM_MEDIUM_TIMES(
318 "Profile.CreateTimeCanceledNoTimeout",
319 base::TimeTicks::Now() - profile_creation_start_time_);
320 RecordProfileCreationMetrics(Profile::CREATE_STATUS_CANCELED);
321 }
322
323 DCHECK(managed_user_registration_utility_.get());
324 managed_user_registration_utility_.reset();
325
326 DCHECK_NE(NO_CREATION_IN_PROGRESS, profile_creation_type_);
327 profile_creation_type_ = NO_CREATION_IN_PROGRESS;
328
329 // Cancelling registration means the callback passed into
330 // RegisterAndInitSync() won't be called, so the cleanup must be done here.
331 profile_path_being_created_.clear();
332 helper::DeleteProfileAtPath(new_profile->GetPath(), web_ui());
333 }
334
RecordProfileCreationMetrics(Profile::CreateStatus status)335 void CreateProfileHandler::RecordProfileCreationMetrics(
336 Profile::CreateStatus status) {
337 UMA_HISTOGRAM_ENUMERATION("Profile.CreateResult",
338 status,
339 Profile::MAX_CREATE_STATUS);
340 UMA_HISTOGRAM_MEDIUM_TIMES(
341 "Profile.CreateTimeNoTimeout",
342 base::TimeTicks::Now() - profile_creation_start_time_);
343 }
344
RecordSupervisedProfileCreationMetrics(GoogleServiceAuthError::State error_state)345 void CreateProfileHandler::RecordSupervisedProfileCreationMetrics(
346 GoogleServiceAuthError::State error_state) {
347 if (profile_creation_type_ == SUPERVISED_PROFILE_CREATION) {
348 UMA_HISTOGRAM_ENUMERATION("Profile.SupervisedProfileCreateError",
349 error_state,
350 GoogleServiceAuthError::NUM_STATES);
351 UMA_HISTOGRAM_MEDIUM_TIMES(
352 "Profile.SupervisedProfileTotalCreateTime",
353 base::TimeTicks::Now() - profile_creation_start_time_);
354 } else {
355 DCHECK_EQ(SUPERVISED_PROFILE_IMPORT, profile_creation_type_);
356 UMA_HISTOGRAM_ENUMERATION("Profile.SupervisedProfileImportError",
357 error_state,
358 GoogleServiceAuthError::NUM_STATES);
359 UMA_HISTOGRAM_MEDIUM_TIMES(
360 "Profile.SupervisedProfileTotalImportTime",
361 base::TimeTicks::Now() - profile_creation_start_time_);
362 }
363 }
364
GetProfileCreationErrorMessage(ProfileCreationErrorType error) const365 base::string16 CreateProfileHandler::GetProfileCreationErrorMessage(
366 ProfileCreationErrorType error) const {
367 int message_id = -1;
368 switch (error) {
369 case SIGNIN_ERROR:
370 message_id =
371 profile_creation_type_ == SUPERVISED_PROFILE_IMPORT ?
372 IDS_MANAGED_USER_IMPORT_SIGN_IN_ERROR :
373 IDS_PROFILES_CREATE_SIGN_IN_ERROR;
374 break;
375 case REMOTE_ERROR:
376 message_id =
377 profile_creation_type_ == SUPERVISED_PROFILE_IMPORT ?
378 IDS_MANAGED_USER_IMPORT_REMOTE_ERROR :
379 IDS_PROFILES_CREATE_REMOTE_ERROR;
380 break;
381 case LOCAL_ERROR:
382 message_id =
383 profile_creation_type_ == SUPERVISED_PROFILE_IMPORT ?
384 IDS_MANAGED_USER_IMPORT_LOCAL_ERROR :
385 IDS_PROFILES_CREATE_LOCAL_ERROR;
386 break;
387 }
388
389 return l10n_util::GetStringUTF16(message_id);
390 }
391
GetJavascriptMethodName(ProfileCreationStatus status) const392 std::string CreateProfileHandler::GetJavascriptMethodName(
393 ProfileCreationStatus status) const {
394 switch (status) {
395 case PROFILE_CREATION_SUCCESS:
396 return profile_creation_type_ == SUPERVISED_PROFILE_IMPORT ?
397 "BrowserOptions.showManagedUserImportSuccess" :
398 "BrowserOptions.showCreateProfileSuccess";
399 case PROFILE_CREATION_ERROR:
400 return profile_creation_type_ == SUPERVISED_PROFILE_IMPORT ?
401 "BrowserOptions.showManagedUserImportError" :
402 "BrowserOptions.showCreateProfileError";
403 }
404
405 NOTREACHED();
406 return std::string();
407 }
408
IsValidExistingManagedUserId(const std::string & existing_managed_user_id) const409 bool CreateProfileHandler::IsValidExistingManagedUserId(
410 const std::string& existing_managed_user_id) const {
411 if (existing_managed_user_id.empty())
412 return true;
413
414 if (!CommandLine::ForCurrentProcess()->HasSwitch(
415 switches::kAllowCreateExistingManagedUsers)) {
416 return false;
417 }
418
419 Profile* profile = Profile::FromWebUI(web_ui());
420 const DictionaryValue* dict =
421 ManagedUserSyncServiceFactory::GetForProfile(profile)->GetManagedUsers();
422 if (!dict->HasKey(existing_managed_user_id))
423 return false;
424
425 // Check if this managed user already exists on this machine.
426 const ProfileInfoCache& cache =
427 g_browser_process->profile_manager()->GetProfileInfoCache();
428 for (size_t i = 0; i < cache.GetNumberOfProfiles(); ++i) {
429 if (existing_managed_user_id == cache.GetManagedUserIdOfProfileAtIndex(i))
430 return false;
431 }
432 return true;
433 }
434
435 } // namespace options
436