Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(426)

Unified Diff: sync/internal_api/sync_manager_impl.cc

Issue 10827266: [Sync] Add SyncEncryptionHandler (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sync/internal_api/sync_manager_impl.h ('k') | sync/internal_api/sync_manager_impl_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sync/internal_api/sync_manager_impl.cc
diff --git a/sync/internal_api/sync_manager_impl.cc b/sync/internal_api/sync_manager_impl.cc
index 95d650caaeccb56eb8a64ecd81e7e3b8a7758123..4335fe12e661d5789d9259be417d933a080f04ca 100644
--- a/sync/internal_api/sync_manager_impl.cc
+++ b/sync/internal_api/sync_manager_impl.cc
@@ -41,13 +41,11 @@
#include "sync/js/js_reply_handler.h"
#include "sync/notifier/invalidation_util.h"
#include "sync/notifier/sync_notifier.h"
-#include "sync/protocol/encryption.pb.h"
#include "sync/protocol/proto_value_conversions.h"
#include "sync/protocol/sync.pb.h"
#include "sync/syncable/directory.h"
#include "sync/syncable/entry.h"
#include "sync/syncable/in_memory_directory_backing_store.h"
-#include "sync/syncable/nigori_util.h"
#include "sync/syncable/on_disk_directory_backing_store.h"
#include "sync/util/get_session_name.h"
@@ -68,10 +66,6 @@ static const int kPreferencesNudgeDelayMilliseconds = 2000;
static const int kSyncRefreshDelayMsec = 500;
static const int kSyncSchedulerDelayMsec = 250;
-// The maximum number of times we will automatically overwrite the nigori node
-// because the encryption keys don't match (per chrome instantiation).
-static const int kNigoriOverwriteLimit = 10;
-
// Maximum count and size for traffic recorder.
static const unsigned int kMaxMessagesToRecord = 10;
static const unsigned int kMaxMessageSizeToRecord = 5 * 1024;
@@ -179,8 +173,7 @@ SyncManagerImpl::SyncManagerImpl(const std::string& name)
traffic_recorder_(kMaxMessagesToRecord, kMaxMessageSizeToRecord),
encryptor_(NULL),
unrecoverable_error_handler_(NULL),
- report_unrecoverable_error_function_(NULL),
- nigori_overwrite_count_(0) {
+ report_unrecoverable_error_function_(NULL) {
// Pre-fill |notification_info_map_|.
for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) {
notification_info_map_.insert(
@@ -310,24 +303,6 @@ ModelTypeSet SyncManagerImpl::GetTypesWithEmptyProgressMarkerToken(
return result;
}
-void SyncManagerImpl::EnableEncryptEverything() {
- DCHECK(thread_checker_.CalledOnValidThread());
- {
- // Update the cryptographer to know we're now encrypting everything.
- WriteTransaction trans(FROM_HERE, GetUserShare());
- Cryptographer* cryptographer = trans.GetCryptographer();
- // Only set encrypt everything if we know we can encrypt. This allows the
- // user to cancel encryption if they have forgotten their passphrase.
- if (cryptographer->is_ready())
- cryptographer->set_encrypt_everything();
- }
-
- // Reads from cryptographer so will automatically encrypt all
- // datatypes and update the nigori node as necessary. Will trigger
- // OnPassphraseRequired if necessary.
- RefreshEncryption();
-}
-
void SyncManagerImpl::ConfigureSyncer(
ConfigureReason reason,
const ModelTypeSet& types_to_config,
@@ -489,7 +464,15 @@ void SyncManagerImpl::Init(
trans.GetCryptographer()->Bootstrap(restored_key_for_bootstrapping);
trans.GetCryptographer()->BootstrapKeystoreKey(
restored_keystore_key_for_bootstrapping);
- trans.GetCryptographer()->AddObserver(this);
+
+ sync_encryption_handler_.reset(new SyncEncryptionHandlerImpl(
+ &share_,
+ trans.GetCryptographer()));
+ sync_encryption_handler_->AddObserver(this);
+ sync_encryption_handler_->AddObserver(&debug_info_event_listener_);
+ sync_encryption_handler_->AddObserver(&js_sync_encryption_handler_observer_);
+ trans.GetCryptographer()->SetNigoriHandler(
+ sync_encryption_handler_.get());
FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
OnInitializationComplete(
@@ -497,141 +480,82 @@ void SyncManagerImpl::Init(
true, InitialSyncEndedTypes()));
}
-void SyncManagerImpl::RefreshNigori(const std::string& chrome_version,
- const base::Closure& done_callback) {
- DCHECK(initialized_);
- DCHECK(thread_checker_.CalledOnValidThread());
- GetSessionName(
- blocking_task_runner_,
- base::Bind(
- &SyncManagerImpl::UpdateCryptographerAndNigoriCallback,
- weak_ptr_factory_.GetWeakPtr(),
- chrome_version,
- done_callback));
-}
-
-void SyncManagerImpl::UpdateNigoriEncryptionState(
- Cryptographer* cryptographer,
- WriteNode* nigori_node) {
- DCHECK(nigori_node);
- sync_pb::NigoriSpecifics nigori = nigori_node->GetNigoriSpecifics();
-
- if (cryptographer->is_ready() &&
- nigori_overwrite_count_ < kNigoriOverwriteLimit) {
- // Does not modify the encrypted blob if the unencrypted data already
- // matches what is about to be written.
- sync_pb::EncryptedData original_keys = nigori.encrypted();
- if (!cryptographer->GetKeys(nigori.mutable_encrypted()))
- NOTREACHED();
-
- if (nigori.encrypted().SerializeAsString() !=
- original_keys.SerializeAsString()) {
- // We've updated the nigori node's encryption keys. In order to prevent
- // a possible looping of two clients constantly overwriting each other,
- // we limit the absolute number of overwrites per client instantiation.
- nigori_overwrite_count_++;
- UMA_HISTOGRAM_COUNTS("Sync.AutoNigoriOverwrites",
- nigori_overwrite_count_);
- }
-
- // Note: we don't try to set using_explicit_passphrase here since if that
- // is lost the user can always set it again. The main point is to preserve
- // the encryption keys so all data remains decryptable.
- }
- cryptographer->UpdateNigoriFromEncryptedTypes(&nigori);
-
- // If nothing has changed, this is a no-op.
- nigori_node->SetNigoriSpecifics(nigori);
-}
-
-void SyncManagerImpl::UpdateCryptographerAndNigoriCallback(
+void SyncManagerImpl::UpdateSessionNameCallback(
const std::string& chrome_version,
- const base::Closure& done_callback,
const std::string& session_name) {
- if (!directory()->initial_sync_ended_for_type(NIGORI)) {
- done_callback.Run(); // Should only happen during first time sync.
+ WriteTransaction trans(FROM_HERE, GetUserShare());
+ WriteNode node(&trans);
+ // TODO(rlarocque): switch to device info node.
+ if (node.InitByTagLookup(syncer::kNigoriTag) != syncer::BaseNode::INIT_OK) {
return;
}
- bool success = false;
- {
- WriteTransaction trans(FROM_HERE, GetUserShare());
- Cryptographer* cryptographer = trans.GetCryptographer();
- WriteNode node(&trans);
-
- if (node.InitByTagLookup(kNigoriTag) == BaseNode::INIT_OK) {
- sync_pb::NigoriSpecifics nigori(node.GetNigoriSpecifics());
- Cryptographer::UpdateResult result = cryptographer->Update(nigori);
- if (result == Cryptographer::NEEDS_PASSPHRASE) {
- sync_pb::EncryptedData pending_keys;
- if (cryptographer->has_pending_keys())
- pending_keys = cryptographer->GetPendingKeys();
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseRequired(REASON_DECRYPTION,
- pending_keys));
- }
-
- // Add or update device information.
- bool contains_this_device = false;
- for (int i = 0; i < nigori.device_information_size(); ++i) {
- const sync_pb::DeviceInformation& device_information =
- nigori.device_information(i);
- if (device_information.cache_guid() == directory()->cache_guid()) {
- // Update the version number in case it changed due to an update.
- if (device_information.chrome_version() != chrome_version) {
- sync_pb::DeviceInformation* mutable_device_information =
- nigori.mutable_device_information(i);
- mutable_device_information->set_chrome_version(
- chrome_version);
- }
- contains_this_device = true;
- }
+ sync_pb::NigoriSpecifics nigori(node.GetNigoriSpecifics());
+ // Add or update device information.
+ bool contains_this_device = false;
+ for (int i = 0; i < nigori.device_information_size(); ++i) {
+ const sync_pb::DeviceInformation& device_information =
+ nigori.device_information(i);
+ if (device_information.cache_guid() == directory()->cache_guid()) {
+ // Update the version number in case it changed due to an update.
+ if (device_information.chrome_version() != chrome_version) {
+ sync_pb::DeviceInformation* mutable_device_information =
+ nigori.mutable_device_information(i);
+ mutable_device_information->set_chrome_version(
+ chrome_version);
}
+ contains_this_device = true;
+ }
+ }
- if (!contains_this_device) {
- sync_pb::DeviceInformation* device_information =
- nigori.add_device_information();
- device_information->set_cache_guid(directory()->cache_guid());
+ if (!contains_this_device) {
+ sync_pb::DeviceInformation* device_information =
+ nigori.add_device_information();
+ device_information->set_cache_guid(directory()->cache_guid());
#if defined(OS_CHROMEOS)
- device_information->set_platform("ChromeOS");
+ device_information->set_platform("ChromeOS");
#elif defined(OS_LINUX)
- device_information->set_platform("Linux");
+ device_information->set_platform("Linux");
#elif defined(OS_MACOSX)
- device_information->set_platform("Mac");
+ device_information->set_platform("Mac");
#elif defined(OS_WIN)
- device_information->set_platform("Windows");
+ device_information->set_platform("Windows");
#endif
- device_information->set_name(session_name);
- device_information->set_chrome_version(chrome_version);
- }
- // Disabled to avoid nigori races. TODO(zea): re-enable. crbug.com/122837
- // node.SetNigoriSpecifics(nigori);
+ device_information->set_name(session_name);
+ device_information->set_chrome_version(chrome_version);
+ }
+ node.SetNigoriSpecifics(nigori);
+}
- // Make sure the nigori node has the up to date encryption info.
- UpdateNigoriEncryptionState(cryptographer, &node);
- NotifyCryptographerState(cryptographer);
- allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes());
+void SyncManagerImpl::OnPassphraseRequired(
+ PassphraseRequiredReason reason,
+ const sync_pb::EncryptedData& pending_keys) {
+ // Does nothing.
+}
- success = cryptographer->is_ready();
- } else {
- NOTREACHED();
- }
- }
+void SyncManagerImpl::OnPassphraseAccepted() {
+ // Does nothing.
+}
- if (success)
- RefreshEncryption();
- done_callback.Run();
+void SyncManagerImpl::OnBootstrapTokenUpdated(
+ const std::string& bootstrap_token) {
+ // Does nothing.
}
-void SyncManagerImpl::NotifyCryptographerState(Cryptographer * cryptographer) {
- // TODO(lipalani): Explore the possibility of hooking this up to
- // SyncManager::Observer and making |AllStatus| a listener for that.
+void SyncManagerImpl::OnEncryptedTypesChanged(ModelTypeSet encrypted_types,
+ bool encrypt_everything) {
+ allstatus_.SetEncryptedTypes(encrypted_types);
+}
+
+void SyncManagerImpl::OnEncryptionComplete() {
+ // Does nothing.
+}
+
+void SyncManagerImpl::OnCryptographerStateChanged(
+ Cryptographer* cryptographer) {
allstatus_.SetCryptographerReady(cryptographer->is_ready());
allstatus_.SetCryptoHasPendingKeys(cryptographer->has_pending_keys());
- debug_info_event_listener_.SetCryptographerReady(cryptographer->is_ready());
- debug_info_event_listener_.SetCrytographerHasPendingKeys(
- cryptographer->has_pending_keys());
}
void SyncManagerImpl::StartSyncingNormally(
@@ -760,444 +684,11 @@ void SyncManagerImpl::UnregisterInvalidationHandler(
sync_notifier_->UnregisterHandler(handler);
}
-void SyncManagerImpl::SetEncryptionPassphrase(
- const std::string& passphrase,
- bool is_explicit) {
- DCHECK(thread_checker_.CalledOnValidThread());
- // We do not accept empty passphrases.
- if (passphrase.empty()) {
- NOTREACHED() << "Cannot encrypt with an empty passphrase.";
- return;
- }
-
- // All accesses to the cryptographer are protected by a transaction.
- WriteTransaction trans(FROM_HERE, GetUserShare());
- Cryptographer* cryptographer = trans.GetCryptographer();
- KeyParams key_params = {"localhost", "dummy", passphrase};
- WriteNode node(&trans);
- if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) {
- // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
- NOTREACHED();
- return;
- }
-
- bool nigori_has_explicit_passphrase =
- node.GetNigoriSpecifics().using_explicit_passphrase();
- std::string bootstrap_token;
- sync_pb::EncryptedData pending_keys;
- if (cryptographer->has_pending_keys())
- pending_keys = cryptographer->GetPendingKeys();
- bool success = false;
-
-
- // There are six cases to handle here:
- // 1. The user has no pending keys and is setting their current GAIA password
- // as the encryption passphrase. This happens either during first time sync
- // with a clean profile, or after re-authenticating on a profile that was
- // already signed in with the cryptographer ready.
- // 2. The user has no pending keys, and is overwriting an (already provided)
- // implicit passphrase with an explicit (custom) passphrase.
- // 3. The user has pending keys for an explicit passphrase that is somehow set
- // to their current GAIA passphrase.
- // 4. The user has pending keys encrypted with their current GAIA passphrase
- // and the caller passes in the current GAIA passphrase.
- // 5. The user has pending keys encrypted with an older GAIA passphrase
- // and the caller passes in the current GAIA passphrase.
- // 6. The user has previously done encryption with an explicit passphrase.
- // Furthermore, we enforce the fact that the bootstrap encryption token will
- // always be derived from the newest GAIA password if the account is using
- // an implicit passphrase (even if the data is encrypted with an old GAIA
- // password). If the account is using an explicit (custom) passphrase, the
- // bootstrap token will be derived from the most recently provided explicit
- // passphrase (that was able to decrypt the data).
- if (!nigori_has_explicit_passphrase) {
- if (!cryptographer->has_pending_keys()) {
- if (cryptographer->AddKey(key_params)) {
- // Case 1 and 2. We set a new GAIA passphrase when there are no pending
- // keys (1), or overwriting an implicit passphrase with a new explicit
- // one (2) when there are no pending keys.
- DVLOG(1) << "Setting " << (is_explicit ? "explicit" : "implicit" )
- << " passphrase for encryption.";
- cryptographer->GetBootstrapToken(&bootstrap_token);
- success = true;
- } else {
- NOTREACHED() << "Failed to add key to cryptographer.";
- success = false;
- }
- } else { // cryptographer->has_pending_keys() == true
- if (is_explicit) {
- // This can only happen if the nigori node is updated with a new
- // implicit passphrase while a client is attempting to set a new custom
- // passphrase (race condition).
- DVLOG(1) << "Failing because an implicit passphrase is already set.";
- success = false;
- } else { // is_explicit == false
- if (cryptographer->DecryptPendingKeys(key_params)) {
- // Case 4. We successfully decrypted with the implicit GAIA passphrase
- // passed in.
- DVLOG(1) << "Implicit internal passphrase accepted for decryption.";
- cryptographer->GetBootstrapToken(&bootstrap_token);
- success = true;
- } else {
- // Case 5. Encryption was done with an old GAIA password, but we were
- // provided with the current GAIA password. We need to generate a new
- // bootstrap token to preserve it. We build a temporary cryptographer
- // to allow us to extract these params without polluting our current
- // cryptographer.
- DVLOG(1) << "Implicit internal passphrase failed to decrypt, adding "
- << "anyways as default passphrase and persisting via "
- << "bootstrap token.";
- Cryptographer temp_cryptographer(encryptor_);
- temp_cryptographer.AddKey(key_params);
- temp_cryptographer.GetBootstrapToken(&bootstrap_token);
- // We then set the new passphrase as the default passphrase of the
- // real cryptographer, even though we have pending keys. This is safe,
- // as although Cryptographer::is_initialized() will now be true,
- // is_ready() will remain false due to having pending keys.
- cryptographer->AddKey(key_params);
- success = false;
- }
- } // is_explicit
- } // cryptographer->has_pending_keys()
- } else { // nigori_has_explicit_passphrase == true
- // Case 6. We do not want to override a previously set explicit passphrase,
- // so we return a failure.
- DVLOG(1) << "Failing because an explicit passphrase is already set.";
- success = false;
- }
-
- DVLOG_IF(1, !success)
- << "Failure in SetEncryptionPassphrase; notifying and returning.";
- DVLOG_IF(1, success)
- << "Successfully set encryption passphrase; updating nigori and "
- "reencrypting.";
-
- FinishSetPassphrase(
- success, bootstrap_token, is_explicit, &trans, &node);
-}
-
-void SyncManagerImpl::SetDecryptionPassphrase(
- const std::string& passphrase) {
- DCHECK(thread_checker_.CalledOnValidThread());
- // We do not accept empty passphrases.
- if (passphrase.empty()) {
- NOTREACHED() << "Cannot decrypt with an empty passphrase.";
- return;
- }
-
- // All accesses to the cryptographer are protected by a transaction.
- WriteTransaction trans(FROM_HERE, GetUserShare());
- Cryptographer* cryptographer = trans.GetCryptographer();
- KeyParams key_params = {"localhost", "dummy", passphrase};
- WriteNode node(&trans);
- if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) {
- // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
- NOTREACHED();
- return;
- }
-
- if (!cryptographer->has_pending_keys()) {
- // Note that this *can* happen in a rare situation where data is
- // re-encrypted on another client while a SetDecryptionPassphrase() call is
- // in-flight on this client. It is rare enough that we choose to do nothing.
- NOTREACHED() << "Attempt to set decryption passphrase failed because there "
- << "were no pending keys.";
- return;
- }
-
- bool nigori_has_explicit_passphrase =
- node.GetNigoriSpecifics().using_explicit_passphrase();
- std::string bootstrap_token;
- sync_pb::EncryptedData pending_keys;
- pending_keys = cryptographer->GetPendingKeys();
- bool success = false;
-
- // There are three cases to handle here:
- // 7. We're using the current GAIA password to decrypt the pending keys. This
- // happens when signing in to an account with a previously set implicit
- // passphrase, where the data is already encrypted with the newest GAIA
- // password.
- // 8. The user is providing an old GAIA password to decrypt the pending keys.
- // In this case, the user is using an implicit passphrase, but has changed
- // their password since they last encrypted their data, and therefore
- // their current GAIA password was unable to decrypt the data. This will
- // happen when the user is setting up a new profile with a previously
- // encrypted account (after changing passwords).
- // 9. The user is providing a previously set explicit passphrase to decrypt
- // the pending keys.
- if (!nigori_has_explicit_passphrase) {
- if (cryptographer->is_initialized()) {
- // We only want to change the default encryption key to the pending
- // one if the pending keybag already contains the current default.
- // This covers the case where a different client re-encrypted
- // everything with a newer gaia passphrase (and hence the keybag
- // contains keys from all previously used gaia passphrases).
- // Otherwise, we're in a situation where the pending keys are
- // encrypted with an old gaia passphrase, while the default is the
- // current gaia passphrase. In that case, we preserve the default.
- Cryptographer temp_cryptographer(encryptor_);
- temp_cryptographer.SetPendingKeys(cryptographer->GetPendingKeys());
- if (temp_cryptographer.DecryptPendingKeys(key_params)) {
- // Check to see if the pending bag of keys contains the current
- // default key.
- sync_pb::EncryptedData encrypted;
- cryptographer->GetKeys(&encrypted);
- if (temp_cryptographer.CanDecrypt(encrypted)) {
- DVLOG(1) << "Implicit user provided passphrase accepted for "
- << "decryption, overwriting default.";
- // Case 7. The pending keybag contains the current default. Go ahead
- // and update the cryptographer, letting the default change.
- cryptographer->DecryptPendingKeys(key_params);
- cryptographer->GetBootstrapToken(&bootstrap_token);
- success = true;
- } else {
- // Case 8. The pending keybag does not contain the current default
- // encryption key. We decrypt the pending keys here, and in
- // FinishSetPassphrase, re-encrypt everything with the current GAIA
- // passphrase instead of the passphrase just provided by the user.
- DVLOG(1) << "Implicit user provided passphrase accepted for "
- << "decryption, restoring implicit internal passphrase "
- << "as default.";
- std::string bootstrap_token_from_current_key;
- cryptographer->GetBootstrapToken(
- &bootstrap_token_from_current_key);
- cryptographer->DecryptPendingKeys(key_params);
- // Overwrite the default from the pending keys.
- cryptographer->AddKeyFromBootstrapToken(
- bootstrap_token_from_current_key);
- success = true;
- }
- } else { // !temp_cryptographer.DecryptPendingKeys(..)
- DVLOG(1) << "Implicit user provided passphrase failed to decrypt.";
- success = false;
- } // temp_cryptographer.DecryptPendingKeys(...)
- } else { // cryptographer->is_initialized() == false
- if (cryptographer->DecryptPendingKeys(key_params)) {
- // This can happpen in two cases:
- // - First time sync on android, where we'll never have a
- // !user_provided passphrase.
- // - This is a restart for a client that lost their bootstrap token.
- // In both cases, we should go ahead and initialize the cryptographer
- // and persist the new bootstrap token.
- //
- // Note: at this point, we cannot distinguish between cases 7 and 8
- // above. This user provided passphrase could be the current or the
- // old. But, as long as we persist the token, there's nothing more
- // we can do.
- cryptographer->GetBootstrapToken(&bootstrap_token);
- DVLOG(1) << "Implicit user provided passphrase accepted, initializing"
- << " cryptographer.";
- success = true;
- } else {
- DVLOG(1) << "Implicit user provided passphrase failed to decrypt.";
- success = false;
- }
- } // cryptographer->is_initialized()
- } else { // nigori_has_explicit_passphrase == true
- // Case 9. Encryption was done with an explicit passphrase, and we decrypt
- // with the passphrase provided by the user.
- if (cryptographer->DecryptPendingKeys(key_params)) {
- DVLOG(1) << "Explicit passphrase accepted for decryption.";
- cryptographer->GetBootstrapToken(&bootstrap_token);
- success = true;
- } else {
- DVLOG(1) << "Explicit passphrase failed to decrypt.";
- success = false;
- }
- } // nigori_has_explicit_passphrase
-
- DVLOG_IF(1, !success)
- << "Failure in SetDecryptionPassphrase; notifying and returning.";
- DVLOG_IF(1, success)
- << "Successfully set decryption passphrase; updating nigori and "
- "reencrypting.";
-
- FinishSetPassphrase(success,
- bootstrap_token,
- nigori_has_explicit_passphrase,
- &trans,
- &node);
-}
-
-void SyncManagerImpl::FinishSetPassphrase(
- bool success,
- const std::string& bootstrap_token,
- bool is_explicit,
- WriteTransaction* trans,
- WriteNode* nigori_node) {
- Cryptographer* cryptographer = trans->GetCryptographer();
- NotifyCryptographerState(cryptographer);
-
- // It's possible we need to change the bootstrap token even if we failed to
- // set the passphrase (for example if we need to preserve the new GAIA
- // passphrase).
- if (!bootstrap_token.empty()) {
- DVLOG(1) << "Bootstrap token updated.";
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnBootstrapTokenUpdated(bootstrap_token));
- }
-
- if (!success) {
- if (cryptographer->is_ready()) {
- LOG(ERROR) << "Attempt to change passphrase failed while cryptographer "
- << "was ready.";
- } else if (cryptographer->has_pending_keys()) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseRequired(REASON_DECRYPTION,
- cryptographer->GetPendingKeys()));
- } else {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseRequired(REASON_ENCRYPTION,
- sync_pb::EncryptedData()));
- }
- return;
- }
-
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseAccepted());
- DCHECK(cryptographer->is_ready());
-
- // TODO(tim): Bug 58231. It would be nice if setting a passphrase didn't
- // require messing with the Nigori node, because we can't set a passphrase
- // until download conditions are met vs Cryptographer init. It seems like
- // it's safe to defer this work.
- sync_pb::NigoriSpecifics specifics(nigori_node->GetNigoriSpecifics());
- // Does not modify specifics.encrypted() if the original decrypted data was
- // the same.
- if (!cryptographer->GetKeys(specifics.mutable_encrypted())) {
- NOTREACHED();
- return;
- }
- specifics.set_using_explicit_passphrase(is_explicit);
- nigori_node->SetNigoriSpecifics(specifics);
-
- // Does nothing if everything is already encrypted or the cryptographer has
- // pending keys.
- ReEncryptEverything(trans);
-}
-
-bool SyncManagerImpl::IsUsingExplicitPassphrase() {
- ReadTransaction trans(FROM_HERE, &share_);
- ReadNode node(&trans);
- if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) {
- // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
- NOTREACHED();
- return false;
- }
-
- return node.GetNigoriSpecifics().using_explicit_passphrase();
-}
-
bool SyncManagerImpl::GetKeystoreKeyBootstrapToken(std::string* token) {
ReadTransaction trans(FROM_HERE, GetUserShare());
return trans.GetCryptographer()->GetKeystoreKeyBootstrapToken(token);
}
-void SyncManagerImpl::RefreshEncryption() {
- DCHECK(initialized_);
-
- WriteTransaction trans(FROM_HERE, GetUserShare());
- WriteNode node(&trans);
- if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) {
- NOTREACHED() << "Unable to set encrypted datatypes because Nigori node not "
- << "found.";
- return;
- }
-
- Cryptographer* cryptographer = trans.GetCryptographer();
-
- if (!cryptographer->is_ready()) {
- DVLOG(1) << "Attempting to encrypt datatypes when cryptographer not "
- << "initialized, prompting for passphrase.";
- // TODO(zea): this isn't really decryption, but that's the only way we have
- // to prompt the user for a passsphrase. See http://crbug.com/91379.
- sync_pb::EncryptedData pending_keys;
- if (cryptographer->has_pending_keys())
- pending_keys = cryptographer->GetPendingKeys();
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseRequired(REASON_DECRYPTION,
- pending_keys));
- return;
- }
-
- UpdateNigoriEncryptionState(cryptographer, &node);
-
- allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes());
-
- // We reencrypt everything regardless of whether the set of encrypted
- // types changed to ensure that any stray unencrypted entries are overwritten.
- ReEncryptEverything(&trans);
-}
-
-// This function iterates over all encrypted types. There are many scenarios in
-// which data for some or all types is not currently available. In that case,
-// the lookup of the root node will fail and we will skip encryption for that
-// type.
-void SyncManagerImpl::ReEncryptEverything(
- WriteTransaction* trans) {
- Cryptographer* cryptographer = trans->GetCryptographer();
- if (!cryptographer || !cryptographer->is_ready())
- return;
- ModelTypeSet encrypted_types = GetEncryptedTypes(trans);
- for (ModelTypeSet::Iterator iter = encrypted_types.First();
- iter.Good(); iter.Inc()) {
- if (iter.Get() == PASSWORDS || iter.Get() == NIGORI)
- continue; // These types handle encryption differently.
-
- ReadNode type_root(trans);
- std::string tag = ModelTypeToRootTag(iter.Get());
- if (type_root.InitByTagLookup(tag) != BaseNode::INIT_OK)
- continue; // Don't try to reencrypt if the type's data is unavailable.
-
- // Iterate through all children of this datatype.
- std::queue<int64> to_visit;
- int64 child_id = type_root.GetFirstChildId();
- to_visit.push(child_id);
- while (!to_visit.empty()) {
- child_id = to_visit.front();
- to_visit.pop();
- if (child_id == kInvalidId)
- continue;
-
- WriteNode child(trans);
- if (child.InitByIdLookup(child_id) != BaseNode::INIT_OK) {
- NOTREACHED();
- continue;
- }
- if (child.GetIsFolder()) {
- to_visit.push(child.GetFirstChildId());
- }
- if (child.GetEntry()->Get(syncable::UNIQUE_SERVER_TAG).empty()) {
- // Rewrite the specifics of the node with encrypted data if necessary
- // (only rewrite the non-unique folders).
- child.ResetFromSpecifics();
- }
- to_visit.push(child.GetSuccessorId());
- }
- }
-
- // Passwords are encrypted with their own legacy scheme. Passwords are always
- // encrypted so we don't need to check GetEncryptedTypes() here.
- ReadNode passwords_root(trans);
- std::string passwords_tag = ModelTypeToRootTag(PASSWORDS);
- if (passwords_root.InitByTagLookup(passwords_tag) == BaseNode::INIT_OK) {
- int64 child_id = passwords_root.GetFirstChildId();
- while (child_id != kInvalidId) {
- WriteNode child(trans);
- if (child.InitByIdLookup(child_id) != BaseNode::INIT_OK) {
- NOTREACHED();
- return;
- }
- child.SetPasswordSpecifics(child.GetPasswordSpecifics());
- child_id = child.GetSuccessorId();
- }
- }
-
- // NOTE: We notify from within a transaction.
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnEncryptionComplete());
-}
-
void SyncManagerImpl::AddObserver(SyncManager::Observer* observer) {
DCHECK(thread_checker_.CalledOnValidThread());
observers_.AddObserver(observer);
@@ -1226,6 +717,11 @@ void SyncManagerImpl::ShutdownOnSyncThread() {
scheduler_.reset();
session_context_.reset();
+ if (sync_encryption_handler_.get()) {
+ sync_encryption_handler_->RemoveObserver(&debug_info_event_listener_);
+ sync_encryption_handler_->RemoveObserver(this);
+ }
+
SetJsEventHandler(WeakHandle<JsEventHandler>());
RemoveObserver(&js_sync_manager_observer_);
@@ -1248,12 +744,6 @@ void SyncManagerImpl::ShutdownOnSyncThread() {
observing_ip_address_changes_ = false;
if (initialized_ && directory()) {
- {
- // Cryptographer should only be accessed while holding a
- // transaction.
- ReadTransaction trans(FROM_HERE, GetUserShare());
- trans.GetCryptographer()->RemoveObserver(this);
- }
directory()->SaveChanges();
}
@@ -1506,32 +996,6 @@ void SyncManagerImpl::OnSyncEngineEvent(const SyncEngineEvent& event) {
// Notifications are sent at the end of every sync cycle, regardless of
// whether we should sync again.
if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) {
- {
- // Check to see if we need to notify the frontend that we have newly
- // encrypted types or that we require a passphrase.
- ReadTransaction trans(FROM_HERE, GetUserShare());
- Cryptographer* cryptographer = trans.GetCryptographer();
- // If we've completed a sync cycle and the cryptographer isn't ready
- // yet, prompt the user for a passphrase.
- if (cryptographer->has_pending_keys()) {
- DVLOG(1) << "OnPassPhraseRequired Sent";
- sync_pb::EncryptedData pending_keys = cryptographer->GetPendingKeys();
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseRequired(REASON_DECRYPTION,
- pending_keys));
- } else if (!cryptographer->is_ready() &&
- event.snapshot.initial_sync_ended().Has(NIGORI)) {
- DVLOG(1) << "OnPassphraseRequired sent because cryptographer is not "
- << "ready";
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseRequired(REASON_ENCRYPTION,
- sync_pb::EncryptedData()));
- }
-
- NotifyCryptographerState(cryptographer);
- allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes());
- }
-
if (!initialized_) {
LOG(INFO) << "OnSyncCycleCompleted not sent because sync api is not "
<< "initialized";
@@ -1539,17 +1003,6 @@ void SyncManagerImpl::OnSyncEngineEvent(const SyncEngineEvent& event) {
}
if (!event.snapshot.has_more_to_sync()) {
- {
- // To account for a nigori node arriving with stale/bad data, we ensure
- // that the nigori node is up to date at the end of each cycle.
- WriteTransaction trans(FROM_HERE, GetUserShare());
- WriteNode nigori_node(&trans);
- if (nigori_node.InitByTagLookup(kNigoriTag) == BaseNode::INIT_OK) {
- Cryptographer* cryptographer = trans.GetCryptographer();
- UpdateNigoriEncryptionState(cryptographer, &nigori_node);
- }
- }
-
DVLOG(1) << "Sending OnSyncCycleCompleted";
FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
OnSyncCycleCompleted(event.snapshot));
@@ -1599,6 +1052,7 @@ void SyncManagerImpl::SetJsEventHandler(
js_event_handler_ = event_handler;
js_sync_manager_observer_.SetJsEventHandler(js_event_handler_);
js_mutation_event_observer_.SetJsEventHandler(js_event_handler_);
+ js_sync_encryption_handler_observer_.SetJsEventHandler(js_event_handler_);
}
void SyncManagerImpl::ProcessJsMessage(
@@ -1804,15 +1258,6 @@ JsArgList SyncManagerImpl::GetChildNodeIds(const JsArgList& args) {
return JsArgList(&return_args);
}
-void SyncManagerImpl::OnEncryptedTypesChanged(
- ModelTypeSet encrypted_types,
- bool encrypt_everything) {
- // NOTE: We're in a transaction.
- FOR_EACH_OBSERVER(
- SyncManager::Observer, observers_,
- OnEncryptedTypesChanged(encrypted_types, encrypt_everything));
-}
-
void SyncManagerImpl::UpdateNotificationInfo(
const ModelTypePayloadMap& type_payloads) {
for (ModelTypePayloadMap::const_iterator it = type_payloads.begin();
@@ -1911,6 +1356,10 @@ bool SyncManagerImpl::HasUnsyncedItems() {
return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0);
}
+SyncEncryptionHandler* SyncManagerImpl::GetEncryptionHandler() {
+ return sync_encryption_handler_.get();
+}
+
// static.
int SyncManagerImpl::GetDefaultNudgeDelay() {
return kDefaultNudgeDelayMilliseconds;
« no previous file with comments | « sync/internal_api/sync_manager_impl.h ('k') | sync/internal_api/sync_manager_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698