summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync
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 /chrome/browser/sync
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
Diffstat (limited to 'chrome/browser/sync')
-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
13 files changed, 633 insertions, 110 deletions
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_
-