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