Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |