Home | History | Annotate | Download | only in engine
      1 // Copyright 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/format_macros.h"
      6 #include "base/location.h"
      7 #include "base/memory/scoped_ptr.h"
      8 #include "base/strings/stringprintf.h"
      9 #include "sync/engine/apply_control_data_updates.h"
     10 #include "sync/engine/syncer.h"
     11 #include "sync/engine/syncer_util.h"
     12 #include "sync/internal_api/public/test/test_entry_factory.h"
     13 #include "sync/protocol/nigori_specifics.pb.h"
     14 #include "sync/syncable/mutable_entry.h"
     15 #include "sync/syncable/nigori_util.h"
     16 #include "sync/syncable/syncable_read_transaction.h"
     17 #include "sync/syncable/syncable_util.h"
     18 #include "sync/syncable/syncable_write_transaction.h"
     19 #include "sync/test/engine/fake_model_worker.h"
     20 #include "sync/test/engine/syncer_command_test.h"
     21 #include "sync/test/engine/test_id_factory.h"
     22 #include "sync/test/fake_sync_encryption_handler.h"
     23 #include "sync/util/cryptographer.h"
     24 #include "testing/gtest/include/gtest/gtest.h"
     25 
     26 namespace syncer {
     27 
     28 using syncable::MutableEntry;
     29 using syncable::UNITTEST;
     30 using syncable::Id;
     31 
     32 class ApplyControlDataUpdatesTest : public SyncerCommandTest {
     33  public:
     34  protected:
     35   ApplyControlDataUpdatesTest() {}
     36   virtual ~ApplyControlDataUpdatesTest() {}
     37 
     38   virtual void SetUp() {
     39     workers()->clear();
     40     mutable_routing_info()->clear();
     41     workers()->push_back(make_scoped_refptr(new FakeModelWorker(GROUP_UI)));
     42     workers()->push_back(
     43         make_scoped_refptr(new FakeModelWorker(GROUP_PASSWORD)));
     44     (*mutable_routing_info())[NIGORI] = GROUP_PASSIVE;
     45     (*mutable_routing_info())[EXPERIMENTS] = GROUP_PASSIVE;
     46     SyncerCommandTest::SetUp();
     47     entry_factory_.reset(new TestEntryFactory(directory()));
     48 
     49     session()->mutable_status_controller()->set_updates_request_types(
     50         ControlTypes());
     51 
     52     syncable::ReadTransaction trans(FROM_HERE, directory());
     53   }
     54 
     55   TestIdFactory id_factory_;
     56   scoped_ptr<TestEntryFactory> entry_factory_;
     57  private:
     58   DISALLOW_COPY_AND_ASSIGN(ApplyControlDataUpdatesTest);
     59 };
     60 
     61 // Verify that applying a nigori node sets initial sync ended properly,
     62 // updates the set of encrypted types, and updates the cryptographer.
     63 TEST_F(ApplyControlDataUpdatesTest, NigoriUpdate) {
     64   // Storing the cryptographer separately is bad, but for this test we
     65   // know it's safe.
     66   Cryptographer* cryptographer;
     67   ModelTypeSet encrypted_types;
     68   encrypted_types.PutAll(SyncEncryptionHandler::SensitiveTypes());
     69 
     70   {
     71     syncable::ReadTransaction trans(FROM_HERE, directory());
     72     cryptographer = directory()->GetCryptographer(&trans);
     73     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
     74         .Equals(encrypted_types));
     75   }
     76 
     77   // Nigori node updates should update the Cryptographer.
     78   Cryptographer other_cryptographer(cryptographer->encryptor());
     79   KeyParams params = {"localhost", "dummy", "foobar"};
     80   other_cryptographer.AddKey(params);
     81 
     82   sync_pb::EntitySpecifics specifics;
     83   sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
     84   other_cryptographer.GetKeys(nigori->mutable_encryption_keybag());
     85   nigori->set_encrypt_everything(true);
     86   entry_factory_->CreateUnappliedNewItem(
     87       ModelTypeToRootTag(NIGORI), specifics, true);
     88   EXPECT_FALSE(cryptographer->has_pending_keys());
     89 
     90   ApplyControlDataUpdates(session());
     91 
     92   EXPECT_FALSE(cryptographer->is_ready());
     93   EXPECT_TRUE(cryptographer->has_pending_keys());
     94   {
     95     syncable::ReadTransaction trans(FROM_HERE, directory());
     96     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
     97         .Equals(ModelTypeSet::All()));
     98   }
     99 }
    100 
    101 // Create some local unsynced and unencrypted data. Apply a nigori update that
    102 // turns on encryption for the unsynced data. Ensure we properly encrypt the
    103 // data as part of the nigori update. Apply another nigori update with no
    104 // changes. Ensure we ignore already-encrypted unsynced data and that nothing
    105 // breaks.
    106 TEST_F(ApplyControlDataUpdatesTest, EncryptUnsyncedChanges) {
    107   // Storing the cryptographer separately is bad, but for this test we
    108   // know it's safe.
    109   Cryptographer* cryptographer;
    110   ModelTypeSet encrypted_types;
    111   encrypted_types.PutAll(SyncEncryptionHandler::SensitiveTypes());
    112   {
    113     syncable::ReadTransaction trans(FROM_HERE, directory());
    114     cryptographer = directory()->GetCryptographer(&trans);
    115     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
    116         .Equals(encrypted_types));
    117 
    118     // With default encrypted_types, this should be true.
    119     EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
    120 
    121     Syncer::UnsyncedMetaHandles handles;
    122     GetUnsyncedEntries(&trans, &handles);
    123     EXPECT_TRUE(handles.empty());
    124   }
    125 
    126   // Create unsynced bookmarks without encryption.
    127   // First item is a folder
    128   Id folder_id = id_factory_.NewLocalId();
    129   entry_factory_->CreateUnsyncedItem(folder_id, id_factory_.root(), "folder",
    130                                      true, BOOKMARKS, NULL);
    131   // Next five items are children of the folder
    132   size_t i;
    133   size_t batch_s = 5;
    134   for (i = 0; i < batch_s; ++i) {
    135     entry_factory_->CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id,
    136                                        base::StringPrintf("Item %" PRIuS "", i),
    137                                        false, BOOKMARKS, NULL);
    138   }
    139   // Next five items are children of the root.
    140   for (; i < 2*batch_s; ++i) {
    141     entry_factory_->CreateUnsyncedItem(
    142         id_factory_.NewLocalId(), id_factory_.root(),
    143         base::StringPrintf("Item %" PRIuS "", i), false,
    144         BOOKMARKS, NULL);
    145   }
    146 
    147   KeyParams params = {"localhost", "dummy", "foobar"};
    148   cryptographer->AddKey(params);
    149   sync_pb::EntitySpecifics specifics;
    150   sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
    151   cryptographer->GetKeys(nigori->mutable_encryption_keybag());
    152   nigori->set_encrypt_everything(true);
    153   encrypted_types.Put(BOOKMARKS);
    154   entry_factory_->CreateUnappliedNewItem(
    155       ModelTypeToRootTag(NIGORI), specifics, true);
    156   EXPECT_FALSE(cryptographer->has_pending_keys());
    157   EXPECT_TRUE(cryptographer->is_ready());
    158 
    159   {
    160     // Ensure we have unsynced nodes that aren't properly encrypted.
    161     syncable::ReadTransaction trans(FROM_HERE, directory());
    162     EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
    163 
    164     Syncer::UnsyncedMetaHandles handles;
    165     GetUnsyncedEntries(&trans, &handles);
    166     EXPECT_EQ(2*batch_s+1, handles.size());
    167   }
    168 
    169   ApplyControlDataUpdates(session());
    170 
    171   EXPECT_FALSE(cryptographer->has_pending_keys());
    172   EXPECT_TRUE(cryptographer->is_ready());
    173   {
    174     syncable::ReadTransaction trans(FROM_HERE, directory());
    175 
    176     // If ProcessUnsyncedChangesForEncryption worked, all our unsynced changes
    177     // should be encrypted now.
    178     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
    179         .Equals(ModelTypeSet::All()));
    180     EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
    181 
    182     Syncer::UnsyncedMetaHandles handles;
    183     GetUnsyncedEntries(&trans, &handles);
    184     EXPECT_EQ(2*batch_s+1, handles.size());
    185   }
    186 
    187   // Simulate another nigori update that doesn't change anything.
    188   {
    189     syncable::WriteTransaction trans(FROM_HERE, UNITTEST, directory());
    190     MutableEntry entry(&trans, syncable::GET_BY_SERVER_TAG,
    191                        ModelTypeToRootTag(NIGORI));
    192     ASSERT_TRUE(entry.good());
    193     entry.Put(syncable::SERVER_VERSION, entry_factory_->GetNextRevision());
    194     entry.Put(syncable::IS_UNAPPLIED_UPDATE, true);
    195   }
    196 
    197   ApplyControlDataUpdates(session());
    198 
    199   EXPECT_FALSE(cryptographer->has_pending_keys());
    200   EXPECT_TRUE(cryptographer->is_ready());
    201   {
    202     syncable::ReadTransaction trans(FROM_HERE, directory());
    203 
    204     // All our changes should still be encrypted.
    205     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
    206         .Equals(ModelTypeSet::All()));
    207     EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
    208 
    209     Syncer::UnsyncedMetaHandles handles;
    210     GetUnsyncedEntries(&trans, &handles);
    211     EXPECT_EQ(2*batch_s+1, handles.size());
    212   }
    213 }
    214 
    215 // Create some local unsynced and unencrypted changes. Receive a new nigori
    216 // node enabling their encryption but also introducing pending keys. Ensure
    217 // we apply the update properly without encrypting the unsynced changes or
    218 // breaking.
    219 TEST_F(ApplyControlDataUpdatesTest, CannotEncryptUnsyncedChanges) {
    220   // Storing the cryptographer separately is bad, but for this test we
    221   // know it's safe.
    222   Cryptographer* cryptographer;
    223   ModelTypeSet encrypted_types;
    224   encrypted_types.PutAll(SyncEncryptionHandler::SensitiveTypes());
    225   {
    226     syncable::ReadTransaction trans(FROM_HERE, directory());
    227     cryptographer = directory()->GetCryptographer(&trans);
    228     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
    229         .Equals(encrypted_types));
    230 
    231     // With default encrypted_types, this should be true.
    232     EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
    233 
    234     Syncer::UnsyncedMetaHandles handles;
    235     GetUnsyncedEntries(&trans, &handles);
    236     EXPECT_TRUE(handles.empty());
    237   }
    238 
    239   // Create unsynced bookmarks without encryption.
    240   // First item is a folder
    241   Id folder_id = id_factory_.NewLocalId();
    242   entry_factory_->CreateUnsyncedItem(
    243       folder_id, id_factory_.root(), "folder", true,
    244       BOOKMARKS, NULL);
    245   // Next five items are children of the folder
    246   size_t i;
    247   size_t batch_s = 5;
    248   for (i = 0; i < batch_s; ++i) {
    249     entry_factory_->CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id,
    250                                        base::StringPrintf("Item %" PRIuS "", i),
    251                                        false, BOOKMARKS, NULL);
    252   }
    253   // Next five items are children of the root.
    254   for (; i < 2*batch_s; ++i) {
    255     entry_factory_->CreateUnsyncedItem(
    256         id_factory_.NewLocalId(), id_factory_.root(),
    257         base::StringPrintf("Item %" PRIuS "", i), false,
    258         BOOKMARKS, NULL);
    259   }
    260 
    261   // We encrypt with new keys, triggering the local cryptographer to be unready
    262   // and unable to decrypt data (once updated).
    263   Cryptographer other_cryptographer(cryptographer->encryptor());
    264   KeyParams params = {"localhost", "dummy", "foobar"};
    265   other_cryptographer.AddKey(params);
    266   sync_pb::EntitySpecifics specifics;
    267   sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
    268   other_cryptographer.GetKeys(nigori->mutable_encryption_keybag());
    269   nigori->set_encrypt_everything(true);
    270   encrypted_types.Put(BOOKMARKS);
    271   entry_factory_->CreateUnappliedNewItem(
    272       ModelTypeToRootTag(NIGORI), specifics, true);
    273   EXPECT_FALSE(cryptographer->has_pending_keys());
    274 
    275   {
    276     // Ensure we have unsynced nodes that aren't properly encrypted.
    277     syncable::ReadTransaction trans(FROM_HERE, directory());
    278     EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
    279     Syncer::UnsyncedMetaHandles handles;
    280     GetUnsyncedEntries(&trans, &handles);
    281     EXPECT_EQ(2*batch_s+1, handles.size());
    282   }
    283 
    284   ApplyControlDataUpdates(session());
    285 
    286   EXPECT_FALSE(cryptographer->is_ready());
    287   EXPECT_TRUE(cryptographer->has_pending_keys());
    288   {
    289     syncable::ReadTransaction trans(FROM_HERE, directory());
    290 
    291     // Since we have pending keys, we would have failed to encrypt, but the
    292     // cryptographer should be updated.
    293     EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
    294     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
    295         .Equals(ModelTypeSet::All()));
    296     EXPECT_FALSE(cryptographer->is_ready());
    297     EXPECT_TRUE(cryptographer->has_pending_keys());
    298 
    299     Syncer::UnsyncedMetaHandles handles;
    300     GetUnsyncedEntries(&trans, &handles);
    301     EXPECT_EQ(2*batch_s+1, handles.size());
    302   }
    303 }
    304 
    305 // Verify we handle a nigori node conflict by merging encryption keys and
    306 // types, but preserve the custom passphrase state of the server.
    307 // Initial sync ended should be set.
    308 TEST_F(ApplyControlDataUpdatesTest,
    309        NigoriConflictPendingKeysServerEncryptEverythingCustom) {
    310   Cryptographer* cryptographer;
    311   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
    312   KeyParams other_params = {"localhost", "dummy", "foobar"};
    313   KeyParams local_params = {"localhost", "dummy", "local"};
    314   {
    315     syncable::ReadTransaction trans(FROM_HERE, directory());
    316     cryptographer = directory()->GetCryptographer(&trans);
    317     EXPECT_TRUE(encrypted_types.Equals(
    318             directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
    319   }
    320 
    321   // Set up a temporary cryptographer to generate new keys with.
    322   Cryptographer other_cryptographer(cryptographer->encryptor());
    323   other_cryptographer.AddKey(other_params);
    324 
    325   // Create server specifics with pending keys, new encrypted types,
    326   // and a custom passphrase (unmigrated).
    327   sync_pb::EntitySpecifics server_specifics;
    328   sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
    329   other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
    330   server_nigori->set_encrypt_everything(true);
    331   server_nigori->set_keybag_is_frozen(true);
    332   int64 nigori_handle =
    333       entry_factory_->CreateUnappliedNewItem(kNigoriTag,
    334                                              server_specifics,
    335                                              true);
    336 
    337   // Initialize the local cryptographer with the local keys.
    338   cryptographer->AddKey(local_params);
    339   EXPECT_TRUE(cryptographer->is_ready());
    340 
    341   // Set up a local nigori with the local encryption keys and default encrypted
    342   // types.
    343   sync_pb::EntitySpecifics local_specifics;
    344   sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
    345   cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
    346   local_nigori->set_encrypt_everything(false);
    347   local_nigori->set_keybag_is_frozen(true);
    348   ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
    349           nigori_handle, local_specifics));
    350   // Apply the update locally so that UpdateFromEncryptedTypes knows what state
    351   // to use.
    352   {
    353     syncable::ReadTransaction trans(FROM_HERE, directory());
    354     cryptographer = directory()->GetCryptographer(&trans);
    355     directory()->GetNigoriHandler()->ApplyNigoriUpdate(
    356         *local_nigori,
    357         &trans);
    358   }
    359 
    360   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
    361   EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
    362   ApplyControlDataUpdates(session());
    363   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
    364   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
    365 
    366   EXPECT_FALSE(cryptographer->is_ready());
    367   EXPECT_TRUE(cryptographer->is_initialized());
    368   EXPECT_TRUE(cryptographer->has_pending_keys());
    369   EXPECT_TRUE(other_cryptographer.CanDecryptUsingDefaultKey(
    370           entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    371               nigori().encryption_keybag()));
    372   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    373       nigori().keybag_is_frozen());
    374   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    375       nigori().encrypt_everything());
    376   {
    377     syncable::ReadTransaction trans(FROM_HERE, directory());
    378     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
    379         .Equals(ModelTypeSet::All()));
    380   }
    381 }
    382 
    383 // Verify we handle a nigori node conflict by merging encryption keys and
    384 // types, but preserve the custom passphrase state of the server.
    385 // Initial sync ended should be set.
    386 TEST_F(ApplyControlDataUpdatesTest,
    387        NigoriConflictPendingKeysLocalEncryptEverythingCustom) {
    388   Cryptographer* cryptographer;
    389   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
    390   KeyParams other_params = {"localhost", "dummy", "foobar"};
    391   KeyParams local_params = {"localhost", "dummy", "local"};
    392   {
    393     syncable::ReadTransaction trans(FROM_HERE, directory());
    394     cryptographer = directory()->GetCryptographer(&trans);
    395     EXPECT_TRUE(encrypted_types.Equals(
    396             directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
    397   }
    398 
    399   // Set up a temporary cryptographer to generate new keys with.
    400   Cryptographer other_cryptographer(cryptographer->encryptor());
    401   other_cryptographer.AddKey(other_params);
    402 
    403   // Create server specifics with pending keys, new encrypted types,
    404   // and a custom passphrase (unmigrated).
    405   sync_pb::EntitySpecifics server_specifics;
    406   sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
    407   other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
    408   server_nigori->set_encrypt_everything(false);
    409   server_nigori->set_keybag_is_frozen(false);
    410   int64 nigori_handle =
    411       entry_factory_->CreateUnappliedNewItem(kNigoriTag,
    412                                              server_specifics,
    413                                              true);
    414 
    415   // Initialize the local cryptographer with the local keys.
    416   cryptographer->AddKey(local_params);
    417   EXPECT_TRUE(cryptographer->is_ready());
    418 
    419   // Set up a local nigori with the local encryption keys and default encrypted
    420   // types.
    421   sync_pb::EntitySpecifics local_specifics;
    422   sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
    423   cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
    424   local_nigori->set_encrypt_everything(true);
    425   local_nigori->set_keybag_is_frozen(true);
    426   ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
    427           nigori_handle, local_specifics));
    428   // Apply the update locally so that UpdateFromEncryptedTypes knows what state
    429   // to use.
    430   {
    431     syncable::ReadTransaction trans(FROM_HERE, directory());
    432     cryptographer = directory()->GetCryptographer(&trans);
    433     directory()->GetNigoriHandler()->ApplyNigoriUpdate(
    434         *local_nigori,
    435         &trans);
    436   }
    437 
    438   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
    439   EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
    440   ApplyControlDataUpdates(session());
    441   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
    442   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
    443 
    444   EXPECT_FALSE(cryptographer->is_ready());
    445   EXPECT_TRUE(cryptographer->is_initialized());
    446   EXPECT_TRUE(cryptographer->has_pending_keys());
    447   EXPECT_TRUE(other_cryptographer.CanDecryptUsingDefaultKey(
    448           entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    449               nigori().encryption_keybag()));
    450   EXPECT_FALSE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    451       nigori().keybag_is_frozen());
    452   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    453       nigori().encrypt_everything());
    454   {
    455     syncable::ReadTransaction trans(FROM_HERE, directory());
    456     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
    457         .Equals(ModelTypeSet::All()));
    458   }
    459 }
    460 
    461 // If the conflicting nigori has a subset of the local keys, the conflict
    462 // resolution should preserve the full local keys. Initial sync ended should be
    463 // set.
    464 TEST_F(ApplyControlDataUpdatesTest,
    465        NigoriConflictOldKeys) {
    466   Cryptographer* cryptographer;
    467   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
    468   KeyParams old_params = {"localhost", "dummy", "old"};
    469   KeyParams new_params = {"localhost", "dummy", "new"};
    470   {
    471     syncable::ReadTransaction trans(FROM_HERE, directory());
    472     cryptographer = directory()->GetCryptographer(&trans);
    473     EXPECT_TRUE(encrypted_types.Equals(
    474             directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
    475   }
    476 
    477   // Set up the cryptographer with old keys
    478   cryptographer->AddKey(old_params);
    479 
    480   // Create server specifics with old keys and new encrypted types.
    481   sync_pb::EntitySpecifics server_specifics;
    482   sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
    483   cryptographer->GetKeys(server_nigori->mutable_encryption_keybag());
    484   server_nigori->set_encrypt_everything(true);
    485   int64 nigori_handle =
    486       entry_factory_->CreateUnappliedNewItem(kNigoriTag,
    487                                              server_specifics,
    488                                              true);
    489 
    490   // Add the new keys to the cryptogrpaher
    491   cryptographer->AddKey(new_params);
    492   EXPECT_TRUE(cryptographer->is_ready());
    493 
    494   // Set up a local nigori with the superset of keys.
    495   sync_pb::EntitySpecifics local_specifics;
    496   sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
    497   cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
    498   local_nigori->set_encrypt_everything(false);
    499   ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
    500           nigori_handle, local_specifics));
    501   // Apply the update locally so that UpdateFromEncryptedTypes knows what state
    502   // to use.
    503   {
    504     syncable::ReadTransaction trans(FROM_HERE, directory());
    505     cryptographer = directory()->GetCryptographer(&trans);
    506     directory()->GetNigoriHandler()->ApplyNigoriUpdate(
    507         *local_nigori,
    508         &trans);
    509   }
    510 
    511   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
    512   EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
    513   ApplyControlDataUpdates(session());
    514   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
    515   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
    516 
    517   EXPECT_TRUE(cryptographer->is_ready());
    518   EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
    519           entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    520               nigori().encryption_keybag()));
    521   EXPECT_FALSE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    522       nigori().keybag_is_frozen());
    523   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    524       nigori().encrypt_everything());
    525   {
    526     syncable::ReadTransaction trans(FROM_HERE, directory());
    527     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
    528         .Equals(ModelTypeSet::All()));
    529   }
    530 }
    531 
    532 // If both nigoris are migrated, but we also set a custom passphrase locally,
    533 // the local nigori should be preserved.
    534 TEST_F(ApplyControlDataUpdatesTest,
    535        NigoriConflictBothMigratedLocalCustom) {
    536   Cryptographer* cryptographer;
    537   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
    538   KeyParams old_params = {"localhost", "dummy", "old"};
    539   KeyParams new_params = {"localhost", "dummy", "new"};
    540   {
    541     syncable::ReadTransaction trans(FROM_HERE, directory());
    542     cryptographer = directory()->GetCryptographer(&trans);
    543     EXPECT_TRUE(encrypted_types.Equals(
    544             directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
    545   }
    546 
    547   // Set up the cryptographer with new keys
    548   Cryptographer other_cryptographer(cryptographer->encryptor());
    549   other_cryptographer.AddKey(old_params);
    550 
    551   // Create server specifics with a migrated keystore passphrase type.
    552   sync_pb::EntitySpecifics server_specifics;
    553   sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
    554   other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
    555   server_nigori->set_encrypt_everything(false);
    556   server_nigori->set_keybag_is_frozen(true);
    557   server_nigori->set_passphrase_type(
    558       sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
    559   server_nigori->mutable_keystore_decryptor_token();
    560   int64 nigori_handle =
    561       entry_factory_->CreateUnappliedNewItem(kNigoriTag,
    562                                              server_specifics,
    563                                              true);
    564 
    565   // Add the new keys to the cryptographer.
    566   cryptographer->AddKey(old_params);
    567   cryptographer->AddKey(new_params);
    568   EXPECT_TRUE(cryptographer->is_ready());
    569 
    570   // Set up a local nigori with a migrated custom passphrase type
    571   sync_pb::EntitySpecifics local_specifics;
    572   sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
    573   cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
    574   local_nigori->set_encrypt_everything(true);
    575   local_nigori->set_keybag_is_frozen(true);
    576   local_nigori->set_passphrase_type(
    577       sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
    578   ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
    579           nigori_handle, local_specifics));
    580   // Apply the update locally so that UpdateFromEncryptedTypes knows what state
    581   // to use.
    582   {
    583     syncable::ReadTransaction trans(FROM_HERE, directory());
    584     cryptographer = directory()->GetCryptographer(&trans);
    585     directory()->GetNigoriHandler()->ApplyNigoriUpdate(
    586         *local_nigori,
    587         &trans);
    588   }
    589 
    590   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
    591   EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
    592   ApplyControlDataUpdates(session());
    593   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
    594   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
    595 
    596   EXPECT_TRUE(cryptographer->is_ready());
    597   EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
    598           entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    599               nigori().encryption_keybag()));
    600   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    601       nigori().keybag_is_frozen());
    602   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    603       nigori().encrypt_everything());
    604   EXPECT_EQ(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE,
    605             entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    606                 nigori().passphrase_type());
    607   {
    608     syncable::ReadTransaction trans(FROM_HERE, directory());
    609     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
    610         .Equals(ModelTypeSet::All()));
    611   }
    612 }
    613 
    614 // If both nigoris are migrated, but a custom passphrase with a new key was
    615 // set remotely, the remote nigori should be preserved.
    616 TEST_F(ApplyControlDataUpdatesTest,
    617        NigoriConflictBothMigratedServerCustom) {
    618   Cryptographer* cryptographer;
    619   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
    620   KeyParams old_params = {"localhost", "dummy", "old"};
    621   KeyParams new_params = {"localhost", "dummy", "new"};
    622   {
    623     syncable::ReadTransaction trans(FROM_HERE, directory());
    624     cryptographer = directory()->GetCryptographer(&trans);
    625     EXPECT_TRUE(encrypted_types.Equals(
    626             directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
    627   }
    628 
    629   // Set up the cryptographer with both new keys and old keys.
    630   Cryptographer other_cryptographer(cryptographer->encryptor());
    631   other_cryptographer.AddKey(old_params);
    632   other_cryptographer.AddKey(new_params);
    633 
    634   // Create server specifics with a migrated custom passphrase type.
    635   sync_pb::EntitySpecifics server_specifics;
    636   sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
    637   other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
    638   server_nigori->set_encrypt_everything(true);
    639   server_nigori->set_keybag_is_frozen(true);
    640   server_nigori->set_passphrase_type(
    641       sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
    642   int64 nigori_handle =
    643       entry_factory_->CreateUnappliedNewItem(kNigoriTag,
    644                                              server_specifics,
    645                                              true);
    646 
    647   // Add the old keys to the cryptographer.
    648   cryptographer->AddKey(old_params);
    649   EXPECT_TRUE(cryptographer->is_ready());
    650 
    651   // Set up a local nigori with a migrated keystore passphrase type
    652   sync_pb::EntitySpecifics local_specifics;
    653   sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
    654   cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
    655   local_nigori->set_encrypt_everything(false);
    656   local_nigori->set_keybag_is_frozen(true);
    657   local_nigori->set_passphrase_type(
    658       sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
    659   server_nigori->mutable_keystore_decryptor_token();
    660   ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
    661           nigori_handle, local_specifics));
    662   // Apply the update locally so that UpdateFromEncryptedTypes knows what state
    663   // to use.
    664   {
    665     syncable::ReadTransaction trans(FROM_HERE, directory());
    666     cryptographer = directory()->GetCryptographer(&trans);
    667     directory()->GetNigoriHandler()->ApplyNigoriUpdate(
    668         *local_nigori,
    669         &trans);
    670   }
    671 
    672   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
    673   EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
    674   ApplyControlDataUpdates(session());
    675   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
    676   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
    677 
    678   EXPECT_TRUE(cryptographer->is_initialized());
    679   EXPECT_TRUE(cryptographer->has_pending_keys());
    680   EXPECT_TRUE(other_cryptographer.CanDecryptUsingDefaultKey(
    681           entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    682               nigori().encryption_keybag()));
    683   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    684       nigori().keybag_is_frozen());
    685   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    686       nigori().encrypt_everything());
    687   EXPECT_EQ(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE,
    688             entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    689                 nigori().passphrase_type());
    690   {
    691     syncable::ReadTransaction trans(FROM_HERE, directory());
    692     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
    693         .Equals(ModelTypeSet::All()));
    694   }
    695 }
    696 
    697 // If the local nigori is migrated but the server is not, preserve the local
    698 // nigori.
    699 TEST_F(ApplyControlDataUpdatesTest,
    700        NigoriConflictLocalMigrated) {
    701   Cryptographer* cryptographer;
    702   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
    703   KeyParams old_params = {"localhost", "dummy", "old"};
    704   KeyParams new_params = {"localhost", "dummy", "new"};
    705   {
    706     syncable::ReadTransaction trans(FROM_HERE, directory());
    707     cryptographer = directory()->GetCryptographer(&trans);
    708     EXPECT_TRUE(encrypted_types.Equals(
    709             directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
    710   }
    711 
    712   // Set up the cryptographer with both new keys and old keys.
    713   Cryptographer other_cryptographer(cryptographer->encryptor());
    714   other_cryptographer.AddKey(old_params);
    715 
    716   // Create server specifics with an unmigrated implicit passphrase type.
    717   sync_pb::EntitySpecifics server_specifics;
    718   sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
    719   other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
    720   server_nigori->set_encrypt_everything(true);
    721   server_nigori->set_keybag_is_frozen(false);
    722   int64 nigori_handle =
    723       entry_factory_->CreateUnappliedNewItem(kNigoriTag,
    724                                              server_specifics,
    725                                              true);
    726 
    727   // Add the old keys to the cryptographer.
    728   cryptographer->AddKey(old_params);
    729   cryptographer->AddKey(new_params);
    730   EXPECT_TRUE(cryptographer->is_ready());
    731 
    732   // Set up a local nigori with a migrated custom passphrase type
    733   sync_pb::EntitySpecifics local_specifics;
    734   sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
    735   cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
    736   local_nigori->set_encrypt_everything(true);
    737   local_nigori->set_keybag_is_frozen(true);
    738   local_nigori->set_passphrase_type(
    739       sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
    740   ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
    741           nigori_handle, local_specifics));
    742   // Apply the update locally so that UpdateFromEncryptedTypes knows what state
    743   // to use.
    744   {
    745     syncable::ReadTransaction trans(FROM_HERE, directory());
    746     cryptographer = directory()->GetCryptographer(&trans);
    747     directory()->GetNigoriHandler()->ApplyNigoriUpdate(
    748         *local_nigori,
    749         &trans);
    750   }
    751 
    752   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
    753   EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
    754   ApplyControlDataUpdates(session());
    755   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
    756   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
    757 
    758   EXPECT_TRUE(cryptographer->is_ready());
    759   EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
    760           entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    761               nigori().encryption_keybag()));
    762   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    763       nigori().keybag_is_frozen());
    764   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    765       nigori().encrypt_everything());
    766   EXPECT_EQ(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE,
    767             entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    768                 nigori().passphrase_type());
    769   {
    770     syncable::ReadTransaction trans(FROM_HERE, directory());
    771     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
    772         .Equals(ModelTypeSet::All()));
    773   }
    774 }
    775 
    776 // If the server nigori is migrated but the local is not, preserve the server
    777 // nigori.
    778 TEST_F(ApplyControlDataUpdatesTest,
    779        NigoriConflictServerMigrated) {
    780   Cryptographer* cryptographer;
    781   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
    782   KeyParams old_params = {"localhost", "dummy", "old"};
    783   KeyParams new_params = {"localhost", "dummy", "new"};
    784   {
    785     syncable::ReadTransaction trans(FROM_HERE, directory());
    786     cryptographer = directory()->GetCryptographer(&trans);
    787     EXPECT_TRUE(encrypted_types.Equals(
    788             directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
    789   }
    790 
    791   // Set up the cryptographer with both new keys and old keys.
    792   Cryptographer other_cryptographer(cryptographer->encryptor());
    793   other_cryptographer.AddKey(old_params);
    794 
    795   // Create server specifics with an migrated keystore passphrase type.
    796   sync_pb::EntitySpecifics server_specifics;
    797   sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
    798   other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
    799   server_nigori->set_encrypt_everything(false);
    800   server_nigori->set_keybag_is_frozen(true);
    801   server_nigori->set_passphrase_type(
    802       sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
    803   server_nigori->mutable_keystore_decryptor_token();
    804   int64 nigori_handle =
    805       entry_factory_->CreateUnappliedNewItem(kNigoriTag,
    806                                              server_specifics,
    807                                              true);
    808 
    809   // Add the old keys to the cryptographer.
    810   cryptographer->AddKey(old_params);
    811   cryptographer->AddKey(new_params);
    812   EXPECT_TRUE(cryptographer->is_ready());
    813 
    814   // Set up a local nigori with a migrated custom passphrase type
    815   sync_pb::EntitySpecifics local_specifics;
    816   sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
    817   cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
    818   local_nigori->set_encrypt_everything(false);
    819   local_nigori->set_keybag_is_frozen(false);
    820   ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
    821           nigori_handle, local_specifics));
    822   // Apply the update locally so that UpdateFromEncryptedTypes knows what state
    823   // to use.
    824   {
    825     syncable::ReadTransaction trans(FROM_HERE, directory());
    826     cryptographer = directory()->GetCryptographer(&trans);
    827     directory()->GetNigoriHandler()->ApplyNigoriUpdate(
    828         *local_nigori,
    829         &trans);
    830   }
    831 
    832   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
    833   EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
    834   ApplyControlDataUpdates(session());
    835   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
    836   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
    837 
    838   EXPECT_TRUE(cryptographer->is_ready());
    839   // Note: we didn't overwrite the encryption keybag with the local keys. The
    840   // sync encryption handler will do that when it detects that the new
    841   // keybag is out of date (and update the keystore bootstrap if necessary).
    842   EXPECT_FALSE(cryptographer->CanDecryptUsingDefaultKey(
    843           entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    844               nigori().encryption_keybag()));
    845   EXPECT_TRUE(cryptographer->CanDecrypt(
    846           entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    847               nigori().encryption_keybag()));
    848   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    849       nigori().keybag_is_frozen());
    850   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    851       nigori().has_keystore_decryptor_token());
    852   EXPECT_EQ(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE,
    853             entry_factory_->GetLocalSpecificsForItem(nigori_handle).
    854                 nigori().passphrase_type());
    855   {
    856     syncable::ReadTransaction trans(FROM_HERE, directory());
    857   }
    858 }
    859 
    860 // Check that we can apply a simple control datatype node successfully.
    861 TEST_F(ApplyControlDataUpdatesTest, ControlApply) {
    862   std::string experiment_id = "experiment";
    863   sync_pb::EntitySpecifics specifics;
    864   specifics.mutable_experiments()->mutable_keystore_encryption()->
    865       set_enabled(true);
    866   int64 experiment_handle = entry_factory_->CreateUnappliedNewItem(
    867       experiment_id, specifics, false);
    868   ApplyControlDataUpdates(session());
    869 
    870   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(experiment_handle));
    871   EXPECT_TRUE(
    872       entry_factory_->GetLocalSpecificsForItem(experiment_handle).
    873           experiments().keystore_encryption().enabled());
    874 }
    875 
    876 // Verify that we apply top level folders before their children.
    877 TEST_F(ApplyControlDataUpdatesTest, ControlApplyParentBeforeChild) {
    878   std::string parent_id = "parent";
    879   std::string experiment_id = "experiment";
    880   sync_pb::EntitySpecifics specifics;
    881   specifics.mutable_experiments()->mutable_keystore_encryption()->
    882       set_enabled(true);
    883   int64 experiment_handle = entry_factory_->CreateUnappliedNewItemWithParent(
    884       experiment_id, specifics, parent_id);
    885   int64 parent_handle = entry_factory_->CreateUnappliedNewItem(
    886       parent_id, specifics, true);
    887   ApplyControlDataUpdates(session());
    888 
    889   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(parent_handle));
    890   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(experiment_handle));
    891   EXPECT_TRUE(
    892       entry_factory_->GetLocalSpecificsForItem(experiment_handle).
    893           experiments().keystore_encryption().enabled());
    894 }
    895 
    896 // Verify that we handle control datatype conflicts by preserving the server
    897 // data.
    898 TEST_F(ApplyControlDataUpdatesTest, ControlConflict) {
    899   std::string experiment_id = "experiment";
    900   sync_pb::EntitySpecifics local_specifics, server_specifics;
    901   server_specifics.mutable_experiments()->mutable_keystore_encryption()->
    902       set_enabled(true);
    903   local_specifics.mutable_experiments()->mutable_keystore_encryption()->
    904       set_enabled(false);
    905   int64 experiment_handle = entry_factory_->CreateSyncedItem(
    906       experiment_id, EXPERIMENTS, false);
    907   entry_factory_->SetServerSpecificsForItem(experiment_handle,
    908                                             server_specifics);
    909   entry_factory_->SetLocalSpecificsForItem(experiment_handle,
    910                                            local_specifics);
    911   ApplyControlDataUpdates(session());
    912 
    913   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(experiment_handle));
    914   EXPECT_TRUE(
    915       entry_factory_->GetLocalSpecificsForItem(experiment_handle).
    916           experiments().keystore_encryption().enabled());
    917 }
    918 
    919 }  // namespace syncer
    920