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

Unified Diff: sync/internal_api/sync_encryption_handler_impl.cc

Issue 10844005: [Sync] Refactor GetEncryptedTypes usage. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase + add dcheck 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
Index: sync/internal_api/sync_encryption_handler_impl.cc
diff --git a/sync/internal_api/sync_encryption_handler_impl.cc b/sync/internal_api/sync_encryption_handler_impl.cc
index 6ebe4a9f231cf239f0e851c778a54842185651cb..b9f5ed193d19a49f1598d484f63b0d6edde59b29 100644
--- a/sync/internal_api/sync_encryption_handler_impl.cc
+++ b/sync/internal_api/sync_encryption_handler_impl.cc
@@ -19,6 +19,7 @@
#include "sync/internal_api/public/write_transaction.h"
#include "sync/protocol/encryption.pb.h"
#include "sync/protocol/nigori_specifics.pb.h"
+#include "sync/protocol/sync.pb.h"
#include "sync/syncable/base_transaction.h"
#include "sync/syncable/directory.h"
#include "sync/syncable/entry.h"
@@ -36,13 +37,22 @@ namespace {
static const int kNigoriOverwriteLimit = 10;
}
+SyncEncryptionHandlerImpl::Vault::Vault(
+ Encryptor* encryptor,
+ ModelTypeSet encrypted_types)
+ : cryptographer(encryptor),
+ encrypted_types(encrypted_types) {
+}
+
+SyncEncryptionHandlerImpl::Vault::~Vault() {
+}
+
SyncEncryptionHandlerImpl::SyncEncryptionHandlerImpl(
UserShare* user_share,
- Cryptographer* cryptographer)
+ Encryptor* encryptor)
: weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
user_share_(user_share),
- cryptographer_(cryptographer),
- encrypted_types_(SensitiveTypes()),
+ vault_unsafe_(encryptor, SensitiveTypes()),
encrypt_everything_(false),
explicit_passphrase_(false),
nigori_overwrite_count_(0) {
@@ -51,20 +61,21 @@ SyncEncryptionHandlerImpl::SyncEncryptionHandlerImpl(
SyncEncryptionHandlerImpl::~SyncEncryptionHandlerImpl() {}
void SyncEncryptionHandlerImpl::AddObserver(Observer* observer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!observers_.HasObserver(observer));
observers_.AddObserver(observer);
}
void SyncEncryptionHandlerImpl::RemoveObserver(Observer* observer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(observers_.HasObserver(observer));
observers_.RemoveObserver(observer);
}
void SyncEncryptionHandlerImpl::Init() {
+ DCHECK(thread_checker_.CalledOnValidThread());
WriteTransaction trans(FROM_HERE, user_share_);
WriteNode node(&trans);
- Cryptographer* cryptographer = trans.GetCryptographer();
- cryptographer_ = cryptographer;
if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK)
return;
@@ -73,44 +84,31 @@ void SyncEncryptionHandlerImpl::Init() {
WriteEncryptionStateToNigori(&trans);
}
- FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
- OnCryptographerStateChanged(cryptographer));
+ // Always trigger an encrypted types and cryptographer state change event at
+ // init time so observers get the initial values.
+ FOR_EACH_OBSERVER(
+ Observer, observers_,
+ OnEncryptedTypesChanged(
+ UnlockVault(trans.GetWrappedTrans()).encrypted_types,
+ encrypt_everything_));
+ FOR_EACH_OBSERVER(
+ SyncEncryptionHandler::Observer,
+ observers_,
+ OnCryptographerStateChanged(
+ &UnlockVaultMutable(trans.GetWrappedTrans())->cryptographer));
// If the cryptographer is not ready (either it has pending keys or we
// failed to initialize it), we don't want to try and re-encrypt the data.
// If we had encrypted types, the DataTypeManager will block, preventing
// sync from happening until the the passphrase is provided.
- if (cryptographer->is_ready())
+ if (UnlockVault(trans.GetWrappedTrans()).cryptographer.is_ready())
ReEncryptEverything(&trans);
}
-// Note: this is called from within a syncable transaction, so we need to post
-// tasks if we want to do any work that creates a new sync_api transaction.
-void SyncEncryptionHandlerImpl::ApplyNigoriUpdate(
- const sync_pb::NigoriSpecifics& nigori,
- syncable::BaseTransaction* const trans) {
- DCHECK(trans);
- if (!ApplyNigoriUpdateImpl(nigori, trans)) {
- MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&SyncEncryptionHandlerImpl::RewriteNigori,
- weak_ptr_factory_.GetWeakPtr()));
- }
-
- FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
- OnCryptographerStateChanged(cryptographer_));
-}
-
-// Note: this is always called via the Cryptographer interface right now,
-// so a transaction is already held. Once we remove that interface, we'll
-// need to enforce holding a transaction when calling this method.
-ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypes() const {
- return encrypted_types_;
-}
-
void SyncEncryptionHandlerImpl::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.";
@@ -119,7 +117,6 @@ void SyncEncryptionHandlerImpl::SetEncryptionPassphrase(
// All accesses to the cryptographer are protected by a transaction.
WriteTransaction trans(FROM_HERE, user_share_);
- Cryptographer* cryptographer = trans.GetCryptographer();
KeyParams key_params = {"localhost", "dummy", passphrase};
WriteNode node(&trans);
if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) {
@@ -131,11 +128,12 @@ void SyncEncryptionHandlerImpl::SetEncryptionPassphrase(
node.GetNigoriSpecifics().using_explicit_passphrase();
std::string bootstrap_token;
sync_pb::EncryptedData pending_keys;
+ Cryptographer* cryptographer =
+ &UnlockVaultMutable(trans.GetWrappedTrans())->cryptographer;
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
@@ -224,6 +222,7 @@ void SyncEncryptionHandlerImpl::SetEncryptionPassphrase(
void SyncEncryptionHandlerImpl::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.";
@@ -232,7 +231,6 @@ void SyncEncryptionHandlerImpl::SetDecryptionPassphrase(
// All accesses to the cryptographer are protected by a transaction.
WriteTransaction trans(FROM_HERE, user_share_);
- Cryptographer* cryptographer = trans.GetCryptographer();
KeyParams key_params = {"localhost", "dummy", passphrase};
WriteNode node(&trans);
if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) {
@@ -240,6 +238,8 @@ void SyncEncryptionHandlerImpl::SetDecryptionPassphrase(
return;
}
+ Cryptographer* cryptographer =
+ &UnlockVaultMutable(trans.GetWrappedTrans())->cryptographer;
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
@@ -364,43 +364,94 @@ void SyncEncryptionHandlerImpl::SetDecryptionPassphrase(
}
void SyncEncryptionHandlerImpl::EnableEncryptEverything() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ WriteTransaction trans(FROM_HERE, user_share_);
+ ModelTypeSet* encrypted_types =
+ &UnlockVaultMutable(trans.GetWrappedTrans())->encrypted_types;
if (encrypt_everything_) {
- DCHECK(encrypted_types_.Equals(ModelTypeSet::All()));
+ DCHECK(encrypted_types->Equals(ModelTypeSet::All()));
return;
}
- WriteTransaction trans(FROM_HERE, user_share_);
+ DVLOG(1) << "Enabling encrypt everything.";
encrypt_everything_ = true;
// Change |encrypted_types_| directly to avoid sending more than one
// notification.
- encrypted_types_ = ModelTypeSet::All();
+ *encrypted_types = ModelTypeSet::All();
FOR_EACH_OBSERVER(
Observer, observers_,
- OnEncryptedTypesChanged(encrypted_types_, encrypt_everything_));
+ OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_));
WriteEncryptionStateToNigori(&trans);
- ReEncryptEverything(&trans);
+ if (UnlockVault(trans.GetWrappedTrans()).cryptographer.is_ready())
+ ReEncryptEverything(&trans);
}
bool SyncEncryptionHandlerImpl::EncryptEverythingEnabled() const {
- ReadTransaction trans(FROM_HERE, user_share_);
+ DCHECK(thread_checker_.CalledOnValidThread());
return encrypt_everything_;
}
bool SyncEncryptionHandlerImpl::IsUsingExplicitPassphrase() const {
+ // TODO(zea): this is called from the UI thread, so we have to have a
+ // transaction while accessing it. Add an OnPassphraseTypeChanged observer
+ // and have the SBH cache the value on the UI thread.
ReadTransaction trans(FROM_HERE, user_share_);
return explicit_passphrase_;
}
+// Note: this is called from within a syncable transaction, so we need to post
+// tasks if we want to do any work that creates a new sync_api transaction.
+void SyncEncryptionHandlerImpl::ApplyNigoriUpdate(
+ const sync_pb::NigoriSpecifics& nigori,
+ syncable::BaseTransaction* const trans) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(trans);
+ if (!ApplyNigoriUpdateImpl(nigori, trans)) {
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&SyncEncryptionHandlerImpl::RewriteNigori,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ FOR_EACH_OBSERVER(
+ SyncEncryptionHandler::Observer,
+ observers_,
+ OnCryptographerStateChanged(
+ &UnlockVaultMutable(trans)->cryptographer));
+}
+
+void SyncEncryptionHandlerImpl::UpdateNigoriFromEncryptedTypes(
+ sync_pb::NigoriSpecifics* nigori,
+ syncable::BaseTransaction* const trans) const {
+ syncable::UpdateNigoriFromEncryptedTypes(UnlockVault(trans).encrypted_types,
+ encrypt_everything_,
+ nigori);
+}
+
+ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypes(
+ syncable::BaseTransaction* const trans) const {
+ return UnlockVault(trans).encrypted_types;
+}
+
+Cryptographer* SyncEncryptionHandlerImpl::GetCryptographerUnsafe() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return &vault_unsafe_.cryptographer;
+}
+
+ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypesUnsafe() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return vault_unsafe_.encrypted_types;
+}
+
// 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 SyncEncryptionHandlerImpl::ReEncryptEverything(
WriteTransaction* trans) {
- Cryptographer* cryptographer = trans->GetCryptographer();
- if (!cryptographer->is_ready())
- return;
- ModelTypeSet encrypted_types = GetEncryptedTypes();
- for (ModelTypeSet::Iterator iter = encrypted_types.First();
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(UnlockVault(trans->GetWrappedTrans()).cryptographer.is_ready());
+ for (ModelTypeSet::Iterator iter =
+ UnlockVault(trans->GetWrappedTrans()).encrypted_types.First();
iter.Good(); iter.Inc()) {
if (iter.Get() == PASSWORDS || iter.Get() == NIGORI)
continue; // These types handle encryption differently.
@@ -455,6 +506,8 @@ void SyncEncryptionHandlerImpl::ReEncryptEverything(
}
}
+ DVLOG(1) << "Re-encrypt everything complete.";
+
// NOTE: We notify from within a transaction.
FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
OnEncryptionComplete());
@@ -463,11 +516,13 @@ void SyncEncryptionHandlerImpl::ReEncryptEverything(
bool SyncEncryptionHandlerImpl::ApplyNigoriUpdateImpl(
const sync_pb::NigoriSpecifics& nigori,
syncable::BaseTransaction* const trans) {
- Cryptographer* cryptographer = trans->directory()->GetCryptographer(trans);
- bool nigori_types_need_update = !UpdateEncryptedTypesFromNigori(nigori);
+ DCHECK(thread_checker_.CalledOnValidThread());
+ bool nigori_types_need_update = !UpdateEncryptedTypesFromNigori(nigori,
+ trans);
if (nigori.using_explicit_passphrase())
explicit_passphrase_ = true;
+ Cryptographer* cryptographer = &UnlockVaultMutable(trans)->cryptographer;
bool nigori_needs_new_keys = false;
if (!nigori.encrypted().blob().empty()) {
if (cryptographer->CanDecrypt(nigori.encrypted())) {
@@ -522,24 +577,28 @@ bool SyncEncryptionHandlerImpl::ApplyNigoriUpdateImpl(
}
void SyncEncryptionHandlerImpl::RewriteNigori() {
+ DVLOG(1) << "Overwriting stale nigori node.";
+ DCHECK(thread_checker_.CalledOnValidThread());
WriteTransaction trans(FROM_HERE, user_share_);
WriteEncryptionStateToNigori(&trans);
}
void SyncEncryptionHandlerImpl::WriteEncryptionStateToNigori(
WriteTransaction* trans) {
+ DCHECK(thread_checker_.CalledOnValidThread());
WriteNode nigori_node(trans);
// This can happen in tests that don't have nigori nodes.
- if (!nigori_node.InitByTagLookup(kNigoriTag) == BaseNode::INIT_OK)
+ if (nigori_node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK)
return;
sync_pb::NigoriSpecifics nigori = nigori_node.GetNigoriSpecifics();
- Cryptographer* cryptographer = trans->GetCryptographer();
- if (cryptographer->is_ready() &&
+ const Cryptographer& cryptographer =
+ UnlockVault(trans->GetWrappedTrans()).cryptographer;
+ 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()))
+ if (!cryptographer.GetKeys(nigori.mutable_encrypted()))
NOTREACHED();
if (nigori.encrypted().SerializeAsString() !=
@@ -556,58 +615,55 @@ void SyncEncryptionHandlerImpl::WriteEncryptionStateToNigori(
// is lost the user can always set it again. The main point is to preserve
// the encryption keys so all data remains decryptable.
}
- syncable::UpdateNigoriFromEncryptedTypes(encrypted_types_,
- encrypt_everything_,
- &nigori);
+ syncable::UpdateNigoriFromEncryptedTypes(
+ UnlockVault(trans->GetWrappedTrans()).encrypted_types,
+ encrypt_everything_,
+ &nigori);
// If nothing has changed, this is a no-op.
nigori_node.SetNigoriSpecifics(nigori);
}
bool SyncEncryptionHandlerImpl::UpdateEncryptedTypesFromNigori(
- const sync_pb::NigoriSpecifics& nigori) {
+ const sync_pb::NigoriSpecifics& nigori,
+ syncable::BaseTransaction* const trans) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ ModelTypeSet* encrypted_types = &UnlockVaultMutable(trans)->encrypted_types;
if (nigori.encrypt_everything()) {
if (!encrypt_everything_) {
encrypt_everything_ = true;
- encrypted_types_ = ModelTypeSet::All();
+ *encrypted_types = ModelTypeSet::All();
+ DVLOG(1) << "Enabling encrypt everything via nigori node update";
FOR_EACH_OBSERVER(
Observer, observers_,
- OnEncryptedTypesChanged(encrypted_types_, encrypt_everything_));
+ OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_));
}
- DCHECK(encrypted_types_.Equals(ModelTypeSet::All()));
+ DCHECK(encrypted_types->Equals(ModelTypeSet::All()));
return true;
}
- ModelTypeSet encrypted_types;
- encrypted_types = syncable::GetEncryptedTypesFromNigori(nigori);
- encrypted_types.PutAll(SensitiveTypes());
+ ModelTypeSet nigori_encrypted_types;
+ nigori_encrypted_types = syncable::GetEncryptedTypesFromNigori(nigori);
+ nigori_encrypted_types.PutAll(SensitiveTypes());
// If anything more than the sensitive types were encrypted, and
// encrypt_everything is not explicitly set to false, we assume it means
// a client intended to enable encrypt everything.
if (!nigori.has_encrypt_everything() &&
- !Difference(encrypted_types, SensitiveTypes()).Empty()) {
+ !Difference(nigori_encrypted_types, SensitiveTypes()).Empty()) {
if (!encrypt_everything_) {
encrypt_everything_ = true;
- encrypted_types_ = ModelTypeSet::All();
+ *encrypted_types = ModelTypeSet::All();
FOR_EACH_OBSERVER(
Observer, observers_,
- OnEncryptedTypesChanged(encrypted_types_, encrypt_everything_));
+ OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_));
}
- DCHECK(encrypted_types_.Equals(ModelTypeSet::All()));
+ DCHECK(encrypted_types->Equals(ModelTypeSet::All()));
return false;
}
- MergeEncryptedTypes(encrypted_types);
- return encrypted_types_.Equals(encrypted_types);
-}
-
-void SyncEncryptionHandlerImpl::UpdateNigoriFromEncryptedTypes(
- sync_pb::NigoriSpecifics* nigori,
- syncable::BaseTransaction* const trans) const {
- syncable::UpdateNigoriFromEncryptedTypes(encrypted_types_,
- encrypt_everything_,
- nigori);
+ MergeEncryptedTypes(nigori_encrypted_types, trans);
+ return encrypted_types->Equals(nigori_encrypted_types);
}
void SyncEncryptionHandlerImpl::FinishSetPassphrase(
@@ -616,9 +672,12 @@ void SyncEncryptionHandlerImpl::FinishSetPassphrase(
bool is_explicit,
WriteTransaction* trans,
WriteNode* nigori_node) {
- Cryptographer* cryptographer = trans->GetCryptographer();
- FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
- OnCryptographerStateChanged(cryptographer));
+ DCHECK(thread_checker_.CalledOnValidThread());
+ FOR_EACH_OBSERVER(
+ SyncEncryptionHandler::Observer,
+ observers_,
+ OnCryptographerStateChanged(
+ &UnlockVaultMutable(trans->GetWrappedTrans())->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
@@ -629,14 +688,16 @@ void SyncEncryptionHandlerImpl::FinishSetPassphrase(
OnBootstrapTokenUpdated(bootstrap_token));
}
+ const Cryptographer& cryptographer =
+ UnlockVault(trans->GetWrappedTrans()).cryptographer;
if (!success) {
- if (cryptographer->is_ready()) {
+ if (cryptographer.is_ready()) {
LOG(ERROR) << "Attempt to change passphrase failed while cryptographer "
<< "was ready.";
- } else if (cryptographer->has_pending_keys()) {
+ } else if (cryptographer.has_pending_keys()) {
FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
OnPassphraseRequired(REASON_DECRYPTION,
- cryptographer->GetPendingKeys()));
+ cryptographer.GetPendingKeys()));
} else {
FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
OnPassphraseRequired(REASON_ENCRYPTION,
@@ -647,32 +708,44 @@ void SyncEncryptionHandlerImpl::FinishSetPassphrase(
FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
OnPassphraseAccepted());
- DCHECK(cryptographer->is_ready());
+ DCHECK(cryptographer.is_ready());
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())) {
+ if (!cryptographer.GetKeys(specifics.mutable_encrypted()))
NOTREACHED();
- return;
- }
explicit_passphrase_ = is_explicit;
specifics.set_using_explicit_passphrase(is_explicit);
nigori_node->SetNigoriSpecifics(specifics);
- // Does nothing if everything is already encrypted or the cryptographer has
- // pending keys.
+ // Does nothing if everything is already encrypted.
ReEncryptEverything(trans);
}
void SyncEncryptionHandlerImpl::MergeEncryptedTypes(
- ModelTypeSet encrypted_types) {
- if (!encrypted_types_.HasAll(encrypted_types)) {
- encrypted_types_ = encrypted_types;
+ ModelTypeSet new_encrypted_types,
+ syncable::BaseTransaction* const trans) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ ModelTypeSet* encrypted_types = &UnlockVaultMutable(trans)->encrypted_types;
+ if (!encrypted_types->HasAll(new_encrypted_types)) {
+ *encrypted_types = new_encrypted_types;
FOR_EACH_OBSERVER(
Observer, observers_,
- OnEncryptedTypesChanged(encrypted_types_, encrypt_everything_));
+ OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_));
}
}
+SyncEncryptionHandlerImpl::Vault* SyncEncryptionHandlerImpl::UnlockVaultMutable(
+ syncable::BaseTransaction* const trans) {
+ DCHECK_EQ(user_share_->directory.get(), trans->directory());
+ return &vault_unsafe_;
+}
+
+const SyncEncryptionHandlerImpl::Vault& SyncEncryptionHandlerImpl::UnlockVault(
+ syncable::BaseTransaction* const trans) const {
+ DCHECK_EQ(user_share_->directory.get(), trans->directory());
+ return vault_unsafe_;
+}
+
} // namespace browser_sync
« no previous file with comments | « sync/internal_api/sync_encryption_handler_impl.h ('k') | sync/internal_api/sync_encryption_handler_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698