• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
ApplyControlDataUpdatesTest()37   ApplyControlDataUpdatesTest() {}
~ApplyControlDataUpdatesTest()38   virtual ~ApplyControlDataUpdatesTest() {}
39 
SetUp()40   virtual void SetUp() {
41     dir_maker_.SetUp();
42     entry_factory_.reset(new TestEntryFactory(directory()));
43   }
44 
TearDown()45   virtual void TearDown() {
46     dir_maker_.TearDown();
47   }
48 
directory()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.
TEST_F(ApplyControlDataUpdatesTest,NigoriUpdate)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.
TEST_F(ApplyControlDataUpdatesTest,EncryptUnsyncedChanges)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.
TEST_F(ApplyControlDataUpdatesTest,CannotEncryptUnsyncedChanges)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.
TEST_F(ApplyControlDataUpdatesTest,NigoriConflictPendingKeysServerEncryptEverythingCustom)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.
TEST_F(ApplyControlDataUpdatesTest,NigoriConflictPendingKeysLocalEncryptEverythingCustom)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.
TEST_F(ApplyControlDataUpdatesTest,NigoriConflictOldKeys)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.
TEST_F(ApplyControlDataUpdatesTest,NigoriConflictBothMigratedLocalCustom)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.
TEST_F(ApplyControlDataUpdatesTest,NigoriConflictBothMigratedServerCustom)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.
TEST_F(ApplyControlDataUpdatesTest,NigoriConflictLocalMigrated)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.
TEST_F(ApplyControlDataUpdatesTest,NigoriConflictServerMigrated)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.
TEST_F(ApplyControlDataUpdatesTest,ControlApply)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.
TEST_F(ApplyControlDataUpdatesTest,ControlApplyParentBeforeChild)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.
TEST_F(ApplyControlDataUpdatesTest,ControlConflict)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