summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/sync/engine/syncapi.cc64
-rw-r--r--chrome/browser/sync/engine/syncapi.h9
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.cc20
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.h11
-rw-r--r--chrome/browser/sync/profile_sync_service.cc52
-rw-r--r--chrome/browser/sync/profile_sync_service.h29
-rw-r--r--chrome/browser/sync/profile_sync_service_harness.cc24
-rw-r--r--chrome/browser/sync/profile_sync_service_harness.h18
-rw-r--r--chrome/browser/sync/profile_sync_service_password_unittest.cc2
-rw-r--r--chrome/browser/sync/protocol/nigori_specifics.proto3
-rw-r--r--chrome/browser/sync/resources/passphrase.html7
-rw-r--r--chrome/browser/sync/sync_setup_flow.cc26
-rw-r--r--chrome/browser/sync/sync_setup_flow.h3
-rw-r--r--chrome/browser/sync/sync_setup_wizard_unittest.cc6
-rw-r--r--chrome/test/live_sync/two_client_live_passwords_sync_test.cc14
15 files changed, 221 insertions, 67 deletions
diff --git a/chrome/browser/sync/engine/syncapi.cc b/chrome/browser/sync/engine/syncapi.cc
index b453a52..9d42312 100644
--- a/chrome/browser/sync/engine/syncapi.cc
+++ b/chrome/browser/sync/engine/syncapi.cc
@@ -976,7 +976,13 @@ class SyncManager::SyncInternal
// Tell the sync engine to start the syncing process.
void StartSyncing();
- void SetPassphrase(const std::string& passphrase);
+ // Whether or not the Nigori node is encrypted using an explicit passphrase.
+ bool IsUsingExplicitPassphrase();
+
+ // Try to set the current passphrase to |passphrase|, and record whether
+ // it is an explicit passphrase or implicitly using gaia in the Nigori
+ // node.
+ void SetPassphrase(const std::string& passphrase, bool is_explicit);
// Call periodically from a database-safe thread to persist recent changes
// to the syncapi model.
@@ -1173,6 +1179,12 @@ class SyncManager::SyncInternal
// decryption. Otherwise, the cryptographer is made ready (is_ready()).
void BootstrapEncryption(const std::string& restored_key_for_bootstrapping);
+ // Helper for migration to new nigori proto to set
+ // 'using_explicit_passphrase' in the NigoriSpecifics.
+ // TODO(tim): Bug 62103. Remove this after it has been pushed out to dev
+ // channel users.
+ void SetUsingExplicitPassphrasePrefForMigration();
+
// Checks for server reachabilty and requests a nudge.
void OnIPAddressChangedImpl();
@@ -1297,8 +1309,13 @@ void SyncManager::StartSyncing() {
data_->StartSyncing();
}
-void SyncManager::SetPassphrase(const std::string& passphrase) {
- data_->SetPassphrase(passphrase);
+void SyncManager::SetPassphrase(const std::string& passphrase,
+ bool is_explicit) {
+ data_->SetPassphrase(passphrase, is_explicit);
+}
+
+bool SyncManager::IsUsingExplicitPassphrase() {
+ return data_ && data_->IsUsingExplicitPassphrase();
}
bool SyncManager::RequestPause() {
@@ -1572,8 +1589,21 @@ void SyncManager::SyncInternal::RaiseAuthNeededEvent() {
}
}
+void SyncManager::SyncInternal::SetUsingExplicitPassphrasePrefForMigration() {
+ WriteTransaction trans(&share_);
+ WriteNode node(&trans);
+ if (!node.InitByTagLookup(kNigoriTag)) {
+ // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
+ NOTREACHED();
+ return;
+ }
+ sync_pb::NigoriSpecifics specifics(node.GetNigoriSpecifics());
+ specifics.set_using_explicit_passphrase(true);
+ node.SetNigoriSpecifics(specifics);
+}
+
void SyncManager::SyncInternal::SetPassphrase(
- const std::string& passphrase) {
+ const std::string& passphrase, bool is_explicit) {
Cryptographer* cryptographer = dir_manager()->cryptographer();
KeyParams params = {"localhost", "dummy", passphrase};
if (cryptographer->has_pending_keys()) {
@@ -1581,6 +1611,13 @@ void SyncManager::SyncInternal::SetPassphrase(
observer_->OnPassphraseRequired();
return;
}
+
+ // TODO(tim): If this is the first time the user has entered a passphrase
+ // since the protocol changed to store passphrase preferences in the cloud,
+ // make sure we update this preference. See bug 62103.
+ if (is_explicit)
+ SetUsingExplicitPassphrasePrefForMigration();
+
// Nudge the syncer so that passwords updates that were waiting for this
// passphrase get applied as soon as possible.
sync_manager_->RequestNudge();
@@ -1592,6 +1629,12 @@ void SyncManager::SyncInternal::SetPassphrase(
NOTREACHED();
return;
}
+
+ // Prevent an implicit SetPassphrase request from changing an explicitly
+ // set passphrase.
+ if (!is_explicit && node.GetNigoriSpecifics().using_explicit_passphrase())
+ return;
+
cryptographer->AddKey(params);
// TODO(tim): Bug 58231. It would be nice if SetPassphrase didn't require
@@ -1600,6 +1643,7 @@ void SyncManager::SyncInternal::SetPassphrase(
// safe to defer this work.
sync_pb::NigoriSpecifics specifics;
cryptographer->GetKeys(specifics.mutable_encrypted());
+ specifics.set_using_explicit_passphrase(is_explicit);
node.SetNigoriSpecifics(specifics);
ReEncryptEverything(&trans);
}
@@ -1609,6 +1653,18 @@ void SyncManager::SyncInternal::SetPassphrase(
observer_->OnPassphraseAccepted(bootstrap_token);
}
+bool SyncManager::SyncInternal::IsUsingExplicitPassphrase() {
+ ReadTransaction trans(&share_);
+ ReadNode node(&trans);
+ if (!node.InitByTagLookup(kNigoriTag)) {
+ // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
+ NOTREACHED();
+ return false;
+ }
+
+ return node.GetNigoriSpecifics().using_explicit_passphrase();
+}
+
void SyncManager::SyncInternal::ReEncryptEverything(WriteTransaction* trans) {
// TODO(tim): bug 59242. We shouldn't lookup by data type and instead use
// a protocol flag or existence of an EncryptedData message, but for now,
diff --git a/chrome/browser/sync/engine/syncapi.h b/chrome/browser/sync/engine/syncapi.h
index 9a3da9b..6ea7b63 100644
--- a/chrome/browser/sync/engine/syncapi.h
+++ b/chrome/browser/sync/engine/syncapi.h
@@ -815,7 +815,11 @@ class SyncManager {
// If the passphrase in invalid, OnPassphraseRequired will be fired.
// Calling this metdod again is the appropriate course of action to "retry"
// with a new passphrase.
- void SetPassphrase(const std::string& passphrase);
+ // |is_explicit| is true if the call is in response to the user explicitly
+ // setting a passphrase as opposed to implicitly (from the users' perspective)
+ // using their Google Account password. An implicit SetPassphrase will *not*
+ // *not* override an explicit passphrase set previously.
+ void SetPassphrase(const std::string& passphrase, bool is_explicit);
// Requests the syncer thread to pause. The observer's OnPause
// method will be called when the syncer thread is paused. Returns
@@ -852,6 +856,9 @@ class SyncManager {
Status::Summary GetStatusSummary() const;
Status GetDetailedStatus() const;
+ // Whether or not the Nigori node is encrypted using an explicit passphrase.
+ bool IsUsingExplicitPassphrase();
+
// Get the internal implementation for use by BaseTransaction, etc.
SyncInternal* GetImpl() const;
diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc
index 7d833bd..342e989 100644
--- a/chrome/browser/sync/glue/sync_backend_host.cc
+++ b/chrome/browser/sync/glue/sync_backend_host.cc
@@ -158,6 +158,12 @@ bool SyncBackendHost::IsNigoriEnabled() const {
registrar_.routing_info.end();
}
+bool SyncBackendHost::IsUsingExplicitPassphrase() {
+ return IsNigoriEnabled() && syncapi_initialized_ &&
+ core_->syncapi()->InitialSyncEndedForAllEnabledTypes() &&
+ core_->syncapi()->IsUsingExplicitPassphrase();
+}
+
bool SyncBackendHost::IsCryptographerReady() const {
return syncapi_initialized_ &&
GetUserShareHandle()->dir_manager->cryptographer()->is_ready();
@@ -186,7 +192,8 @@ void SyncBackendHost::StartSyncingWithServer() {
NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoStartSyncing));
}
-void SyncBackendHost::SetPassphrase(const std::string& passphrase) {
+void SyncBackendHost::SetPassphrase(const std::string& passphrase,
+ bool is_explicit) {
if (!IsNigoriEnabled()) {
LOG(WARNING) << "Silently dropping SetPassphrase request.";
return;
@@ -195,7 +202,7 @@ void SyncBackendHost::SetPassphrase(const std::string& passphrase) {
// If encryption is enabled and we've got a SetPassphrase
core_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoSetPassphrase,
- passphrase));
+ passphrase, is_explicit));
}
void SyncBackendHost::Shutdown(bool sync_disabled) {
@@ -385,6 +392,8 @@ void SyncBackendHost::Core::NotifyPassphraseRequired() {
void SyncBackendHost::Core::NotifyPassphraseAccepted(
const std::string& bootstrap_token) {
+ if (!host_)
+ return;
host_->PersistEncryptionBootstrapToken(bootstrap_token);
NotificationService::current()->Notify(
NotificationType::SYNC_PASSPHRASE_ACCEPTED,
@@ -393,6 +402,8 @@ void SyncBackendHost::Core::NotifyPassphraseAccepted(
}
void SyncBackendHost::Core::NotifyUpdatedToken(const std::string& token) {
+ if (!host_)
+ return;
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
TokenAvailableDetails details(GaiaConstants::kSyncService, token);
NotificationService::current()->Notify(
@@ -526,9 +537,10 @@ void SyncBackendHost::Core::DoStartSyncing() {
syncapi_->StartSyncing();
}
-void SyncBackendHost::Core::DoSetPassphrase(const std::string& passphrase) {
+void SyncBackendHost::Core::DoSetPassphrase(const std::string& passphrase,
+ bool is_explicit) {
DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
- syncapi_->SetPassphrase(passphrase);
+ syncapi_->SetPassphrase(passphrase, is_explicit);
}
UIModelWorker* SyncBackendHost::ui_worker() {
diff --git a/chrome/browser/sync/glue/sync_backend_host.h b/chrome/browser/sync/glue/sync_backend_host.h
index 26d060a..0b8f94e 100644
--- a/chrome/browser/sync/glue/sync_backend_host.h
+++ b/chrome/browser/sync/glue/sync_backend_host.h
@@ -124,7 +124,11 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
virtual void StartSyncingWithServer();
// Called on |frontend_loop_| to asynchronously set the passphrase.
- void SetPassphrase(const std::string& passphrase);
+ // |is_explicit| is true if the call is in response to the user explicitly
+ // setting a passphrase as opposed to implicitly (from the users' perspective)
+ // using their Google Account password. An implicit SetPassphrase will *not*
+ // *not* override an explicit passphrase set previously.
+ void SetPassphrase(const std::string& passphrase, bool is_explicit);
// Called on |frontend_loop_| to kick off shutdown.
// |sync_disabled| indicates if syncing is being disabled or not.
@@ -194,6 +198,9 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// Whether or not we are syncing encryption keys.
bool IsNigoriEnabled() const;
+ // Whether or not the Nigori node is encrypted using an explicit passphrase.
+ bool IsUsingExplicitPassphrase();
+
// True if the cryptographer has any keys available to attempt decryption.
// Could mean we've downloaded and loaded Nigori objects, or we bootstrapped
// using a token previously received.
@@ -282,7 +289,7 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// Called on our SyncBackendHost's |core_thread_| to set the passphrase
// on behalf of SyncBackendHost::SupplyPassphrase.
- void DoSetPassphrase(const std::string& passphrase);
+ void DoSetPassphrase(const std::string& passphrase, bool is_explicit);
// The shutdown order is a bit complicated:
// 1) From |core_thread_|, invoke the syncapi Shutdown call to do a final
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index 7b210d0..c235ad5 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -75,7 +75,6 @@ ProfileSyncService::ProfileSyncService(ProfileSyncFactory* factory,
unrecoverable_error_detected_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(scoped_runnable_method_factory_(this)),
token_migrator_(NULL),
-
clear_server_data_state_(CLEAR_NOT_STARTED) {
DCHECK(factory);
DCHECK(profile);
@@ -97,6 +96,8 @@ ProfileSyncService::ProfileSyncService(ProfileSyncFactory* factory,
sync_service_url_ = GURL(kSyncServerUrl);
}
#endif
+
+ tried_implicit_gaia_remove_when_bug_62103_fixed_ = false;
}
ProfileSyncService::ProfileSyncService()
@@ -365,8 +366,6 @@ void ProfileSyncService::RegisterPreferences() {
enable_by_default);
pref_service->RegisterBooleanPref(prefs::kSyncManaged, false);
pref_service->RegisterStringPref(prefs::kEncryptionBootstrapToken, "");
- pref_service->RegisterBooleanPref(prefs::kSyncUsingSecondaryPassphrase,
- false);
}
void ProfileSyncService::ClearPreferences() {
@@ -374,7 +373,6 @@ void ProfileSyncService::ClearPreferences() {
pref_service->ClearPref(prefs::kSyncLastSyncedTime);
pref_service->ClearPref(prefs::kSyncHasSetupCompleted);
pref_service->ClearPref(prefs::kEncryptionBootstrapToken);
- pref_service->ClearPref(prefs::kSyncUsingSecondaryPassphrase);
// TODO(nick): The current behavior does not clear e.g. prefs::kSyncBookmarks.
// Is that really what we want?
@@ -923,12 +921,9 @@ void ProfileSyncService::GetRegisteredDataTypes(
}
bool ProfileSyncService::IsUsingSecondaryPassphrase() const {
- return profile_->GetPrefs()->GetBoolean(prefs::kSyncUsingSecondaryPassphrase);
-}
-
-void ProfileSyncService::SetSecondaryPassphrase(const std::string& passphrase) {
- SetPassphrase(passphrase);
- profile_->GetPrefs()->SetBoolean(prefs::kSyncUsingSecondaryPassphrase, true);
+ return backend_.get() && backend_->IsUsingExplicitPassphrase() ||
+ (tried_implicit_gaia_remove_when_bug_62103_fixed_ &&
+ observed_passphrase_required_);
}
bool ProfileSyncService::IsCryptographerReady() const {
@@ -973,11 +968,13 @@ void ProfileSyncService::DeactivateDataType(
backend_->DeactivateDataType(data_type_controller, change_processor);
}
-void ProfileSyncService::SetPassphrase(const std::string& passphrase) {
+void ProfileSyncService::SetPassphrase(const std::string& passphrase,
+ bool is_explicit) {
if (ShouldPushChanges() || observed_passphrase_required_) {
- backend_->SetPassphrase(passphrase);
+ backend_->SetPassphrase(passphrase, is_explicit);
} else {
- cached_passphrase_ = passphrase;
+ cached_passphrase_.value = passphrase;
+ cached_passphrase_.is_explicit = is_explicit;
}
}
@@ -1003,10 +1000,11 @@ void ProfileSyncService::Observe(NotificationType type,
return;
}
- if (!cached_passphrase_.empty()) {
+ if (!cached_passphrase_.value.empty()) {
// Don't hold on to the passphrase in raw form longer than needed.
- SetPassphrase(cached_passphrase_);
- cached_passphrase_.clear();
+ SetPassphrase(cached_passphrase_.value,
+ cached_passphrase_.is_explicit);
+ cached_passphrase_ = CachedPassphrase();
}
// TODO(sync): Less wizard, more toast.
@@ -1021,9 +1019,10 @@ void ProfileSyncService::Observe(NotificationType type,
DCHECK(backend_->IsNigoriEnabled());
observed_passphrase_required_ = true;
- if (!cached_passphrase_.empty()) {
- SetPassphrase(cached_passphrase_);
- cached_passphrase_.clear();
+ if (!cached_passphrase_.value.empty()) {
+ SetPassphrase(cached_passphrase_.value,
+ cached_passphrase_.is_explicit);
+ cached_passphrase_ = CachedPassphrase();
break;
}
@@ -1068,12 +1067,15 @@ void ProfileSyncService::Observe(NotificationType type,
break;
}
case NotificationType::GOOGLE_SIGNIN_SUCCESSFUL: {
- PrefService* prefs = profile_->GetPrefs();
- if (!prefs->GetBoolean(prefs::kSyncUsingSecondaryPassphrase)) {
- const GoogleServiceSigninSuccessDetails* successful =
- (Details<const GoogleServiceSigninSuccessDetails>(details).ptr());
- SetPassphrase(successful->password);
- }
+ const GoogleServiceSigninSuccessDetails* successful =
+ (Details<const GoogleServiceSigninSuccessDetails>(details).ptr());
+ // We pass 'false' to SetPassphrase to denote that this is an implicit
+ // request and shouldn't override an explicit one. Thus, we either
+ // update the implicit passphrase (idempotent if the passphrase didn't
+ // actually change), or the user has an explicit passphrase set so this
+ // becomes a no-op.
+ tried_implicit_gaia_remove_when_bug_62103_fixed_ = true;
+ SetPassphrase(successful->password, false);
break;
}
case NotificationType::GOOGLE_SIGNIN_FAILED: {
diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h
index 65f18f5..d4cb576 100644
--- a/chrome/browser/sync/profile_sync_service.h
+++ b/chrome/browser/sync/profile_sync_service.h
@@ -340,14 +340,15 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
// Returns true if a secondary passphrase is being used.
virtual bool IsUsingSecondaryPassphrase() const;
- // Sets the secondary passphrase.
- virtual void SetSecondaryPassphrase(const std::string& passphrase);
-
// Sets the Cryptographer's passphrase, or caches it until that is possible.
// This will check asynchronously whether the passphrase is valid and notify
// ProfileSyncServiceObservers via the NotificationService when the outcome
// is known.
- virtual void SetPassphrase(const std::string& passphrase);
+ // |is_explicit| is true if the call is in response to the user explicitly
+ // setting a passphrase as opposed to implicitly (from the users' perspective)
+ // using their Google Account password. An implicit SetPassphrase will *not*
+ // *not* override an explicit passphrase set previously.
+ virtual void SetPassphrase(const std::string& passphrase, bool is_explicit);
// Returns whether processing changes is allowed. Check this before doing
// any model-modifying operations.
@@ -485,7 +486,7 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
NotificationRegistrar registrar_;
ScopedRunnableMethodFactory<ProfileSyncService>
- scoped_runnable_method_factory_;
+ scoped_runnable_method_factory_;
// The preference that controls whether sync is under control by configuration
// management.
@@ -502,13 +503,27 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
// yet have a backend to send it to. This happens during initialization as
// we don't StartUp until we have a valid token, which happens after valid
// credentials were provided.
- std::string cached_passphrase_;
+ struct CachedPassphrase {
+ std::string value;
+ bool is_explicit;
+ CachedPassphrase() : is_explicit(false) {}
+ };
+ CachedPassphrase cached_passphrase_;
+
+ // TODO(tim): Remove this once new 'explicit passphrase' code flushes through
+ // dev channel. See bug 62103.
+ // To "migrate" early adopters of password sync on dev channel to the new
+ // model that stores their secondary passphrase preference in the cloud, we
+ // need some extra state since this cloud pref will be empty for all of them
+ // regardless of how they set up sync, and we can't trust
+ // kSyncUsingSecondaryPassphrase due to bugs in that implementation.
+ bool tried_implicit_gaia_remove_when_bug_62103_fixed_;
// Keep track of where we are in a server clear operation
ClearServerDataState clear_server_data_state_;
// Timeout for the clear data command. This timeout is a temporary hack
- // and is necessary becaue the nudge sync framework can drop nudges for
+ // and is necessary because the nudge sync framework can drop nudges for
// a wide variety of sync-related conditions (throttling, connections issues,
// syncer paused, etc.). It can only be removed correctly when the framework
// is reworked to allow one-shot commands like clearing server data.
diff --git a/chrome/browser/sync/profile_sync_service_harness.cc b/chrome/browser/sync/profile_sync_service_harness.cc
index 4750033..d86c286 100644
--- a/chrome/browser/sync/profile_sync_service_harness.cc
+++ b/chrome/browser/sync/profile_sync_service_harness.cc
@@ -14,6 +14,7 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/net/gaia/google_service_auth_error.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/pref_names.h"
// The default value for min_timestamp_needed_ when we're not in the
@@ -95,6 +96,7 @@ ProfileSyncServiceHarness::ProfileSyncServiceHarness(
min_timestamp_needed_(kMinTimestampNeededNone),
username_(username),
password_(password),
+ passphrase_acceptance_counter_(0),
id_(id) {
if (IsSyncAlreadySetup()) {
service_ = profile_->GetProfileSyncService();
@@ -132,6 +134,14 @@ bool ProfileSyncServiceHarness::SetupSync() {
return SetupSync(synced_datatypes);
}
+void ProfileSyncServiceHarness::StartObservingPassphraseAcceptance() {
+ // Prime the counter to account for the implicit set passphrase due to
+ // gaia login.
+ passphrase_acceptance_counter_--;
+ registrar_.Add(this, NotificationType::SYNC_PASSPHRASE_ACCEPTED,
+ Source<browser_sync::SyncBackendHost>(service_->backend()));
+}
+
bool ProfileSyncServiceHarness::SetupSync(
const syncable::ModelTypeSet& synced_datatypes) {
// Initialize the sync client's profile sync service object.
@@ -198,6 +208,7 @@ bool ProfileSyncServiceHarness::RunStateChangeMachine() {
if (service()->sync_initialized()) {
// The sync backend is initialized. Start waiting for the first sync
// cycle to complete.
+ StartObservingPassphraseAcceptance();
SignalStateCompleteWithNextState(WAITING_FOR_INITIAL_SYNC);
}
break;
@@ -251,7 +262,7 @@ bool ProfileSyncServiceHarness::RunStateChangeMachine() {
}
case WAITING_FOR_PASSPHRASE_ACCEPTED: {
LogClientInfo("WAITING_FOR_PASSPHRASE_ACCEPTED");
- if (!service()->observed_passphrase_required())
+ if (passphrase_acceptance_counter_ >= 0)
SignalStateCompleteWithNextState(FULLY_SYNCED);
break;
}
@@ -278,13 +289,21 @@ bool ProfileSyncServiceHarness::AwaitPassphraseAccepted() {
LOG(ERROR) << "Sync disabled for Client " << id_ << ".";
return false;
}
- if (!service()->observed_passphrase_required())
+ passphrase_acceptance_counter_--;
+ if (passphrase_acceptance_counter_ >= 0)
return true;
wait_state_ = WAITING_FOR_PASSPHRASE_ACCEPTED;
return AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs,
"Waiting for passphrase accepted.");
}
+void ProfileSyncServiceHarness::Observe(NotificationType type,
+ const NotificationSource& source, const NotificationDetails& details) {
+ DCHECK_EQ(NotificationType::SYNC_PASSPHRASE_ACCEPTED, type.value);
+ passphrase_acceptance_counter_++;
+ RunStateChangeMachine();
+}
+
bool ProfileSyncServiceHarness::AwaitSyncCycleCompletion(
const std::string& reason) {
LogClientInfo("AwaitSyncCycleCompletion");
@@ -412,6 +431,7 @@ bool ProfileSyncServiceHarness::IsSynced() {
// TODO(rsimha): Remove additional checks of snap->has_more_to_sync and
// snap->unsynced_count once http://crbug.com/48989 is fixed.
return (snap &&
+ snap->num_conflicting_updates == 0 && // We can decrypt everything.
ServiceIsPushingChanges() &&
GetStatus().notifications_enabled &&
!service()->backend()->HasUnsyncedItems() &&
diff --git a/chrome/browser/sync/profile_sync_service_harness.h b/chrome/browser/sync/profile_sync_service_harness.h
index a50bb8a..383c786 100644
--- a/chrome/browser/sync/profile_sync_service_harness.h
+++ b/chrome/browser/sync/profile_sync_service_harness.h
@@ -11,6 +11,8 @@
#include "base/time.h"
#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
using browser_sync::sessions::SyncSessionSnapshot;
@@ -21,7 +23,8 @@ class Profile;
// profile passed to it on construction and automates certain things like setup
// and authentication. It provides ways to "wait" adequate periods of time for
// several clients to get to the same state.
-class ProfileSyncServiceHarness : public ProfileSyncServiceObserver {
+class ProfileSyncServiceHarness : public ProfileSyncServiceObserver,
+ public NotificationObserver {
public:
ProfileSyncServiceHarness(Profile* profile,
const std::string& username,
@@ -54,6 +57,11 @@ class ProfileSyncServiceHarness : public ProfileSyncServiceObserver {
// ProfileSyncServiceObserver implementation.
virtual void OnStateChanged();
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
// Blocks the caller until this harness has completed a single sync cycle
// since the previous one. Returns true if a sync cycle has completed.
bool AwaitSyncCycleCompletion(const std::string& reason);
@@ -172,6 +180,8 @@ class ProfileSyncServiceHarness : public ProfileSyncServiceObserver {
// Returns the new value of |last_timestamp_|.
int64 GetUpdatedTimestamp();
+ void StartObservingPassphraseAcceptance();
+
WaitState wait_state_;
Profile* profile_;
@@ -191,6 +201,12 @@ class ProfileSyncServiceHarness : public ProfileSyncServiceObserver {
std::string username_;
std::string password_;
+ // A counter to track the number of await passphrase requests versus
+ // actual acceptances. Can go negative if #requests > #acceptances.
+ int passphrase_acceptance_counter_;
+
+ NotificationRegistrar registrar_;
+
// Client ID, used for logging purposes.
int id_;
diff --git a/chrome/browser/sync/profile_sync_service_password_unittest.cc b/chrome/browser/sync/profile_sync_service_password_unittest.cc
index 43ee1fb..dfb172b 100644
--- a/chrome/browser/sync/profile_sync_service_password_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_password_unittest.cc
@@ -198,7 +198,7 @@ class ProfileSyncServicePasswordTest : public AbstractProfileSyncServiceTest {
NotificationType(NotificationType::SYNC_CONFIGURE_DONE),
_,_)).
WillOnce(QuitUIMessageLoop());
- service_->SetPassphrase("foo");
+ service_->SetPassphrase("foo", false);
MessageLoop::current()->Run();
}
}
diff --git a/chrome/browser/sync/protocol/nigori_specifics.proto b/chrome/browser/sync/protocol/nigori_specifics.proto
index aa33ba6..e7458c6 100644
--- a/chrome/browser/sync/protocol/nigori_specifics.proto
+++ b/chrome/browser/sync/protocol/nigori_specifics.proto
@@ -28,6 +28,9 @@ message NigoriKeyBag {
// Properties of nigori sync object.
message NigoriSpecifics {
optional EncryptedData encrypted = 1;
+ // True if |encrypted| is encrypted using a passphrase
+ // explicitly set by the user.
+ optional bool using_explicit_passphrase = 2;
}
extend EntitySpecifics {
diff --git a/chrome/browser/sync/resources/passphrase.html b/chrome/browser/sync/resources/passphrase.html
index e18da44..4ea8317 100644
--- a/chrome/browser/sync/resources/passphrase.html
+++ b/chrome/browser/sync/resources/passphrase.html
@@ -52,8 +52,8 @@ html[os='mac'] input[type='submit'] {
</style>
<script src="chrome://resources/js/cr.js"></script>
-<script>
- var currentTab;
+<script>
+ var currentMode;
// Called once, when this html/js is loaded.
function setupPassphraseDialog(args) {
@@ -88,7 +88,8 @@ html[os='mac'] input[type='submit'] {
function sendPassphraseAndClose() {
var f = document.getElementById("passphraseForm");
- var result = JSON.stringify({"passphrase": f.passphrase.value});
+ var result = JSON.stringify({"passphrase": f.passphrase.value,
+ "mode": currentMode});
chrome.send("Passphrase", [result]);
}
</script>
diff --git a/chrome/browser/sync/sync_setup_flow.cc b/chrome/browser/sync/sync_setup_flow.cc
index 08dcfa1..ff923da 100644
--- a/chrome/browser/sync/sync_setup_flow.cc
+++ b/chrome/browser/sync/sync_setup_flow.cc
@@ -68,13 +68,15 @@ static bool GetAuthData(const std::string& json,
return true;
}
-static bool GetPassphrase(const std::string& json, std::string* passphrase) {
+bool GetPassphrase(const std::string& json, std::string* passphrase,
+ std::string* mode) {
scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
return false;
DictionaryValue* result = static_cast<DictionaryValue*>(parsed_value.get());
- return result->GetString("passphrase", passphrase);
+ return result->GetString("passphrase", passphrase) &&
+ result->GetString("mode", mode);
}
static bool GetConfiguration(const std::string& json,
@@ -194,14 +196,15 @@ void FlowHandler::HandlePassphraseEntry(const ListValue* args) {
return;
std::string passphrase;
- if (!GetPassphrase(json, &passphrase)) {
+ std::string mode;
+ if (!GetPassphrase(json, &passphrase, &mode)) {
// Couldn't understand what the page sent. Indicates a programming error.
NOTREACHED();
return;
}
DCHECK(flow_);
- flow_->OnPassphraseEntry(passphrase);
+ flow_->OnPassphraseEntry(passphrase, mode);
}
// Called by SyncSetupFlow::Advance.
@@ -654,6 +657,10 @@ void SyncSetupFlow::OnUserConfigured(const SyncConfiguration& configuration) {
// 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;
}
@@ -674,8 +681,9 @@ void SyncSetupFlow::OnConfigurationComplete() {
configuration_.secondary_passphrase.length() > 0);
if (configuration_.use_secondary_passphrase &&
- !service_->IsUsingSecondaryPassphrase())
- service_->SetSecondaryPassphrase(configuration_.secondary_passphrase);
+ !service_->IsUsingSecondaryPassphrase()) {
+ service_->SetPassphrase(configuration_.secondary_passphrase, true);
+ }
service_->OnUserChoseDatatypes(configuration_.sync_everything,
configuration_.data_types);
@@ -683,11 +691,13 @@ void SyncSetupFlow::OnConfigurationComplete() {
configuration_pending_ = false;
}
-void SyncSetupFlow::OnPassphraseEntry(const std::string& passphrase) {
+void SyncSetupFlow::OnPassphraseEntry(const std::string& passphrase,
+ const std::string& mode) {
if (current_state_ == SyncSetupWizard::ENTER_PASSPHRASE) {
- service_->SetSecondaryPassphrase(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();
}
diff --git a/chrome/browser/sync/sync_setup_flow.h b/chrome/browser/sync/sync_setup_flow.h
index 4b4b034..7d64402 100644
--- a/chrome/browser/sync/sync_setup_flow.h
+++ b/chrome/browser/sync/sync_setup_flow.h
@@ -115,7 +115,8 @@ class SyncSetupFlow : public HtmlDialogUIDelegate {
void OnUserConfigured(const SyncConfiguration& configuration);
- void OnPassphraseEntry(const std::string& passphrase);
+ void OnPassphraseEntry(const std::string& passphrase,
+ const std::string& mode);
void OnConfigurationComplete();
diff --git a/chrome/browser/sync/sync_setup_wizard_unittest.cc b/chrome/browser/sync/sync_setup_wizard_unittest.cc
index ba432af..c8b733c 100644
--- a/chrome/browser/sync/sync_setup_wizard_unittest.cc
+++ b/chrome/browser/sync/sync_setup_wizard_unittest.cc
@@ -59,7 +59,8 @@ class ProfileSyncServiceForWizardTest : public ProfileSyncService {
user_cancelled_dialog_ = true;
}
- virtual void SetSecondaryPassphrase(const std::string& passphrase) {
+ virtual void SetPassphrase(const std::string& passphrase,
+ bool is_explicit) {
passphrase_ = passphrase;
}
@@ -352,7 +353,8 @@ TEST_F(SyncSetupWizardTest, EnterPassphraseRequired) {
EXPECT_EQ(SyncSetupWizard::ENTER_PASSPHRASE,
test_window_->flow()->current_state_);
ListValue value;
- value.Append(new StringValue("{\"passphrase\":\"myPassphrase\"}"));
+ value.Append(new StringValue("{\"passphrase\":\"myPassphrase\","
+ "\"mode\":\"gaia\"}"));
test_window_->flow()->flow_handler_->HandlePassphraseEntry(&value);
EXPECT_EQ("myPassphrase", service_->passphrase_);
}
diff --git a/chrome/test/live_sync/two_client_live_passwords_sync_test.cc b/chrome/test/live_sync/two_client_live_passwords_sync_test.cc
index 764ac52..3444e4e 100644
--- a/chrome/test/live_sync/two_client_live_passwords_sync_test.cc
+++ b/chrome/test/live_sync/two_client_live_passwords_sync_test.cc
@@ -68,12 +68,13 @@ IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, Race) {
}
// Marked as FAILS -- see http://crbug.com/59867.
-IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, FAILS_SetPassphrase) {
+IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, SetPassphrase) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
- GetClient(0)->service()->SetPassphrase(kValidPassphrase);
+ GetClient(0)->service()->SetPassphrase(kValidPassphrase, true);
+ GetClient(0)->AwaitPassphraseAccepted();
GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1));
ASSERT_TRUE(GetClient(1)->service()->observed_passphrase_required());
- GetClient(1)->service()->SetPassphrase(kValidPassphrase);
+ GetClient(1)->service()->SetPassphrase(kValidPassphrase, true);
GetClient(1)->AwaitPassphraseAccepted();
ASSERT_FALSE(GetClient(1)->service()->observed_passphrase_required());
}
@@ -81,7 +82,8 @@ IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, FAILS_SetPassphrase) {
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest,
SetPassphraseAndAddPassword) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
- GetClient(0)->service()->SetPassphrase(kValidPassphrase);
+ GetClient(0)->service()->SetPassphrase(kValidPassphrase, true);
+ GetClient(0)->AwaitPassphraseAccepted();
PasswordForm form;
form.origin = GURL("http://www.google.com/");
@@ -95,10 +97,10 @@ IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest,
ASSERT_EQ(1, GetClient(1)->GetLastSessionSnapshot()->
num_conflicting_updates);
- GetClient(1)->service()->SetPassphrase(kValidPassphrase);
- GetClient(1)->AwaitSyncCycleCompletion("Accept passphrase and decrypt.");
+ GetClient(1)->service()->SetPassphrase(kValidPassphrase, true);
GetClient(1)->AwaitPassphraseAccepted();
ASSERT_FALSE(GetClient(1)->service()->observed_passphrase_required());
+ GetClient(1)->AwaitSyncCycleCompletion("Accept passphrase and decrypt.");
ASSERT_EQ(0, GetClient(1)->GetLastSessionSnapshot()->
num_conflicting_updates);
}