| Index: sync/engine/apply_control_data_updates.cc
|
| diff --git a/sync/engine/apply_control_data_updates.cc b/sync/engine/apply_control_data_updates.cc
|
| deleted file mode 100644
|
| index 0f5ae398c6aa9f9d15e651973fb2aa3456feb6ab..0000000000000000000000000000000000000000
|
| --- a/sync/engine/apply_control_data_updates.cc
|
| +++ /dev/null
|
| @@ -1,228 +0,0 @@
|
| -// Copyright 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "sync/engine/apply_control_data_updates.h"
|
| -
|
| -#include <stdint.h>
|
| -
|
| -#include <vector>
|
| -
|
| -#include "base/metrics/histogram.h"
|
| -#include "sync/engine/conflict_resolver.h"
|
| -#include "sync/engine/conflict_util.h"
|
| -#include "sync/engine/syncer_util.h"
|
| -#include "sync/syncable/directory.h"
|
| -#include "sync/syncable/mutable_entry.h"
|
| -#include "sync/syncable/nigori_handler.h"
|
| -#include "sync/syncable/nigori_util.h"
|
| -#include "sync/syncable/syncable_write_transaction.h"
|
| -#include "sync/util/cryptographer.h"
|
| -
|
| -namespace syncer {
|
| -
|
| -void ApplyControlDataUpdates(syncable::Directory* dir) {
|
| - syncable::WriteTransaction trans(FROM_HERE, syncable::SYNCER, dir);
|
| -
|
| - std::vector<int64_t> handles;
|
| - dir->GetUnappliedUpdateMetaHandles(
|
| - &trans, ToFullModelTypeSet(ControlTypes()), &handles);
|
| -
|
| - // First, go through and manually apply any new top level datatype nodes (so
|
| - // that we don't have to worry about hitting a CONFLICT_HIERARCHY with an
|
| - // entry because we haven't applied its parent yet).
|
| - // TODO(sync): if at some point we support control datatypes with actual
|
| - // hierarchies we'll need to revisit this logic.
|
| - ModelTypeSet control_types = ControlTypes();
|
| - for (ModelTypeSet::Iterator iter = control_types.First(); iter.Good();
|
| - iter.Inc()) {
|
| - ModelType type = iter.Get();
|
| - syncable::MutableEntry entry(&trans, syncable::GET_TYPE_ROOT, type);
|
| - if (!entry.good())
|
| - continue;
|
| -
|
| - if (!entry.GetIsUnappliedUpdate()) {
|
| - // If this is a type with client generated root, the root node has been
|
| - // created locally and might never be updated by the server. In that case
|
| - // it has to be marked as having the initial download completed (which is
|
| - // done by changing the root's base version to a value other than
|
| - // CHANGES_VERSION). This does nothing if the root's base version is
|
| - // already other than CHANGES_VERSION.
|
| - if (IsTypeWithClientGeneratedRoot(type)) {
|
| - dir->MarkInitialSyncEndedForType(&trans, type);
|
| - }
|
| - continue;
|
| - }
|
| -
|
| - DCHECK_EQ(type, entry.GetServerModelType());
|
| - if (type == NIGORI) {
|
| - // Nigori node applications never fail.
|
| - ApplyNigoriUpdate(&trans,
|
| - &entry,
|
| - dir->GetCryptographer(&trans));
|
| - } else {
|
| - ApplyControlUpdate(&trans,
|
| - &entry,
|
| - dir->GetCryptographer(&trans));
|
| - }
|
| - }
|
| -
|
| - // Go through the rest of the unapplied control updates, skipping over any
|
| - // top level folders.
|
| - for (std::vector<int64_t>::const_iterator iter = handles.begin();
|
| - iter != handles.end(); ++iter) {
|
| - syncable::MutableEntry entry(&trans, syncable::GET_BY_HANDLE, *iter);
|
| - CHECK(entry.good());
|
| - ModelType type = entry.GetServerModelType();
|
| - CHECK(ControlTypes().Has(type));
|
| - if (!entry.GetUniqueServerTag().empty()) {
|
| - // We should have already applied all top level control nodes.
|
| - DCHECK(!entry.GetIsUnappliedUpdate());
|
| - continue;
|
| - }
|
| -
|
| - ApplyControlUpdate(&trans,
|
| - &entry,
|
| - dir->GetCryptographer(&trans));
|
| - }
|
| -}
|
| -
|
| -// Update the nigori handler with the server's nigori node.
|
| -//
|
| -// If we have a locally modified nigori node, we merge them manually. This
|
| -// handles the case where two clients both set a different passphrase. The
|
| -// second client to attempt to commit will go into a state of having pending
|
| -// keys, unioned the set of encrypted types, and eventually re-encrypt
|
| -// everything with the passphrase of the first client and commit the set of
|
| -// merged encryption keys. Until the second client provides the pending
|
| -// passphrase, the cryptographer will preserve the encryption keys based on the
|
| -// local passphrase, while the nigori node will preserve the server encryption
|
| -// keys.
|
| -void ApplyNigoriUpdate(syncable::WriteTransaction* const trans,
|
| - syncable::MutableEntry* const entry,
|
| - Cryptographer* cryptographer) {
|
| - DCHECK(entry->GetIsUnappliedUpdate());
|
| -
|
| - // We apply the nigori update regardless of whether there's a conflict or
|
| - // not in order to preserve any new encrypted types or encryption keys.
|
| - // TODO(zea): consider having this return a bool reflecting whether it was a
|
| - // valid update or not, and in the case of invalid updates not overwrite the
|
| - // local data.
|
| - const sync_pb::NigoriSpecifics& nigori =
|
| - entry->GetServerSpecifics().nigori();
|
| - trans->directory()->GetNigoriHandler()->ApplyNigoriUpdate(nigori, trans);
|
| -
|
| - // Make sure any unsynced changes are properly encrypted as necessary.
|
| - // We only perform this if the cryptographer is ready. If not, these are
|
| - // re-encrypted at SetDecryptionPassphrase time (via ReEncryptEverything).
|
| - // This logic covers the case where the nigori update marked new datatypes
|
| - // for encryption, but didn't change the passphrase.
|
| - if (cryptographer->is_ready()) {
|
| - // Note that we don't bother to encrypt any data for which IS_UNSYNCED
|
| - // == false here. The machine that turned on encryption should know about
|
| - // and re-encrypt all synced data. It's possible it could get interrupted
|
| - // during this process, but we currently reencrypt everything at startup
|
| - // as well, so as soon as a client is restarted with this datatype marked
|
| - // for encryption, all the data should be updated as necessary.
|
| -
|
| - // If this fails, something is wrong with the cryptographer, but there's
|
| - // nothing we can do about it here.
|
| - DVLOG(1) << "Received new nigori, encrypting unsynced changes.";
|
| - syncable::ProcessUnsyncedChangesForEncryption(trans);
|
| - }
|
| -
|
| - if (!entry->GetIsUnsynced()) { // Update only.
|
| - UpdateLocalDataFromServerData(trans, entry);
|
| - } else { // Conflict.
|
| - const sync_pb::EntitySpecifics& server_specifics =
|
| - entry->GetServerSpecifics();
|
| - const sync_pb::NigoriSpecifics& server_nigori = server_specifics.nigori();
|
| - const sync_pb::EntitySpecifics& local_specifics =
|
| - entry->GetSpecifics();
|
| - const sync_pb::NigoriSpecifics& local_nigori = local_specifics.nigori();
|
| -
|
| - // We initialize the new nigori with the server state, and will override
|
| - // it as necessary below.
|
| - sync_pb::EntitySpecifics new_specifics = entry->GetServerSpecifics();
|
| - sync_pb::NigoriSpecifics* new_nigori = new_specifics.mutable_nigori();
|
| -
|
| - // If the cryptographer is not ready, another client set a new encryption
|
| - // passphrase. If we had migrated locally, we will re-migrate when the
|
| - // pending keys are provided. If we had set a new custom passphrase locally
|
| - // the user will have another chance to set a custom passphrase later
|
| - // (assuming they hadn't set a custom passphrase on the other client).
|
| - // Therefore, we only attempt to merge the nigori nodes if the cryptographer
|
| - // is ready.
|
| - // Note: we only update the encryption keybag if we're sure that we aren't
|
| - // invalidating the keystore_decryptor_token (i.e. we're either
|
| - // not migrated or we copying over all local state).
|
| - if (cryptographer->is_ready()) {
|
| - if (local_nigori.has_passphrase_type() &&
|
| - server_nigori.has_passphrase_type()) {
|
| - // They're both migrated, preserve the local nigori if the passphrase
|
| - // type is more conservative.
|
| - if (server_nigori.passphrase_type() ==
|
| - sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE &&
|
| - local_nigori.passphrase_type() !=
|
| - sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE) {
|
| - DCHECK(local_nigori.passphrase_type() ==
|
| - sync_pb::NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE ||
|
| - local_nigori.passphrase_type() ==
|
| - sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
|
| - new_nigori->CopyFrom(local_nigori);
|
| - cryptographer->GetKeys(new_nigori->mutable_encryption_keybag());
|
| - }
|
| - } else if (!local_nigori.has_passphrase_type() &&
|
| - !server_nigori.has_passphrase_type()) {
|
| - // Set the explicit passphrase based on the local state. If the server
|
| - // had set an explict passphrase, we should have pending keys, so
|
| - // should not reach this code.
|
| - // Because neither side is migrated, we don't have to worry about the
|
| - // keystore decryptor token.
|
| - new_nigori->set_keybag_is_frozen(local_nigori.keybag_is_frozen());
|
| - cryptographer->GetKeys(new_nigori->mutable_encryption_keybag());
|
| - } else if (local_nigori.has_passphrase_type()) {
|
| - // Local is migrated but server is not. Copy over the local migrated
|
| - // data.
|
| - new_nigori->CopyFrom(local_nigori);
|
| - cryptographer->GetKeys(new_nigori->mutable_encryption_keybag());
|
| - } // else leave the new nigori with the server state.
|
| - }
|
| -
|
| - // Always update to the safest set of encrypted types.
|
| - trans->directory()->GetNigoriHandler()->UpdateNigoriFromEncryptedTypes(
|
| - new_nigori,
|
| - trans);
|
| -
|
| - entry->PutSpecifics(new_specifics);
|
| - DVLOG(1) << "Resolving simple conflict, merging nigori nodes: "
|
| - << entry;
|
| -
|
| - conflict_util::OverwriteServerChanges(entry);
|
| -
|
| - UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
|
| - ConflictResolver::NIGORI_MERGE,
|
| - ConflictResolver::CONFLICT_RESOLUTION_SIZE);
|
| - }
|
| -}
|
| -
|
| -void ApplyControlUpdate(syncable::WriteTransaction* const trans,
|
| - syncable::MutableEntry* const entry,
|
| - Cryptographer* cryptographer) {
|
| - DCHECK_NE(entry->GetServerModelType(), NIGORI);
|
| - DCHECK(entry->GetIsUnappliedUpdate());
|
| - if (entry->GetIsUnsynced()) {
|
| - // We just let the server win all conflicts with control types.
|
| - DVLOG(1) << "Ignoring local changes for control update.";
|
| - conflict_util::IgnoreLocalChanges(entry);
|
| - UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
|
| - ConflictResolver::OVERWRITE_LOCAL,
|
| - ConflictResolver::CONFLICT_RESOLUTION_SIZE);
|
| - }
|
| -
|
| - UpdateAttemptResponse response = AttemptToUpdateEntry(
|
| - trans, entry, cryptographer);
|
| - DCHECK_EQ(SUCCESS, response);
|
| -}
|
| -
|
| -} // namespace syncer
|
|
|