• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/sync/sync_setup_flow.h"
6 
7 #include "base/callback.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h"
10 #include "base/metrics/histogram.h"
11 #include "base/string_util.h"
12 #include "base/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/platform_util.h"
15 #include "chrome/browser/prefs/pref_service.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/sync/profile_sync_service.h"
18 #include "chrome/browser/sync/sync_setup_flow_handler.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_dialogs.h"
21 #include "chrome/browser/ui/browser_list.h"
22 #include "chrome/common/net/gaia/google_service_auth_error.h"
23 #include "chrome/common/pref_names.h"
24 #include "chrome/common/url_constants.h"
25 #include "content/browser/renderer_host/render_view_host.h"
26 #include "content/browser/tab_contents/tab_contents.h"
27 #include "grit/generated_resources.h"
28 #include "grit/locale_settings.h"
29 #include "ui/base/l10n/l10n_font_util.h"
30 #include "ui/gfx/font.h"
31 
32 namespace {
33 
34 // Helper function to disable password sync.
DisablePasswordSync(ProfileSyncService * service)35 void DisablePasswordSync(ProfileSyncService* service) {
36   syncable::ModelTypeSet types;
37   service->GetPreferredDataTypes(&types);
38   types.erase(syncable::PASSWORDS);
39   service->OnUserChoseDatatypes(false, types);
40 }
41 
42 }  // namespace
43 
SyncConfiguration()44 SyncConfiguration::SyncConfiguration()
45     : sync_everything(false),
46       use_secondary_passphrase(false) {
47 }
48 
~SyncConfiguration()49 SyncConfiguration::~SyncConfiguration() {}
50 
~SyncSetupFlow()51 SyncSetupFlow::~SyncSetupFlow() {
52   flow_handler_->SetFlow(NULL);
53 }
54 
55 // static
Run(ProfileSyncService * service,SyncSetupFlowContainer * container,SyncSetupWizard::State start,SyncSetupWizard::State end)56 SyncSetupFlow* SyncSetupFlow::Run(ProfileSyncService* service,
57                                   SyncSetupFlowContainer* container,
58                                   SyncSetupWizard::State start,
59                                   SyncSetupWizard::State end) {
60   DictionaryValue args;
61   if (start == SyncSetupWizard::GAIA_LOGIN)
62     SyncSetupFlow::GetArgsForGaiaLogin(service, &args);
63   else if (start == SyncSetupWizard::CONFIGURE)
64     SyncSetupFlow::GetArgsForConfigure(service, &args);
65   else if (start == SyncSetupWizard::ENTER_PASSPHRASE)
66     SyncSetupFlow::GetArgsForEnterPassphrase(false, false, &args);
67   else if (start == SyncSetupWizard::PASSPHRASE_MIGRATION)
68     args.SetString("iframeToShow", "firstpassphrase");
69 
70   std::string json_args;
71   base::JSONWriter::Write(&args, false, &json_args);
72 
73   SyncSetupFlow* flow = new SyncSetupFlow(start, end, json_args,
74       container, service);
75 
76   Browser* b = BrowserList::GetLastActive();
77   b->ShowOptionsTab(chrome::kSyncSetupSubPage);
78   return flow;
79 }
80 
81 // static
GetArgsForGaiaLogin(const ProfileSyncService * service,DictionaryValue * args)82 void SyncSetupFlow::GetArgsForGaiaLogin(const ProfileSyncService* service,
83                                         DictionaryValue* args) {
84   args->SetString("iframeToShow", "login");
85   const GoogleServiceAuthError& error = service->GetAuthError();
86   if (!service->last_attempted_user_email().empty()) {
87     args->SetString("user", service->last_attempted_user_email());
88     args->SetInteger("error", error.state());
89     args->SetBoolean("editable_user", true);
90   } else {
91     string16 user;
92     if (!service->cros_user().empty())
93       user = UTF8ToUTF16(service->cros_user());
94     else
95       user = service->GetAuthenticatedUsername();
96     args->SetString("user", user);
97     args->SetInteger("error", 0);
98     args->SetBoolean("editable_user", user.empty());
99   }
100 
101   args->SetString("captchaUrl", error.captcha().image_url.spec());
102 }
103 
104 // static
GetArgsForConfigure(ProfileSyncService * service,DictionaryValue * args)105 void SyncSetupFlow::GetArgsForConfigure(ProfileSyncService* service,
106                                         DictionaryValue* args) {
107   args->SetString("iframeToShow", "configure");
108 
109   // The SYNC_EVERYTHING case will set this to true.
110   args->SetBoolean("syncEverything", false);
111 
112   args->SetBoolean("keepEverythingSynced",
113       service->profile()->GetPrefs()->GetBoolean(prefs::kKeepEverythingSynced));
114 
115   // Bookmarks, Preferences, and Themes are launched for good, there's no
116   // going back now.  Check if the other data types are registered though.
117   syncable::ModelTypeSet registered_types;
118   service->GetRegisteredDataTypes(&registered_types);
119   args->SetBoolean("passwordsRegistered",
120       registered_types.count(syncable::PASSWORDS) > 0);
121   args->SetBoolean("autofillRegistered",
122       registered_types.count(syncable::AUTOFILL) > 0);
123   args->SetBoolean("extensionsRegistered",
124       registered_types.count(syncable::EXTENSIONS) > 0);
125   args->SetBoolean("typedUrlsRegistered",
126       registered_types.count(syncable::TYPED_URLS) > 0);
127   args->SetBoolean("appsRegistered",
128       registered_types.count(syncable::APPS) > 0);
129   args->SetBoolean("sessionsRegistered",
130       registered_types.count(syncable::SESSIONS) > 0);
131   args->SetBoolean("syncBookmarks",
132       service->profile()->GetPrefs()->GetBoolean(prefs::kSyncBookmarks));
133   args->SetBoolean("syncPreferences",
134       service->profile()->GetPrefs()->GetBoolean(prefs::kSyncPreferences));
135   args->SetBoolean("syncThemes",
136       service->profile()->GetPrefs()->GetBoolean(prefs::kSyncThemes));
137   args->SetBoolean("syncPasswords",
138       service->profile()->GetPrefs()->GetBoolean(prefs::kSyncPasswords));
139   args->SetBoolean("syncAutofill",
140       service->profile()->GetPrefs()->GetBoolean(prefs::kSyncAutofill));
141   args->SetBoolean("syncExtensions",
142       service->profile()->GetPrefs()->GetBoolean(prefs::kSyncExtensions));
143   args->SetBoolean("syncSessions",
144       service->profile()->GetPrefs()->GetBoolean(prefs::kSyncSessions));
145   args->SetBoolean("syncTypedUrls",
146       service->profile()->GetPrefs()->GetBoolean(prefs::kSyncTypedUrls));
147   args->SetBoolean("syncApps",
148       service->profile()->GetPrefs()->GetBoolean(prefs::kSyncApps));
149 
150   // Load the parameters for the encryption tab.
151   args->SetBoolean("usePassphrase", service->IsUsingSecondaryPassphrase());
152 }
153 
154 // static
GetArgsForEnterPassphrase(bool tried_creating_explicit_passphrase,bool tried_setting_explicit_passphrase,DictionaryValue * args)155 void SyncSetupFlow::GetArgsForEnterPassphrase(
156     bool tried_creating_explicit_passphrase,
157     bool tried_setting_explicit_passphrase,
158     DictionaryValue* args) {
159   args->SetString("iframeToShow", "passphrase");
160   args->SetBoolean("passphrase_creation_rejected",
161                    tried_creating_explicit_passphrase);
162   args->SetBoolean("passphrase_setting_rejected",
163                    tried_setting_explicit_passphrase);
164 }
165 
AttachSyncSetupHandler(SyncSetupFlowHandler * handler)166 void SyncSetupFlow::AttachSyncSetupHandler(SyncSetupFlowHandler* handler) {
167   flow_handler_ = handler;
168   ActivateState(current_state_);
169 }
170 
Advance(SyncSetupWizard::State advance_state)171 void SyncSetupFlow::Advance(SyncSetupWizard::State advance_state) {
172   if (!ShouldAdvance(advance_state)) {
173     LOG(WARNING) << "Invalid state change from "
174                  << current_state_ << " to " << advance_state;
175     return;
176   }
177 
178   ActivateState(advance_state);
179 }
180 
Focus()181 void SyncSetupFlow::Focus() {
182   // TODO(jhawkins): Implement this.
183 }
184 
185 // A callback to notify the delegate that the dialog closed.
OnDialogClosed(const std::string & json_retval)186 void SyncSetupFlow::OnDialogClosed(const std::string& json_retval) {
187   DCHECK(json_retval.empty());
188   container_->set_flow(NULL);  // Sever ties from the wizard.
189   if (current_state_ == SyncSetupWizard::DONE ||
190       current_state_ == SyncSetupWizard::DONE_FIRST_TIME) {
191     service_->SetSyncSetupCompleted();
192   }
193 
194   // Record the state at which the user cancelled the signon dialog.
195   switch (current_state_) {
196     case SyncSetupWizard::GAIA_LOGIN:
197       ProfileSyncService::SyncEvent(
198           ProfileSyncService::CANCEL_FROM_SIGNON_WITHOUT_AUTH);
199       break;
200     case SyncSetupWizard::GAIA_SUCCESS:
201       ProfileSyncService::SyncEvent(
202           ProfileSyncService::CANCEL_DURING_SIGNON);
203       break;
204     case SyncSetupWizard::CONFIGURE:
205     case SyncSetupWizard::ENTER_PASSPHRASE:
206     case SyncSetupWizard::SETTING_UP:
207       // TODO(atwilson): Treat a close during ENTER_PASSPHRASE like a
208       // Cancel + Skip (i.e. call OnPassphraseCancel()). http://crbug.com/74645
209       ProfileSyncService::SyncEvent(
210           ProfileSyncService::CANCEL_DURING_CONFIGURE);
211       break;
212     case SyncSetupWizard::DONE_FIRST_TIME:
213     case SyncSetupWizard::DONE:
214       // TODO(sync): rename this histogram; it's tracking authorization AND
215       // initial sync download time.
216       UMA_HISTOGRAM_MEDIUM_TIMES("Sync.UserPerceivedAuthorizationTime",
217                                  base::TimeTicks::Now() - login_start_time_);
218       break;
219     default:
220       break;
221   }
222 
223   service_->OnUserCancelledDialog();
224   delete this;
225 }
226 
OnUserSubmittedAuth(const std::string & username,const std::string & password,const std::string & captcha,const std::string & access_code)227 void SyncSetupFlow::OnUserSubmittedAuth(const std::string& username,
228                                         const std::string& password,
229                                         const std::string& captcha,
230                                         const std::string& access_code) {
231   service_->OnUserSubmittedAuth(username, password, captcha, access_code);
232 }
233 
OnUserConfigured(const SyncConfiguration & configuration)234 void SyncSetupFlow::OnUserConfigured(const SyncConfiguration& configuration) {
235   // Go to the "loading..." screen.
236   Advance(SyncSetupWizard::SETTING_UP);
237 
238   // If we are activating the passphrase, we need to have one supplied.
239   DCHECK(service_->IsUsingSecondaryPassphrase() ||
240          !configuration.use_secondary_passphrase ||
241          configuration.secondary_passphrase.length() > 0);
242 
243   if (configuration.use_secondary_passphrase &&
244       !service_->IsUsingSecondaryPassphrase()) {
245     service_->SetPassphrase(configuration.secondary_passphrase, true, true);
246     tried_creating_explicit_passphrase_ = true;
247   }
248 
249   service_->OnUserChoseDatatypes(configuration.sync_everything,
250                                  configuration.data_types);
251 }
252 
OnPassphraseEntry(const std::string & passphrase)253 void SyncSetupFlow::OnPassphraseEntry(const std::string& passphrase) {
254   Advance(SyncSetupWizard::SETTING_UP);
255   service_->SetPassphrase(passphrase, true, false);
256   tried_setting_explicit_passphrase_ = true;
257 }
258 
OnPassphraseCancel()259 void SyncSetupFlow::OnPassphraseCancel() {
260   // If the user cancels when being asked for the passphrase,
261   // just disable encrypted sync and continue setting up.
262   if (current_state_ == SyncSetupWizard::ENTER_PASSPHRASE)
263     DisablePasswordSync(service_);
264 
265   Advance(SyncSetupWizard::SETTING_UP);
266 }
267 
268 // TODO(jhawkins): Remove this method.
OnFirstPassphraseEntry(const std::string & option,const std::string & passphrase)269 void SyncSetupFlow::OnFirstPassphraseEntry(const std::string& option,
270                                            const std::string& passphrase) {
271   NOTREACHED();
272 }
273 
274 // TODO(jhawkins): Use this method instead of a direct link in the html.
OnGoToDashboard()275 void SyncSetupFlow::OnGoToDashboard() {
276   BrowserList::GetLastActive()->OpenPrivacyDashboardTabAndActivate();
277 }
278 
279 // Use static Run method to get an instance.
SyncSetupFlow(SyncSetupWizard::State start_state,SyncSetupWizard::State end_state,const std::string & args,SyncSetupFlowContainer * container,ProfileSyncService * service)280 SyncSetupFlow::SyncSetupFlow(SyncSetupWizard::State start_state,
281                              SyncSetupWizard::State end_state,
282                              const std::string& args,
283                              SyncSetupFlowContainer* container,
284                              ProfileSyncService* service)
285     : container_(container),
286       dialog_start_args_(args),
287       current_state_(start_state),
288       end_state_(end_state),
289       login_start_time_(base::TimeTicks::Now()),
290       flow_handler_(NULL),
291       service_(service),
292       tried_creating_explicit_passphrase_(false),
293       tried_setting_explicit_passphrase_(false) {
294 }
295 
296 // Returns true if the flow should advance to |state| based on |current_state_|.
ShouldAdvance(SyncSetupWizard::State state)297 bool SyncSetupFlow::ShouldAdvance(SyncSetupWizard::State state) {
298   switch (state) {
299     case SyncSetupWizard::GAIA_LOGIN:
300       return current_state_ == SyncSetupWizard::FATAL_ERROR ||
301              current_state_ == SyncSetupWizard::GAIA_LOGIN ||
302              current_state_ == SyncSetupWizard::SETTING_UP;
303     case SyncSetupWizard::GAIA_SUCCESS:
304       return current_state_ == SyncSetupWizard::GAIA_LOGIN;
305     case SyncSetupWizard::SYNC_EVERYTHING:
306     case SyncSetupWizard::CONFIGURE:
307       return current_state_ == SyncSetupWizard::GAIA_SUCCESS;
308     case SyncSetupWizard::ENTER_PASSPHRASE:
309       return current_state_ == SyncSetupWizard::SYNC_EVERYTHING ||
310              current_state_ == SyncSetupWizard::CONFIGURE ||
311              current_state_ == SyncSetupWizard::SETTING_UP;
312     case SyncSetupWizard::PASSPHRASE_MIGRATION:
313       return current_state_ == SyncSetupWizard::GAIA_LOGIN;
314     case SyncSetupWizard::SETUP_ABORTED_BY_PENDING_CLEAR:
315       DCHECK(current_state_ != SyncSetupWizard::GAIA_LOGIN &&
316              current_state_ != SyncSetupWizard::GAIA_SUCCESS);
317       return true;
318     case SyncSetupWizard::SETTING_UP:
319       return current_state_ == SyncSetupWizard::SYNC_EVERYTHING ||
320              current_state_ == SyncSetupWizard::CONFIGURE ||
321              current_state_ == SyncSetupWizard::ENTER_PASSPHRASE ||
322              current_state_ == SyncSetupWizard::PASSPHRASE_MIGRATION;
323     case SyncSetupWizard::FATAL_ERROR:
324       return true;  // You can always hit the panic button.
325     case SyncSetupWizard::DONE_FIRST_TIME:
326     case SyncSetupWizard::DONE:
327       return current_state_ == SyncSetupWizard::SETTING_UP ||
328              current_state_ == SyncSetupWizard::ENTER_PASSPHRASE;
329     default:
330       NOTREACHED() << "Unhandled State: " << state;
331       return false;
332   }
333 }
334 
ActivateState(SyncSetupWizard::State state)335 void SyncSetupFlow::ActivateState(SyncSetupWizard::State state) {
336   switch (state) {
337     case SyncSetupWizard::GAIA_LOGIN: {
338       DictionaryValue args;
339       SyncSetupFlow::GetArgsForGaiaLogin(service_, &args);
340       flow_handler_->ShowGaiaLogin(args);
341       break;
342     }
343     case SyncSetupWizard::GAIA_SUCCESS:
344       if (end_state_ == SyncSetupWizard::GAIA_SUCCESS) {
345         flow_handler_->ShowGaiaSuccessAndClose();
346         break;
347       }
348       state = SyncSetupWizard::SYNC_EVERYTHING;
349       //  Fall through.
350     case SyncSetupWizard::SYNC_EVERYTHING: {
351       DictionaryValue args;
352       SyncSetupFlow::GetArgsForConfigure(service_, &args);
353       args.SetBoolean("syncEverything", true);
354       flow_handler_->ShowConfigure(args);
355       break;
356     }
357     case SyncSetupWizard::CONFIGURE: {
358       DictionaryValue args;
359       SyncSetupFlow::GetArgsForConfigure(service_, &args);
360       flow_handler_->ShowConfigure(args);
361       break;
362     }
363     case SyncSetupWizard::ENTER_PASSPHRASE: {
364       DictionaryValue args;
365       SyncSetupFlow::GetArgsForEnterPassphrase(
366           tried_creating_explicit_passphrase_,
367           tried_setting_explicit_passphrase_,
368           &args);
369       flow_handler_->ShowPassphraseEntry(args);
370       break;
371     }
372     case SyncSetupWizard::PASSPHRASE_MIGRATION: {
373       DictionaryValue args;
374       args.SetString("iframeToShow", "firstpassphrase");
375       flow_handler_->ShowFirstPassphrase(args);
376       break;
377     }
378     case SyncSetupWizard::SETUP_ABORTED_BY_PENDING_CLEAR: {
379       DictionaryValue args;
380       SyncSetupFlow::GetArgsForConfigure(service_, &args);
381       args.SetBoolean("was_aborted", true);
382       flow_handler_->ShowConfigure(args);
383       break;
384     }
385     case SyncSetupWizard::SETTING_UP: {
386       flow_handler_->ShowSettingUp();
387       break;
388     }
389     case SyncSetupWizard::FATAL_ERROR: {
390       // This shows the user the "Could not connect to server" error.
391       // TODO(sync): Update this error messaging.
392       DictionaryValue args;
393       SyncSetupFlow::GetArgsForGaiaLogin(service_, &args);
394       args.SetInteger("error", GoogleServiceAuthError::CONNECTION_FAILED);
395       flow_handler_->ShowGaiaLogin(args);
396       break;
397     }
398     case SyncSetupWizard::DONE_FIRST_TIME:
399       flow_handler_->ShowFirstTimeDone(
400           UTF16ToWide(service_->GetAuthenticatedUsername()));
401       break;
402     case SyncSetupWizard::DONE:
403       flow_handler_->ShowSetupDone(
404           UTF16ToWide(service_->GetAuthenticatedUsername()));
405       break;
406     default:
407       NOTREACHED() << "Invalid advance state: " << state;
408   }
409   current_state_ = state;
410 }
411