summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjohnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-08 01:45:18 +0000
committerjohnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-08 01:45:18 +0000
commit22d3eff8c7ed0fe79450dc214857286e88c5dfed (patch)
tree7e2f37cf354aa0947d227e277ed3457aff670d6e
parentb15b5e32959926441c298a89c843293c52de75e2 (diff)
downloadchromium_src-22d3eff8c7ed0fe79450dc214857286e88c5dfed.zip
chromium_src-22d3eff8c7ed0fe79450dc214857286e88c5dfed.tar.gz
chromium_src-22d3eff8c7ed0fe79450dc214857286e88c5dfed.tar.bz2
Add passphrase migration UI according to the flow chart for users who require a passphrase the first time.
BUG=63014,58935 TEST=test Review URL: http://codereview.chromium.org/5563004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@70825 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/generated_resources.grd79
-rw-r--r--chrome/browser/browser_resources.grd2
-rw-r--r--chrome/browser/dom_ui/new_tab_page_sync_handler.cc26
-rw-r--r--chrome/browser/dom_ui/new_tab_page_sync_handler.h1
-rw-r--r--chrome/browser/resources/browser_signin.html8
-rw-r--r--chrome/browser/sync/profile_sync_service.cc55
-rw-r--r--chrome/browser/sync/profile_sync_service.h10
-rw-r--r--chrome/browser/sync/resources/configure.html199
-rw-r--r--chrome/browser/sync/resources/encryption_login.html6
-rw-r--r--chrome/browser/sync/resources/firstpassphrase.html204
-rw-r--r--chrome/browser/sync/resources/setup_flow.html7
-rw-r--r--chrome/browser/sync/sync_setup_flow.cc139
-rw-r--r--chrome/browser/sync/sync_setup_flow.h14
-rw-r--r--chrome/browser/sync/sync_setup_wizard.cc42
-rw-r--r--chrome/browser/sync/sync_setup_wizard.h5
-rw-r--r--chrome/browser/sync/sync_setup_wizard_unittest.cc17
-rw-r--r--chrome/browser/sync/sync_ui_util.cc40
-rw-r--r--chrome/browser/sync/sync_ui_util.h5
18 files changed, 723 insertions, 136 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index e252069..7a9797d 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -8470,11 +8470,47 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_SYNC_ERROR_SIGNING_IN" desc="An error was encountered while signing the user in.">
Error signing in.
</message>
+ <message name="IDS_SYNC_CONFIGURE_ENCRYPTION" desc="Link to configure sync encryption for passwords">
+ Configure password sync.
+ </message>
+ <message name="IDS_SYNC_PLEASE_SIGN_IN" desc="An title for a sign in dialog.">
+ Please sign in
+ </message>
+ <message name="IDS_SYNC_LOGIN_FOR_ENCRYPTION" desc="Explanation of login for the purpose of encryption.">
+ <ph name="PRODUCT_NAME">$1<ex>Chrome</ex></ph> can now sync your passwords. To protect your data, you need to confirm your account information.
+ </message>
+ <message name="IDS_SYNC_FIRST_PASSPHRASE_TITLE" desc="Title for dialog setting up first passphrase.">
+ Set up encrypted sync
+ </message>
+ <message name="IDS_SYNC_FIRST_PASSPHRASE_MESSAGE" desc="Message for setting up first passphrase.">
+ To sync passwords, <ph name="PRODUCT_NAME">$1<ex>Chrome</ex></ph> requires you to encrypt your data using either your Google password or your own passphrase.
+ </message>
+ <message name="IDS_SYNC_PASSPHRASE_OPT_GOOGLE" desc="Radio button label for using Google password.">
+ Use my Google password.
+ </message>
+ <message name="IDS_SYNC_PASSPHRASE_OPT_EXPLICIT" desc="Radio button label for using explicit passphrase.">
+ Choose my own passphrase.
+ </message>
+ <message name="IDS_SYNC_PASSPHRASE_OPT_CANCEL" desc="Radio button label for not syncing encrypted types.">
+ Do not sync my passwords.
+ </message>
+ <message name="IDS_SYNC_PASSPHRASE_MSG_GOOGLE" desc="Message when Google password is selected.">
+ You have chosen to encrypt data using your Google password; you can always change your mind later by changing your sync settings.
+ </message>
+ <message name="IDS_SYNC_PASSPHRASE_MSG_EXPLICIT" desc="Message when explicit passphrase is selected.">
+ Only someone with your passphrase can read your data. Google does not store your passphrase. If you lose or forget your passphrase, you will have to reset sync.
+ </message>
+ <message name="IDS_SYNC_PASSPHRASE_MSG_CANCEL" desc="Message when not syncing passwords is selected.">
+ You have chosen not to sync passwords; you can always change your mind later by changing your sync settings.
+ </message>
+ <message name="IDS_SYNC_CLEAR_DATA_FOR_PASSPHRASE" desc="Text on a button which clears data if the user wants to clear out their passphrase.">
+ Reset sync
+ </message>
<message name="IDS_SYNC_LOGIN_INFO_OUT_OF_DATE" desc="The login information for the user is out of date - for example, the user changed their password and therefore signing in again is required.">
Account sign-in details are out of date.
</message>
<message name="IDS_SYNC_SERVER_IS_UNREACHABLE" desc="The message to display in the New Tab Page sync section when the server is unreachable.">
- <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex> could not sync your data because it could not connect to the sync server. Retrying...</ph>
+ <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> could not sync your data because it could not connect to the sync server. Retrying...
</message>
<message name="IDS_SYNC_RELOGIN_LINK_LABEL" desc="The text to display on in the hyperlink when the user needs to sign in again to use sync.">
Sign in again
@@ -8527,7 +8563,16 @@ Keep your key file in a safe place. You will need it to create new versions of y
Sync
</message>
<message name="IDS_SYNC_NTP_SYNC_SECTION_ERROR_TITLE" desc="The title to display in the New Tab Page sync status section in case of an error.">
- Sync Error!
+ Sync needs your attention!
+ </message>
+ <message name="IDS_SYNC_NTP_SYNC_SECTION_PROMO_TITLE" desc="The title to display in the New Tab Page sync status section in case of a promotion.">
+ New!
+ </message>
+ <message name="IDS_SYNC_NTP_PASSWORD_PROMO" desc="The message to display to promote passwords sync now being available.">
+ <ph name="PRODUCT_NAME">$1<ex>Chrome</ex></ph> can now sync your passwords.
+ </message>
+ <message name="IDS_SYNC_NTP_PASSWORD_ENABLE" desc="The link text to present for passwords sync.">
+ Enable
</message>
<message name="IDS_SYNC_NTP_SETUP_IN_PROGRESS" desc="The message to display in the New Tab Page sync section when the sync setup is underway.">
Setup in progress...
@@ -8596,7 +8641,7 @@ Keep your key file in a safe place. You will need it to create new versions of y
<!-- Encryption tab of the configure sync dialog -->
<message name="IDS_SYNC_ENCRYPTION_INSTRUCTIONS" desc="Instructions for the encryption settings tab.">
- <ph name="PRODUCT_NAME">$1<ex>Chrome</ex></ph> always encrypts your data when it's transmitted to Google. Additionally, passwords are stored encrypted on Google servers.
+ <ph name="PRODUCT_NAME">$1<ex>Chrome</ex></ph> requires you to encrypt your data using either your Google password or your own passphrase.
</message>
<message name="IDS_SYNC_ENCRYPT_ALL_LABEL" desc="Label for the checkbox that enables encryption of everything.">
Encrypt all my data
@@ -8605,32 +8650,31 @@ Keep your key file in a safe place. You will need it to create new versions of y
Use a sync passphrase to encrypt my data
</message>
<message name="IDS_SYNC_PASSPHRASE_WARNING" desc="Warning message about using a passphrase for sync.">
- Once you start using a passphrase, you cannot remove the passphrase without clearing your sync data. The passphrase does not leave this computer, and if you lose this passphrase, you may not be able to sync this data on other computers.
+ You are currently using a passphrase. If you've lost or forgotten your passphrase, you can reset sync to clear your synced data from Google's servers using the Google Privacy Dashboard.
+ </message>
+ <message name="IDS_SYNC_CLEAR_DATA_LINK" desc="Link to the Google Dashboard.">
+ Go to Google Privacy Dashboard
</message>
<!-- Passphrase dialog strings -->
- <message name="IDS_SYNC_NEW_PASSPHRASE_TITLE" desc="Title for the dialog where the user creates a new passphrase.">
- Create a passphrase
- </message>
- <message name="IDS_SYNC_NEW_PASSPHRASE_BODY" desc="Instructions for the dialog where the user creates a new passphrase.">
- Choose a passphrase to encrypt your sync data. This passphrase will not leave this computer, and if you lose it you may not be able to sync your data.
- </message>
<message name="IDS_SYNC_ENTER_PASSPHRASE_TITLE" desc="Title for the dialog where the user enters the passphrase.">
Enter your passphrase
</message>
<message name="IDS_SYNC_ENTER_PASSPHRASE_BODY" desc="Instructions for the dialog where the user enters the passphrase.">
Your sync data has been encrypted using a passphrase. Please enter your passphrase to decrypt the data.
</message>
- <message name="IDS_SYNC_GAIA_PASSPHRASE_TITLE" desc="Title for the dialog where the user enters their password as passphrase.">
- Enter your Google account password
+ <message name="IDS_SYNC_PASSPHRASE_LABEL" desc="Label for the passphrase field.">
+ Passphrase:
</message>
- <message name="IDS_SYNC_GAIA_PASSPHRASE_BODY" desc="Instructions for the dialog where the user enters their password as passphrase.">
- Your sync data has been encrypted. Please re-enter your password to decrypt the data.
+ <message name="IDS_SYNC_CONFIRM_PASSPHRASE_LABEL" desc="Label for the confirm-passphrase field.">
+ Confirm Passphrase:
</message>
- <message name="IDS_SYNC_PASSPHRASE_LABEL" desc="Label for the passphrase field.">
- Passphrase
+ <message name="IDS_SYNC_EMPTY_PASSPHRASE_ERROR" desc="Error message when the passphrase is empty.">
+ Empty passphrase is not allowed.
+ </message>
+ <message name="IDS_SYNC_PASSPHRASE_MISMATCH_ERROR" desc="Error message when the passphrase and confirmation don't match.">
+ You must enter the same passphrase twice.
</message>
-
<!-- Login dialog strings -->
<message name="IDS_SYNC_MY_BOOKMARKS_LABEL" desc="Title of the sync login dialog.">
@@ -8847,7 +8891,6 @@ Keep your key file in a safe place. You will need it to create new versions of y
</message>
-
<!-- New Tab Page Promotional messages -->
<message name="IDS_NTP_PROMOTION_NEW" desc="Beginning of promotional message; a word in special red font signaling something new is coming.">
New!
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index dade7cd..3d03dbf 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -61,7 +61,9 @@ without changes to the corresponding grd file. etaa -->
<include name="IDR_SSL_ERROR_HTML" file="security\resources\ssl_error.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_SSL_ROAD_BLOCK_HTML" file="security\resources\ssl_roadblock.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_SYNC_CONFIGURE_HTML" file="sync\resources\configure.html" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_SYNC_ENCRYPTION_LOGIN_HTML" file="sync\resources\encryption_login.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_SYNC_PASSPHRASE_HTML" file="sync\resources\passphrase.html" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_SYNC_FIRST_PASSPHRASE_HTML" file="sync\resources\firstpassphrase.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_SYNC_SETTING_UP_HTML" file="sync\resources\setting_up.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_SYNC_SETUP_DONE_HTML" file="sync\resources\setup_done.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_SYNC_SETUP_FLOW_HTML" file="sync\resources\setup_flow.html" flattenhtml="true" type="BINDATA" />
diff --git a/chrome/browser/dom_ui/new_tab_page_sync_handler.cc b/chrome/browser/dom_ui/new_tab_page_sync_handler.cc
index c075793..d7a5543 100644
--- a/chrome/browser/dom_ui/new_tab_page_sync_handler.cc
+++ b/chrome/browser/dom_ui/new_tab_page_sync_handler.cc
@@ -90,6 +90,8 @@ NewTabPageSyncHandler::MessageType
switch (type) {
case sync_ui_util::SYNC_ERROR:
return SYNC_ERROR;
+ case sync_ui_util::SYNC_PROMO:
+ return SYNC_PROMO;
case sync_ui_util::PRE_SYNCED:
case sync_ui_util::SYNCED:
default:
@@ -155,6 +157,13 @@ void NewTabPageSyncHandler::HandleSyncLinkClicked(const ListValue* args) {
if (!sync_service_->IsSyncEnabled())
return;
if (sync_service_->HasSyncSetupCompleted()) {
+ if (sync_service_->observed_passphrase_required()) {
+ if (sync_service_->IsUsingSecondaryPassphrase())
+ sync_service_->PromptForExistingPassphrase(NULL);
+ else
+ sync_service_->SigninForPassphrase(dom_ui_->tab_contents());
+ return;
+ }
if (sync_service_->GetAuthError().state() ==
GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS ||
sync_service_->GetAuthError().state() ==
@@ -164,8 +173,7 @@ void NewTabPageSyncHandler::HandleSyncLinkClicked(const ListValue* args) {
sync_service_->GetAuthError().state() ==
GoogleServiceAuthError::ACCOUNT_DISABLED ||
sync_service_->GetAuthError().state() ==
- GoogleServiceAuthError::SERVICE_UNAVAILABLE ||
- sync_service_->observed_passphrase_required()) {
+ GoogleServiceAuthError::SERVICE_UNAVAILABLE) {
sync_service_->ShowLoginDialog(NULL);
return;
}
@@ -196,12 +204,16 @@ void NewTabPageSyncHandler::SendSyncMessageToPage(
std::string title;
std::string linkurl;
- // If there is no message to show, we should hide the sync section
- // altogether.
- if (type == HIDE || msg.empty()) {
+ // If there is nothing to show, we should hide the sync section altogether.
+ if (type == HIDE || (msg.empty() && linktext.empty())) {
value.SetBoolean("syncsectionisvisible", false);
- } else { // type == SYNC_ERROR
- title = l10n_util::GetStringUTF8(IDS_SYNC_NTP_SYNC_SECTION_ERROR_TITLE);
+ } else {
+ if (type == SYNC_ERROR)
+ title = l10n_util::GetStringUTF8(IDS_SYNC_NTP_SYNC_SECTION_ERROR_TITLE);
+ else if (type == SYNC_PROMO)
+ title = l10n_util::GetStringUTF8(IDS_SYNC_NTP_SYNC_SECTION_PROMO_TITLE);
+ else
+ NOTREACHED();
value.SetBoolean("syncsectionisvisible", true);
value.SetString("msg", msg);
diff --git a/chrome/browser/dom_ui/new_tab_page_sync_handler.h b/chrome/browser/dom_ui/new_tab_page_sync_handler.h
index 9db005b..99c817e 100644
--- a/chrome/browser/dom_ui/new_tab_page_sync_handler.h
+++ b/chrome/browser/dom_ui/new_tab_page_sync_handler.h
@@ -38,6 +38,7 @@ class NewTabPageSyncHandler : public DOMMessageHandler,
enum MessageType {
HIDE,
SYNC_ERROR,
+ SYNC_PROMO
};
// Helper to invoke the |syncMessageChanged| JS function on the new tab page.
void SendSyncMessageToPage(MessageType type,
diff --git a/chrome/browser/resources/browser_signin.html b/chrome/browser/resources/browser_signin.html
index 17ead4e..ef4afed 100644
--- a/chrome/browser/resources/browser_signin.html
+++ b/chrome/browser/resources/browser_signin.html
@@ -2,7 +2,7 @@
<style>
body {
margin: 0;
- font-family: sans-serif;
+ font-family: arial,sans-serif;
}
#message {
position: absolute;
@@ -13,6 +13,12 @@ body {
position: absolute;
left: 50%;
}
+#message h1 {
+ font-size: medium;
+}
+#message p {
+ font-size: smaller;
+}
</style>
<script>
function initmessage() {
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index a3da689..852ed4b 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -19,6 +19,7 @@
#include "base/string_util.h"
#include "base/task.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_signin.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
@@ -31,6 +32,7 @@
#include "chrome/browser/sync/glue/session_data_type_controller.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/signin_manager.h"
+#include "chrome/browser/sync/sync_ui_util.h"
#include "chrome/browser/sync/token_migrator.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/net/gaia/gaia_constants.h"
@@ -39,6 +41,7 @@
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/time_format.h"
+#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "jingle/notifier/communicator/const_communicator.h"
#include "net/base/cookie_monster.h"
@@ -716,11 +719,7 @@ void ProfileSyncService::ShowLoginDialog(gfx::NativeWindow parent_window) {
}
wizard_.SetParent(parent_window);
- // This method will also be called if a passphrase is needed.
- if (observed_passphrase_required_)
- wizard_.Step(SyncSetupWizard::ENTER_PASSPHRASE);
- else
- wizard_.Step(SyncSetupWizard::GAIA_LOGIN);
+ wizard_.Step(SyncSetupWizard::GAIA_LOGIN);
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
}
@@ -734,6 +733,31 @@ void ProfileSyncService::ShowConfigure(gfx::NativeWindow parent_window) {
wizard_.Step(SyncSetupWizard::CONFIGURE);
}
+void ProfileSyncService::PromptForExistingPassphrase(
+ gfx::NativeWindow parent_window) {
+ if (WizardIsVisible()) {
+ wizard_.Focus();
+ return;
+ }
+ wizard_.SetParent(parent_window);
+ wizard_.Step(SyncSetupWizard::ENTER_PASSPHRASE);
+}
+
+void ProfileSyncService::ShowPassphraseMigration(
+ gfx::NativeWindow parent_window) {
+ wizard_.SetParent(parent_window);
+ wizard_.Step(SyncSetupWizard::PASSPHRASE_MIGRATION);
+}
+
+void ProfileSyncService::SigninForPassphrase(TabContents* container) {
+ string16 prefilled_username = GetAuthenticatedUsername();
+ string16 login_message = sync_ui_util::GetLoginMessageForEncryption();
+ profile_->GetBrowserSignin()->RequestSignin(container,
+ prefilled_username,
+ login_message,
+ this);
+}
+
SyncBackendHost::StatusSummary ProfileSyncService::QuerySyncStatusSummary() {
if (backend_.get() && backend_initialized_)
return backend_->GetStatusSummary();
@@ -1138,6 +1162,27 @@ void ProfileSyncService::Observe(NotificationType type,
}
}
+// This is the delegate callback from BrowserSigin.
+void ProfileSyncService::OnLoginSuccess() {
+ // The reason for the browser signin was a non-explicit passphrase
+ // required signal. If this is the first time through the passphrase
+ // process, we want to show the migration UI and offer an explicit
+ // passphrase. Otherwise, we're done because the implicit is enough.
+
+ if (passphrase_required_for_decryption_) {
+ // NOT first time (decrypting something encrypted elsewhere).
+ // Do nothing.
+ } else {
+ ShowPassphraseMigration(NULL);
+ }
+}
+
+// This is the delegate callback from BrowserSigin.
+void ProfileSyncService::OnLoginFailure(const GoogleServiceAuthError& error) {
+ // Do nothing. The UI will already reflect the fact that the
+ // user is not signed in.
+}
+
void ProfileSyncService::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h
index de66ec8..62a8e07 100644
--- a/chrome/browser/sync/profile_sync_service.h
+++ b/chrome/browser/sync/profile_sync_service.h
@@ -15,6 +15,7 @@
#include "base/string16.h"
#include "base/time.h"
#include "base/timer.h"
+#include "chrome/browser/browser_signin.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
@@ -37,6 +38,7 @@ class NotificationSource;
class NotificationType;
class Profile;
class ProfileSyncFactory;
+class TabContents;
class TokenMigrator;
// ProfileSyncService is the layer between browser subsystems like bookmarks,
@@ -83,6 +85,7 @@ class TokenMigrator;
//
class ProfileSyncService : public browser_sync::SyncFrontend,
public browser_sync::UnrecoverableErrorHandler,
+ public BrowserSignin::SigninDelegate,
public NotificationObserver {
public:
typedef ProfileSyncServiceObserver Observer;
@@ -223,6 +226,9 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
}
virtual void ShowLoginDialog(gfx::NativeWindow parent_window);
void ShowConfigure(gfx::NativeWindow parent_window);
+ void PromptForExistingPassphrase(gfx::NativeWindow parent_window);
+ void SigninForPassphrase(TabContents* container);
+ void ShowPassphraseMigration(gfx::NativeWindow parent_window);
// Pretty-printed strings for a given StatusSummary.
static std::string BuildSyncStatusSummaryText(
@@ -319,6 +325,10 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
const NotificationSource& source,
const NotificationDetails& details);
+ // BrowserSignin::SigninDelegate interface.
+ virtual void OnLoginSuccess();
+ virtual void OnLoginFailure(const GoogleServiceAuthError& error);
+
// Changes which data types we're going to be syncing to |preferred_types|.
// If it is running, the DataTypeManager will be instructed to reconfigure
// the sync backend so that exactly these datatypes are actively synced. See
diff --git a/chrome/browser/sync/resources/configure.html b/chrome/browser/sync/resources/configure.html
index 90a3491..b087169 100644
--- a/chrome/browser/sync/resources/configure.html
+++ b/chrome/browser/sync/resources/configure.html
@@ -83,13 +83,11 @@ form {
}
#sync-encryption-instructions {
- margin-bottom: 10px;
- line-height: 1.8em;
+ margin-bottom: 5px;
}
#sync-passphrase-warning {
- font-style: italic;
- line-height: 1.8em;
+ margin-bottom: 5px;
}
#encryption-tab-contents > .sync_item_show {
@@ -145,6 +143,26 @@ form {
margin-right: 10px;
margin-bottom: 10px;
}
+.sync-section {
+ background: #EEE;
+ margin: 5px 0px;
+ padding: 6px;
+}
+
+#explicit-message {
+ margin-bottom: 5px;
+}
+
+#change-passphrase {
+ margin: 10px 0;
+ background: #EEE;
+ padding: 8px;
+}
+
+#clear-data-button {
+ margin-top: 10px;
+}
+
html[dir='rtl'] .sync-footer {
text-align: left;
left: 0px;
@@ -254,9 +272,9 @@ html[os='mac'] input[type='submit'] {
args.syncApps;
document.getElementById("appsItem").className = "sync-item-show";
} else {
- document.getElementById("appsItem").className = "sync-item-hide";
- }
-
+ document.getElementById("appsItem").className = "sync-item-hide";
+ }
+
setCheckboxesToKeepEverythingSynced(args.keepEverythingSynced);
if (args.sessionsRegistered) {
document.getElementById("sessionsCheckbox").checked = args.syncSessions;
@@ -267,13 +285,18 @@ html[os='mac'] input[type='submit'] {
}
function setEncryptionCheckboxes(args) {
- document.getElementById("usePassphraseCheckbox").checked =
- args["usePassphrase"];
-
- // The passphrase, once set, cannot be unset.
if (args["usePassphrase"]) {
- document.getElementById("usePassphraseCheckbox").disabled = true;
+ document.getElementById("explicit-option").checked = true;
+
+ // The passphrase, once set, cannot be unset, but we show a reset link.
+ document.getElementById("explicit-option").disabled = true;
+ document.getElementById("google-option").disabled = true;
+ document.getElementById("change-passphrase").style.display = "block";
+ } else {
+ document.getElementById("google-option").checked = true;
+ document.getElementById("change-passphrase").style.display = "none";
}
+ switchToMode("");
}
function setErrorState(args) {
@@ -298,6 +321,8 @@ html[os='mac'] input[type='submit'] {
}
}
+
+
// Returns true if at least one data type is enabled and no data types are
// checked. (If all data type checkboxes are disabled, it's because "keep
// everything synced" is checked.)
@@ -328,6 +353,10 @@ html[os='mac'] input[type='submit'] {
}
var f = document.getElementById("chooseDataTypesForm");
+ if (!checkPassphraseMatch()) {
+ return false;
+ }
+
var syncAll = f.keepEverythingSyncedRadio.checked;
// These values need to be kept in sync with where they are read in
// SyncSetupFlow::GetDataTypeChoiceData().
@@ -342,7 +371,8 @@ html[os='mac'] input[type='submit'] {
"syncTypedUrls": syncAll || f.typedUrlsCheckbox.checked,
"syncApps": syncAll || f.appsCheckbox.checked,
"syncSessions": syncAll || f.sessionsCheckbox.checked,
- "usePassphrase": document.getElementById("usePassphraseCheckbox").checked
+ "usePassphrase": (getRadioCheckedValue() == 'explicit'),
+ "passphrase": f.passphrase.value
});
chrome.send("Configure", [result]);
}
@@ -354,15 +384,73 @@ html[os='mac'] input[type='submit'] {
document.getElementById(currentTab + "-tab-contents").className =
"sync-config-tab-contents-inactive";
}
-
+
document.getElementById(newTab + "-tab").className =
"sync-config-tab-active";
document.getElementById(newTab + "-tab-contents").className =
"sync-config-tab-contents-active";
-
+
currentTab = newTab;
}
+ function switchToMode(mode) {
+ document.getElementById("section-explicit").style.display = "none";
+ document.getElementById("section-google").style.display = "none";
+
+ if (mode == "google") {
+ document.getElementById("section-google").style.display = "block";
+ } else if (mode =="explicit") {
+ document.getElementById("section-explicit").style.display = "block";
+ }
+ }
+
+ function getRadioCheckedValue() {
+ var f = document.getElementById("chooseDataTypesForm");
+ for (var i = 0; i < f.option.length; ++i) {
+ if (f.option[i].checked) {
+ return f.option[i].value;
+ }
+ }
+ return undefined;
+ }
+
+ function onRadioChange() {
+ switchToMode(getRadioCheckedValue());
+ }
+
+ function checkPassphraseMatch() {
+ var emptyError = document.getElementById("emptyerror");
+ var mismatchError = document.getElementById("mismatcherror");
+ emptyError.style.display = "none";
+ mismatchError.style.display = "none";
+
+ if (getRadioCheckedValue() != "explicit") {
+ return true;
+ }
+ var f = document.getElementById("chooseDataTypesForm");
+ if (f.passphrase.value.length == 0) {
+ emptyError.style.display = "block";
+ return false;
+ }
+ if (f.confirmpassphrase.value.length > 0 &&
+ f.confirmpassphrase.value != f.passphrase.value) {
+ mismatchError.style.display = "block";
+ return false;
+ }
+ return true;
+ }
+
+ function sendValuesAndClose() {
+ var result = JSON.stringify({"option": getRadioCheckedValue(),
+ "passphrase": f.passphrase.value});
+ chrome.send("FirstPassphrase", [result]);
+ }
+
+ function goToDashboard() {
+ chrome.send("GoToDashboard", [""]);
+ chrome.send("DialogClose", [""]);
+ }
+
</script>
</head>
<body i18n-values=".style.fontFamily:fontfamily"
@@ -381,9 +469,9 @@ html[os='mac'] input[type='submit'] {
</div>
<div id="data-type-tab-contents" class="sync-config-tab-contents-inactive">
- <div class="sync-header"
+ <div class="sync-header"
i18n-content="choosedatatypesheader"></div>
- <div class="sync-choose_data_types_instructions"
+ <div class="sync-choose_data_types_instructions"
i18n-content="choosedatatypesinstructions"></div>
<div class="sync-select-customization">
<div class="sync-choice_radio">
@@ -395,7 +483,7 @@ html[os='mac'] input[type='submit'] {
</label>
</div>
<div id="chooseDataTypes" class="sync-choice_radio">
- <input id="chooseDataTypesRadio" type="radio" name="syncChooseDataTypes"
+ <input id="chooseDataTypesRadio" type="radio" name="syncChooseDataTypes"
onclick="setCheckboxesToKeepEverythingSynced(false)">
<label for="chooseDataTypesRadio" i18n-content="choosedatatypes" ></label>
<div id="chooseDataTypesBody">
@@ -403,49 +491,49 @@ html[os='mac'] input[type='submit'] {
<!-- Apps -->
<div class="sync-item-show" id="appsItem">
<input id="appsCheckbox" name="dataTypeCheckbox" type="checkbox">
- <label id="appsCheckboxLabel" name="dataTypeLabel"
+ <label id="appsCheckboxLabel" name="dataTypeLabel"
for="appsCheckbox" i18n-content="apps"
i18n-values="title:apps"></label>
</div>
<!-- Autofill -->
<div class="sync-item-show" id="autofillItem">
<input id="autofillCheckbox" name="dataTypeCheckbox" type="checkbox">
- <label id="autofillCheckboxLabel" name="dataTypeLabel"
+ <label id="autofillCheckboxLabel" name="dataTypeLabel"
for="autofillCheckbox" i18n-content="autofill"
i18n-values="title:autofill"></label>
</div>
<!-- Bookmarks -->
<div class="sync-item-show" id="bookmarksItem">
<input id="bookmarksCheckbox" name="dataTypeCheckbox" type="checkbox">
- <label id="bookmarksCheckboxLabel" name="dataTypeLabel"
+ <label id="bookmarksCheckboxLabel" name="dataTypeLabel"
for="bookmarksCheckbox" i18n-content="bookmarks"
i18n-values="title:bookmarks"></label>
</div>
<!-- Extensions -->
<div class="sync-item-show" id="extensionsItem">
<input id="extensionsCheckbox" name="dataTypeCheckbox" type="checkbox">
- <label id="extensionsCheckboxLabel" name="dataTypeLabel"
+ <label id="extensionsCheckboxLabel" name="dataTypeLabel"
for="extensionsCheckbox" i18n-content="extensions"
i18n-values="title:extensions"></label>
</div>
<!-- Omnibox -->
<div class="sync-item-show" id="omniboxItem">
<input id="typedUrlsCheckbox" name="dataTypeCheckbox" type="checkbox">
- <label id="typedUrlsCheckboxLabel" name="dataTypeLabel"
+ <label id="typedUrlsCheckboxLabel" name="dataTypeLabel"
for="typedUrlsCheckbox" i18n-content="typedurls"
i18n-values="title:typedurls"></label>
</div>
<!-- Passwords -->
<div class="sync-item-show" id="passwordsItem">
<input id="passwordsCheckbox" name="dataTypeCheckbox" type="checkbox">
- <label id="passwordsCheckboxLabel" name="dataTypeLabel"
+ <label id="passwordsCheckboxLabel" name="dataTypeLabel"
for="passwordsCheckbox" i18n-content="passwords"
i18n-values="title:passwords"></label>
</div>
<!-- Preferences -->
<div class="sync-item-show" id="preferencesItem">
<input id="preferencesCheckbox" name="dataTypeCheckbox" type="checkbox">
- <label id="preferencesCheckboxLabel" name="dataTypeLabel"
+ <label id="preferencesCheckboxLabel" name="dataTypeLabel"
for="preferencesCheckbox" i18n-content="preferences"
i18n-values="title:preferences"></label>
</div>
@@ -458,7 +546,7 @@ html[os='mac'] input[type='submit'] {
<!-- Sessions -->
<div class="sync-item-show" id="sessionsItem">
<input id="sessionsCheckbox" name="dataTypeCheckbox" type="checkbox">
- <label id="sessionsCheckboxLabel" name="dataTypeLabel"
+ <label id="sessionsCheckboxLabel" name="dataTypeLabel"
for="sessionsCheckbox" i18n-content="foreignsessions"
il8n-values="title:sessions"></label>
</div>
@@ -475,21 +563,58 @@ html[os='mac'] input[type='submit'] {
</div>
<div id="encryption-tab-contents" class="sync-config-tab-contents-inactive">
- <div id="sync-encryption-instructions"
+ <div id="sync-encryption-instructions"
i18n-content="encryptionInstructions"></div>
-
- <div class="sync-item-show" id="usePassphrase">
- <input id="usePassphraseCheckbox" name="usePassphraseCheckbox"
- type="checkbox" />
- <label id="usePassphraseLabel" name="usePassphraseLabel"
- for="usePassphraseCheckbox" i18n-content="usePassphraseLabel">
- </label>
+
+ <div>
+ <input id="google-option" name="option" type="radio"
+ value="google" onchange="onRadioChange();">
+ <span i18n-content="googleOption"></span>
+ </input>
+ </div>
+ <div>
+ <input id="explicit-option" name="option" type="radio"
+ value="explicit" onchange="onRadioChange();">
+ <span i18n-content="explicitOption"></span>
+ </input>
+ </div>
+
+ <div class="sync-section" id="section-google">
+ <div i18n-content="sectionGoogleMessage"></div>
+ </div>
+ <div class="sync-section" id="section-explicit">
+ <div i18n-content="sectionExplicitMessage" id="explicit-message"></div>
+ <div>
+ <div i18n-content="passphraseLabel" id="passphraseLabel"></div>
+ <input id="passphrase" name="passphrase" label="passphraseLabel"
+ type="password" onkeyup="checkPassphraseMatch();"
+ onchange="checkPassphraseMatch();"/>
+ </div>
+ <div>
+ <div i18n-content="confirmLabel" id="confirmPassphraseLabel">
+ </div>
+ <input id="confirmpassphrase" name="confirmpassphrase" type="password"
+ label="confirmPassphraseLabel"
+ onkeyup="checkPassphraseMatch();"
+ onchange="checkPassphraseMatch();" />
+ </div>
+ <div class="error" style="display:none"
+ id="emptyerror" i18n-content="emptyErrorMessage"></div>
+ <div class="error" style="display:none"
+ id="mismatcherror" i18n-content="mismatchErrorMessage"></div>
</div>
-
- <div id="sync-passphrase-warning" i18n-content="passphraseWarning">
+
+ <div id="change-passphrase">
+ <div id="sync-passphrase-warning" i18n-content="passphraseWarning">
+ </div>
+ <div id="sync-reset-confirmation" i18n-content="cleardataconfirmation"
+ style="display: none;">
+ </div>
+ <a id="clear-data-link" i18n-content="cleardatalink" href="#"
+ onclick='goToDashboard(); return false;'></a>
</div>
</div>
-
+
<div class="sync-footer">
<input id="okButton" type="submit" i18n-values="value:ok" />
<input id="cancelButton" type="button" i18n-values="value:cancel"
diff --git a/chrome/browser/sync/resources/encryption_login.html b/chrome/browser/sync/resources/encryption_login.html
new file mode 100644
index 0000000..7883cca
--- /dev/null
+++ b/chrome/browser/sync/resources/encryption_login.html
@@ -0,0 +1,6 @@
+<!-- This is intentionally an HTML fragment to be embedded
+ in the browser sign in HTML -->
+<div id="login_message">
+<h1>$1</h1>
+<p>$2</p>
+</div>
diff --git a/chrome/browser/sync/resources/firstpassphrase.html b/chrome/browser/sync/resources/firstpassphrase.html
new file mode 100644
index 0000000..4f82ef9
--- /dev/null
+++ b/chrome/browser/sync/resources/firstpassphrase.html
@@ -0,0 +1,204 @@
+<html i18n-values="dir:textdirection;">
+<head>
+<title></title>
+<style type="text/css">
+body {
+ line-height: 1.5em;
+ background: #FFFFFF;
+ font-size: 11pt;
+}
+html[os='mac'] body {
+ line-height: 1.5em;
+ background: #FFFFFF;
+}
+form {
+ -webkit-user-select: none;
+}
+.error {
+ color: red;
+ font-size: 10pt;
+ }
+.sync-header {
+ font-size: 1.2em;
+ font-weight: bold;
+ margin-bottom: 10px;
+}
+.sync-instructions {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+.sync-footer {
+ position: fixed;
+ right: 0px;
+ bottom: 0px;
+ margin-right: 10px;
+ margin-bottom: 10px;
+}
+.sync-section {
+ background: #EEE;
+ margin: 5px;
+ padding: 10px;
+}
+html[dir='rtl'] .sync-footer {
+ text-align: left;
+ left: 0px;
+ bottom: 0px;
+ margin-left: 20px;
+}
+input[type='button'],
+input[type='submit'] {
+ min-width: 87px;
+ min-height: 26px;
+}
+html[os='mac'] input[type='button'],
+html[os='mac'] input[type='submit'] {
+ font-size: 12pt;
+}
+
+#passphrase {
+ margin-top: 5px;
+}
+
+#passphraseLabel,
+#confirmPassphraseLabel {
+ width: 145px;
+ float: left;
+ text-align: right;
+ margin-right: 4px;
+ padding-top: 3px;
+}
+
+</style>
+<script src="chrome://resources/js/cr.js"></script>
+<script>
+ var currentMode;
+
+ // Called once, when this html/js is loaded.
+ function setupDialog(args) {
+ // Allow platform specific rules
+ if (cr.isMac) {
+ document.documentElement.setAttribute('os', 'mac');
+ } else if (!cr.isWindows) {
+ document.documentElement.setAttribute('os', 'linux');
+ }
+
+ switchToMode("");
+ }
+
+ function switchToMode(mode) {
+ document.getElementById("section-explicit").style.display = "none";
+ document.getElementById("section-nothanks").style.display = "none";
+ document.getElementById("section-google").style.display = "none";
+
+ if (mode == "google") {
+ document.getElementById("section-google").style.display = "block";
+ } else if (mode =="explicit") {
+ document.getElementById("section-explicit").style.display = "block";
+ } else if (mode == "nothanks") {
+ document.getElementById("section-nothanks").style.display = "block";
+ }
+ }
+
+ function getRadioCheckedValue() {
+ var f = document.getElementById("form");
+ for (var i = 0; i < f.option.length; ++i) {
+ if (f.option[i].checked) {
+ return f.option[i].value;
+ }
+ }
+ return undefined;
+ }
+
+ function onRadioChange() {
+ switchToMode(getRadioCheckedValue());
+ }
+
+ function checkPassphraseMatch() {
+ var emptyError = document.getElementById("emptyerror");
+ var mismatchError = document.getElementById("mismatcherror");
+ emptyError.style.display = "none";
+ mismatchError.style.display = "none";
+
+ if (getRadioCheckedValue() != "explicit") {
+ return true;
+ }
+ var f = document.getElementById("form");
+ if (f.passphrase.value.length == 0) {
+ emptyError.style.display = "block";
+ return false;
+ }
+ if (f.confirmpassphrase.value.length > 0 &&
+ f.confirmpassphrase.value != f.passphrase.value) {
+ mismatchError.style.display = "block";
+ return false;
+ }
+ return true;
+ }
+
+ function sendValuesAndClose() {
+ var f = document.getElementById("form");
+ if (!checkPassphraseMatch()) {
+ return false;
+ }
+
+ var result = JSON.stringify({"option": getRadioCheckedValue(),
+ "passphrase": f.passphrase.value});
+ chrome.send("FirstPassphrase", [result]);
+ }
+</script>
+</head>
+<body i18n-values=".style.fontFamily:fontfamily" onload="setupDialog();">
+<form id="form" onSubmit="sendValuesAndClose(); return false;">
+ <div class="sync-header" id="title" i18n-content="title"></div>
+ <div class="sync-instructions" id="instructions"
+ i18n-content="instructions"></div>
+ <div>
+ <input name="option" type="radio" value="google" onchange="onRadioChange();">
+ <span i18n-content="googleOption"></span>
+ </input>
+ </div>
+ <div>
+ <input name="option" type="radio" value="explicit" onchange="onRadioChange();">
+ <span i18n-content="explicitOption"></span>
+ </input>
+ </div>
+ <div>
+ <input name="option" type="radio" value="nothanks" onchange="onRadioChange();">
+ <span i18n-content="nothanksOption"></span>
+ </input>
+ </div>
+
+ <div class="sync-section" id="section-google">
+ <div i18n-content="sectionGoogleMessage"></div>
+ </div>
+ <div class="sync-section" id="section-explicit">
+ <div i18n-content="sectionExplicitMessage"></div>
+ <div>
+ <div i18n-content="passphraseLabel" id="passphraseLabel"></div>
+ <input id="passphrase" name="passphrase" label="passphraseLabel"
+ type="password" onkeyup="checkPassphraseMatch();"
+ onchange="checkPassphraseMatch();"/>
+ </div>
+ <div>
+ <div i18n-content="confirmLabel" id="confirmPassphraseLabel">
+ </div>
+ <input id="confirmpassphrase" name="confirmpassphrase" type="password"
+ label="confirmPassphraseLabel"
+ onkeyup="checkPassphraseMatch();"
+ onchange="checkPassphraseMatch();" />
+ </div>
+ <div class="error" style="display:none"
+ id="emptyerror" i18n-content="emptyErrorMessage"></div>
+ <div class="error" style="display:none"
+ id="mismatcherror" i18n-content="mismatchErrorMessage"></div>
+ </div>
+ <div class="sync-section" id="section-nothanks">
+ <div i18n-content="sectionNothanksMessage"></div>
+ </div>
+
+ <div class="sync-footer">
+ <input id="okButton" type="submit" i18n-values="value:ok" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/chrome/browser/sync/resources/setup_flow.html b/chrome/browser/sync/resources/setup_flow.html
index a3de363..495828f 100644
--- a/chrome/browser/sync/resources/setup_flow.html
+++ b/chrome/browser/sync/resources/setup_flow.html
@@ -3,7 +3,8 @@
<title></title>
<script type="text/javascript">
function hideAllPages() {
- var pages = ['login', 'configure', 'passphrase', 'settingup', 'done'];
+ var pages = ['login', 'configure', 'passphrase',
+ 'settingup', 'done', 'firstpassphrase'];
for (var i = 0; i < pages.length; ++i) {
document.getElementById(pages[i]).style.display = 'none';
document.getElementById(pages[i]).tabIndex = -1;
@@ -21,6 +22,7 @@
function showPassphrase() { showPage('passphrase'); }
function showSettingUp() { showPage('settingup'); }
function showSetupDone() { showPage('done'); }
+ function showFirstPassphrase() { showPage('firstpassphrase'); }
// Called once, when this html/js is loaded.
function showTheRightIframe() {
@@ -45,5 +47,8 @@
<iframe id="done" frameborder="0" width="100%" scrolling="no" height="100%"
src="chrome://syncresources/setupdone" style="display:none"
tabindex="-1"></iframe>
+ <iframe id="firstpassphrase" frameborder="0" width="100%" scrolling="no"
+ height="100%" src="chrome://syncresources/firstpassphrase"
+ style="display:none" tabindex="-1"></iframe>
</body>
</html>
diff --git a/chrome/browser/sync/sync_setup_flow.cc b/chrome/browser/sync/sync_setup_flow.cc
index 3d24877..adb06ea 100644
--- a/chrome/browser/sync/sync_setup_flow.cc
+++ b/chrome/browser/sync/sync_setup_flow.cc
@@ -44,6 +44,10 @@ void FlowHandler::RegisterMessages() {
NewCallback(this, &FlowHandler::HandleConfigure));
dom_ui_->RegisterMessageCallback("Passphrase",
NewCallback(this, &FlowHandler::HandlePassphraseEntry));
+ dom_ui_->RegisterMessageCallback("FirstPassphrase",
+ NewCallback(this, &FlowHandler::HandleFirstPassphrase));
+ dom_ui_->RegisterMessageCallback("GoToDashboard",
+ NewCallback(this, &FlowHandler::HandleGoToDashboard));
}
static bool GetAuthData(const std::string& json,
@@ -76,6 +80,18 @@ bool GetPassphrase(const std::string& json, std::string* passphrase,
result->GetString("mode", mode);
}
+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);
+}
+
static bool GetConfiguration(const std::string& json,
SyncConfiguration* config) {
scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
@@ -145,6 +161,9 @@ static bool GetConfiguration(const std::string& json,
// Encyption 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;
}
@@ -204,6 +223,28 @@ void FlowHandler::HandlePassphraseEntry(const ListValue* args) {
flow_->OnPassphraseEntry(passphrase, mode);
}
+void FlowHandler::HandleFirstPassphrase(const ListValue* args) {
+ std::string json(dom_ui_util::GetJsonResponseFromFirstArgumentInList(args));
+
+ 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 FlowHandler::HandleGoToDashboard(const ListValue* args) {
+ flow_->OnGoToDashboard();
+}
+
// Called by SyncSetupFlow::Advance.
void FlowHandler::ShowGaiaLogin(const DictionaryValue& args) {
// Whenever you start a wizard, you pass in an arg so it starts on the right
@@ -258,6 +299,17 @@ void FlowHandler::ShowPassphraseEntry(const DictionaryValue& args) {
ExecuteJavascriptInIFrame(kPassphraseIFrameXPath, script);
}
+void FlowHandler::ShowFirstPassphrase(const DictionaryValue& args) {
+ if (dom_ui_)
+ dom_ui_->CallJavascriptFunction(L"showFirstPassphrase");
+
+ std::string json;
+ base::JSONWriter::Write(&args, false, &json);
+ std::wstring script = std::wstring(L"setupDialog") +
+ L"(" + UTF8ToWide(json) + L");";
+ ExecuteJavascriptInIFrame(kPassphraseIFrameXPath, script);
+}
+
void FlowHandler::ShowSettingUp() {
if (dom_ui_)
dom_ui_->CallJavascriptFunction(L"showSettingUp");
@@ -306,7 +358,6 @@ SyncSetupFlow::SyncSetupFlow(SyncSetupWizard::State start_state,
login_start_time_(base::TimeTicks::Now()),
flow_handler_(new FlowHandler()),
owns_flow_handler_(true),
- configuration_pending_(false),
service_(service),
html_dialog_window_(NULL) {
flow_handler_->set_flow(this);
@@ -503,8 +554,6 @@ bool SyncSetupFlow::ShouldAdvance(SyncSetupWizard::State state) {
return current_state_ == SyncSetupWizard::GAIA_LOGIN;
case SyncSetupWizard::CONFIGURE:
return current_state_ == SyncSetupWizard::GAIA_SUCCESS;
- case SyncSetupWizard::CREATE_PASSPHRASE:
- return current_state_ == SyncSetupWizard::CONFIGURE;
case SyncSetupWizard::ENTER_PASSPHRASE:
return current_state_ == SyncSetupWizard::CONFIGURE ||
current_state_ == SyncSetupWizard::SETTING_UP;
@@ -512,8 +561,8 @@ bool SyncSetupFlow::ShouldAdvance(SyncSetupWizard::State state) {
return current_state_ == SyncSetupWizard::CONFIGURE;
case SyncSetupWizard::SETTING_UP:
return current_state_ == SyncSetupWizard::CONFIGURE ||
- current_state_ == SyncSetupWizard::CREATE_PASSPHRASE ||
- current_state_ == SyncSetupWizard::ENTER_PASSPHRASE;
+ current_state_ == SyncSetupWizard::ENTER_PASSPHRASE ||
+ current_state_ == SyncSetupWizard::PASSPHRASE_MIGRATION;
case SyncSetupWizard::FATAL_ERROR:
return true; // You can always hit the panic button.
case SyncSetupWizard::DONE_FIRST_TIME:
@@ -554,16 +603,16 @@ void SyncSetupFlow::Advance(SyncSetupWizard::State advance_state) {
flow_handler_->ShowConfigure(args);
break;
}
- case SyncSetupWizard::CREATE_PASSPHRASE: {
+ case SyncSetupWizard::ENTER_PASSPHRASE: {
DictionaryValue args;
- args.SetString("mode", "new");
+ SyncSetupFlow::GetArgsForEnterPassphrase(service_, &args);
flow_handler_->ShowPassphraseEntry(args);
break;
}
- case SyncSetupWizard::ENTER_PASSPHRASE: {
+ case SyncSetupWizard::PASSPHRASE_MIGRATION: {
DictionaryValue args;
- SyncSetupFlow::GetArgsForEnterPassphrase(service_, &args);
- flow_handler_->ShowPassphraseEntry(args);
+ args.SetString("iframeToShow", "firstpassphrase");
+ flow_handler_->ShowFirstPassphrase(args);
break;
}
case SyncSetupWizard::SETUP_ABORTED_BY_PENDING_CLEAR: {
@@ -630,6 +679,9 @@ SyncSetupFlow* SyncSetupFlow::Run(ProfileSyncService* service,
SyncSetupFlow::GetArgsForConfigure(service, &args);
else if (start == SyncSetupWizard::ENTER_PASSPHRASE)
SyncSetupFlow::GetArgsForEnterPassphrase(service, &args);
+ else if (start == SyncSetupWizard::PASSPHRASE_MIGRATION)
+ args.SetString("iframeToShow", "firstpassphrase");
+
std::string json_args;
base::JSONWriter::Write(&args, false, &json_args);
@@ -664,56 +716,47 @@ void SyncSetupFlow::OnUserSubmittedAuth(const std::string& username,
}
void SyncSetupFlow::OnUserConfigured(const SyncConfiguration& configuration) {
- // Store the configuration in case we need more information.
- configuration_ = configuration;
- configuration_pending_ = true;
-
- // If the user is activating secondary passphrase for the first time,
- // we need to prompt them to enter one.
- if (configuration.use_secondary_passphrase &&
- !service_->IsUsingSecondaryPassphrase()) {
- // TODO(tim): If we could download the Nigori node first before any other
- // types, we could do that prior to showing the configure page so that we
- // could pre-populate the 'Use an encryption passphrase' checkbox.
- // http://crbug.com/60182
- Advance(SyncSetupWizard::CREATE_PASSPHRASE);
- return;
- }
-
- OnConfigurationComplete();
-}
-
-void SyncSetupFlow::OnConfigurationComplete() {
- if (!configuration_pending_)
- return;
-
// Go to the "loading..." screen."
Advance(SyncSetupWizard::SETTING_UP);
// If we are activating the passphrase, we need to have one supplied.
DCHECK(service_->IsUsingSecondaryPassphrase() ||
- !configuration_.use_secondary_passphrase ||
- configuration_.secondary_passphrase.length() > 0);
+ !configuration.use_secondary_passphrase ||
+ configuration.secondary_passphrase.length() > 0);
- if (configuration_.use_secondary_passphrase &&
+ if (configuration.use_secondary_passphrase &&
!service_->IsUsingSecondaryPassphrase()) {
- service_->SetPassphrase(configuration_.secondary_passphrase, true);
+ service_->SetPassphrase(configuration.secondary_passphrase, true);
}
- service_->OnUserChoseDatatypes(configuration_.sync_everything,
- configuration_.data_types);
-
- configuration_pending_ = false;
+ service_->OnUserChoseDatatypes(configuration.sync_everything,
+ configuration.data_types);
}
void SyncSetupFlow::OnPassphraseEntry(const std::string& passphrase,
const std::string& mode) {
- if (current_state_ == SyncSetupWizard::ENTER_PASSPHRASE) {
- service_->SetPassphrase(passphrase, mode == std::string("enter"));
- Advance(SyncSetupWizard::SETTING_UP);
- } else if (configuration_pending_) {
- DCHECK_EQ(SyncSetupWizard::CREATE_PASSPHRASE, current_state_);
- configuration_.secondary_passphrase = passphrase;
- OnConfigurationComplete();
+ Advance(SyncSetupWizard::SETTING_UP);
+ service_->SetPassphrase(passphrase, true);
+}
+
+void SyncSetupFlow::OnFirstPassphraseEntry(const std::string& option,
+ const std::string& passphrase) {
+ Advance(SyncSetupWizard::SETTING_UP);
+ if (option == "explicit") {
+ service_->SetPassphrase(passphrase, true);
+ } else if (option == "nothanks") {
+ // User opted out of encrypted sync, need to turn off encrypted
+ // data types.
+ syncable::ModelTypeSet registered_types;
+ service_->GetRegisteredDataTypes(&registered_types);
+ registered_types.erase(syncable::PASSWORDS);
+ service_->OnUserChoseDatatypes(false, registered_types);
+ } else if (option == "google") {
+ // Implicit passphrase already set up.
+ Advance(SyncSetupWizard::DONE);
}
}
+
+void SyncSetupFlow::OnGoToDashboard() {
+ BrowserList::GetLastActive()->OpenPrivacyDashboardTabAndActivate();
+}
diff --git a/chrome/browser/sync/sync_setup_flow.h b/chrome/browser/sync/sync_setup_flow.h
index 8bfc443..f6c0233 100644
--- a/chrome/browser/sync/sync_setup_flow.h
+++ b/chrome/browser/sync/sync_setup_flow.h
@@ -110,7 +110,10 @@ class SyncSetupFlow : public HtmlDialogUIDelegate {
void OnPassphraseEntry(const std::string& passphrase,
const std::string& mode);
- void OnConfigurationComplete();
+ void OnFirstPassphraseEntry(const std::string& option,
+ const std::string& passphrase);
+
+ void OnGoToDashboard();
private:
FRIEND_TEST_ALL_PREFIXES(SyncSetupWizardTest, InitialStepLogin);
@@ -124,6 +127,7 @@ class SyncSetupFlow : public HtmlDialogUIDelegate {
FRIEND_TEST_ALL_PREFIXES(SyncSetupWizardTest,
DiscreteRunChooseDataTypesAbortedByPendingClear);
FRIEND_TEST_ALL_PREFIXES(SyncSetupWizardTest, EnterPassphraseRequired);
+ FRIEND_TEST_ALL_PREFIXES(SyncSetupWizardTest, PassphraseMigration);
// Use static Run method to get an instance.
SyncSetupFlow(SyncSetupWizard::State start_state,
@@ -149,11 +153,6 @@ class SyncSetupFlow : public HtmlDialogUIDelegate {
FlowHandler* flow_handler_;
mutable bool owns_flow_handler_;
- // The current configuration, held pending until all the information has
- // been populated (possibly using multiple dialog states).
- SyncConfiguration configuration_;
- bool configuration_pending_;
-
// We need this to write the sentinel "setup completed" pref.
ProfileSyncService* service_;
@@ -198,6 +197,8 @@ class FlowHandler : public DOMMessageHandler {
void HandleSubmitAuth(const ListValue* args);
void HandleConfigure(const ListValue* args);
void HandlePassphraseEntry(const ListValue* args);
+ void HandleFirstPassphrase(const ListValue* args);
+ void HandleGoToDashboard(const ListValue* args);
// These functions control which part of the HTML is visible.
void ShowGaiaLogin(const DictionaryValue& args);
@@ -205,6 +206,7 @@ class FlowHandler : public DOMMessageHandler {
void ShowGaiaSuccessAndSettingUp();
void ShowConfigure(const DictionaryValue& args);
void ShowPassphraseEntry(const DictionaryValue& args);
+ void ShowFirstPassphrase(const DictionaryValue& args);
void ShowSettingUp();
void ShowSetupDone(const std::wstring& user);
void ShowFirstTimeDone(const std::wstring& user);
diff --git a/chrome/browser/sync/sync_setup_wizard.cc b/chrome/browser/sync/sync_setup_wizard.cc
index e80afe0..6e9d254 100644
--- a/chrome/browser/sync/sync_setup_wizard.cc
+++ b/chrome/browser/sync/sync_setup_wizard.cc
@@ -79,6 +79,7 @@ void SyncResourcesSource::StartDataRequest(const std::string& path_raw,
const char kSyncGaiaLoginPath[] = "gaialogin";
const char kSyncConfigurePath[] = "configure";
const char kSyncPassphrasePath[] = "passphrase";
+ const char kSyncFirstPassphrasePath[] = "firstpassphrase";
const char kSyncSettingUpPath[] = "settingup";
const char kSyncSetupDonePath[] = "setupdone";
@@ -149,23 +150,48 @@ void SyncResourcesSource::StartDataRequest(const std::string& path_raw,
GetStringFUTF16(IDS_SYNC_ENCRYPTION_INSTRUCTIONS,
GetStringUTF16(IDS_PRODUCT_NAME)));
AddString(dict, "encryptAllLabel", IDS_SYNC_ENCRYPT_ALL_LABEL);
- AddString(dict, "usePassphraseLabel", IDS_SYNC_PASSPHRASE_CHECKBOX_LABEL);
+
+ AddString(dict, "googleOption", IDS_SYNC_PASSPHRASE_OPT_GOOGLE);
+ AddString(dict, "explicitOption", IDS_SYNC_PASSPHRASE_OPT_EXPLICIT);
+ AddString(dict, "sectionGoogleMessage", IDS_SYNC_PASSPHRASE_MSG_GOOGLE);
+ AddString(dict, "sectionExplicitMessage", IDS_SYNC_PASSPHRASE_MSG_EXPLICIT);
+ AddString(dict, "passphraseLabel", IDS_SYNC_PASSPHRASE_LABEL);
+ AddString(dict, "confirmLabel", IDS_SYNC_CONFIRM_PASSPHRASE_LABEL);
+ AddString(dict, "emptyErrorMessage", IDS_SYNC_EMPTY_PASSPHRASE_ERROR);
+ AddString(dict, "mismatchErrorMessage", IDS_SYNC_PASSPHRASE_MISMATCH_ERROR);
+
AddString(dict, "passphraseWarning", IDS_SYNC_PASSPHRASE_WARNING);
+ AddString(dict, "cleardata", IDS_SYNC_CLEAR_DATA_FOR_PASSPHRASE);
+ AddString(dict, "cleardatalink", IDS_SYNC_CLEAR_DATA_LINK);
// Stuff for the footer.
AddString(dict, "ok", IDS_OK);
AddString(dict, "cancel", IDS_CANCEL);
} else if (path_raw == kSyncPassphrasePath) {
html_resource_id = IDR_SYNC_PASSPHRASE_HTML;
- AddString(dict, "newPassphraseTitle", IDS_SYNC_NEW_PASSPHRASE_TITLE);
- AddString(dict, "newPassphraseBody", IDS_SYNC_NEW_PASSPHRASE_BODY);
AddString(dict, "enterPassphraseTitle", IDS_SYNC_ENTER_PASSPHRASE_TITLE);
AddString(dict, "enterPassphraseBody", IDS_SYNC_ENTER_PASSPHRASE_BODY);
- AddString(dict, "gaiaPassphraseTitle", IDS_SYNC_GAIA_PASSPHRASE_TITLE);
- AddString(dict, "gaiaPassphraseBody", IDS_SYNC_GAIA_PASSPHRASE_BODY);
AddString(dict, "passphraseLabel", IDS_SYNC_PASSPHRASE_LABEL);
AddString(dict, "ok", IDS_OK);
AddString(dict, "cancel", IDS_CANCEL);
+ } else if (path_raw == kSyncFirstPassphrasePath) {
+ html_resource_id = IDR_SYNC_FIRST_PASSPHRASE_HTML;
+ AddString(dict, "title", IDS_SYNC_FIRST_PASSPHRASE_TITLE);
+ dict->SetString("instructions",
+ GetStringFUTF16(IDS_SYNC_FIRST_PASSPHRASE_MESSAGE,
+ GetStringUTF16(IDS_PRODUCT_NAME)));
+ AddString(dict, "googleOption", IDS_SYNC_PASSPHRASE_OPT_GOOGLE);
+ AddString(dict, "explicitOption", IDS_SYNC_PASSPHRASE_OPT_EXPLICIT);
+ AddString(dict, "nothanksOption", IDS_SYNC_PASSPHRASE_OPT_CANCEL);
+ AddString(dict, "sectionGoogleMessage", IDS_SYNC_PASSPHRASE_MSG_GOOGLE);
+ AddString(dict, "sectionExplicitMessage", IDS_SYNC_PASSPHRASE_MSG_EXPLICIT);
+ AddString(dict, "sectionNothanksMessage", IDS_SYNC_PASSPHRASE_MSG_CANCEL);
+ AddString(dict, "passphraseLabel", IDS_SYNC_PASSPHRASE_LABEL);
+ AddString(dict, "confirmLabel", IDS_SYNC_CONFIRM_PASSPHRASE_LABEL);
+ AddString(dict, "emptyErrorMessage", IDS_SYNC_EMPTY_PASSPHRASE_ERROR);
+ AddString(dict, "mismatchErrorMessage", IDS_SYNC_PASSPHRASE_MISMATCH_ERROR);
+ AddString(dict, "ok", IDS_OK);
+ AddString(dict, "cancel", IDS_CANCEL);
} else if (path_raw == kSyncSettingUpPath) {
html_resource_id = IDR_SYNC_SETTING_UP_HTML;
@@ -279,9 +305,9 @@ SyncSetupWizard::State SyncSetupWizard::GetEndStateForDiscreteRun(
State result = FATAL_ERROR;
if (start_state == GAIA_LOGIN) {
result = GAIA_SUCCESS;
- } else if (start_state == ENTER_PASSPHRASE) {
- result = DONE;
- } else if (start_state == CONFIGURE) {
+ } else if (start_state == ENTER_PASSPHRASE ||
+ start_state == CONFIGURE ||
+ start_state == PASSPHRASE_MIGRATION) {
result = DONE;
}
DCHECK_NE(FATAL_ERROR, result) <<
diff --git a/chrome/browser/sync/sync_setup_wizard.h b/chrome/browser/sync/sync_setup_wizard.h
index dad3fa9..76b6fae 100644
--- a/chrome/browser/sync/sync_setup_wizard.h
+++ b/chrome/browser/sync/sync_setup_wizard.h
@@ -29,10 +29,11 @@ class SyncSetupWizard {
// Encryption --
// Choose what to encrypt and whether to use a passphrase.
CONFIGURE,
- // Show the screen that lets you enter a new passphrase
- CREATE_PASSPHRASE,
// Show the screen that prompts for your passphrase
ENTER_PASSPHRASE,
+ // Show the passphrase "first time" screen for migrating users, where all
+ // is explained and they choose between google password/custom passphrase.
+ PASSPHRASE_MIGRATION,
// The panic switch. Something went terribly wrong during setup and we
// can't recover.
FATAL_ERROR,
diff --git a/chrome/browser/sync/sync_setup_wizard_unittest.cc b/chrome/browser/sync/sync_setup_wizard_unittest.cc
index 46a0d69..b0da0d7b 100644
--- a/chrome/browser/sync/sync_setup_wizard_unittest.cc
+++ b/chrome/browser/sync/sync_setup_wizard_unittest.cc
@@ -312,6 +312,7 @@ TEST_F(SyncSetupWizardTest, InitialStepLogin) {
TEST_F(SyncSetupWizardTest, ChooseDataTypesSetsPrefs) {
SKIP_TEST_ON_MACOSX();
wizard_->Step(SyncSetupWizard::GAIA_LOGIN);
+ wizard_->Step(SyncSetupWizard::GAIA_SUCCESS);
wizard_->Step(SyncSetupWizard::CONFIGURE);
ListValue data_type_choices_value;
@@ -359,6 +360,22 @@ TEST_F(SyncSetupWizardTest, EnterPassphraseRequired) {
EXPECT_EQ("myPassphrase", service_->passphrase_);
}
+TEST_F(SyncSetupWizardTest, PassphraseMigration) {
+ SKIP_TEST_ON_MACOSX();
+ wizard_->Step(SyncSetupWizard::PASSPHRASE_MIGRATION);
+ ListValue value;
+ value.Append(new StringValue("{\"option\":\"explicit\","
+ "\"passphrase\":\"myPassphrase\"}"));
+ test_window_->flow()->flow_handler_->HandleFirstPassphrase(&value);
+ EXPECT_EQ("myPassphrase", service_->passphrase_);
+
+ ListValue value2;
+ value2.Append(new StringValue("{\"option\":\"nothanks\","
+ "\"passphrase\":\"myPassphrase\"}"));
+ test_window_->flow()->flow_handler_->HandleFirstPassphrase(&value2);
+ EXPECT_EQ(service_->chosen_data_types_.count(syncable::PASSWORDS), 0U);
+}
+
TEST_F(SyncSetupWizardTest, DialogCancelled) {
SKIP_TEST_ON_MACOSX();
wizard_->Step(SyncSetupWizard::GAIA_LOGIN);
diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc
index 43a97d0..d49ada1 100644
--- a/chrome/browser/sync/sync_ui_util.cc
+++ b/chrome/browser/sync/sync_ui_util.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/sync/sync_ui_util.h"
#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
#include "base/i18n/number_formatting.h"
#include "base/i18n/time_formatting.h"
#include "base/string_util.h"
@@ -13,6 +14,7 @@
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/ui/options/options_window.h"
#include "chrome/common/net/gaia/google_service_auth_error.h"
+#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -102,8 +104,28 @@ MessageType GetStatusInfo(ProfileSyncService* service,
l10n_util::GetStringUTF16(IDS_SYNC_AUTHENTICATING_LABEL));
}
result_type = PRE_SYNCED;
- } else if (auth_error.state() != AuthError::NONE ||
- service->observed_passphrase_required()) {
+ } else if (service->observed_passphrase_required()) {
+ if (service->passphrase_required_for_decryption()) {
+ // NOT first machine.
+ // Show a link and present as an error ("needs attention").
+ if (status_label && link_label) {
+ status_label->assign(string16());
+ link_label->assign(
+ l10n_util::GetStringUTF16(IDS_SYNC_CONFIGURE_ENCRYPTION));
+ }
+ result_type = SYNC_ERROR;
+ } else {
+ // First machine. Show as a promotion.
+ if (status_label && link_label) {
+ status_label->assign(
+ l10n_util::GetStringFUTF16(IDS_SYNC_NTP_PASSWORD_PROMO,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
+ link_label->assign(
+ l10n_util::GetStringUTF16(IDS_SYNC_NTP_PASSWORD_ENABLE));
+ }
+ result_type = SYNC_PROMO;
+ }
+ } else if (auth_error.state() != AuthError::NONE) {
if (status_label && link_label) {
GetStatusLabelsForAuthError(auth_error, service,
status_label, link_label);
@@ -156,6 +178,20 @@ MessageType GetStatusInfo(ProfileSyncService* service,
} // namespace
+// Returns an HTML chunk for a login prompt related to encryption.
+string16 GetLoginMessageForEncryption() {
+ std::vector<std::string> subst;
+ const base::StringPiece html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_SYNC_ENCRYPTION_LOGIN_HTML));
+ subst.push_back(l10n_util::GetStringUTF8(IDS_SYNC_PLEASE_SIGN_IN));
+ subst.push_back(
+ l10n_util::GetStringFUTF8(IDS_SYNC_LOGIN_FOR_ENCRYPTION,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
+
+ return UTF8ToUTF16(ReplaceStringPlaceholders(html, subst, NULL));
+}
+
MessageType GetStatusLabels(ProfileSyncService* service,
string16* status_label,
string16* link_label) {
diff --git a/chrome/browser/sync/sync_ui_util.h b/chrome/browser/sync/sync_ui_util.h
index 8bcd85a..5a168c4 100644
--- a/chrome/browser/sync/sync_ui_util.h
+++ b/chrome/browser/sync/sync_ui_util.h
@@ -24,11 +24,15 @@ enum MessageType {
PRE_SYNCED, // User has not set up sync.
SYNCED, // We are synced and authenticated to a gmail account.
SYNC_ERROR, // A sync error (such as invalid credentials) has occurred.
+ SYNC_PROMO, // A situation has occurred which should be brought to the user's
+ // attention, but not as an error.
};
// TODO(akalin): audit the use of ProfileSyncService* service below,
// and use const ProfileSyncService& service where possible.
+string16 GetLoginMessageForEncryption();
+
// Create status and link labels for the current status labels and link text
// by querying |service|.
MessageType GetStatusLabels(ProfileSyncService* service,
@@ -60,4 +64,3 @@ void AddIntSyncDetail(ListValue* details,
int64 stat_value);
} // namespace sync_ui_util
#endif // CHROME_BROWSER_SYNC_SYNC_UI_UTIL_H_
-