summaryrefslogtreecommitdiffstats
path: root/sync/engine
diff options
context:
space:
mode:
authorzea@chromium.org <zea@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-17 20:42:01 +0000
committerzea@chromium.org <zea@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-17 20:42:01 +0000
commitbe72dd2fdf5afb3db30579ac11fa4df5f3559e26 (patch)
tree1d3acffbc6939b7e510874aeba3c01e3716fa6b8 /sync/engine
parentbe973f5a168edcaed5f19a04b4e8d49ae240de77 (diff)
downloadchromium_src-be72dd2fdf5afb3db30579ac11fa4df5f3559e26.zip
chromium_src-be72dd2fdf5afb3db30579ac11fa4df5f3559e26.tar.gz
chromium_src-be72dd2fdf5afb3db30579ac11fa4df5f3559e26.tar.bz2
[Sync] Add keystore migration conflict support.
We rely on the encryption handler's rollback detection for any cases where conflicts might lose data and we can't merge. Else, we merge the data as needed. BUG=129665 Review URL: https://chromiumcodereview.appspot.com/10905191 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@157186 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sync/engine')
-rw-r--r--sync/engine/apply_control_data_updates.cc98
-rw-r--r--sync/engine/apply_control_data_updates_unittest.cc622
-rw-r--r--sync/engine/syncer_unittest.cc124
3 files changed, 634 insertions, 210 deletions
diff --git a/sync/engine/apply_control_data_updates.cc b/sync/engine/apply_control_data_updates.cc
index 7a52e8c..aa1454e 100644
--- a/sync/engine/apply_control_data_updates.cc
+++ b/sync/engine/apply_control_data_updates.cc
@@ -57,6 +57,8 @@ bool ApplyNigoriUpdates(syncable::WriteTransaction* trans,
return true;
}
+ // We apply the nigori update regardless of whether there's a conflict or
+ // not in order to preserve any new encrypted types or encryption keys.
const sync_pb::NigoriSpecifics& nigori =
nigori_node.Get(SERVER_SPECIFICS).nigori();
trans->directory()->GetNigoriHandler()->ApplyNigoriUpdate(nigori, trans);
@@ -83,45 +85,67 @@ bool ApplyNigoriUpdates(syncable::WriteTransaction* trans,
if (!nigori_node.Get(IS_UNSYNCED)) { // Update only.
UpdateLocalDataFromServerData(trans, &nigori_node);
} else { // Conflict.
- // Create a new set of specifics based on the server specifics (which
- // preserves their encryption keys).
- sync_pb::EntitySpecifics specifics = nigori_node.Get(SERVER_SPECIFICS);
- sync_pb::NigoriSpecifics* server_nigori = specifics.mutable_nigori();
- // Store the merged set of encrypted types.
- // (NigoriHandler::ApplyNigoriUpdate(..) will have merged the local types
- // already).
- trans->directory()->GetNigoriHandler()->UpdateNigoriFromEncryptedTypes(
- server_nigori,
- trans);
- // The cryptographer has the both the local and remote encryption keys
- // (added at NigoriHandler::ApplyNigoriUpdate(..) time).
- // If the cryptographer is ready, then it already merged both sets of keys
- // and we can store them back in. In that case, the remote key was already
- // part of the local keybag, so we preserve the local key as the default
- // (including whether it's an explicit key).
- // If the cryptographer is not ready, then the user will have to provide
- // the passphrase to decrypt the pending keys. When they do so, the
- // SetDecryptionPassphrase code will act based on whether the server
- // update has an explicit passphrase or not.
- // - If the server had an explicit passphrase, that explicit passphrase
- // will be preserved as the default encryption key.
- // - If the server did not have an explicit passphrase, we assume the
- // local passphrase is the most up to date and preserve the local
- // default encryption key marked as an implicit passphrase.
- // This works fine except for the case where we had locally set an
- // explicit passphrase. In that case the nigori node will have the default
- // key based on the local explicit passphassphrase, but will not have it
- // marked as explicit. To fix this we'd have to track whether we have a
- // explicit passphrase or not separate from the nigori, which would
- // introduce even more complexity, so we leave it up to the user to reset
- // that passphrase as an explicit one via settings. The goal here is to
- // ensure both sets of encryption keys are preserved.
+ const sync_pb::EntitySpecifics& server_specifics =
+ nigori_node.Get(SERVER_SPECIFICS);
+ const sync_pb::NigoriSpecifics& server_nigori = server_specifics.nigori();
+ const sync_pb::EntitySpecifics& local_specifics =
+ nigori_node.Get(SPECIFICS);
+ const sync_pb::NigoriSpecifics& local_nigori = local_specifics.nigori();
+
+ // We initialize the new nigori with the server state, and will override
+ // it as necessary below.
+ sync_pb::EntitySpecifics new_specifics = nigori_node.Get(SERVER_SPECIFICS);
+ sync_pb::NigoriSpecifics* new_nigori = new_specifics.mutable_nigori();
+
+ // If the cryptographer is not ready, another client set a new encryption
+ // passphrase. If we had migrated locally, we will re-migrate when the
+ // pending keys are provided. If we had set a new custom passphrase locally
+ // the user will have another chance to set a custom passphrase later
+ // (assuming they hadn't set a custom passphrase on the other client).
+ // Therefore, we only attempt to merge the nigori nodes if the cryptographer
+ // is ready.
+ // Note: we only update the encryption keybag if we're sure that we aren't
+ // invalidating the keystore_decryptor_token (i.e. we're either
+ // not migrated or we copying over all local state).
if (cryptographer->is_ready()) {
- cryptographer->GetKeys(server_nigori->mutable_encryption_keybag());
- server_nigori->set_keybag_is_frozen(
- nigori_node.Get(SPECIFICS).nigori().keybag_is_frozen());
+ if (local_nigori.has_passphrase_type() &&
+ server_nigori.has_passphrase_type()) {
+ // They're both migrated, preserve the local nigori if the passphrase
+ // type is more conservative.
+ if (server_nigori.passphrase_type() ==
+ sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE &&
+ local_nigori.passphrase_type() !=
+ sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE) {
+ DCHECK(local_nigori.passphrase_type() ==
+ sync_pb::NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE ||
+ local_nigori.passphrase_type() ==
+ sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
+ new_nigori->CopyFrom(local_nigori);
+ cryptographer->GetKeys(new_nigori->mutable_encryption_keybag());
+ }
+ } else if (!local_nigori.has_passphrase_type() &&
+ !server_nigori.has_passphrase_type()) {
+ // Set the explicit passphrase based on the local state. If the server
+ // had set an explict passphrase, we should have pending keys, so
+ // should not reach this code.
+ // Because neither side is migrated, we don't have to worry about the
+ // keystore decryptor token.
+ new_nigori->set_keybag_is_frozen(local_nigori.keybag_is_frozen());
+ cryptographer->GetKeys(new_nigori->mutable_encryption_keybag());
+ } else if (local_nigori.has_passphrase_type()) {
+ // Local is migrated but server is not. Copy over the local migrated
+ // data.
+ new_nigori->CopyFrom(local_nigori);
+ cryptographer->GetKeys(new_nigori->mutable_encryption_keybag());
+ } // else leave the new nigori with the server state.
}
- nigori_node.Put(SPECIFICS, specifics);
+
+ // Always update to the safest set of encrypted types.
+ trans->directory()->GetNigoriHandler()->UpdateNigoriFromEncryptedTypes(
+ new_nigori,
+ trans);
+
+ nigori_node.Put(SPECIFICS, new_specifics);
DVLOG(1) << "Resolving simple conflict, merging nigori nodes: "
<< nigori_node;
diff --git a/sync/engine/apply_control_data_updates_unittest.cc b/sync/engine/apply_control_data_updates_unittest.cc
index 7f1a9fa..aa00865 100644
--- a/sync/engine/apply_control_data_updates_unittest.cc
+++ b/sync/engine/apply_control_data_updates_unittest.cc
@@ -56,59 +56,17 @@ class ApplyControlDataUpdatesTest : public SyncerCommandTest {
DISALLOW_COPY_AND_ASSIGN(ApplyControlDataUpdatesTest);
};
+// Verify that applying a nigori node sets initial sync ended properly,
+// updates the set of encrypted types, and updates the cryptographer.
TEST_F(ApplyControlDataUpdatesTest, NigoriUpdate) {
// Storing the cryptographer separately is bad, but for this test we
// know it's safe.
Cryptographer* cryptographer;
ModelTypeSet encrypted_types;
- encrypted_types.Put(PASSWORDS);
+ encrypted_types.PutAll(SyncEncryptionHandler::SensitiveTypes());
- // We start with initial_sync_ended == false. This is wrong, since would have
- // no nigori node if that were the case. Howerver, it makes it easier to
- // verify that ApplyControlDataUpdates sets initial_sync_ended correctly.
- EXPECT_FALSE(directory()->initial_sync_ended_types().Has(NIGORI));
-
- {
- syncable::ReadTransaction trans(FROM_HERE, directory());
- cryptographer = directory()->GetCryptographer(&trans);
- EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
- .Equals(encrypted_types));
- }
-
- // Nigori node updates should update the Cryptographer.
- Cryptographer other_cryptographer(cryptographer->encryptor());
- KeyParams params = {"localhost", "dummy", "foobar"};
- other_cryptographer.AddKey(params);
-
- sync_pb::EntitySpecifics specifics;
- sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
- other_cryptographer.GetKeys(nigori->mutable_encryption_keybag());
- nigori->set_encrypt_everything(true);
- entry_factory_->CreateUnappliedNewItem(
- ModelTypeToRootTag(NIGORI), specifics, true);
- EXPECT_FALSE(cryptographer->has_pending_keys());
-
- ApplyControlDataUpdates(directory());
-
- EXPECT_FALSE(cryptographer->is_ready());
- EXPECT_TRUE(cryptographer->has_pending_keys());
- {
- syncable::ReadTransaction trans(FROM_HERE, directory());
- EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
- .Equals(ModelTypeSet::All()));
- EXPECT_TRUE(directory()->initial_sync_ended_types().Has(NIGORI));
- }
-}
-
-TEST_F(ApplyControlDataUpdatesTest, NigoriUpdateForDisabledTypes) {
- // Storing the cryptographer separately is bad, but for this test we
- // know it's safe.
- Cryptographer* cryptographer;
- ModelTypeSet encrypted_types;
- encrypted_types.Put(PASSWORDS);
-
- // We start with initial_sync_ended == false. This is wrong, since would have
- // no nigori node if that were the case. Howerver, it makes it easier to
+ // We start with initial_sync_ended == false. This is wrong, since we would
+ // have no nigori node if that were the case. However, it makes it easier to
// verify that ApplyControlDataUpdates sets initial_sync_ended correctly.
EXPECT_FALSE(directory()->initial_sync_ended_types().Has(NIGORI));
@@ -154,7 +112,7 @@ TEST_F(ApplyControlDataUpdatesTest, EncryptUnsyncedChanges) {
// know it's safe.
Cryptographer* cryptographer;
ModelTypeSet encrypted_types;
- encrypted_types.Put(PASSWORDS);
+ encrypted_types.PutAll(SyncEncryptionHandler::SensitiveTypes());
{
syncable::ReadTransaction trans(FROM_HERE, directory());
cryptographer = directory()->GetCryptographer(&trans);
@@ -258,12 +216,16 @@ TEST_F(ApplyControlDataUpdatesTest, EncryptUnsyncedChanges) {
}
}
+// Create some local unsynced and unencrypted changes. Receive a new nigori
+// node enabling their encryption but also introducing pending keys. Ensure
+// we apply the update properly without encrypting the unsynced changes or
+// breaking.
TEST_F(ApplyControlDataUpdatesTest, CannotEncryptUnsyncedChanges) {
// Storing the cryptographer separately is bad, but for this test we
// know it's safe.
Cryptographer* cryptographer;
ModelTypeSet encrypted_types;
- encrypted_types.Put(PASSWORDS);
+ encrypted_types.PutAll(SyncEncryptionHandler::SensitiveTypes());
{
syncable::ReadTransaction trans(FROM_HERE, directory());
cryptographer = directory()->GetCryptographer(&trans);
@@ -344,4 +306,566 @@ TEST_F(ApplyControlDataUpdatesTest, CannotEncryptUnsyncedChanges) {
}
}
+// Verify we handle a nigori node conflict by merging encryption keys and
+// types, but preserve the custom passphrase state of the server.
+// Initial sync ended should be set.
+TEST_F(ApplyControlDataUpdatesTest,
+ NigoriConflictPendingKeysServerEncryptEverythingCustom) {
+ Cryptographer* cryptographer;
+ ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
+ KeyParams other_params = {"localhost", "dummy", "foobar"};
+ KeyParams local_params = {"localhost", "dummy", "local"};
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ cryptographer = directory()->GetCryptographer(&trans);
+ EXPECT_TRUE(encrypted_types.Equals(
+ directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
+ }
+
+ // Set up a temporary cryptographer to generate new keys with.
+ Cryptographer other_cryptographer(cryptographer->encryptor());
+ other_cryptographer.AddKey(other_params);
+
+ // Create server specifics with pending keys, new encrypted types,
+ // and a custom passphrase (unmigrated).
+ sync_pb::EntitySpecifics server_specifics;
+ sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
+ other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
+ server_nigori->set_encrypt_everything(true);
+ server_nigori->set_keybag_is_frozen(true);
+ int64 nigori_handle =
+ entry_factory_->CreateUnappliedNewItem(kNigoriTag,
+ server_specifics,
+ true);
+
+ // Initialize the local cryptographer with the local keys.
+ cryptographer->AddKey(local_params);
+ EXPECT_TRUE(cryptographer->is_ready());
+
+ // Set up a local nigori with the local encryption keys and default encrypted
+ // types.
+ sync_pb::EntitySpecifics local_specifics;
+ sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
+ cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
+ local_nigori->set_encrypt_everything(false);
+ local_nigori->set_keybag_is_frozen(true);
+ ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
+ nigori_handle, local_specifics));
+ // Apply the update locally so that UpdateFromEncryptedTypes knows what state
+ // to use.
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ cryptographer = directory()->GetCryptographer(&trans);
+ directory()->GetNigoriHandler()->ApplyNigoriUpdate(
+ *local_nigori,
+ &trans);
+ }
+
+ EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
+ EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
+ ApplyControlDataUpdates(directory());
+ EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
+ EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
+
+ EXPECT_FALSE(cryptographer->is_ready());
+ EXPECT_TRUE(cryptographer->is_initialized());
+ EXPECT_TRUE(cryptographer->has_pending_keys());
+ EXPECT_TRUE(other_cryptographer.CanDecryptUsingDefaultKey(
+ entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().encryption_keybag()));
+ EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().keybag_is_frozen());
+ EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().encrypt_everything());
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
+ .Equals(ModelTypeSet::All()));
+ EXPECT_TRUE(directory()->initial_sync_ended_types().Has(NIGORI));
+ }
+}
+
+// Verify we handle a nigori node conflict by merging encryption keys and
+// types, but preserve the custom passphrase state of the server.
+// Initial sync ended should be set.
+TEST_F(ApplyControlDataUpdatesTest,
+ NigoriConflictPendingKeysLocalEncryptEverythingCustom) {
+ Cryptographer* cryptographer;
+ ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
+ KeyParams other_params = {"localhost", "dummy", "foobar"};
+ KeyParams local_params = {"localhost", "dummy", "local"};
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ cryptographer = directory()->GetCryptographer(&trans);
+ EXPECT_TRUE(encrypted_types.Equals(
+ directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
+ }
+
+ // Set up a temporary cryptographer to generate new keys with.
+ Cryptographer other_cryptographer(cryptographer->encryptor());
+ other_cryptographer.AddKey(other_params);
+
+ // Create server specifics with pending keys, new encrypted types,
+ // and a custom passphrase (unmigrated).
+ sync_pb::EntitySpecifics server_specifics;
+ sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
+ other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
+ server_nigori->set_encrypt_everything(false);
+ server_nigori->set_keybag_is_frozen(false);
+ int64 nigori_handle =
+ entry_factory_->CreateUnappliedNewItem(kNigoriTag,
+ server_specifics,
+ true);
+
+ // Initialize the local cryptographer with the local keys.
+ cryptographer->AddKey(local_params);
+ EXPECT_TRUE(cryptographer->is_ready());
+
+ // Set up a local nigori with the local encryption keys and default encrypted
+ // types.
+ sync_pb::EntitySpecifics local_specifics;
+ sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
+ cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
+ local_nigori->set_encrypt_everything(true);
+ local_nigori->set_keybag_is_frozen(true);
+ ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
+ nigori_handle, local_specifics));
+ // Apply the update locally so that UpdateFromEncryptedTypes knows what state
+ // to use.
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ cryptographer = directory()->GetCryptographer(&trans);
+ directory()->GetNigoriHandler()->ApplyNigoriUpdate(
+ *local_nigori,
+ &trans);
+ }
+
+ EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
+ EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
+ ApplyControlDataUpdates(directory());
+ EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
+ EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
+
+ EXPECT_FALSE(cryptographer->is_ready());
+ EXPECT_TRUE(cryptographer->is_initialized());
+ EXPECT_TRUE(cryptographer->has_pending_keys());
+ EXPECT_TRUE(other_cryptographer.CanDecryptUsingDefaultKey(
+ entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().encryption_keybag()));
+ EXPECT_FALSE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().keybag_is_frozen());
+ EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().encrypt_everything());
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
+ .Equals(ModelTypeSet::All()));
+ EXPECT_TRUE(directory()->initial_sync_ended_types().Has(NIGORI));
+ }
+}
+
+// If the conflicting nigori has a subset of the local keys, the conflict
+// resolution should preserve the full local keys. Initial sync ended should be
+// set.
+TEST_F(ApplyControlDataUpdatesTest,
+ NigoriConflictOldKeys) {
+ Cryptographer* cryptographer;
+ ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
+ KeyParams old_params = {"localhost", "dummy", "old"};
+ KeyParams new_params = {"localhost", "dummy", "new"};
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ cryptographer = directory()->GetCryptographer(&trans);
+ EXPECT_TRUE(encrypted_types.Equals(
+ directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
+ }
+
+ // Set up the cryptographer with old keys
+ cryptographer->AddKey(old_params);
+
+ // Create server specifics with old keys and new encrypted types.
+ sync_pb::EntitySpecifics server_specifics;
+ sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
+ cryptographer->GetKeys(server_nigori->mutable_encryption_keybag());
+ server_nigori->set_encrypt_everything(true);
+ int64 nigori_handle =
+ entry_factory_->CreateUnappliedNewItem(kNigoriTag,
+ server_specifics,
+ true);
+
+ // Add the new keys to the cryptogrpaher
+ cryptographer->AddKey(new_params);
+ EXPECT_TRUE(cryptographer->is_ready());
+
+ // Set up a local nigori with the superset of keys.
+ sync_pb::EntitySpecifics local_specifics;
+ sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
+ cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
+ local_nigori->set_encrypt_everything(false);
+ ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
+ nigori_handle, local_specifics));
+ // Apply the update locally so that UpdateFromEncryptedTypes knows what state
+ // to use.
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ cryptographer = directory()->GetCryptographer(&trans);
+ directory()->GetNigoriHandler()->ApplyNigoriUpdate(
+ *local_nigori,
+ &trans);
+ }
+
+ EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
+ EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
+ ApplyControlDataUpdates(directory());
+ EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
+ EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
+
+ EXPECT_TRUE(cryptographer->is_ready());
+ EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
+ entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().encryption_keybag()));
+ EXPECT_FALSE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().keybag_is_frozen());
+ EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().encrypt_everything());
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
+ .Equals(ModelTypeSet::All()));
+ EXPECT_TRUE(directory()->initial_sync_ended_types().Has(NIGORI));
+ }
+}
+
+// If both nigoris are migrated, but we also set a custom passphrase locally,
+// the local nigori should be preserved.
+TEST_F(ApplyControlDataUpdatesTest,
+ NigoriConflictBothMigratedLocalCustom) {
+ Cryptographer* cryptographer;
+ ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
+ KeyParams old_params = {"localhost", "dummy", "old"};
+ KeyParams new_params = {"localhost", "dummy", "new"};
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ cryptographer = directory()->GetCryptographer(&trans);
+ EXPECT_TRUE(encrypted_types.Equals(
+ directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
+ }
+
+ // Set up the cryptographer with new keys
+ Cryptographer other_cryptographer(cryptographer->encryptor());
+ other_cryptographer.AddKey(old_params);
+
+ // Create server specifics with a migrated keystore passphrase type.
+ sync_pb::EntitySpecifics server_specifics;
+ sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
+ other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
+ server_nigori->set_encrypt_everything(false);
+ server_nigori->set_keybag_is_frozen(true);
+ server_nigori->set_passphrase_type(
+ sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
+ server_nigori->mutable_keystore_decryptor_token();
+ int64 nigori_handle =
+ entry_factory_->CreateUnappliedNewItem(kNigoriTag,
+ server_specifics,
+ true);
+
+ // Add the new keys to the cryptographer.
+ cryptographer->AddKey(old_params);
+ cryptographer->AddKey(new_params);
+ EXPECT_TRUE(cryptographer->is_ready());
+
+ // Set up a local nigori with a migrated custom passphrase type
+ sync_pb::EntitySpecifics local_specifics;
+ sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
+ cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
+ local_nigori->set_encrypt_everything(true);
+ local_nigori->set_keybag_is_frozen(true);
+ local_nigori->set_passphrase_type(
+ sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
+ ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
+ nigori_handle, local_specifics));
+ // Apply the update locally so that UpdateFromEncryptedTypes knows what state
+ // to use.
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ cryptographer = directory()->GetCryptographer(&trans);
+ directory()->GetNigoriHandler()->ApplyNigoriUpdate(
+ *local_nigori,
+ &trans);
+ }
+
+ EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
+ EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
+ ApplyControlDataUpdates(directory());
+ EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
+ EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
+
+ EXPECT_TRUE(cryptographer->is_ready());
+ EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
+ entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().encryption_keybag()));
+ EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().keybag_is_frozen());
+ EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().encrypt_everything());
+ EXPECT_EQ(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE,
+ entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().passphrase_type());
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
+ .Equals(ModelTypeSet::All()));
+ EXPECT_TRUE(directory()->initial_sync_ended_types().Has(NIGORI));
+ }
+}
+
+// If both nigoris are migrated, but a custom passphrase with a new key was
+// set remotely, the remote nigori should be preserved.
+TEST_F(ApplyControlDataUpdatesTest,
+ NigoriConflictBothMigratedServerCustom) {
+ Cryptographer* cryptographer;
+ ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
+ KeyParams old_params = {"localhost", "dummy", "old"};
+ KeyParams new_params = {"localhost", "dummy", "new"};
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ cryptographer = directory()->GetCryptographer(&trans);
+ EXPECT_TRUE(encrypted_types.Equals(
+ directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
+ }
+
+ // Set up the cryptographer with both new keys and old keys.
+ Cryptographer other_cryptographer(cryptographer->encryptor());
+ other_cryptographer.AddKey(old_params);
+ other_cryptographer.AddKey(new_params);
+
+ // Create server specifics with a migrated custom passphrase type.
+ sync_pb::EntitySpecifics server_specifics;
+ sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
+ other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
+ server_nigori->set_encrypt_everything(true);
+ server_nigori->set_keybag_is_frozen(true);
+ server_nigori->set_passphrase_type(
+ sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
+ int64 nigori_handle =
+ entry_factory_->CreateUnappliedNewItem(kNigoriTag,
+ server_specifics,
+ true);
+
+ // Add the old keys to the cryptographer.
+ cryptographer->AddKey(old_params);
+ EXPECT_TRUE(cryptographer->is_ready());
+
+ // Set up a local nigori with a migrated keystore passphrase type
+ sync_pb::EntitySpecifics local_specifics;
+ sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
+ cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
+ local_nigori->set_encrypt_everything(false);
+ local_nigori->set_keybag_is_frozen(true);
+ local_nigori->set_passphrase_type(
+ sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
+ server_nigori->mutable_keystore_decryptor_token();
+ ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
+ nigori_handle, local_specifics));
+ // Apply the update locally so that UpdateFromEncryptedTypes knows what state
+ // to use.
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ cryptographer = directory()->GetCryptographer(&trans);
+ directory()->GetNigoriHandler()->ApplyNigoriUpdate(
+ *local_nigori,
+ &trans);
+ }
+
+ EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
+ EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
+ ApplyControlDataUpdates(directory());
+ EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
+ EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
+
+ EXPECT_TRUE(cryptographer->is_initialized());
+ EXPECT_TRUE(cryptographer->has_pending_keys());
+ EXPECT_TRUE(other_cryptographer.CanDecryptUsingDefaultKey(
+ entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().encryption_keybag()));
+ EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().keybag_is_frozen());
+ EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().encrypt_everything());
+ EXPECT_EQ(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE,
+ entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().passphrase_type());
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
+ .Equals(ModelTypeSet::All()));
+ EXPECT_TRUE(directory()->initial_sync_ended_types().Has(NIGORI));
+ }
+}
+
+// If the local nigori is migrated but the server is not, preserve the local
+// nigori.
+TEST_F(ApplyControlDataUpdatesTest,
+ NigoriConflictLocalMigrated) {
+ Cryptographer* cryptographer;
+ ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
+ KeyParams old_params = {"localhost", "dummy", "old"};
+ KeyParams new_params = {"localhost", "dummy", "new"};
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ cryptographer = directory()->GetCryptographer(&trans);
+ EXPECT_TRUE(encrypted_types.Equals(
+ directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
+ }
+
+ // Set up the cryptographer with both new keys and old keys.
+ Cryptographer other_cryptographer(cryptographer->encryptor());
+ other_cryptographer.AddKey(old_params);
+
+ // Create server specifics with an unmigrated implicit passphrase type.
+ sync_pb::EntitySpecifics server_specifics;
+ sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
+ other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
+ server_nigori->set_encrypt_everything(true);
+ server_nigori->set_keybag_is_frozen(false);
+ int64 nigori_handle =
+ entry_factory_->CreateUnappliedNewItem(kNigoriTag,
+ server_specifics,
+ true);
+
+ // Add the old keys to the cryptographer.
+ cryptographer->AddKey(old_params);
+ cryptographer->AddKey(new_params);
+ EXPECT_TRUE(cryptographer->is_ready());
+
+ // Set up a local nigori with a migrated custom passphrase type
+ sync_pb::EntitySpecifics local_specifics;
+ sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
+ cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
+ local_nigori->set_encrypt_everything(true);
+ local_nigori->set_keybag_is_frozen(true);
+ local_nigori->set_passphrase_type(
+ sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
+ ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
+ nigori_handle, local_specifics));
+ // Apply the update locally so that UpdateFromEncryptedTypes knows what state
+ // to use.
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ cryptographer = directory()->GetCryptographer(&trans);
+ directory()->GetNigoriHandler()->ApplyNigoriUpdate(
+ *local_nigori,
+ &trans);
+ }
+
+ EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
+ EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
+ ApplyControlDataUpdates(directory());
+ EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
+ EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
+
+ EXPECT_TRUE(cryptographer->is_ready());
+ EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
+ entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().encryption_keybag()));
+ EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().keybag_is_frozen());
+ EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().encrypt_everything());
+ EXPECT_EQ(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE,
+ entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().passphrase_type());
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
+ .Equals(ModelTypeSet::All()));
+ EXPECT_TRUE(directory()->initial_sync_ended_types().Has(NIGORI));
+ }
+}
+
+// If the server nigori is migrated but the local is not, preserve the server
+// nigori.
+TEST_F(ApplyControlDataUpdatesTest,
+ NigoriConflictServerMigrated) {
+ Cryptographer* cryptographer;
+ ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
+ KeyParams old_params = {"localhost", "dummy", "old"};
+ KeyParams new_params = {"localhost", "dummy", "new"};
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ cryptographer = directory()->GetCryptographer(&trans);
+ EXPECT_TRUE(encrypted_types.Equals(
+ directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
+ }
+
+ // Set up the cryptographer with both new keys and old keys.
+ Cryptographer other_cryptographer(cryptographer->encryptor());
+ other_cryptographer.AddKey(old_params);
+
+ // Create server specifics with an migrated keystore passphrase type.
+ sync_pb::EntitySpecifics server_specifics;
+ sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
+ other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
+ server_nigori->set_encrypt_everything(false);
+ server_nigori->set_keybag_is_frozen(true);
+ server_nigori->set_passphrase_type(
+ sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
+ server_nigori->mutable_keystore_decryptor_token();
+ int64 nigori_handle =
+ entry_factory_->CreateUnappliedNewItem(kNigoriTag,
+ server_specifics,
+ true);
+
+ // Add the old keys to the cryptographer.
+ cryptographer->AddKey(old_params);
+ cryptographer->AddKey(new_params);
+ EXPECT_TRUE(cryptographer->is_ready());
+
+ // Set up a local nigori with a migrated custom passphrase type
+ sync_pb::EntitySpecifics local_specifics;
+ sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
+ cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
+ local_nigori->set_encrypt_everything(false);
+ local_nigori->set_keybag_is_frozen(false);
+ ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
+ nigori_handle, local_specifics));
+ // Apply the update locally so that UpdateFromEncryptedTypes knows what state
+ // to use.
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ cryptographer = directory()->GetCryptographer(&trans);
+ directory()->GetNigoriHandler()->ApplyNigoriUpdate(
+ *local_nigori,
+ &trans);
+ }
+
+ EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
+ EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
+ ApplyControlDataUpdates(directory());
+ EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
+ EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
+
+ EXPECT_TRUE(cryptographer->is_ready());
+ // Note: we didn't overwrite the encryption keybag with the local keys. The
+ // sync encryption handler will do that when it detects that the new
+ // keybag is out of date (and update the keystore bootstrap if necessary).
+ EXPECT_FALSE(cryptographer->CanDecryptUsingDefaultKey(
+ entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().encryption_keybag()));
+ EXPECT_TRUE(cryptographer->CanDecrypt(
+ entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().encryption_keybag()));
+ EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().keybag_is_frozen());
+ EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().has_keystore_decryptor_token());
+ EXPECT_EQ(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE,
+ entry_factory_->GetLocalSpecificsForItem(nigori_handle).
+ nigori().passphrase_type());
+ {
+ syncable::ReadTransaction trans(FROM_HERE, directory());
+ EXPECT_TRUE(directory()->initial_sync_ended_types().Has(NIGORI));
+ }
+}
+
} // namespace syncer
diff --git a/sync/engine/syncer_unittest.cc b/sync/engine/syncer_unittest.cc
index 0165016..28650a6 100644
--- a/sync/engine/syncer_unittest.cc
+++ b/sync/engine/syncer_unittest.cc
@@ -978,130 +978,6 @@ TEST_F(SyncerTest, EncryptionAwareConflicts) {
#undef VERIFY_ENTRY
-// Resolve a confict between two nigori's with different encrypted types,
-// and encryption keys (remote is explicit). Afterwards, the encrypted types
-// should be unioned and the cryptographer should have both keys and be
-// encrypting with the remote encryption key by default.
-// TODO(zea): Test conflicts with keystore migration.
-TEST_F(SyncerTest, NigoriConflicts) {
- KeyParams local_key_params = {"localhost", "dummy", "blargle"};
- KeyParams other_key_params = {"localhost", "dummy", "foobar"};
- Cryptographer other_cryptographer(&encryptor_);
- other_cryptographer.AddKey(other_key_params);
- ModelTypeSet encrypted_types(PASSWORDS, NIGORI);
- sync_pb::EntitySpecifics initial_nigori_specifics;
- initial_nigori_specifics.mutable_nigori();
- mock_server_->SetNigori(1, 10, 10, initial_nigori_specifics);
-
- // Data for testing encryption/decryption.
- sync_pb::EntitySpecifics other_encrypted_specifics;
- other_encrypted_specifics.mutable_bookmark()->set_title("title");
- other_cryptographer.Encrypt(
- other_encrypted_specifics,
- other_encrypted_specifics.mutable_encrypted());
- sync_pb::EntitySpecifics our_encrypted_specifics;
- our_encrypted_specifics.mutable_bookmark()->set_title("title2");
-
- // Receive the initial nigori node.
- SyncShareNudge();
- encrypted_types = ModelTypeSet::All();
- {
- // Local changes with different passphrase, different types.
- WriteTransaction wtrans(FROM_HERE, UNITTEST, directory());
- sync_pb::EntitySpecifics specifics;
- sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
- GetCryptographer(&wtrans)->AddKey(local_key_params);
- GetCryptographer(&wtrans)->Encrypt(
- our_encrypted_specifics,
- our_encrypted_specifics.mutable_encrypted());
- GetCryptographer(&wtrans)->GetKeys(
- nigori->mutable_encryption_keybag());
- dir_maker_.encryption_handler()->EnableEncryptEverything();
- directory()->GetNigoriHandler()->UpdateNigoriFromEncryptedTypes(
- nigori,
- &wtrans);
- MutableEntry nigori_entry(&wtrans, GET_BY_SERVER_TAG,
- ModelTypeToRootTag(NIGORI));
- ASSERT_TRUE(nigori_entry.good());
- nigori_entry.Put(SPECIFICS, specifics);
- nigori_entry.Put(IS_UNSYNCED, true);
- EXPECT_FALSE(GetCryptographer(&wtrans)->has_pending_keys());
- EXPECT_TRUE(encrypted_types.Equals(
- directory()->GetNigoriHandler()->GetEncryptedTypes(&wtrans)));
- }
- {
- sync_pb::EntitySpecifics specifics;
- sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
- other_cryptographer.GetKeys(nigori->mutable_encryption_keybag());
- nigori->set_encrypt_bookmarks(true);
- nigori->set_encrypt_preferences(true);
- nigori->set_encrypt_everything(false);
- nigori->set_keybag_is_frozen(true);
- mock_server_->SetNigori(1, 20, 20, specifics);
- }
-
- // Will result in downloading the server nigori, which puts the local nigori
- // in a state of conflict. This is resolved by merging the local and server
- // data (with priority given to the server's encryption keys if they are
- // undecryptable), which we then commit. The cryptographer should have pending
- // keys and merge the set of encrypted types.
- SyncShareNudge(); // Resolve conflict in this cycle.
- SyncShareNudge(); // Commit local change in this cycle.
- {
- // Ensure the nigori data merged (encrypted types).
- WriteTransaction wtrans(FROM_HERE, UNITTEST, directory());
- MutableEntry nigori_entry(&wtrans, GET_BY_SERVER_TAG,
- ModelTypeToRootTag(NIGORI));
- ASSERT_TRUE(nigori_entry.good());
- EXPECT_FALSE(nigori_entry.Get(IS_UNAPPLIED_UPDATE));
- EXPECT_FALSE(nigori_entry.Get(IS_UNSYNCED));
- sync_pb::EntitySpecifics specifics = nigori_entry.Get(SPECIFICS);
- ASSERT_TRUE(GetCryptographer(&wtrans)->has_pending_keys());
- EXPECT_TRUE(encrypted_types.Equals(
- directory()->GetNigoriHandler()->GetEncryptedTypes(&wtrans)));
- EXPECT_TRUE(dir_maker_.encryption_handler()->EncryptEverythingEnabled());
- EXPECT_TRUE(specifics.nigori().keybag_is_frozen());
- // Supply the pending keys. Afterwards, we should be able to decrypt both
- // our own encrypted data and data encrypted by the other cryptographer,
- // but the key provided by the other cryptographer should be the default.
- EXPECT_TRUE(
- GetCryptographer(&wtrans)->DecryptPendingKeys(other_key_params));
- EXPECT_FALSE(GetCryptographer(&wtrans)->has_pending_keys());
- sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
- GetCryptographer(&wtrans)->GetKeys(nigori->mutable_encryption_keybag());
- directory()->GetNigoriHandler()->UpdateNigoriFromEncryptedTypes(
- nigori,
- &wtrans);
- // Normally this would be written as part of SetPassphrase, but we do it
- // manually for the test.
- nigori_entry.Put(SPECIFICS, specifics);
- nigori_entry.Put(IS_UNSYNCED, true);
- }
-
- SyncShareNudge();
- {
- // Ensure everything is committed and stable now. The cryptographer
- // should be able to decrypt both sets of keys, and the encrypted types
- // should have been unioned.
- WriteTransaction wtrans(FROM_HERE, UNITTEST, directory());
- MutableEntry nigori_entry(&wtrans, GET_BY_SERVER_TAG,
- ModelTypeToRootTag(NIGORI));
- ASSERT_TRUE(nigori_entry.good());
- EXPECT_FALSE(nigori_entry.Get(IS_UNAPPLIED_UPDATE));
- EXPECT_FALSE(nigori_entry.Get(IS_UNSYNCED));
- EXPECT_TRUE(GetCryptographer(&wtrans)->CanDecrypt(
- our_encrypted_specifics.encrypted()));
- EXPECT_FALSE(GetCryptographer(&wtrans)->
- CanDecryptUsingDefaultKey(our_encrypted_specifics.encrypted()));
- EXPECT_TRUE(GetCryptographer(&wtrans)->CanDecrypt(
- other_encrypted_specifics.encrypted()));
- EXPECT_TRUE(GetCryptographer(&wtrans)->
- CanDecryptUsingDefaultKey(other_encrypted_specifics.encrypted()));
- EXPECT_TRUE(nigori_entry.Get(SPECIFICS).nigori().
- keybag_is_frozen());
- }
-}
-
TEST_F(SyncerTest, TestGetUnsyncedAndSimpleCommit) {
{
WriteTransaction wtrans(FROM_HERE, UNITTEST, directory());