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/ui/webui/options/sync_setup_handler.h"
6
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/values.h"
10 #include "chrome/browser/google/google_util.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/sync/profile_sync_service.h"
13 #include "chrome/browser/sync/sync_setup_flow.h"
14 #include "grit/chromium_strings.h"
15 #include "grit/generated_resources.h"
16 #include "grit/locale_settings.h"
17 #include "ui/base/l10n/l10n_util.h"
18
19 using l10n_util::GetStringFUTF16;
20 using l10n_util::GetStringUTF16;
21
22 namespace {
23
24 // TODO(jhawkins): Move these to url_constants.h.
25 const char* kInvalidPasswordHelpUrl =
26 "http://www.google.com/support/accounts/bin/answer.py?ctx=ch&answer=27444";
27 const char* kCanNotAccessAccountUrl =
28 "http://www.google.com/support/accounts/bin/answer.py?answer=48598";
29 #if defined(OS_CHROMEOS)
30 const char* kEncryptionHelpUrl =
31 "http://www.google.com/support/chromeos/bin/answer.py?answer=1181035";
32 #else
33 const char* kEncryptionHelpUrl =
34 "http://www.google.com/support/chrome/bin/answer.py?answer=1181035";
35 #endif
36 const char* kCreateNewAccountUrl =
37 "https://www.google.com/accounts/NewAccount?service=chromiumsync";
38
GetAuthData(const std::string & json,std::string * username,std::string * password,std::string * captcha,std::string * access_code)39 bool GetAuthData(const std::string& json,
40 std::string* username,
41 std::string* password,
42 std::string* captcha,
43 std::string* access_code) {
44 scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
45 if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
46 return false;
47
48 DictionaryValue* result = static_cast<DictionaryValue*>(parsed_value.get());
49 if (!result->GetString("user", username) ||
50 !result->GetString("pass", password) ||
51 !result->GetString("captcha", captcha) ||
52 !result->GetString("access_code", access_code)) {
53 return false;
54 }
55 return true;
56 }
57
GetConfiguration(const std::string & json,SyncConfiguration * config)58 bool GetConfiguration(const std::string& json, SyncConfiguration* config) {
59 scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
60 if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
61 return false;
62
63 DictionaryValue* result = static_cast<DictionaryValue*>(parsed_value.get());
64 if (!result->GetBoolean("keepEverythingSynced", &config->sync_everything))
65 return false;
66
67 // These values need to be kept in sync with where they are written in
68 // choose_datatypes.html.
69 bool sync_bookmarks;
70 if (!result->GetBoolean("syncBookmarks", &sync_bookmarks))
71 return false;
72 if (sync_bookmarks)
73 config->data_types.insert(syncable::BOOKMARKS);
74
75 bool sync_preferences;
76 if (!result->GetBoolean("syncPreferences", &sync_preferences))
77 return false;
78 if (sync_preferences)
79 config->data_types.insert(syncable::PREFERENCES);
80
81 bool sync_themes;
82 if (!result->GetBoolean("syncThemes", &sync_themes))
83 return false;
84 if (sync_themes)
85 config->data_types.insert(syncable::THEMES);
86
87 bool sync_passwords;
88 if (!result->GetBoolean("syncPasswords", &sync_passwords))
89 return false;
90 if (sync_passwords)
91 config->data_types.insert(syncable::PASSWORDS);
92
93 bool sync_autofill;
94 if (!result->GetBoolean("syncAutofill", &sync_autofill))
95 return false;
96 if (sync_autofill)
97 config->data_types.insert(syncable::AUTOFILL);
98
99 bool sync_extensions;
100 if (!result->GetBoolean("syncExtensions", &sync_extensions))
101 return false;
102 if (sync_extensions)
103 config->data_types.insert(syncable::EXTENSIONS);
104
105 bool sync_typed_urls;
106 if (!result->GetBoolean("syncTypedUrls", &sync_typed_urls))
107 return false;
108 if (sync_typed_urls)
109 config->data_types.insert(syncable::TYPED_URLS);
110
111 bool sync_sessions;
112 if (!result->GetBoolean("syncSessions", &sync_sessions))
113 return false;
114 if (sync_sessions)
115 config->data_types.insert(syncable::SESSIONS);
116
117 bool sync_apps;
118 if (!result->GetBoolean("syncApps", &sync_apps))
119 return false;
120 if (sync_apps)
121 config->data_types.insert(syncable::APPS);
122
123 // Encryption settings.
124 if (!result->GetBoolean("usePassphrase", &config->use_secondary_passphrase))
125 return false;
126 if (config->use_secondary_passphrase &&
127 !result->GetString("passphrase", &config->secondary_passphrase))
128 return false;
129
130 return true;
131 }
132
GetPassphrase(const std::string & json,std::string * passphrase)133 bool GetPassphrase(const std::string& json, std::string* passphrase) {
134 scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
135 if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
136 return false;
137
138 DictionaryValue* result = static_cast<DictionaryValue*>(parsed_value.get());
139 return result->GetString("passphrase", passphrase);
140 }
141
GetFirstPassphrase(const std::string & json,std::string * option,std::string * passphrase)142 bool GetFirstPassphrase(const std::string& json,
143 std::string* option,
144 std::string* passphrase) {
145 scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
146 if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
147 return false;
148
149 DictionaryValue* result = static_cast<DictionaryValue*>(parsed_value.get());
150 return result->GetString("option", option) &&
151 result->GetString("passphrase", passphrase);
152 }
153
154 } // namespace
155
SyncSetupHandler()156 SyncSetupHandler::SyncSetupHandler() : flow_(NULL) {
157 }
158
~SyncSetupHandler()159 SyncSetupHandler::~SyncSetupHandler() {
160 }
161
GetLocalizedValues(DictionaryValue * localized_strings)162 void SyncSetupHandler::GetLocalizedValues(DictionaryValue* localized_strings) {
163 DCHECK(localized_strings);
164
165 localized_strings->SetString(
166 "invalidpasswordhelpurl",
167 google_util::StringAppendGoogleLocaleParam(kInvalidPasswordHelpUrl));
168 localized_strings->SetString(
169 "cannotaccessaccounturl",
170 google_util::StringAppendGoogleLocaleParam(kCanNotAccessAccountUrl));
171 localized_strings->SetString(
172 "createnewaccounturl",
173 google_util::StringAppendGoogleLocaleParam(kCreateNewAccountUrl));
174 localized_strings->SetString(
175 "introduction",
176 GetStringFUTF16(IDS_SYNC_LOGIN_INTRODUCTION,
177 GetStringUTF16(IDS_PRODUCT_NAME)));
178 localized_strings->SetString(
179 "choosedatatypesinstructions",
180 GetStringFUTF16(IDS_SYNC_CHOOSE_DATATYPES_INSTRUCTIONS,
181 GetStringUTF16(IDS_PRODUCT_NAME)));
182 localized_strings->SetString(
183 "encryptionInstructions",
184 GetStringFUTF16(IDS_SYNC_ENCRYPTION_INSTRUCTIONS,
185 GetStringUTF16(IDS_PRODUCT_NAME)));
186 localized_strings->SetString(
187 "encryptionhelpurl",
188 google_util::StringAppendGoogleLocaleParam(kEncryptionHelpUrl));
189 localized_strings->SetString(
190 "passphraseEncryptionMessage",
191 GetStringFUTF16(IDS_SYNC_PASSPHRASE_ENCRYPTION_MESSAGE,
192 GetStringUTF16(IDS_PRODUCT_NAME)));
193
194 static OptionsStringResource resources[] = {
195 { "syncSetupOverlayTitle", IDS_SYNC_SETUP_TITLE },
196 { "syncSetupConfigureTitle", IDS_SYNC_SETUP_CONFIGURE_TITLE },
197 { "signinprefix", IDS_SYNC_LOGIN_SIGNIN_PREFIX },
198 { "signinsuffix", IDS_SYNC_LOGIN_SIGNIN_SUFFIX },
199 { "cannotbeblank", IDS_SYNC_CANNOT_BE_BLANK },
200 { "emaillabel", IDS_SYNC_LOGIN_EMAIL },
201 { "passwordlabel", IDS_SYNC_LOGIN_PASSWORD },
202 { "invalidcredentials", IDS_SYNC_INVALID_USER_CREDENTIALS },
203 { "signin", IDS_SYNC_SIGNIN },
204 { "couldnotconnect", IDS_SYNC_LOGIN_COULD_NOT_CONNECT },
205 { "cannotaccessaccount", IDS_SYNC_CANNOT_ACCESS_ACCOUNT },
206 { "createaccount", IDS_SYNC_CREATE_ACCOUNT },
207 { "cancel", IDS_CANCEL },
208 { "settingup", IDS_SYNC_LOGIN_SETTING_UP },
209 { "settingupsync", IDS_SYNC_LOGIN_SETTING_UP_SYNC },
210 { "errorsigningin", IDS_SYNC_ERROR_SIGNING_IN },
211 { "captchainstructions", IDS_SYNC_GAIA_CAPTCHA_INSTRUCTIONS },
212 { "invalidaccesscode", IDS_SYNC_INVALID_ACCESS_CODE_LABEL },
213 { "enteraccesscode", IDS_SYNC_ENTER_ACCESS_CODE_LABEL },
214 { "getaccesscodehelp", IDS_SYNC_ACCESS_CODE_HELP_LABEL },
215 { "getaccesscodeurl", IDS_SYNC_GET_ACCESS_CODE_URL },
216 { "dataTypes", IDS_SYNC_DATA_TYPES_TAB_NAME },
217 { "encryption", IDS_SYNC_ENCRYPTION_TAB_NAME },
218 { "choosedatatypesheader", IDS_SYNC_CHOOSE_DATATYPES_HEADER },
219 { "keepeverythingsynced", IDS_SYNC_EVERYTHING },
220 { "choosedatatypes", IDS_SYNC_CHOOSE_DATATYPES },
221 { "bookmarks", IDS_SYNC_DATATYPE_BOOKMARKS },
222 { "preferences", IDS_SYNC_DATATYPE_PREFERENCES },
223 { "autofill", IDS_SYNC_DATATYPE_AUTOFILL },
224 { "themes", IDS_SYNC_DATATYPE_THEMES },
225 { "passwords", IDS_SYNC_DATATYPE_PASSWORDS },
226 { "extensions", IDS_SYNC_DATATYPE_EXTENSIONS },
227 { "typedurls", IDS_SYNC_DATATYPE_TYPED_URLS },
228 { "apps", IDS_SYNC_DATATYPE_APPS },
229 { "foreignsessions", IDS_SYNC_DATATYPE_SESSIONS },
230 { "synczerodatatypeserror", IDS_SYNC_ZERO_DATA_TYPES_ERROR },
231 { "abortederror", IDS_SYNC_SETUP_ABORTED_BY_PENDING_CLEAR },
232 { "encryptAllLabel", IDS_SYNC_ENCRYPT_ALL_LABEL },
233 { "googleOption", IDS_SYNC_PASSPHRASE_OPT_GOOGLE },
234 { "explicitOption", IDS_SYNC_PASSPHRASE_OPT_EXPLICIT },
235 { "sectionGoogleMessage", IDS_SYNC_PASSPHRASE_MSG_GOOGLE },
236 { "sectionExplicitMessage", IDS_SYNC_PASSPHRASE_MSG_EXPLICIT },
237 { "passphraseLabel", IDS_SYNC_PASSPHRASE_LABEL },
238 { "confirmLabel", IDS_SYNC_CONFIRM_PASSPHRASE_LABEL },
239 { "emptyErrorMessage", IDS_SYNC_EMPTY_PASSPHRASE_ERROR },
240 { "mismatchErrorMessage", IDS_SYNC_PASSPHRASE_MISMATCH_ERROR },
241 { "passphraseWarning", IDS_SYNC_PASSPHRASE_WARNING },
242 { "cleardata", IDS_SYNC_CLEAR_DATA_FOR_PASSPHRASE },
243 { "cleardatalink", IDS_SYNC_CLEAR_DATA_LINK },
244 { "settingup", IDS_SYNC_LOGIN_SETTING_UP },
245 { "success", IDS_SYNC_SUCCESS },
246 { "firsttimesummary", IDS_SYNC_SETUP_FIRST_TIME_ALL_DONE },
247 { "okay", IDS_SYNC_SETUP_OK_BUTTON_LABEL },
248 { "enterPassphraseTitle", IDS_SYNC_ENTER_PASSPHRASE_TITLE },
249 { "firstPassphraseTitle", IDS_SYNC_FIRST_PASSPHRASE_TITLE },
250 { "customizeLinkLabel", IDS_SYNC_CUSTOMIZE_LINK_LABEL },
251 { "confirmSyncPreferences", IDS_SYNC_CONFIRM_SYNC_PREFERENCES },
252 { "syncEverything", IDS_SYNC_SYNC_EVERYTHING },
253 { "useDefaultSettings", IDS_SYNC_USE_DEFAULT_SETTINGS },
254 { "passphraseSectionTitle", IDS_SYNC_PASSPHRASE_SECTION_TITLE },
255 { "privacyDashboardLink", IDS_SYNC_PRIVACY_DASHBOARD_LINK_LABEL },
256 { "enterPassphraseTitle", IDS_SYNC_ENTER_PASSPHRASE_TITLE },
257 { "enterPassphraseBody", IDS_SYNC_ENTER_PASSPHRASE_BODY },
258 { "enterOtherPassphraseBody", IDS_SYNC_ENTER_OTHER_PASSPHRASE_BODY },
259 { "passphraseLabel", IDS_SYNC_PASSPHRASE_LABEL },
260 { "incorrectPassphrase", IDS_SYNC_INCORRECT_PASSPHRASE },
261 { "passphraseRecover", IDS_SYNC_PASSPHRASE_RECOVER },
262 { "passphraseWarning", IDS_SYNC_PASSPHRASE_WARNING },
263 { "cleardatalink", IDS_SYNC_CLEAR_DATA_LINK },
264 { "cancelWarningHeader", IDS_SYNC_PASSPHRASE_CANCEL_WARNING_HEADER },
265 { "cancelWarning", IDS_SYNC_PASSPHRASE_CANCEL_WARNING },
266 { "yes", IDS_SYNC_PASSPHRASE_CANCEL_YES },
267 { "no", IDS_SYNC_PASSPHRASE_CANCEL_NO },
268 { "sectionExplicitMessagePrefix", IDS_SYNC_PASSPHRASE_MSG_EXPLICIT_PREFIX },
269 { "sectionExplicitMessagePostfix",
270 IDS_SYNC_PASSPHRASE_MSG_EXPLICIT_POSTFIX },
271 };
272
273 RegisterStrings(localized_strings, resources, arraysize(resources));
274 }
275
Initialize()276 void SyncSetupHandler::Initialize() {
277 }
278
RegisterMessages()279 void SyncSetupHandler::RegisterMessages() {
280 web_ui_->RegisterMessageCallback("didShowPage",
281 NewCallback(this, &SyncSetupHandler::OnDidShowPage));
282 web_ui_->RegisterMessageCallback("didClosePage",
283 NewCallback(this, &SyncSetupHandler::OnDidClosePage));
284 web_ui_->RegisterMessageCallback("SubmitAuth",
285 NewCallback(this, &SyncSetupHandler::HandleSubmitAuth));
286 web_ui_->RegisterMessageCallback("Configure",
287 NewCallback(this, &SyncSetupHandler::HandleConfigure));
288 web_ui_->RegisterMessageCallback("Passphrase",
289 NewCallback(this, &SyncSetupHandler::HandlePassphraseEntry));
290 web_ui_->RegisterMessageCallback("PassphraseCancel",
291 NewCallback(this, &SyncSetupHandler::HandlePassphraseCancel));
292 web_ui_->RegisterMessageCallback("FirstPassphrase",
293 NewCallback(this, &SyncSetupHandler::HandleFirstPassphrase));
294 web_ui_->RegisterMessageCallback("GoToDashboard",
295 NewCallback(this, &SyncSetupHandler::HandleGoToDashboard));
296 }
297
298 // Called by SyncSetupFlow::Advance.
ShowGaiaLogin(const DictionaryValue & args)299 void SyncSetupHandler::ShowGaiaLogin(const DictionaryValue& args) {
300 StringValue page("login");
301 web_ui_->CallJavascriptFunction(
302 "SyncSetupOverlay.showSyncSetupPage", page, args);
303 }
304
ShowGaiaSuccessAndClose()305 void SyncSetupHandler::ShowGaiaSuccessAndClose() {
306 web_ui_->CallJavascriptFunction("SyncSetupOverlay.showSuccessAndClose");
307 }
308
ShowGaiaSuccessAndSettingUp()309 void SyncSetupHandler::ShowGaiaSuccessAndSettingUp() {
310 web_ui_->CallJavascriptFunction("SyncSetupOverlay.showSuccessAndSettingUp");
311 }
312
313 // Called by SyncSetupFlow::Advance.
ShowConfigure(const DictionaryValue & args)314 void SyncSetupHandler::ShowConfigure(const DictionaryValue& args) {
315 StringValue page("configure");
316 web_ui_->CallJavascriptFunction(
317 "SyncSetupOverlay.showSyncSetupPage", page, args);
318 }
319
ShowPassphraseEntry(const DictionaryValue & args)320 void SyncSetupHandler::ShowPassphraseEntry(const DictionaryValue& args) {
321 StringValue page("passphrase");
322 web_ui_->CallJavascriptFunction(
323 "SyncSetupOverlay.showSyncSetupPage", page, args);
324 }
325
ShowFirstPassphrase(const DictionaryValue & args)326 void SyncSetupHandler::ShowFirstPassphrase(const DictionaryValue& args) {
327 // TODO(jhawkins): Remove this logic in SyncSetupFlow. It will never be
328 // reached.
329 NOTREACHED();
330 }
331
ShowSettingUp()332 void SyncSetupHandler::ShowSettingUp() {
333 StringValue page("settingUp");
334 web_ui_->CallJavascriptFunction(
335 "SyncSetupOverlay.showSyncSetupPage", page);
336 }
337
ShowSetupDone(const std::wstring & user)338 void SyncSetupHandler::ShowSetupDone(const std::wstring& user) {
339 StringValue page("done");
340 web_ui_->CallJavascriptFunction(
341 "SyncSetupOverlay.showSyncSetupPage", page);
342 }
343
ShowFirstTimeDone(const std::wstring & user)344 void SyncSetupHandler::ShowFirstTimeDone(const std::wstring& user) {
345 // TODO(jhawkins): Remove this from Sync since it's not called anymore.
346 NOTREACHED();
347 }
348
OnDidShowPage(const ListValue * args)349 void SyncSetupHandler::OnDidShowPage(const ListValue* args) {
350 DCHECK(web_ui_);
351
352 ProfileSyncService* sync_service =
353 web_ui_->GetProfile()->GetProfileSyncService();
354 if (!sync_service)
355 return;
356
357 flow_ = sync_service->get_wizard().AttachSyncSetupHandler(this);
358 }
359
OnDidClosePage(const ListValue * args)360 void SyncSetupHandler::OnDidClosePage(const ListValue* args) {
361 if (flow_) {
362 flow_->OnDialogClosed(std::string());
363 flow_ = NULL;
364 }
365 }
366
HandleSubmitAuth(const ListValue * args)367 void SyncSetupHandler::HandleSubmitAuth(const ListValue* args) {
368 std::string json;
369 if (!args->GetString(0, &json)) {
370 NOTREACHED() << "Could not read JSON argument";
371 return;
372 }
373
374 if (json.empty())
375 return;
376
377 std::string username, password, captcha, access_code;
378 if (!GetAuthData(json, &username, &password, &captcha, &access_code)) {
379 // The page sent us something that we didn't understand.
380 // This probably indicates a programming error.
381 NOTREACHED();
382 return;
383 }
384
385 if (flow_)
386 flow_->OnUserSubmittedAuth(username, password, captcha, access_code);
387 }
388
HandleConfigure(const ListValue * args)389 void SyncSetupHandler::HandleConfigure(const ListValue* args) {
390 std::string json;
391 if (!args->GetString(0, &json)) {
392 NOTREACHED() << "Could not read JSON argument";
393 return;
394 }
395 if (json.empty()) {
396 NOTREACHED();
397 return;
398 }
399
400 SyncConfiguration configuration;
401 if (!GetConfiguration(json, &configuration)) {
402 // The page sent us something that we didn't understand.
403 // This probably indicates a programming error.
404 NOTREACHED();
405 return;
406 }
407
408 DCHECK(flow_);
409 flow_->OnUserConfigured(configuration);
410 }
411
HandlePassphraseEntry(const ListValue * args)412 void SyncSetupHandler::HandlePassphraseEntry(const ListValue* args) {
413 std::string json;
414 if (!args->GetString(0, &json)) {
415 NOTREACHED() << "Could not read JSON argument";
416 return;
417 }
418
419 if (json.empty())
420 return;
421
422 std::string passphrase;
423 if (!GetPassphrase(json, &passphrase)) {
424 // Couldn't understand what the page sent. Indicates a programming error.
425 NOTREACHED();
426 return;
427 }
428
429 DCHECK(flow_);
430 flow_->OnPassphraseEntry(passphrase);
431 }
432
HandlePassphraseCancel(const ListValue * args)433 void SyncSetupHandler::HandlePassphraseCancel(const ListValue* args) {
434 DCHECK(flow_);
435 flow_->OnPassphraseCancel();
436 }
437
HandleFirstPassphrase(const ListValue * args)438 void SyncSetupHandler::HandleFirstPassphrase(const ListValue* args) {
439 std::string json;
440 if (!args->GetString(0, &json)) {
441 NOTREACHED() << "Could not read JSON argument";
442 return;
443 }
444 if (json.empty())
445 return;
446
447 std::string option;
448 std::string passphrase;
449 if (!GetFirstPassphrase(json, &option, &passphrase)) {
450 // Page sent result which couldn't be parsed. Programming error.
451 NOTREACHED();
452 return;
453 }
454
455 DCHECK(flow_);
456 flow_->OnFirstPassphraseEntry(option, passphrase);
457 }
458
HandleGoToDashboard(const ListValue * args)459 void SyncSetupHandler::HandleGoToDashboard(const ListValue* args) {
460 DCHECK(flow_);
461 flow_->OnGoToDashboard();
462 }
463