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/strings/stringprintf.h"
9 #include "sync/engine/apply_control_data_updates.h"
10 #include "sync/engine/syncer.h"
11 #include "sync/engine/syncer_util.h"
12 #include "sync/internal_api/public/test/test_entry_factory.h"
13 #include "sync/protocol/nigori_specifics.pb.h"
14 #include "sync/syncable/mutable_entry.h"
15 #include "sync/syncable/nigori_util.h"
16 #include "sync/syncable/syncable_read_transaction.h"
17 #include "sync/syncable/syncable_util.h"
18 #include "sync/syncable/syncable_write_transaction.h"
19 #include "sync/test/engine/fake_model_worker.h"
20 #include "sync/test/engine/syncer_command_test.h"
21 #include "sync/test/engine/test_id_factory.h"
22 #include "sync/test/fake_sync_encryption_handler.h"
23 #include "sync/util/cryptographer.h"
24 #include "testing/gtest/include/gtest/gtest.h"
28 using syncable::MutableEntry
;
29 using syncable::UNITTEST
;
32 class ApplyControlDataUpdatesTest
: public SyncerCommandTest
{
35 ApplyControlDataUpdatesTest() {}
36 virtual ~ApplyControlDataUpdatesTest() {}
38 virtual void SetUp() {
40 mutable_routing_info()->clear();
41 workers()->push_back(make_scoped_refptr(new FakeModelWorker(GROUP_UI
)));
43 make_scoped_refptr(new FakeModelWorker(GROUP_PASSWORD
)));
44 (*mutable_routing_info())[NIGORI
] = GROUP_PASSIVE
;
45 (*mutable_routing_info())[EXPERIMENTS
] = GROUP_PASSIVE
;
46 SyncerCommandTest::SetUp();
47 entry_factory_
.reset(new TestEntryFactory(directory()));
49 session()->mutable_status_controller()->set_updates_request_types(
52 syncable::ReadTransaction
trans(FROM_HERE
, directory());
55 TestIdFactory id_factory_
;
56 scoped_ptr
<TestEntryFactory
> entry_factory_
;
58 DISALLOW_COPY_AND_ASSIGN(ApplyControlDataUpdatesTest
);
61 // Verify that applying a nigori node sets initial sync ended properly,
62 // updates the set of encrypted types, and updates the cryptographer.
63 TEST_F(ApplyControlDataUpdatesTest
, NigoriUpdate
) {
64 // Storing the cryptographer separately is bad, but for this test we
66 Cryptographer
* cryptographer
;
67 ModelTypeSet encrypted_types
;
68 encrypted_types
.PutAll(SyncEncryptionHandler::SensitiveTypes());
71 syncable::ReadTransaction
trans(FROM_HERE
, directory());
72 cryptographer
= directory()->GetCryptographer(&trans
);
73 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
74 .Equals(encrypted_types
));
77 // Nigori node updates should update the Cryptographer.
78 Cryptographer
other_cryptographer(cryptographer
->encryptor());
79 KeyParams params
= {"localhost", "dummy", "foobar"};
80 other_cryptographer
.AddKey(params
);
82 sync_pb::EntitySpecifics specifics
;
83 sync_pb::NigoriSpecifics
* nigori
= specifics
.mutable_nigori();
84 other_cryptographer
.GetKeys(nigori
->mutable_encryption_keybag());
85 nigori
->set_encrypt_everything(true);
86 entry_factory_
->CreateUnappliedNewItem(
87 ModelTypeToRootTag(NIGORI
), specifics
, true);
88 EXPECT_FALSE(cryptographer
->has_pending_keys());
90 ApplyControlDataUpdates(session());
92 EXPECT_FALSE(cryptographer
->is_ready());
93 EXPECT_TRUE(cryptographer
->has_pending_keys());
95 syncable::ReadTransaction
trans(FROM_HERE
, directory());
96 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
97 .Equals(ModelTypeSet::All()));
101 // Create some local unsynced and unencrypted data. Apply a nigori update that
102 // turns on encryption for the unsynced data. Ensure we properly encrypt the
103 // data as part of the nigori update. Apply another nigori update with no
104 // changes. Ensure we ignore already-encrypted unsynced data and that nothing
106 TEST_F(ApplyControlDataUpdatesTest
, EncryptUnsyncedChanges
) {
107 // Storing the cryptographer separately is bad, but for this test we
109 Cryptographer
* cryptographer
;
110 ModelTypeSet encrypted_types
;
111 encrypted_types
.PutAll(SyncEncryptionHandler::SensitiveTypes());
113 syncable::ReadTransaction
trans(FROM_HERE
, directory());
114 cryptographer
= directory()->GetCryptographer(&trans
);
115 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
116 .Equals(encrypted_types
));
118 // With default encrypted_types, this should be true.
119 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans
, encrypted_types
));
121 Syncer::UnsyncedMetaHandles handles
;
122 GetUnsyncedEntries(&trans
, &handles
);
123 EXPECT_TRUE(handles
.empty());
126 // Create unsynced bookmarks without encryption.
127 // First item is a folder
128 Id folder_id
= id_factory_
.NewLocalId();
129 entry_factory_
->CreateUnsyncedItem(folder_id
, id_factory_
.root(), "folder",
130 true, BOOKMARKS
, NULL
);
131 // Next five items are children of the folder
134 for (i
= 0; i
< batch_s
; ++i
) {
135 entry_factory_
->CreateUnsyncedItem(id_factory_
.NewLocalId(), folder_id
,
136 base::StringPrintf("Item %" PRIuS
"", i
),
137 false, BOOKMARKS
, NULL
);
139 // Next five items are children of the root.
140 for (; i
< 2*batch_s
; ++i
) {
141 entry_factory_
->CreateUnsyncedItem(
142 id_factory_
.NewLocalId(), id_factory_
.root(),
143 base::StringPrintf("Item %" PRIuS
"", i
), false,
147 KeyParams params
= {"localhost", "dummy", "foobar"};
148 cryptographer
->AddKey(params
);
149 sync_pb::EntitySpecifics specifics
;
150 sync_pb::NigoriSpecifics
* nigori
= specifics
.mutable_nigori();
151 cryptographer
->GetKeys(nigori
->mutable_encryption_keybag());
152 nigori
->set_encrypt_everything(true);
153 encrypted_types
.Put(BOOKMARKS
);
154 entry_factory_
->CreateUnappliedNewItem(
155 ModelTypeToRootTag(NIGORI
), specifics
, true);
156 EXPECT_FALSE(cryptographer
->has_pending_keys());
157 EXPECT_TRUE(cryptographer
->is_ready());
160 // Ensure we have unsynced nodes that aren't properly encrypted.
161 syncable::ReadTransaction
trans(FROM_HERE
, directory());
162 EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans
, encrypted_types
));
164 Syncer::UnsyncedMetaHandles handles
;
165 GetUnsyncedEntries(&trans
, &handles
);
166 EXPECT_EQ(2*batch_s
+1, handles
.size());
169 ApplyControlDataUpdates(session());
171 EXPECT_FALSE(cryptographer
->has_pending_keys());
172 EXPECT_TRUE(cryptographer
->is_ready());
174 syncable::ReadTransaction
trans(FROM_HERE
, directory());
176 // If ProcessUnsyncedChangesForEncryption worked, all our unsynced changes
177 // should be encrypted now.
178 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
179 .Equals(ModelTypeSet::All()));
180 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans
, encrypted_types
));
182 Syncer::UnsyncedMetaHandles handles
;
183 GetUnsyncedEntries(&trans
, &handles
);
184 EXPECT_EQ(2*batch_s
+1, handles
.size());
187 // Simulate another nigori update that doesn't change anything.
189 syncable::WriteTransaction
trans(FROM_HERE
, UNITTEST
, directory());
190 MutableEntry
entry(&trans
, syncable::GET_BY_SERVER_TAG
,
191 ModelTypeToRootTag(NIGORI
));
192 ASSERT_TRUE(entry
.good());
193 entry
.Put(syncable::SERVER_VERSION
, entry_factory_
->GetNextRevision());
194 entry
.Put(syncable::IS_UNAPPLIED_UPDATE
, true);
197 ApplyControlDataUpdates(session());
199 EXPECT_FALSE(cryptographer
->has_pending_keys());
200 EXPECT_TRUE(cryptographer
->is_ready());
202 syncable::ReadTransaction
trans(FROM_HERE
, directory());
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
));
209 Syncer::UnsyncedMetaHandles handles
;
210 GetUnsyncedEntries(&trans
, &handles
);
211 EXPECT_EQ(2*batch_s
+1, handles
.size());
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
219 TEST_F(ApplyControlDataUpdatesTest
, CannotEncryptUnsyncedChanges
) {
220 // Storing the cryptographer separately is bad, but for this test we
222 Cryptographer
* cryptographer
;
223 ModelTypeSet encrypted_types
;
224 encrypted_types
.PutAll(SyncEncryptionHandler::SensitiveTypes());
226 syncable::ReadTransaction
trans(FROM_HERE
, directory());
227 cryptographer
= directory()->GetCryptographer(&trans
);
228 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
229 .Equals(encrypted_types
));
231 // With default encrypted_types, this should be true.
232 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans
, encrypted_types
));
234 Syncer::UnsyncedMetaHandles handles
;
235 GetUnsyncedEntries(&trans
, &handles
);
236 EXPECT_TRUE(handles
.empty());
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,
245 // Next five items are children of the folder
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
);
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,
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());
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());
284 ApplyControlDataUpdates(session());
286 EXPECT_FALSE(cryptographer
->is_ready());
287 EXPECT_TRUE(cryptographer
->has_pending_keys());
289 syncable::ReadTransaction
trans(FROM_HERE
, directory());
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());
299 Syncer::UnsyncedMetaHandles handles
;
300 GetUnsyncedEntries(&trans
, &handles
);
301 EXPECT_EQ(2*batch_s
+1, handles
.size());
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"};
315 syncable::ReadTransaction
trans(FROM_HERE
, directory());
316 cryptographer
= directory()->GetCryptographer(&trans
);
317 EXPECT_TRUE(encrypted_types
.Equals(
318 directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)));
321 // Set up a temporary cryptographer to generate new keys with.
322 Cryptographer
other_cryptographer(cryptographer
->encryptor());
323 other_cryptographer
.AddKey(other_params
);
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
,
337 // Initialize the local cryptographer with the local keys.
338 cryptographer
->AddKey(local_params
);
339 EXPECT_TRUE(cryptographer
->is_ready());
341 // Set up a local nigori with the local encryption keys and default encrypted
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
353 syncable::ReadTransaction
trans(FROM_HERE
, directory());
354 cryptographer
= directory()->GetCryptographer(&trans
);
355 directory()->GetNigoriHandler()->ApplyNigoriUpdate(
360 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
361 EXPECT_TRUE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
362 ApplyControlDataUpdates(session());
363 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
364 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
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());
377 syncable::ReadTransaction
trans(FROM_HERE
, directory());
378 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
379 .Equals(ModelTypeSet::All()));
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"};
393 syncable::ReadTransaction
trans(FROM_HERE
, directory());
394 cryptographer
= directory()->GetCryptographer(&trans
);
395 EXPECT_TRUE(encrypted_types
.Equals(
396 directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)));
399 // Set up a temporary cryptographer to generate new keys with.
400 Cryptographer
other_cryptographer(cryptographer
->encryptor());
401 other_cryptographer
.AddKey(other_params
);
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
,
415 // Initialize the local cryptographer with the local keys.
416 cryptographer
->AddKey(local_params
);
417 EXPECT_TRUE(cryptographer
->is_ready());
419 // Set up a local nigori with the local encryption keys and default encrypted
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
431 syncable::ReadTransaction
trans(FROM_HERE
, directory());
432 cryptographer
= directory()->GetCryptographer(&trans
);
433 directory()->GetNigoriHandler()->ApplyNigoriUpdate(
438 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
439 EXPECT_TRUE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
440 ApplyControlDataUpdates(session());
441 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
442 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
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());
455 syncable::ReadTransaction
trans(FROM_HERE
, directory());
456 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
457 .Equals(ModelTypeSet::All()));
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
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"};
471 syncable::ReadTransaction
trans(FROM_HERE
, directory());
472 cryptographer
= directory()->GetCryptographer(&trans
);
473 EXPECT_TRUE(encrypted_types
.Equals(
474 directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)));
477 // Set up the cryptographer with old keys
478 cryptographer
->AddKey(old_params
);
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
,
490 // Add the new keys to the cryptogrpaher
491 cryptographer
->AddKey(new_params
);
492 EXPECT_TRUE(cryptographer
->is_ready());
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
504 syncable::ReadTransaction
trans(FROM_HERE
, directory());
505 cryptographer
= directory()->GetCryptographer(&trans
);
506 directory()->GetNigoriHandler()->ApplyNigoriUpdate(
511 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
512 EXPECT_TRUE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
513 ApplyControlDataUpdates(session());
514 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
515 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
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());
526 syncable::ReadTransaction
trans(FROM_HERE
, directory());
527 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
528 .Equals(ModelTypeSet::All()));
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"};
541 syncable::ReadTransaction
trans(FROM_HERE
, directory());
542 cryptographer
= directory()->GetCryptographer(&trans
);
543 EXPECT_TRUE(encrypted_types
.Equals(
544 directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)));
547 // Set up the cryptographer with new keys
548 Cryptographer
other_cryptographer(cryptographer
->encryptor());
549 other_cryptographer
.AddKey(old_params
);
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
,
565 // Add the new keys to the cryptographer.
566 cryptographer
->AddKey(old_params
);
567 cryptographer
->AddKey(new_params
);
568 EXPECT_TRUE(cryptographer
->is_ready());
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
583 syncable::ReadTransaction
trans(FROM_HERE
, directory());
584 cryptographer
= directory()->GetCryptographer(&trans
);
585 directory()->GetNigoriHandler()->ApplyNigoriUpdate(
590 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
591 EXPECT_TRUE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
592 ApplyControlDataUpdates(session());
593 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
594 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
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());
608 syncable::ReadTransaction
trans(FROM_HERE
, directory());
609 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
610 .Equals(ModelTypeSet::All()));
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"};
623 syncable::ReadTransaction
trans(FROM_HERE
, directory());
624 cryptographer
= directory()->GetCryptographer(&trans
);
625 EXPECT_TRUE(encrypted_types
.Equals(
626 directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)));
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
);
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
,
647 // Add the old keys to the cryptographer.
648 cryptographer
->AddKey(old_params
);
649 EXPECT_TRUE(cryptographer
->is_ready());
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
665 syncable::ReadTransaction
trans(FROM_HERE
, directory());
666 cryptographer
= directory()->GetCryptographer(&trans
);
667 directory()->GetNigoriHandler()->ApplyNigoriUpdate(
672 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
673 EXPECT_TRUE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
674 ApplyControlDataUpdates(session());
675 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
676 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
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());
691 syncable::ReadTransaction
trans(FROM_HERE
, directory());
692 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
693 .Equals(ModelTypeSet::All()));
697 // If the local nigori is migrated but the server is not, preserve the local
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"};
706 syncable::ReadTransaction
trans(FROM_HERE
, directory());
707 cryptographer
= directory()->GetCryptographer(&trans
);
708 EXPECT_TRUE(encrypted_types
.Equals(
709 directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)));
712 // Set up the cryptographer with both new keys and old keys.
713 Cryptographer
other_cryptographer(cryptographer
->encryptor());
714 other_cryptographer
.AddKey(old_params
);
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
,
727 // Add the old keys to the cryptographer.
728 cryptographer
->AddKey(old_params
);
729 cryptographer
->AddKey(new_params
);
730 EXPECT_TRUE(cryptographer
->is_ready());
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
745 syncable::ReadTransaction
trans(FROM_HERE
, directory());
746 cryptographer
= directory()->GetCryptographer(&trans
);
747 directory()->GetNigoriHandler()->ApplyNigoriUpdate(
752 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
753 EXPECT_TRUE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
754 ApplyControlDataUpdates(session());
755 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
756 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
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());
770 syncable::ReadTransaction
trans(FROM_HERE
, directory());
771 EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)
772 .Equals(ModelTypeSet::All()));
776 // If the server nigori is migrated but the local is not, preserve the server
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"};
785 syncable::ReadTransaction
trans(FROM_HERE
, directory());
786 cryptographer
= directory()->GetCryptographer(&trans
);
787 EXPECT_TRUE(encrypted_types
.Equals(
788 directory()->GetNigoriHandler()->GetEncryptedTypes(&trans
)));
791 // Set up the cryptographer with both new keys and old keys.
792 Cryptographer
other_cryptographer(cryptographer
->encryptor());
793 other_cryptographer
.AddKey(old_params
);
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
,
809 // Add the old keys to the cryptographer.
810 cryptographer
->AddKey(old_params
);
811 cryptographer
->AddKey(new_params
);
812 EXPECT_TRUE(cryptographer
->is_ready());
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
825 syncable::ReadTransaction
trans(FROM_HERE
, directory());
826 cryptographer
= directory()->GetCryptographer(&trans
);
827 directory()->GetNigoriHandler()->ApplyNigoriUpdate(
832 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
833 EXPECT_TRUE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
834 ApplyControlDataUpdates(session());
835 EXPECT_TRUE(entry_factory_
->GetIsUnsyncedForItem(nigori_handle
));
836 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(nigori_handle
));
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());
856 syncable::ReadTransaction
trans(FROM_HERE
, directory());
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()->
866 int64 experiment_handle
= entry_factory_
->CreateUnappliedNewItem(
867 experiment_id
, specifics
, false);
868 ApplyControlDataUpdates(session());
870 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(experiment_handle
));
872 entry_factory_
->GetLocalSpecificsForItem(experiment_handle
).
873 experiments().keystore_encryption().enabled());
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()->
883 int64 experiment_handle
= entry_factory_
->CreateUnappliedNewItemWithParent(
884 experiment_id
, specifics
, parent_id
);
885 int64 parent_handle
= entry_factory_
->CreateUnappliedNewItem(
886 parent_id
, specifics
, true);
887 ApplyControlDataUpdates(session());
889 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(parent_handle
));
890 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(experiment_handle
));
892 entry_factory_
->GetLocalSpecificsForItem(experiment_handle
).
893 experiments().keystore_encryption().enabled());
896 // Verify that we handle control datatype conflicts by preserving the server
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()->
903 local_specifics
.mutable_experiments()->mutable_keystore_encryption()->
905 int64 experiment_handle
= entry_factory_
->CreateSyncedItem(
906 experiment_id
, EXPERIMENTS
, false);
907 entry_factory_
->SetServerSpecificsForItem(experiment_handle
,
909 entry_factory_
->SetLocalSpecificsForItem(experiment_handle
,
911 ApplyControlDataUpdates(session());
913 EXPECT_FALSE(entry_factory_
->GetIsUnappliedForItem(experiment_handle
));
915 entry_factory_
->GetLocalSpecificsForItem(experiment_handle
).
916 experiments().keystore_encryption().enabled());
919 } // namespace syncer