diff options
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/sync/engine/syncapi.cc | 64 | ||||
-rw-r--r-- | chrome/browser/sync/engine/syncapi.h | 9 | ||||
-rw-r--r-- | chrome/browser/sync/glue/sync_backend_host.cc | 20 | ||||
-rw-r--r-- | chrome/browser/sync/glue/sync_backend_host.h | 11 | ||||
-rw-r--r-- | chrome/browser/sync/profile_sync_service.cc | 52 | ||||
-rw-r--r-- | chrome/browser/sync/profile_sync_service.h | 29 | ||||
-rw-r--r-- | chrome/browser/sync/profile_sync_service_harness.cc | 24 | ||||
-rw-r--r-- | chrome/browser/sync/profile_sync_service_harness.h | 18 | ||||
-rw-r--r-- | chrome/browser/sync/profile_sync_service_password_unittest.cc | 2 | ||||
-rw-r--r-- | chrome/browser/sync/protocol/nigori_specifics.proto | 3 | ||||
-rw-r--r-- | chrome/browser/sync/resources/passphrase.html | 7 | ||||
-rw-r--r-- | chrome/browser/sync/sync_setup_flow.cc | 26 | ||||
-rw-r--r-- | chrome/browser/sync/sync_setup_flow.h | 3 | ||||
-rw-r--r-- | chrome/browser/sync/sync_setup_wizard_unittest.cc | 6 | ||||
-rw-r--r-- | chrome/test/live_sync/two_client_live_passwords_sync_test.cc | 14 |
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); } |