Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #include "sync/engine/apply_metadata_updates.h" | |
| 2 | |
| 3 #include "base/metrics/histogram.h" | |
| 4 #include "sync/engine/conflict_resolver.h" // For the ConflictResolution enums F IXME | |
| 5 #include "sync/engine/nigori_util.h" | |
| 6 #include "sync/engine/syncer_util.h" | |
| 7 #include "sync/syncable/directory.h" | |
| 8 #include "sync/syncable/mutable_entry.h" | |
| 9 #include "sync/syncable/write_transaction.h" | |
| 10 #include "sync/util/cryptographer.h" | |
| 11 | |
| 12 using syncable::GET_BY_SERVER_TAG; | |
| 13 using syncable::IS_UNAPPLIED_UPDATE; | |
| 14 using syncable::IS_UNSYNCED; | |
| 15 using syncable::NIGORI; | |
| 16 using syncable::SERVER_SPECIFICS; | |
| 17 using syncable::SPECIFICS; | |
| 18 using syncable::SYNCER; | |
| 19 | |
| 20 namespace browser_sync { | |
| 21 | |
| 22 void ApplyMetadataUpdates(syncable::Directory* dir) { | |
| 23 syncable::WriteTransaction trans(FROM_HERE, SYNCER, dir); | |
| 24 ApplyNigoriUpdates(&trans, dir->GetCryptographer(&trans)); | |
| 25 } | |
| 26 | |
| 27 void ApplyNigoriUpdates(syncable::WriteTransaction* trans, | |
| 28 Cryptographer* cryptographer) { | |
| 29 syncable::MutableEntry nigori_node(trans, GET_BY_SERVER_TAG, | |
| 30 ModelTypeToRootTag(NIGORI)); | |
| 31 | |
| 32 // Mainly for unit tests. We should have a Nigori node by this point. | |
| 33 if (!nigori_node.good()) { | |
| 34 return; | |
| 35 } | |
| 36 | |
| 37 // We always update the cryptographer with the server's nigori node, | |
| 38 // even if we have a locally modified nigori node (we manually merge nigori | |
| 39 // data in the conflict resolver in that case). This handles the case where | |
| 40 // two clients both set a different passphrase. The second client to attempt | |
| 41 // to commit will go into a state of having pending keys, unioned the set of | |
| 42 // encrypted types, and eventually re-encrypt everything with the passphrase | |
| 43 // of the first client and commit the set of merged encryption keys. Until the | |
| 44 // second client provides the pending passphrase, the cryptographer will | |
| 45 // preserve the encryption keys based on the local passphrase, while the | |
| 46 // nigori node will preserve the server encryption keys. | |
| 47 // | |
| 48 // If non-encryption changes are made to the nigori node, they will be | |
| 49 // lost as part of conflict resolution. This is intended, as we place a higher | |
| 50 // priority on preserving the server's passphrase change to preserving local | |
| 51 // non-encryption changes. Next time the non-encryption changes are made to | |
| 52 // the nigori node (e.g. on restart), they will commit without issue. | |
| 53 if (nigori_node.Get(IS_UNAPPLIED_UPDATE)) { | |
|
Nicolas Zea
2012/06/21 02:58:36
if (!nigori_node.Get(IS_UNAPPLIED_UPDATE))
retur
| |
| 54 const sync_pb::NigoriSpecifics& nigori = | |
| 55 nigori_node.Get(SERVER_SPECIFICS).nigori(); | |
| 56 cryptographer->Update(nigori); | |
| 57 | |
| 58 // Make sure any unsynced changes are properly encrypted as necessary. | |
| 59 // We only perform this if the cryptographer is ready. If not, these are | |
| 60 // re-encrypted at SetDecryptionPassphrase time (via ReEncryptEverything). | |
| 61 // This logic covers the case where the nigori update marked new datatypes | |
| 62 // for encryption, but didn't change the passphrase. | |
| 63 if (cryptographer->is_ready()) { | |
| 64 // Note that we don't bother to encrypt any data for which IS_UNSYNCED | |
| 65 // == false here. The machine that turned on encryption should know about | |
| 66 // and re-encrypt all synced data. It's possible it could get interrupted | |
| 67 // during this process, but we currently reencrypt everything at startup | |
| 68 // as well, so as soon as a client is restarted with this datatype marked | |
| 69 // for encryption, all the data should be updated as necessary. | |
| 70 | |
| 71 // If this fails, something is wrong with the cryptographer, but there's | |
| 72 // nothing we can do about it here. | |
| 73 DVLOG(1) << "Received new nigori, encrypting unsynced changes."; | |
| 74 syncable::ProcessUnsyncedChangesForEncryption(trans, cryptographer); | |
| 75 } | |
| 76 | |
| 77 if (!nigori_node.Get(IS_UNSYNCED)) { // Update only. | |
| 78 SyncerUtil::UpdateLocalDataFromServerData(trans, &nigori_node); | |
| 79 } else { // Conflict. | |
| 80 // Create a new set of specifics based on the server specifics (which | |
| 81 // preserves their encryption keys). | |
| 82 sync_pb::EntitySpecifics specifics = nigori_node.Get(SERVER_SPECIFICS); | |
| 83 sync_pb::NigoriSpecifics* server_nigori = specifics.mutable_nigori(); | |
| 84 // Store the merged set of encrypted types (cryptographer->Update(..) will | |
| 85 // have merged the local types already). | |
| 86 cryptographer->UpdateNigoriFromEncryptedTypes(server_nigori); | |
| 87 // The cryptographer has the both the local and remote encryption keys | |
| 88 // (added at cryptographer->Update(..) time). | |
| 89 // If the cryptographer is ready, then it already merged both sets of keys | |
| 90 // and we can store them back in. In that case, the remote key was already | |
| 91 // part of the local keybag, so we preserve the local key as the default | |
| 92 // (including whether it's an explicit key). | |
| 93 // If the cryptographer is not ready, then the user will have to provide | |
| 94 // the passphrase to decrypt the pending keys. When they do so, the | |
| 95 // SetDecryptionPassphrase code will act based on whether the server | |
| 96 // update has an explicit passphrase or not. | |
| 97 // - If the server had an explicit passphrase, that explicit passphrase | |
| 98 // will be preserved as the default encryption key. | |
| 99 // - If the server did not have an explicit passphrase, we assume the | |
| 100 // local passphrase is the most up to date and preserve the local | |
| 101 // default encryption key marked as an implicit passphrase. | |
| 102 // This works fine except for the case where we had locally set an | |
| 103 // explicit passphrase. In that case the nigori node will have the default | |
| 104 // key based on the local explicit passphassphrase, but will not have it | |
| 105 // marked as explicit. To fix this we'd have to track whether we have a | |
| 106 // explicit passphrase or not separate from the nigori, which would | |
| 107 // introduce even more complexity, so we leave it up to the user to reset | |
| 108 // that passphrase as an explicit one via settings. The goal here is to | |
| 109 // ensure both sets of encryption keys are preserved. | |
| 110 if (cryptographer->is_ready()) { | |
| 111 cryptographer->GetKeys(server_nigori->mutable_encrypted()); | |
| 112 server_nigori->set_using_explicit_passphrase( | |
| 113 nigori_node.Get(SPECIFICS).nigori(). | |
| 114 using_explicit_passphrase()); | |
| 115 } | |
| 116 // We deliberately leave the server's device information. This client will | |
| 117 // add its own device information on restart. | |
| 118 nigori_node.Put(SPECIFICS, specifics); | |
| 119 DVLOG(1) << "Resolving simple conflict, merging nigori nodes: " | |
| 120 << nigori_node; | |
| 121 | |
| 122 SyncerUtil::OverwriteServerChanges(&nigori_node); | |
| 123 | |
| 124 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", | |
| 125 ConflictResolver::NIGORI_MERGE, | |
| 126 ConflictResolver::CONFLICT_RESOLUTION_SIZE); | |
| 127 } | |
| 128 } | |
| 129 } | |
| 130 | |
| 131 } // namespace browser_sync | |
| OLD | NEW |