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.
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"
30 using syncable::MutableEntry
;
31 using syncable::UNITTEST
;
34 class ApplyControlDataUpdatesTest
: public ::testing::Test
{
37 ApplyControlDataUpdatesTest() {}
38 ~ApplyControlDataUpdatesTest() override
{}
40 void SetUp() override
{
42 entry_factory_
.reset(new TestEntryFactory(directory()));
45 void TearDown() override
{ dir_maker_
.TearDown(); }
47 syncable::Directory
* directory() {
48 return dir_maker_
.directory();
51 TestIdFactory id_factory_
;
52 scoped_ptr
<TestEntryFactory
> entry_factory_
;
54 base::MessageLoop loop_
; // Needed for directory init.
55 TestDirectorySetterUpper dir_maker_
;
57 DISALLOW_COPY_AND_ASSIGN(ApplyControlDataUpdatesTest
);
60 // Verify that applying a nigori node sets initial sync ended properly,
61 // updates the set of encrypted types, and updates the cryptographer.
62 TEST_F(ApplyControlDataUpdatesTest
, NigoriUpdate
) {
63 // Storing the cryptographer separately is bad, but for this test we
65 Cryptographer
* cryptographer
;
66 ModelTypeSet encrypted_types
;
67 encrypted_types
.PutAll(SyncEncryptionHandler::SensitiveTypes());
70 syncable::ReadTransaction
trans(FROM_HERE
, directory());
71 cryptographer
= directory()->GetCryptographer(&trans
);
72 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
73 .Equals(encrypted_types
));
76 // Nigori node updates should update the Cryptographer.
77 Cryptographer
other_cryptographer(cryptographer
->encryptor());
78 KeyParams params
= {"localhost", "dummy", "foobar"};
79 other_cryptographer
.AddKey(params
);
81 sync_pb::EntitySpecifics specifics
;
82 sync_pb::NigoriSpecifics
* nigori
= specifics
.mutable_nigori();
83 other_cryptographer
.GetKeys(nigori
->mutable_encryption_keybag());
84 nigori
->set_encrypt_everything(true);
85 entry_factory_
->CreateUnappliedNewItem(
86 ModelTypeToRootTag(NIGORI
), specifics
, true);
87 EXPECT_FALSE(cryptographer
->has_pending_keys());
89 ApplyControlDataUpdates(directory());
91 EXPECT_FALSE(cryptographer
->is_ready());
92 EXPECT_TRUE(cryptographer
->has_pending_keys());
94 syncable::ReadTransaction
trans(FROM_HERE
, directory());
95 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
96 .Equals(ModelTypeSet::All()));
100 // Create some local unsynced and unencrypted data. Apply a nigori update that
101 // turns on encryption for the unsynced data. Ensure we properly encrypt the
102 // data as part of the nigori update. Apply another nigori update with no
103 // changes. Ensure we ignore already-encrypted unsynced data and that nothing
105 TEST_F(ApplyControlDataUpdatesTest
, EncryptUnsyncedChanges
) {
106 // Storing the cryptographer separately is bad, but for this test we
108 Cryptographer
* cryptographer
;
109 ModelTypeSet encrypted_types
;
110 encrypted_types
.PutAll(SyncEncryptionHandler::SensitiveTypes());
112 syncable::ReadTransaction
trans(FROM_HERE
, directory());
113 cryptographer
= directory()->GetCryptographer(&trans
);
114 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
115 .Equals(encrypted_types
));
117 // With default encrypted_types, this should be true.
118 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans
, encrypted_types
));
120 Syncer::UnsyncedMetaHandles handles
;
121 GetUnsyncedEntries(&trans
, &handles
);
122 EXPECT_TRUE(handles
.empty());
125 // Create unsynced bookmarks without encryption.
126 // First item is a folder
127 Id folder_id
= id_factory_
.NewLocalId();
128 entry_factory_
->CreateUnsyncedItem(folder_id
, id_factory_
.root(), "folder",
129 true, BOOKMARKS
, NULL
);
130 // Next five items are children of the folder
133 for (i
= 0; i
< batch_s
; ++i
) {
134 entry_factory_
->CreateUnsyncedItem(id_factory_
.NewLocalId(), folder_id
,
135 base::StringPrintf("Item %" PRIuS
"", i
),
136 false, BOOKMARKS
, NULL
);
138 // Next five items are children of the root.
139 for (; i
< 2*batch_s
; ++i
) {
140 entry_factory_
->CreateUnsyncedItem(
141 id_factory_
.NewLocalId(), id_factory_
.root(),
142 base::StringPrintf("Item %" PRIuS
"", i
), false,
146 KeyParams params
= {"localhost", "dummy", "foobar"};
147 cryptographer
->AddKey(params
);
148 sync_pb::EntitySpecifics specifics
;
149 sync_pb::NigoriSpecifics
* nigori
= specifics
.mutable_nigori();
150 cryptographer
->GetKeys(nigori
->mutable_encryption_keybag());
151 nigori
->set_encrypt_everything(true);
152 encrypted_types
.Put(BOOKMARKS
);
153 entry_factory_
->CreateUnappliedNewItem(
154 ModelTypeToRootTag(NIGORI
), specifics
, true);
155 EXPECT_FALSE(cryptographer
->has_pending_keys());
156 EXPECT_TRUE(cryptographer
->is_ready());
159 // Ensure we have unsynced nodes that aren't properly encrypted.
160 syncable::ReadTransaction
trans(FROM_HERE
, directory());
161 EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans
, encrypted_types
));
163 Syncer::UnsyncedMetaHandles handles
;
164 GetUnsyncedEntries(&trans
, &handles
);
165 EXPECT_EQ(2*batch_s
+1, handles
.size());
168 ApplyControlDataUpdates(directory());
170 EXPECT_FALSE(cryptographer
->has_pending_keys());
171 EXPECT_TRUE(cryptographer
->is_ready());
173 syncable::ReadTransaction
trans(FROM_HERE
, directory());
175 // If ProcessUnsyncedChangesForEncryption worked, all our unsynced changes
176 // should be encrypted now.
177 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
178 .Equals(ModelTypeSet::All()));
179 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans
, encrypted_types
));
181 Syncer::UnsyncedMetaHandles handles
;
182 GetUnsyncedEntries(&trans
, &handles
);
183 EXPECT_EQ(2*batch_s
+1, handles
.size());
186 // Simulate another nigori update that doesn't change anything.
188 syncable::WriteTransaction
trans(FROM_HERE
, UNITTEST
, directory());
189 MutableEntry
entry(&trans
, syncable::GET_TYPE_ROOT
, NIGORI
);
190 ASSERT_TRUE(entry
.good());
191 entry
.PutServerVersion(entry_factory_
->GetNextRevision());
192 entry
.PutIsUnappliedUpdate(true);
195 ApplyControlDataUpdates(directory());
197 EXPECT_FALSE(cryptographer
->has_pending_keys());
198 EXPECT_TRUE(cryptographer
->is_ready());
200 syncable::ReadTransaction
trans(FROM_HERE
, directory());
202 // All our changes should still be encrypted.
203 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
204 .Equals(ModelTypeSet::All()));
205 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans
, encrypted_types
));
207 Syncer::UnsyncedMetaHandles handles
;
208 GetUnsyncedEntries(&trans
, &handles
);
209 EXPECT_EQ(2*batch_s
+1, handles
.size());
213 // Create some local unsynced and unencrypted changes. Receive a new nigori
214 // node enabling their encryption but also introducing pending keys. Ensure
215 // we apply the update properly without encrypting the unsynced changes or
217 TEST_F(ApplyControlDataUpdatesTest
, CannotEncryptUnsyncedChanges
) {
218 // Storing the cryptographer separately is bad, but for this test we
220 Cryptographer
* cryptographer
;
221 ModelTypeSet encrypted_types
;
222 encrypted_types
.PutAll(SyncEncryptionHandler::SensitiveTypes());
224 syncable::ReadTransaction
trans(FROM_HERE
, directory());
225 cryptographer
= directory()->GetCryptographer(&trans
);
226 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
227 .Equals(encrypted_types
));
229 // With default encrypted_types, this should be true.
230 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans
, encrypted_types
));
232 Syncer::UnsyncedMetaHandles handles
;
233 GetUnsyncedEntries(&trans
, &handles
);
234 EXPECT_TRUE(handles
.empty());
237 // Create unsynced bookmarks without encryption.
238 // First item is a folder
239 Id folder_id
= id_factory_
.NewLocalId();
240 entry_factory_
->CreateUnsyncedItem(
241 folder_id
, id_factory_
.root(), "folder", true,
243 // Next five items are children of the folder
246 for (i
= 0; i
< batch_s
; ++i
) {
247 entry_factory_
->CreateUnsyncedItem(id_factory_
.NewLocalId(), folder_id
,
248 base::StringPrintf("Item %" PRIuS
"", i
),
249 false, BOOKMARKS
, NULL
);
251 // Next five items are children of the root.
252 for (; i
< 2*batch_s
; ++i
) {
253 entry_factory_
->CreateUnsyncedItem(
254 id_factory_
.NewLocalId(), id_factory_
.root(),
255 base::StringPrintf("Item %" PRIuS
"", i
), false,
259 // We encrypt with new keys, triggering the local cryptographer to be unready
260 // and unable to decrypt data (once updated).
261 Cryptographer
other_cryptographer(cryptographer
->encryptor());
262 KeyParams params
= {"localhost", "dummy", "foobar"};
263 other_cryptographer
.AddKey(params
);
264 sync_pb::EntitySpecifics specifics
;
265 sync_pb::NigoriSpecifics
* nigori
= specifics
.mutable_nigori();
266 other_cryptographer
.GetKeys(nigori
->mutable_encryption_keybag());
267 nigori
->set_encrypt_everything(true);
268 encrypted_types
.Put(BOOKMARKS
);
269 entry_factory_
->CreateUnappliedNewItem(
270 ModelTypeToRootTag(NIGORI
), specifics
, true);
271 EXPECT_FALSE(cryptographer
->has_pending_keys());
274 // Ensure we have unsynced nodes that aren't properly encrypted.
275 syncable::ReadTransaction
trans(FROM_HERE
, directory());
276 EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans
, encrypted_types
));
277 Syncer::UnsyncedMetaHandles handles
;
278 GetUnsyncedEntries(&trans
, &handles
);
279 EXPECT_EQ(2*batch_s
+1, handles
.size());
282 ApplyControlDataUpdates(directory());
284 EXPECT_FALSE(cryptographer
->is_ready());
285 EXPECT_TRUE(cryptographer
->has_pending_keys());
287 syncable::ReadTransaction
trans(FROM_HERE
, directory());
289 // Since we have pending keys, we would have failed to encrypt, but the
290 // cryptographer should be updated.
291 EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans
, encrypted_types
));
292 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
293 .Equals(ModelTypeSet::All()));
294 EXPECT_FALSE(cryptographer
->is_ready());
295 EXPECT_TRUE(cryptographer
->has_pending_keys());
297 Syncer::UnsyncedMetaHandles handles
;
298 GetUnsyncedEntries(&trans
, &handles
);
299 EXPECT_EQ(2*batch_s
+1, handles
.size());
303 // Verify we handle a nigori node conflict by merging encryption keys and
304 // types, but preserve the custom passphrase state of the server.
305 // Initial sync ended should be set.
306 TEST_F(ApplyControlDataUpdatesTest
,
307 NigoriConflictPendingKeysServerEncryptEverythingCustom
) {
308 Cryptographer
* cryptographer
;
309 ModelTypeSet
encrypted_types(SyncEncryptionHandler::SensitiveTypes());
310 KeyParams other_params
= {"localhost", "dummy", "foobar"};
311 KeyParams local_params
= {"localhost", "dummy", "local"};
313 syncable::ReadTransaction
trans(FROM_HERE
, directory());
314 cryptographer
= directory()->GetCryptographer(&trans
);
315 EXPECT_TRUE(encrypted_types
.Equals(
316 directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)));
319 // Set up a temporary cryptographer to generate new keys with.
320 Cryptographer
other_cryptographer(cryptographer
->encryptor());
321 other_cryptographer
.AddKey(other_params
);
323 // Create server specifics with pending keys, new encrypted types,
324 // and a custom passphrase (unmigrated).
325 sync_pb::EntitySpecifics server_specifics
;
326 sync_pb::NigoriSpecifics
* server_nigori
= server_specifics
.mutable_nigori();
327 other_cryptographer
.GetKeys(server_nigori
->mutable_encryption_keybag());
328 server_nigori
->set_encrypt_everything(true);
329 server_nigori
->set_keybag_is_frozen(true);
330 int64 nigori_handle
=
331 entry_factory_
->CreateUnappliedNewItem(kNigoriTag
,
335 // Initialize the local cryptographer with the local keys.
336 cryptographer
->AddKey(local_params
);
337 EXPECT_TRUE(cryptographer
->is_ready());
339 // Set up a local nigori with the local encryption keys and default encrypted
341 sync_pb::EntitySpecifics local_specifics
;
342 sync_pb::NigoriSpecifics
* local_nigori
= local_specifics
.mutable_nigori();
343 cryptographer
->GetKeys(local_nigori
->mutable_encryption_keybag());
344 local_nigori
->set_encrypt_everything(false);
345 local_nigori
->set_keybag_is_frozen(true);
346 ASSERT_TRUE(entry_factory_
->SetLocalSpecificsForItem(
347 nigori_handle
, local_specifics
));
348 // Apply the update locally so that UpdateFromEncryptedTypes knows what state
351 syncable::ReadTransaction
trans(FROM_HERE
, directory());
352 cryptographer
= directory()->GetCryptographer(&trans
);
353 directory()->GetNigoriHandler()->ApplyNigoriUpdate(
358 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
359 EXPECT_TRUE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
360 ApplyControlDataUpdates(directory());
361 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
362 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
364 EXPECT_FALSE(cryptographer
->is_ready());
365 EXPECT_TRUE(cryptographer
->is_initialized());
366 EXPECT_TRUE(cryptographer
->has_pending_keys());
367 EXPECT_TRUE(other_cryptographer
.CanDecryptUsingDefaultKey(
368 entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
369 nigori().encryption_keybag()));
370 EXPECT_TRUE(entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
371 nigori().keybag_is_frozen());
372 EXPECT_TRUE(entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
373 nigori().encrypt_everything());
375 syncable::ReadTransaction
trans(FROM_HERE
, directory());
376 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
377 .Equals(ModelTypeSet::All()));
381 // Verify we handle a nigori node conflict by merging encryption keys and
382 // types, but preserve the custom passphrase state of the server.
383 // Initial sync ended should be set.
384 TEST_F(ApplyControlDataUpdatesTest
,
385 NigoriConflictPendingKeysLocalEncryptEverythingCustom
) {
386 Cryptographer
* cryptographer
;
387 ModelTypeSet
encrypted_types(SyncEncryptionHandler::SensitiveTypes());
388 KeyParams other_params
= {"localhost", "dummy", "foobar"};
389 KeyParams local_params
= {"localhost", "dummy", "local"};
391 syncable::ReadTransaction
trans(FROM_HERE
, directory());
392 cryptographer
= directory()->GetCryptographer(&trans
);
393 EXPECT_TRUE(encrypted_types
.Equals(
394 directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)));
397 // Set up a temporary cryptographer to generate new keys with.
398 Cryptographer
other_cryptographer(cryptographer
->encryptor());
399 other_cryptographer
.AddKey(other_params
);
401 // Create server specifics with pending keys, new encrypted types,
402 // and a custom passphrase (unmigrated).
403 sync_pb::EntitySpecifics server_specifics
;
404 sync_pb::NigoriSpecifics
* server_nigori
= server_specifics
.mutable_nigori();
405 other_cryptographer
.GetKeys(server_nigori
->mutable_encryption_keybag());
406 server_nigori
->set_encrypt_everything(false);
407 server_nigori
->set_keybag_is_frozen(false);
408 int64 nigori_handle
=
409 entry_factory_
->CreateUnappliedNewItem(kNigoriTag
,
413 // Initialize the local cryptographer with the local keys.
414 cryptographer
->AddKey(local_params
);
415 EXPECT_TRUE(cryptographer
->is_ready());
417 // Set up a local nigori with the local encryption keys and default encrypted
419 sync_pb::EntitySpecifics local_specifics
;
420 sync_pb::NigoriSpecifics
* local_nigori
= local_specifics
.mutable_nigori();
421 cryptographer
->GetKeys(local_nigori
->mutable_encryption_keybag());
422 local_nigori
->set_encrypt_everything(true);
423 local_nigori
->set_keybag_is_frozen(true);
424 ASSERT_TRUE(entry_factory_
->SetLocalSpecificsForItem(
425 nigori_handle
, local_specifics
));
426 // Apply the update locally so that UpdateFromEncryptedTypes knows what state
429 syncable::ReadTransaction
trans(FROM_HERE
, directory());
430 cryptographer
= directory()->GetCryptographer(&trans
);
431 directory()->GetNigoriHandler()->ApplyNigoriUpdate(
436 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
437 EXPECT_TRUE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
438 ApplyControlDataUpdates(directory());
439 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
440 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
442 EXPECT_FALSE(cryptographer
->is_ready());
443 EXPECT_TRUE(cryptographer
->is_initialized());
444 EXPECT_TRUE(cryptographer
->has_pending_keys());
445 EXPECT_TRUE(other_cryptographer
.CanDecryptUsingDefaultKey(
446 entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
447 nigori().encryption_keybag()));
448 EXPECT_FALSE(entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
449 nigori().keybag_is_frozen());
450 EXPECT_TRUE(entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
451 nigori().encrypt_everything());
453 syncable::ReadTransaction
trans(FROM_HERE
, directory());
454 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
455 .Equals(ModelTypeSet::All()));
459 // If the conflicting nigori has a subset of the local keys, the conflict
460 // resolution should preserve the full local keys. Initial sync ended should be
462 TEST_F(ApplyControlDataUpdatesTest
,
463 NigoriConflictOldKeys
) {
464 Cryptographer
* cryptographer
;
465 ModelTypeSet
encrypted_types(SyncEncryptionHandler::SensitiveTypes());
466 KeyParams old_params
= {"localhost", "dummy", "old"};
467 KeyParams new_params
= {"localhost", "dummy", "new"};
469 syncable::ReadTransaction
trans(FROM_HERE
, directory());
470 cryptographer
= directory()->GetCryptographer(&trans
);
471 EXPECT_TRUE(encrypted_types
.Equals(
472 directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)));
475 // Set up the cryptographer with old keys
476 cryptographer
->AddKey(old_params
);
478 // Create server specifics with old keys and new encrypted types.
479 sync_pb::EntitySpecifics server_specifics
;
480 sync_pb::NigoriSpecifics
* server_nigori
= server_specifics
.mutable_nigori();
481 cryptographer
->GetKeys(server_nigori
->mutable_encryption_keybag());
482 server_nigori
->set_encrypt_everything(true);
483 int64 nigori_handle
=
484 entry_factory_
->CreateUnappliedNewItem(kNigoriTag
,
488 // Add the new keys to the cryptogrpaher
489 cryptographer
->AddKey(new_params
);
490 EXPECT_TRUE(cryptographer
->is_ready());
492 // Set up a local nigori with the superset of keys.
493 sync_pb::EntitySpecifics local_specifics
;
494 sync_pb::NigoriSpecifics
* local_nigori
= local_specifics
.mutable_nigori();
495 cryptographer
->GetKeys(local_nigori
->mutable_encryption_keybag());
496 local_nigori
->set_encrypt_everything(false);
497 ASSERT_TRUE(entry_factory_
->SetLocalSpecificsForItem(
498 nigori_handle
, local_specifics
));
499 // Apply the update locally so that UpdateFromEncryptedTypes knows what state
502 syncable::ReadTransaction
trans(FROM_HERE
, directory());
503 cryptographer
= directory()->GetCryptographer(&trans
);
504 directory()->GetNigoriHandler()->ApplyNigoriUpdate(
509 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
510 EXPECT_TRUE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
511 ApplyControlDataUpdates(directory());
512 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
513 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
515 EXPECT_TRUE(cryptographer
->is_ready());
516 EXPECT_TRUE(cryptographer
->CanDecryptUsingDefaultKey(
517 entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
518 nigori().encryption_keybag()));
519 EXPECT_FALSE(entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
520 nigori().keybag_is_frozen());
521 EXPECT_TRUE(entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
522 nigori().encrypt_everything());
524 syncable::ReadTransaction
trans(FROM_HERE
, directory());
525 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
526 .Equals(ModelTypeSet::All()));
530 // If both nigoris are migrated, but we also set a custom passphrase locally,
531 // the local nigori should be preserved.
532 TEST_F(ApplyControlDataUpdatesTest
,
533 NigoriConflictBothMigratedLocalCustom
) {
534 Cryptographer
* cryptographer
;
535 ModelTypeSet
encrypted_types(SyncEncryptionHandler::SensitiveTypes());
536 KeyParams old_params
= {"localhost", "dummy", "old"};
537 KeyParams new_params
= {"localhost", "dummy", "new"};
539 syncable::ReadTransaction
trans(FROM_HERE
, directory());
540 cryptographer
= directory()->GetCryptographer(&trans
);
541 EXPECT_TRUE(encrypted_types
.Equals(
542 directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)));
545 // Set up the cryptographer with new keys
546 Cryptographer
other_cryptographer(cryptographer
->encryptor());
547 other_cryptographer
.AddKey(old_params
);
549 // Create server specifics with a migrated keystore passphrase type.
550 sync_pb::EntitySpecifics server_specifics
;
551 sync_pb::NigoriSpecifics
* server_nigori
= server_specifics
.mutable_nigori();
552 other_cryptographer
.GetKeys(server_nigori
->mutable_encryption_keybag());
553 server_nigori
->set_encrypt_everything(false);
554 server_nigori
->set_keybag_is_frozen(true);
555 server_nigori
->set_passphrase_type(
556 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE
);
557 server_nigori
->mutable_keystore_decryptor_token();
558 int64 nigori_handle
=
559 entry_factory_
->CreateUnappliedNewItem(kNigoriTag
,
563 // Add the new keys to the cryptographer.
564 cryptographer
->AddKey(old_params
);
565 cryptographer
->AddKey(new_params
);
566 EXPECT_TRUE(cryptographer
->is_ready());
568 // Set up a local nigori with a migrated custom passphrase type
569 sync_pb::EntitySpecifics local_specifics
;
570 sync_pb::NigoriSpecifics
* local_nigori
= local_specifics
.mutable_nigori();
571 cryptographer
->GetKeys(local_nigori
->mutable_encryption_keybag());
572 local_nigori
->set_encrypt_everything(true);
573 local_nigori
->set_keybag_is_frozen(true);
574 local_nigori
->set_passphrase_type(
575 sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE
);
576 ASSERT_TRUE(entry_factory_
->SetLocalSpecificsForItem(
577 nigori_handle
, local_specifics
));
578 // Apply the update locally so that UpdateFromEncryptedTypes knows what state
581 syncable::ReadTransaction
trans(FROM_HERE
, directory());
582 cryptographer
= directory()->GetCryptographer(&trans
);
583 directory()->GetNigoriHandler()->ApplyNigoriUpdate(
588 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
589 EXPECT_TRUE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
590 ApplyControlDataUpdates(directory());
591 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
592 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
594 EXPECT_TRUE(cryptographer
->is_ready());
595 EXPECT_TRUE(cryptographer
->CanDecryptUsingDefaultKey(
596 entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
597 nigori().encryption_keybag()));
598 EXPECT_TRUE(entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
599 nigori().keybag_is_frozen());
600 EXPECT_TRUE(entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
601 nigori().encrypt_everything());
602 EXPECT_EQ(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE
,
603 entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
604 nigori().passphrase_type());
606 syncable::ReadTransaction
trans(FROM_HERE
, directory());
607 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
608 .Equals(ModelTypeSet::All()));
612 // If both nigoris are migrated, but a custom passphrase with a new key was
613 // set remotely, the remote nigori should be preserved.
614 TEST_F(ApplyControlDataUpdatesTest
,
615 NigoriConflictBothMigratedServerCustom
) {
616 Cryptographer
* cryptographer
;
617 ModelTypeSet
encrypted_types(SyncEncryptionHandler::SensitiveTypes());
618 KeyParams old_params
= {"localhost", "dummy", "old"};
619 KeyParams new_params
= {"localhost", "dummy", "new"};
621 syncable::ReadTransaction
trans(FROM_HERE
, directory());
622 cryptographer
= directory()->GetCryptographer(&trans
);
623 EXPECT_TRUE(encrypted_types
.Equals(
624 directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)));
627 // Set up the cryptographer with both new keys and old keys.
628 Cryptographer
other_cryptographer(cryptographer
->encryptor());
629 other_cryptographer
.AddKey(old_params
);
630 other_cryptographer
.AddKey(new_params
);
632 // Create server specifics with a migrated custom passphrase type.
633 sync_pb::EntitySpecifics server_specifics
;
634 sync_pb::NigoriSpecifics
* server_nigori
= server_specifics
.mutable_nigori();
635 other_cryptographer
.GetKeys(server_nigori
->mutable_encryption_keybag());
636 server_nigori
->set_encrypt_everything(true);
637 server_nigori
->set_keybag_is_frozen(true);
638 server_nigori
->set_passphrase_type(
639 sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE
);
640 int64 nigori_handle
=
641 entry_factory_
->CreateUnappliedNewItem(kNigoriTag
,
645 // Add the old keys to the cryptographer.
646 cryptographer
->AddKey(old_params
);
647 EXPECT_TRUE(cryptographer
->is_ready());
649 // Set up a local nigori with a migrated keystore passphrase type
650 sync_pb::EntitySpecifics local_specifics
;
651 sync_pb::NigoriSpecifics
* local_nigori
= local_specifics
.mutable_nigori();
652 cryptographer
->GetKeys(local_nigori
->mutable_encryption_keybag());
653 local_nigori
->set_encrypt_everything(false);
654 local_nigori
->set_keybag_is_frozen(true);
655 local_nigori
->set_passphrase_type(
656 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE
);
657 server_nigori
->mutable_keystore_decryptor_token();
658 ASSERT_TRUE(entry_factory_
->SetLocalSpecificsForItem(
659 nigori_handle
, local_specifics
));
660 // Apply the update locally so that UpdateFromEncryptedTypes knows what state
663 syncable::ReadTransaction
trans(FROM_HERE
, directory());
664 cryptographer
= directory()->GetCryptographer(&trans
);
665 directory()->GetNigoriHandler()->ApplyNigoriUpdate(
670 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
671 EXPECT_TRUE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
672 ApplyControlDataUpdates(directory());
673 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
674 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
676 EXPECT_TRUE(cryptographer
->is_initialized());
677 EXPECT_TRUE(cryptographer
->has_pending_keys());
678 EXPECT_TRUE(other_cryptographer
.CanDecryptUsingDefaultKey(
679 entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
680 nigori().encryption_keybag()));
681 EXPECT_TRUE(entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
682 nigori().keybag_is_frozen());
683 EXPECT_TRUE(entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
684 nigori().encrypt_everything());
685 EXPECT_EQ(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE
,
686 entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
687 nigori().passphrase_type());
689 syncable::ReadTransaction
trans(FROM_HERE
, directory());
690 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
691 .Equals(ModelTypeSet::All()));
695 // If the local nigori is migrated but the server is not, preserve the local
697 TEST_F(ApplyControlDataUpdatesTest
,
698 NigoriConflictLocalMigrated
) {
699 Cryptographer
* cryptographer
;
700 ModelTypeSet
encrypted_types(SyncEncryptionHandler::SensitiveTypes());
701 KeyParams old_params
= {"localhost", "dummy", "old"};
702 KeyParams new_params
= {"localhost", "dummy", "new"};
704 syncable::ReadTransaction
trans(FROM_HERE
, directory());
705 cryptographer
= directory()->GetCryptographer(&trans
);
706 EXPECT_TRUE(encrypted_types
.Equals(
707 directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)));
710 // Set up the cryptographer with both new keys and old keys.
711 Cryptographer
other_cryptographer(cryptographer
->encryptor());
712 other_cryptographer
.AddKey(old_params
);
714 // Create server specifics with an unmigrated implicit passphrase type.
715 sync_pb::EntitySpecifics server_specifics
;
716 sync_pb::NigoriSpecifics
* server_nigori
= server_specifics
.mutable_nigori();
717 other_cryptographer
.GetKeys(server_nigori
->mutable_encryption_keybag());
718 server_nigori
->set_encrypt_everything(true);
719 server_nigori
->set_keybag_is_frozen(false);
720 int64 nigori_handle
=
721 entry_factory_
->CreateUnappliedNewItem(kNigoriTag
,
725 // Add the old keys to the cryptographer.
726 cryptographer
->AddKey(old_params
);
727 cryptographer
->AddKey(new_params
);
728 EXPECT_TRUE(cryptographer
->is_ready());
730 // Set up a local nigori with a migrated custom passphrase type
731 sync_pb::EntitySpecifics local_specifics
;
732 sync_pb::NigoriSpecifics
* local_nigori
= local_specifics
.mutable_nigori();
733 cryptographer
->GetKeys(local_nigori
->mutable_encryption_keybag());
734 local_nigori
->set_encrypt_everything(true);
735 local_nigori
->set_keybag_is_frozen(true);
736 local_nigori
->set_passphrase_type(
737 sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE
);
738 ASSERT_TRUE(entry_factory_
->SetLocalSpecificsForItem(
739 nigori_handle
, local_specifics
));
740 // Apply the update locally so that UpdateFromEncryptedTypes knows what state
743 syncable::ReadTransaction
trans(FROM_HERE
, directory());
744 cryptographer
= directory()->GetCryptographer(&trans
);
745 directory()->GetNigoriHandler()->ApplyNigoriUpdate(
750 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
751 EXPECT_TRUE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
752 ApplyControlDataUpdates(directory());
753 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
754 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
756 EXPECT_TRUE(cryptographer
->is_ready());
757 EXPECT_TRUE(cryptographer
->CanDecryptUsingDefaultKey(
758 entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
759 nigori().encryption_keybag()));
760 EXPECT_TRUE(entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
761 nigori().keybag_is_frozen());
762 EXPECT_TRUE(entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
763 nigori().encrypt_everything());
764 EXPECT_EQ(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE
,
765 entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
766 nigori().passphrase_type());
768 syncable::ReadTransaction
trans(FROM_HERE
, directory());
769 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
770 .Equals(ModelTypeSet::All()));
774 // If the server nigori is migrated but the local is not, preserve the server
776 TEST_F(ApplyControlDataUpdatesTest
,
777 NigoriConflictServerMigrated
) {
778 Cryptographer
* cryptographer
;
779 ModelTypeSet
encrypted_types(SyncEncryptionHandler::SensitiveTypes());
780 KeyParams old_params
= {"localhost", "dummy", "old"};
781 KeyParams new_params
= {"localhost", "dummy", "new"};
783 syncable::ReadTransaction
trans(FROM_HERE
, directory());
784 cryptographer
= directory()->GetCryptographer(&trans
);
785 EXPECT_TRUE(encrypted_types
.Equals(
786 directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)));
789 // Set up the cryptographer with both new keys and old keys.
790 Cryptographer
other_cryptographer(cryptographer
->encryptor());
791 other_cryptographer
.AddKey(old_params
);
793 // Create server specifics with an migrated keystore passphrase type.
794 sync_pb::EntitySpecifics server_specifics
;
795 sync_pb::NigoriSpecifics
* server_nigori
= server_specifics
.mutable_nigori();
796 other_cryptographer
.GetKeys(server_nigori
->mutable_encryption_keybag());
797 server_nigori
->set_encrypt_everything(false);
798 server_nigori
->set_keybag_is_frozen(true);
799 server_nigori
->set_passphrase_type(
800 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE
);
801 server_nigori
->mutable_keystore_decryptor_token();
802 int64 nigori_handle
=
803 entry_factory_
->CreateUnappliedNewItem(kNigoriTag
,
807 // Add the old keys to the cryptographer.
808 cryptographer
->AddKey(old_params
);
809 cryptographer
->AddKey(new_params
);
810 EXPECT_TRUE(cryptographer
->is_ready());
812 // Set up a local nigori with a migrated custom passphrase type
813 sync_pb::EntitySpecifics local_specifics
;
814 sync_pb::NigoriSpecifics
* local_nigori
= local_specifics
.mutable_nigori();
815 cryptographer
->GetKeys(local_nigori
->mutable_encryption_keybag());
816 local_nigori
->set_encrypt_everything(false);
817 local_nigori
->set_keybag_is_frozen(false);
818 ASSERT_TRUE(entry_factory_
->SetLocalSpecificsForItem(
819 nigori_handle
, local_specifics
));
820 // Apply the update locally so that UpdateFromEncryptedTypes knows what state
823 syncable::ReadTransaction
trans(FROM_HERE
, directory());
824 cryptographer
= directory()->GetCryptographer(&trans
);
825 directory()->GetNigoriHandler()->ApplyNigoriUpdate(
830 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
831 EXPECT_TRUE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
832 ApplyControlDataUpdates(directory());
833 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
834 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
836 EXPECT_TRUE(cryptographer
->is_ready());
837 // Note: we didn't overwrite the encryption keybag with the local keys. The
838 // sync encryption handler will do that when it detects that the new
839 // keybag is out of date (and update the keystore bootstrap if necessary).
840 EXPECT_FALSE(cryptographer
->CanDecryptUsingDefaultKey(
841 entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
842 nigori().encryption_keybag()));
843 EXPECT_TRUE(cryptographer
->CanDecrypt(
844 entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
845 nigori().encryption_keybag()));
846 EXPECT_TRUE(entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
847 nigori().keybag_is_frozen());
848 EXPECT_TRUE(entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
849 nigori().has_keystore_decryptor_token());
850 EXPECT_EQ(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE
,
851 entry_factory_
->GetLocalSpecificsForItem(nigori_handle
).
852 nigori().passphrase_type());
854 syncable::ReadTransaction
trans(FROM_HERE
, directory());
858 // Check that we can apply a simple control datatype node successfully.
859 TEST_F(ApplyControlDataUpdatesTest
, ControlApply
) {
860 std::string experiment_id
= "experiment";
861 sync_pb::EntitySpecifics specifics
;
862 specifics
.mutable_experiments()->mutable_keystore_encryption()->
864 int64 experiment_handle
= entry_factory_
->CreateUnappliedNewItem(
865 experiment_id
, specifics
, false);
866 ApplyControlDataUpdates(directory());
868 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(experiment_handle
));
870 entry_factory_
->GetLocalSpecificsForItem(experiment_handle
).
871 experiments().keystore_encryption().enabled());
874 // Verify that we apply top level folders before their children.
875 TEST_F(ApplyControlDataUpdatesTest
, ControlApplyParentBeforeChild
) {
876 std::string parent_id
= "parent";
877 std::string experiment_id
= "experiment";
878 sync_pb::EntitySpecifics specifics
;
879 specifics
.mutable_experiments()->mutable_keystore_encryption()->
881 int64 experiment_handle
= entry_factory_
->CreateUnappliedNewItemWithParent(
882 experiment_id
, specifics
, parent_id
);
883 int64 parent_handle
= entry_factory_
->CreateUnappliedNewItem(
884 parent_id
, specifics
, true);
885 ApplyControlDataUpdates(directory());
887 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(parent_handle
));
888 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(experiment_handle
));
890 entry_factory_
->GetLocalSpecificsForItem(experiment_handle
).
891 experiments().keystore_encryption().enabled());
894 // Verify that we handle control datatype conflicts by preserving the server
896 TEST_F(ApplyControlDataUpdatesTest
, ControlConflict
) {
897 std::string experiment_id
= "experiment";
898 sync_pb::EntitySpecifics local_specifics
, server_specifics
;
899 server_specifics
.mutable_experiments()->mutable_keystore_encryption()->
901 local_specifics
.mutable_experiments()->mutable_keystore_encryption()->
903 int64 experiment_handle
= entry_factory_
->CreateSyncedItem(
904 experiment_id
, EXPERIMENTS
, false);
905 entry_factory_
->SetServerSpecificsForItem(experiment_handle
,
907 entry_factory_
->SetLocalSpecificsForItem(experiment_handle
,
909 ApplyControlDataUpdates(directory());
911 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(experiment_handle
));
913 entry_factory_
->GetLocalSpecificsForItem(experiment_handle
).
914 experiments().keystore_encryption().enabled());
917 } // namespace syncer