OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "sync/internal_api/sync_manager_impl.h" | 5 #include "sync/internal_api/sync_manager_impl.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/base64.h" | 9 #include "base/base64.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 23 matching lines...) Expand all Loading... |
34 #include "sync/internal_api/public/write_node.h" | 34 #include "sync/internal_api/public/write_node.h" |
35 #include "sync/internal_api/public/write_transaction.h" | 35 #include "sync/internal_api/public/write_transaction.h" |
36 #include "sync/internal_api/syncapi_internal.h" | 36 #include "sync/internal_api/syncapi_internal.h" |
37 #include "sync/internal_api/syncapi_server_connection_manager.h" | 37 #include "sync/internal_api/syncapi_server_connection_manager.h" |
38 #include "sync/js/js_arg_list.h" | 38 #include "sync/js/js_arg_list.h" |
39 #include "sync/js/js_event_details.h" | 39 #include "sync/js/js_event_details.h" |
40 #include "sync/js/js_event_handler.h" | 40 #include "sync/js/js_event_handler.h" |
41 #include "sync/js/js_reply_handler.h" | 41 #include "sync/js/js_reply_handler.h" |
42 #include "sync/notifier/invalidation_util.h" | 42 #include "sync/notifier/invalidation_util.h" |
43 #include "sync/notifier/sync_notifier.h" | 43 #include "sync/notifier/sync_notifier.h" |
44 #include "sync/protocol/encryption.pb.h" | |
45 #include "sync/protocol/proto_value_conversions.h" | 44 #include "sync/protocol/proto_value_conversions.h" |
46 #include "sync/protocol/sync.pb.h" | 45 #include "sync/protocol/sync.pb.h" |
47 #include "sync/syncable/directory.h" | 46 #include "sync/syncable/directory.h" |
48 #include "sync/syncable/entry.h" | 47 #include "sync/syncable/entry.h" |
49 #include "sync/syncable/in_memory_directory_backing_store.h" | 48 #include "sync/syncable/in_memory_directory_backing_store.h" |
50 #include "sync/syncable/nigori_util.h" | |
51 #include "sync/syncable/on_disk_directory_backing_store.h" | 49 #include "sync/syncable/on_disk_directory_backing_store.h" |
52 #include "sync/util/get_session_name.h" | 50 #include "sync/util/get_session_name.h" |
53 | 51 |
54 using base::TimeDelta; | 52 using base::TimeDelta; |
55 using sync_pb::GetUpdatesCallerInfo; | 53 using sync_pb::GetUpdatesCallerInfo; |
56 | 54 |
57 namespace syncer { | 55 namespace syncer { |
58 | 56 |
59 using sessions::SyncSessionContext; | 57 using sessions::SyncSessionContext; |
60 using syncable::ImmutableWriteTransactionInfo; | 58 using syncable::ImmutableWriteTransactionInfo; |
61 using syncable::SPECIFICS; | 59 using syncable::SPECIFICS; |
62 | 60 |
63 namespace { | 61 namespace { |
64 | 62 |
65 // Delays for syncer nudges. | 63 // Delays for syncer nudges. |
66 static const int kDefaultNudgeDelayMilliseconds = 200; | 64 static const int kDefaultNudgeDelayMilliseconds = 200; |
67 static const int kPreferencesNudgeDelayMilliseconds = 2000; | 65 static const int kPreferencesNudgeDelayMilliseconds = 2000; |
68 static const int kSyncRefreshDelayMsec = 500; | 66 static const int kSyncRefreshDelayMsec = 500; |
69 static const int kSyncSchedulerDelayMsec = 250; | 67 static const int kSyncSchedulerDelayMsec = 250; |
70 | 68 |
71 // The maximum number of times we will automatically overwrite the nigori node | |
72 // because the encryption keys don't match (per chrome instantiation). | |
73 static const int kNigoriOverwriteLimit = 10; | |
74 | |
75 // Maximum count and size for traffic recorder. | 69 // Maximum count and size for traffic recorder. |
76 static const unsigned int kMaxMessagesToRecord = 10; | 70 static const unsigned int kMaxMessagesToRecord = 10; |
77 static const unsigned int kMaxMessageSizeToRecord = 5 * 1024; | 71 static const unsigned int kMaxMessageSizeToRecord = 5 * 1024; |
78 | 72 |
79 GetUpdatesCallerInfo::GetUpdatesSource GetSourceFromReason( | 73 GetUpdatesCallerInfo::GetUpdatesSource GetSourceFromReason( |
80 ConfigureReason reason) { | 74 ConfigureReason reason) { |
81 switch (reason) { | 75 switch (reason) { |
82 case CONFIGURE_REASON_RECONFIGURATION: | 76 case CONFIGURE_REASON_RECONFIGURATION: |
83 return GetUpdatesCallerInfo::RECONFIGURATION; | 77 return GetUpdatesCallerInfo::RECONFIGURATION; |
84 case CONFIGURE_REASON_MIGRATION: | 78 case CONFIGURE_REASON_MIGRATION: |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 : name_(name), | 166 : name_(name), |
173 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), | 167 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), |
174 change_delegate_(NULL), | 168 change_delegate_(NULL), |
175 initialized_(false), | 169 initialized_(false), |
176 observing_ip_address_changes_(false), | 170 observing_ip_address_changes_(false), |
177 notifications_disabled_reason_(TRANSIENT_NOTIFICATION_ERROR), | 171 notifications_disabled_reason_(TRANSIENT_NOTIFICATION_ERROR), |
178 throttled_data_type_tracker_(&allstatus_), | 172 throttled_data_type_tracker_(&allstatus_), |
179 traffic_recorder_(kMaxMessagesToRecord, kMaxMessageSizeToRecord), | 173 traffic_recorder_(kMaxMessagesToRecord, kMaxMessageSizeToRecord), |
180 encryptor_(NULL), | 174 encryptor_(NULL), |
181 unrecoverable_error_handler_(NULL), | 175 unrecoverable_error_handler_(NULL), |
182 report_unrecoverable_error_function_(NULL), | 176 report_unrecoverable_error_function_(NULL) { |
183 nigori_overwrite_count_(0) { | |
184 // Pre-fill |notification_info_map_|. | 177 // Pre-fill |notification_info_map_|. |
185 for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) { | 178 for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) { |
186 notification_info_map_.insert( | 179 notification_info_map_.insert( |
187 std::make_pair(ModelTypeFromInt(i), NotificationInfo())); | 180 std::make_pair(ModelTypeFromInt(i), NotificationInfo())); |
188 } | 181 } |
189 | 182 |
190 // Bind message handlers. | 183 // Bind message handlers. |
191 BindJsMessageHandler( | 184 BindJsMessageHandler( |
192 "getNotificationState", | 185 "getNotificationState", |
193 &SyncManagerImpl::GetNotificationState); | 186 &SyncManagerImpl::GetNotificationState); |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
303 sync_pb::DataTypeProgressMarker marker; | 296 sync_pb::DataTypeProgressMarker marker; |
304 directory()->GetDownloadProgress(i.Get(), &marker); | 297 directory()->GetDownloadProgress(i.Get(), &marker); |
305 | 298 |
306 if (marker.token().empty()) | 299 if (marker.token().empty()) |
307 result.Put(i.Get()); | 300 result.Put(i.Get()); |
308 | 301 |
309 } | 302 } |
310 return result; | 303 return result; |
311 } | 304 } |
312 | 305 |
313 void SyncManagerImpl::EnableEncryptEverything() { | |
314 DCHECK(thread_checker_.CalledOnValidThread()); | |
315 { | |
316 // Update the cryptographer to know we're now encrypting everything. | |
317 WriteTransaction trans(FROM_HERE, GetUserShare()); | |
318 Cryptographer* cryptographer = trans.GetCryptographer(); | |
319 // Only set encrypt everything if we know we can encrypt. This allows the | |
320 // user to cancel encryption if they have forgotten their passphrase. | |
321 if (cryptographer->is_ready()) | |
322 cryptographer->set_encrypt_everything(); | |
323 } | |
324 | |
325 // Reads from cryptographer so will automatically encrypt all | |
326 // datatypes and update the nigori node as necessary. Will trigger | |
327 // OnPassphraseRequired if necessary. | |
328 RefreshEncryption(); | |
329 } | |
330 | |
331 void SyncManagerImpl::ConfigureSyncer( | 306 void SyncManagerImpl::ConfigureSyncer( |
332 ConfigureReason reason, | 307 ConfigureReason reason, |
333 const ModelTypeSet& types_to_config, | 308 const ModelTypeSet& types_to_config, |
334 const ModelSafeRoutingInfo& new_routing_info, | 309 const ModelSafeRoutingInfo& new_routing_info, |
335 const base::Closure& ready_task, | 310 const base::Closure& ready_task, |
336 const base::Closure& retry_task) { | 311 const base::Closure& retry_task) { |
337 DCHECK(thread_checker_.CalledOnValidThread()); | 312 DCHECK(thread_checker_.CalledOnValidThread()); |
338 DCHECK(!ready_task.is_null()); | 313 DCHECK(!ready_task.is_null()); |
339 DCHECK(!retry_task.is_null()); | 314 DCHECK(!retry_task.is_null()); |
340 | 315 |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 UpdateCredentials(credentials); | 457 UpdateCredentials(credentials); |
483 | 458 |
484 // Cryptographer should only be accessed while holding a | 459 // Cryptographer should only be accessed while holding a |
485 // transaction. Grabbing the user share for the transaction | 460 // transaction. Grabbing the user share for the transaction |
486 // checks the initialization state, so this must come after | 461 // checks the initialization state, so this must come after |
487 // |initialized_| is set to true. | 462 // |initialized_| is set to true. |
488 ReadTransaction trans(FROM_HERE, GetUserShare()); | 463 ReadTransaction trans(FROM_HERE, GetUserShare()); |
489 trans.GetCryptographer()->Bootstrap(restored_key_for_bootstrapping); | 464 trans.GetCryptographer()->Bootstrap(restored_key_for_bootstrapping); |
490 trans.GetCryptographer()->BootstrapKeystoreKey( | 465 trans.GetCryptographer()->BootstrapKeystoreKey( |
491 restored_keystore_key_for_bootstrapping); | 466 restored_keystore_key_for_bootstrapping); |
492 trans.GetCryptographer()->AddObserver(this); | 467 |
| 468 sync_encryption_handler_.reset(new SyncEncryptionHandlerImpl( |
| 469 &share_, |
| 470 trans.GetCryptographer())); |
| 471 sync_encryption_handler_->AddObserver(this); |
| 472 sync_encryption_handler_->AddObserver(&debug_info_event_listener_); |
| 473 sync_encryption_handler_->AddObserver(&js_sync_encryption_handler_observer_); |
| 474 trans.GetCryptographer()->SetNigoriHandler( |
| 475 sync_encryption_handler_.get()); |
493 | 476 |
494 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | 477 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, |
495 OnInitializationComplete( | 478 OnInitializationComplete( |
496 MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()), | 479 MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()), |
497 true, InitialSyncEndedTypes())); | 480 true, InitialSyncEndedTypes())); |
498 } | 481 } |
499 | 482 |
500 void SyncManagerImpl::RefreshNigori(const std::string& chrome_version, | 483 void SyncManagerImpl::UpdateSessionNameCallback( |
501 const base::Closure& done_callback) { | |
502 DCHECK(initialized_); | |
503 DCHECK(thread_checker_.CalledOnValidThread()); | |
504 GetSessionName( | |
505 blocking_task_runner_, | |
506 base::Bind( | |
507 &SyncManagerImpl::UpdateCryptographerAndNigoriCallback, | |
508 weak_ptr_factory_.GetWeakPtr(), | |
509 chrome_version, | |
510 done_callback)); | |
511 } | |
512 | |
513 void SyncManagerImpl::UpdateNigoriEncryptionState( | |
514 Cryptographer* cryptographer, | |
515 WriteNode* nigori_node) { | |
516 DCHECK(nigori_node); | |
517 sync_pb::NigoriSpecifics nigori = nigori_node->GetNigoriSpecifics(); | |
518 | |
519 if (cryptographer->is_ready() && | |
520 nigori_overwrite_count_ < kNigoriOverwriteLimit) { | |
521 // Does not modify the encrypted blob if the unencrypted data already | |
522 // matches what is about to be written. | |
523 sync_pb::EncryptedData original_keys = nigori.encrypted(); | |
524 if (!cryptographer->GetKeys(nigori.mutable_encrypted())) | |
525 NOTREACHED(); | |
526 | |
527 if (nigori.encrypted().SerializeAsString() != | |
528 original_keys.SerializeAsString()) { | |
529 // We've updated the nigori node's encryption keys. In order to prevent | |
530 // a possible looping of two clients constantly overwriting each other, | |
531 // we limit the absolute number of overwrites per client instantiation. | |
532 nigori_overwrite_count_++; | |
533 UMA_HISTOGRAM_COUNTS("Sync.AutoNigoriOverwrites", | |
534 nigori_overwrite_count_); | |
535 } | |
536 | |
537 // Note: we don't try to set using_explicit_passphrase here since if that | |
538 // is lost the user can always set it again. The main point is to preserve | |
539 // the encryption keys so all data remains decryptable. | |
540 } | |
541 cryptographer->UpdateNigoriFromEncryptedTypes(&nigori); | |
542 | |
543 // If nothing has changed, this is a no-op. | |
544 nigori_node->SetNigoriSpecifics(nigori); | |
545 } | |
546 | |
547 void SyncManagerImpl::UpdateCryptographerAndNigoriCallback( | |
548 const std::string& chrome_version, | 484 const std::string& chrome_version, |
549 const base::Closure& done_callback, | |
550 const std::string& session_name) { | 485 const std::string& session_name) { |
551 if (!directory()->initial_sync_ended_for_type(NIGORI)) { | 486 WriteTransaction trans(FROM_HERE, GetUserShare()); |
552 done_callback.Run(); // Should only happen during first time sync. | 487 WriteNode node(&trans); |
| 488 // TODO(rlarocque): switch to device info node. |
| 489 if (node.InitByTagLookup(syncer::kNigoriTag) != syncer::BaseNode::INIT_OK) { |
553 return; | 490 return; |
554 } | 491 } |
555 | 492 |
556 bool success = false; | 493 sync_pb::NigoriSpecifics nigori(node.GetNigoriSpecifics()); |
557 { | 494 // Add or update device information. |
558 WriteTransaction trans(FROM_HERE, GetUserShare()); | 495 bool contains_this_device = false; |
559 Cryptographer* cryptographer = trans.GetCryptographer(); | 496 for (int i = 0; i < nigori.device_information_size(); ++i) { |
560 WriteNode node(&trans); | 497 const sync_pb::DeviceInformation& device_information = |
561 | 498 nigori.device_information(i); |
562 if (node.InitByTagLookup(kNigoriTag) == BaseNode::INIT_OK) { | 499 if (device_information.cache_guid() == directory()->cache_guid()) { |
563 sync_pb::NigoriSpecifics nigori(node.GetNigoriSpecifics()); | 500 // Update the version number in case it changed due to an update. |
564 Cryptographer::UpdateResult result = cryptographer->Update(nigori); | 501 if (device_information.chrome_version() != chrome_version) { |
565 if (result == Cryptographer::NEEDS_PASSPHRASE) { | 502 sync_pb::DeviceInformation* mutable_device_information = |
566 sync_pb::EncryptedData pending_keys; | 503 nigori.mutable_device_information(i); |
567 if (cryptographer->has_pending_keys()) | 504 mutable_device_information->set_chrome_version( |
568 pending_keys = cryptographer->GetPendingKeys(); | 505 chrome_version); |
569 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
570 OnPassphraseRequired(REASON_DECRYPTION, | |
571 pending_keys)); | |
572 } | 506 } |
573 | 507 contains_this_device = true; |
574 // Add or update device information. | |
575 bool contains_this_device = false; | |
576 for (int i = 0; i < nigori.device_information_size(); ++i) { | |
577 const sync_pb::DeviceInformation& device_information = | |
578 nigori.device_information(i); | |
579 if (device_information.cache_guid() == directory()->cache_guid()) { | |
580 // Update the version number in case it changed due to an update. | |
581 if (device_information.chrome_version() != chrome_version) { | |
582 sync_pb::DeviceInformation* mutable_device_information = | |
583 nigori.mutable_device_information(i); | |
584 mutable_device_information->set_chrome_version( | |
585 chrome_version); | |
586 } | |
587 contains_this_device = true; | |
588 } | |
589 } | |
590 | |
591 if (!contains_this_device) { | |
592 sync_pb::DeviceInformation* device_information = | |
593 nigori.add_device_information(); | |
594 device_information->set_cache_guid(directory()->cache_guid()); | |
595 #if defined(OS_CHROMEOS) | |
596 device_information->set_platform("ChromeOS"); | |
597 #elif defined(OS_LINUX) | |
598 device_information->set_platform("Linux"); | |
599 #elif defined(OS_MACOSX) | |
600 device_information->set_platform("Mac"); | |
601 #elif defined(OS_WIN) | |
602 device_information->set_platform("Windows"); | |
603 #endif | |
604 device_information->set_name(session_name); | |
605 device_information->set_chrome_version(chrome_version); | |
606 } | |
607 // Disabled to avoid nigori races. TODO(zea): re-enable. crbug.com/122837 | |
608 // node.SetNigoriSpecifics(nigori); | |
609 | |
610 // Make sure the nigori node has the up to date encryption info. | |
611 UpdateNigoriEncryptionState(cryptographer, &node); | |
612 | |
613 NotifyCryptographerState(cryptographer); | |
614 allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes()); | |
615 | |
616 success = cryptographer->is_ready(); | |
617 } else { | |
618 NOTREACHED(); | |
619 } | 508 } |
620 } | 509 } |
621 | 510 |
622 if (success) | 511 if (!contains_this_device) { |
623 RefreshEncryption(); | 512 sync_pb::DeviceInformation* device_information = |
624 done_callback.Run(); | 513 nigori.add_device_information(); |
| 514 device_information->set_cache_guid(directory()->cache_guid()); |
| 515 #if defined(OS_CHROMEOS) |
| 516 device_information->set_platform("ChromeOS"); |
| 517 #elif defined(OS_LINUX) |
| 518 device_information->set_platform("Linux"); |
| 519 #elif defined(OS_MACOSX) |
| 520 device_information->set_platform("Mac"); |
| 521 #elif defined(OS_WIN) |
| 522 device_information->set_platform("Windows"); |
| 523 #endif |
| 524 device_information->set_name(session_name); |
| 525 device_information->set_chrome_version(chrome_version); |
| 526 } |
| 527 node.SetNigoriSpecifics(nigori); |
625 } | 528 } |
626 | 529 |
627 void SyncManagerImpl::NotifyCryptographerState(Cryptographer * cryptographer) { | 530 |
628 // TODO(lipalani): Explore the possibility of hooking this up to | 531 void SyncManagerImpl::OnPassphraseRequired( |
629 // SyncManager::Observer and making |AllStatus| a listener for that. | 532 PassphraseRequiredReason reason, |
| 533 const sync_pb::EncryptedData& pending_keys) { |
| 534 // Does nothing. |
| 535 } |
| 536 |
| 537 void SyncManagerImpl::OnPassphraseAccepted() { |
| 538 // Does nothing. |
| 539 } |
| 540 |
| 541 void SyncManagerImpl::OnBootstrapTokenUpdated( |
| 542 const std::string& bootstrap_token) { |
| 543 // Does nothing. |
| 544 } |
| 545 |
| 546 void SyncManagerImpl::OnEncryptedTypesChanged(ModelTypeSet encrypted_types, |
| 547 bool encrypt_everything) { |
| 548 allstatus_.SetEncryptedTypes(encrypted_types); |
| 549 } |
| 550 |
| 551 void SyncManagerImpl::OnEncryptionComplete() { |
| 552 // Does nothing. |
| 553 } |
| 554 |
| 555 void SyncManagerImpl::OnCryptographerStateChanged( |
| 556 Cryptographer* cryptographer) { |
630 allstatus_.SetCryptographerReady(cryptographer->is_ready()); | 557 allstatus_.SetCryptographerReady(cryptographer->is_ready()); |
631 allstatus_.SetCryptoHasPendingKeys(cryptographer->has_pending_keys()); | 558 allstatus_.SetCryptoHasPendingKeys(cryptographer->has_pending_keys()); |
632 debug_info_event_listener_.SetCryptographerReady(cryptographer->is_ready()); | |
633 debug_info_event_listener_.SetCrytographerHasPendingKeys( | |
634 cryptographer->has_pending_keys()); | |
635 } | 559 } |
636 | 560 |
637 void SyncManagerImpl::StartSyncingNormally( | 561 void SyncManagerImpl::StartSyncingNormally( |
638 const ModelSafeRoutingInfo& routing_info) { | 562 const ModelSafeRoutingInfo& routing_info) { |
639 // Start the sync scheduler. | 563 // Start the sync scheduler. |
640 // TODO(sync): We always want the newest set of routes when we switch back | 564 // TODO(sync): We always want the newest set of routes when we switch back |
641 // to normal mode. Figure out how to enforce set_routing_info is always | 565 // to normal mode. Figure out how to enforce set_routing_info is always |
642 // appropriately set and that it's only modified when switching to normal | 566 // appropriately set and that it's only modified when switching to normal |
643 // mode. | 567 // mode. |
644 DCHECK(thread_checker_.CalledOnValidThread()); | 568 DCHECK(thread_checker_.CalledOnValidThread()); |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
753 sync_notifier_->UpdateRegisteredIds(handler, ids); | 677 sync_notifier_->UpdateRegisteredIds(handler, ids); |
754 } | 678 } |
755 | 679 |
756 void SyncManagerImpl::UnregisterInvalidationHandler( | 680 void SyncManagerImpl::UnregisterInvalidationHandler( |
757 SyncNotifierObserver* handler) { | 681 SyncNotifierObserver* handler) { |
758 DCHECK(thread_checker_.CalledOnValidThread()); | 682 DCHECK(thread_checker_.CalledOnValidThread()); |
759 DCHECK(initialized_); | 683 DCHECK(initialized_); |
760 sync_notifier_->UnregisterHandler(handler); | 684 sync_notifier_->UnregisterHandler(handler); |
761 } | 685 } |
762 | 686 |
763 void SyncManagerImpl::SetEncryptionPassphrase( | |
764 const std::string& passphrase, | |
765 bool is_explicit) { | |
766 DCHECK(thread_checker_.CalledOnValidThread()); | |
767 // We do not accept empty passphrases. | |
768 if (passphrase.empty()) { | |
769 NOTREACHED() << "Cannot encrypt with an empty passphrase."; | |
770 return; | |
771 } | |
772 | |
773 // All accesses to the cryptographer are protected by a transaction. | |
774 WriteTransaction trans(FROM_HERE, GetUserShare()); | |
775 Cryptographer* cryptographer = trans.GetCryptographer(); | |
776 KeyParams key_params = {"localhost", "dummy", passphrase}; | |
777 WriteNode node(&trans); | |
778 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { | |
779 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS. | |
780 NOTREACHED(); | |
781 return; | |
782 } | |
783 | |
784 bool nigori_has_explicit_passphrase = | |
785 node.GetNigoriSpecifics().using_explicit_passphrase(); | |
786 std::string bootstrap_token; | |
787 sync_pb::EncryptedData pending_keys; | |
788 if (cryptographer->has_pending_keys()) | |
789 pending_keys = cryptographer->GetPendingKeys(); | |
790 bool success = false; | |
791 | |
792 | |
793 // There are six cases to handle here: | |
794 // 1. The user has no pending keys and is setting their current GAIA password | |
795 // as the encryption passphrase. This happens either during first time sync | |
796 // with a clean profile, or after re-authenticating on a profile that was | |
797 // already signed in with the cryptographer ready. | |
798 // 2. The user has no pending keys, and is overwriting an (already provided) | |
799 // implicit passphrase with an explicit (custom) passphrase. | |
800 // 3. The user has pending keys for an explicit passphrase that is somehow set | |
801 // to their current GAIA passphrase. | |
802 // 4. The user has pending keys encrypted with their current GAIA passphrase | |
803 // and the caller passes in the current GAIA passphrase. | |
804 // 5. The user has pending keys encrypted with an older GAIA passphrase | |
805 // and the caller passes in the current GAIA passphrase. | |
806 // 6. The user has previously done encryption with an explicit passphrase. | |
807 // Furthermore, we enforce the fact that the bootstrap encryption token will | |
808 // always be derived from the newest GAIA password if the account is using | |
809 // an implicit passphrase (even if the data is encrypted with an old GAIA | |
810 // password). If the account is using an explicit (custom) passphrase, the | |
811 // bootstrap token will be derived from the most recently provided explicit | |
812 // passphrase (that was able to decrypt the data). | |
813 if (!nigori_has_explicit_passphrase) { | |
814 if (!cryptographer->has_pending_keys()) { | |
815 if (cryptographer->AddKey(key_params)) { | |
816 // Case 1 and 2. We set a new GAIA passphrase when there are no pending | |
817 // keys (1), or overwriting an implicit passphrase with a new explicit | |
818 // one (2) when there are no pending keys. | |
819 DVLOG(1) << "Setting " << (is_explicit ? "explicit" : "implicit" ) | |
820 << " passphrase for encryption."; | |
821 cryptographer->GetBootstrapToken(&bootstrap_token); | |
822 success = true; | |
823 } else { | |
824 NOTREACHED() << "Failed to add key to cryptographer."; | |
825 success = false; | |
826 } | |
827 } else { // cryptographer->has_pending_keys() == true | |
828 if (is_explicit) { | |
829 // This can only happen if the nigori node is updated with a new | |
830 // implicit passphrase while a client is attempting to set a new custom | |
831 // passphrase (race condition). | |
832 DVLOG(1) << "Failing because an implicit passphrase is already set."; | |
833 success = false; | |
834 } else { // is_explicit == false | |
835 if (cryptographer->DecryptPendingKeys(key_params)) { | |
836 // Case 4. We successfully decrypted with the implicit GAIA passphrase | |
837 // passed in. | |
838 DVLOG(1) << "Implicit internal passphrase accepted for decryption."; | |
839 cryptographer->GetBootstrapToken(&bootstrap_token); | |
840 success = true; | |
841 } else { | |
842 // Case 5. Encryption was done with an old GAIA password, but we were | |
843 // provided with the current GAIA password. We need to generate a new | |
844 // bootstrap token to preserve it. We build a temporary cryptographer | |
845 // to allow us to extract these params without polluting our current | |
846 // cryptographer. | |
847 DVLOG(1) << "Implicit internal passphrase failed to decrypt, adding " | |
848 << "anyways as default passphrase and persisting via " | |
849 << "bootstrap token."; | |
850 Cryptographer temp_cryptographer(encryptor_); | |
851 temp_cryptographer.AddKey(key_params); | |
852 temp_cryptographer.GetBootstrapToken(&bootstrap_token); | |
853 // We then set the new passphrase as the default passphrase of the | |
854 // real cryptographer, even though we have pending keys. This is safe, | |
855 // as although Cryptographer::is_initialized() will now be true, | |
856 // is_ready() will remain false due to having pending keys. | |
857 cryptographer->AddKey(key_params); | |
858 success = false; | |
859 } | |
860 } // is_explicit | |
861 } // cryptographer->has_pending_keys() | |
862 } else { // nigori_has_explicit_passphrase == true | |
863 // Case 6. We do not want to override a previously set explicit passphrase, | |
864 // so we return a failure. | |
865 DVLOG(1) << "Failing because an explicit passphrase is already set."; | |
866 success = false; | |
867 } | |
868 | |
869 DVLOG_IF(1, !success) | |
870 << "Failure in SetEncryptionPassphrase; notifying and returning."; | |
871 DVLOG_IF(1, success) | |
872 << "Successfully set encryption passphrase; updating nigori and " | |
873 "reencrypting."; | |
874 | |
875 FinishSetPassphrase( | |
876 success, bootstrap_token, is_explicit, &trans, &node); | |
877 } | |
878 | |
879 void SyncManagerImpl::SetDecryptionPassphrase( | |
880 const std::string& passphrase) { | |
881 DCHECK(thread_checker_.CalledOnValidThread()); | |
882 // We do not accept empty passphrases. | |
883 if (passphrase.empty()) { | |
884 NOTREACHED() << "Cannot decrypt with an empty passphrase."; | |
885 return; | |
886 } | |
887 | |
888 // All accesses to the cryptographer are protected by a transaction. | |
889 WriteTransaction trans(FROM_HERE, GetUserShare()); | |
890 Cryptographer* cryptographer = trans.GetCryptographer(); | |
891 KeyParams key_params = {"localhost", "dummy", passphrase}; | |
892 WriteNode node(&trans); | |
893 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { | |
894 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS. | |
895 NOTREACHED(); | |
896 return; | |
897 } | |
898 | |
899 if (!cryptographer->has_pending_keys()) { | |
900 // Note that this *can* happen in a rare situation where data is | |
901 // re-encrypted on another client while a SetDecryptionPassphrase() call is | |
902 // in-flight on this client. It is rare enough that we choose to do nothing. | |
903 NOTREACHED() << "Attempt to set decryption passphrase failed because there " | |
904 << "were no pending keys."; | |
905 return; | |
906 } | |
907 | |
908 bool nigori_has_explicit_passphrase = | |
909 node.GetNigoriSpecifics().using_explicit_passphrase(); | |
910 std::string bootstrap_token; | |
911 sync_pb::EncryptedData pending_keys; | |
912 pending_keys = cryptographer->GetPendingKeys(); | |
913 bool success = false; | |
914 | |
915 // There are three cases to handle here: | |
916 // 7. We're using the current GAIA password to decrypt the pending keys. This | |
917 // happens when signing in to an account with a previously set implicit | |
918 // passphrase, where the data is already encrypted with the newest GAIA | |
919 // password. | |
920 // 8. The user is providing an old GAIA password to decrypt the pending keys. | |
921 // In this case, the user is using an implicit passphrase, but has changed | |
922 // their password since they last encrypted their data, and therefore | |
923 // their current GAIA password was unable to decrypt the data. This will | |
924 // happen when the user is setting up a new profile with a previously | |
925 // encrypted account (after changing passwords). | |
926 // 9. The user is providing a previously set explicit passphrase to decrypt | |
927 // the pending keys. | |
928 if (!nigori_has_explicit_passphrase) { | |
929 if (cryptographer->is_initialized()) { | |
930 // We only want to change the default encryption key to the pending | |
931 // one if the pending keybag already contains the current default. | |
932 // This covers the case where a different client re-encrypted | |
933 // everything with a newer gaia passphrase (and hence the keybag | |
934 // contains keys from all previously used gaia passphrases). | |
935 // Otherwise, we're in a situation where the pending keys are | |
936 // encrypted with an old gaia passphrase, while the default is the | |
937 // current gaia passphrase. In that case, we preserve the default. | |
938 Cryptographer temp_cryptographer(encryptor_); | |
939 temp_cryptographer.SetPendingKeys(cryptographer->GetPendingKeys()); | |
940 if (temp_cryptographer.DecryptPendingKeys(key_params)) { | |
941 // Check to see if the pending bag of keys contains the current | |
942 // default key. | |
943 sync_pb::EncryptedData encrypted; | |
944 cryptographer->GetKeys(&encrypted); | |
945 if (temp_cryptographer.CanDecrypt(encrypted)) { | |
946 DVLOG(1) << "Implicit user provided passphrase accepted for " | |
947 << "decryption, overwriting default."; | |
948 // Case 7. The pending keybag contains the current default. Go ahead | |
949 // and update the cryptographer, letting the default change. | |
950 cryptographer->DecryptPendingKeys(key_params); | |
951 cryptographer->GetBootstrapToken(&bootstrap_token); | |
952 success = true; | |
953 } else { | |
954 // Case 8. The pending keybag does not contain the current default | |
955 // encryption key. We decrypt the pending keys here, and in | |
956 // FinishSetPassphrase, re-encrypt everything with the current GAIA | |
957 // passphrase instead of the passphrase just provided by the user. | |
958 DVLOG(1) << "Implicit user provided passphrase accepted for " | |
959 << "decryption, restoring implicit internal passphrase " | |
960 << "as default."; | |
961 std::string bootstrap_token_from_current_key; | |
962 cryptographer->GetBootstrapToken( | |
963 &bootstrap_token_from_current_key); | |
964 cryptographer->DecryptPendingKeys(key_params); | |
965 // Overwrite the default from the pending keys. | |
966 cryptographer->AddKeyFromBootstrapToken( | |
967 bootstrap_token_from_current_key); | |
968 success = true; | |
969 } | |
970 } else { // !temp_cryptographer.DecryptPendingKeys(..) | |
971 DVLOG(1) << "Implicit user provided passphrase failed to decrypt."; | |
972 success = false; | |
973 } // temp_cryptographer.DecryptPendingKeys(...) | |
974 } else { // cryptographer->is_initialized() == false | |
975 if (cryptographer->DecryptPendingKeys(key_params)) { | |
976 // This can happpen in two cases: | |
977 // - First time sync on android, where we'll never have a | |
978 // !user_provided passphrase. | |
979 // - This is a restart for a client that lost their bootstrap token. | |
980 // In both cases, we should go ahead and initialize the cryptographer | |
981 // and persist the new bootstrap token. | |
982 // | |
983 // Note: at this point, we cannot distinguish between cases 7 and 8 | |
984 // above. This user provided passphrase could be the current or the | |
985 // old. But, as long as we persist the token, there's nothing more | |
986 // we can do. | |
987 cryptographer->GetBootstrapToken(&bootstrap_token); | |
988 DVLOG(1) << "Implicit user provided passphrase accepted, initializing" | |
989 << " cryptographer."; | |
990 success = true; | |
991 } else { | |
992 DVLOG(1) << "Implicit user provided passphrase failed to decrypt."; | |
993 success = false; | |
994 } | |
995 } // cryptographer->is_initialized() | |
996 } else { // nigori_has_explicit_passphrase == true | |
997 // Case 9. Encryption was done with an explicit passphrase, and we decrypt | |
998 // with the passphrase provided by the user. | |
999 if (cryptographer->DecryptPendingKeys(key_params)) { | |
1000 DVLOG(1) << "Explicit passphrase accepted for decryption."; | |
1001 cryptographer->GetBootstrapToken(&bootstrap_token); | |
1002 success = true; | |
1003 } else { | |
1004 DVLOG(1) << "Explicit passphrase failed to decrypt."; | |
1005 success = false; | |
1006 } | |
1007 } // nigori_has_explicit_passphrase | |
1008 | |
1009 DVLOG_IF(1, !success) | |
1010 << "Failure in SetDecryptionPassphrase; notifying and returning."; | |
1011 DVLOG_IF(1, success) | |
1012 << "Successfully set decryption passphrase; updating nigori and " | |
1013 "reencrypting."; | |
1014 | |
1015 FinishSetPassphrase(success, | |
1016 bootstrap_token, | |
1017 nigori_has_explicit_passphrase, | |
1018 &trans, | |
1019 &node); | |
1020 } | |
1021 | |
1022 void SyncManagerImpl::FinishSetPassphrase( | |
1023 bool success, | |
1024 const std::string& bootstrap_token, | |
1025 bool is_explicit, | |
1026 WriteTransaction* trans, | |
1027 WriteNode* nigori_node) { | |
1028 Cryptographer* cryptographer = trans->GetCryptographer(); | |
1029 NotifyCryptographerState(cryptographer); | |
1030 | |
1031 // It's possible we need to change the bootstrap token even if we failed to | |
1032 // set the passphrase (for example if we need to preserve the new GAIA | |
1033 // passphrase). | |
1034 if (!bootstrap_token.empty()) { | |
1035 DVLOG(1) << "Bootstrap token updated."; | |
1036 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
1037 OnBootstrapTokenUpdated(bootstrap_token)); | |
1038 } | |
1039 | |
1040 if (!success) { | |
1041 if (cryptographer->is_ready()) { | |
1042 LOG(ERROR) << "Attempt to change passphrase failed while cryptographer " | |
1043 << "was ready."; | |
1044 } else if (cryptographer->has_pending_keys()) { | |
1045 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
1046 OnPassphraseRequired(REASON_DECRYPTION, | |
1047 cryptographer->GetPendingKeys())); | |
1048 } else { | |
1049 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
1050 OnPassphraseRequired(REASON_ENCRYPTION, | |
1051 sync_pb::EncryptedData())); | |
1052 } | |
1053 return; | |
1054 } | |
1055 | |
1056 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
1057 OnPassphraseAccepted()); | |
1058 DCHECK(cryptographer->is_ready()); | |
1059 | |
1060 // TODO(tim): Bug 58231. It would be nice if setting a passphrase didn't | |
1061 // require messing with the Nigori node, because we can't set a passphrase | |
1062 // until download conditions are met vs Cryptographer init. It seems like | |
1063 // it's safe to defer this work. | |
1064 sync_pb::NigoriSpecifics specifics(nigori_node->GetNigoriSpecifics()); | |
1065 // Does not modify specifics.encrypted() if the original decrypted data was | |
1066 // the same. | |
1067 if (!cryptographer->GetKeys(specifics.mutable_encrypted())) { | |
1068 NOTREACHED(); | |
1069 return; | |
1070 } | |
1071 specifics.set_using_explicit_passphrase(is_explicit); | |
1072 nigori_node->SetNigoriSpecifics(specifics); | |
1073 | |
1074 // Does nothing if everything is already encrypted or the cryptographer has | |
1075 // pending keys. | |
1076 ReEncryptEverything(trans); | |
1077 } | |
1078 | |
1079 bool SyncManagerImpl::IsUsingExplicitPassphrase() { | |
1080 ReadTransaction trans(FROM_HERE, &share_); | |
1081 ReadNode node(&trans); | |
1082 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { | |
1083 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS. | |
1084 NOTREACHED(); | |
1085 return false; | |
1086 } | |
1087 | |
1088 return node.GetNigoriSpecifics().using_explicit_passphrase(); | |
1089 } | |
1090 | |
1091 bool SyncManagerImpl::GetKeystoreKeyBootstrapToken(std::string* token) { | 687 bool SyncManagerImpl::GetKeystoreKeyBootstrapToken(std::string* token) { |
1092 ReadTransaction trans(FROM_HERE, GetUserShare()); | 688 ReadTransaction trans(FROM_HERE, GetUserShare()); |
1093 return trans.GetCryptographer()->GetKeystoreKeyBootstrapToken(token); | 689 return trans.GetCryptographer()->GetKeystoreKeyBootstrapToken(token); |
1094 } | 690 } |
1095 | 691 |
1096 void SyncManagerImpl::RefreshEncryption() { | |
1097 DCHECK(initialized_); | |
1098 | |
1099 WriteTransaction trans(FROM_HERE, GetUserShare()); | |
1100 WriteNode node(&trans); | |
1101 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { | |
1102 NOTREACHED() << "Unable to set encrypted datatypes because Nigori node not " | |
1103 << "found."; | |
1104 return; | |
1105 } | |
1106 | |
1107 Cryptographer* cryptographer = trans.GetCryptographer(); | |
1108 | |
1109 if (!cryptographer->is_ready()) { | |
1110 DVLOG(1) << "Attempting to encrypt datatypes when cryptographer not " | |
1111 << "initialized, prompting for passphrase."; | |
1112 // TODO(zea): this isn't really decryption, but that's the only way we have | |
1113 // to prompt the user for a passsphrase. See http://crbug.com/91379. | |
1114 sync_pb::EncryptedData pending_keys; | |
1115 if (cryptographer->has_pending_keys()) | |
1116 pending_keys = cryptographer->GetPendingKeys(); | |
1117 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
1118 OnPassphraseRequired(REASON_DECRYPTION, | |
1119 pending_keys)); | |
1120 return; | |
1121 } | |
1122 | |
1123 UpdateNigoriEncryptionState(cryptographer, &node); | |
1124 | |
1125 allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes()); | |
1126 | |
1127 // We reencrypt everything regardless of whether the set of encrypted | |
1128 // types changed to ensure that any stray unencrypted entries are overwritten. | |
1129 ReEncryptEverything(&trans); | |
1130 } | |
1131 | |
1132 // This function iterates over all encrypted types. There are many scenarios in | |
1133 // which data for some or all types is not currently available. In that case, | |
1134 // the lookup of the root node will fail and we will skip encryption for that | |
1135 // type. | |
1136 void SyncManagerImpl::ReEncryptEverything( | |
1137 WriteTransaction* trans) { | |
1138 Cryptographer* cryptographer = trans->GetCryptographer(); | |
1139 if (!cryptographer || !cryptographer->is_ready()) | |
1140 return; | |
1141 ModelTypeSet encrypted_types = GetEncryptedTypes(trans); | |
1142 for (ModelTypeSet::Iterator iter = encrypted_types.First(); | |
1143 iter.Good(); iter.Inc()) { | |
1144 if (iter.Get() == PASSWORDS || iter.Get() == NIGORI) | |
1145 continue; // These types handle encryption differently. | |
1146 | |
1147 ReadNode type_root(trans); | |
1148 std::string tag = ModelTypeToRootTag(iter.Get()); | |
1149 if (type_root.InitByTagLookup(tag) != BaseNode::INIT_OK) | |
1150 continue; // Don't try to reencrypt if the type's data is unavailable. | |
1151 | |
1152 // Iterate through all children of this datatype. | |
1153 std::queue<int64> to_visit; | |
1154 int64 child_id = type_root.GetFirstChildId(); | |
1155 to_visit.push(child_id); | |
1156 while (!to_visit.empty()) { | |
1157 child_id = to_visit.front(); | |
1158 to_visit.pop(); | |
1159 if (child_id == kInvalidId) | |
1160 continue; | |
1161 | |
1162 WriteNode child(trans); | |
1163 if (child.InitByIdLookup(child_id) != BaseNode::INIT_OK) { | |
1164 NOTREACHED(); | |
1165 continue; | |
1166 } | |
1167 if (child.GetIsFolder()) { | |
1168 to_visit.push(child.GetFirstChildId()); | |
1169 } | |
1170 if (child.GetEntry()->Get(syncable::UNIQUE_SERVER_TAG).empty()) { | |
1171 // Rewrite the specifics of the node with encrypted data if necessary | |
1172 // (only rewrite the non-unique folders). | |
1173 child.ResetFromSpecifics(); | |
1174 } | |
1175 to_visit.push(child.GetSuccessorId()); | |
1176 } | |
1177 } | |
1178 | |
1179 // Passwords are encrypted with their own legacy scheme. Passwords are always | |
1180 // encrypted so we don't need to check GetEncryptedTypes() here. | |
1181 ReadNode passwords_root(trans); | |
1182 std::string passwords_tag = ModelTypeToRootTag(PASSWORDS); | |
1183 if (passwords_root.InitByTagLookup(passwords_tag) == BaseNode::INIT_OK) { | |
1184 int64 child_id = passwords_root.GetFirstChildId(); | |
1185 while (child_id != kInvalidId) { | |
1186 WriteNode child(trans); | |
1187 if (child.InitByIdLookup(child_id) != BaseNode::INIT_OK) { | |
1188 NOTREACHED(); | |
1189 return; | |
1190 } | |
1191 child.SetPasswordSpecifics(child.GetPasswordSpecifics()); | |
1192 child_id = child.GetSuccessorId(); | |
1193 } | |
1194 } | |
1195 | |
1196 // NOTE: We notify from within a transaction. | |
1197 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
1198 OnEncryptionComplete()); | |
1199 } | |
1200 | |
1201 void SyncManagerImpl::AddObserver(SyncManager::Observer* observer) { | 692 void SyncManagerImpl::AddObserver(SyncManager::Observer* observer) { |
1202 DCHECK(thread_checker_.CalledOnValidThread()); | 693 DCHECK(thread_checker_.CalledOnValidThread()); |
1203 observers_.AddObserver(observer); | 694 observers_.AddObserver(observer); |
1204 } | 695 } |
1205 | 696 |
1206 void SyncManagerImpl::RemoveObserver(SyncManager::Observer* observer) { | 697 void SyncManagerImpl::RemoveObserver(SyncManager::Observer* observer) { |
1207 DCHECK(thread_checker_.CalledOnValidThread()); | 698 DCHECK(thread_checker_.CalledOnValidThread()); |
1208 observers_.RemoveObserver(observer); | 699 observers_.RemoveObserver(observer); |
1209 } | 700 } |
1210 | 701 |
1211 void SyncManagerImpl::StopSyncingForShutdown(const base::Closure& callback) { | 702 void SyncManagerImpl::StopSyncingForShutdown(const base::Closure& callback) { |
1212 DVLOG(2) << "StopSyncingForShutdown"; | 703 DVLOG(2) << "StopSyncingForShutdown"; |
1213 scheduler_->RequestStop(callback); | 704 scheduler_->RequestStop(callback); |
1214 if (connection_manager_.get()) | 705 if (connection_manager_.get()) |
1215 connection_manager_->TerminateAllIO(); | 706 connection_manager_->TerminateAllIO(); |
1216 } | 707 } |
1217 | 708 |
1218 void SyncManagerImpl::ShutdownOnSyncThread() { | 709 void SyncManagerImpl::ShutdownOnSyncThread() { |
1219 DCHECK(thread_checker_.CalledOnValidThread()); | 710 DCHECK(thread_checker_.CalledOnValidThread()); |
1220 | 711 |
1221 // Prevent any in-flight method calls from running. Also | 712 // Prevent any in-flight method calls from running. Also |
1222 // invalidates |weak_handle_this_| and |change_observer_|. | 713 // invalidates |weak_handle_this_| and |change_observer_|. |
1223 weak_ptr_factory_.InvalidateWeakPtrs(); | 714 weak_ptr_factory_.InvalidateWeakPtrs(); |
1224 js_mutation_event_observer_.InvalidateWeakPtrs(); | 715 js_mutation_event_observer_.InvalidateWeakPtrs(); |
1225 | 716 |
1226 scheduler_.reset(); | 717 scheduler_.reset(); |
1227 session_context_.reset(); | 718 session_context_.reset(); |
1228 | 719 |
| 720 if (sync_encryption_handler_.get()) { |
| 721 sync_encryption_handler_->RemoveObserver(&debug_info_event_listener_); |
| 722 sync_encryption_handler_->RemoveObserver(this); |
| 723 } |
| 724 |
1229 SetJsEventHandler(WeakHandle<JsEventHandler>()); | 725 SetJsEventHandler(WeakHandle<JsEventHandler>()); |
1230 RemoveObserver(&js_sync_manager_observer_); | 726 RemoveObserver(&js_sync_manager_observer_); |
1231 | 727 |
1232 RemoveObserver(&debug_info_event_listener_); | 728 RemoveObserver(&debug_info_event_listener_); |
1233 | 729 |
1234 // |sync_notifier_| and |connection_manager_| may end up being NULL here in | 730 // |sync_notifier_| and |connection_manager_| may end up being NULL here in |
1235 // tests (in synchronous initialization mode). | 731 // tests (in synchronous initialization mode). |
1236 // | 732 // |
1237 // TODO(akalin): Fix this behavior. | 733 // TODO(akalin): Fix this behavior. |
1238 | 734 |
1239 if (sync_notifier_.get()) | 735 if (sync_notifier_.get()) |
1240 sync_notifier_->UnregisterHandler(this); | 736 sync_notifier_->UnregisterHandler(this); |
1241 sync_notifier_.reset(); | 737 sync_notifier_.reset(); |
1242 | 738 |
1243 if (connection_manager_.get()) | 739 if (connection_manager_.get()) |
1244 connection_manager_->RemoveListener(this); | 740 connection_manager_->RemoveListener(this); |
1245 connection_manager_.reset(); | 741 connection_manager_.reset(); |
1246 | 742 |
1247 net::NetworkChangeNotifier::RemoveIPAddressObserver(this); | 743 net::NetworkChangeNotifier::RemoveIPAddressObserver(this); |
1248 observing_ip_address_changes_ = false; | 744 observing_ip_address_changes_ = false; |
1249 | 745 |
1250 if (initialized_ && directory()) { | 746 if (initialized_ && directory()) { |
1251 { | |
1252 // Cryptographer should only be accessed while holding a | |
1253 // transaction. | |
1254 ReadTransaction trans(FROM_HERE, GetUserShare()); | |
1255 trans.GetCryptographer()->RemoveObserver(this); | |
1256 } | |
1257 directory()->SaveChanges(); | 747 directory()->SaveChanges(); |
1258 } | 748 } |
1259 | 749 |
1260 share_.directory.reset(); | 750 share_.directory.reset(); |
1261 | 751 |
1262 change_delegate_ = NULL; | 752 change_delegate_ = NULL; |
1263 | 753 |
1264 initialized_ = false; | 754 initialized_ = false; |
1265 | 755 |
1266 // We reset these here, since only now we know they will not be | 756 // We reset these here, since only now we know they will not be |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1499 void SyncManagerImpl::OnSyncEngineEvent(const SyncEngineEvent& event) { | 989 void SyncManagerImpl::OnSyncEngineEvent(const SyncEngineEvent& event) { |
1500 DCHECK(thread_checker_.CalledOnValidThread()); | 990 DCHECK(thread_checker_.CalledOnValidThread()); |
1501 // Only send an event if this is due to a cycle ending and this cycle | 991 // Only send an event if this is due to a cycle ending and this cycle |
1502 // concludes a canonical "sync" process; that is, based on what is known | 992 // concludes a canonical "sync" process; that is, based on what is known |
1503 // locally we are "all happy" and up-to-date. There may be new changes on | 993 // locally we are "all happy" and up-to-date. There may be new changes on |
1504 // the server, but we'll get them on a subsequent sync. | 994 // the server, but we'll get them on a subsequent sync. |
1505 // | 995 // |
1506 // Notifications are sent at the end of every sync cycle, regardless of | 996 // Notifications are sent at the end of every sync cycle, regardless of |
1507 // whether we should sync again. | 997 // whether we should sync again. |
1508 if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) { | 998 if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) { |
1509 { | |
1510 // Check to see if we need to notify the frontend that we have newly | |
1511 // encrypted types or that we require a passphrase. | |
1512 ReadTransaction trans(FROM_HERE, GetUserShare()); | |
1513 Cryptographer* cryptographer = trans.GetCryptographer(); | |
1514 // If we've completed a sync cycle and the cryptographer isn't ready | |
1515 // yet, prompt the user for a passphrase. | |
1516 if (cryptographer->has_pending_keys()) { | |
1517 DVLOG(1) << "OnPassPhraseRequired Sent"; | |
1518 sync_pb::EncryptedData pending_keys = cryptographer->GetPendingKeys(); | |
1519 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
1520 OnPassphraseRequired(REASON_DECRYPTION, | |
1521 pending_keys)); | |
1522 } else if (!cryptographer->is_ready() && | |
1523 event.snapshot.initial_sync_ended().Has(NIGORI)) { | |
1524 DVLOG(1) << "OnPassphraseRequired sent because cryptographer is not " | |
1525 << "ready"; | |
1526 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
1527 OnPassphraseRequired(REASON_ENCRYPTION, | |
1528 sync_pb::EncryptedData())); | |
1529 } | |
1530 | |
1531 NotifyCryptographerState(cryptographer); | |
1532 allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes()); | |
1533 } | |
1534 | |
1535 if (!initialized_) { | 999 if (!initialized_) { |
1536 LOG(INFO) << "OnSyncCycleCompleted not sent because sync api is not " | 1000 LOG(INFO) << "OnSyncCycleCompleted not sent because sync api is not " |
1537 << "initialized"; | 1001 << "initialized"; |
1538 return; | 1002 return; |
1539 } | 1003 } |
1540 | 1004 |
1541 if (!event.snapshot.has_more_to_sync()) { | 1005 if (!event.snapshot.has_more_to_sync()) { |
1542 { | |
1543 // To account for a nigori node arriving with stale/bad data, we ensure | |
1544 // that the nigori node is up to date at the end of each cycle. | |
1545 WriteTransaction trans(FROM_HERE, GetUserShare()); | |
1546 WriteNode nigori_node(&trans); | |
1547 if (nigori_node.InitByTagLookup(kNigoriTag) == BaseNode::INIT_OK) { | |
1548 Cryptographer* cryptographer = trans.GetCryptographer(); | |
1549 UpdateNigoriEncryptionState(cryptographer, &nigori_node); | |
1550 } | |
1551 } | |
1552 | |
1553 DVLOG(1) << "Sending OnSyncCycleCompleted"; | 1006 DVLOG(1) << "Sending OnSyncCycleCompleted"; |
1554 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | 1007 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, |
1555 OnSyncCycleCompleted(event.snapshot)); | 1008 OnSyncCycleCompleted(event.snapshot)); |
1556 } | 1009 } |
1557 | 1010 |
1558 // This is here for tests, which are still using p2p notifications. | 1011 // This is here for tests, which are still using p2p notifications. |
1559 // | 1012 // |
1560 // TODO(chron): Consider changing this back to track has_more_to_sync | 1013 // TODO(chron): Consider changing this back to track has_more_to_sync |
1561 // only notify peers if a successful commit has occurred. | 1014 // only notify peers if a successful commit has occurred. |
1562 bool is_notifiable_commit = | 1015 bool is_notifiable_commit = |
(...skipping 29 matching lines...) Expand all Loading... |
1592 return; | 1045 return; |
1593 } | 1046 } |
1594 | 1047 |
1595 } | 1048 } |
1596 | 1049 |
1597 void SyncManagerImpl::SetJsEventHandler( | 1050 void SyncManagerImpl::SetJsEventHandler( |
1598 const WeakHandle<JsEventHandler>& event_handler) { | 1051 const WeakHandle<JsEventHandler>& event_handler) { |
1599 js_event_handler_ = event_handler; | 1052 js_event_handler_ = event_handler; |
1600 js_sync_manager_observer_.SetJsEventHandler(js_event_handler_); | 1053 js_sync_manager_observer_.SetJsEventHandler(js_event_handler_); |
1601 js_mutation_event_observer_.SetJsEventHandler(js_event_handler_); | 1054 js_mutation_event_observer_.SetJsEventHandler(js_event_handler_); |
| 1055 js_sync_encryption_handler_observer_.SetJsEventHandler(js_event_handler_); |
1602 } | 1056 } |
1603 | 1057 |
1604 void SyncManagerImpl::ProcessJsMessage( | 1058 void SyncManagerImpl::ProcessJsMessage( |
1605 const std::string& name, const JsArgList& args, | 1059 const std::string& name, const JsArgList& args, |
1606 const WeakHandle<JsReplyHandler>& reply_handler) { | 1060 const WeakHandle<JsReplyHandler>& reply_handler) { |
1607 if (!initialized_) { | 1061 if (!initialized_) { |
1608 NOTREACHED(); | 1062 NOTREACHED(); |
1609 return; | 1063 return; |
1610 } | 1064 } |
1611 | 1065 |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1797 id, &child_handles); | 1251 id, &child_handles); |
1798 for (syncable::Directory::ChildHandles::const_iterator it = | 1252 for (syncable::Directory::ChildHandles::const_iterator it = |
1799 child_handles.begin(); it != child_handles.end(); ++it) { | 1253 child_handles.begin(); it != child_handles.end(); ++it) { |
1800 child_ids->Append(Value::CreateStringValue( | 1254 child_ids->Append(Value::CreateStringValue( |
1801 base::Int64ToString(*it))); | 1255 base::Int64ToString(*it))); |
1802 } | 1256 } |
1803 } | 1257 } |
1804 return JsArgList(&return_args); | 1258 return JsArgList(&return_args); |
1805 } | 1259 } |
1806 | 1260 |
1807 void SyncManagerImpl::OnEncryptedTypesChanged( | |
1808 ModelTypeSet encrypted_types, | |
1809 bool encrypt_everything) { | |
1810 // NOTE: We're in a transaction. | |
1811 FOR_EACH_OBSERVER( | |
1812 SyncManager::Observer, observers_, | |
1813 OnEncryptedTypesChanged(encrypted_types, encrypt_everything)); | |
1814 } | |
1815 | |
1816 void SyncManagerImpl::UpdateNotificationInfo( | 1261 void SyncManagerImpl::UpdateNotificationInfo( |
1817 const ModelTypePayloadMap& type_payloads) { | 1262 const ModelTypePayloadMap& type_payloads) { |
1818 for (ModelTypePayloadMap::const_iterator it = type_payloads.begin(); | 1263 for (ModelTypePayloadMap::const_iterator it = type_payloads.begin(); |
1819 it != type_payloads.end(); ++it) { | 1264 it != type_payloads.end(); ++it) { |
1820 NotificationInfo* info = ¬ification_info_map_[it->first]; | 1265 NotificationInfo* info = ¬ification_info_map_[it->first]; |
1821 info->total_count++; | 1266 info->total_count++; |
1822 info->payload = it->second; | 1267 info->payload = it->second; |
1823 } | 1268 } |
1824 } | 1269 } |
1825 | 1270 |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1904 found_experiment = true; | 1349 found_experiment = true; |
1905 } | 1350 } |
1906 return found_experiment; | 1351 return found_experiment; |
1907 } | 1352 } |
1908 | 1353 |
1909 bool SyncManagerImpl::HasUnsyncedItems() { | 1354 bool SyncManagerImpl::HasUnsyncedItems() { |
1910 ReadTransaction trans(FROM_HERE, GetUserShare()); | 1355 ReadTransaction trans(FROM_HERE, GetUserShare()); |
1911 return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0); | 1356 return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0); |
1912 } | 1357 } |
1913 | 1358 |
| 1359 SyncEncryptionHandler* SyncManagerImpl::GetEncryptionHandler() { |
| 1360 return sync_encryption_handler_.get(); |
| 1361 } |
| 1362 |
1914 // static. | 1363 // static. |
1915 int SyncManagerImpl::GetDefaultNudgeDelay() { | 1364 int SyncManagerImpl::GetDefaultNudgeDelay() { |
1916 return kDefaultNudgeDelayMilliseconds; | 1365 return kDefaultNudgeDelayMilliseconds; |
1917 } | 1366 } |
1918 | 1367 |
1919 // static. | 1368 // static. |
1920 int SyncManagerImpl::GetPreferencesNudgeDelay() { | 1369 int SyncManagerImpl::GetPreferencesNudgeDelay() { |
1921 return kPreferencesNudgeDelayMilliseconds; | 1370 return kPreferencesNudgeDelayMilliseconds; |
1922 } | 1371 } |
1923 | 1372 |
1924 } // namespace syncer | 1373 } // namespace syncer |
OLD | NEW |