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