// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/options/sync_setup_handler.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/values.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/sync_setup_flow.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "ui/base/l10n/l10n_util.h"
using l10n_util::GetStringFUTF16;
using l10n_util::GetStringUTF16;
namespace {
// TODO(jhawkins): Move these to url_constants.h.
const char* kInvalidPasswordHelpUrl =
"http://www.google.com/support/accounts/bin/answer.py?ctx=ch&answer=27444";
const char* kCanNotAccessAccountUrl =
"http://www.google.com/support/accounts/bin/answer.py?answer=48598";
#if defined(OS_CHROMEOS)
const char* kEncryptionHelpUrl =
"http://www.google.com/support/chromeos/bin/answer.py?answer=1181035";
#else
const char* kEncryptionHelpUrl =
"http://www.google.com/support/chrome/bin/answer.py?answer=1181035";
#endif
const char* kCreateNewAccountUrl =
"https://www.google.com/accounts/NewAccount?service=chromiumsync";
bool GetAuthData(const std::string& json,
std::string* username,
std::string* password,
std::string* captcha,
std::string* access_code) {
scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
return false;
DictionaryValue* result = static_cast<DictionaryValue*>(parsed_value.get());
if (!result->GetString("user", username) ||
!result->GetString("pass", password) ||
!result->GetString("captcha", captcha) ||
!result->GetString("access_code", access_code)) {
return false;
}
return true;
}
bool GetConfiguration(const std::string& json, SyncConfiguration* config) {
scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
return false;
DictionaryValue* result = static_cast<DictionaryValue*>(parsed_value.get());
if (!result->GetBoolean("keepEverythingSynced", &config->sync_everything))
return false;
// These values need to be kept in sync with where they are written in
// choose_datatypes.html.
bool sync_bookmarks;
if (!result->GetBoolean("syncBookmarks", &sync_bookmarks))
return false;
if (sync_bookmarks)
config->data_types.insert(syncable::BOOKMARKS);
bool sync_preferences;
if (!result->GetBoolean("syncPreferences", &sync_preferences))
return false;
if (sync_preferences)
config->data_types.insert(syncable::PREFERENCES);
bool sync_themes;
if (!result->GetBoolean("syncThemes", &sync_themes))
return false;
if (sync_themes)
config->data_types.insert(syncable::THEMES);
bool sync_passwords;
if (!result->GetBoolean("syncPasswords", &sync_passwords))
return false;
if (sync_passwords)
config->data_types.insert(syncable::PASSWORDS);
bool sync_autofill;
if (!result->GetBoolean("syncAutofill", &sync_autofill))
return false;
if (sync_autofill)
config->data_types.insert(syncable::AUTOFILL);
bool sync_extensions;
if (!result->GetBoolean("syncExtensions", &sync_extensions))
return false;
if (sync_extensions)
config->data_types.insert(syncable::EXTENSIONS);
bool sync_typed_urls;
if (!result->GetBoolean("syncTypedUrls", &sync_typed_urls))
return false;
if (sync_typed_urls)
config->data_types.insert(syncable::TYPED_URLS);
bool sync_sessions;
if (!result->GetBoolean("syncSessions", &sync_sessions))
return false;
if (sync_sessions)
config->data_types.insert(syncable::SESSIONS);
bool sync_apps;
if (!result->GetBoolean("syncApps", &sync_apps))
return false;
if (sync_apps)
config->data_types.insert(syncable::APPS);
// Encryption settings.
if (!result->GetBoolean("usePassphrase", &config->use_secondary_passphrase))
return false;
if (config->use_secondary_passphrase &&
!result->GetString("passphrase", &config->secondary_passphrase))
return false;
return true;
}
bool GetPassphrase(const std::string& json, std::string* passphrase) {
scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
return false;
DictionaryValue* result = static_cast<DictionaryValue*>(parsed_value.get());
return result->GetString("passphrase", passphrase);
}
bool GetFirstPassphrase(const std::string& json,
std::string* option,
std::string* passphrase) {
scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
return false;
DictionaryValue* result = static_cast<DictionaryValue*>(parsed_value.get());
return result->GetString("option", option) &&
result->GetString("passphrase", passphrase);
}
} // namespace
SyncSetupHandler::SyncSetupHandler() : flow_(NULL) {
}
SyncSetupHandler::~SyncSetupHandler() {
}
void SyncSetupHandler::GetLocalizedValues(DictionaryValue* localized_strings) {
DCHECK(localized_strings);
localized_strings->SetString(
"invalidpasswordhelpurl",
google_util::StringAppendGoogleLocaleParam(kInvalidPasswordHelpUrl));
localized_strings->SetString(
"cannotaccessaccounturl",
google_util::StringAppendGoogleLocaleParam(kCanNotAccessAccountUrl));
localized_strings->SetString(
"createnewaccounturl",
google_util::StringAppendGoogleLocaleParam(kCreateNewAccountUrl));
localized_strings->SetString(
"introduction",
GetStringFUTF16(IDS_SYNC_LOGIN_INTRODUCTION,
GetStringUTF16(IDS_PRODUCT_NAME)));
localized_strings->SetString(
"choosedatatypesinstructions",
GetStringFUTF16(IDS_SYNC_CHOOSE_DATATYPES_INSTRUCTIONS,
GetStringUTF16(IDS_PRODUCT_NAME)));
localized_strings->SetString(
"encryptionInstructions",
GetStringFUTF16(IDS_SYNC_ENCRYPTION_INSTRUCTIONS,
GetStringUTF16(IDS_PRODUCT_NAME)));
localized_strings->SetString(
"encryptionhelpurl",
google_util::StringAppendGoogleLocaleParam(kEncryptionHelpUrl));
localized_strings->SetString(
"passphraseEncryptionMessage",
GetStringFUTF16(IDS_SYNC_PASSPHRASE_ENCRYPTION_MESSAGE,
GetStringUTF16(IDS_PRODUCT_NAME)));
static OptionsStringResource resources[] = {
{ "syncSetupOverlayTitle", IDS_SYNC_SETUP_TITLE },
{ "syncSetupConfigureTitle", IDS_SYNC_SETUP_CONFIGURE_TITLE },
{ "signinprefix", IDS_SYNC_LOGIN_SIGNIN_PREFIX },
{ "signinsuffix", IDS_SYNC_LOGIN_SIGNIN_SUFFIX },
{ "cannotbeblank", IDS_SYNC_CANNOT_BE_BLANK },
{ "emaillabel", IDS_SYNC_LOGIN_EMAIL },
{ "passwordlabel", IDS_SYNC_LOGIN_PASSWORD },
{ "invalidcredentials", IDS_SYNC_INVALID_USER_CREDENTIALS },
{ "signin", IDS_SYNC_SIGNIN },
{ "couldnotconnect", IDS_SYNC_LOGIN_COULD_NOT_CONNECT },
{ "cannotaccessaccount", IDS_SYNC_CANNOT_ACCESS_ACCOUNT },
{ "createaccount", IDS_SYNC_CREATE_ACCOUNT },
{ "cancel", IDS_CANCEL },
{ "settingup", IDS_SYNC_LOGIN_SETTING_UP },
{ "settingupsync", IDS_SYNC_LOGIN_SETTING_UP_SYNC },
{ "errorsigningin", IDS_SYNC_ERROR_SIGNING_IN },
{ "captchainstructions", IDS_SYNC_GAIA_CAPTCHA_INSTRUCTIONS },
{ "invalidaccesscode", IDS_SYNC_INVALID_ACCESS_CODE_LABEL },
{ "enteraccesscode", IDS_SYNC_ENTER_ACCESS_CODE_LABEL },
{ "getaccesscodehelp", IDS_SYNC_ACCESS_CODE_HELP_LABEL },
{ "getaccesscodeurl", IDS_SYNC_GET_ACCESS_CODE_URL },
{ "dataTypes", IDS_SYNC_DATA_TYPES_TAB_NAME },
{ "encryption", IDS_SYNC_ENCRYPTION_TAB_NAME },
{ "choosedatatypesheader", IDS_SYNC_CHOOSE_DATATYPES_HEADER },
{ "keepeverythingsynced", IDS_SYNC_EVERYTHING },
{ "choosedatatypes", IDS_SYNC_CHOOSE_DATATYPES },
{ "bookmarks", IDS_SYNC_DATATYPE_BOOKMARKS },
{ "preferences", IDS_SYNC_DATATYPE_PREFERENCES },
{ "autofill", IDS_SYNC_DATATYPE_AUTOFILL },
{ "themes", IDS_SYNC_DATATYPE_THEMES },
{ "passwords", IDS_SYNC_DATATYPE_PASSWORDS },
{ "extensions", IDS_SYNC_DATATYPE_EXTENSIONS },
{ "typedurls", IDS_SYNC_DATATYPE_TYPED_URLS },
{ "apps", IDS_SYNC_DATATYPE_APPS },
{ "foreignsessions", IDS_SYNC_DATATYPE_SESSIONS },
{ "synczerodatatypeserror", IDS_SYNC_ZERO_DATA_TYPES_ERROR },
{ "abortederror", IDS_SYNC_SETUP_ABORTED_BY_PENDING_CLEAR },
{ "encryptAllLabel", IDS_SYNC_ENCRYPT_ALL_LABEL },
{ "googleOption", IDS_SYNC_PASSPHRASE_OPT_GOOGLE },
{ "explicitOption", IDS_SYNC_PASSPHRASE_OPT_EXPLICIT },
{ "sectionGoogleMessage", IDS_SYNC_PASSPHRASE_MSG_GOOGLE },
{ "sectionExplicitMessage", IDS_SYNC_PASSPHRASE_MSG_EXPLICIT },
{ "passphraseLabel", IDS_SYNC_PASSPHRASE_LABEL },
{ "confirmLabel", IDS_SYNC_CONFIRM_PASSPHRASE_LABEL },
{ "emptyErrorMessage", IDS_SYNC_EMPTY_PASSPHRASE_ERROR },
{ "mismatchErrorMessage", IDS_SYNC_PASSPHRASE_MISMATCH_ERROR },
{ "passphraseWarning", IDS_SYNC_PASSPHRASE_WARNING },
{ "cleardata", IDS_SYNC_CLEAR_DATA_FOR_PASSPHRASE },
{ "cleardatalink", IDS_SYNC_CLEAR_DATA_LINK },
{ "settingup", IDS_SYNC_LOGIN_SETTING_UP },
{ "success", IDS_SYNC_SUCCESS },
{ "firsttimesummary", IDS_SYNC_SETUP_FIRST_TIME_ALL_DONE },
{ "okay", IDS_SYNC_SETUP_OK_BUTTON_LABEL },
{ "enterPassphraseTitle", IDS_SYNC_ENTER_PASSPHRASE_TITLE },
{ "firstPassphraseTitle", IDS_SYNC_FIRST_PASSPHRASE_TITLE },
{ "customizeLinkLabel", IDS_SYNC_CUSTOMIZE_LINK_LABEL },
{ "confirmSyncPreferences", IDS_SYNC_CONFIRM_SYNC_PREFERENCES },
{ "syncEverything", IDS_SYNC_SYNC_EVERYTHING },
{ "useDefaultSettings", IDS_SYNC_USE_DEFAULT_SETTINGS },
{ "passphraseSectionTitle", IDS_SYNC_PASSPHRASE_SECTION_TITLE },
{ "privacyDashboardLink", IDS_SYNC_PRIVACY_DASHBOARD_LINK_LABEL },
{ "enterPassphraseTitle", IDS_SYNC_ENTER_PASSPHRASE_TITLE },
{ "enterPassphraseBody", IDS_SYNC_ENTER_PASSPHRASE_BODY },
{ "enterOtherPassphraseBody", IDS_SYNC_ENTER_OTHER_PASSPHRASE_BODY },
{ "passphraseLabel", IDS_SYNC_PASSPHRASE_LABEL },
{ "incorrectPassphrase", IDS_SYNC_INCORRECT_PASSPHRASE },
{ "passphraseRecover", IDS_SYNC_PASSPHRASE_RECOVER },
{ "passphraseWarning", IDS_SYNC_PASSPHRASE_WARNING },
{ "cleardatalink", IDS_SYNC_CLEAR_DATA_LINK },
{ "cancelWarningHeader", IDS_SYNC_PASSPHRASE_CANCEL_WARNING_HEADER },
{ "cancelWarning", IDS_SYNC_PASSPHRASE_CANCEL_WARNING },
{ "yes", IDS_SYNC_PASSPHRASE_CANCEL_YES },
{ "no", IDS_SYNC_PASSPHRASE_CANCEL_NO },
{ "sectionExplicitMessagePrefix", IDS_SYNC_PASSPHRASE_MSG_EXPLICIT_PREFIX },
{ "sectionExplicitMessagePostfix",
IDS_SYNC_PASSPHRASE_MSG_EXPLICIT_POSTFIX },
};
RegisterStrings(localized_strings, resources, arraysize(resources));
}
void SyncSetupHandler::Initialize() {
}
void SyncSetupHandler::RegisterMessages() {
web_ui_->RegisterMessageCallback("didShowPage",
NewCallback(this, &SyncSetupHandler::OnDidShowPage));
web_ui_->RegisterMessageCallback("didClosePage",
NewCallback(this, &SyncSetupHandler::OnDidClosePage));
web_ui_->RegisterMessageCallback("SubmitAuth",
NewCallback(this, &SyncSetupHandler::HandleSubmitAuth));
web_ui_->RegisterMessageCallback("Configure",
NewCallback(this, &SyncSetupHandler::HandleConfigure));
web_ui_->RegisterMessageCallback("Passphrase",
NewCallback(this, &SyncSetupHandler::HandlePassphraseEntry));
web_ui_->RegisterMessageCallback("PassphraseCancel",
NewCallback(this, &SyncSetupHandler::HandlePassphraseCancel));
web_ui_->RegisterMessageCallback("FirstPassphrase",
NewCallback(this, &SyncSetupHandler::HandleFirstPassphrase));
web_ui_->RegisterMessageCallback("GoToDashboard",
NewCallback(this, &SyncSetupHandler::HandleGoToDashboard));
}
// Called by SyncSetupFlow::Advance.
void SyncSetupHandler::ShowGaiaLogin(const DictionaryValue& args) {
StringValue page("login");
web_ui_->CallJavascriptFunction(
"SyncSetupOverlay.showSyncSetupPage", page, args);
}
void SyncSetupHandler::ShowGaiaSuccessAndClose() {
web_ui_->CallJavascriptFunction("SyncSetupOverlay.showSuccessAndClose");
}
void SyncSetupHandler::ShowGaiaSuccessAndSettingUp() {
web_ui_->CallJavascriptFunction("SyncSetupOverlay.showSuccessAndSettingUp");
}
// Called by SyncSetupFlow::Advance.
void SyncSetupHandler::ShowConfigure(const DictionaryValue& args) {
StringValue page("configure");
web_ui_->CallJavascriptFunction(
"SyncSetupOverlay.showSyncSetupPage", page, args);
}
void SyncSetupHandler::ShowPassphraseEntry(const DictionaryValue& args) {
StringValue page("passphrase");
web_ui_->CallJavascriptFunction(
"SyncSetupOverlay.showSyncSetupPage", page, args);
}
void SyncSetupHandler::ShowFirstPassphrase(const DictionaryValue& args) {
// TODO(jhawkins): Remove this logic in SyncSetupFlow. It will never be
// reached.
NOTREACHED();
}
void SyncSetupHandler::ShowSettingUp() {
StringValue page("settingUp");
web_ui_->CallJavascriptFunction(
"SyncSetupOverlay.showSyncSetupPage", page);
}
void SyncSetupHandler::ShowSetupDone(const std::wstring& user) {
StringValue page("done");
web_ui_->CallJavascriptFunction(
"SyncSetupOverlay.showSyncSetupPage", page);
}
void SyncSetupHandler::ShowFirstTimeDone(const std::wstring& user) {
// TODO(jhawkins): Remove this from Sync since it's not called anymore.
NOTREACHED();
}
void SyncSetupHandler::OnDidShowPage(const ListValue* args) {
DCHECK(web_ui_);
ProfileSyncService* sync_service =
web_ui_->GetProfile()->GetProfileSyncService();
if (!sync_service)
return;
flow_ = sync_service->get_wizard().AttachSyncSetupHandler(this);
}
void SyncSetupHandler::OnDidClosePage(const ListValue* args) {
if (flow_) {
flow_->OnDialogClosed(std::string());
flow_ = NULL;
}
}
void SyncSetupHandler::HandleSubmitAuth(const ListValue* args) {
std::string json;
if (!args->GetString(0, &json)) {
NOTREACHED() << "Could not read JSON argument";
return;
}
if (json.empty())
return;
std::string username, password, captcha, access_code;
if (!GetAuthData(json, &username, &password, &captcha, &access_code)) {
// The page sent us something that we didn't understand.
// This probably indicates a programming error.
NOTREACHED();
return;
}
if (flow_)
flow_->OnUserSubmittedAuth(username, password, captcha, access_code);
}
void SyncSetupHandler::HandleConfigure(const ListValue* args) {
std::string json;
if (!args->GetString(0, &json)) {
NOTREACHED() << "Could not read JSON argument";
return;
}
if (json.empty()) {
NOTREACHED();
return;
}
SyncConfiguration configuration;
if (!GetConfiguration(json, &configuration)) {
// The page sent us something that we didn't understand.
// This probably indicates a programming error.
NOTREACHED();
return;
}
DCHECK(flow_);
flow_->OnUserConfigured(configuration);
}
void SyncSetupHandler::HandlePassphraseEntry(const ListValue* args) {
std::string json;
if (!args->GetString(0, &json)) {
NOTREACHED() << "Could not read JSON argument";
return;
}
if (json.empty())
return;
std::string passphrase;
if (!GetPassphrase(json, &passphrase)) {
// Couldn't understand what the page sent. Indicates a programming error.
NOTREACHED();
return;
}
DCHECK(flow_);
flow_->OnPassphraseEntry(passphrase);
}
void SyncSetupHandler::HandlePassphraseCancel(const ListValue* args) {
DCHECK(flow_);
flow_->OnPassphraseCancel();
}
void SyncSetupHandler::HandleFirstPassphrase(const ListValue* args) {
std::string json;
if (!args->GetString(0, &json)) {
NOTREACHED() << "Could not read JSON argument";
return;
}
if (json.empty())
return;
std::string option;
std::string passphrase;
if (!GetFirstPassphrase(json, &option, &passphrase)) {
// Page sent result which couldn't be parsed. Programming error.
NOTREACHED();
return;
}
DCHECK(flow_);
flow_->OnFirstPassphraseEntry(option, passphrase);
}
void SyncSetupHandler::HandleGoToDashboard(const ListValue* args) {
DCHECK(flow_);
flow_->OnGoToDashboard();
}