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/message_loop/message_loop.h"
      9 #include "base/strings/stringprintf.h"
     10 #include "sync/engine/apply_control_data_updates.h"
     11 #include "sync/engine/syncer.h"
     12 #include "sync/engine/syncer_util.h"
     13 #include "sync/internal_api/public/test/test_entry_factory.h"
     14 #include "sync/protocol/nigori_specifics.pb.h"
     15 #include "sync/syncable/directory.h"
     16 #include "sync/syncable/mutable_entry.h"
     17 #include "sync/syncable/nigori_util.h"
     18 #include "sync/syncable/syncable_read_transaction.h"
     19 #include "sync/syncable/syncable_util.h"
     20 #include "sync/syncable/syncable_write_transaction.h"
     21 #include "sync/test/engine/fake_model_worker.h"
     22 #include "sync/test/engine/test_directory_setter_upper.h"
     23 #include "sync/test/engine/test_id_factory.h"
     24 #include "sync/test/fake_sync_encryption_handler.h"
     25 #include "sync/util/cryptographer.h"
     26 #include "testing/gtest/include/gtest/gtest.h"
     27 
     28 namespace syncer {
     29 
     30 using syncable::MutableEntry;
     31 using syncable::UNITTEST;
     32 using syncable::Id;
     33 
     34 class ApplyControlDataUpdatesTest : public ::testing::Test {
     35  public:
     36  protected:
     37   ApplyControlDataUpdatesTest() {}
     38   virtual ~ApplyControlDataUpdatesTest() {}
     39 
     40   virtual void SetUp() {
     41     dir_maker_.SetUp();
     42     entry_factory_.reset(new TestEntryFactory(directory()));
     43   }
     44 
     45   virtual void TearDown() {
     46     dir_maker_.TearDown();
     47   }
     48 
     49   syncable::Directory* directory() {
     50     return dir_maker_.directory();
     51   }
     52 
     53   TestIdFactory id_factory_;
     54   scoped_ptr<TestEntryFactory> entry_factory_;
     55  private:
     56   base::MessageLoop loop_;  // Needed for directory init.
     57   TestDirectorySetterUpper dir_maker_;
     58 
     59   DISALLOW_COPY_AND_ASSIGN(ApplyControlDataUpdatesTest);
     60 };
     61 
     62 // Verify that applying a nigori node sets initial sync ended properly,
     63 // updates the set of encrypted types, and updates the cryptographer.
     64 TEST_F(ApplyControlDataUpdatesTest, NigoriUpdate) {
     65   // Storing the cryptographer separately is bad, but for this test we
     66   // know it's safe.
     67   Cryptographer* cryptographer;
     68   ModelTypeSet encrypted_types;
     69   encrypted_types.PutAll(SyncEncryptionHandler::SensitiveTypes());
     70 
     71   {
     72     syncable::ReadTransaction trans(FROM_HERE, directory());
     73     cryptographer = directory()->GetCryptographer(&trans);
     74     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
     75         .Equals(encrypted_types));
     76   }
     77 
     78   // Nigori node updates should update the Cryptographer.
     79   Cryptographer other_cryptographer(cryptographer->encryptor());
     80   KeyParams params = {"localhost", "dummy", "foobar"};
     81   other_cryptographer.AddKey(params);
     82 
     83   sync_pb::EntitySpecifics specifics;
     84   sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
     85   other_cryptographer.GetKeys(nigori->mutable_encryption_keybag());
     86   nigori->set_encrypt_everything(true);
     87   entry_factory_->CreateUnappliedNewItem(
     88       ModelTypeToRootTag(NIGORI), specifics, true);
     89   EXPECT_FALSE(cryptographer->has_pending_keys());
     90 
     91   ApplyControlDataUpdates(directory());
     92 
     93   EXPECT_FALSE(cryptographer->is_ready());
     94   EXPECT_TRUE(cryptographer->has_pending_keys());
     95   {
     96     syncable::ReadTransaction trans(FROM_HERE, directory());
     97     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
     98         .Equals(ModelTypeSet::All()));
     99   }
    100 }
    101 
    102 // Create some local unsynced and unencrypted data. Apply a nigori update that
    103 // turns on encryption for the unsynced data. Ensure we properly encrypt the
    104 // data as part of the nigori update. Apply another nigori update with no
    105 // changes. Ensure we ignore already-encrypted unsynced data and that nothing
    106 // breaks.
    107 TEST_F(ApplyControlDataUpdatesTest, EncryptUnsyncedChanges) {
    108   // Storing the cryptographer separately is bad, but for this test we
    109   // know it's safe.
    110   Cryptographer* cryptographer;
    111   ModelTypeSet encrypted_types;
    112   encrypted_types.PutAll(SyncEncryptionHandler::SensitiveTypes());
    113   {
    114     syncable::ReadTransaction trans(FROM_HERE, directory());
    115     cryptographer = directory()->GetCryptographer(&trans);
    116     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
    117         .Equals(encrypted_types));
    118 
    119     // With default encrypted_types, this should be true.
    120     EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
    121 
    122     Syncer::UnsyncedMetaHandles handles;
    123     GetUnsyncedEntries(&trans, &handles);
    124     EXPECT_TRUE(handles.empty());
    125   }
    126 
    127   // Create unsynced bookmarks without encryption.
    128   // First item is a folder
    129   Id folder_id = id_factory_.NewLocalId();
    130   entry_factory_->CreateUnsyncedItem(folder_id, id_factory_.root(), "folder",
    131                                      true, BOOKMARKS, NULL);
    132   // Next five items are children of the folder
    133   size_t i;
    134   size_t batch_s = 5;
    135   for (i = 0; i < batch_s; ++i) {
    136     entry_factory_->CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id,
    137                                        base::StringPrintf("Item %" PRIuS "", i),
    138                                        false, BOOKMARKS, NULL);
    139   }
    140   // Next five items are children of the root.
    141   for (; i < 2*batch_s; ++i) {
    142     entry_factory_->CreateUnsyncedItem(
    143         id_factory_.NewLocalId(), id_factory_.root(),
    144         base::StringPrintf("Item %" PRIuS "", i), false,
    145         BOOKMARKS, NULL);
    146   }
    147 
    148   KeyParams params = {"localhost", "dummy", "foobar"};
    149   cryptographer->AddKey(params);
    150   sync_pb::EntitySpecifics specifics;
    151   sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
    152   cryptographer->GetKeys(nigori->mutable_encryption_keybag());
    153   nigori->set_encrypt_everything(true);
    154   encrypted_types.Put(BOOKMARKS);
    155   entry_factory_->CreateUnappliedNewItem(
    156       ModelTypeToRootTag(NIGORI), specifics, true);
    157   EXPECT_FALSE(cryptographer->has_pending_keys());
    158   EXPECT_TRUE(cryptographer->is_ready());
    159 
    160   {
    161     // Ensure we have unsynced nodes that aren't properly encrypted.
    162     syncable::ReadTransaction trans(FROM_HERE, directory());
    163     EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
    164 
    165     Syncer::UnsyncedMetaHandles handles;
    166     GetUnsyncedEntries(&trans, &handles);
    167     EXPECT_EQ(2*batch_s+1, handles.size());
    168   }
    169 
    170   ApplyControlDataUpdates(directory());
    171 
    172   EXPECT_FALSE(cryptographer->has_pending_keys());
    173   EXPECT_TRUE(cryptographer->is_ready());
    174   {
    175     syncable::ReadTransaction trans(FROM_HERE, directory());
    176 
    177     // If ProcessUnsyncedChangesForEncryption worked, all our unsynced changes
    178     // should be encrypted now.
    179     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
    180         .Equals(ModelTypeSet::All()));
    181     EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
    182 
    183     Syncer::UnsyncedMetaHandles handles;
    184     GetUnsyncedEntries(&trans, &handles);
    185     EXPECT_EQ(2*batch_s+1, handles.size());
    186   }
    187 
    188   // Simulate another nigori update that doesn't change anything.
    189   {
    190     syncable::WriteTransaction trans(FROM_HERE, UNITTEST, directory());
    191     MutableEntry entry(&trans, syncable::GET_TYPE_ROOT, NIGORI);
    192     ASSERT_TRUE(entry.good());
    193     entry.PutServerVersion(entry_factory_->GetNextRevision());
    194     entry.PutIsUnappliedUpdate(true);
    195   }
    196 
    197   ApplyControlDataUpdates(directory());
    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(directory());
    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(directory());
    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(directory());
    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(directory());
    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(directory());
    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(directory());
    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(directory());
    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(directory());
    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(directory());
    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(directory());
    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(directory());
    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