| Index: chrome/browser/sync/engine/syncer_util.cc
|
| diff --git a/chrome/browser/sync/engine/syncer_util.cc b/chrome/browser/sync/engine/syncer_util.cc
|
| index 1be2e0c33e5ef9e56f511617a8dd6e0fac880e1a..20391686a6998a67428369181bd147711da5f52f 100644
|
| --- a/chrome/browser/sync/engine/syncer_util.cc
|
| +++ b/chrome/browser/sync/engine/syncer_util.cc
|
| @@ -253,6 +253,53 @@ UpdateAttemptResponse SyncerUtil::AttemptToUpdateEntry(
|
| if (!entry->Get(IS_UNAPPLIED_UPDATE))
|
| return SUCCESS; // No work to do.
|
| syncable::Id id = entry->Get(ID);
|
| + const sync_pb::EntitySpecifics& specifics = entry->Get(SERVER_SPECIFICS);
|
| +
|
| + // We intercept updates to the Nigori node, update the Cryptographer and
|
| + // encrypt any unsynced changes here because there is no Nigori
|
| + // ChangeProcessor. We never put the nigori node in a state of
|
| + // conflict_encryption.
|
| + //
|
| + // We always update the cryptographer with the server's nigori node,
|
| + // even if we have a locally modified nigori node (we manually merge nigori
|
| + // data in the conflict resolver in that case). 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.
|
| + //
|
| + // If non-encryption changes are made to the nigori node, they will be
|
| + // lost as part of conflict resolution. This is intended, as we place a higher
|
| + // priority on preserving the server's passphrase change to preserving local
|
| + // non-encryption changes. Next time the non-encryption changes are made to
|
| + // the nigori node (e.g. on restart), they will commit without issue.
|
| + if (specifics.HasExtension(sync_pb::nigori)) {
|
| + const sync_pb::NigoriSpecifics& nigori =
|
| + specifics.GetExtension(sync_pb::nigori);
|
| + cryptographer->Update(nigori);
|
| +
|
| + // 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 SetPassphrase time (via ReEncryptEverything). This logic
|
| + // covers the case where the nigori updated 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.
|
| + syncable::ProcessUnsyncedChangesForEncryption(trans,
|
| + cryptographer);
|
| + }
|
| + }
|
|
|
| if (entry->Get(IS_UNSYNCED)) {
|
| DVLOG(1) << "Skipping update, returning conflict for: " << id
|
| @@ -289,44 +336,6 @@ UpdateAttemptResponse SyncerUtil::AttemptToUpdateEntry(
|
| }
|
| }
|
|
|
| - // We intercept updates to the Nigori node, update the Cryptographer and
|
| - // encrypt any unsynced changes here because there is no Nigori
|
| - // ChangeProcessor.
|
| - const sync_pb::EntitySpecifics& specifics = entry->Get(SERVER_SPECIFICS);
|
| - if (specifics.HasExtension(sync_pb::nigori)) {
|
| - const sync_pb::NigoriSpecifics& nigori =
|
| - specifics.GetExtension(sync_pb::nigori);
|
| - cryptographer->Update(nigori);
|
| -
|
| - // Make sure any unsynced changes are properly encrypted as necessary.
|
| - const syncable::ModelTypeSet encrypted_types =
|
| - cryptographer->GetEncryptedTypes();
|
| - if (!VerifyUnsyncedChangesAreEncrypted(trans, encrypted_types) &&
|
| - (!cryptographer->is_ready() ||
|
| - !syncable::ProcessUnsyncedChangesForEncryption(trans,
|
| - cryptographer))) {
|
| - // We were unable to encrypt the changes, possibly due to a missing
|
| - // passphrase. We return conflict, even though the conflict is with the
|
| - // unsynced change and not the nigori node. We ensure foward progress
|
| - // because the cryptographer already has the pending keys set, so once
|
| - // the new passphrase is entered we should be able to encrypt properly.
|
| - // And, because this update will not be applied yet, next time around
|
| - // we will properly encrypt all appropriate unsynced data.
|
| - // Note: we return CONFLICT_ENCRYPTION instead of CONFLICT. See
|
| - // explanation below.
|
| - DVLOG(1) << "Marking nigori node update as conflicting due to being "
|
| - << "unable to encrypt all necessary unsynced changes.";
|
| - return CONFLICT_ENCRYPTION;
|
| - }
|
| -
|
| - // Note that we don't bother to encrypt any synced data that now requires
|
| - // encryption. The machine that turned on encryption should encrypt
|
| - // everything itself. 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 encrypted, all the
|
| - // data should be updated as necessary.
|
| - }
|
| -
|
| // Only apply updates that we can decrypt. If we can't decrypt the update, it
|
| // is likely because the passphrase has not arrived yet. Because the
|
| // passphrase may not arrive within this GetUpdates, we can't just return
|
|
|