diff options
author | maniscalco <maniscalco@chromium.org> | 2015-06-15 17:36:44 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-16 00:37:49 +0000 |
commit | 358cabb346973315059d9afbff9d9c17c4b706f2 (patch) | |
tree | 410d746f718826d83205f6416087685887b36695 | |
parent | f9f1b3f900cf87068880ad6edae608a2abca0132 (diff) | |
download | chromium_src-358cabb346973315059d9afbff9d9c17c4b706f2.zip chromium_src-358cabb346973315059d9afbff9d9c17c4b706f2.tar.gz chromium_src-358cabb346973315059d9afbff9d9c17c4b706f2.tar.bz2 |
[Sync] Add ability to save/restore Nigori to SyncEncryptionHandlerImpl
SyncEncryptionHandlerImpl now detects when a user enables passphrase
encryption locally and notifies observers with the updated Nigori
state. An observer can then use this state to restore a future instance
of SyncEncryptionHandler. The ability to save/restore Nigori across
Directory instances is a prerequisite for issuing a lightweight
"dashboard stop and clear" when a user enables passphrase encryption.
Add OnLocalSetCustomPassphrase to SyncEncryptionHandler interface.
Plumb OnLocalSetCustomPassphrase events from SyncEncryptionHandlerImpl
on the sync thread to ProfileSyncService on the UI thread.
Loosen a restriction on ModelNeutralMutableEntry's capabilities.
BUG=490836
Review URL: https://codereview.chromium.org/1177853002
Cr-Commit-Position: refs/heads/master@{#334513}
22 files changed, 355 insertions, 41 deletions
diff --git a/chrome/browser/sync/glue/sync_backend_host_core.cc b/chrome/browser/sync/glue/sync_backend_host_core.cc index 7c077cb..4589f7c 100644 --- a/chrome/browser/sync/glue/sync_backend_host_core.cc +++ b/chrome/browser/sync/glue/sync_backend_host_core.cc @@ -299,6 +299,14 @@ void SyncBackendHostCore::OnPassphraseTypeChanged( type, passphrase_time); } +void SyncBackendHostCore::OnLocalSetPassphraseEncryption( + const syncer::SyncEncryptionHandler::NigoriState& nigori_state) { + host_.Call( + FROM_HERE, + &SyncBackendHostImpl::HandleLocalSetPassphraseEncryptionOnFrontendLoop, + nigori_state); +} + void SyncBackendHostCore::OnCommitCountersUpdated( syncer::ModelType type, const syncer::CommitCounters& counters) { diff --git a/chrome/browser/sync/glue/sync_backend_host_core.h b/chrome/browser/sync/glue/sync_backend_host_core.h index 4e876636..1da2309 100644 --- a/chrome/browser/sync/glue/sync_backend_host_core.h +++ b/chrome/browser/sync/glue/sync_backend_host_core.h @@ -115,6 +115,8 @@ class SyncBackendHostCore syncer::Cryptographer* cryptographer) override; void OnPassphraseTypeChanged(syncer::PassphraseType type, base::Time passphrase_time) override; + void OnLocalSetPassphraseEncryption( + const syncer::SyncEncryptionHandler::NigoriState& nigori_state) override; // TypeDebugInfoObserver implementation void OnCommitCountersUpdated(syncer::ModelType type, diff --git a/chrome/browser/sync/glue/sync_backend_host_impl.cc b/chrome/browser/sync/glue/sync_backend_host_impl.cc index c0b7660..15f42b1 100644 --- a/chrome/browser/sync/glue/sync_backend_host_impl.cc +++ b/chrome/browser/sync/glue/sync_backend_host_impl.cc @@ -811,6 +811,12 @@ void SyncBackendHostImpl::HandlePassphraseTypeChangedOnFrontendLoop( cached_explicit_passphrase_time_ = explicit_passphrase_time; } +void SyncBackendHostImpl::HandleLocalSetPassphraseEncryptionOnFrontendLoop( + const syncer::SyncEncryptionHandler::NigoriState& nigori_state) { + DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); + frontend_->OnLocalSetPassphraseEncryption(nigori_state); +} + void SyncBackendHostImpl::HandleConnectionStatusChangeOnFrontendLoop( syncer::ConnectionStatus status) { if (!frontend_) diff --git a/chrome/browser/sync/glue/sync_backend_host_impl.h b/chrome/browser/sync/glue/sync_backend_host_impl.h index 57d99ec..e1a8e2f 100644 --- a/chrome/browser/sync/glue/sync_backend_host_impl.h +++ b/chrome/browser/sync/glue/sync_backend_host_impl.h @@ -279,6 +279,9 @@ class SyncBackendHostImpl syncer::PassphraseType type, base::Time explicit_passphrase_time); + void HandleLocalSetPassphraseEncryptionOnFrontendLoop( + const syncer::SyncEncryptionHandler::NigoriState& nigori_state); + void HandleStopSyncingPermanentlyOnFrontendLoop(); // Dispatched to from OnConnectionStatusChange to handle updating @@ -361,4 +364,3 @@ class SyncBackendHostImpl } // namespace browser_sync #endif // CHROME_BROWSER_SYNC_GLUE_SYNC_BACKEND_HOST_IMPL_H_ - diff --git a/chrome/browser/sync/glue/sync_backend_host_impl_unittest.cc b/chrome/browser/sync/glue/sync_backend_host_impl_unittest.cc index c8ef8d9..e3e0e72 100644 --- a/chrome/browser/sync/glue/sync_backend_host_impl_unittest.cc +++ b/chrome/browser/sync/glue/sync_backend_host_impl_unittest.cc @@ -106,6 +106,9 @@ class MockSyncFrontend : public sync_driver::SyncFrontend { MOCK_METHOD1(OnActionableError, void(const syncer::SyncProtocolError& sync_error)); MOCK_METHOD0(OnSyncConfigureRetry, void()); + MOCK_METHOD1( + OnLocalSetPassphraseEncryption, + void(const syncer::SyncEncryptionHandler::NigoriState& nigori_state)); }; class FakeSyncManagerFactory : public syncer::SyncManagerFactory { diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc index 68be69a..6593bd5 100644 --- a/chrome/browser/sync/profile_sync_service.cc +++ b/chrome/browser/sync/profile_sync_service.cc @@ -1412,6 +1412,18 @@ void ProfileSyncService::OnActionableError(const SyncProtocolError& error) { } } +void ProfileSyncService::OnLocalSetPassphraseEncryption( + const syncer::SyncEncryptionHandler::NigoriState& nigori_state) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + // TODO(maniscalco): At this point the user has set a custom passphrase and we + // have received the updated nigori state. Time to cache the nigori state, + // shutdown sync, then restart it and restore the cached nigori state. + // + // We should also clear the bootstrap keystore key from the pref before + // restarting sync to ensure we obtain a new, valid one when we perform the + // configuration sync cycle (crbug.com/490836). +} + void ProfileSyncService::OnConfigureDone( const DataTypeManager::ConfigureResult& result) { configure_status_ = result.status; diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h index dbac6a5..38606c7 100644 --- a/chrome/browser/sync/profile_sync_service.h +++ b/chrome/browser/sync/profile_sync_service.h @@ -420,6 +420,8 @@ class ProfileSyncService : public sync_driver::SyncService, void OnMigrationNeededForTypes(syncer::ModelTypeSet types) override; void OnExperimentsChanged(const syncer::Experiments& experiments) override; void OnActionableError(const syncer::SyncProtocolError& error) override; + void OnLocalSetPassphraseEncryption( + const syncer::SyncEncryptionHandler::NigoriState& nigori_state) override; // DataTypeManagerObserver implementation. void OnConfigureDone( diff --git a/components/sync_driver/sync_frontend.h b/components/sync_driver/sync_frontend.h index 774a553..17db8f5 100644 --- a/components/sync_driver/sync_frontend.h +++ b/components/sync_driver/sync_frontend.h @@ -134,6 +134,14 @@ class SyncFrontend { // Called when the sync cycle returns there is an user actionable error. virtual void OnActionableError(const syncer::SyncProtocolError& error) = 0; + + // Called when the user of this device enables passphrase encryption. + // + // |nigori_state| contains the new (post custom passphrase) encryption keys + // and can be used to restore SyncEncryptionHandler's state across sync + // backend instances. See also SyncEncryptionHandlerImpl::RestoreNigori. + virtual void OnLocalSetPassphraseEncryption( + const syncer::SyncEncryptionHandler::NigoriState& nigori_state) = 0; }; } // namespace sync_driver diff --git a/sync/internal_api/debug_info_event_listener.cc b/sync/internal_api/debug_info_event_listener.cc index 3e7780c..28965d2 100644 --- a/sync/internal_api/debug_info_event_listener.cc +++ b/sync/internal_api/debug_info_event_listener.cc @@ -109,6 +109,10 @@ void DebugInfoEventListener::OnPassphraseTypeChanged( CreateAndAddEvent(sync_pb::SyncEnums::PASSPHRASE_TYPE_CHANGED); } +void DebugInfoEventListener::OnLocalSetPassphraseEncryption( + const SyncEncryptionHandler::NigoriState& nigori_state) { +} + void DebugInfoEventListener::OnActionableError( const SyncProtocolError& sync_error) { DCHECK(thread_checker_.CalledOnValidThread()); diff --git a/sync/internal_api/debug_info_event_listener.h b/sync/internal_api/debug_info_event_listener.h index ba55650..fda4f5f 100644 --- a/sync/internal_api/debug_info_event_listener.h +++ b/sync/internal_api/debug_info_event_listener.h @@ -65,6 +65,8 @@ class SYNC_EXPORT_PRIVATE DebugInfoEventListener void OnCryptographerStateChanged(Cryptographer* cryptographer) override; void OnPassphraseTypeChanged(PassphraseType type, base::Time explicit_passphrase_time) override; + void OnLocalSetPassphraseEncryption( + const SyncEncryptionHandler::NigoriState& nigori_state) override; // Sync manager events. void OnNudgeFromDatatype(ModelType datatype); diff --git a/sync/internal_api/js_sync_encryption_handler_observer.cc b/sync/internal_api/js_sync_encryption_handler_observer.cc index a000fa6..7924d31 100644 --- a/sync/internal_api/js_sync_encryption_handler_observer.cc +++ b/sync/internal_api/js_sync_encryption_handler_observer.cc @@ -113,6 +113,10 @@ void JsSyncEncryptionHandlerObserver::OnPassphraseTypeChanged( JsEventDetails(&details)); } +void JsSyncEncryptionHandlerObserver::OnLocalSetPassphraseEncryption( + const SyncEncryptionHandler::NigoriState& nigori_state) { +} + void JsSyncEncryptionHandlerObserver::HandleJsEvent( const tracked_objects::Location& from_here, const std::string& name, const JsEventDetails& details) { diff --git a/sync/internal_api/js_sync_encryption_handler_observer.h b/sync/internal_api/js_sync_encryption_handler_observer.h index 82d5743..9211514 100644 --- a/sync/internal_api/js_sync_encryption_handler_observer.h +++ b/sync/internal_api/js_sync_encryption_handler_observer.h @@ -45,6 +45,8 @@ class SYNC_EXPORT_PRIVATE JsSyncEncryptionHandlerObserver void OnCryptographerStateChanged(Cryptographer* cryptographer) override; void OnPassphraseTypeChanged(PassphraseType type, base::Time explicit_passphrase_time) override; + void OnLocalSetPassphraseEncryption( + const SyncEncryptionHandler::NigoriState& nigori_state) override; private: void HandleJsEvent(const tracked_objects::Location& from_here, diff --git a/sync/internal_api/public/sync_encryption_handler.h b/sync/internal_api/public/sync_encryption_handler.h index bf5a6ef..f8f768e 100644 --- a/sync/internal_api/public/sync_encryption_handler.h +++ b/sync/internal_api/public/sync_encryption_handler.h @@ -10,10 +10,7 @@ #include "base/time/time.h" #include "sync/base/sync_export.h" #include "sync/internal_api/public/base/model_type.h" - -namespace sync_pb { -class EncryptedData; -} +#include "sync/protocol/sync.pb.h" namespace syncer { @@ -56,6 +53,8 @@ enum BootstrapTokenType { // methods must be invoked on the sync thread. class SYNC_EXPORT SyncEncryptionHandler { public: + struct NigoriState; + // All Observer methods are done synchronously from within a transaction and // on the sync thread. class SYNC_EXPORT Observer { @@ -123,10 +122,22 @@ class SYNC_EXPORT SyncEncryptionHandler { virtual void OnPassphraseTypeChanged(PassphraseType type, base::Time passphrase_time) = 0; + // The user has set a passphrase using this device. + // + // |nigori_state| can be used to restore nigori state across + // SyncEncryptionHandlerImpl lifetimes. See also SyncEncryptionHandlerImpl's + // RestoredNigori method. + virtual void OnLocalSetPassphraseEncryption( + const NigoriState& nigori_state) = 0; + protected: virtual ~Observer(); }; + struct NigoriState { + sync_pb::NigoriSpecifics nigori_specifics; + }; + SyncEncryptionHandler(); virtual ~SyncEncryptionHandler(); diff --git a/sync/internal_api/sync_encryption_handler_impl.cc b/sync/internal_api/sync_encryption_handler_impl.cc index 1e73b4a..cec5238 100644 --- a/sync/internal_api/sync_encryption_handler_impl.cc +++ b/sync/internal_api/sync_encryption_handler_impl.cc @@ -26,8 +26,11 @@ #include "sync/protocol/sync.pb.h" #include "sync/syncable/directory.h" #include "sync/syncable/entry.h" +#include "sync/syncable/mutable_entry.h" #include "sync/syncable/nigori_util.h" #include "sync/syncable/syncable_base_transaction.h" +#include "sync/syncable/syncable_model_neutral_write_transaction.h" +#include "sync/syncable/syncable_write_transaction.h" #include "sync/util/cryptographer.h" #include "sync/util/encryptor.h" #include "sync/util/time.h" @@ -783,6 +786,36 @@ base::Time SyncEncryptionHandlerImpl::custom_passphrase_time() const { return custom_passphrase_time_; } +void SyncEncryptionHandlerImpl::RestoreNigori( + const SyncEncryptionHandler::NigoriState& nigori_state) { + DCHECK(thread_checker_.CalledOnValidThread()); + WriteTransaction trans(FROM_HERE, user_share_); + + // Verify we don't already have a nigori node. + WriteNode nigori_node(&trans); + BaseNode::InitByLookupResult init_result = nigori_node.InitTypeRoot(NIGORI); + DCHECK(init_result == BaseNode::INIT_FAILED_ENTRY_NOT_GOOD); + + // Create one. + syncable::ModelNeutralMutableEntry model_neutral_mutable_entry( + trans.GetWrappedWriteTrans(), syncable::CREATE_NEW_TYPE_ROOT, NIGORI); + DCHECK(model_neutral_mutable_entry.good()); + model_neutral_mutable_entry.PutServerIsDir(true); + model_neutral_mutable_entry.PutUniqueServerTag(ModelTypeToRootTag(NIGORI)); + model_neutral_mutable_entry.PutIsUnsynced(true); + + // Update it with the saved nigori specifics. + syncable::MutableEntry mutable_entry(trans.GetWrappedWriteTrans(), + syncable::GET_TYPE_ROOT, NIGORI); + DCHECK(mutable_entry.good()); + sync_pb::EntitySpecifics specifics; + specifics.mutable_nigori()->CopyFrom(nigori_state.nigori_specifics); + mutable_entry.PutSpecifics(specifics); + + // Update our state based on the saved nigori node. + ApplyNigoriUpdate(nigori_state.nigori_specifics, trans.GetWrappedTrans()); +} + // This function iterates over all encrypted types. There are many scenarios in // which data for some or all types is not currently available. In that case, // the lookup of the root node will fail and we will skip encryption for that @@ -1126,22 +1159,36 @@ void SyncEncryptionHandlerImpl::SetCustomPassphrase( } std::string bootstrap_token; - if (cryptographer->AddKey(key_params)) { - DVLOG(1) << "Setting custom passphrase."; - cryptographer->GetBootstrapToken(&bootstrap_token); - passphrase_type_ = CUSTOM_PASSPHRASE; - custom_passphrase_time_ = base::Time::Now(); - FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, - OnPassphraseTypeChanged( - passphrase_type_, - GetExplicitPassphraseTime())); - } else { + if (!cryptographer->AddKey(key_params)) { NOTREACHED() << "Failed to add key to cryptographer."; return; } + + DVLOG(1) << "Setting custom passphrase."; + cryptographer->GetBootstrapToken(&bootstrap_token); + passphrase_type_ = CUSTOM_PASSPHRASE; + custom_passphrase_time_ = base::Time::Now(); + FOR_EACH_OBSERVER( + SyncEncryptionHandler::Observer, observers_, + OnPassphraseTypeChanged(passphrase_type_, GetExplicitPassphraseTime())); FinishSetPassphrase(true, bootstrap_token, trans, nigori_node); } +void SyncEncryptionHandlerImpl::NotifyObserversOfLocalCustomPassphrase( + WriteTransaction* trans) { + WriteNode nigori_node(trans); + BaseNode::InitByLookupResult init_result = nigori_node.InitTypeRoot(NIGORI); + DCHECK_EQ(init_result, BaseNode::INIT_OK); + NigoriState nigori_state; + nigori_state.nigori_specifics = nigori_node.GetNigoriSpecifics(); + DCHECK(nigori_state.nigori_specifics.passphrase_type() == + sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE || + nigori_state.nigori_specifics.passphrase_type() == + sync_pb::NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE); + FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, + OnLocalSetPassphraseEncryption(nigori_state)); +} + void SyncEncryptionHandlerImpl::DecryptPendingKeysWithExplicitPassphrase( const std::string& passphrase, WriteTransaction* trans, @@ -1485,6 +1532,11 @@ bool SyncEncryptionHandlerImpl::AttemptToMigrateNigoriToKeystore( DVLOG(1) << "Completing nigori migration to keystore support."; nigori_node->SetNigoriSpecifics(migrated_nigori); + if (new_encrypt_everything && + (new_passphrase_type == FROZEN_IMPLICIT_PASSPHRASE || + new_passphrase_type == CUSTOM_PASSPHRASE)) + NotifyObserversOfLocalCustomPassphrase(trans); + switch (new_passphrase_type) { case KEYSTORE_PASSPHRASE: if (old_keystore_keys_.size() > 0) { diff --git a/sync/internal_api/sync_encryption_handler_impl.h b/sync/internal_api/sync_encryption_handler_impl.h index 79f43f2..4e466f1 100644 --- a/sync/internal_api/sync_encryption_handler_impl.h +++ b/sync/internal_api/sync_encryption_handler_impl.h @@ -88,6 +88,11 @@ class SYNC_EXPORT_PRIVATE SyncEncryptionHandlerImpl base::Time migration_time() const; base::Time custom_passphrase_time() const; + // Restore a saved nigori obtained from OnLocalSetPassphraseEncryption. + // + // Writes the nigori to the Directory and updates the Cryptographer. + void RestoreNigori(const SyncEncryptionHandler::NigoriState& nigori_state); + private: friend class SyncEncryptionHandlerImplTest; FRIEND_TEST_ALL_PREFIXES(SyncEncryptionHandlerImplTest, @@ -139,7 +144,10 @@ class SYNC_EXPORT_PRIVATE SyncEncryptionHandlerImpl // Iterate over all encrypted types ensuring each entry is properly encrypted. void ReEncryptEverything(WriteTransaction* trans); - // Apply a nigori update. Updates internal and cryptographer state. + // Updates internal and cryptographer state. + // + // Assumes |nigori| is already present in the Sync Directory. + // // Returns true on success, false if |nigori| was incompatible, and the // nigori node must be corrected. // Note: must be called from within a transaction. @@ -261,6 +269,9 @@ class SYNC_EXPORT_PRIVATE SyncEncryptionHandlerImpl // (if known). Else return base::Time(). base::Time GetExplicitPassphraseTime() const; + // Notify observers when a custom passphrase is set by this device. + void NotifyObserversOfLocalCustomPassphrase(WriteTransaction* trans); + base::ThreadChecker thread_checker_; base::ObserverList<SyncEncryptionHandler::Observer> observers_; diff --git a/sync/internal_api/sync_encryption_handler_impl_unittest.cc b/sync/internal_api/sync_encryption_handler_impl_unittest.cc index 829ecd2..ef1b93e5 100644 --- a/sync/internal_api/sync_encryption_handler_impl_unittest.cc +++ b/sync/internal_api/sync_encryption_handler_impl_unittest.cc @@ -59,6 +59,8 @@ class SyncEncryptionHandlerObserverMock MOCK_METHOD1(OnCryptographerStateChanged, void(Cryptographer*)); // NOLINT MOCK_METHOD2(OnPassphraseTypeChanged, void(PassphraseType, base::Time)); // NOLINT + MOCK_METHOD1(OnLocalSetPassphraseEncryption, + void(const SyncEncryptionHandler::NigoriState&)); // NOLINT }; google::protobuf::RepeatedPtrField<google::protobuf::string> @@ -88,11 +90,14 @@ class SyncEncryptionHandlerImplTest : public ::testing::Test { protected: void SetUpEncryption() { - encryption_handler_.reset( - new SyncEncryptionHandlerImpl(user_share(), - &encryptor_, - std::string(), - std::string() /* bootstrap tokens */)); + SetUpEncryptionWithKeyForBootstrapping(std::string()); + } + + void SetUpEncryptionWithKeyForBootstrapping( + const std::string& key_for_bootstrapping) { + encryption_handler_.reset(new SyncEncryptionHandlerImpl( + user_share(), &encryptor_, key_for_bootstrapping, + std::string() /* keystore key for bootstrapping */)); encryption_handler_->AddObserver(&observer_); } @@ -331,6 +336,33 @@ class SyncEncryptionHandlerImplTest : public ::testing::Test { Mock::VerifyAndClearExpectations(observer()); } + // Verify we can restore the SyncEncryptionHandler state using a saved + // |bootstrap_token| and |nigori_state|. + // + // |migration_time| is the time migration occurred. + // + // |passphrase| is the custom passphrase. + void VerifyRestoreAfterCustomPassphrase( + int64 migration_time, + const std::string& passphrase, + const std::string& bootstrap_token, + const SyncEncryptionHandler::NigoriState& nigori_state, + PassphraseType passphrase_type) { + TearDown(); + test_user_share_.SetUp(); + SetUpEncryptionWithKeyForBootstrapping(bootstrap_token); + EXPECT_CALL(*observer(), OnCryptographerStateChanged(_)).Times(AnyNumber()); + EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, true)) + .Times(AnyNumber()); + EXPECT_CALL(*observer(), OnPassphraseTypeChanged(passphrase_type, _)); + EXPECT_CALL(*observer(), OnEncryptionComplete()); + encryption_handler()->RestoreNigori(nigori_state); + encryption_handler()->Init(); + Mock::VerifyAndClearExpectations(observer()); + VerifyMigratedNigoriWithTimestamp(migration_time, passphrase_type, + passphrase); + } + protected: TestUserShare test_user_share_; FakeEncryptor encryptor_; @@ -818,17 +850,27 @@ TEST_F(SyncEncryptionHandlerImplTest, MigrateOnDecryptCustomPass) { OnCryptographerStateChanged(_)).Times(AnyNumber()); EXPECT_CALL(*observer(), OnPassphraseAccepted()); + std::string captured_bootstrap_token; EXPECT_CALL(*observer(), - OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)) + .WillOnce(testing::SaveArg<0>(&captured_bootstrap_token)); EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, true)); + SyncEncryptionHandler::NigoriState captured_nigori_state; + EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) + .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); EXPECT_CALL(*observer(), OnEncryptionComplete()).Times(2); EXPECT_FALSE(encryption_handler()->MigratedToKeystore()); encryption_handler()->SetDecryptionPassphrase(kOtherKey); EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); + const base::Time migration_time = encryption_handler()->migration_time(); EXPECT_EQ(CUSTOM_PASSPHRASE, encryption_handler()->GetPassphraseType()); VerifyMigratedNigori(CUSTOM_PASSPHRASE, kOtherKey); + + VerifyRestoreAfterCustomPassphrase(TimeToProtoTime(migration_time), kOtherKey, + captured_bootstrap_token, + captured_nigori_state, CUSTOM_PASSPHRASE); } // Test that we trigger a migration when we set the keystore key, had an @@ -885,9 +927,11 @@ TEST_F(SyncEncryptionHandlerImplTest, OnEncryptionComplete()); encryption_handler()->Init(); Mock::VerifyAndClearExpectations(observer()); - EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, true)); + SyncEncryptionHandler::NigoriState captured_nigori_state; + EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) + .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); EXPECT_CALL(*observer(), OnEncryptionComplete()); encryption_handler()->EnableEncryptEverything(); @@ -905,13 +949,26 @@ TEST_F(SyncEncryptionHandlerImplTest, } EXPECT_CALL(*observer(), OnPassphraseTypeChanged(FROZEN_IMPLICIT_PASSPHRASE, _)); + // The actual migration gets posted, so run all pending tasks. PumpLoop(); + Mock::VerifyAndClearExpectations(observer()); + EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); + const base::Time migration_time = encryption_handler()->migration_time(); EXPECT_EQ(FROZEN_IMPLICIT_PASSPHRASE, encryption_handler()->GetPassphraseType()); EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled()); VerifyMigratedNigori(FROZEN_IMPLICIT_PASSPHRASE, kCurKey); + + // We need the passphrase bootstrap token, but OnBootstrapTokenUpdated(_, + // PASSPHRASE_BOOTSTRAP_TOKEN) has not been invoked (because it was invoked + // during a previous instance) so get it from the Cryptographer. + std::string passphrase_bootstrap_token; + GetCryptographer()->GetBootstrapToken(&passphrase_bootstrap_token); + VerifyRestoreAfterCustomPassphrase( + TimeToProtoTime(migration_time), kCurKey, passphrase_bootstrap_token, + captured_nigori_state, FROZEN_IMPLICIT_PASSPHRASE); } // Test that we trigger a migration when we set the keystore key, had a @@ -932,8 +989,10 @@ TEST_F(SyncEncryptionHandlerImplTest, OnEncryptionComplete()); EXPECT_CALL(*observer(), OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); + std::string captured_bootstrap_token; EXPECT_CALL(*observer(), - OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)) + .WillOnce(testing::SaveArg<0>(&captured_bootstrap_token)); encryption_handler()->Init(); encryption_handler()->SetEncryptionPassphrase(kCurKey, true); EXPECT_FALSE(encryption_handler()->custom_passphrase_time().is_null()); @@ -946,6 +1005,7 @@ TEST_F(SyncEncryptionHandlerImplTest, encryption_handler()->EnableEncryptEverything(); Mock::VerifyAndClearExpectations(observer()); + SyncEncryptionHandler::NigoriState captured_nigori_state; { ReadTransaction trans(FROM_HERE, user_share()); // Once we provide a keystore key, we should perform the migration. @@ -953,17 +1013,27 @@ TEST_F(SyncEncryptionHandlerImplTest, OnCryptographerStateChanged(_)).Times(AnyNumber()); EXPECT_CALL(*observer(), OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); + EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) + .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); encryption_handler()->SetKeystoreKeys(BuildEncryptionKeyProto( kRawKeystoreKey), trans.GetWrappedTrans()); } + // The actual migration gets posted, so run all pending tasks. PumpLoop(); + Mock::VerifyAndClearExpectations(observer()); + EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); + const base::Time migration_time = encryption_handler()->migration_time(); EXPECT_EQ(CUSTOM_PASSPHRASE, encryption_handler()->GetPassphraseType()); EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled()); VerifyMigratedNigori(CUSTOM_PASSPHRASE, kCurKey); + + VerifyRestoreAfterCustomPassphrase(TimeToProtoTime(migration_time), kCurKey, + captured_bootstrap_token, + captured_nigori_state, CUSTOM_PASSPHRASE); } // Test that we trigger a migration when we set the keystore key, had a @@ -984,8 +1054,10 @@ TEST_F(SyncEncryptionHandlerImplTest, OnEncryptionComplete()); EXPECT_CALL(*observer(), OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); + std::string captured_bootstrap_token; EXPECT_CALL(*observer(), - OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)) + .WillOnce(testing::SaveArg<0>(&captured_bootstrap_token)); encryption_handler()->Init(); encryption_handler()->SetEncryptionPassphrase(kCurKey, true); EXPECT_FALSE(encryption_handler()->custom_passphrase_time().is_null()); @@ -1004,15 +1076,23 @@ TEST_F(SyncEncryptionHandlerImplTest, } EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, true)); + SyncEncryptionHandler::NigoriState captured_nigori_state; + EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) + .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); EXPECT_CALL(*observer(), OnEncryptionComplete()); // The actual migration gets posted, so run all pending tasks. PumpLoop(); EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); + const base::Time migration_time = encryption_handler()->migration_time(); EXPECT_EQ(CUSTOM_PASSPHRASE, encryption_handler()->GetPassphraseType()); EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled()); VerifyMigratedNigori(CUSTOM_PASSPHRASE, kCurKey); + + VerifyRestoreAfterCustomPassphrase(TimeToProtoTime(migration_time), kCurKey, + captured_bootstrap_token, + captured_nigori_state, CUSTOM_PASSPHRASE); } // Test that we can handle receiving a migrated nigori node in the @@ -1258,6 +1338,7 @@ TEST_F(SyncEncryptionHandlerImplTest, ReceiveUnmigratedNigoriAfterMigration) { GetCryptographer()->AddKey(cur_key); // Build a migrated nigori with full encryption. + const int64 migration_time = 1; { WriteTransaction trans(FROM_HERE, user_share()); WriteNode nigori_node(&trans); @@ -1284,7 +1365,7 @@ TEST_F(SyncEncryptionHandlerImplTest, ReceiveUnmigratedNigoriAfterMigration) { EXPECT_TRUE(GetCryptographer()->is_ready()); EXPECT_EQ(encryption_handler()->GetPassphraseType(), CUSTOM_PASSPHRASE); EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled()); - VerifyMigratedNigoriWithTimestamp(1, CUSTOM_PASSPHRASE, kCurKey); + VerifyMigratedNigoriWithTimestamp(migration_time, CUSTOM_PASSPHRASE, kCurKey); { EXPECT_CALL(*observer(), @@ -1300,6 +1381,9 @@ TEST_F(SyncEncryptionHandlerImplTest, ReceiveUnmigratedNigoriAfterMigration) { // properly overwrite it with the migrated + encrypt everything state. EXPECT_CALL(*observer(), OnCryptographerStateChanged(_)).Times(AnyNumber()); + SyncEncryptionHandler::NigoriState captured_nigori_state; + EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) + .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); EXPECT_CALL(*observer(), OnEncryptionComplete()); { Cryptographer other_cryptographer(GetCryptographer()->encryptor()); @@ -1322,6 +1406,15 @@ TEST_F(SyncEncryptionHandlerImplTest, ReceiveUnmigratedNigoriAfterMigration) { EXPECT_EQ(encryption_handler()->GetPassphraseType(), CUSTOM_PASSPHRASE); EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled()); VerifyMigratedNigoriWithTimestamp(1, CUSTOM_PASSPHRASE, kCurKey); + + // We need the passphrase bootstrap token, but OnBootstrapTokenUpdated(_, + // PASSPHRASE_BOOTSTRAP_TOKEN) has not been invoked (because it was invoked + // during a previous instance) so get it from the Cryptographer. + std::string passphrase_bootstrap_token; + GetCryptographer()->GetBootstrapToken(&passphrase_bootstrap_token); + VerifyRestoreAfterCustomPassphrase(migration_time, kCurKey, + passphrase_bootstrap_token, + captured_nigori_state, CUSTOM_PASSPHRASE); } // Test that if we have a migrated nigori with a custom passphrase, then receive @@ -1379,7 +1472,11 @@ TEST_F(SyncEncryptionHandlerImplTest, ReceiveOldMigratedNigori) { // properly overwrite it with the migrated + encrypt everything state. EXPECT_CALL(*observer(), OnCryptographerStateChanged(_)).Times(AnyNumber()); + SyncEncryptionHandler::NigoriState captured_nigori_state; + EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) + .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); EXPECT_CALL(*observer(), OnEncryptionComplete()); + const int64 migration_time = 1; { WriteTransaction trans(FROM_HERE, user_share()); WriteNode nigori_node(&trans); @@ -1395,7 +1492,7 @@ TEST_F(SyncEncryptionHandlerImplTest, ReceiveOldMigratedNigori) { nigori.set_keybag_is_frozen(true); nigori.set_encrypt_everything(false); nigori.set_passphrase_type(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE); - nigori.set_keystore_migration_time(1); + nigori.set_keystore_migration_time(migration_time); encryption_handler()->ApplyNigoriUpdate(nigori, trans.GetWrappedTrans()); nigori_node.SetNigoriSpecifics(nigori); } @@ -1406,7 +1503,16 @@ TEST_F(SyncEncryptionHandlerImplTest, ReceiveOldMigratedNigori) { EXPECT_TRUE(GetCryptographer()->is_ready()); EXPECT_EQ(encryption_handler()->GetPassphraseType(), CUSTOM_PASSPHRASE); EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled()); - VerifyMigratedNigoriWithTimestamp(1, CUSTOM_PASSPHRASE, kCurKey); + VerifyMigratedNigoriWithTimestamp(migration_time, CUSTOM_PASSPHRASE, kCurKey); + + // We need the passphrase bootstrap token, but OnBootstrapTokenUpdated(_, + // PASSPHRASE_BOOTSTRAP_TOKEN) has not been invoked (because it was invoked + // during a previous instance) so get it from the Cryptographer. + std::string passphrase_bootstrap_token; + GetCryptographer()->GetBootstrapToken(&passphrase_bootstrap_token); + VerifyRestoreAfterCustomPassphrase(migration_time, kCurKey, + passphrase_bootstrap_token, + captured_nigori_state, CUSTOM_PASSPHRASE); } // Test that if we receive the keystore key after receiving a migrated nigori @@ -1510,6 +1616,7 @@ TEST_F(SyncEncryptionHandlerImplTest, SetCustomPassAfterMigration) { // Build a nigori node with the generated keystore decryptor token and // initialize the encryption handler with it. The cryptographer should be // initialized properly to decrypt both kOldKey and kKeystoreKey. + const int64 migration_time = 1; { WriteTransaction trans(FROM_HERE, user_share()); WriteNode nigori_node(&trans); @@ -1519,7 +1626,7 @@ TEST_F(SyncEncryptionHandlerImplTest, SetCustomPassAfterMigration) { keystore_decryptor_token); other_cryptographer.GetKeys(nigori.mutable_encryption_keybag()); nigori.set_keybag_is_frozen(true); - nigori.set_keystore_migration_time(1); + nigori.set_keystore_migration_time(migration_time); nigori.set_passphrase_type(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE); nigori_node.SetNigoriSpecifics(nigori); EXPECT_CALL(*observer(), @@ -1552,8 +1659,13 @@ TEST_F(SyncEncryptionHandlerImplTest, SetCustomPassAfterMigration) { OnCryptographerStateChanged(_)).Times(AnyNumber()); EXPECT_CALL(*observer(), OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); + SyncEncryptionHandler::NigoriState captured_nigori_state; + EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) + .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); + std::string captured_bootstrap_token; EXPECT_CALL(*observer(), - OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)) + .WillOnce(testing::SaveArg<0>(&captured_bootstrap_token)); EXPECT_CALL(*observer(), OnPassphraseAccepted()); EXPECT_CALL(*observer(), @@ -1561,12 +1673,15 @@ TEST_F(SyncEncryptionHandlerImplTest, SetCustomPassAfterMigration) { EXPECT_CALL(*observer(), OnEncryptionComplete()).Times(2); encryption_handler()->SetEncryptionPassphrase(kNewKey, true); + Mock::VerifyAndClearExpectations(observer()); + + EXPECT_FALSE(captured_bootstrap_token.empty()); EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); EXPECT_TRUE(GetCryptographer()->is_ready()); EXPECT_EQ(encryption_handler()->GetPassphraseType(), CUSTOM_PASSPHRASE); EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled()); EXPECT_FALSE(encryption_handler()->custom_passphrase_time().is_null()); - VerifyMigratedNigoriWithTimestamp(1, CUSTOM_PASSPHRASE, kNewKey); + VerifyMigratedNigoriWithTimestamp(migration_time, CUSTOM_PASSPHRASE, kNewKey); // Check that the cryptographer can decrypt the old key. sync_pb::EncryptedData old_encrypted; @@ -1588,6 +1703,12 @@ TEST_F(SyncEncryptionHandlerImplTest, SetCustomPassAfterMigration) { sync_pb::EncryptedData new_encrypted; new_cryptographer.EncryptString("string", &new_encrypted); EXPECT_TRUE(GetCryptographer()->CanDecryptUsingDefaultKey(new_encrypted)); + + // Now verify that we can restore the current state using the captured + // bootstrap token and nigori state. + VerifyRestoreAfterCustomPassphrase(migration_time, kNewKey, + captured_bootstrap_token, + captured_nigori_state, CUSTOM_PASSPHRASE); } // Test that if a client without a keystore key (e.g. one without keystore @@ -1612,6 +1733,7 @@ TEST_F(SyncEncryptionHandlerImplTest, // Build a nigori node with the generated keystore decryptor token and // initialize the encryption handler with it. The cryptographer will have // pending keys until we provide the decryption passphrase. + const int64 migration_time = 1; { WriteTransaction trans(FROM_HERE, user_share()); WriteNode nigori_node(&trans); @@ -1621,7 +1743,7 @@ TEST_F(SyncEncryptionHandlerImplTest, keystore_decryptor_token); other_cryptographer.GetKeys(nigori.mutable_encryption_keybag()); nigori.set_keybag_is_frozen(true); - nigori.set_keystore_migration_time(1); + nigori.set_keystore_migration_time(migration_time); nigori.set_passphrase_type(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE); nigori_node.SetNigoriSpecifics(nigori); } @@ -1659,8 +1781,13 @@ TEST_F(SyncEncryptionHandlerImplTest, OnCryptographerStateChanged(_)).Times(AnyNumber()); EXPECT_CALL(*observer(), OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); + SyncEncryptionHandler::NigoriState captured_nigori_state; + EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) + .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); + std::string captured_bootstrap_token; EXPECT_CALL(*observer(), - OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)) + .WillOnce(testing::SaveArg<0>(&captured_bootstrap_token)); EXPECT_CALL(*observer(), OnPassphraseAccepted()); EXPECT_CALL(*observer(), @@ -1673,7 +1800,7 @@ TEST_F(SyncEncryptionHandlerImplTest, EXPECT_EQ(encryption_handler()->GetPassphraseType(), CUSTOM_PASSPHRASE); EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled()); EXPECT_FALSE(encryption_handler()->custom_passphrase_time().is_null()); - VerifyMigratedNigoriWithTimestamp(1, CUSTOM_PASSPHRASE, kNewKey); + VerifyMigratedNigoriWithTimestamp(migration_time, CUSTOM_PASSPHRASE, kNewKey); // Check that the cryptographer can decrypt the old key. sync_pb::EncryptedData old_encrypted; @@ -1695,6 +1822,12 @@ TEST_F(SyncEncryptionHandlerImplTest, sync_pb::EncryptedData new_encrypted; new_cryptographer.EncryptString("string", &new_encrypted); EXPECT_TRUE(GetCryptographer()->CanDecryptUsingDefaultKey(new_encrypted)); + + // Now verify that we can restore the current state using the captured + // bootstrap token and nigori state. + VerifyRestoreAfterCustomPassphrase(migration_time, kNewKey, + captured_bootstrap_token, + captured_nigori_state, CUSTOM_PASSPHRASE); } // Test that if a client without a keystore key (e.g. one without keystore @@ -1814,6 +1947,7 @@ TEST_F(SyncEncryptionHandlerImplTest, // Build a nigori node with the generated keystore decryptor token and // initialize the encryption handler with it. The cryptographer will have // pending keys until we provide the decryption passphrase. + const int64 migration_time = 1; { WriteTransaction trans(FROM_HERE, user_share()); WriteNode nigori_node(&trans); @@ -1823,7 +1957,7 @@ TEST_F(SyncEncryptionHandlerImplTest, keystore_decryptor_token); other_cryptographer.GetKeys(nigori.mutable_encryption_keybag()); nigori.set_keybag_is_frozen(true); - nigori.set_keystore_migration_time(1); + nigori.set_keystore_migration_time(migration_time); nigori.set_passphrase_type(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE); nigori_node.SetNigoriSpecifics(nigori); } @@ -1846,8 +1980,10 @@ TEST_F(SyncEncryptionHandlerImplTest, OnPassphraseAccepted()); EXPECT_CALL(*observer(), OnCryptographerStateChanged(_)).Times(AnyNumber()); + std::string captured_bootstrap_token; EXPECT_CALL(*observer(), - OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)) + .WillOnce(testing::SaveArg<0>(&captured_bootstrap_token)); EXPECT_CALL(*observer(), OnEncryptionComplete()); encryption_handler()->SetDecryptionPassphrase(kCurKey); @@ -1859,6 +1995,9 @@ TEST_F(SyncEncryptionHandlerImplTest, OnEncryptionComplete()); EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, true)); + SyncEncryptionHandler::NigoriState captured_nigori_state; + EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) + .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); EXPECT_CALL(*observer(), OnCryptographerStateChanged(_)).Times(AnyNumber()); encryption_handler()->EnableEncryptEverything(); @@ -1883,6 +2022,10 @@ TEST_F(SyncEncryptionHandlerImplTest, sync_pb::EncryptedData keystore_encrypted; keystore_cryptographer.EncryptString("string", &keystore_encrypted); EXPECT_TRUE(GetCryptographer()->CanDecrypt(keystore_encrypted)); + + VerifyRestoreAfterCustomPassphrase( + migration_time, kCurKey, captured_bootstrap_token, captured_nigori_state, + FROZEN_IMPLICIT_PASSPHRASE); } // If we receive a nigori migrated and with a KEYSTORE_PASSPHRASE type, but @@ -2242,14 +2385,24 @@ TEST_F(SyncEncryptionHandlerImplTest, RotateKeysUnmigratedCustomPassphrase) { OnPassphraseAccepted()); EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, true)); + SyncEncryptionHandler::NigoriState captured_nigori_state; + EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) + .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); EXPECT_CALL(*observer(), OnEncryptionComplete()).Times(AnyNumber()); + std::string captured_bootstrap_token; EXPECT_CALL(*observer(), - OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)) + .WillOnce(testing::SaveArg<0>(&captured_bootstrap_token)); encryption_handler()->SetDecryptionPassphrase(kCustomPass); Mock::VerifyAndClearExpectations(observer()); VerifyMigratedNigori(CUSTOM_PASSPHRASE, kCustomPass); + + const base::Time migration_time = encryption_handler()->migration_time(); + VerifyRestoreAfterCustomPassphrase(TimeToProtoTime(migration_time), + kCustomPass, captured_bootstrap_token, + captured_nigori_state, CUSTOM_PASSPHRASE); } // Verify that a key rotation done after we've migrated a custom passphrase @@ -2261,9 +2414,12 @@ TEST_F(SyncEncryptionHandlerImplTest, RotateKeysMigratedCustomPassphrase) { KeyParams custom_key = {"localhost", "dummy", kCustomPass}; GetCryptographer()->AddKey(custom_key); - InitCustomPassMigratedNigori(1, kCustomPass); - VerifyMigratedNigoriWithTimestamp(1, CUSTOM_PASSPHRASE, kCustomPass); + const int64 migration_time = 1; + InitCustomPassMigratedNigori(migration_time, kCustomPass); + VerifyMigratedNigoriWithTimestamp(migration_time, CUSTOM_PASSPHRASE, + kCustomPass); + SyncEncryptionHandler::NigoriState captured_nigori_state; { // Pass multiple keystore keys, signaling a rotation has happened. google::protobuf::RepeatedPtrField<google::protobuf::string> keys; @@ -2274,13 +2430,25 @@ TEST_F(SyncEncryptionHandlerImplTest, RotateKeysMigratedCustomPassphrase) { OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); EXPECT_CALL(*observer(), OnCryptographerStateChanged(_)).Times(AnyNumber()); + EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) + .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); encryption_handler()->SetKeystoreKeys(keys, trans.GetWrappedTrans()); } PumpLoop(); Mock::VerifyAndClearExpectations(observer()); - VerifyMigratedNigoriWithTimestamp(1, CUSTOM_PASSPHRASE, kCustomPass); + VerifyMigratedNigoriWithTimestamp(migration_time, CUSTOM_PASSPHRASE, + kCustomPass); + + // We need the passphrase bootstrap token, but OnBootstrapTokenUpdated(_, + // PASSPHRASE_BOOTSTRAP_TOKEN) has not been invoked (because it was invoked + // during a previous instance) so get it from the Cryptographer. + std::string passphrase_bootstrap_token; + GetCryptographer()->GetBootstrapToken(&passphrase_bootstrap_token); + VerifyRestoreAfterCustomPassphrase(migration_time, kCustomPass, + passphrase_bootstrap_token, + captured_nigori_state, CUSTOM_PASSPHRASE); } } // namespace syncer diff --git a/sync/internal_api/sync_manager_impl.cc b/sync/internal_api/sync_manager_impl.cc index 42de79e..a9824104 100644 --- a/sync/internal_api/sync_manager_impl.cc +++ b/sync/internal_api/sync_manager_impl.cc @@ -404,6 +404,10 @@ void SyncManagerImpl::OnPassphraseTypeChanged( sync_encryption_handler_->migration_time()); } +void SyncManagerImpl::OnLocalSetPassphraseEncryption( + const SyncEncryptionHandler::NigoriState& nigori_state) { +} + void SyncManagerImpl::StartSyncingNormally( const ModelSafeRoutingInfo& routing_info, base::Time last_poll_time) { diff --git a/sync/internal_api/sync_manager_impl.h b/sync/internal_api/sync_manager_impl.h index 283d3f1..9053284 100644 --- a/sync/internal_api/sync_manager_impl.h +++ b/sync/internal_api/sync_manager_impl.h @@ -123,6 +123,8 @@ class SYNC_EXPORT_PRIVATE SyncManagerImpl void OnCryptographerStateChanged(Cryptographer* cryptographer) override; void OnPassphraseTypeChanged(PassphraseType type, base::Time explicit_passphrase_time) override; + void OnLocalSetPassphraseEncryption( + const SyncEncryptionHandler::NigoriState& nigori_state) override; // SyncEngineEventListener implementation. void OnSyncCycleEvent(const SyncCycleEvent& event) override; diff --git a/sync/internal_api/sync_manager_impl_unittest.cc b/sync/internal_api/sync_manager_impl_unittest.cc index 8bab47a..de645ae 100644 --- a/sync/internal_api/sync_manager_impl_unittest.cc +++ b/sync/internal_api/sync_manager_impl_unittest.cc @@ -817,6 +817,8 @@ class SyncEncryptionHandlerObserverMock MOCK_METHOD1(OnCryptographerStateChanged, void(Cryptographer*)); // NOLINT MOCK_METHOD2(OnPassphraseTypeChanged, void(PassphraseType, base::Time)); // NOLINT + MOCK_METHOD1(OnLocalSetPassphraseEncryption, + void(const SyncEncryptionHandler::NigoriState&)); // NOLINT }; } // namespace diff --git a/sync/sessions/model_type_registry.cc b/sync/sessions/model_type_registry.cc index 729727e..0bd70b2 100644 --- a/sync/sessions/model_type_registry.cc +++ b/sync/sessions/model_type_registry.cc @@ -333,6 +333,10 @@ void ModelTypeRegistry::OnPassphraseTypeChanged(PassphraseType type, base::Time passphrase_time) { } +void ModelTypeRegistry::OnLocalSetPassphraseEncryption( + const SyncEncryptionHandler::NigoriState& nigori_state) { +} + ModelTypeSet ModelTypeRegistry::GetEnabledDirectoryTypes() const { return enabled_directory_types_; } diff --git a/sync/sessions/model_type_registry.h b/sync/sessions/model_type_registry.h index ccfc117..53c0d99 100644 --- a/sync/sessions/model_type_registry.h +++ b/sync/sessions/model_type_registry.h @@ -83,6 +83,8 @@ class SYNC_EXPORT_PRIVATE ModelTypeRegistry void OnCryptographerStateChanged(Cryptographer* cryptographer) override; void OnPassphraseTypeChanged(PassphraseType type, base::Time passphrase_time) override; + void OnLocalSetPassphraseEncryption( + const SyncEncryptionHandler::NigoriState& nigori_state) override; // Gets the set of enabled types. ModelTypeSet GetEnabledTypes() const; diff --git a/sync/syncable/model_neutral_mutable_entry.cc b/sync/syncable/model_neutral_mutable_entry.cc index 02cdcbb..ca05bdd 100644 --- a/sync/syncable/model_neutral_mutable_entry.cc +++ b/sync/syncable/model_neutral_mutable_entry.cc @@ -48,7 +48,10 @@ ModelNeutralMutableEntry::ModelNeutralMutableEntry(BaseWriteTransaction* trans, CreateNewTypeRoot, ModelType type) : Entry(trans), base_write_transaction_(trans) { - DCHECK(IsTypeWithClientGeneratedRoot(type)); + // We allow NIGORI because we allow SyncEncryptionHandler to restore a nigori + // across Directory instances (see SyncEncryptionHandler::RestoreNigori). + if (type != NIGORI) + DCHECK(IsTypeWithClientGeneratedRoot(type)); Entry same_type_root(trans, GET_TYPE_ROOT, type); kernel_ = NULL; if (same_type_root.good()) { |