Index: chrome/browser/sync/engine/syncapi.cc |
diff --git a/chrome/browser/sync/engine/syncapi.cc b/chrome/browser/sync/engine/syncapi.cc |
index ef3f5b43659ceff68594c5bb28996f9b732dd60e..49ccba0a509bd6d44546ba1974083ea286eaeed2 100644 |
--- a/chrome/browser/sync/engine/syncapi.cc |
+++ b/chrome/browser/sync/engine/syncapi.cc |
@@ -202,7 +202,7 @@ UserShare::~UserShare() {} |
//////////////////////////////////// |
// BaseNode member definitions. |
-BaseNode::BaseNode() {} |
+BaseNode::BaseNode() : password_data_(new sync_pb::PasswordSpecificsData) {} |
BaseNode::~BaseNode() {} |
@@ -245,8 +245,10 @@ bool BaseNode::DecryptIfNecessary() { |
// Passwords have their own legacy encryption structure. |
scoped_ptr<sync_pb::PasswordSpecificsData> data(DecryptPasswordSpecifics( |
specifics, GetTransaction()->GetCryptographer())); |
- if (!data.get()) |
+ if (!data.get()) { |
+ LOG(ERROR) << "Failed to decrypt password specifics."; |
return false; |
+ } |
password_data_.swap(data); |
return true; |
} |
@@ -259,9 +261,8 @@ bool BaseNode::DecryptIfNecessary() { |
specifics.encrypted(); |
std::string plaintext_data = GetTransaction()->GetCryptographer()-> |
DecryptToString(encrypted); |
- if (plaintext_data.length() == 0) |
- return false; |
- if (!unencrypted_data_.ParseFromString(plaintext_data)) { |
+ if (plaintext_data.length() == 0 || |
+ !unencrypted_data_.ParseFromString(plaintext_data)) { |
LOG(ERROR) << "Failed to decrypt encrypted node of type " << |
syncable::ModelTypeToString(GetModelType()) << "."; |
return false; |
@@ -404,7 +405,6 @@ const sync_pb::NigoriSpecifics& BaseNode::GetNigoriSpecifics() const { |
const sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const { |
DCHECK_EQ(syncable::PASSWORDS, GetModelType()); |
- DCHECK(password_data_.get()); |
return *password_data_; |
} |
@@ -571,7 +571,9 @@ void WriteNode::SetPasswordSpecifics( |
sync_pb::PasswordSpecifics new_value; |
if (!cryptographer->Encrypt(data, new_value.mutable_encrypted())) { |
- NOTREACHED(); |
+ NOTREACHED() << "Failed to encrypt password, possibly due to sync node " |
+ << "corruption"; |
+ return; |
} |
sync_pb::EntitySpecifics entity_specifics; |
@@ -1203,6 +1205,12 @@ class SyncManager::SyncInternal |
// Whether or not the Nigori node is encrypted using an explicit passphrase. |
bool IsUsingExplicitPassphrase(); |
+ // Update the Cryptographer from the current nigori node. |
+ // Note: opens a transaction and can trigger an ON_PASSPHRASE_REQUIRED, so |
+ // should only be called after syncapi is fully initialized. |
+ // Returns true if cryptographer is ready, false otherwise. |
+ bool UpdateCryptographerFromNigori(); |
+ |
// Set the datatypes we want to encrypt and encrypt any nodes as necessary. |
void EncryptDataTypes(const syncable::ModelTypeSet& encrypted_types); |
@@ -1800,50 +1808,42 @@ bool SyncManager::SyncInternal::Init( |
void SyncManager::SyncInternal::BootstrapEncryption( |
const std::string& restored_key_for_bootstrapping) { |
+ // Cryptographer should only be accessed while holding a transaction. |
+ ReadTransaction trans(GetUserShare()); |
+ Cryptographer* cryptographer = trans.GetCryptographer(); |
+ |
+ // Set the bootstrap token before bailing out if nigori node is not there. |
+ // This could happen if server asked us to migrate nigri. |
+ cryptographer->Bootstrap(restored_key_for_bootstrapping); |
+} |
+ |
+bool SyncManager::SyncInternal::UpdateCryptographerFromNigori() { |
syncable::ScopedDirLookup lookup(dir_manager(), username_for_share()); |
if (!lookup.good()) { |
- LOG(INFO) << "BootstrapEncryption: lookup not good so bailing out"; |
- NOTREACHED(); |
- return; |
+ NOTREACHED() << "BootstrapEncryption: lookup not good so bailing out"; |
+ return false; |
} |
+ if (!lookup->initial_sync_ended_for_type(syncable::NIGORI)) |
+ return false; // Should only happen during first time sync. |
- sync_pb::NigoriSpecifics nigori; |
- syncable::ModelTypeSet encrypted_types; |
- { |
- // Cryptographer should only be accessed while holding a transaction. |
- ReadTransaction trans(GetUserShare()); |
- Cryptographer* cryptographer = trans.GetCryptographer(); |
- |
- // Set the bootstrap token before bailing out if nigori node is not there. |
- // This could happen if server asked us to migrate nigri. |
- cryptographer->Bootstrap(restored_key_for_bootstrapping); |
- |
- if (!lookup->initial_sync_ended_for_type(syncable::NIGORI)) |
- return; |
- |
- ReadNode node(&trans); |
- if (!node.InitByTagLookup(kNigoriTag)) { |
- NOTREACHED(); |
- return; |
- } |
- |
- nigori.CopyFrom(node.GetNigoriSpecifics()); |
- Cryptographer::UpdateResult result = cryptographer->Update(nigori); |
- if (result == Cryptographer::NEEDS_PASSPHRASE) { |
- ObserverList<SyncManager::Observer> temp_obs_list; |
- CopyObservers(&temp_obs_list); |
- FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list, |
- OnPassphraseRequired(sync_api::REASON_DECRYPTION)); |
- } |
+ ReadTransaction trans(GetUserShare()); |
+ Cryptographer* cryptographer = trans.GetCryptographer(); |
- // Refresh list of encrypted datatypes. |
- encrypted_types = GetEncryptedTypes(&trans); |
+ ReadNode node(&trans); |
+ if (!node.InitByTagLookup(kNigoriTag)) { |
+ NOTREACHED(); |
+ return false; |
+ } |
+ Cryptographer::UpdateResult result = |
+ cryptographer->Update(node.GetNigoriSpecifics()); |
+ if (result == Cryptographer::NEEDS_PASSPHRASE) { |
+ ObserverList<SyncManager::Observer> temp_obs_list; |
+ CopyObservers(&temp_obs_list); |
+ FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list, |
+ OnPassphraseRequired(sync_api::REASON_DECRYPTION)); |
} |
- |
- |
- // Ensure any datatypes that need encryption are encrypted. |
- EncryptDataTypes(encrypted_types); |
+ return cryptographer->is_ready(); |
} |
void SyncManager::SyncInternal::StartSyncingNormally() { |
@@ -2089,14 +2089,19 @@ void SyncManager::SyncInternal::EncryptDataTypes( |
WriteTransaction trans(GetUserShare()); |
WriteNode node(&trans); |
if (!node.InitByTagLookup(kNigoriTag)) { |
- LOG(ERROR) << "Unable to set encrypted datatypes because Nigori node not " |
- << "found."; |
- NOTREACHED(); |
+ NOTREACHED() << "Unable to set encrypted datatypes because Nigori node not " |
+ << "found."; |
return; |
} |
Cryptographer* cryptographer = trans.GetCryptographer(); |
+ if (!cryptographer->is_initialized()) { |
+ NOTREACHED() << "Attempting to encrypt datatypes when cryptographer not " |
+ << "initialized."; |
+ return; |
+ } |
+ |
// Update the Nigori node set of encrypted datatypes so other machines notice. |
// Note, we merge the current encrypted types with those requested. Once a |
// datatypes is marked as needing encryption, it is never unmarked. |
@@ -3002,12 +3007,17 @@ UserShare* SyncManager::GetUserShare() const { |
return data_->GetUserShare(); |
} |
+void SyncManager::RefreshEncryption() { |
+ DCHECK(data_->initialized()); |
+ if (data_->UpdateCryptographerFromNigori()) |
+ data_->EncryptDataTypes(syncable::ModelTypeSet()); |
+} |
+ |
syncable::ModelTypeSet SyncManager::GetEncryptedDataTypes() const { |
sync_api::ReadTransaction trans(GetUserShare()); |
return GetEncryptedTypes(&trans); |
} |
- |
bool SyncManager::HasUnsyncedItems() const { |
sync_api::ReadTransaction trans(GetUserShare()); |
return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0); |