• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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