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

Unified Diff: chrome/browser/sync/engine/syncer_util.cc

Issue 8917031: [Sync] Add nigori node conflict resolution. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase + pass trans/cryptographer directly through Created 9 years 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: 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
« no previous file with comments | « chrome/browser/sync/engine/syncer_unittest.cc ('k') | chrome/browser/sync/test/engine/mock_connection_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698