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

Side by Side 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: Re-add some lines lost in the split 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/sync/engine/syncer_util.h" 5 #include "chrome/browser/sync/engine/syncer_util.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <set> 8 #include <set>
9 #include <string> 9 #include <string>
10 #include <vector> 10 #include <vector>
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 // static 246 // static
247 UpdateAttemptResponse SyncerUtil::AttemptToUpdateEntry( 247 UpdateAttemptResponse SyncerUtil::AttemptToUpdateEntry(
248 syncable::WriteTransaction* const trans, 248 syncable::WriteTransaction* const trans,
249 syncable::MutableEntry* const entry, 249 syncable::MutableEntry* const entry,
250 ConflictResolver* resolver, 250 ConflictResolver* resolver,
251 Cryptographer* cryptographer) { 251 Cryptographer* cryptographer) {
252 CHECK(entry->good()); 252 CHECK(entry->good());
253 if (!entry->Get(IS_UNAPPLIED_UPDATE)) 253 if (!entry->Get(IS_UNAPPLIED_UPDATE))
254 return SUCCESS; // No work to do. 254 return SUCCESS; // No work to do.
255 syncable::Id id = entry->Get(ID); 255 syncable::Id id = entry->Get(ID);
256 const sync_pb::EntitySpecifics& specifics = entry->Get(SERVER_SPECIFICS);
257
258 // We intercept updates to the Nigori node, update the Cryptographer and
259 // encrypt any unsynced changes here because there is no Nigori
260 // ChangeProcessor. We never put the nigori node in a state of
261 // conflict_encryption
tim (not reviewing) 2011/12/20 17:54:05 period.
Nicolas Zea 2011/12/20 19:54:10 Done.
262 //
263 // We always update the cryptographer with the server's nigori node,
264 // even if we have a locally modified nigori node (we manually merge nigori
265 // data in the conflict resolver in that case). This handles the case where
266 // two clients both set a different passphrase. The second client to attempt
267 // to commit will go into a state of having pending keys, merge the set of
268 // encrypted types, and eventually re-encrypt everything with the passphrase
tim (not reviewing) 2011/12/20 17:54:05 We should probably say union instead of merged whe
Nicolas Zea 2011/12/20 19:54:10 Done.
269 // of the first client and commit the set of merged encryption keys. Until the
270 // second client provides the pending passphrase, the cryptographer will
271 // preserve the encryption keys based on the local passphrase, while the
272 // nigori node will preserve the server encryption keys.
273 //
274 // If non-encryption changes are made to the nigori node, they will be
275 // lost as part of conflict resolution. This is intended, as we place a higher
276 // priority on preserving the server's passphrase change to preserving local
277 // non-encryption changes. Next time the non-encryption changes are made to
278 // the nigori node (e.g. on restart), they will commit without issue.
279 if (specifics.HasExtension(sync_pb::nigori)) {
280 const sync_pb::NigoriSpecifics& nigori =
281 specifics.GetExtension(sync_pb::nigori);
282 cryptographer->Update(nigori);
283
284 // Make sure any unsynced changes are properly encrypted as necessary.
285 // We only perform this is the cryptographer is ready. If not, these are
tim (not reviewing) 2011/12/20 17:54:05 s/is/if
Nicolas Zea 2011/12/20 19:54:10 Done.
286 // re-encrypted at SetPassphrase time (via ReEncryptEverything).
287 if (cryptographer->is_ready()) {
288 // Note that we don't bother to re-encrypt any data for which IS_UNSYNCED
289 // == false. The machine that turned on encryption should re-encrypt
290 // everything itself. It's possible it could get interrupted during this
tim (not reviewing) 2011/12/20 17:54:05 Is this the first official departure from the orig
Nicolas Zea 2011/12/20 19:54:10 The logic to re-encrypt on restart has been there
291 // process, but we currently reencrypt everything at startup as well,
292 // so as soon as a client is restarted with this datatype encrypted, all
293 // the data should be updated as necessary.
294
295 // If this fails, something is wrong with the cryptographer, but there's
296 // nothing we can do about it here.
297 syncable::ProcessUnsyncedChangesForEncryption(trans,
298 cryptographer);
299 }
300 }
256 301
257 if (entry->Get(IS_UNSYNCED)) { 302 if (entry->Get(IS_UNSYNCED)) {
258 DVLOG(1) << "Skipping update, returning conflict for: " << id 303 DVLOG(1) << "Skipping update, returning conflict for: " << id
259 << " ; it's unsynced."; 304 << " ; it's unsynced.";
260 return CONFLICT; 305 return CONFLICT;
261 } 306 }
262 if (!entry->Get(SERVER_IS_DEL)) { 307 if (!entry->Get(SERVER_IS_DEL)) {
263 syncable::Id new_parent = entry->Get(SERVER_PARENT_ID); 308 syncable::Id new_parent = entry->Get(SERVER_PARENT_ID);
264 Entry parent(trans, GET_BY_ID, new_parent); 309 Entry parent(trans, GET_BY_ID, new_parent);
265 // A note on non-directory parents: 310 // A note on non-directory parents:
(...skipping 16 matching lines...) Expand all
282 Directory::ChildHandles handles; 327 Directory::ChildHandles handles;
283 trans->directory()->GetChildHandlesById(trans, id, &handles); 328 trans->directory()->GetChildHandlesById(trans, id, &handles);
284 if (!handles.empty()) { 329 if (!handles.empty()) {
285 // If we have still-existing children, then we need to deal with 330 // If we have still-existing children, then we need to deal with
286 // them before we can process this change. 331 // them before we can process this change.
287 DVLOG(1) << "Not deleting directory; it's not empty " << *entry; 332 DVLOG(1) << "Not deleting directory; it's not empty " << *entry;
288 return CONFLICT; 333 return CONFLICT;
289 } 334 }
290 } 335 }
291 336
292 // We intercept updates to the Nigori node, update the Cryptographer and
293 // encrypt any unsynced changes here because there is no Nigori
294 // ChangeProcessor.
295 const sync_pb::EntitySpecifics& specifics = entry->Get(SERVER_SPECIFICS);
296 if (specifics.HasExtension(sync_pb::nigori)) {
297 const sync_pb::NigoriSpecifics& nigori =
298 specifics.GetExtension(sync_pb::nigori);
299 cryptographer->Update(nigori);
300
301 // Make sure any unsynced changes are properly encrypted as necessary.
302 const syncable::ModelTypeSet encrypted_types =
303 cryptographer->GetEncryptedTypes();
304 if (!VerifyUnsyncedChangesAreEncrypted(trans, encrypted_types) &&
305 (!cryptographer->is_ready() ||
306 !syncable::ProcessUnsyncedChangesForEncryption(trans,
307 cryptographer))) {
308 // We were unable to encrypt the changes, possibly due to a missing
309 // passphrase. We return conflict, even though the conflict is with the
310 // unsynced change and not the nigori node. We ensure foward progress
311 // because the cryptographer already has the pending keys set, so once
312 // the new passphrase is entered we should be able to encrypt properly.
313 // And, because this update will not be applied yet, next time around
314 // we will properly encrypt all appropriate unsynced data.
315 // Note: we return CONFLICT_ENCRYPTION instead of CONFLICT. See
316 // explanation below.
317 DVLOG(1) << "Marking nigori node update as conflicting due to being "
318 << "unable to encrypt all necessary unsynced changes.";
319 return CONFLICT_ENCRYPTION;
320 }
321
322 // Note that we don't bother to encrypt any synced data that now requires
323 // encryption. The machine that turned on encryption should encrypt
324 // everything itself. It's possible it could get interrupted during this
325 // process, but we currently reencrypt everything at startup as well,
326 // so as soon as a client is restarted with this datatype encrypted, all the
327 // data should be updated as necessary.
328 }
329
330 // Only apply updates that we can decrypt. If we can't decrypt the update, it 337 // Only apply updates that we can decrypt. If we can't decrypt the update, it
331 // is likely because the passphrase has not arrived yet. Because the 338 // is likely because the passphrase has not arrived yet. Because the
332 // passphrase may not arrive within this GetUpdates, we can't just return 339 // passphrase may not arrive within this GetUpdates, we can't just return
333 // conflict, else the syncer gets stuck. As such, we return 340 // conflict, else the syncer gets stuck. As such, we return
334 // CONFLICT_ENCRYPTION, which is treated as a non-blocking conflict. See the 341 // CONFLICT_ENCRYPTION, which is treated as a non-blocking conflict. See the
335 // description in syncer_types.h. 342 // description in syncer_types.h.
336 if (specifics.has_encrypted() && 343 if (specifics.has_encrypted() &&
337 !cryptographer->CanDecrypt(specifics.encrypted())) { 344 !cryptographer->CanDecrypt(specifics.encrypted())) {
338 // We can't decrypt this node yet. 345 // We can't decrypt this node yet.
339 DVLOG(1) << "Received an undecryptable " 346 DVLOG(1) << "Received an undecryptable "
(...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after
753 if (update.version() < target->Get(SERVER_VERSION)) { 760 if (update.version() < target->Get(SERVER_VERSION)) {
754 LOG(WARNING) << "Update older than current server version for " 761 LOG(WARNING) << "Update older than current server version for "
755 << *target << " Update:" 762 << *target << " Update:"
756 << SyncerProtoUtil::SyncEntityDebugString(update); 763 << SyncerProtoUtil::SyncEntityDebugString(update);
757 return VERIFY_SUCCESS; // Expected in new sync protocol. 764 return VERIFY_SUCCESS; // Expected in new sync protocol.
758 } 765 }
759 return VERIFY_UNDECIDED; 766 return VERIFY_UNDECIDED;
760 } 767 }
761 768
762 } // namespace browser_sync 769 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698