summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormaniscalco <maniscalco@chromium.org>2015-06-15 17:36:44 -0700
committerCommit bot <commit-bot@chromium.org>2015-06-16 00:37:49 +0000
commit358cabb346973315059d9afbff9d9c17c4b706f2 (patch)
tree410d746f718826d83205f6416087685887b36695
parentf9f1b3f900cf87068880ad6edae608a2abca0132 (diff)
downloadchromium_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}
-rw-r--r--chrome/browser/sync/glue/sync_backend_host_core.cc8
-rw-r--r--chrome/browser/sync/glue/sync_backend_host_core.h2
-rw-r--r--chrome/browser/sync/glue/sync_backend_host_impl.cc6
-rw-r--r--chrome/browser/sync/glue/sync_backend_host_impl.h4
-rw-r--r--chrome/browser/sync/glue/sync_backend_host_impl_unittest.cc3
-rw-r--r--chrome/browser/sync/profile_sync_service.cc12
-rw-r--r--chrome/browser/sync/profile_sync_service.h2
-rw-r--r--components/sync_driver/sync_frontend.h8
-rw-r--r--sync/internal_api/debug_info_event_listener.cc4
-rw-r--r--sync/internal_api/debug_info_event_listener.h2
-rw-r--r--sync/internal_api/js_sync_encryption_handler_observer.cc4
-rw-r--r--sync/internal_api/js_sync_encryption_handler_observer.h2
-rw-r--r--sync/internal_api/public/sync_encryption_handler.h19
-rw-r--r--sync/internal_api/sync_encryption_handler_impl.cc72
-rw-r--r--sync/internal_api/sync_encryption_handler_impl.h13
-rw-r--r--sync/internal_api/sync_encryption_handler_impl_unittest.cc216
-rw-r--r--sync/internal_api/sync_manager_impl.cc4
-rw-r--r--sync/internal_api/sync_manager_impl.h2
-rw-r--r--sync/internal_api/sync_manager_impl_unittest.cc2
-rw-r--r--sync/sessions/model_type_registry.cc4
-rw-r--r--sync/sessions/model_type_registry.h2
-rw-r--r--sync/syncable/model_neutral_mutable_entry.cc5
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()) {