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 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 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 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 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 156 SyncSetupHandler::SyncSetupHandler() : flow_(NULL) { 157 } 158 159 SyncSetupHandler::~SyncSetupHandler() { 160 } 161 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 276 void SyncSetupHandler::Initialize() { 277 } 278 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. 299 void SyncSetupHandler::ShowGaiaLogin(const DictionaryValue& args) { 300 StringValue page("login"); 301 web_ui_->CallJavascriptFunction( 302 "SyncSetupOverlay.showSyncSetupPage", page, args); 303 } 304 305 void SyncSetupHandler::ShowGaiaSuccessAndClose() { 306 web_ui_->CallJavascriptFunction("SyncSetupOverlay.showSuccessAndClose"); 307 } 308 309 void SyncSetupHandler::ShowGaiaSuccessAndSettingUp() { 310 web_ui_->CallJavascriptFunction("SyncSetupOverlay.showSuccessAndSettingUp"); 311 } 312 313 // Called by SyncSetupFlow::Advance. 314 void SyncSetupHandler::ShowConfigure(const DictionaryValue& args) { 315 StringValue page("configure"); 316 web_ui_->CallJavascriptFunction( 317 "SyncSetupOverlay.showSyncSetupPage", page, args); 318 } 319 320 void SyncSetupHandler::ShowPassphraseEntry(const DictionaryValue& args) { 321 StringValue page("passphrase"); 322 web_ui_->CallJavascriptFunction( 323 "SyncSetupOverlay.showSyncSetupPage", page, args); 324 } 325 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 332 void SyncSetupHandler::ShowSettingUp() { 333 StringValue page("settingUp"); 334 web_ui_->CallJavascriptFunction( 335 "SyncSetupOverlay.showSyncSetupPage", page); 336 } 337 338 void SyncSetupHandler::ShowSetupDone(const std::wstring& user) { 339 StringValue page("done"); 340 web_ui_->CallJavascriptFunction( 341 "SyncSetupOverlay.showSyncSetupPage", page); 342 } 343 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 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 360 void SyncSetupHandler::OnDidClosePage(const ListValue* args) { 361 if (flow_) { 362 flow_->OnDialogClosed(std::string()); 363 flow_ = NULL; 364 } 365 } 366 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 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 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 433 void SyncSetupHandler::HandlePassphraseCancel(const ListValue* args) { 434 DCHECK(flow_); 435 flow_->OnPassphraseCancel(); 436 } 437 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 459 void SyncSetupHandler::HandleGoToDashboard(const ListValue* args) { 460 DCHECK(flow_); 461 flow_->OnGoToDashboard(); 462 } 463