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 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
483 UpdateCredentials(credentials); | 458 UpdateCredentials(credentials); |
484 | 459 |
485 // Cryptographer should only be accessed while holding a | 460 // Cryptographer should only be accessed while holding a |
486 // transaction. Grabbing the user share for the transaction | 461 // transaction. Grabbing the user share for the transaction |
487 // checks the initialization state, so this must come after | 462 // checks the initialization state, so this must come after |
488 // |initialized_| is set to true. | 463 // |initialized_| is set to true. |
489 ReadTransaction trans(FROM_HERE, GetUserShare()); | 464 ReadTransaction trans(FROM_HERE, GetUserShare()); |
490 trans.GetCryptographer()->Bootstrap(restored_key_for_bootstrapping); | 465 trans.GetCryptographer()->Bootstrap(restored_key_for_bootstrapping); |
491 trans.GetCryptographer()->BootstrapKeystoreKey( | 466 trans.GetCryptographer()->BootstrapKeystoreKey( |
492 restored_keystore_key_for_bootstrapping); | 467 restored_keystore_key_for_bootstrapping); |
493 trans.GetCryptographer()->AddObserver(this); | 468 |
| 469 sync_encryption_handler_.reset(new SyncEncryptionHandlerImpl( |
| 470 &share_, |
| 471 trans.GetCryptographer())); |
| 472 sync_encryption_handler_->AddObserver(this); |
| 473 sync_encryption_handler_->AddObserver(&debug_info_event_listener_); |
| 474 sync_encryption_handler_->AddObserver(&js_sync_encryption_handler_observer_); |
| 475 trans.GetCryptographer()->SetSyncEncryptionHandlerDelegate( |
| 476 sync_encryption_handler_.get()); |
494 | 477 |
495 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | 478 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, |
496 OnInitializationComplete( | 479 OnInitializationComplete( |
497 MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()), | 480 MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()), |
498 true, InitialSyncEndedTypes())); | 481 true, InitialSyncEndedTypes())); |
499 } | 482 } |
500 | 483 |
501 void SyncManagerImpl::RefreshNigori(const std::string& chrome_version, | 484 void SyncManagerImpl::UpdateSessionNameCallback( |
502 const base::Closure& done_callback) { | |
503 DCHECK(initialized_); | |
504 DCHECK(thread_checker_.CalledOnValidThread()); | |
505 GetSessionName( | |
506 blocking_task_runner_, | |
507 base::Bind( | |
508 &SyncManagerImpl::UpdateCryptographerAndNigoriCallback, | |
509 weak_ptr_factory_.GetWeakPtr(), | |
510 chrome_version, | |
511 done_callback)); | |
512 } | |
513 | |
514 void SyncManagerImpl::UpdateNigoriEncryptionState( | |
515 Cryptographer* cryptographer, | |
516 WriteNode* nigori_node) { | |
517 DCHECK(nigori_node); | |
518 sync_pb::NigoriSpecifics nigori = nigori_node->GetNigoriSpecifics(); | |
519 | |
520 if (cryptographer->is_ready() && | |
521 nigori_overwrite_count_ < kNigoriOverwriteLimit) { | |
522 // Does not modify the encrypted blob if the unencrypted data already | |
523 // matches what is about to be written. | |
524 sync_pb::EncryptedData original_keys = nigori.encrypted(); | |
525 if (!cryptographer->GetKeys(nigori.mutable_encrypted())) | |
526 NOTREACHED(); | |
527 | |
528 if (nigori.encrypted().SerializeAsString() != | |
529 original_keys.SerializeAsString()) { | |
530 // We've updated the nigori node's encryption keys. In order to prevent | |
531 // a possible looping of two clients constantly overwriting each other, | |
532 // we limit the absolute number of overwrites per client instantiation. | |
533 nigori_overwrite_count_++; | |
534 UMA_HISTOGRAM_COUNTS("Sync.AutoNigoriOverwrites", | |
535 nigori_overwrite_count_); | |
536 } | |
537 | |
538 // Note: we don't try to set using_explicit_passphrase here since if that | |
539 // is lost the user can always set it again. The main point is to preserve | |
540 // the encryption keys so all data remains decryptable. | |
541 } | |
542 cryptographer->UpdateNigoriFromEncryptedTypes(&nigori); | |
543 | |
544 // If nothing has changed, this is a no-op. | |
545 nigori_node->SetNigoriSpecifics(nigori); | |
546 } | |
547 | |
548 void SyncManagerImpl::UpdateCryptographerAndNigoriCallback( | |
549 const std::string& chrome_version, | 485 const std::string& chrome_version, |
550 const base::Closure& done_callback, | |
551 const std::string& session_name) { | 486 const std::string& session_name) { |
552 if (!directory()->initial_sync_ended_for_type(NIGORI)) { | 487 WriteTransaction trans(FROM_HERE, GetUserShare()); |
553 done_callback.Run(); // Should only happen during first time sync. | 488 WriteNode node(&trans); |
| 489 // TODO(rlarocque): switch to device info node. |
| 490 if (node.InitByTagLookup(syncer::kNigoriTag) != syncer::BaseNode::INIT_OK) { |
554 return; | 491 return; |
555 } | 492 } |
556 | 493 |
557 bool success = false; | 494 sync_pb::NigoriSpecifics nigori(node.GetNigoriSpecifics()); |
558 { | 495 // Add or update device information. |
559 WriteTransaction trans(FROM_HERE, GetUserShare()); | 496 bool contains_this_device = false; |
560 Cryptographer* cryptographer = trans.GetCryptographer(); | 497 for (int i = 0; i < nigori.device_information_size(); ++i) { |
561 WriteNode node(&trans); | 498 const sync_pb::DeviceInformation& device_information = |
562 | 499 nigori.device_information(i); |
563 if (node.InitByTagLookup(kNigoriTag) == BaseNode::INIT_OK) { | 500 if (device_information.cache_guid() == directory()->cache_guid()) { |
564 sync_pb::NigoriSpecifics nigori(node.GetNigoriSpecifics()); | 501 // Update the version number in case it changed due to an update. |
565 Cryptographer::UpdateResult result = cryptographer->Update(nigori); | 502 if (device_information.chrome_version() != chrome_version) { |
566 if (result == Cryptographer::NEEDS_PASSPHRASE) { | 503 sync_pb::DeviceInformation* mutable_device_information = |
567 sync_pb::EncryptedData pending_keys; | 504 nigori.mutable_device_information(i); |
568 if (cryptographer->has_pending_keys()) | 505 mutable_device_information->set_chrome_version( |
569 pending_keys = cryptographer->GetPendingKeys(); | 506 chrome_version); |
570 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
571 OnPassphraseRequired(REASON_DECRYPTION, | |
572 pending_keys)); | |
573 } | 507 } |
574 | 508 contains_this_device = true; |
575 // Add or update device information. | |
576 bool contains_this_device = false; | |
577 for (int i = 0; i < nigori.device_information_size(); ++i) { | |
578 const sync_pb::DeviceInformation& device_information = | |
579 nigori.device_information(i); | |
580 if (device_information.cache_guid() == directory()->cache_guid()) { | |
581 // Update the version number in case it changed due to an update. | |
582 if (device_information.chrome_version() != chrome_version) { | |
583 sync_pb::DeviceInformation* mutable_device_information = | |
584 nigori.mutable_device_information(i); | |
585 mutable_device_information->set_chrome_version( | |
586 chrome_version); | |
587 } | |
588 contains_this_device = true; | |
589 } | |
590 } | |
591 | |
592 if (!contains_this_device) { | |
593 sync_pb::DeviceInformation* device_information = | |
594 nigori.add_device_information(); | |
595 device_information->set_cache_guid(directory()->cache_guid()); | |
596 #if defined(OS_CHROMEOS) | |
597 device_information->set_platform("ChromeOS"); | |
598 #elif defined(OS_LINUX) | |
599 device_information->set_platform("Linux"); | |
600 #elif defined(OS_MACOSX) | |
601 device_information->set_platform("Mac"); | |
602 #elif defined(OS_WIN) | |
603 device_information->set_platform("Windows"); | |
604 #endif | |
605 device_information->set_name(session_name); | |
606 device_information->set_chrome_version(chrome_version); | |
607 } | |
608 // Disabled to avoid nigori races. TODO(zea): re-enable. crbug.com/122837 | |
609 // node.SetNigoriSpecifics(nigori); | |
610 | |
611 // Make sure the nigori node has the up to date encryption info. | |
612 UpdateNigoriEncryptionState(cryptographer, &node); | |
613 | |
614 NotifyCryptographerState(cryptographer); | |
615 allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes()); | |
616 | |
617 success = cryptographer->is_ready(); | |
618 } else { | |
619 NOTREACHED(); | |
620 } | 509 } |
621 } | 510 } |
622 | 511 |
623 if (success) | 512 if (!contains_this_device) { |
624 RefreshEncryption(); | 513 sync_pb::DeviceInformation* device_information = |
625 done_callback.Run(); | 514 nigori.add_device_information(); |
| 515 device_information->set_cache_guid(directory()->cache_guid()); |
| 516 #if defined(OS_CHROMEOS) |
| 517 device_information->set_platform("ChromeOS"); |
| 518 #elif defined(OS_LINUX) |
| 519 device_information->set_platform("Linux"); |
| 520 #elif defined(OS_MACOSX) |
| 521 device_information->set_platform("Mac"); |
| 522 #elif defined(OS_WIN) |
| 523 device_information->set_platform("Windows"); |
| 524 #endif |
| 525 device_information->set_name(session_name); |
| 526 device_information->set_chrome_version(chrome_version); |
| 527 } |
| 528 node.SetNigoriSpecifics(nigori); |
626 } | 529 } |
627 | 530 |
628 void SyncManagerImpl::NotifyCryptographerState(Cryptographer * cryptographer) { | 531 |
629 // TODO(lipalani): Explore the possibility of hooking this up to | 532 void SyncManagerImpl::OnPassphraseRequired( |
630 // SyncManager::Observer and making |AllStatus| a listener for that. | 533 PassphraseRequiredReason reason, |
| 534 const sync_pb::EncryptedData& pending_keys) { |
| 535 // Does nothing. |
| 536 } |
| 537 |
| 538 void SyncManagerImpl::OnPassphraseAccepted() { |
| 539 // Does nothing. |
| 540 } |
| 541 |
| 542 void SyncManagerImpl::OnBootstrapTokenUpdated( |
| 543 const std::string& bootstrap_token) { |
| 544 // Does nothing. |
| 545 } |
| 546 |
| 547 void SyncManagerImpl::OnEncryptedTypesChanged(ModelTypeSet encrypted_types, |
| 548 bool encrypt_everything) { |
| 549 allstatus_.SetEncryptedTypes(encrypted_types); |
| 550 } |
| 551 |
| 552 void SyncManagerImpl::OnEncryptionComplete() { |
| 553 // Does nothing. |
| 554 } |
| 555 |
| 556 void SyncManagerImpl::OnCryptographerStateChanged( |
| 557 Cryptographer* cryptographer) { |
631 allstatus_.SetCryptographerReady(cryptographer->is_ready()); | 558 allstatus_.SetCryptographerReady(cryptographer->is_ready()); |
632 allstatus_.SetCryptoHasPendingKeys(cryptographer->has_pending_keys()); | 559 allstatus_.SetCryptoHasPendingKeys(cryptographer->has_pending_keys()); |
633 debug_info_event_listener_.SetCryptographerReady(cryptographer->is_ready()); | |
634 debug_info_event_listener_.SetCrytographerHasPendingKeys( | |
635 cryptographer->has_pending_keys()); | |
636 } | 560 } |
637 | 561 |
638 void SyncManagerImpl::StartSyncingNormally( | 562 void SyncManagerImpl::StartSyncingNormally( |
639 const ModelSafeRoutingInfo& routing_info) { | 563 const ModelSafeRoutingInfo& routing_info) { |
640 // Start the sync scheduler. | 564 // Start the sync scheduler. |
641 // TODO(sync): We always want the newest set of routes when we switch back | 565 // TODO(sync): We always want the newest set of routes when we switch back |
642 // to normal mode. Figure out how to enforce set_routing_info is always | 566 // to normal mode. Figure out how to enforce set_routing_info is always |
643 // appropriately set and that it's only modified when switching to normal | 567 // appropriately set and that it's only modified when switching to normal |
644 // mode. | 568 // mode. |
645 DCHECK(thread_checker_.CalledOnValidThread()); | 569 DCHECK(thread_checker_.CalledOnValidThread()); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
738 ModelTypeSetToObjectIdSet(enabled_types)); | 662 ModelTypeSetToObjectIdSet(enabled_types)); |
739 } | 663 } |
740 | 664 |
741 void SyncManagerImpl::UpdateRegisteredInvalidationIds( | 665 void SyncManagerImpl::UpdateRegisteredInvalidationIds( |
742 SyncNotifierObserver* handler, | 666 SyncNotifierObserver* handler, |
743 const ObjectIdSet& ids) { | 667 const ObjectIdSet& ids) { |
744 DCHECK(thread_checker_.CalledOnValidThread()); | 668 DCHECK(thread_checker_.CalledOnValidThread()); |
745 sync_notifier_->UpdateRegisteredIds(handler, ids); | 669 sync_notifier_->UpdateRegisteredIds(handler, ids); |
746 } | 670 } |
747 | 671 |
748 void SyncManagerImpl::SetEncryptionPassphrase( | |
749 const std::string& passphrase, | |
750 bool is_explicit) { | |
751 DCHECK(thread_checker_.CalledOnValidThread()); | |
752 // We do not accept empty passphrases. | |
753 if (passphrase.empty()) { | |
754 NOTREACHED() << "Cannot encrypt with an empty passphrase."; | |
755 return; | |
756 } | |
757 | |
758 // All accesses to the cryptographer are protected by a transaction. | |
759 WriteTransaction trans(FROM_HERE, GetUserShare()); | |
760 Cryptographer* cryptographer = trans.GetCryptographer(); | |
761 KeyParams key_params = {"localhost", "dummy", passphrase}; | |
762 WriteNode node(&trans); | |
763 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { | |
764 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS. | |
765 NOTREACHED(); | |
766 return; | |
767 } | |
768 | |
769 bool nigori_has_explicit_passphrase = | |
770 node.GetNigoriSpecifics().using_explicit_passphrase(); | |
771 std::string bootstrap_token; | |
772 sync_pb::EncryptedData pending_keys; | |
773 if (cryptographer->has_pending_keys()) | |
774 pending_keys = cryptographer->GetPendingKeys(); | |
775 bool success = false; | |
776 | |
777 | |
778 // There are six cases to handle here: | |
779 // 1. The user has no pending keys and is setting their current GAIA password | |
780 // as the encryption passphrase. This happens either during first time sync | |
781 // with a clean profile, or after re-authenticating on a profile that was | |
782 // already signed in with the cryptographer ready. | |
783 // 2. The user has no pending keys, and is overwriting an (already provided) | |
784 // implicit passphrase with an explicit (custom) passphrase. | |
785 // 3. The user has pending keys for an explicit passphrase that is somehow set | |
786 // to their current GAIA passphrase. | |
787 // 4. The user has pending keys encrypted with their current GAIA passphrase | |
788 // and the caller passes in the current GAIA passphrase. | |
789 // 5. The user has pending keys encrypted with an older GAIA passphrase | |
790 // and the caller passes in the current GAIA passphrase. | |
791 // 6. The user has previously done encryption with an explicit passphrase. | |
792 // Furthermore, we enforce the fact that the bootstrap encryption token will | |
793 // always be derived from the newest GAIA password if the account is using | |
794 // an implicit passphrase (even if the data is encrypted with an old GAIA | |
795 // password). If the account is using an explicit (custom) passphrase, the | |
796 // bootstrap token will be derived from the most recently provided explicit | |
797 // passphrase (that was able to decrypt the data). | |
798 if (!nigori_has_explicit_passphrase) { | |
799 if (!cryptographer->has_pending_keys()) { | |
800 if (cryptographer->AddKey(key_params)) { | |
801 // Case 1 and 2. We set a new GAIA passphrase when there are no pending | |
802 // keys (1), or overwriting an implicit passphrase with a new explicit | |
803 // one (2) when there are no pending keys. | |
804 DVLOG(1) << "Setting " << (is_explicit ? "explicit" : "implicit" ) | |
805 << " passphrase for encryption."; | |
806 cryptographer->GetBootstrapToken(&bootstrap_token); | |
807 success = true; | |
808 } else { | |
809 NOTREACHED() << "Failed to add key to cryptographer."; | |
810 success = false; | |
811 } | |
812 } else { // cryptographer->has_pending_keys() == true | |
813 if (is_explicit) { | |
814 // This can only happen if the nigori node is updated with a new | |
815 // implicit passphrase while a client is attempting to set a new custom | |
816 // passphrase (race condition). | |
817 DVLOG(1) << "Failing because an implicit passphrase is already set."; | |
818 success = false; | |
819 } else { // is_explicit == false | |
820 if (cryptographer->DecryptPendingKeys(key_params)) { | |
821 // Case 4. We successfully decrypted with the implicit GAIA passphrase | |
822 // passed in. | |
823 DVLOG(1) << "Implicit internal passphrase accepted for decryption."; | |
824 cryptographer->GetBootstrapToken(&bootstrap_token); | |
825 success = true; | |
826 } else { | |
827 // Case 5. Encryption was done with an old GAIA password, but we were | |
828 // provided with the current GAIA password. We need to generate a new | |
829 // bootstrap token to preserve it. We build a temporary cryptographer | |
830 // to allow us to extract these params without polluting our current | |
831 // cryptographer. | |
832 DVLOG(1) << "Implicit internal passphrase failed to decrypt, adding " | |
833 << "anyways as default passphrase and persisting via " | |
834 << "bootstrap token."; | |
835 Cryptographer temp_cryptographer(encryptor_); | |
836 temp_cryptographer.AddKey(key_params); | |
837 temp_cryptographer.GetBootstrapToken(&bootstrap_token); | |
838 // We then set the new passphrase as the default passphrase of the | |
839 // real cryptographer, even though we have pending keys. This is safe, | |
840 // as although Cryptographer::is_initialized() will now be true, | |
841 // is_ready() will remain false due to having pending keys. | |
842 cryptographer->AddKey(key_params); | |
843 success = false; | |
844 } | |
845 } // is_explicit | |
846 } // cryptographer->has_pending_keys() | |
847 } else { // nigori_has_explicit_passphrase == true | |
848 // Case 6. We do not want to override a previously set explicit passphrase, | |
849 // so we return a failure. | |
850 DVLOG(1) << "Failing because an explicit passphrase is already set."; | |
851 success = false; | |
852 } | |
853 | |
854 DVLOG_IF(1, !success) | |
855 << "Failure in SetEncryptionPassphrase; notifying and returning."; | |
856 DVLOG_IF(1, success) | |
857 << "Successfully set encryption passphrase; updating nigori and " | |
858 "reencrypting."; | |
859 | |
860 FinishSetPassphrase( | |
861 success, bootstrap_token, is_explicit, &trans, &node); | |
862 } | |
863 | |
864 void SyncManagerImpl::SetDecryptionPassphrase( | |
865 const std::string& passphrase) { | |
866 DCHECK(thread_checker_.CalledOnValidThread()); | |
867 // We do not accept empty passphrases. | |
868 if (passphrase.empty()) { | |
869 NOTREACHED() << "Cannot decrypt with an empty passphrase."; | |
870 return; | |
871 } | |
872 | |
873 // All accesses to the cryptographer are protected by a transaction. | |
874 WriteTransaction trans(FROM_HERE, GetUserShare()); | |
875 Cryptographer* cryptographer = trans.GetCryptographer(); | |
876 KeyParams key_params = {"localhost", "dummy", passphrase}; | |
877 WriteNode node(&trans); | |
878 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { | |
879 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS. | |
880 NOTREACHED(); | |
881 return; | |
882 } | |
883 | |
884 if (!cryptographer->has_pending_keys()) { | |
885 // Note that this *can* happen in a rare situation where data is | |
886 // re-encrypted on another client while a SetDecryptionPassphrase() call is | |
887 // in-flight on this client. It is rare enough that we choose to do nothing. | |
888 NOTREACHED() << "Attempt to set decryption passphrase failed because there " | |
889 << "were no pending keys."; | |
890 return; | |
891 } | |
892 | |
893 bool nigori_has_explicit_passphrase = | |
894 node.GetNigoriSpecifics().using_explicit_passphrase(); | |
895 std::string bootstrap_token; | |
896 sync_pb::EncryptedData pending_keys; | |
897 pending_keys = cryptographer->GetPendingKeys(); | |
898 bool success = false; | |
899 | |
900 // There are three cases to handle here: | |
901 // 7. We're using the current GAIA password to decrypt the pending keys. This | |
902 // happens when signing in to an account with a previously set implicit | |
903 // passphrase, where the data is already encrypted with the newest GAIA | |
904 // password. | |
905 // 8. The user is providing an old GAIA password to decrypt the pending keys. | |
906 // In this case, the user is using an implicit passphrase, but has changed | |
907 // their password since they last encrypted their data, and therefore | |
908 // their current GAIA password was unable to decrypt the data. This will | |
909 // happen when the user is setting up a new profile with a previously | |
910 // encrypted account (after changing passwords). | |
911 // 9. The user is providing a previously set explicit passphrase to decrypt | |
912 // the pending keys. | |
913 if (!nigori_has_explicit_passphrase) { | |
914 if (cryptographer->is_initialized()) { | |
915 // We only want to change the default encryption key to the pending | |
916 // one if the pending keybag already contains the current default. | |
917 // This covers the case where a different client re-encrypted | |
918 // everything with a newer gaia passphrase (and hence the keybag | |
919 // contains keys from all previously used gaia passphrases). | |
920 // Otherwise, we're in a situation where the pending keys are | |
921 // encrypted with an old gaia passphrase, while the default is the | |
922 // current gaia passphrase. In that case, we preserve the default. | |
923 Cryptographer temp_cryptographer(encryptor_); | |
924 temp_cryptographer.SetPendingKeys(cryptographer->GetPendingKeys()); | |
925 if (temp_cryptographer.DecryptPendingKeys(key_params)) { | |
926 // Check to see if the pending bag of keys contains the current | |
927 // default key. | |
928 sync_pb::EncryptedData encrypted; | |
929 cryptographer->GetKeys(&encrypted); | |
930 if (temp_cryptographer.CanDecrypt(encrypted)) { | |
931 DVLOG(1) << "Implicit user provided passphrase accepted for " | |
932 << "decryption, overwriting default."; | |
933 // Case 7. The pending keybag contains the current default. Go ahead | |
934 // and update the cryptographer, letting the default change. | |
935 cryptographer->DecryptPendingKeys(key_params); | |
936 cryptographer->GetBootstrapToken(&bootstrap_token); | |
937 success = true; | |
938 } else { | |
939 // Case 8. The pending keybag does not contain the current default | |
940 // encryption key. We decrypt the pending keys here, and in | |
941 // FinishSetPassphrase, re-encrypt everything with the current GAIA | |
942 // passphrase instead of the passphrase just provided by the user. | |
943 DVLOG(1) << "Implicit user provided passphrase accepted for " | |
944 << "decryption, restoring implicit internal passphrase " | |
945 << "as default."; | |
946 std::string bootstrap_token_from_current_key; | |
947 cryptographer->GetBootstrapToken( | |
948 &bootstrap_token_from_current_key); | |
949 cryptographer->DecryptPendingKeys(key_params); | |
950 // Overwrite the default from the pending keys. | |
951 cryptographer->AddKeyFromBootstrapToken( | |
952 bootstrap_token_from_current_key); | |
953 success = true; | |
954 } | |
955 } else { // !temp_cryptographer.DecryptPendingKeys(..) | |
956 DVLOG(1) << "Implicit user provided passphrase failed to decrypt."; | |
957 success = false; | |
958 } // temp_cryptographer.DecryptPendingKeys(...) | |
959 } else { // cryptographer->is_initialized() == false | |
960 if (cryptographer->DecryptPendingKeys(key_params)) { | |
961 // This can happpen in two cases: | |
962 // - First time sync on android, where we'll never have a | |
963 // !user_provided passphrase. | |
964 // - This is a restart for a client that lost their bootstrap token. | |
965 // In both cases, we should go ahead and initialize the cryptographer | |
966 // and persist the new bootstrap token. | |
967 // | |
968 // Note: at this point, we cannot distinguish between cases 7 and 8 | |
969 // above. This user provided passphrase could be the current or the | |
970 // old. But, as long as we persist the token, there's nothing more | |
971 // we can do. | |
972 cryptographer->GetBootstrapToken(&bootstrap_token); | |
973 DVLOG(1) << "Implicit user provided passphrase accepted, initializing" | |
974 << " cryptographer."; | |
975 success = true; | |
976 } else { | |
977 DVLOG(1) << "Implicit user provided passphrase failed to decrypt."; | |
978 success = false; | |
979 } | |
980 } // cryptographer->is_initialized() | |
981 } else { // nigori_has_explicit_passphrase == true | |
982 // Case 9. Encryption was done with an explicit passphrase, and we decrypt | |
983 // with the passphrase provided by the user. | |
984 if (cryptographer->DecryptPendingKeys(key_params)) { | |
985 DVLOG(1) << "Explicit passphrase accepted for decryption."; | |
986 cryptographer->GetBootstrapToken(&bootstrap_token); | |
987 success = true; | |
988 } else { | |
989 DVLOG(1) << "Explicit passphrase failed to decrypt."; | |
990 success = false; | |
991 } | |
992 } // nigori_has_explicit_passphrase | |
993 | |
994 DVLOG_IF(1, !success) | |
995 << "Failure in SetDecryptionPassphrase; notifying and returning."; | |
996 DVLOG_IF(1, success) | |
997 << "Successfully set decryption passphrase; updating nigori and " | |
998 "reencrypting."; | |
999 | |
1000 FinishSetPassphrase(success, | |
1001 bootstrap_token, | |
1002 nigori_has_explicit_passphrase, | |
1003 &trans, | |
1004 &node); | |
1005 } | |
1006 | |
1007 void SyncManagerImpl::FinishSetPassphrase( | |
1008 bool success, | |
1009 const std::string& bootstrap_token, | |
1010 bool is_explicit, | |
1011 WriteTransaction* trans, | |
1012 WriteNode* nigori_node) { | |
1013 Cryptographer* cryptographer = trans->GetCryptographer(); | |
1014 NotifyCryptographerState(cryptographer); | |
1015 | |
1016 // It's possible we need to change the bootstrap token even if we failed to | |
1017 // set the passphrase (for example if we need to preserve the new GAIA | |
1018 // passphrase). | |
1019 if (!bootstrap_token.empty()) { | |
1020 DVLOG(1) << "Bootstrap token updated."; | |
1021 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
1022 OnBootstrapTokenUpdated(bootstrap_token)); | |
1023 } | |
1024 | |
1025 if (!success) { | |
1026 if (cryptographer->is_ready()) { | |
1027 LOG(ERROR) << "Attempt to change passphrase failed while cryptographer " | |
1028 << "was ready."; | |
1029 } else if (cryptographer->has_pending_keys()) { | |
1030 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
1031 OnPassphraseRequired(REASON_DECRYPTION, | |
1032 cryptographer->GetPendingKeys())); | |
1033 } else { | |
1034 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
1035 OnPassphraseRequired(REASON_ENCRYPTION, | |
1036 sync_pb::EncryptedData())); | |
1037 } | |
1038 return; | |
1039 } | |
1040 | |
1041 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
1042 OnPassphraseAccepted()); | |
1043 DCHECK(cryptographer->is_ready()); | |
1044 | |
1045 // TODO(tim): Bug 58231. It would be nice if setting a passphrase didn't | |
1046 // require messing with the Nigori node, because we can't set a passphrase | |
1047 // until download conditions are met vs Cryptographer init. It seems like | |
1048 // it's safe to defer this work. | |
1049 sync_pb::NigoriSpecifics specifics(nigori_node->GetNigoriSpecifics()); | |
1050 // Does not modify specifics.encrypted() if the original decrypted data was | |
1051 // the same. | |
1052 if (!cryptographer->GetKeys(specifics.mutable_encrypted())) { | |
1053 NOTREACHED(); | |
1054 return; | |
1055 } | |
1056 specifics.set_using_explicit_passphrase(is_explicit); | |
1057 nigori_node->SetNigoriSpecifics(specifics); | |
1058 | |
1059 // Does nothing if everything is already encrypted or the cryptographer has | |
1060 // pending keys. | |
1061 ReEncryptEverything(trans); | |
1062 } | |
1063 | |
1064 bool SyncManagerImpl::IsUsingExplicitPassphrase() { | |
1065 ReadTransaction trans(FROM_HERE, &share_); | |
1066 ReadNode node(&trans); | |
1067 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { | |
1068 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS. | |
1069 NOTREACHED(); | |
1070 return false; | |
1071 } | |
1072 | |
1073 return node.GetNigoriSpecifics().using_explicit_passphrase(); | |
1074 } | |
1075 | |
1076 bool SyncManagerImpl::GetKeystoreKeyBootstrapToken(std::string* token) { | 672 bool SyncManagerImpl::GetKeystoreKeyBootstrapToken(std::string* token) { |
1077 ReadTransaction trans(FROM_HERE, GetUserShare()); | 673 ReadTransaction trans(FROM_HERE, GetUserShare()); |
1078 return trans.GetCryptographer()->GetKeystoreKeyBootstrapToken(token); | 674 return trans.GetCryptographer()->GetKeystoreKeyBootstrapToken(token); |
1079 } | 675 } |
1080 | 676 |
1081 void SyncManagerImpl::RefreshEncryption() { | |
1082 DCHECK(initialized_); | |
1083 | |
1084 WriteTransaction trans(FROM_HERE, GetUserShare()); | |
1085 WriteNode node(&trans); | |
1086 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { | |
1087 NOTREACHED() << "Unable to set encrypted datatypes because Nigori node not " | |
1088 << "found."; | |
1089 return; | |
1090 } | |
1091 | |
1092 Cryptographer* cryptographer = trans.GetCryptographer(); | |
1093 | |
1094 if (!cryptographer->is_ready()) { | |
1095 DVLOG(1) << "Attempting to encrypt datatypes when cryptographer not " | |
1096 << "initialized, prompting for passphrase."; | |
1097 // TODO(zea): this isn't really decryption, but that's the only way we have | |
1098 // to prompt the user for a passsphrase. See http://crbug.com/91379. | |
1099 sync_pb::EncryptedData pending_keys; | |
1100 if (cryptographer->has_pending_keys()) | |
1101 pending_keys = cryptographer->GetPendingKeys(); | |
1102 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
1103 OnPassphraseRequired(REASON_DECRYPTION, | |
1104 pending_keys)); | |
1105 return; | |
1106 } | |
1107 | |
1108 UpdateNigoriEncryptionState(cryptographer, &node); | |
1109 | |
1110 allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes()); | |
1111 | |
1112 // We reencrypt everything regardless of whether the set of encrypted | |
1113 // types changed to ensure that any stray unencrypted entries are overwritten. | |
1114 ReEncryptEverything(&trans); | |
1115 } | |
1116 | |
1117 // This function iterates over all encrypted types. There are many scenarios in | |
1118 // which data for some or all types is not currently available. In that case, | |
1119 // the lookup of the root node will fail and we will skip encryption for that | |
1120 // type. | |
1121 void SyncManagerImpl::ReEncryptEverything( | |
1122 WriteTransaction* trans) { | |
1123 Cryptographer* cryptographer = trans->GetCryptographer(); | |
1124 if (!cryptographer || !cryptographer->is_ready()) | |
1125 return; | |
1126 ModelTypeSet encrypted_types = GetEncryptedTypes(trans); | |
1127 for (ModelTypeSet::Iterator iter = encrypted_types.First(); | |
1128 iter.Good(); iter.Inc()) { | |
1129 if (iter.Get() == PASSWORDS || iter.Get() == NIGORI) | |
1130 continue; // These types handle encryption differently. | |
1131 | |
1132 ReadNode type_root(trans); | |
1133 std::string tag = ModelTypeToRootTag(iter.Get()); | |
1134 if (type_root.InitByTagLookup(tag) != BaseNode::INIT_OK) | |
1135 continue; // Don't try to reencrypt if the type's data is unavailable. | |
1136 | |
1137 // Iterate through all children of this datatype. | |
1138 std::queue<int64> to_visit; | |
1139 int64 child_id = type_root.GetFirstChildId(); | |
1140 to_visit.push(child_id); | |
1141 while (!to_visit.empty()) { | |
1142 child_id = to_visit.front(); | |
1143 to_visit.pop(); | |
1144 if (child_id == kInvalidId) | |
1145 continue; | |
1146 | |
1147 WriteNode child(trans); | |
1148 if (child.InitByIdLookup(child_id) != BaseNode::INIT_OK) { | |
1149 NOTREACHED(); | |
1150 continue; | |
1151 } | |
1152 if (child.GetIsFolder()) { | |
1153 to_visit.push(child.GetFirstChildId()); | |
1154 } | |
1155 if (child.GetEntry()->Get(syncable::UNIQUE_SERVER_TAG).empty()) { | |
1156 // Rewrite the specifics of the node with encrypted data if necessary | |
1157 // (only rewrite the non-unique folders). | |
1158 child.ResetFromSpecifics(); | |
1159 } | |
1160 to_visit.push(child.GetSuccessorId()); | |
1161 } | |
1162 } | |
1163 | |
1164 // Passwords are encrypted with their own legacy scheme. Passwords are always | |
1165 // encrypted so we don't need to check GetEncryptedTypes() here. | |
1166 ReadNode passwords_root(trans); | |
1167 std::string passwords_tag = ModelTypeToRootTag(PASSWORDS); | |
1168 if (passwords_root.InitByTagLookup(passwords_tag) == BaseNode::INIT_OK) { | |
1169 int64 child_id = passwords_root.GetFirstChildId(); | |
1170 while (child_id != kInvalidId) { | |
1171 WriteNode child(trans); | |
1172 if (child.InitByIdLookup(child_id) != BaseNode::INIT_OK) { | |
1173 NOTREACHED(); | |
1174 return; | |
1175 } | |
1176 child.SetPasswordSpecifics(child.GetPasswordSpecifics()); | |
1177 child_id = child.GetSuccessorId(); | |
1178 } | |
1179 } | |
1180 | |
1181 // NOTE: We notify from within a transaction. | |
1182 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
1183 OnEncryptionComplete()); | |
1184 } | |
1185 | |
1186 void SyncManagerImpl::AddObserver(SyncManager::Observer* observer) { | 677 void SyncManagerImpl::AddObserver(SyncManager::Observer* observer) { |
1187 DCHECK(thread_checker_.CalledOnValidThread()); | 678 DCHECK(thread_checker_.CalledOnValidThread()); |
1188 observers_.AddObserver(observer); | 679 observers_.AddObserver(observer); |
1189 } | 680 } |
1190 | 681 |
1191 void SyncManagerImpl::RemoveObserver(SyncManager::Observer* observer) { | 682 void SyncManagerImpl::RemoveObserver(SyncManager::Observer* observer) { |
1192 DCHECK(thread_checker_.CalledOnValidThread()); | 683 DCHECK(thread_checker_.CalledOnValidThread()); |
1193 observers_.RemoveObserver(observer); | 684 observers_.RemoveObserver(observer); |
1194 } | 685 } |
1195 | 686 |
1196 void SyncManagerImpl::StopSyncingForShutdown(const base::Closure& callback) { | 687 void SyncManagerImpl::StopSyncingForShutdown(const base::Closure& callback) { |
1197 DVLOG(2) << "StopSyncingForShutdown"; | 688 DVLOG(2) << "StopSyncingForShutdown"; |
1198 scheduler_->RequestStop(callback); | 689 scheduler_->RequestStop(callback); |
1199 if (connection_manager_.get()) | 690 if (connection_manager_.get()) |
1200 connection_manager_->TerminateAllIO(); | 691 connection_manager_->TerminateAllIO(); |
1201 } | 692 } |
1202 | 693 |
1203 void SyncManagerImpl::ShutdownOnSyncThread() { | 694 void SyncManagerImpl::ShutdownOnSyncThread() { |
1204 DCHECK(thread_checker_.CalledOnValidThread()); | 695 DCHECK(thread_checker_.CalledOnValidThread()); |
1205 | 696 |
1206 // Prevent any in-flight method calls from running. Also | 697 // Prevent any in-flight method calls from running. Also |
1207 // invalidates |weak_handle_this_| and |change_observer_|. | 698 // invalidates |weak_handle_this_| and |change_observer_|. |
1208 weak_ptr_factory_.InvalidateWeakPtrs(); | 699 weak_ptr_factory_.InvalidateWeakPtrs(); |
1209 js_mutation_event_observer_.InvalidateWeakPtrs(); | 700 js_mutation_event_observer_.InvalidateWeakPtrs(); |
1210 | 701 |
1211 scheduler_.reset(); | 702 scheduler_.reset(); |
1212 session_context_.reset(); | 703 session_context_.reset(); |
1213 | 704 |
| 705 if (sync_encryption_handler_.get()) { |
| 706 sync_encryption_handler_->RemoveObserver(&debug_info_event_listener_); |
| 707 sync_encryption_handler_->RemoveObserver(this); |
| 708 } |
| 709 |
1214 SetJsEventHandler(WeakHandle<JsEventHandler>()); | 710 SetJsEventHandler(WeakHandle<JsEventHandler>()); |
1215 RemoveObserver(&js_sync_manager_observer_); | 711 RemoveObserver(&js_sync_manager_observer_); |
1216 | 712 |
1217 RemoveObserver(&debug_info_event_listener_); | 713 RemoveObserver(&debug_info_event_listener_); |
1218 | 714 |
1219 if (sync_notifier_.get()) { | 715 if (sync_notifier_.get()) { |
1220 sync_notifier_->UpdateRegisteredIds(this, ObjectIdSet()); | 716 sync_notifier_->UpdateRegisteredIds(this, ObjectIdSet()); |
1221 } | 717 } |
1222 sync_notifier_.reset(); | 718 sync_notifier_.reset(); |
1223 | 719 |
1224 if (connection_manager_.get()) { | 720 if (connection_manager_.get()) { |
1225 connection_manager_->RemoveListener(this); | 721 connection_manager_->RemoveListener(this); |
1226 } | 722 } |
1227 connection_manager_.reset(); | 723 connection_manager_.reset(); |
1228 | 724 |
1229 net::NetworkChangeNotifier::RemoveIPAddressObserver(this); | 725 net::NetworkChangeNotifier::RemoveIPAddressObserver(this); |
1230 observing_ip_address_changes_ = false; | 726 observing_ip_address_changes_ = false; |
1231 | 727 |
1232 if (initialized_ && directory()) { | 728 if (initialized_ && directory()) { |
1233 { | |
1234 // Cryptographer should only be accessed while holding a | |
1235 // transaction. | |
1236 ReadTransaction trans(FROM_HERE, GetUserShare()); | |
1237 trans.GetCryptographer()->RemoveObserver(this); | |
1238 } | |
1239 directory()->SaveChanges(); | 729 directory()->SaveChanges(); |
1240 } | 730 } |
1241 | 731 |
1242 share_.directory.reset(); | 732 share_.directory.reset(); |
1243 | 733 |
1244 change_delegate_ = NULL; | 734 change_delegate_ = NULL; |
1245 | 735 |
1246 initialized_ = false; | 736 initialized_ = false; |
1247 | 737 |
1248 // We reset these here, since only now we know they will not be | 738 // 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... |
1481 void SyncManagerImpl::OnSyncEngineEvent(const SyncEngineEvent& event) { | 971 void SyncManagerImpl::OnSyncEngineEvent(const SyncEngineEvent& event) { |
1482 DCHECK(thread_checker_.CalledOnValidThread()); | 972 DCHECK(thread_checker_.CalledOnValidThread()); |
1483 // Only send an event if this is due to a cycle ending and this cycle | 973 // Only send an event if this is due to a cycle ending and this cycle |
1484 // concludes a canonical "sync" process; that is, based on what is known | 974 // concludes a canonical "sync" process; that is, based on what is known |
1485 // locally we are "all happy" and up-to-date. There may be new changes on | 975 // locally we are "all happy" and up-to-date. There may be new changes on |
1486 // the server, but we'll get them on a subsequent sync. | 976 // the server, but we'll get them on a subsequent sync. |
1487 // | 977 // |
1488 // Notifications are sent at the end of every sync cycle, regardless of | 978 // Notifications are sent at the end of every sync cycle, regardless of |
1489 // whether we should sync again. | 979 // whether we should sync again. |
1490 if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) { | 980 if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) { |
1491 { | |
1492 // Check to see if we need to notify the frontend that we have newly | |
1493 // encrypted types or that we require a passphrase. | |
1494 ReadTransaction trans(FROM_HERE, GetUserShare()); | |
1495 Cryptographer* cryptographer = trans.GetCryptographer(); | |
1496 // If we've completed a sync cycle and the cryptographer isn't ready | |
1497 // yet, prompt the user for a passphrase. | |
1498 if (cryptographer->has_pending_keys()) { | |
1499 DVLOG(1) << "OnPassPhraseRequired Sent"; | |
1500 sync_pb::EncryptedData pending_keys = cryptographer->GetPendingKeys(); | |
1501 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
1502 OnPassphraseRequired(REASON_DECRYPTION, | |
1503 pending_keys)); | |
1504 } else if (!cryptographer->is_ready() && | |
1505 event.snapshot.initial_sync_ended().Has(NIGORI)) { | |
1506 DVLOG(1) << "OnPassphraseRequired sent because cryptographer is not " | |
1507 << "ready"; | |
1508 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | |
1509 OnPassphraseRequired(REASON_ENCRYPTION, | |
1510 sync_pb::EncryptedData())); | |
1511 } | |
1512 | |
1513 NotifyCryptographerState(cryptographer); | |
1514 allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes()); | |
1515 } | |
1516 | |
1517 if (!initialized_) { | 981 if (!initialized_) { |
1518 LOG(INFO) << "OnSyncCycleCompleted not sent because sync api is not " | 982 LOG(INFO) << "OnSyncCycleCompleted not sent because sync api is not " |
1519 << "initialized"; | 983 << "initialized"; |
1520 return; | 984 return; |
1521 } | 985 } |
1522 | 986 |
1523 if (!event.snapshot.has_more_to_sync()) { | 987 if (!event.snapshot.has_more_to_sync()) { |
1524 { | |
1525 // To account for a nigori node arriving with stale/bad data, we ensure | |
1526 // that the nigori node is up to date at the end of each cycle. | |
1527 WriteTransaction trans(FROM_HERE, GetUserShare()); | |
1528 WriteNode nigori_node(&trans); | |
1529 if (nigori_node.InitByTagLookup(kNigoriTag) == BaseNode::INIT_OK) { | |
1530 Cryptographer* cryptographer = trans.GetCryptographer(); | |
1531 UpdateNigoriEncryptionState(cryptographer, &nigori_node); | |
1532 } | |
1533 } | |
1534 | |
1535 DVLOG(1) << "Sending OnSyncCycleCompleted"; | 988 DVLOG(1) << "Sending OnSyncCycleCompleted"; |
1536 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | 989 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, |
1537 OnSyncCycleCompleted(event.snapshot)); | 990 OnSyncCycleCompleted(event.snapshot)); |
1538 } | 991 } |
1539 | 992 |
1540 // This is here for tests, which are still using p2p notifications. | 993 // This is here for tests, which are still using p2p notifications. |
1541 // | 994 // |
1542 // TODO(chron): Consider changing this back to track has_more_to_sync | 995 // TODO(chron): Consider changing this back to track has_more_to_sync |
1543 // only notify peers if a successful commit has occurred. | 996 // only notify peers if a successful commit has occurred. |
1544 bool is_notifiable_commit = | 997 bool is_notifiable_commit = |
(...skipping 29 matching lines...) Expand all Loading... |
1574 return; | 1027 return; |
1575 } | 1028 } |
1576 | 1029 |
1577 } | 1030 } |
1578 | 1031 |
1579 void SyncManagerImpl::SetJsEventHandler( | 1032 void SyncManagerImpl::SetJsEventHandler( |
1580 const WeakHandle<JsEventHandler>& event_handler) { | 1033 const WeakHandle<JsEventHandler>& event_handler) { |
1581 js_event_handler_ = event_handler; | 1034 js_event_handler_ = event_handler; |
1582 js_sync_manager_observer_.SetJsEventHandler(js_event_handler_); | 1035 js_sync_manager_observer_.SetJsEventHandler(js_event_handler_); |
1583 js_mutation_event_observer_.SetJsEventHandler(js_event_handler_); | 1036 js_mutation_event_observer_.SetJsEventHandler(js_event_handler_); |
| 1037 js_sync_encryption_handler_observer_.SetJsEventHandler(js_event_handler_); |
1584 } | 1038 } |
1585 | 1039 |
1586 void SyncManagerImpl::ProcessJsMessage( | 1040 void SyncManagerImpl::ProcessJsMessage( |
1587 const std::string& name, const JsArgList& args, | 1041 const std::string& name, const JsArgList& args, |
1588 const WeakHandle<JsReplyHandler>& reply_handler) { | 1042 const WeakHandle<JsReplyHandler>& reply_handler) { |
1589 if (!initialized_) { | 1043 if (!initialized_) { |
1590 NOTREACHED(); | 1044 NOTREACHED(); |
1591 return; | 1045 return; |
1592 } | 1046 } |
1593 | 1047 |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1779 id, &child_handles); | 1233 id, &child_handles); |
1780 for (syncable::Directory::ChildHandles::const_iterator it = | 1234 for (syncable::Directory::ChildHandles::const_iterator it = |
1781 child_handles.begin(); it != child_handles.end(); ++it) { | 1235 child_handles.begin(); it != child_handles.end(); ++it) { |
1782 child_ids->Append(Value::CreateStringValue( | 1236 child_ids->Append(Value::CreateStringValue( |
1783 base::Int64ToString(*it))); | 1237 base::Int64ToString(*it))); |
1784 } | 1238 } |
1785 } | 1239 } |
1786 return JsArgList(&return_args); | 1240 return JsArgList(&return_args); |
1787 } | 1241 } |
1788 | 1242 |
1789 void SyncManagerImpl::OnEncryptedTypesChanged( | |
1790 ModelTypeSet encrypted_types, | |
1791 bool encrypt_everything) { | |
1792 // NOTE: We're in a transaction. | |
1793 FOR_EACH_OBSERVER( | |
1794 SyncManager::Observer, observers_, | |
1795 OnEncryptedTypesChanged(encrypted_types, encrypt_everything)); | |
1796 } | |
1797 | |
1798 void SyncManagerImpl::UpdateNotificationInfo( | 1243 void SyncManagerImpl::UpdateNotificationInfo( |
1799 const ModelTypePayloadMap& type_payloads) { | 1244 const ModelTypePayloadMap& type_payloads) { |
1800 for (ModelTypePayloadMap::const_iterator it = type_payloads.begin(); | 1245 for (ModelTypePayloadMap::const_iterator it = type_payloads.begin(); |
1801 it != type_payloads.end(); ++it) { | 1246 it != type_payloads.end(); ++it) { |
1802 NotificationInfo* info = ¬ification_info_map_[it->first]; | 1247 NotificationInfo* info = ¬ification_info_map_[it->first]; |
1803 info->total_count++; | 1248 info->total_count++; |
1804 info->payload = it->second; | 1249 info->payload = it->second; |
1805 } | 1250 } |
1806 } | 1251 } |
1807 | 1252 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1866 | 1311 |
1867 const std::string& SyncManagerImpl::username_for_share() const { | 1312 const std::string& SyncManagerImpl::username_for_share() const { |
1868 return share_.name; | 1313 return share_.name; |
1869 } | 1314 } |
1870 | 1315 |
1871 UserShare* SyncManagerImpl::GetUserShare() { | 1316 UserShare* SyncManagerImpl::GetUserShare() { |
1872 DCHECK(initialized_); | 1317 DCHECK(initialized_); |
1873 return &share_; | 1318 return &share_; |
1874 } | 1319 } |
1875 | 1320 |
1876 bool SyncManagerImpl::ReceivedExperiment(Experiments* experiments) { | |
1877 ReadTransaction trans(FROM_HERE, GetUserShare()); | |
1878 ReadNode node(&trans); | |
1879 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { | |
1880 DVLOG(1) << "Couldn't find Nigori node."; | |
1881 return false; | |
1882 } | |
1883 bool found_experiment = false; | |
1884 if (node.GetNigoriSpecifics().sync_tab_favicons()) { | |
1885 experiments->sync_tab_favicons = true; | |
1886 found_experiment = true; | |
1887 } | |
1888 return found_experiment; | |
1889 } | |
1890 | |
1891 bool SyncManagerImpl::HasUnsyncedItems() { | 1321 bool SyncManagerImpl::HasUnsyncedItems() { |
1892 ReadTransaction trans(FROM_HERE, GetUserShare()); | 1322 ReadTransaction trans(FROM_HERE, GetUserShare()); |
1893 return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0); | 1323 return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0); |
1894 } | 1324 } |
1895 | 1325 |
| 1326 SyncEncryptionHandler* SyncManagerImpl::GetEncryptionHandler() { |
| 1327 return sync_encryption_handler_.get(); |
| 1328 } |
| 1329 |
1896 // static. | 1330 // static. |
1897 int SyncManagerImpl::GetDefaultNudgeDelay() { | 1331 int SyncManagerImpl::GetDefaultNudgeDelay() { |
1898 return kDefaultNudgeDelayMilliseconds; | 1332 return kDefaultNudgeDelayMilliseconds; |
1899 } | 1333 } |
1900 | 1334 |
1901 // static. | 1335 // static. |
1902 int SyncManagerImpl::GetPreferencesNudgeDelay() { | 1336 int SyncManagerImpl::GetPreferencesNudgeDelay() { |
1903 return kPreferencesNudgeDelayMilliseconds; | 1337 return kPreferencesNudgeDelayMilliseconds; |
1904 } | 1338 } |
1905 | 1339 |
1906 } // namespace syncer | 1340 } // namespace syncer |
OLD | NEW |