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

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: Always trigger OnEncryptedTypesChanged on init 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..ec670ac565ca62c6456ea27ba4d57198e9bab914 100644
--- a/sync/internal_api/sync_encryption_handler_impl.cc
+++ b/sync/internal_api/sync_encryption_handler_impl.cc
@@ -13,12 +13,12 @@
#include "base/metrics/histogram.h"
#include "sync/internal_api/public/read_node.h"
#include "sync/internal_api/public/read_transaction.h"
-#include "sync/internal_api/public/user_share.h"
#include "sync/internal_api/public/util/experiments.h"
#include "sync/internal_api/public/write_node.h"
#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 +36,29 @@ namespace {
static const int kNigoriOverwriteLimit = 10;
}
+template <typename T>
+const T& TransactionalHolder<T>::Get(
+ syncable::BaseTransaction* const trans) const {
+ DCHECK_EQ(user_share_->directory.get(), trans->directory());
+ return *obj_;
+}
+
+template <typename T>
+T* TransactionalHolder<T>::GetMutable(
+ syncable::BaseTransaction* const trans) {
+ DCHECK_EQ(user_share_->directory.get(), trans->directory());
+ return obj_;
+}
+
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()),
+ cryptographer_unsafe_(encryptor),
+ encrypted_types_unsafe_(SensitiveTypes()),
+ cryptographer_holder_(user_share_, &cryptographer_unsafe_),
+ encrypted_types_holder_(user_share_, &encrypted_types_unsafe_),
encrypt_everything_(false),
explicit_passphrase_(false),
nigori_overwrite_count_(0) {
@@ -51,20 +67,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 +90,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(
+ encrypted_types_holder_.Get(trans.GetWrappedTrans()),
+ encrypt_everything_));
+ FOR_EACH_OBSERVER(
+ SyncEncryptionHandler::Observer,
+ observers_,
+ OnCryptographerStateChanged(
+ cryptographer_holder_.GetMutable(trans.GetWrappedTrans())));
// 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 (cryptographer_holder_.Get(trans.GetWrappedTrans()).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 +123,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 +134,12 @@ void SyncEncryptionHandlerImpl::SetEncryptionPassphrase(
node.GetNigoriSpecifics().using_explicit_passphrase();
std::string bootstrap_token;
sync_pb::EncryptedData pending_keys;
+ Cryptographer* cryptographer =
+ cryptographer_holder_.GetMutable(trans.GetWrappedTrans());
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 +228,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 +237,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 +244,8 @@ void SyncEncryptionHandlerImpl::SetDecryptionPassphrase(
return;
}
+ Cryptographer* cryptographer =
+ cryptographer_holder_.GetMutable(trans.GetWrappedTrans());
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 +370,84 @@ void SyncEncryptionHandlerImpl::SetDecryptionPassphrase(
}
void SyncEncryptionHandlerImpl::EnableEncryptEverything() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ WriteTransaction trans(FROM_HERE, user_share_);
+ ModelTypeSet* encrypted_types =
+ encrypted_types_holder_.GetMutable(trans.GetWrappedTrans());
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 (cryptographer_holder_.Get(trans.GetWrappedTrans()).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(
tim (not reviewing) 2012/08/23 18:38:10 Should we bubble the trans up through this observe
Nicolas Zea 2012/08/23 22:49:32 We'd have to do that with most other observer meth
+ cryptographer_holder_.GetMutable(trans)));
+}
+
+void SyncEncryptionHandlerImpl::UpdateNigoriFromEncryptedTypes(
+ sync_pb::NigoriSpecifics* nigori,
+ syncable::BaseTransaction* const trans) const {
+ syncable::UpdateNigoriFromEncryptedTypes(encrypted_types_holder_.Get(trans),
+ encrypt_everything_,
+ nigori);
+}
+
+ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypes(
+ syncable::BaseTransaction* const trans) const {
+ return encrypted_types_holder_.Get(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 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(cryptographer_holder_.Get(trans->GetWrappedTrans()).is_ready());
+ for (ModelTypeSet::Iterator iter = encrypted_types_holder_.Get(
+ trans->GetWrappedTrans()).First();
iter.Good(); iter.Inc()) {
if (iter.Get() == PASSWORDS || iter.Get() == NIGORI)
continue; // These types handle encryption differently.
@@ -455,6 +502,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 +512,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 = cryptographer_holder_.GetMutable(trans);
bool nigori_needs_new_keys = false;
if (!nigori.encrypted().blob().empty()) {
if (cryptographer->CanDecrypt(nigori.encrypted())) {
@@ -522,24 +573,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 = cryptographer_holder_.Get(
+ trans->GetWrappedTrans());
+ 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 +611,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(
+ encrypted_types_holder_.Get(trans->GetWrappedTrans()),
+ 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 = encrypted_types_holder_.GetMutable(trans);
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 +668,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(
+ cryptographer_holder_.GetMutable(trans->GetWrappedTrans())));
// 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 +684,16 @@ void SyncEncryptionHandlerImpl::FinishSetPassphrase(
OnBootstrapTokenUpdated(bootstrap_token));
}
+ const Cryptographer& cryptographer =
+ cryptographer_holder_.Get(trans->GetWrappedTrans());
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,31 +704,31 @@ 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 = encrypted_types_holder_.GetMutable(trans);
+ 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_));
}
}

Powered by Google App Engine
This is Rietveld 408576698